Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
函数参数anyelement,PostgreSQL错误?_Sql_Postgresql_Types_Query Planner_Polymorphic Functions - Fatal编程技术网

函数参数anyelement,PostgreSQL错误?

函数参数anyelement,PostgreSQL错误?,sql,postgresql,types,query-planner,polymorphic-functions,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(

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

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
提供了一定的灵活性,但是SQL语句仍然是静态地使用给定类型规划的

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

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

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 $1 > '2'  -- use a string literal!
               ELSE true END
$func$ LANGUAGE sql IMMUTABLE;
而不是:

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

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


它肯定与SQL planner/optimizer有关。由于函数被声明为不可变
,因此优化器尝试对查询部分进行预评估。出于某种原因,即使使用
text
参数调用函数,它也会计算表达式
$1::int>2

如果将
foo
函数更改为
VOLATILE
,它将正常工作,因为查询优化器不会尝试对其进行优化/预评估

但是为什么
函数即使是不可变的也能正常工作呢?我猜优化器决定不预先评估它,因为它不在循环中使用表达式。我的意思是,
$1::int>2
只计算一次,而在
foo
函数中,它被计算多次


SQL planner在
SQL
PLPGSQL
语言中的工作方式似乎有些不同。
PLPGSQL
中的相同函数工作正常

CREATE FUNCTION foo2(anyelement) RETURNS SETOF int AS $f$
DECLARE 
    i INTEGER;
BEGIN
    FOR i IN SELECT id FROM unnest(array[1,2,3]) t(id) 
        WHERE 
            CASE WHEN pg_typeof($1) = 'integer'::regtype 
                THEN $1::int > 2
                ELSE true END
    LOOP
        RETURN NEXT i;
    END LOOP;
END;
$f$ LANGUAGE plpgsql IMMUTABLE;

SELECT * FROM foo2('test'::text); -- works fine
CREATE FUNCTION foo2(anyelement) RETURNS SETOF int AS $f$
DECLARE 
    i INTEGER;
BEGIN
    FOR i IN SELECT id FROM unnest(array[1,2,3]) t(id) 
        WHERE 
            CASE WHEN pg_typeof($1) = 'integer'::regtype 
                THEN $1::int > 2
                ELSE true END
    LOOP
        RETURN NEXT i;
    END LOOP;
END;
$f$ LANGUAGE plpgsql IMMUTABLE;

SELECT * FROM foo2('test'::text); -- works fine