19.4. 表达式

所有在PL/pgSQL 语句里使用的表达式都是用后端的普通SQL执行器进行处理的. 那些看上去象是包含常量的表达式实际上需要运行时计算(比如,用于 TIMESTAMP 类型的 'now'),因此 除了 NULL 关键字之外,对于PL/pgSQL分析器而言, 实际上是不可能 标识真正的常量数值的.所有表达式都是使用 SPI 管理器通过在内部执行一个查询计算的.

SELECT expression

在表达式里,出现PL/pgSQL变量标识符的 地方被那些从参数数组里传递给执行器的变量的实际 数值替代. 这样就允许SELECT的查询规划只需要准备一次,并且在随后的计算中 复用.

PostgreSQL 的主分析器做的类型检查 对常量数值的代换有一些副作用.详细说来就是下面这两个函数 做的事情有些区别∶

CREATE FUNCTION logfunc1 (text) RETURNS TIMESTAMP AS '
    DECLARE
        logtxt ALIAS FOR $1;
    BEGIN
        INSERT INTO logtable VALUES (logtxt, ''now'');
        RETURN ''now'';
    END;
' LANGUAGE 'plpgsql';

CREATE FUNCTION logfunc2 (text) RETURNS TIMESTAMP AS '
    DECLARE
        logtxt ALIAS FOR $1;
        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绕开这个问题.)