↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2
历史版本。 PostgreSQL 8.0 已结束支持。 请参阅 当前版本手册.

35.5. 表达式 #

PL/pgSQL 语句中使用的所有表达式都由服务器的主 SQL 执行器处理。实际上,像下面这样的查询

SELECT expression

是通过 SPI 管理器执行的。在求值之前,出现的 PL/pgSQL 变量标识符会被替换为参数,而变量的实际值则通过参数数组传递给执行器。这使得 SELECT 的查询计划只需准备一次,随后就可以重复用于后续的求值。

PostgreSQL 主解析器所做的求值,对常量值的解释有一些副作用。具体来说,下面这两个函数的行为有所不同:

CREATE FUNCTION logfunc1(logtxt text) RETURNS timestamp AS $$
    BEGIN
        INSERT INTO logtable VALUES (logtxt, 'now');
        RETURN 'now';
    END;
$$ LANGUAGE plpgsql;

和

CREATE FUNCTION logfunc2(logtxt text) RETURNS timestamp AS $$
    DECLARE
        curtime timestamp;
    BEGIN
        curtime := 'now';
        INSERT INTO logtable VALUES (logtxt, curtime);
        RETURN curtime;
    END;
$$ LANGUAGE plpgsql;

在logfunc1的例子中,PostgreSQL主解析器在为INSERT准备计划时就知道字符串'now'应被解释为timestamp,因为logtable的目标列就是该类型。这样,它会在此时为此生成一个常量,而该常量值随后在该会话的整个生命周期内logfunc1的所有调用中使用。毫无疑问,这并不是程序员想要的结果。

在logfunc2的例子中,PostgreSQL主解析器不知道'now'应转换成什么类型,因此它返回一个包含字符串now的text类型数据值。在随后向局部变量curtime赋值时,PL/pgSQL解释器通过调用text_out和timestamp_in函数进行转换,把这个字符串强制转换为timestamp类型。这样,计算得到的时间戳在每次执行时都会更新,正符合程序员的期望。

记录变量的可变本性在此方面带来一个问题。当记录变量的字段被用于表达式或语句中时,各字段的数据类型在同一表达式的多次调用之间不得改变,因为表达式将使用第一次到达时出现的数据类型进行规划。在编写处理多张表事件的触发器过程时,请牢记这一点。(必要时可以用EXECUTE来绕过这一问题。)

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.