函数参数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” (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |