PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come utilizzare l'input di testo come nome/i di colonna in una funzione Postgres?

Il passaggio di più nomi di colonna come stringa concatenata per l'esecuzione dinamica richiede urgentemente la decontaminazione. Suggerisco un VARIADIC parametro function invece, con identificatori opportunamente quotati (usando quote_ident() in questo caso):

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<>violino qui

L'identificatore di formato %I per format() tratta con un single identificatore. Devi impegnarti di più per più identificatori, in particolare per un numero variabile di identificatori 0-n. Questa implementazione cita ogni singolo nome di colonna e aggiunge solo un , se sono stati passati nomi di colonna. Quindi funziona per ogni possibile input , anche senza alcun input. Nota VARIADIC cols text[] = NULL come ultimo parametro di input con NULL come valore predefinito:

Correlati:

I nomi delle colonne fanno distinzione tra maiuscole e minuscole in questo contesto!

Chiama per il tuo esempio (importante!):

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

Sintassi alternativa:

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

Chiamata più rivelatrice, con un nome di terza colonna e intenti dannosi (sebbene futili):

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

A proposito di quella strana terza colonna nome e SQL injection:

Informazioni su VAIRADIC parametri:

Usando un OUT parametro per semplicità. È totalmente facoltativo. Vedi:

Cosa non fare

Se davvero, ti fidi davvero che l'input sia sempre un elenco formattato correttamente di 1 o più nomi di colonne validi - e hai affermato che ...

Potresti semplificare:

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

(Come puoi essere così sicuro che l'input sarà sempre affidabile?)