PostgreSQL 9.1 lub nowszy
format()
ma wbudowany sposób ucieczki identyfikatorów. Prostsze niż wcześniej:
CREATE OR REPLACE FUNCTION foo_before()
RETURNS trigger AS
$func$
BEGIN
EXECUTE format('INSERT INTO %I.%I SELECT $1.*'
, TG_TABLE_SCHEMA, TG_TABLE_NAME || 'shadow')
USING OLD;
RETURN OLD;
END
$func$ LANGUAGE plpgsql;
Działa z VALUES
również wyrażenie.
db<>graj tutaj
Stary sqlfiddle.
Główne punkty
- Użyj
format()
lubquote_ident()
cytować identyfikatory (automatycznie i tylko w razie potrzeby), chroniąc w ten sposób przed wstrzyknięciem SQL i prostymi naruszeniami składni.
Jest to konieczne , nawet z własnymi nazwami stołów! - Kwalifikacja schematu nazwy tabeli. W zależności od bieżącej
search_path
ustawienie samej nazwy tabeli może w inny sposób rozwiązać inną tabelę o tej samej nazwie w innym schemacie. - Użyj
EXECUTE
dla dynamicznych instrukcji DDL. - Przekaż wartości bezpiecznie z
USING
klauzula. - Zapoznaj się z doskonałą instrukcją wykonywania poleceń dynamicznych w plpgsql.
- Pamiętaj, że
RETURN OLD;
w funkcji wyzwalacza jest wymagane dla wyzwalaczaBEFORE DELETE
. Szczegóły w instrukcji tutaj.
Otrzymujesz komunikat o błędzie w Twojej prawie udanej wersji, ponieważ OLD
jest niewidoczny wewnątrz EXECUTE
. A jeśli chcesz połączyć poszczególne wartości rozłożonego wiersza, tak jak próbowałeś, musisz przygotować reprezentację tekstową każdej kolumny za pomocą quote_literal()
aby zagwarantować poprawną składnię. Trzeba by też wiedzieć nazwy kolumn wcześniej, aby je obsłużyć lub przeszukać katalogi systemowe - co stoi w sprzeczności z twoją ideą posiadania prostej, dynamicznej funkcji wyzwalania ...
Moje rozwiązanie pozwala uniknąć tych wszystkich komplikacji. Również nieco uproszczona.
PostgreSQL 9.0 lub starszy
format()
nie jest jeszcze dostępny, więc:
CREATE OR REPLACE FUNCTION foo_before()
RETURNS trigger AS
$func$
BEGIN
EXECUTE 'INSERT INTO ' || quote_ident(TG_TABLE_SCHEMA)
|| '.' || quote_ident(TG_TABLE_NAME || 'shadow')
|| ' SELECT $1.*'
USING OLD;
RETURN OLD;
END
$func$ LANGUAGE plpgsql;
Powiązane:
- Jak dynamicznie używać TG_TABLE_NAME w PostgreSQL 8.2?