Du måste försvara dig mot SQL-injektion när du omvandlar användarinmatning till kod. Det inkluderar tabell- och kolumnnamn som kommer från systemkataloger eller från direkt användarinmatning. På så sätt förhindrar du också triviala undantag med icke-standardiserade identifierare. Det finns i princip tre inbyggda metoder:
1. format()
Första frågan, sanerad:
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()
kräver Postgres 9.1 eller senare. Använd den med %I
formatspecifikator.
Bara tabellnamnet kan vara tvetydigt. Du kanske måste ange schemanamnet för att undvika att fel tabell ändras av misstag. Relaterat:
- INSERT med dynamiskt tabellnamn i triggerfunktionen
- Hur påverkar sökvägen identifierarens upplösning och det "aktuella schemat"
Bortsett från:lägga till flera kolumner med en enda ALTER TABLE
kommandot är billigare.
2. regclass
Du kan också använda en cast till en registrerad klass (regclass
) för det speciella fallet med existerande tabellnamn. Eventuellt schemakvalificerad. Detta misslyckas omedelbart och graciöst för tabellnamn som inte är giltiga och synliga för den anropande användaren. Den första frågan sanerades med en cast till 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$;
Ring:
SELECT foo('table_name');
Eller:
SELECT foo('my_schema.table_name'::regclass);
Bortsett från:överväg att bara använda text
istället för varchar(20)
.
3. quote_ident()
Den andra frågan sanerades:
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$;
För flera sammanlänkningar/interpolationer, format()
är renare ...
Relaterade svar:
- Tabellnamn som en PostgreSQL-funktionsparameter
- Postgres-funktioner kontra förberedda frågor
Skiftlägeskänslig!
Tänk på att identifierare utan citattecken inte är gjuts till gemener här. När den används som identifierare i SQL [Postgres kastar automatiskt till gemener][7]. Men här skickar vi strängar för dynamisk SQL. När escaped som visat, CaMel-case-identifierare (som UserS
) kommer att bevaras genom dubbelcitation ("UserS"
), precis som andra icke-standardiserade namn som "name with space"
"SELECT"
etc. Därför är namn skiftlägeskänsliga i detta sammanhang.
Mitt råd är att endast använda juridiska gemener och aldrig oroa dig för det.
Bortsett från:enkla citattecken är för värden, dubbla citattecken är för identifierare. Se:
- https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS