sql >> Database >  >> RDS >> PostgreSQL

INSERT met dynamische tabelnaam in triggerfunctie

PostgreSQL 9.1 of hoger

format() heeft een ingebouwde manier om aan identifiers te ontsnappen. Eenvoudiger dan voorheen:

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;

Werkt met een VALUES uitdrukking ook.

db<>viool hier
Oude sqlfiddle.

Belangrijkste punten

  • Gebruik format() of quote_ident() om identifiers te citeren (automatisch en alleen waar nodig), en zo te beschermen tegen SQL-injectie en eenvoudige syntaxisschendingen.
    Dit is noodzakelijk , zelfs met je eigen tafelnamen!
  • Schema-kwalificeer de tabelnaam. Afhankelijk van het huidige search_path het instellen van een kale tabelnaam kan anders worden omgezet in een andere tabel met dezelfde naam in een ander schema.
  • Gebruik EXECUTE voor dynamische DDL-instructies.
  • Geef waarden door veilig met de USING clausule.
  • Raadpleeg de goede handleiding over het uitvoeren van dynamische opdrachten in plpgsql.
  • Let opRETURN OLD; in de triggerfunctie is vereist voor een trigger BEFORE DELETE . Details in de handleiding hier.

U krijgt de foutmelding in uw bijna succesvolle versie omdat OLD is niet zichtbaar binnen EXECUTE . En als je individuele waarden van de ontlede rij wilt samenvoegen zoals je hebt geprobeerd, moet je de tekstrepresentatie van elke afzonderlijke kolom voorbereiden met quote_literal() om een ​​geldige syntaxis te garanderen. Je zou ook moeten weten kolomnamen vooraf om ze af te handelen of de systeemcatalogi te doorzoeken - wat indruist tegen uw idee van een eenvoudige, dynamische triggerfunctie ...

Mijn oplossing vermijdt al deze complicaties. Ook een beetje vereenvoudigd.

PostgreSQL 9.0 of eerder

format() is nog niet beschikbaar, dus:

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;

Gerelateerd:

  • Hoe dynamisch gebruik te maken van TG_TABLE_NAME in PostgreSQL 8.2?


  1. Batch meerdere select-instructies bij het aanroepen van Oracle vanuit ADO.NET

  2. Hoe MySQLdb gebruiken met Python en Django in OSX 10.6?

  3. Hoe Create Table DDL uit te voeren met IMMEDIATE UITVOEREN in Oracle Database

  4. CS50:LIKE-operator, variabele vervanging met % uitbreiding