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_path
Das Festlegen eines bloßen Tabellennamens könnte andernfalls zu einer anderen Tabelle mit demselben Namen in einem anderen Schema aufgelöst werden. - Verwenden Sie
EXECUTE
für dynamische DDL-Anweisungen. - Übergeben Sie Werte sicher mit
USING
Klausel. - 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 DELETE
benö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?