Je ne suis pas sûr de savoir comment réaliser quelque chose comme ceci:
CREATE OR REPLACE FUNCTION fnJobQueueBEFORE() RETURNS trigger AS $$
DECLARE
shadowname varchar := TG_TABLE_NAME || 'shadow';
BEGIN
INSERT INTO shadowname VALUES(OLD.*);
RETURN OLD;
END;
$$
LANGUAGE plpgsql;
C'est à dire. insertion de valeurs dans une table avec un nom généré dynamiquement.
L’exécution du code ci-dessus donne:
ERROR: relation "shadowname" does not exist
LINE 1: INSERT INTO shadowname VALUES(OLD.*)
Il semble suggérer que les variables ne sont pas développées/autorisées en tant que noms de table. Je n'ai trouvé aucune référence à cela dans le manuel de Postgres.
J'ai déjà expérimenté avec EXECUTE
comme ceci:
EXECUTE 'INSERT INTO ' || quote_ident(shadowname) || ' VALUES ' || OLD.*;
Mais pas de chance:
ERROR: syntax error at or near ","
LINE 1: INSERT INTO personenshadow VALUES (1,sven,,,)
Le type RECORD
semble être perdu: OLD.*
semble avoir été converti en une chaîne et obtenir une reparation, générant toutes sortes de problèmes de type (par exemple, les valeurs NULL
).
Des idées?
format()
a un moyen intégré pour é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;
SQL Fiddle.
Fonctionne également avec une expression VALUES
.
quote_ident()
pour citer des identificateurs, le cas échéant, et vous défendre contre injection SQL .search_path
actuel , un nom de table nu peut sinon être résolu en une autre table du même nom dans un schéma différent.EXECUTE
pour les instructions DDL dynamiques.USING
.RETURN OLD;
dans la fonction de déclenchement est requis pour un déclencheur BEFORE DELETE
. Détails dans le manuel ici.Vous obtenez le message error dans votre version presque réussie car OLD
est non visible dans EXECUTE
. Et si vous souhaitez concaténer les 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 devez également connaître nom de colonne à l'avance pour pouvoir les manipuler ou interroger les catalogues système - ce qui va à l'encontre de votre idée de disposer d'une fonction de déclenchement simple et dynamique ...
Ma solution évite toutes ces complications. Aussi simplifié un peu.
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;
En relation:
Je suis tombé sur cela parce que je cherchais un déclencheur dynamique INSTEAD OF DELETE
. En guise de remerciement pour la question et les réponses, je posterai ma solution pour Postgres 9.3.
CREATE OR REPLACE FUNCTION set_deleted_instead_of_delete()
RETURNS TRIGGER AS $$
BEGIN
EXECUTE format('UPDATE %I set deleted = now() WHERE id = $1.id', TG_TABLE_NAME)
USING OLD;
RETURN NULL;
END;
$$ language plpgsql;