PostgreSQL 9.1 ou version ultérieure
format()
a un moyen intégré d'échapper aux identifiants. Plus simple qu'avant :
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;
Fonctionne avec un VALUES
expression également.
db<>jouez ici
Vieux sqlfiddle.
Points majeurs
- Utilisez
format()
ouquote_ident()
pour citer les identifiants (automatiquement et uniquement si nécessaire), se défendant ainsi contre l'injection SQL et les simples violations de syntaxe.
C'est nécessaire , même avec vos propres noms de table ! - Schéma-qualifie le nom de la table. En fonction du
search_path
actuel la définition d'un nom de table simple pourrait sinon être résolue en une autre table du même nom dans un schéma différent. - Utilisez
EXECUTE
pour les instructions DDL dynamiques. - Transmettre des valeurs en toute sécurité avec le
USING
clause. - Consultez le bon manuel sur l'exécution des commandes dynamiques dans plpgsql.
- Notez que
RETURN OLD;
dans la fonction trigger est requis pour un triggerBEFORE DELETE
. Détails dans le manuel ici.
Vous obtenez le message d'erreur dans votre version presque réussie car OLD
n'est pas visible dans EXECUTE
. Et si vous voulez concaténer des valeurs individuelles de la ligne décomposée comme vous l'avez essayé, vous devez préparer la représentation textuelle de chaque colonne avec quote_literal()
pour garantir une syntaxe valide. Vous devriez également savoir noms de colonnes au préalable pour les manipuler ou interroger les catalogues système - ce qui va à l'encontre de votre idée d'avoir une fonction de déclenchement simple et dynamique...
Ma solution évite toutes ces complications. Aussi simplifié un peu.
PostgreSQL 9.0 ou version antérieure
format()
n'est pas encore disponible, donc :
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;
Connexe :
- Comment utiliser dynamiquement TG_TABLE_NAME dans PostgreSQL 8.2 ?