PostgreSQL 9.1 eller nyere
format()
har en indbygget måde at undslippe identifikatorer. Enklere end før:
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;
Fungerer med en VALUES
udtryk også.
db<>spil her
Gamle sqlfiddle.
Vigtige punkter
- Brug
format()
ellerquote_ident()
at citere identifikatorer (automatisk og kun hvor det er nødvendigt), og dermed forsvare mod SQL-injektion og simple syntaksovertrædelser.
Dette er nødvendigt , selv med dine egne tabelnavne! - Skema-kvalificere tabelnavnet. Afhængigt af den aktuelle
search_path
indstilling af et blottet tabelnavn kan ellers løses til en anden tabel med samme navn i et andet skema. - Brug
EXECUTE
for dynamiske DDL-sætninger. - Bestå værdier sikkert med
USING
klausul. - Se den fine manual om udførelse af dynamiske kommandoer i plpgsql.
- Bemærk at
RETURN OLD;
i triggerfunktionen er påkrævet for en triggerBEFORE DELETE
. Detaljer i manualen her.
Du får fejlmeddelelsen i din næsten vellykkede version, fordi OLD
er ikke synlig inde i EXECUTE
. Og hvis du vil sammenkæde individuelle værdier af den dekomponerede række, som du prøvede, skal du forberede tekstrepræsentationen af hver enkelt kolonne med quote_literal()
for at garantere gyldig syntaks. Du skal også vide kolonnenavne på forhånd for at håndtere dem eller forespørge systemkatalogerne - hvilket står imod din idé om at have en simpel, dynamisk triggerfunktion ...
Min løsning undgår alle disse komplikationer. Også forenklet en smule.
PostgreSQL 9.0 eller tidligere
format()
er ikke tilgængelig endnu, så:
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;
Relateret:
- Hvordan bruger man TG_TABLE_NAME dynamisk i PostgreSQL 8.2?