我没有看到这个实现中的错误:
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”
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。