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:
- Restituisce le righe corrispondenti agli elementi dell'array di input nella funzione plpgsql
- Passa più valori in un singolo parametro
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?)