A passagem de vários nomes de coluna como string concatenada para execução dinâmica requer urgentemente a descontaminação. Sugiro um
VARIADIC
parâmetro de função em vez disso, com identificadores corretamente citados (usando quote_ident()
nesse 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 aqui
O especificador de formato
%I
para formato()
lida com um único identificador. Você precisa trabalhar mais para vários identificadores, especialmente para um número variável de identificadores 0-n. Esta implementação cita cada nome de coluna e adiciona apenas um ,
se algum nome de coluna foi passado. Portanto, funciona para todas as entradas possíveis , mesmo sem nenhuma entrada. Nota VARIADIC cols text[] =NULL
como último parâmetro de entrada com NULL como valor padrão:Relacionado:
Os nomes das colunas diferenciam maiúsculas de minúsculas neste contexto!
Peça seu exemplo (importante!):
SELECT select_by_txt(10,32,33,'col1', 'col2');
Sintaxe alternativa:
SELECT select_by_txt(10,32,33, VARIADIC '{col1,col2}');
Chamada mais reveladora, com um nome de terceira coluna e intenção maliciosa (embora fútil):
SELECT select_by_txt(10,32,33,'col1', 'col2', $$col3'); DROP TABLE table1;--$$);
Sobre esse estranho nome de terceira coluna e injeção de SQL:
Sobre
VAIRADIC
parâmetros:- Retorna linhas correspondentes aos elementos do array de entrada na função plpgsql
- Passe vários valores em um único parâmetro
Usando um
OUT
parâmetro de simplicidade. Isso é totalmente opcional. Ver:O que eu não fazer
Se você realmente confia na entrada para ser uma lista devidamente formatada de 1 ou mais nomes de coluna válidos em todos os momentos - e você afirmou que ...
Você poderia 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$;
(Como você pode ter tanta certeza de que a entrada sempre será confiável?)