从串联字符串调用函数

时间:2013-02-05 17:02:26

标签: sql postgresql plpgsql dynamic-sql

我有两个字符串:

  • 'UPP'
  • 'ER'

值,例如'a'。

我需要调用函数UPPER(从两个字符串合成)并将值作为参数传递 我怎么能这样做?

(实际上,我需要将函数交叉表与列的计数器连接起来...)

1 个答案:

答案 0 :(得分:2)

使用动态SQL的函数的存根可能如下所示:

CREATE OR REPLACE FUNCTION f_exec(text, text, text, OUT result text)
  RETURNS text AS
$func$
BEGIN
    EXECUTE 'SELECT ' || $1  || $2 || '($1)' -- last $1 not referring func param
    INTO   result
    USING  $3;
END
$func$ LANGUAGE plpgsql;

呼叫:

SELECT f_exec('up', 'per', 'a')

不要混淆,$1EXECUTE内有自己的作用域,并引用USING子句传入的参数,而不是外部函数参数。

手册中this related answer或章节Executing Dynamic Commands中的更多背景信息。

警告

这为您打开了 SQL注入
阅读this related question on dba.SE下的建议以及手册中的"Writing SECURITY DEFINER Functions Safely"章节。

在这种特殊情况下,有一种智能方式来避免SQLi

CREATE OR REPLACE FUNCTION f_exec(
   func1 text
  ,func2 text
  ,param text
  ,OUT result text) AS
$func$
DECLARE
   funcname text := (func1 || func2)::regproc;
BEGIN
   EXECUTE 'SELECT ' || funcname || '($1)::text'
   INTO   result
   USING  param;
END
$func$ LANGUAGE plpgsql;

object identifier type regproc的强制转换有效地清除了所有尝试通过$1$2注入除有效函数名称之外的任何内容。 USING子句已经中和了通过$3param)注入代码的尝试。

此外:

  • 使用参数名称可以减少混淆。
  • 从函数定义中省略RETURNING子句,因为OUT参数负责处理它。
  • 将函数的结果转换为text,因为我们不知道函数的实际返回类型,并且Postgres中的每个数据类型都可以转换为text
    该函数仍然需要接受IN类型的text个参数,否则会出现异常。