微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

函数参数anyelement,PostgreSQL错误?

我没有看到这个实现中的错误

CREATE FUNCTION foo(anyelement) RETURNS SetoF int  AS $f$
    SELECT id FROM unnest(array[1,2,3]) t(id) 
    WHERE CASE WHEN (pg_typeof($1)::text)='integer' THEN $1::int>2 ELSE true END
$f$LANGUAGE sql IMMUTABLE;

SELECT * FROM foo(123); -- OK!
SELECT * FROM foo('test'::text); -- BUG

这是某种Postgresql错误还是对任何元素数据类型的非文档限制?

有趣:当被隔离时,CASE条款正常工作:

CREATE FUNCTION bar(anyelement) RETURNS boolean  AS $f$
   SELECT CASE WHEN (pg_typeof($1)::text)='integer' THEN $1::int>2;
 $f$LANGUAGE sql IMMUTABLE;

 SELECT bar('test'::text),bar(123),bar(1); -- works fine!

解决方法

您的问题是由于sql语句的计划方式. sql对数据类型非常严格. Postgres函数为多态伪类型ANYELEMENT提供了一些灵活性,但sql语句仍然是静态地使用给定类型进行规划.

虽然表达式$1 :: int> 2永远不会被执行,如果$1不是整数(你可以避免这种方式除以零),这无法避免在规划查询的早期阶段出现的语法错误.

您仍然可以使用您拥有的功能执行某些操作.使用无类型字符串文字

CREATE OR REPLACE FUNCTION foo(anyelement)
  RETURNS SetoF int AS
 $func$
   SELECT id FROM unnest(array[1,3]) id
   WHERE  CASE WHEN pg_typeof($1) = 'integer'::regtype
               THEN $1 > '2'  -- use a string literal!
               ELSE true END
$func$LANGUAGE sql IMMUTABLE;

这至少适用于所有字符和数字数据类型.字符串文字被强制转换为提供的数据类型.但对于“2”无效的其他数据类型,它仍然会失败.

值得注意的是,您的第二个示例不会触发语法错误.从我对Postgres 9.5的测试中可以看出,如果函数不是IMMUTABLE,则会触发语法错误,或者在FROM列表中调用set-returns函数(RETURNS SetoF …而不是RETURNS boolean):SELECT * FROM foo(而不是SELECT foo().对于可以内联的简单IMMUTABLE函数,似乎对查询规划的处理方式不同.

除此之外,使用:

pg_typeof($1) = 'integer'::regtype

代替:

(pg_typeof($1)::文本)= ‘整数’

这通常更好.每次强制转换常量而不是计算值总是更好.这也适用于类型名称的已知别名.

> PostgreSQL syntax error in parameterized query on “date $1”

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐