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();
トランザクション制御は、トップレベル、または、他の干渉するコマンドを伴わない入れ子の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)で駆動されるカーソルループ内では許可されません。
例外ハンドラを伴うブロック内ではトランザクションを終了できません。