PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

INSERT com nome de tabela dinâmica na função de gatilho

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() ou quote_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 queRETURN OLD; na função de gatilho é necessário para um gatilho BEFORE 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?