PL/pgSQL文で使用される式は全て、サーバの通常のSQLエグゼキュータを使用して処理されます。 PL/pgSQLのパーサでは、NULLキーワード以外の実際の定数値を識別することはできませんので、(例えば、timestamp型の'now'などの)定数を持つ式は実際には実行時評価が必要になる可能性があります。 全ての式は、SPIマネージャを使用して、以下の問い合わせを実行することで内部的に評価されます。
SELECT expression
評価では、式の中のPL/pgSQL変数識別子はパラメータによって置換され、変数の実際の値はエグゼキュータのパラメータ配列に渡されます。 これにより、SELECTの問い合わせ計画は一度だけ準備することができ、その後の評価で再利用されます。
PostgreSQLのメインパーサによって行われるこの評価には、定数値の解釈に多少の副作用があります。 詳しくは、以下の2つの関数の結果に違いが現れます。
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用の計画を準備する時に、logtableの対象列の型から'now'をtimestampと解釈しなければならないことを把握しています。 こうして、パーサはその時点で定数を作成し、その定数値をその後のセッションの有効期間におけるlogfunc1()の全ての呼び出しで使用します。 いうまでもありませんが、これはプログラマが意図した動作ではありません。
logfunc2()の場合では、PostgreSQLメインパーサは'now'の型を決定することができません。 そのため、nowという文字列をもつtext型のデータ値を返します。 curtimeローカル変数に代入する時に、PL/pgSQLインタプリタはこの文字列をtext_out()とtimestamp_in()関数を変換に使用してtimestamp型にキャストします。 ですから、演算されたタイムスタンプは、プログラマが意図した通り、実行の度に更新されます。
レコード変数の変わりやすいという性質はこの接続において問題となります。 レコード変数のフィールドが式や文の中で使用される場合、そのフィールドのデータ型を同じ式を呼び出す間で変更してはいけません。 その式が最初に実行された時のデータ型を使用して、その式の計画が作成されているからです。 複数のテーブル用のイベントを扱うトリガプロシージャを作成する時に、これに注意して下さい。 (必要な場合EXECUTEを使用してこの問題を回避することができます。)