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_path
actual de lo contrario, establecer un nombre de tabla simple podría resolverse en otra tabla con el mismo nombre en un esquema diferente. - Utilice
EXECUTE
para sentencias DDL dinámicas. - Pasar valores de forma segura con el
USING
clá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?