ďťż
 
[plpgsql] Triger before/after - Problem ze zrozumieniem. ďťż
 
[plpgsql] Triger before/after - Problem ze zrozumieniem.
Zobacz wiadomości
 
Cytat
A gdyby tak się wedrzeć na umysłów górę, / Gdyby stanąć na ludzkich myśli piramidzie, / I przebić czołem przesądów chmurę, / I być najwyższą myślą wcieloną. . . Juliusz Słowacki, Kordian
Indeks BCB i MySQL subiekt gt fototapeta
 
  Witamy

[plpgsql] Triger before/after - Problem ze zrozumieniem.



kraf101 - 28-09-2007 00:11
[plpgsql] Triger before/after - Problem ze zrozumieniem.
  Witam,

Robię bazkę w PGSQL i mam pewien problem ze zrozumieniem na czym polega
różnica w deklaracjach triggerów before/after insert/update/delete.

Powiedzmy, że mamy dwie tabele "faktury" i "wpłaty" w relacji "1 do wiele"
(model bazy poniżej).
Pole "saldo" jest wyliczane przez trigger na funkcji faktury_i_u() (before
insert/update). Pole "zaplacono" w tablicy faktury jest wypełniane przez
trigger na funkcji wplaty_i_u() oraz wplaty_d() (delete).

Nie bardzo rozumiem jaka jest różnica między deklaracjami before a after.
W przypadku naruszenia ograniczenia pola "saldo > = 0" operacja
insert/update jest odrzucana zarówno dla deklaracji triggera "before" jak
i "after".

Jeszcze dziwniej jest przy usuwaniu wiersza z tablicy "wplaty".
W przypadku deklaracji "before", triggery wplaty_d() i faktury_i_u() są
odpalone i wykonują zmiany na tablicy "faktury" ale wiersz NIE ZOSTAJE
USUNIĘTY - bez żadnego komunikatu do klienta. W psql podaje "DELETE 0".
W przypadku deklaracji "after" wszystko wygląda OK, wykonują się zarówno
triggery jak i "DELETE 1"

Dlaczego tak jest ???

Dzięki
RAF

CREATE TABLE faktury
(
fak_id serial NOT NULL,
do_zaplaty float8 NOT NULL,
zaplacono float8 NOT NULL DEFAULT 0,
saldo float8 NOT NULL DEFAULT 0,
CONSTRAINT fak_pkey PRIMARY KEY (fak_id),
CONSTRAINT saldo_no_minus CHECK (saldo >= 0::double precision),
CONSTRAINT zap_no_minus CHECK (zaplacono >= 0::double precision)
);

CREATE OR REPLACE FUNCTION faktury_i_u()
RETURNS "trigger" AS
$BODY$BEGIN
NEW.saldo := NEW.do_zaplaty - NEW.zaplacono;
RETURN NEW;
END;$BODY$
LANGUAGE 'plpgsql' VOLATILE;

CREATE TRIGGER i_u
BEFORE INSERT OR UPDATE
ON faktury
FOR EACH ROW
EXECUTE PROCEDURE faktury_i_u();

CREATE TABLE wplaty
(
wpl_id serial NOT NULL,
fak_id int4 NOT NULL,
kwota float8 NOT NULL,
CONSTRAINT wpl_pkey PRIMARY KEY (wpl_id),
CONSTRAINT fak_ref FOREIGN KEY (fak_id)
REFERENCES faktury (fak_id) MATCH SIMPLE ON UPDATE RESTRICT ON DELETE
RESTRICT
);

CREATE OR REPLACE FUNCTION wplaty_i_u()
RETURNS "trigger" AS
$BODY$DECLARE
wpl_pop FLOAT8;
zap_fak FLOAT8;

BEGIN

IF TG_OP = 'INSERT' THEN
wpl_pop := 0;
ELSE
wpl_pop := OLD.kwota;
END IF;

SELECT zaplacono INTO zap_fak FROM faktury WHERE fak_id = NEW.fak_id;
UPDATE faktury SET zaplacono = zap_fak + NEW.kwota - wpl_pop WHERE fak_id =
NEW.fak_id;

RETURN NEW;
END;$BODY$
LANGUAGE 'plpgsql' VOLATILE;

CREATE TRIGGER i_u
AFTER INSERT OR UPDATE
ON wplaty
FOR EACH ROW
EXECUTE PROCEDURE wplaty_i_u();

CREATE OR REPLACE FUNCTION wplaty_d()
RETURNS "trigger" AS
$BODY$DECLARE
zap_fak FLOAT8;

BEGIN

SELECT zaplacono INTO zap_fak FROM faktury WHERE fak_id = OLD.fak_id;
UPDATE faktury SET zaplacono = zap_fak - OLD.kwota WHERE fak_id =
OLD.fak_id;

RETURN NEW;
END;$BODY$
LANGUAGE 'plpgsql' VOLATILE;

CREATE TRIGGER d
BEFORE DELETE
ON wplaty
FOR EACH ROW
EXECUTE PROCEDURE wplaty_d();





=?ISO-8859-2?Q?Pawe=B3_Matejski?= - 28-09-2007 00:11

  kraf101 wrote:
> Witam,
>
> Robię bazkę w PGSQL i mam pewien problem ze zrozumieniem na czym polega
> różnica w deklaracjach triggerów before/after insert/update/delete.
>
> Powiedzmy, że mamy dwie tabele "faktury" i "wpłaty" w relacji "1 do wiele"
> (model bazy poniżej).
> Pole "saldo" jest wyliczane przez trigger na funkcji faktury_i_u() (before
> insert/update). Pole "zaplacono" w tablicy faktury jest wypełniane przez
> trigger na funkcji wplaty_i_u() oraz wplaty_d() (delete).
>
> Nie bardzo rozumiem jaka jest różnica między deklaracjami before a after.
> W przypadku naruszenia ograniczenia pola "saldo > = 0" operacja
> insert/update jest odrzucana zarówno dla deklaracji triggera "before" jak
> i "after".

Ale w AFTER nie możesz zrobić tego po ciuchu, przez zwrócenie NULL. Nie możesz
też zmieniać danych w NEW rekordu.

> Jeszcze dziwniej jest przy usuwaniu wiersza z tablicy "wplaty".
> W przypadku deklaracji "before", triggery wplaty_d() i faktury_i_u() są
> odpalone i wykonują zmiany na tablicy "faktury" ale wiersz NIE ZOSTAJE
> USUNIĘTY - bez żadnego komunikatu do klienta. W psql podaje "DELETE 0".
> W przypadku deklaracji "after" wszystko wygląda OK, wykonują się zarówno
> triggery jak i "DELETE 1"
>
> Dlaczego tak jest ???
>
> CREATE OR REPLACE FUNCTION wplaty_d()
> RETURNS "trigger" AS
> $BODY$DECLARE
> zap_fak FLOAT8;
>
> BEGIN
>
> SELECT zaplacono INTO zap_fak FROM faktury WHERE fak_id = OLD.fak_id;
> UPDATE faktury SET zaplacono = zap_fak - OLD.kwota WHERE fak_id =
> OLD.fak_id;
>
> RETURN NEW;

Zastanów się, jaką wartość może mieć NEW w DELETE. I co się stanie, jak tę wartość
zwrócisz w BEFOR. :)

> END;$BODY$
> LANGUAGE 'plpgsql' VOLATILE;

--
P.M.




kraf101 - 28-09-2007 00:11

  Paweł Matejski wrote:

>
> Ale w AFTER nie możesz zrobić tego po ciuchu, przez zwrócenie NULL. Nie
> możesz też zmieniać danych w NEW rekordu.
>
>
> Zastanów się, jaką wartość może mieć NEW w DELETE. I co się stanie, jak tę
> wartość zwrócisz w BEFOR. :)
>

Dzięki,

Trochę załapałem, ale dalej to jakieś porąbane ;)
Jest gdzieś może jakieś info kiedy i co się powinno używać?
Tak żeby było poprawnie i nie wpadać w jakieś pułapki?

Pozdrawiam
RAF




=?ISO-8859-2?Q?Pawe=B3_Matejski?= - 28-09-2007 00:11

  kraf101 wrote:
> Paweł Matejski wrote:
>
>
>> Ale w AFTER nie możesz zrobić tego po ciuchu, przez zwrócenie NULL. Nie
>> możesz też zmieniać danych w NEW rekordu.
>>
>>
>> Zastanów się, jaką wartość może mieć NEW w DELETE. I co się stanie, jak tę
>> wartość zwrócisz w BEFOR. :)
>>
>
> Dzięki,
>
> Trochę załapałem, ale dalej to jakieś porąbane ;)
> Jest gdzieś może jakieś info kiedy i co się powinno używać?
> Tak żeby było poprawnie i nie wpadać w jakieś pułapki?

W dokumentacji postgresa jest rozdział triggers.

Ale zasady są proste. W BEFOR robisz
wszelkie zmiany na rekordzie wyzwalającym trigger - bo gdzie indziej się nie da,
oraz walidację - żeby zaoszczędzić pracy pozostałym triggerom albo wycofać się
ze zmian "po cichu", bez przerywania transakcji

W AFTER robisz
updaty pozostałych tabel - jesteś już pewny wprowadzonych danych, bo już ich nie można zmieniać.

--
P.M.
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • effulla.pev.pl
  • comp
    [MSSQL2000] Problem z =?ISO-8859-2?Q?tabel=B1/indeksem/zapytanie?==?ISO-8859-2?Q?m_czy_b=B3=B1d_w_bazie_danych=2E=2E=2E?= mysql i mysql-front, problem String line; if (line=="cos"){...}....problem Problemy z =?ISO-8859-2?Q?instalacj=B1_PostgreSQL_na_syste?==?ISO-8859-2?Q?mach_Windows?= [postgres] Problem z =?ISO-8859-2?Q?zmian=B1_struktury_i_z?==?ISO-8859-2?Q?ale=BFno=B6ciami=2E?= [oracle] =?ISO-8859-2?Q?zmia=BFd=BFony_przez_problem=3A_za?==?ISO-8859-2?Q?pytanie_do_hierarchi?= Problem z wartościami w MySQL :( [ MySQL and ASP and VBScript ] [PGSQL] czy ktos mial problemy z initdb pgsql 8.1 ? [MySQL] Problem z zapisem danych w bazie danych Problem z mysql - can't connect to MySQL/nietypowo...
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • misida.pev.pl
  • Cytat

    Decede mihi sole - nie zasłaniaj mi słonca.
    Gdy kogoś kochasz, jesteś jak stworzyciel świata - na cokolwiek spojrzysz, nabiera to kształtu, wypełnia się barwą, światłem. Powietrze przytula się do ciebie, choćby był mróz, a ty masz w sobie tyle radości, że musisz ją rozdawać wokoło, bo się w tobie nie mieści
    Hoc fac - tak czyń.
    A tergo - od tyłu; z tyłu.
    I czarne włosy posiwieją. Safona

    Valid HTML 4.01 Transitional

    Free website template provided by freeweblooks.com