PostgreSQL 9.1 o posterior
format() tiene una forma integrada de escapar de los 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;
Funciona con un VALUES expresión también.
db<>violín aquí
Antiguo sqlfiddle.
Puntos principales
- Usar
format()oquote_ident()para citar identificadores (automáticamente y solo cuando sea necesario), protegiendo así contra la inyección de SQL y violaciones de sintaxis simples.
Esto es necesario , ¡incluso con sus propios nombres de tabla! - Esquema:califique el nombre de la tabla. Dependiendo de la
search_pathactual de lo contrario, establecer un nombre de tabla simple podría resolverse en otra tabla con el mismo nombre en un esquema diferente. - Utilice
EXECUTEpara sentencias DDL dinámicas. - Pasar valores de forma segura con el
USINGcláusula. - Consulte el excelente manual sobre la ejecución de comandos dinámicos en plpgsql.
- Tenga en cuenta que
RETURN OLD;en la función de disparo es necesario para un disparoBEFORE DELETE. Detalles en el manual aquí.
Recibe el mensaje de error en su versión casi exitosa porque OLD es no 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 tendrías que saber nombres de columna 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 simple y dinámica...
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:
- ¿Cómo utilizar dinámicamente TG_TABLE_NAME en PostgreSQL 8.2?