PostgreSQL 9.1 ou posterior
format()
tem uma maneira interna de escapar de identificadores. Mais simples do 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 com um
VALUES
expressão também. db<>mexa aqui
Antigo sqlfiddle.
Pontos principais
- Usar
format()
ouquote_ident()
para citar identificadores (automaticamente e somente quando necessário), protegendo assim contra injeção de SQL e violações de sintaxe simples.
Isso é necessário , mesmo com seus próprios nomes de tabela! - Esquema-qualifique o nome da tabela. Dependendo do
search_path
atual definir um nome de tabela simples pode resolver para outra tabela com o mesmo nome em um esquema diferente. - Usar
EXECUTE
para instruções DDL dinâmicas. - Passe valores com segurança com o
USING
cláusula. - Consulte o bom manual sobre Executando Comandos Dinâmicos no plpgsql.
- Observe que
RETURN OLD;
na função de gatilho é necessário para um gatilhoBEFORE DELETE
. Detalhes no manual aqui.
Você recebe a mensagem de erro em sua versão quase bem-sucedida porque
OLD
está não visível dentro de EXECUTE
. E se você quiser concatenar valores individuais da linha decomposta como você tentou, você deve preparar a representação de texto de cada coluna com quote_literal()
para garantir uma sintaxe válida. Você também teria que saber nomes de colunas de antemão para manipulá-los ou consultar os catálogos do sistema - o que contraria sua ideia de ter uma função de gatilho simples e dinâmica ... Minha solução evita todas essas complicações. Também simplificou um pouco.
PostgreSQL 9.0 ou anterior
format()
ainda não está disponível, então: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:
- Como usar dinamicamente o TG_TABLE_NAME no PostgreSQL 8.2?