sql >> Databasteknik >  >> RDS >> PostgreSQL

Definiera tabell- och kolumnnamn som argument i en plpgsql-funktion?

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



  1. T-SQL XOR-operatör

  2. Hur tar man bort en fil i PL/SQL?

  3. MySQL-strängbyte

  4. Fatalt fel:Oupptäckt undantag 'mysqli_sql_exception' med meddelandet 'Inget index används i fråga/förberedd sats'