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()
oquote_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 che
RETURN OLD;
nella funzione trigger è richiesto per un triggerBEFORE 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?