PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Tabellen- und Spaltennamen als Argumente in einer plpgsql-Funktion definieren?

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