Musíte se bránit vložení SQL kdykoli změníte uživatelský vstup na kód. To zahrnuje názvy tabulek a sloupců pocházející ze systémových katalogů nebo z přímého uživatelského vstupu. Předejdete tak i triviálním výjimkám s nestandardními identifikátory. V zásadě jsoutři vestavěné metody:
1. format()
1. dotaz, vyčištěno:
CREATE OR REPLACE FUNCTION foo(_t text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('
ALTER TABLE %I ADD COLUMN c1 varchar(20)
, ADD COLUMN c2 varchar(20)', _t);
END
$func$;
format()
vyžaduje Postgres 9.1 nebo novější. Použijte jej s %I
specifikátor formátu.
Samotný název tabulky může být nejednoznačný. Možná budete muset zadat název schématu, abyste se vyhnuli náhodné změně nesprávné tabulky. Související:
- INSERT s názvem dynamické tabulky ve funkci spouštění
- Jak parametr search_path ovlivňuje rozlišení identifikátoru a "aktuální schéma"
Stranou:přidání více sloupců s jedinou ALTER TABLE
příkaz je levnější.
2. regclass
Můžete také použít obsazení do registrované třídy (regclass
) pro zvláštní případ existující názvy tabulek. Volitelně kvalifikováno pro schéma. To selže okamžitě a bez chyb u názvů tabulek, které nejsou platné a viditelné pro volajícího uživatele. První dotaz byl vyčištěn přetypováním na regclass
:
CREATE OR REPLACE FUNCTION foo(_t regclass)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'ALTER TABLE ' || _t || ' ADD COLUMN c1 varchar(20)
, ADD COLUMN c2 varchar(20)';
END
$func$;
Volejte:
SELECT foo('table_name');
Nebo:
SELECT foo('my_schema.table_name'::regclass);
Stranou:zvažte použití pouze text
místo varchar(20)
.
3. quote_ident()
2. dotaz byl vyčištěn:
CREATE OR REPLACE FUNCTION foo(_t regclass, _c text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'UPDATE ' || _t -- sanitized with regclass
|| ' SET ' || quote_ident(_c) || ' = ''This is a test''';
END
$func$;
Pro vícenásobné zřetězení / interpolace použijte format()
je čistší ...
Související odpovědi:
- Název tabulky jako parametr funkce PostgreSQL
- Funkce Postgres vs. připravené dotazy
Rozlišují se malá a velká písmena!
Uvědomte si, že neuvedené identifikátory nejsou zde přehodit na malá písmena. Při použití jako identifikátor v SQL [Postgres přetypuje na malá písmena automaticky][7]. Ale tady předáváme řetězce pro dynamické SQL. Při escapování, jak je ukázáno, identifikátory CaMel-case (jako UserS
) budou zachovány dvojitými uvozovkami ("UserS"
), stejně jako ostatní nestandardní názvy jako "name with space"
"SELECT"
atd. U jmen se tedy v tomto kontextu rozlišují velká a malá písmena.
Moje stálá rada je používat výhradně legální malá písmena a nikdy si s tím nedělejte starosti.
Stranou:jednoduché uvozovky jsou pro hodnoty, dvojité uvozovky jsou pro identifikátory. Viz:
- https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS