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)で駆動されるカーソルループ内では許可されません。
   
例外ハンドラを伴うブロック内ではトランザクションを終了できません。