PostgreSQL 9.1 oder höher
format() hat eine eingebaute Möglichkeit, Bezeichner zu maskieren. Einfacher als zuvor:
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;
Funktioniert mit einem VALUES auch Ausdruck.
db<>hier fummeln
Altes sqlfiddle.
Wichtige Punkte
- Verwenden Sie
format()oderquote_ident()Bezeichner zu zitieren (automatisch und nur dort, wo es notwendig ist) und sich so gegen SQL-Injection und einfache Syntaxverletzungen zu wehren.
Das ist notwendig , sogar mit eigenen Tabellennamen! - Schemaqualifizieren Sie den Tabellennamen. Abhängig vom aktuellen
search_pathDas Festlegen eines bloßen Tabellennamens könnte andernfalls zu einer anderen Tabelle mit demselben Namen in einem anderen Schema aufgelöst werden. - Verwenden Sie
EXECUTEfür dynamische DDL-Anweisungen. - Übergeben Sie Werte sicher mit
USINGKlausel. - Konsultieren Sie das feine Handbuch zum Ausführen dynamischer Befehle in plpgsql.
- Beachten Sie, dass
RETURN OLD;in der Triggerfunktion wird für einen TriggerBEFORE DELETEbenötigt . Details im Handbuch hier.
Sie erhalten die Fehlermeldung in Ihrer fast erfolgreichen Version, weil OLD ist nicht sichtbar innerhalb von EXECUTE . Und wenn Sie einzelne Werte der zerlegten Zeile so verketten möchten, wie Sie es versucht haben, müssen Sie die Textdarstellung jeder einzelnen Spalte mit quote_literal() vorbereiten um eine gültige Syntax zu gewährleisten. Sie müssten es auch wissen Spaltennamen vorher zu bearbeiten oder die Systemkataloge abzufragen - was Ihrer Vorstellung einer einfachen, dynamischen Triggerfunktion widerspricht ...
Meine Lösung vermeidet all diese Komplikationen. Auch etwas vereinfacht.
PostgreSQL 9.0 oder früher
format() ist noch nicht verfügbar, also:
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;
Verwandte:
- Wie verwende ich TG_TABLE_NAME dynamisch in PostgreSQL 8.2?