PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Nieskończona pętla w funkcji wyzwalania

INNE gałąź można radykalnie uprościć. Ale kilka innych rzeczy jest nieefektywnych / niedokładnych / niebezpiecznych:

CREATE OR REPLACE FUNCTION sample_trigger_func()
  RETURNS TRIGGER AS
$func$
BEGIN
   IF TG_OP = 'DELETE' THEN
      RAISE INFO 'OLD: %', OLD.name;

      EXECUTE format('INSERT INTO %I SELECT ($1).*', TG_TABLE_NAME || '_deletes')
      USING OLD #= hstore('{mod_op, mod_datetime}'::text[]
                         , ARRAY[left(TG_OP, 1), now()::text]);
      RETURN OLD;
   ELSE  -- insert, update
      NEW.mod_op       := left(TG_OP, 1);
      NEW.mod_datetime := now();

      RETURN NEW;
   END IF;
END
$func$  LANGUAGE plpgsql;
  • W INNY gałąź po prostu przypisz do NOWY bezpośrednio. Nie ma potrzeby stosowania bardziej dynamicznego kodu SQL — który ponownie uruchomiłby ten sam wyzwalacz, powodując niekończącą się pętlę. To jest główny błąd.

  • POWRÓT NOWOŚĆ; poza JEŻELI konstrukcja zepsuje funkcję wyzwalacza dla DELETE , ponieważ NOWOŚĆ nie jest przypisany do DELETE.

  • Kluczową funkcją jest użycie hstore i operator hstore #= aby dynamicznie zmieniać dwa wybrane pola dobrze znanego typu wiersza - to jest nieznane w momencie pisania kodu. W ten sposób nie manipulujesz przy oryginalnym STARYM wartość, która może mieć zaskakujący efekt uboczny, jeśli masz więcej wyzwalaczy w łańcuchu zdarzeń.

    OLD #= hstore('{mod_op, mod_datetime}'::text[]
                 , ARRAY[left(TG_OP, 1), now()::text]);
    

    Dodatkowy moduł hstore musi być zainstalowane. Szczegóły:

    Korzystanie z hstore(text[], text[]) wariant tutaj, aby skonstruować hstore wartość z wieloma polami w locie.

  • Operator przypisania w plpgsql to := :

  • Zauważ, że użyłem nazwy kolumny mod_datetime zamiast mylącego mod_date , ponieważ kolumna jest oczywiście sygnaturą czasową a nie data .

Dodałem kilka innych ulepszeń będąc przy tym. Sam wyzwalacz powinien wyglądać tak:

CREATE TRIGGER insupdel_bef
BEFORE INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();

Skrzypce SQL.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Dołącz do wielu stołów, używając odrębnego na

  2. Pobierz wartość pola z rekordu, który powoduje, że warunek agregacji jest prawdziwy

  3. rekurencyjne zapytanie postgres na tej samej tabeli

  4. PgBouncer 1.7 – „Kolory różnią się po zmartwychwstaniu”

  5. Ustaw domyślną wartość zwracaną dla funkcji Postgres