マニュアルのキーセンテンスを自分で太字にしました:
SQL関数の本体全体は、実行される前に解析されます。
パーサーステージについてもお読みください マニュアルで。
これは、2つの主要な部分で構成されています。パーサー および変換プロセス 。マニュアルの引用:
変換プロセス パーサーから返されたツリーを入力として受け取り、クエリによって参照されるテーブル、関数、および演算子を理解するために必要なセマンティック解釈を行います。
SQL関数に次のコマンドが含まれている場合:
CREATE TABLE foo (...);
INSERT INTO foo VALUES(...);
両方のステートメントは、実質的に同時に計画されます(システムカタログの同じスナップショットに基づいて)。したがって、INSERT
以前のCREATE
で作成されたと思われるテーブル「foo」が表示されない 指図。これにより、次のいずれかの問題が発生します :
-
その他がない場合
search_patch
の「foo」という名前のテーブル (まだ)、Postgresは作成しようとすると文句を言います 関数:ERROR: relation "foo" does not exist
-
「foo」という名前の別のテーブルが
search_patch
にすでに存在する場合 (競合する列名を使用しないでください)、PostgresはINSERT
を計画します その既存のテーブルに基づいています。通常、その結果、実行時にエラーが発生します。 、(間違った!)テーブルで値が競合する場合。または、運が悪ければ、エラーメッセージなしでそのテーブルに書き込むこともできます。非常に卑劣なバグ。
これは、 PL / pgSQLでは発生しません。 関数は、SQLコマンドをプリペアドステートメントのように扱い、順次計画および実行されるためです。 。したがって、各ステートメントは、前のステートメントで作成されたオブジェクトを見ることができます。
その結果、SQL関数とは異なり、アクセスされることのないステートメントが計画されることさえありません。また、ステートメントの実行プランは、SQL関数とは異なり、同じセッション内にキャッシュできます。 PL / pgSQL関数のプランキャッシングの詳細については、こちらのマニュアルを参照してください。
各アプローチには、いくつかのユースケースに利点があります。さらに読む:
- PostgreSQL関数の言語sqlと言語plpgsqlの違い