sql >> Databasteknik >  >> RDS >> PostgreSQL

INSERT med dynamiskt tabellnamn i triggerfunktion

PostgreSQL 9.1 eller senare

format() har ett inbyggt sätt att undkomma identifierare. Enklare än tidigare:

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;

Fungerar med en VALUES uttryck också.

db<>spela här
Gammal sqlfiddle.

Huvudpunkter

  • Använd format() eller quote_ident() att citera identifierare (automatiskt och endast när det är nödvändigt), och därmed försvara sig mot SQL-injektion och enkla syntaxbrott.
    Detta är nödvändigt , även med dina egna tabellnamn!
  • Schema-kvalificera tabellnamnet. Beroende på den aktuella search_path Att ställa in ett tabellnamn kan annars lösas till en annan tabell med samma namn i ett annat schema.
  • Använd EXECUTE för dynamiska DDL-satser.
  • Placera värden säkert med USING klausul.
  • Konsultera den fina handboken om exekvering av dynamiska kommandon i plpgsql.
  • Observera attRETURN OLD; i triggerfunktionen krävs för en trigger BEFORE DELETE . Detaljer i manualen här.

Du får felmeddelandet i din nästan framgångsrika version eftersom OLD är inte synlig inuti EXECUTE . Och om du vill sammanfoga individuella värden för den dekomponerade raden som du försökte, måste du förbereda textrepresentationen för varje enskild kolumn med quote_literal() för att garantera giltig syntax. Du måste också veta kolumnnamn i förväg för att hantera dem eller fråga i systemkatalogerna - vilket står emot din idé om att ha en enkel, dynamisk triggerfunktion ...

Min lösning undviker alla dessa komplikationer. Också lite förenklat.

PostgreSQL 9.0 eller tidigare

format() är inte tillgänglig än, 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;

Relaterat:

  • Hur använder man TG_TABLE_NAME dynamiskt i PostgreSQL 8.2?


  1. Tuning:Ett bra ställe att börja

  2. vad är materialiserade åsikter i oracle?

  3. Fråga som returnerar en hierarkisk lista över triggerhändelsetyper i SQL Server

  4. C#-parameteriserade frågor för Oracle - allvarlig och farlig bugg!