Sziasztok!
PostgreSQL-ben próbálok egy adatbázist összeállítani, és egy TRIGGER-ből hívott pl/pgsql függvény kifogott rajtam.
A függvény fejléce a következő:
CREATE OR REPLACE FUNCTION next_phs_link(
INOUT rec phs_links, -- Az aktuális fizikai link rekord, majd a következő
INOUT sh portshare, -- SHARE, ha NULL, akkor nincs következő rekord
IN dir linkdirection -- Irány Right: 1-2->, Left <-1-2
) AS $$
...
$$ LANGUAGE plpgsql;
Az első paraméter egy rekord, a második, és harmadik egy-egy saját enumerációs típus.
Meghívva a függvényt, függvény egy új rekord értékkel térne vissza, és egy másik enumerációs értékkel.
Ha simán meghívom a függvényt:
RAISE next_phs_link(lrec_r, psh, dir);
Akkor a parancs után a vártnak megfelelően megváltozik a psh változó értéke, de a lrec_r nem, pedig a függvényben értéket adok neki egy SELECT lekérdezésben.
Találtam a neten egy hívási formát, kipróbáltam:
lrec_r := (next_phs_link(lrec_r, psh, dir)).rec;
Ezzel már megkapta az lrec_r változó a megfelelő értéket, viszont a psh változó értéke maradt a hívás előtti, hiába kapott értéket a függvényben.
Valaki árulja el hogyan kell ezt csinálni, mert én valamit úgy látszik nem értek.
A válaszokat előre is köszönöm.
- 3082 megtekintés
Hozzászólások
- A hozzászóláshoz be kell jelentkezni
Igen olvastam.
Viszont itt nem egy TRIGGER függvényről van szó, csak megemlítettem, hogy egy TRIGGER függvényből hívom. Elnézést, hiba volt a TRIGGER emlegetése, mivel valószínűleg nincs jelentősége a kérdés szempontjából.
- A hozzászóláshoz be kell jelentkezni
Valami teljes példát tegyél elérhetővé, mert így rébuszokban a kérdést se biztos hogy értem.
- A hozzászóláshoz be kell jelentkezni
Az egészet nem akartam beidézni, mert elég hosszú. De talán még a megadott háttér információ is csak félreértéseket szült, az a kb. 200sor kód csak arra lenne jó, hogy legyen miben eltévedni.
Egyébként most már nem tudom beidézni (csak nehezen) az eredeti program részletet, mert átírtam úgy, hogy csak egy rekordot adjon vissza a RETURN-al, így megkapom az eredményt.
Ennek ellenére érdekelne, hogyan kell olyan függvényt írni (vagy hogyan kell hívni), ami egynél több paramétert is megváltoztat (INOUT), és ezek a paraméterek nem mind skalárok, tehát legalább az egyik egy rekord pl..
Ha jól értelmezem a tapasztaltakat, az INOUT-ként megadott paraméter nem ugyanazt jelenti, mint az algoritmikus nyelvekben a cím szerinti paraméter átadás, mert a függvény visszatértekor a hívó nem mindig (?) azt az értéket látja, amit a hívott beállított, de a szabályokat nem értem.
Vagy pontosan így kéne itt is működnie, csak éppen ez egy bug.
- A hozzászóláshoz be kell jelentkezni
Hát adj közre egy 20 soros példát. Ha magyarra 'lefordítod' mint eddig, akkor nekem/nekünk először meg kell írni pgsql-ben hogy értsük a kérdést. Ha egyáltalán sikerül pontosan reprodukálni a 'mesédet'.
- A hozzászóláshoz be kell jelentkezni
Jó. Tegyük fel, azon túl, hogy nem tudok magyarul, még értetlen is vagyok, amikor nem értem mit nem értesz a kérdésen.
Szóval Én minden bizonnyal tévesen abból a feltételezésből indultam, hogy a pl/pgsql-ben az INOUT egy cím szerinti paraméter átadást jelent. Mint pl a c++ ban (abban tudok programozni, plpgsql-ben úgy tűnik nem annyira):
int fuggveny(int& a, int& b){ .... }
A kérdésem arra vonatkozott, hogy pl. következő test1 függvény esetén:
CREATE OR REPLACE FUNCTION test1(INOUT rec phs_links, INOUT sh portshare, IN dir linkdirection) AS $$
BEGIN
SELECT * INTO rec FROM phs_links WHERE port_id1 = 9;
sh := 'B';
RAISE INFO 'rec.port_id1 = %, sh = %', rec.port_id1, sh;
END;
$$ LANGUAGE plpgsql;
A test1() -et hogyan kell meghívni akkor, ha szükségem van mind a rec rekord típusú paraméter, mind az sh enumeráció típusú paraméter új a test1-ben kapott értékére.
Ha van egy test2 föggvényem:
CREATE OR REPLACE FUNCTION test2() RETURNS void AS $$
DECLARE
lrec phs_links;
psh portshare;
dir linkdirection := 'Right';
BEGIN
SELECT * INTO lrec FROM phs_links WHERE port_id1 = 15;
psh := 'A';
RAISE INFO 'test1() elött: lrec.port_id1 = %, psh = %', lrec.port_id1, psh;
PERFORM test1(lrec, psh, dir);
RAISE INFO 'test1() után: lrec.port_id1 = %, psh = %', lrec.port_id1, psh;
END;
$$ LANGUAGE plpgsql;
Akkor ezt meghívva a következő kimenetet kapom:
INFO: test1() elött: lrec.port_id1 = 15, psh = A
INFO: rec.port_id1 = 9, sh = B
CONTEXT: SQL statement "SELECT test1( $1 , $2 , $3 )"
PL/pgSQL function "test2" line 9 at PERFORM
INFO: test1() után: lrec.port_id1 = 15, psh = A
Tehát az eredmény nem az amit én reméltem.
A dokumentációból meg nem sikerült kihámozni, hogyan kaphatom meg test1 futásának az eredményét, vagyis a rec, és sh új értékét, amit a test1()-ben kapott.
ui.: Mondjuk az eredeti programban (NAGYON!) úgy tűnt, mintha a sh paraméter esetén megkapnám az új értéket, de lehet, hogy elnéztem valamit.
- A hozzászóláshoz be kell jelentkezni
Semmi bajom a magyaroddal, annyit próbáltam mondani, hogy futtatható kódrészlet informatívabb mint ha elmeséled. De nem is ez a fontos, hiszen lupus megválaszolta a problémádat. Annyit tennék hozzá, azért ilyen fura a visszatérési érték kezelése, mivel a plpgsql function-oknak SQL-ből is kell működnie.
CREATE OR REPLACE FUNCTION f1(x INT, y INT, INOUT i INT, OUT sum INT, OUT product INT)
AS $$
SELECT $3 + 3, $1 + $2, $1 * $2
$$ LANGUAGE SQL;
SELECT * FROM f1(11, 42, 3);
SELECT f1(11, 42, 3);
--------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION f2(x INT, y INT, INOUT i INT, OUT sum INT, OUT product INT)
AS $$
BEGIN
i := $3 + 3;
sum := $1 + $2;
product := $1 * $2;
END
$$ LANGUAGE plpgsql;
SELECT * FROM f2(11, 42, 3);
SELECT f2(11, 42, 3);
--------------------------------------------------------------------------
DROP FUNCTION IF EXISTS f3(x INT, y INT, i INT);
DROP TYPE IF EXISTS rtype;
CREATE TYPE rtype AS (i INT, sum INT, product INT);
CREATE OR REPLACE FUNCTION f3(x INT, y INT, i INT) RETURNS rtype
AS $$
DECLARE
o rtype;
BEGIN
o.i := $3 + 3;
o.sum := $1 + $2;
o.product := $1 * $2;
return o;
END
$$ LANGUAGE plpgsql;
SELECT * FROM f3(11, 42, 3);
SELECT f3(11, 42, 3);
- A hozzászóláshoz be kell jelentkezni
http://www.postgresql.org/docs/8.3/interactive/plpgsql-errors-and-messa…
Mondjuk biztos, hogy neked a RAISE kell? Szerintem tárolt eljárások hívására a PERFORM van.
----------------
Lvl86 Troll
- A hozzászóláshoz be kell jelentkezni
Basszus! Hülyeségeket írok.
Igen, PERFORM-al hívom a tárolt eljárást.
A RAISE onnan jöhetett, hogy már szinte minden második sor úgy kezdődik a függvényben, hogy RAISE INFO ... .
- A hozzászóláshoz be kell jelentkezni
Bizonyára elkerülte a figyelmedet a dokumentáció vonatkozó része:
When there are OUT or INOUT parameters, the RETURNS clause can be omitted. If present, it must agree with the result type implied by the output parameters: RECORD if there are multiple output parameters, or the same type as the single output parameter.
Az OUT/INOUT esetén nem a paraméter értéke változik, hanem a függvény az OUT paraméter(eke)t adja vissza.
A test2()-t átalakítva, látható lesz az eredmény:
CREATE OR REPLACE FUNCTION test2() RETURNS void AS $$
DECLARE
lrec phs_links;
psh portshare;
dir linkdirection := 'Right';
result record;
BEGIN
SELECT * INTO lrec FROM phs_links WHERE port_id1 = 15;
psh := 'A';
RAISE INFO 'test1() elött: lrec.port_id1 = %, psh = %', lrec.port_id1, psh;
result := test1(lrec, psh, dir);
RAISE INFO 'test1() után: lrec.port_id1 = %, psh = %', lrec.port_id1, psh;
RAISE INFO 'result: %', result;
END;
$$ LANGUAGE plpgsql;
- A hozzászóláshoz be kell jelentkezni
Köszönöm szépen a választ.
A manuál idézett része igen, először elkerülte a figyelmemet. Aztán mikor a dolog nem működött, és tettem egy téves megfigyelést is, nagyon nem értettem a dolgot.
A manuálban nem igazán találkoztam rekord a rekordban adattal. Próbáltam is csinálni egy hasonló típust, de nem sikerült.
A manuál vagy nem ad példákat, vagy azok nagyon primitívek. A fellelhető egyéb leírások pedig igencsak a manuálra hajaznak. És lehet, hogy bennem van a hiba, de ha keresek valamit a manuálban, azt nem egykönnyen találom meg.
- A hozzászóláshoz be kell jelentkezni
A row adattípus környékén keresd (pl: 4.2.12).
Rekord a recordban:
create type test_rec as (
rec phs_links,
sh portshare
);
CREATE OR REPLACE FUNCTION test2() RETURNS void AS $$
DECLARE
lrec phs_links;
psh portshare;
dir linkdirection := 'Right';
result test_rec;
BEGIN
SELECT * INTO lrec FROM phs_links WHERE port_id1 = 15;
psh := 'A';
RAISE INFO 'test1() elött: lrec.port_id1 = %, psh = %', lrec.port_id1, psh;
result := test1(lrec, psh, dir);
RAISE INFO 'test1() után: lrec.port_id1 = %, psh = %', lrec.port_id1, psh;
RAISE INFO 'result: lrec.port_id1 = %, psh = %', result.rec.port_id1, result.sh;
END;
- A hozzászóláshoz be kell jelentkezni