我有两根弦:
以及值,例如“a”。
我需要调用函数
UPPER
(由两个字符串合成)并将值作为参数传递。实际上,我需要将函数
crosstab()
与列计数器连接起来......
使用动态 SQL 的函数的存根可能如下所示:
CREATE OR REPLACE FUNCTION f_exec(text, text, text, OUT result text)
RETURNS text
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'SELECT ' || $1 || $2 || '($1)' -- last ($1) not a reference to func param
INTO result
USING $3;
END
$func$;
致电:
SELECT f_exec('up', 'per', 'a')
不要混淆,
$1
在EXECUTE
内部有自己的作用域,指的是USING
子句传入的参数,而不是外部函数参数。
上面对动态 SQL 的幼稚使用会导致 SQL 注入!
阅读有关 dba.SE 的相关问题下的建议以及手册中“安全地编写
SECURITY DEFINER
函数”章节。
在这种特殊情况下,有一个聪明的方法可以避免 SQLi:
CREATE OR REPLACE FUNCTION f_exec(func1 text, func2 text, param text
, OUT result text)
LANGUAGE plpgsql AS
$func$
DECLARE
funcname text := (func1 || func2)::regproc;
BEGIN
EXECUTE 'SELECT ' || funcname || '($1)::text'
INTO result
USING param;
END
$func$;
转换为对象标识符类型
regproc
有效地排除了通过$1
和$2
注入除有效函数名称之外的任何内容的尝试。 USING
子句已经中和了通过 $3
(param
) 注入代码的尝试。
还有:
RETURNING
子句,因为 OUT
参数会处理它。text
,因为我们不知道函数的实际返回类型,并且 Postgres 中的每个数据类型都可以转换为 text
。IN
类型的单个 text
参数,否则会出现异常。