PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

INSERT con il nome della tabella dinamica nella funzione trigger

PostgreSQL 9.1 o successivo

format() ha un modo integrato per sfuggire agli identificatori. Più semplice di prima:

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;

Funziona con un VALUES anche l'espressione.

db<>gioca qui
Vecchio sqlfiddle.

Punti principali

  • Usa format() o quote_ident() per citare gli identificatori (automaticamente e solo dove necessario), difendendosi così da SQL injection e semplici violazioni della sintassi.
    Questo è necessario , anche con i nomi dei tuoi tavoli!
  • Schema-qualifica il nome della tabella. A seconda del search_path corrente l'impostazione di un nome di tabella nuda potrebbe altrimenti risolversi in un'altra tabella con lo stesso nome in uno schema diverso.
  • Usa EXECUTE per istruzioni DDL dinamiche.
  • Passa valori in sicurezza con il USING clausola.
  • Consulta il manuale sull'esecuzione di comandi dinamici in plpgsql.
  • Nota cheRETURN OLD; nella funzione trigger è richiesto per un trigger BEFORE DELETE . Dettagli nel manuale qui.

Viene visualizzato il messaggio di errore nella tua versione quasi di successo perché OLD è non visibile dentro EXECUTE . E se vuoi concatenare i singoli valori della riga scomposta come hai provato, devi preparare la rappresentazione testuale di ogni singola colonna con quote_literal() per garantire una sintassi valida. Dovresti anche sapere i nomi delle colonne in anticipo per gestirli o interrogare i cataloghi di sistema, il che contrasta con la tua idea di avere una funzione trigger semplice e dinamica ...

La mia soluzione evita tutte queste complicazioni. Anche semplificato un po'.

PostgreSQL 9.0 o precedenti

format() non è ancora disponibile, quindi:

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;

Correlati:

  • Come utilizzare dinamicamente TG_TABLE_NAME in PostgreSQL 8.2?