Greenplum plpgsql 函数在输入结束时返回语法错误

Posted

技术标签:

【中文标题】Greenplum plpgsql 函数在输入结束时返回语法错误【英文标题】:Greenplum plpgsql function returns syntax error at end of input 【发布时间】:2016-05-20 08:12:53 【问题描述】:

我在 Greenplum 中编写了一个 PL/pgSQL 函数,该函数需要将 interval 其中 < interval '00:00:00' 转换为正值。

例如,间隔值-23:57:00 应转换为00:03:00。所以我写了这个函数:

CREATE OR REPLACE FUNCTION abstime(timeval INTERVAL)
RETURNS INTERVAL AS $$
BEGIN
    IF timeval < INTERVAL '00:00:00' THEN
        RETURN timeval + INTERVAL '24:00:00';
    ELSE
        RETURN timeval;
    END IF;
    RETURN;
END;
$$ LANGUAGE plpgsql;

我进入后得到:

ERROR:  syntax error at end of input
LINE 1: SELECT
           ^
QUERY:  SELECT
CONTEXT:  SQL statement in PL/PgSQL function "abstime" near line 7

我不知道出了什么问题?

【问题讨论】:

我猜这个错误是在调用函数后出现的。向我们展示该调用。 你有多少abstime函数?.. 其实我根本没有调用这个函数,按下enter后出现这个错误,所以我的\df中根本没有任何函数 【参考方案1】:

现代 PostgreSQL 有更好的诊断:

postgres=# CREATE OR REPLACE FUNCTION abstime(timeval INTERVAL)
RETURNS INTERVAL AS $$
BEGIN
  IF timeval < INTERVAL '00:00:00' THEN
    RETURN timeval + INTERVAL '24:00:00';
  ELSE
    RETURN timeval;
  END IF;
  RETURN; --- SHOULD BE REMOVED
END;                
$$ LANGUAGE plpgsql;
ERROR:  missing expression at or near ";"
LINE 9: RETURN;
              ^

第 9 行的 return 是无用的,并且缺少一个表达式。您必须删除第 9 行。在这种情况下,RETURN 语句中需要表达式。

【讨论】:

是的,非常感谢。 return; 的东西是从教程中得到的,我使用的是 greenplum,它基于 postgresql v8.2【参考方案2】:

Pavel 在如何修复函数方面是 100% 正确的,但基于函数代码,并且因为您使用的是 Greenplum,我猜您想针对大表选择此内联。这样做时,您需要避免 PL/pgSQL 的开销。它是一门很棒的语言,我经常使用它,但我会避免将它用于内联 SQL。使用 PL/pgSQL 封装转换逻辑,而不是内联 SQL。

其次,我会将函数设为 IMMUTABLE,因为您没有在函数中更新数据库,并且对于给定的参数总是返回相同的值。更多关于这里: http://www.postgresql.org/docs/8.2/static/xfunc-volatility.html

证明:

CREATE OR REPLACE FUNCTION abstime(timeval INTERVAL)
RETURNS INTERVAL AS $$
BEGIN
IF timeval < INTERVAL '00:00:00' THEN
RETURN timeval + INTERVAL '24:00:00';
ELSE
RETURN timeval;
END IF;
END;
$$ LANGUAGE plpgsql;

现在得到解释计划。

EXPLAIN ANALYZE SELECT abstime('04:00:00'::interval);

Result  (cost=0.01..0.02 rows=1 width=0)
  Rows out:  1 rows with 5.230 ms to end, start offset by 0.124 ms.
  InitPlan
    ->  Result  (cost=0.00..0.01 rows=1 width=0)
          Rows out:  1 rows with 5.146 ms to end of 2 scans, start offset by 0.130 ms.
Slice statistics:
  (slice0)    Executor memory: 63K bytes.
  (slice1)    Executor memory: 37K bytes.
Statement statistics:
  Memory used: 128000K bytes
Settings:  optimizer=on
Optimizer status: legacy query optimizer
Total runtime: 5.356 ms

现在,将此函数重写为 SQL 函数并使用 IMMUTABLE 标志。

CREATE OR REPLACE FUNCTION abstime_v2(timeval INTERVAL)
RETURNS INTERVAL AS 
$$
SELECT CASE WHEN $1 < INTERVAL '00:00:00' THEN $1 + INTERVAL '24:00:00' ELSE $1 END;
$$ 
LANGUAGE sql IMMUTABLE;

解释计划。

EXPLAIN ANALYZE SELECT abstime_v2('04:00:00'::interval);

Result  (cost=0.00..0.00 rows=1 width=16)
  Rows out:  1 rows with 0.002 ms to end, start offset by 0.042 ms.
  ->  Result  (cost=0.00..0.00 rows=1 width=1)
        Rows out:  1 rows with 0.001 ms to end, start offset by 0.043 ms.
Slice statistics:
  (slice0)    Executor memory: 13K bytes.
Statement statistics:
  Memory used: 128000K bytes
Settings:  optimizer=on
Optimizer status: PQO version 1.607
Total runtime: 0.046 ms

v2 功能所需的扫描和内存更少。

【讨论】:

哦,是的,这真的很有帮助,是的,因为我使用的是Greenplum,所以我应该考虑资源成本。

以上是关于Greenplum plpgsql 函数在输入结束时返回语法错误的主要内容,如果未能解决你的问题,请参考以下文章

在 postgres plpgsql 函数中重用 json 解析的输入

plpgsql 专家:(记录集)函数的输入和输出

如何将表行传递给 plpgsql 函数?

Greenplum/Postgres 8 函数动态结果集?

在 plpgsql 函数中访问 select 语句结果

plpgsql光标在unnest函数上