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 を使用してこの問題を回避することができます)。