sql >> Database >  >> RDS >> PostgreSQL

Tabel- en kolomnamen definiëren als argumenten in een plpgsql-functie?

U moet zich verdedigen tegen SQL-injectie telkens wanneer u gebruikersinvoer in code omzet. Dat geldt ook voor tabel- en kolomnamen die afkomstig zijn uit systeemcatalogi of uit directe gebruikersinvoer. Zo voorkom je ook triviale uitzonderingen met niet-standaard identifiers. Er zijn in principe drie ingebouwde methoden:

1. format()

1e vraag, opgeschoond:

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() vereist Postgre 9.1 of hoger. Gebruik het met de %I formaatspecificatie.

Alleen de tabelnaam kan dubbelzinnig zijn. Mogelijk moet u de schemanaam opgeven om te voorkomen dat u per ongeluk de verkeerde tabel wijzigt. Gerelateerd:

  • INSERT met dynamische tabelnaam in triggerfunctie
  • Hoe beïnvloedt het zoekpad de resolutie van de ID en het "huidige schema"

Terzijde:het toevoegen van meerdere kolommen met een enkele ALTER TABLE commando is goedkoper.

2. regclass

Je kunt ook een cast gebruiken voor een geregistreerde klas (regclass ) voor het speciale geval van bestaande tafel namen. Optioneel schema-gekwalificeerd. Dit mislukt onmiddellijk en netjes voor tabelnamen die niet geldig en zichtbaar zijn voor de aanroepende gebruiker. De eerste vraag is opgeschoond met een cast naar 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$;

Bel:

SELECT foo('table_name');

Of:

SELECT foo('my_schema.table_name'::regclass);

Terzijde:overweeg om alleen text te gebruiken in plaats van varchar(20) .

3. quote_ident()

De 2e vraag opgeschoond:

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$;

Voor meerdere aaneenschakelingen / interpolaties, format() is schoner ...

Gerelateerde antwoorden:

  • Tabelnaam als een PostgreSQL-functieparameter
  • Postgres-functies versus voorbereide zoekopdrachten

Hoofdlettergevoelig!

Houd er rekening mee dat ID's zonder aanhalingstekens niet . zijn hier in kleine letters gegoten. Bij gebruik als identifier in SQL [Postgres cast automatisch naar kleine letters][7]. Maar hier passeren we strings voor dynamische SQL. Wanneer ontsnapt, zoals aangetoond, CaMel-case-ID's (zoals UserS ) worden bewaard door dubbele aanhalingstekens ("UserS" ), net als andere niet-standaard namen zoals "name with space" "SELECT" enz. Daarom zijn namen in deze context hoofdlettergevoelig.

Mijn vaste advies is om uitsluitend juridische identificatiecodes in kleine letters te gebruiken en u daar nooit zorgen over te maken.

Terzijde:enkele aanhalingstekens zijn voor waarden, dubbele aanhalingstekens zijn voor identifiers. Zie:

  • https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS



  1. Oracle JDeveloper gebruiken met MySQL Database Service op Oracle Cloud Platform, deel 3

  2. Onderhoudsplannen voor databases maken

  3. PostgreSQL implementeren voor hoge beschikbaarheid

  4. MySQL AANTAL ONDERSCHEIDEN