如何在 Postgres 函数中使用文本输入作为列名?
How to use text input as column name(s) in a Postgres function?
我正在使用 Postgres 和 PostGIS。尝试编写一个根据给定参数选择特定列的函数。
我使用 WITH
语句创建结果 table,然后将其转换为 bytea
到 return。
我需要帮助的部分是 </code> 部分 </strong>。我试过它在下面演示并且 <code>::text
都给我返回输入的文本值而不是 table 中的列值 if cols=name
所以我从查询名称中返回并且不是 table 中的实际名称。我也尝试 data()
并遇到类型错误。
代码是这样的:
CREATE OR REPLACE FUNCTION select_by_txt(z integer,x integer,y integer, cols text)
RETURNS bytea
LANGUAGE 'plpgsql'
AS $BODY$
declare
res bytea;
begin
WITH bounds AS (
SELECT ST_TileEnvelope(z, x, y) AS geom
),
mvtgeom AS (
SELECT ST_AsMVTGeom(ST_Transform(t.geom, 3857), bounds.geom) AS geom,
FROM table1 t, bounds
WHERE ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))
)
SELECT ST_AsMVT(mvtgeom, 'public.select_by_txt')
INTO res
FROM mvtgeom;
RETURN res;
end;
$BODY$;
函数调用示例:
select_by_txt(10,32,33,"col1,col2")
参数cols可以是从1开始的多个列名,不受上面限制。 cols
中的列名称将在调用函数之前检查它们是否为有效列。
您需要使用 dynamic 查询:
CREATE OR REPLACE FUNCTION select_by_txt(z integer,x integer,y integer, cols text)
RETURNS bytea
LANGUAGE 'plpgsql'
AS $BODY$
declare
res bytea;
begin
EXECUTE format('
WITH bounds AS (
SELECT ST_TileEnvelope(, , ) AS geom
),
mvtgeom AS (
SELECT ST_AsMVTGeom(ST_Transform(t.geom, 3857), bounds.geom) AS geom, %I
FROM table1 t, bounds
WHERE ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))
)
SELECT ST_AsMVT(mvtgeom, ''public.select_by_txt'')
FROM mvtgeom', cols)
INTO res
USING z,x,y;
RETURN res;
end;
$BODY$;
将多个列名作为连接字符串传递以进行动态执行迫切需要净化。我建议使用 VARIADIC
函数参数,并使用正确引用的标识符(在这种情况下使用 quote_ident()
):
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(, , )) 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 here
format()
的格式说明符 %I
处理 单个 标识符。您必须为 多个 标识符投入更多工作,尤其是对于可变数量的 0-n 标识符。此实现引用每个列名,并且仅在传递了任何列名时才添加 ,
。所以它适用于所有可能的输入,甚至根本没有输入。注意 VARIADIC cols text[] = NULL
作为最后一个输入参数,默认值为 NULL:
- Optional argument in PL/pgSQL function
相关:
在此上下文中,列名区分大小写!
征集你的例子(重要!):
SELECT select_by_txt(10,32,33,'col1', 'col2');
替代语法:
SELECT select_by_txt(10,32,33, VARIADIC '{col1,col2}');
更暴露的调用,带有第三列名称和恶意(虽然徒劳)意图:
SELECT select_by_txt(10,32,33,'col1', 'col2', $$col3'); DROP TABLE table1;--$$);
关于那个奇怪的第三列名称和 SQL 注入:
关于VAIRADIC
参数:
- Return rows matching elements of input array in plpgsql function
- Pass multiple values in single parameter
为简单起见,使用 OUT
参数。这完全是可选的。参见:
- Returning from a function with OUT parameter
我会不会做什么
如果您真的非常相信输入始终是 1 个或多个有效列名的格式正确的列表 - 并且您断言...
the names of the columns inside cols will be checked before calling the function that they are valid columns
你可以简化:
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(, , )) AS bounds(geom)
ON ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))
) mvtgeom
$$, cols
)
INTO res
USING z, x, y;
END
$func$;
(你怎么能确定输入总是可靠的?)
我正在使用 Postgres 和 PostGIS。尝试编写一个根据给定参数选择特定列的函数。
我使用 WITH
语句创建结果 table,然后将其转换为 bytea
到 return。
我需要帮助的部分是 </code> 部分 </strong>。我试过它在下面演示并且 <code>::text
都给我返回输入的文本值而不是 table 中的列值 if cols=name
所以我从查询名称中返回并且不是 table 中的实际名称。我也尝试 data()
并遇到类型错误。
代码是这样的:
CREATE OR REPLACE FUNCTION select_by_txt(z integer,x integer,y integer, cols text)
RETURNS bytea
LANGUAGE 'plpgsql'
AS $BODY$
declare
res bytea;
begin
WITH bounds AS (
SELECT ST_TileEnvelope(z, x, y) AS geom
),
mvtgeom AS (
SELECT ST_AsMVTGeom(ST_Transform(t.geom, 3857), bounds.geom) AS geom,
FROM table1 t, bounds
WHERE ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))
)
SELECT ST_AsMVT(mvtgeom, 'public.select_by_txt')
INTO res
FROM mvtgeom;
RETURN res;
end;
$BODY$;
函数调用示例:
select_by_txt(10,32,33,"col1,col2")
参数cols可以是从1开始的多个列名,不受上面限制。 cols
中的列名称将在调用函数之前检查它们是否为有效列。
您需要使用 dynamic 查询:
CREATE OR REPLACE FUNCTION select_by_txt(z integer,x integer,y integer, cols text)
RETURNS bytea
LANGUAGE 'plpgsql'
AS $BODY$
declare
res bytea;
begin
EXECUTE format('
WITH bounds AS (
SELECT ST_TileEnvelope(, , ) AS geom
),
mvtgeom AS (
SELECT ST_AsMVTGeom(ST_Transform(t.geom, 3857), bounds.geom) AS geom, %I
FROM table1 t, bounds
WHERE ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))
)
SELECT ST_AsMVT(mvtgeom, ''public.select_by_txt'')
FROM mvtgeom', cols)
INTO res
USING z,x,y;
RETURN res;
end;
$BODY$;
将多个列名作为连接字符串传递以进行动态执行迫切需要净化。我建议使用 VARIADIC
函数参数,并使用正确引用的标识符(在这种情况下使用 quote_ident()
):
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(, , )) 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 here
format()
的格式说明符 %I
处理 单个 标识符。您必须为 多个 标识符投入更多工作,尤其是对于可变数量的 0-n 标识符。此实现引用每个列名,并且仅在传递了任何列名时才添加 ,
。所以它适用于所有可能的输入,甚至根本没有输入。注意 VARIADIC cols text[] = NULL
作为最后一个输入参数,默认值为 NULL:
- Optional argument in PL/pgSQL function
相关:
在此上下文中,列名区分大小写!
征集你的例子(重要!):
SELECT select_by_txt(10,32,33,'col1', 'col2');
替代语法:
SELECT select_by_txt(10,32,33, VARIADIC '{col1,col2}');
更暴露的调用,带有第三列名称和恶意(虽然徒劳)意图:
SELECT select_by_txt(10,32,33,'col1', 'col2', $$col3'); DROP TABLE table1;--$$);
关于那个奇怪的第三列名称和 SQL 注入:
关于VAIRADIC
参数:
- Return rows matching elements of input array in plpgsql function
- Pass multiple values in single parameter
为简单起见,使用 OUT
参数。这完全是可选的。参见:
- Returning from a function with OUT parameter
我会不会做什么
如果您真的非常相信输入始终是 1 个或多个有效列名的格式正确的列表 - 并且您断言...
the names of the columns inside cols will be checked before calling the function that they are valid columns
你可以简化:
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(, , )) AS bounds(geom)
ON ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))
) mvtgeom
$$, cols
)
INTO res
USING z, x, y;
END
$func$;
(你怎么能确定输入总是可靠的?)