Pasar varios nombres de columna como una cadena concatenada para una ejecución dinámica requiere una descontaminación urgente. Sugiero un VARIADIC
parámetro de función en su lugar, con identificadores debidamente citados (usando quote_ident()
en este 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<>fiddle aquí
El especificador de formato %I
para format()
se ocupa de un soltero identificador Tienes que trabajar más para múltiples identificadores, especialmente para un número variable de 0-n identificadores. Esta implementación cita cada nombre de columna y solo agrega un ,
si se han pasado nombres de columna. Entonces funciona para cada entrada posible , incluso ninguna entrada en absoluto. Nota VARIADIC cols text[] = NULL
como último parámetro de entrada con NULL como valor predeterminado:
Relacionado:
¡Los nombres de las columnas distinguen entre mayúsculas y minúsculas en este contexto!
Llame para su ejemplo (¡importante!):
SELECT select_by_txt(10,32,33,'col1', 'col2');
Sintaxis alternativa:
SELECT select_by_txt(10,32,33, VARIADIC '{col1,col2}');
Llamada más reveladora, con un nombre en la tercera columna y una intención maliciosa (aunque fútil):
SELECT select_by_txt(10,32,33,'col1', 'col2', $$col3'); DROP TABLE table1;--$$);
Acerca de ese extraño nombre de la tercera columna y la inyección de SQL:
Acerca de VAIRADIC
parámetros:
- Devolver filas que coincidan con los elementos de la matriz de entrada en la función plpgsql
- Pasar múltiples valores en un solo parámetro
Usando un OUT
parámetro por simplicidad. Eso es totalmente opcional. Ver:
Lo que yo no hacer
Si realmente confía en que la entrada sea una lista correctamente formateada de 1 o más nombres de columna válidos en todo momento, y afirmó que...
podrías simplificar:
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$;
(¿Cómo puede estar tan seguro de que la entrada siempre será confiable?)