PostgreSQL 9.1 nebo novější
format()
má vestavěný způsob, jak uniknout identifikátorům. Jednodušší než dříve:
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;
Pracuje s VALUES
výraz také.
db<>zde hrajte
Starý sqlfiddle.
Hlavní body
- Použijte
format()
neboquote_ident()
citovat identifikátory (automaticky a pouze tam, kde je to nutné), a bránit se tak před vkládáním SQL a jednoduchým porušením syntaxe.
To je nezbytné , dokonce i s vlastními názvy tabulek! - Uveďte název tabulky podle schématu. V závislosti na aktuální
search_path
nastavení holého názvu tabulky by se jinak mohlo převést na jinou tabulku se stejným názvem v jiném schématu. - Použijte
EXECUTE
pro dynamické příkazy DDL. - Předávejte hodnoty bezpečně pomocí
USING
doložka. - Prostudujte si podrobnou příručku o provádění dynamických příkazů v plpgsql.
- Všimněte si, že
RETURN OLD;
ve funkci spouštění je vyžadováno pro spouštěníBEFORE DELETE
. Podrobnosti v návodu zde.
Zobrazí se chybová zpráva ve vaší téměř úspěšné verzi, protože OLD
není vidět uvnitř EXECUTE
. A pokud chcete zřetězit jednotlivé hodnoty rozloženého řádku, jak jste to zkusili, musíte připravit textovou reprezentaci každého jednotlivého sloupce pomocí quote_literal()
aby byla zaručena platná syntaxe. Také byste to museli vědět názvy sloupců předem, abyste je mohli zpracovat nebo se dotazovat na systémové katalogy – což je v rozporu s vaší představou jednoduché, dynamické spouštěcí funkce...
Mé řešení se všem těmto komplikacím vyhne. Také trochu zjednodušené.
PostgreSQL 9.0 nebo starší
format()
zatím není k dispozici, takže:
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;
Související:
- Jak dynamicky používat TG_TABLE_NAME v PostgreSQL 8.2?