CALL
コマンドで呼び出されたプロシージャ、また同様に無名コードブロック(DO
コマンド)では、COMMIT
およびROLLBACK
コマンドを使ってトランザクションを終えることができます。
トランザクションをこれらコマンドで終了した後、新たなトランザクションが自動的に開始されます。そのため、別途のSTART TRANSACTION
はありません。
(PL/pgSQLではBEGIN
とEND
は別の意味を持つことに注意してください。)
以下に例を示します。
CREATE PROCEDURE transaction_test1() LANGUAGE plpgsql AS $$ BEGIN FOR i IN 0..9 LOOP INSERT INTO test1 (a) VALUES (i); IF i % 2 = 0 THEN COMMIT; ELSE ROLLBACK; END IF; END LOOP; END; $$; CALL transaction_test1();
新しいトランザクションは、トランザクション分離レベル等のデフォルトのトランザクションの特性で開始します。
トランザクションがループ内でコミットされた場合、新しいトランザクションは前のトランザクションと同じ特性で自動的に開始するのが好ましいかもしれません。
コマンドCOMMIT AND CHAIN
とROLLBACK AND CHAIN
はそのように動作します。
トランザクション制御は、トップレベル、または、他の干渉するコマンドを伴わない入れ子のCALL
またはDO
呼び出しからの、CALL
またはDO
による呼び出しのみで可能です。
例えば、呼び出しスタックがCALL proc1()
→ CALL proc2()
→ CALL proc3()
である場合、二番目と三番目のプロシージャはトランザクション制御を実行できます。
しかし、呼び出しスタックがCALL proc1()
→ SELECT func2()
→ CALL proc3()
である場合、間のSELECT
のため、最後のプロシージャはトランザクション制御を実行できません。
PL/pgSQLはセーブポイント(SAVEPOINT
/ROLLBACK TO SAVEPOINT
/RELEASE SAVEPOINT
コマンド)をサポートしません。
セーブポイントの典型的な使用パターンは、例外ハンドラを持つブロックに置き換えることができます(41.6.8を参照してください)。
内部では、例外ハンドラを持つブロックがサブトランザクションを形成します。これは、そのようなブロック内ではトランザクションを終了できないことを意味します。
カーソルループには特別な考慮事項が当てはまります。 以下の例をよく確認してください。
CREATE PROCEDURE transaction_test2() LANGUAGE plpgsql AS $$ DECLARE r RECORD; BEGIN FOR r IN SELECT * FROM test2 ORDER BY x LOOP INSERT INTO test1 (a) VALUES (r.x); COMMIT; END LOOP; END; $$; CALL transaction_test2();
通常、カーソルはトランザクションのコミット時に自動的に閉じられます。
しかしながら、このようにループの一部として作られたカーソルは、最初のCOMMIT
またはROLLBACK
から自動的に保持可能カーソルに変換されます。
このことは、カーソルが行ごとではなく、最初にCOMMIT
やROLLBACK
された時点で全体として評価されることを意味します。
従来通りカーソルはループ後に自動で削除されるので、このことはユーザにほとんど認識されません。
しかし、カーソルの問い合わせによって取得されたテーブルまたは行のロックは、最初のCOMMIT
またはROLLBACK
の後にはもはや保持されないことに留意しなければなりません。
トランザクションコマンドは、読み込み専用でないコマンド(例えばUPDATE ... RETURNING
)で駆動されるカーソルループ内では許可されません。