ďťż
 
PostgreSQL - dziwne zachowanie triggera ďťż
 
PostgreSQL - dziwne zachowanie triggera
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

PostgreSQL - dziwne zachowanie triggera



Marek - 14-12-2006 16:09
PostgreSQL - dziwne zachowanie triggera
  Witam,

Nie potrafi? zinterpretowa? przedziwnego zachowania triggera. Otó? ma dwie
tabele: document oraz files. Pierwsza z nich zawiera dokumenty a druga m.in.
skojarzone pliki z tymi dokumentami. Tabela document posiada trigger:
CREATE OR REPLACE FUNCTION document_remove()
RETURNS TRIGGER AS
$$
BEGIN
EXECUTE 'DELETE FROM files WHERE document_id=' || OLD.document_id || '
AND document_type_id=2';
EXECUTE 'DELETE FROM shop_order_item WHERE document_id=' ||
OLD.document_id || ' AND was_unavailable=true';
IF OLD.category_id NOTNULL THEN
EXECUTE 'UPDATE category SET doc_counter=doc_counter-1 WHERE
category_id=' || OLD.category_id;
END IF;
RETURN OLD;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER document_remove BEFORE DELETE ON document FOR EACH ROW
EXECUTE PROCEDURE document_remove();

Okazuje si?, ?e wykonanie zapytania SQL w postaci:
DELETE FROM document WHERE document_id=xxx;

za pierwszym razem nie wykonuje si?. Kasowane s? za to stosowne rekordy w
tabeli files. Ponowne wywo?anie usuwa ??dany dokument. Reasumuj?c: je?li
jest odpowiadaj?cy rekord w tabeli files to usuni?cie rekordu w document nie
powiedzie si?, je?li tabela files nie ma rekordów spe?niaj?cych warunek
usuni?cia, wszystko zadzia?a poprawnie.

Zaczynam podejrzewa?, ?e definicja OLD ulega zmianie po wykonaniu SQL. Czy
wiecie co? na ten temat ?

--
Pozdrawiam,
Marek





Marek - 14-12-2006 16:09

  Chyba wiem co jest grane ...
W strukturze document mam deklaracj? pola:

thumbnail_id int4 REFERENCES files (files_id) MATCH FULL ON DELETE SET
NULL ON UPDATE CASCADE,

Trigger powoduje wykasowanie tego samego rekordu z tabeli files, który jest
wskazywany przez thumbnail_id... moje przeoczenie.

Tak czy owak mam inne pytanie. Maj?c na wzgl?dzie powy?sz? sytuacj?
chcia?bym dokonywa? sprawdzenia czy w chwili wstawiania/aktualizacji rekordu
pole thumbnail_id zawiera poprawn? warto?? (czyli jest nullem lub wskazuje
na rekord w files). Z drugiej za? strony przy usuwaniu rekordu z tabeli
document chcia?bym usuwa? równie? rekord w files wskazywany przez
thumbnail_id. Po trzecie - usuni?cie pliku w files powinno ustawi? na null
pole thumbnail_id. Jak to pogodzi? ?




=?ISO-8859-2?Q?Pawe=B3_Matejski?= - 14-12-2006 16:09

  Marek wrote:
> Witam,
>
> Nie potrafi? zinterpretowa? przedziwnego zachowania triggera. Otó? ma
> dwie tabele: document oraz files. Pierwsza z nich zawiera dokumenty a
> druga m.in. skojarzone pliki z tymi dokumentami. Tabela document posiada
> trigger:
> CREATE OR REPLACE FUNCTION document_remove()
> RETURNS TRIGGER AS
> $$
> BEGIN
> EXECUTE 'DELETE FROM files WHERE document_id=' || OLD.document_id || '
> AND document_type_id=2';
> EXECUTE 'DELETE FROM shop_order_item WHERE document_id=' ||
> OLD.document_id || ' AND was_unavailable=true';
> IF OLD.category_id NOTNULL THEN
> EXECUTE 'UPDATE category SET doc_counter=doc_counter-1 WHERE
> category_id=' || OLD.category_id;
> END IF;
> RETURN OLD;
> END;
> $$
> LANGUAGE plpgsql;

Dlaczego u?ywasz dynamicznego SQL'a, gdy nie musisz?

> CREATE TRIGGER document_remove BEFORE DELETE ON document FOR EACH ROW
> EXECUTE PROCEDURE document_remove();

Takie operacje lepiej wykonywa? w triggerze AFTER. Te operacje trwaj? a mo?e si?
okaza?, ?e rekord jest nieskasowany.

> Okazuje si?, ?e wykonanie zapytania SQL w postaci:
> DELETE FROM document WHERE document_id=xxx;
>
> za pierwszym razem nie wykonuje si?. Kasowane s? za to stosowne rekordy
> w tabeli files.

Tak si? dzieje w tylko w jednym przypadku - gdy funkcja triggera zwraca warto??
NULL.
Albo kod tej funkcji ?le przepisa?e? (a przepisywa?e?, nie jest on wklejany ;)
), albo masz jeszcze innego trigera before na tabeli documenty.

> Ponowne wywo?anie usuwa ??dany dokument. Reasumuj?c:
> je?li jest odpowiadaj?cy rekord w tabeli files to usuni?cie rekordu w
> document nie powiedzie si?, je?li tabela files nie ma rekordów
> spe?niaj?cych warunek usuni?cia, wszystko zadzia?a poprawnie.

P.S. Czyta?em Twój drugi post, ale tamto t?umaczenie mnie ne przekonuje -
je?liby co? postgresowi nie pasowa?o, zg?osi?by b??d i wycofa? CA?? transakcj?.

--
P.M.




Marek - 14-12-2006 16:09

  > Dlaczego u?ywasz dynamicznego SQL'a, gdy nie musisz?

Hmmm, tu nast?pi?o zastanowienie ...
Nie mam bladego poj?cia jak inaczej zrealizowa? usuwanie rekordów powi?zanej
tabeli je?li musi ona spe?ni? wi?cej ni? jeden warunek ... tzn. np. tak jak
w tym przypadku document_type_id=2. Masz jak?? lepsz? koncepcj? ?

> Takie operacje lepiej wykonywa? w triggerze AFTER. Te operacje trwaj? a
> mo?e si?
> okaza?, ?e rekord jest nieskasowany.

Tak, masz racj?. Chyba kiepski dzie? mia?em ... To rozwi?zuje problem. Ju?
przetestowa?em.

> P.S. Czyta?em Twój drugi post, ale tamto t?umaczenie mnie ne przekonuje -
> je?liby co? postgresowi nie pasowa?o, zg?osi?by b??d i wycofa? CA??
> transakcj?.

W?a?nie nie - ju? przetestowa?em. Chodzi o to, ?e gdy wy??czy?em wi?zy
integralno?ci na polu thumbnail_id to wszystko cacy dzia?a. Przypuszczam, ?e
w tym przypadku powstawa? kociokwik i autorzy Postgresa nie wzi?li pod uwag?
fantazji programisty :-) Zauwa? co si? dzieje:
1. kasujemy dokument
2. wyzwalany jest trigger "before", który usuwa rekord w files
3. wi?zy integralno?ci update'uj? pole thumbnail_id w rekordzi, który jest
w?a?nie usuway

Czyli próbuj? updateowa? rekord, który jest w trakcie usuwania. Jaka? chora
kombinacja powstaje i pewnie nie przewidywano, ?e mo?na w jednym czasie
realizowa? dwie sprzeczne ze sob? operacje na jednym rekordzie.





=?ISO-8859-2?Q?Pawe=B3_Matejski?= - 14-12-2006 16:09

  Marek wrote:
>> Dlaczego u?ywasz dynamicznego SQL'a, gdy nie musisz?
>
> Hmmm, tu nast?pi?o zastanowienie ...
> Nie mam bladego poj?cia jak inaczej zrealizowa? usuwanie rekordów
> powi?zanej tabeli je?li musi ona spe?ni? wi?cej ni? jeden warunek ...
> tzn. np. tak jak w tym przypadku document_type_id=2. Masz jak?? lepsz?
> koncepcj? ?

Chyba si? nie zrozumieli?my.
Zamiast:
EXECUTE 'DELETE FROM files WHERE document_id=' || OLD.document_id || ' AND
document_type_id=2';
Napisz:
DELETE FROM files WHERE document_id=OLD.document_id AND document_type_id=2;

To jest wydajniejsze, bo prepare robione jest raz na sesj?, a nie przy ka?dym
wykonaniu funkcji.

>> P.S. Czyta?em Twój drugi post, ale tamto t?umaczenie mnie ne przekonuje -
>> je?liby co? postgresowi nie pasowa?o, zg?osi?by b??d i wycofa? CA??
>> transakcj?.
>
> W?a?nie nie - ju? przetestowa?em. Chodzi o to, ?e gdy wy??czy?em wi?zy
> integralno?ci na polu thumbnail_id to wszystko cacy dzia?a.
> Przypuszczam, ?e w tym przypadku powstawa? kociokwik i autorzy Postgresa
> nie wzi?li pod uwag? fantazji programisty :-) Zauwa? co si? dzieje:
> 1. kasujemy dokument
> 2. wyzwalany jest trigger "before", który usuwa rekord w files
> 3. wi?zy integralno?ci update'uj? pole thumbnail_id w rekordzi, który
> jest w?a?nie usuway
>
> Czyli próbuj? updateowa? rekord, który jest w trakcie usuwania. Jaka?
> chora kombinacja powstaje i pewnie nie przewidywano, ?e mo?na w jednym
> czasie realizowa? dwie sprzeczne ze sob? operacje na jednym rekordzie.

Hmmm... to niedobrze - bo powinien w takim wypadku zaprotestowa? je?li mu si?
co? nie podoba i wycofa? transakcj?. A w której wersji tak masz?

--
P.M.




Marek - 14-12-2006 16:09

  > Chyba si? nie zrozumieli?my.
> Zamiast:
> EXECUTE 'DELETE FROM files WHERE document_id=' || OLD.document_id || '
> AND
> document_type_id=2';
> Napisz:
> DELETE FROM files WHERE document_id=OLD.document_id AND
> document_type_id=2;
> To jest wydajniejsze, bo prepare robione jest raz na sesj?, a nie przy
> ka?dym
> wykonaniu funkcji.

No tak ... nie zrozumielimy si?. Zastosowa?em execute z tego wzgl?du gdy?
nie bardzo rozumiem ró?nic?. Czy poj?cie sesji w Postgesie wyznacza otwarcie
po??czenia a? do jego zamkni?cia (w PHP pg_close() lub zamkni?cie skryptu)?
Je?li tak to je?li w trakcie trwania sesji wywo?am 10x usuwanie ró?nych
dokumentów to czy przypadkiem ta druga metoda (DELETE FROM files) nie
spowoduje, ?e nast?pi 10krotna próba kasowania pliku skojarzonego z
pierwszym usuwanym dokumentem?

> Hmmm... to niedobrze - bo powinien w takim wypadku zaprotestowa? je?li mu
> si?
> co? nie podoba i wycofa? transakcj?. A w której wersji tak masz?

8.1.5
Po zmianie triggera z before na after wszystko jest ok. Ten niepotrzebny
update jest wykonywany gdy? rekord jeszcze w tym przypadku istnieje.




hubert depesz lubaczewski - 14-12-2006 16:09

  On 2006-12-06, Marek <marek1967@spam.interia.pl> wrote:
> No tak ... nie zrozumielimy si?. Zastosowa?em execute z tego wzgl?du gdy?
> nie bardzo rozumiem ró?nic?. Czy poj?cie sesji w Postgesie wyznacza otwarcie
> po??czenia a? do jego zamkni?cia (w PHP pg_close() lub zamkni?cie skryptu)?
> Je?li tak to je?li w trakcie trwania sesji wywo?am 10x usuwanie ró?nych
> dokumentów to czy przypadkiem ta druga metoda (DELETE FROM files) nie
> spowoduje, ?e nast?pi 10krotna próba kasowania pliku skojarzonego z
> pierwszym usuwanym dokumentem?

oczywi?cie, ?e nie.
execute u?ywasz tylko do dynamicznych zapyta?. w szczególno?ci - gdy
zmienia ci si? nazwa pola lub tabeli w zale?no?ci od danych.

depesz

--
http://www.depesz.com/ -> nowy, jeszcze lepszy, depesz




Marek - 14-12-2006 16:09

  > oczywi?cie, ?e nie.
> execute u?ywasz tylko do dynamicznych zapyta?. w szczególno?ci - gdy
> zmienia ci si? nazwa pola lub tabeli w zale?no?ci od danych.

Rozumiem ... czyli zapytanie dynamiczne nale?y rozumie? w tym przypadku
jako zmiane jego struktury a nie tylko warto?ci parametrów?

A jak wygl?da kwestia sesji? Co ona oznacza w Postgresie ?




hubert depesz lubaczewski - 14-12-2006 16:09

  On 2006-12-06, Marek <marek1967@spam.interia.pl> wrote:
>> oczywi?cie, ?e nie.
>> execute u?ywasz tylko do dynamicznych zapyta?. w szczególno?ci - gdy
>> zmienia ci si? nazwa pola lub tabeli w zale?no?ci od danych.
> Rozumiem ... czyli zapytanie dynamiczne nale?y rozumie? w tym przypadku
> jako zmiane jego struktury a nie tylko warto?ci parametrów?

dok?adnie.

> A jak wygl?da kwestia sesji? Co ona oznacza w Postgresie ?

nie rozumiem. jakie? szczegó?y?

depesz

--
http://www.depesz.com/ -> nowy, jeszcze lepszy, depesz




Marek - 14-12-2006 16:09

  >> A jak wygl?da kwestia sesji? Co ona oznacza w Postgresie ?
>
> nie rozumiem. jakie? szczegó?y?

Nawiaza?em do mojej dyskusji z Paw?em - s?dzi?em, ?e rozwijasz ten w?tek
w?a?nie. Ok, powtórz?: Pawe? wspomnia? o tym, ?e jaki? tam mechanizm dzia?a
raz na sesj?. Nigdzie natomiast nie znalaz?em (o czym te? napisa?em w
odpowiedzi) definicji sesji Postgresa. Co to takiego w zasadzie? Co wyznacza
jej pocz?tek i koniec?




hubert depesz lubaczewski - 14-12-2006 16:09

  On 2006-12-07, Marek <marek1967@spam.interia.pl> wrote:
> Nawiaza?em do mojej dyskusji z Paw?em - s?dzi?em, ?e rozwijasz ten w?tek
> w?a?nie. Ok, powtórz?: Pawe? wspomnia? o tym, ?e jaki? tam mechanizm dzia?a
> raz na sesj?. Nigdzie natomiast nie znalaz?em (o czym te? napisa?em w
> odpowiedzi) definicji sesji Postgresa. Co to takiego w zasadzie? Co wyznacza
> jej pocz?tek i koniec?

po??cznie i roz??czenie.

depesz

--
http://www.depesz.com/ -> nowy, jeszcze lepszy, depesz




Marek - 14-12-2006 16:09

  > po??cznie i roz??czenie.

Czyli je?li dobrze rozumiem: w trakcie 1 sesji np. skryptu PHP mo?na
ustanowi? wielokrotnie sesj? bazy gdy otworz? równolegle lub kolejno kilka
po??cze??




hubert depesz lubaczewski - 14-12-2006 16:09

  On 2006-12-07, Marek <marek1967@spam.interia.pl> wrote:
> Czyli je?li dobrze rozumiem: w trakcie 1 sesji np. skryptu PHP mo?na
> ustanowi? wielokrotnie sesj? bazy gdy otworz? równolegle lub kolejno kilka
> po??cze??

tak, tylko nie wiem po co ci to.

depesz

--
http://www.depesz.com/ -> nowy, jeszcze lepszy, depesz




Marek - 14-12-2006 16:09

  > tak, tylko nie wiem po co ci to.

Po to by mie? jasno?? poj?cia "sesji" czytaj?c dokumentacj? Postgresa :-)
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • effulla.pev.pl
  • comp
    [PostgreSQL] - jak =?ISO-8859-2?Q?zabezpieczy=E6_interesy_tw?==?ISO-8859-2?Q?=F3rcy_systemu_=3F=3F=3F?= postgresql - int/int postgresql Select count(*) czy raczej Select count(ID) [PostgreSQL] jak =?ISO-8859-2?Q?pobra=E6_warto=B6=E6_zwracan?==?ISO-8859-2?Q?=B1_przez_funkcj=EA=3F?= [postgresql] INSERT OR UPDATE - jak =?ISO-8859-2?Q?b=EAdzie_na?==?ISO-8859-2?Q?jlepiej=3F?= [postgresql] kilka =?ISO-8859-2?Q?rekord=F3w_subquery_jako_?==?ISO-8859-2?Q?string?= [PostgreSQL] Jak =?ISO-8859-2?Q?po=B3=B1czy=E6_funkcje_z_w?==?ISO-8859-2?Q?idokiem?= Postgres - replikcja master-master Dopasowanie do "najlepszego" dopasowania :) [ PostgreSQL] Problemy z =?ISO-8859-2?Q?instalacj=B1_PostgreSQL_na_syste?==?ISO-8859-2?Q?mach_Windows?=
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • dirtyboys.xlx.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