↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 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.2 已于 2011 年 12 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

37.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的目标列就是该类型。这样,'now'会在INSERT完成规划时被转换为一个常量,然后在该会话的整个生命周期内logfunc1的所有调用中都使用它。毫无疑问,这并不是程序员想要的结果。

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

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

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。