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

Wie verwende ich Texteingaben als Spaltennamen in einer Postgres-Funktion?

Das Übergeben mehrerer Spaltennamen als verkettete Zeichenfolge zur dynamischen Ausführung erfordert dringend eine Dekontaminierung. Ich schlage einen VARIADIC Funktionsparameter stattdessen mit korrekt in Anführungszeichen gesetzten Bezeichnern (unter Verwendung von quote_ident() in diesem Fall):

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<>fiddle hier

Der Formatbezeichner %I für format() befasst sich mit einer Single Kennung. Für mehrere müssen Sie mehr Arbeit investieren Identifikatoren, insbesondere für eine variable Anzahl von 0-n Identifikatoren. Diese Implementierung zitiert jeden einzelnen Spaltennamen und fügt nur einen , hinzu ob irgendwelche Spaltennamen übergeben wurden. Es funktioniert also für jede mögliche Eingabe , sogar überhaupt keine Eingabe. Beachten Sie VARIADIC cols text[] =NULL als letzter Eingabeparameter mit NULL als Standardwert:

Verwandte:

Bei Spaltennamen muss in diesem Zusammenhang zwischen Groß- und Kleinschreibung unterschieden werden!

Fordern Sie Ihr Beispiel an (wichtig!):

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

Alternative Syntax:

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

Aufschlussreicherer Aufruf mit einem dritten Spaltennamen und böswilliger (wenn auch vergeblicher) Absicht:

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

Über diesen seltsamen dritten Spaltennamen und die SQL-Injektion:

Über VAIRADIC Parameter:

Mit einem OUT Parameter der Einfachheit halber. Das ist völlig optional. Siehe:

Was ich nicht tun würde tun

Wenn Sie wirklich, wirklich darauf vertrauen, dass die Eingabe zu jeder Zeit eine richtig formatierte Liste von 1 oder mehr gültigen Spaltennamen ist - und Sie haben behauptet, dass ...

Sie könnten vereinfachen:

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

(Wie können Sie so sicher sein, dass die Eingabe immer zuverlässig ist?)