sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur använder man textinmatning som kolumnnamn i en Postgres-funktion?

Att skicka flera kolumnnamn som sammanlänkade strängar för dynamisk exekvering kräver akut dekontaminering. Jag föreslår en VARIADIC funktionsparameter istället, med korrekt citerade identifierare (med quote_ident() i det här fallet):

CREATE OR REPLACE FUNCTION select_by_txt(z int, x int, y int, VARIADIC cols text[] = NULL, OUT res text)
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format(
$$
SELECT ST_AsMVT(mvtgeom, 'public.select_by_txt')
FROM  (
   SELECT ST_AsMVTGeom(ST_Transform(t.geom, 3857), bounds.geom) AS geom%s
   FROM   table1 t
   JOIN  (SELECT ST_TileEnvelope($1, $2, $3)) AS bounds(geom)
          ON ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))
   ) mvtgeom
$$, (SELECT ', ' || string_agg(quote_ident (col), ', ') FROM unnest(cols) col)
   )
   INTO  res
   USING z, x, y;
END
$func$;

db<>fiol här

Formatspecifikationen %I för format() handlar om en singel identifierare. Du måste lägga ner mer arbete för flera identifierare, speciellt för ett variabelt antal 0-n identifierare. Denna implementering citerar varje enskilt kolumnnamn och lägger bara till en , om några kolumnnamn har passerats. Så det fungerar för alla möjliga indata , även ingen input alls. Notera VARIADIC cols text[] =NULL som sista indataparameter med NULL som standardvärde:

Relaterat:

Kolumnnamn är skiftlägeskänsliga i detta sammanhang!

Ring för ditt exempel (viktigt!):

SELECT select_by_txt(10,32,33,'col1', 'col2');

Alternativ syntax:

SELECT select_by_txt(10,32,33, VARIADIC '{col1,col2}');

Mer avslöjande samtal, med ett tredje kolumnnamn och skadliga (men meningslösa) avsikter:

SELECT select_by_txt(10,32,33,'col1', 'col2', $$col3'); DROP TABLE table1;--$$);

Om det udda tredje kolumnnamnet och SQL-injektion:

Om VAIRADIC parametrar:

Använda en OUT parameter för enkelhetens skull. Det är helt valfritt. Se:

Vad jag inte skulle gör

Om du verkligen, verkligen litar på att indata är en korrekt formaterad lista med 1 eller flera giltiga kolumnnamn hela tiden - och du hävdade att ...

Du kunde förenkla:

CREATE OR REPLACE FUNCTION select_by_txt(z int, x int, y int, cols text, OUT res text)
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format(
$$
SELECT ST_AsMVT(mvtgeom, 'public.select_by_txt')
FROM  (
   SELECT ST_AsMVTGeom(ST_Transform(t.geom, 3857), bounds.geom) AS geom, %s
   FROM   table1 t
   JOIN  (SELECT ST_TileEnvelope($1, $2, $3)) AS bounds(geom)
          ON ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))
   ) mvtgeom
$$, cols
   )
   INTO  res
   USING z, x, y;
END
$func$;

(Hur kan du vara så säker på att indata alltid kommer att vara tillförlitlig?)



  1. Välj alla utom den senaste raden

  2. Exportera din databas för överföring

  3. Trigger kontra kontrollbegränsning

  4. Hur man anropar proceduren utan parameter som tabelltyp från en Java-klass