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
のため、最後のプロシージャはトランザクション制御を実行できません。
カーソルループには特別な考慮事項が当てはまります。 以下の例をよく確認してください。
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
の時点でカーソルが行ごとではなく完全に評価されることを意味します。
従来通りカーソルはループ後に自動で削除されるので、このことはユーザにほとんど認識されません。
トランザクションコマンドは、読み込み専用でないコマンド(例えばUPDATE ... RETURNING
)で駆動されるカーソルループ内では許可されません。
例外ハンドラを伴うブロック内ではトランザクションを終了できません。