sql - 函数参数anyelement,PostgreSQL bug?

标签 sql postgresql types query-planner polymorphic-functions

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

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 错误还是对 anyelement 数据类型的未记录限制?


有趣的是: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 提供了一定的灵 active ,但 SQL 语句仍然使用给定的类型进行静态规划。

如果$1 不是整数,则表达式$1::int>2 永远不会执行(您可以通过这种方式避免被零除),这不能使您免于在查询的早期规划阶段出现的语法错误。

你仍然可以用你拥有的功能做一些事情。使用未类型化的字符串文字:

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

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

您的第二个示例没有触发语法错误,这值得注意。从我对 Postgres 9.5 的测试中可以看出,如果函数不是 IMMUTABLE 或设置返回函数(RETURNS SETOF ... 而不是 ,则会触发语法错误>RETURNS boolean) 在 FROM 列表中调用:SELECT * FROM foo() 而不是 SELECT foo()。对于可以内联的简单 IMMUTABLE 函数,查询计划的处理方式似乎有所不同。


除此之外,使用:

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

代替:

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

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

关于sql - 函数参数anyelement,PostgreSQL bug?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36025889/

相关文章:

postgresql - 如何使用 psql 命令列出、创建、使用和检查数据库?

postgresql - 将空值插入 postgresql 中的 inet 字段

sql - 当我在 sqlite 命令行 shell 中使用 varchar(10) 时会发生什么?

mysql - SQL 查询 - CASE 意外标记

mysql - 头脑 NumPy 的 SQL 疯狂

bash - 在 BASH 中使用与 PostgreSQL 的开放数据库连接?

scala - Scala 中是否可以等于抽象类型成员?

types - 我如何表示这些数据?

sql - 列出并终止 PostgresQL 中的所有死锁查询

sql - 为什么我的索引没有自动使用?