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_pathatual definir um nome de tabela simples pode resolver para outra tabela com o mesmo nome em um esquema diferente. - Usar
EXECUTEpara instruções DDL dinâmicas. - Passe valores com segurança com o
USINGclá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?