Drukowana wersja tematu

Kliknij tu, aby zobaczyć temat w orginalnym formacie

Forum PHP.pl _ PostgreSQL _ [PostgreSQL] Problem z funkcją przed update

Napisany przez: KcR 21.06.2014, 11:38:36

Cześć wszystkim,

Mam problem z funkcją, która sprawdza kwotę kary pieniężnej za przetrzymaną książkę i wpisuje ją do odpowiedniej kolumny. Problem jest taki, że próbowałem na różne sposoby zmienić tą funkcję, a problem wyskakuje wciąż ten sam. Ostatnia aktualizacja błędu wraz z kodem funkcji poniżej:

KOD FUNKCJI:

  1. CREATE OR REPLACE FUNCTION policz_pieniadze() RETURNS TRIGGER AS'
  2. DECLARE
  3. roznica_dat int4;
  4. data_zwrotu date;
  5. data_przewidywana date;
  6.  
  7. BEGIN
  8. SELECT borrowed_books.date_due_for_return INTO data_przewidywana FROM borrowed_books WHERE book_borrowing_id = OLD.book_borrowing_id;
  9. data_zwrotu = NEW.date_returned;
  10. roznica_dat = data_zwrotu - data_przewidywana;
  11. IF roznica_dat > 0 THEN
  12. UPDATE borrowed_books SET amount_of_fine = roznica_dat * (SELECT value FROM rules WHERE rules_id = 1) WHERE borrowed_books.book_borrowing_id = OLD.book_borrowing_id;
  13. RETURN NEW;
  14. ELSE
  15. UPDATE borrowed_books SET amount_of_fine = 0 WHERE borrowed_books.book_borrowing_id = OLD.book_borrowing_id;
  16. RETURN NEW;
  17. END IF;
  18. END;
  19. 'LANGUAGE 'plpgsql';


KOD BŁĘDU:
ERROR: stack depth limit exceeded
HINT: Increase the configuration parameter "max_stack_depth".
CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."books" x WHERE "isbn" = $1 FOR SHARE OF x"
SQL statement "UPDATE borrowed_books SET amount_of_fine = $1 * (SELECT value FROM rules WHERE rules_id = 1) WHERE borrowed_books.book_borrowing_id = $2 "

Z góry dziękuję za pomoc.

Napisany przez: Crozin 21.06.2014, 11:51:20

Czy mi się wydaje czy w tym triggerze odpalasz zawsze zapytanie UPDATE na tej samej tabeli co skutkuje zapętleniem całości? Zamiast wykonywać zapytania UPDATE po prostu zmień wartość rekordu z NEW:

  1. IF roznica_data > 0 THEN
  2. NEW.amount_of_fine := ...;
  3. ELSE
  4. NEW.amount_of_fine := 0;
  5. END IF;
  6.  
  7. RETURN NEW;

Napisany przez: KcR 21.06.2014, 12:46:54

Czyli jeśli w triggerze występuje Update to znowu "załącza się" ten sam trigger i tak w kółko? A więc tak działa rekurencja w PSQL oneeyedsmiley02.png Ok, w takim razie funkcja jest trochę odchudzona, lecz w tym problem że nie chce się zapisać kwota kary do tabeli (Nie wiem jak, ale sposób NEW.amount_of_fine = ... nie działa). Może mi ktoś wytłumaczyć jak to zrobić? Próbowałem rzutować, kombinować ze zmiennymi roznica_dat i (SELECT value ...) ale raczej nie tutaj jest problem.

FUNKCJA PO ODCHUDZENIU:

  1. CREATE OR REPLACE FUNCTION policz_pieniadze() RETURNS TRIGGER AS'
  2. DECLARE
  3. roznica_dat int;
  4. BEGIN
  5. roznica_dat = NEW.date_returned - OLD.date_due_for_return;
  6. IF roznica_dat > 0 THEN
  7. NEW.amount_of_fine = roznica_dat * (SELECT value FROM rules WHERE rules_id = 1);
  8. ELSE
  9. NEW.amount_of_fine = 0;
  10. END IF;
  11. RETURN NEW;
  12. END;
  13. 'LANGUAGE 'plpgsql';


EDIT:
Jeśli to potrzebne to kolumna amount_of_fine jest typu real, i select też wyrzuca typ real.
Wpadłem jeszcze na pomysł, aby po prostu usunąć ten wiersz w którym zachodzi update i wstawić go na nowo, ale sądzę iż ktoś zna lepszy sposób na to.

EDIT2:
Ok, problem tkwił w ustawieniu triggera, który musi być before update zamiast after update (wtedy zadziałało, choć byłoby miło jakby ktoś mi wytłumaczył dlaczego). Dziękuję za pomoc Crozin smile.gif.

Napisany przez: Crozin 21.06.2014, 12:57:25

= to operator porównania, := to operator przypisania.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)