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