Sie müssen sich gegen SQL-Injection wehren wenn Sie Benutzereingaben in Code umwandeln. Dazu gehören Tabellen- und Spaltennamen, die aus Systemkatalogen oder aus direkter Benutzereingabe stammen. Auf diese Weise verhindern Sie auch triviale Ausnahmen mit nicht standardmäßigen Bezeichnern. Im Grunde sind es drei eingebaute Methoden:
1. format()
Erste Abfrage, bereinigt:
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()
erfordert Postgres 9.1 oder höher. Verwenden Sie es mit %I
Formatbezeichner.
Der Tabellenname allein kann mehrdeutig sein. Möglicherweise müssen Sie den Schemanamen angeben, um zu vermeiden, dass versehentlich die falsche Tabelle geändert wird. Verwandte:
- INSERT mit dynamischem Tabellennamen in Triggerfunktion
- Wie beeinflusst der Suchpfad die Identifikatorauflösung und das "aktuelle Schema"
Nebenbei:mehrere Spalten hinzufügen mit einem einzigen ALTER TABLE
Befehl ist billiger.
2. regclass
Sie können auch eine Umwandlung in eine registrierte Klasse (regclass
) für den Sonderfall vorhanden Tabellennamen. Optional schemaqualifiziert. Dies schlägt sofort und problemlos für Tabellennamen fehl, die nicht gültig und für den aufrufenden Benutzer sichtbar sind. Die erste Abfrage wurde mit einer Umwandlung in regclass
bereinigt :
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$;
Aufruf:
SELECT foo('table_name');
Oder:
SELECT foo('my_schema.table_name'::regclass);
Abgesehen davon:Erwägen Sie, nur text
zu verwenden statt varchar(20)
.
3. quote_ident()
Die 2. Abfrage bereinigt:
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 mehrfache Verkettungen / Interpolationen format()
ist sauberer ...
Verwandte Antworten:
- Tabellenname als PostgreSQL-Funktionsparameter
- Postgres-Funktionen im Vergleich zu vorbereiteten Abfragen
Groß-/Kleinschreibung beachten!
Beachten Sie, dass Bezeichner ohne Anführungszeichen nicht sind hier in Kleinbuchstaben umwandeln. Bei Verwendung als Bezeichner in SQL [Postgres wandelt automatisch in Kleinbuchstaben um] [7]. Aber hier übergeben wir Strings für dynamisches SQL. Wenn wie gezeigt maskiert, werden CaMel-Case-Bezeichner (wie UserS
) werden durch doppelte Anführungszeichen ("UserS"
) beibehalten ), genau wie andere Nicht-Standard-Namen wie "name with space"
"SELECT"
usw. Daher wird bei Namen in diesem Zusammenhang zwischen Groß- und Kleinschreibung unterschieden.
Mein ständiger Rat ist, ausschließlich legale Kleinbuchstaben zu verwenden und sich darüber keine Gedanken zu machen.
Übrigens:Einfache Anführungszeichen stehen für Werte, doppelte Anführungszeichen für Bezeichner. Siehe:
- https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS