postgresql triggers dynamic-sql plpgsql

postgresql - INSERT con el nombre de la tabla dinámica en la función de activación



triggers dynamic-sql (2)

PostgreSQL 9.1 o posterior

format() tiene una forma integrada de escaparse identificadores. Más simple que antes:

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.
Funciona con una expresión VALUES también.

Puntos principales

Obtiene el mensaje de error en su versión casi exitosa porque OLD no está visible dentro de EXECUTE . Y si desea concatenar valores individuales de la fila descompuesta como lo intentó, debe preparar la representación de texto de cada columna con quote_literal() para garantizar una sintaxis válida. También debería saber los nombres de las columnas de antemano para manejarlos o consultar los catálogos del sistema, lo que va en contra de su idea de tener una función de activación dinámica simple ...

Mi solución evita todas estas complicaciones. También simplificado un poco.

PostgreSQL 9.0 o anterior

format() aún no está disponible, así que:

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;

Relacionado:

No estoy seguro de cómo lograr algo como lo siguiente:

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;

Es decir, insertar valores en una tabla con un nombre generado dinámicamente.
Ejecutando el código anterior produce:

ERROR: relation "shadowname" does not exist LINE 1: INSERT INTO shadowname VALUES(OLD.*)

Parece sugerir que las variables no se expanden / permiten como nombres de tablas. No he encontrado ninguna referencia a esto en el manual de Postgres.

Ya he experimentado con EXECUTE así:

EXECUTE ''INSERT INTO '' || quote_ident(shadowname) || '' VALUES '' || OLD.*;

Pero sin suerte:

ERROR: syntax error at or near "," LINE 1: INSERT INTO personenshadow VALUES (1,sven,,,)

El tipo RECORD parece estar perdido: OLD.* Parece haberse convertido en cadena y reparado, lo que genera todo tipo de problemas de tipo (por ejemplo, valores NULL ).

¿Algunas ideas?


Acabo de tropezar con esto porque estaba buscando un desencadenador dinámico INSTEAD OF DELETE . Como agradecimiento por la pregunta y las respuestas, publicaré mi solución para 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;