Skip to content

Oracle incompatibility: COMMIT inside EXCEPTION-enabled blocks fails #1128

Description

@rophy

Bug Report

IvorySQL Version

master (commit 7261f1c) as container

OS Version (uname -a)

Linux 6.8.0-87-generic #88-Ubuntu SMP PREEMPT_DYNAMIC x86_64 GNU/Linux

Configuration options (config.status --config)

'--prefix=/home/ivorysql/ivorysql' '--enable-debug' '--enable-cassert' '--with-uuid=e2fs' '--with-libxml' '--with-libxslt'

Current Behavior

COMMIT and ROLLBACK statements fail with the error:

cannot commit while a subtransaction is active

or

cannot roll back while a subtransaction is active

This occurs when the COMMIT/ROLLBACK is inside a PL/pgSQL or PL/iSQL block that has an EXCEPTION handler, even if the COMMIT is in the main BEGIN block (not inside the EXCEPTION handler itself).

Expected behavior/code

In Oracle PL/SQL, COMMIT and ROLLBACK work correctly inside procedures that have EXCEPTION handlers. The expected behavior is that COMMIT should succeed in the main block regardless of whether an EXCEPTION handler exists.

Oracle example that works:

CREATE OR REPLACE PROCEDURE my_proc ASBEGININSERT INTO log_table VALUES ('test');
COMMIT; -- Works in Oracle
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
/

Steps to reproduce

-- SetupDROPTABLE IF EXISTS test_log CASCADE;
CREATETABLEtest_log (id SERIAL, msg TEXT);
-- Test 1: COMMIT without EXCEPTION block - WORKS
DO $$
BEGININSERT INTO test_log(msg) VALUES ('no exception block');
COMMIT;
END;
$$;
-- Result: SUCCESS-- Test 2: COMMIT with EXCEPTION block - FAILS
DO $$
BEGININSERT INTO test_log(msg) VALUES ('with exception block');
COMMIT; -- ERROR: cannot commit while a subtransaction is active
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
$$;
-- Result: ERROR-- Test 3: Procedure with EXCEPTION handler - FAILS
CREATE OR REPLACE PROCEDURE proc_with_exception(p_msg TEXT)
LANGUAGE plpgsql AS $$
BEGININSERT INTO test_log(msg) VALUES (p_msg);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
INSERT INTO test_log(msg) VALUES ('caught: '|| SQLERRM);
END;
$$;
CALL proc_with_exception('test');
-- Result: Error is caught, but COMMIT failed

Additional context that can be helpful for identifying the problem

Root Cause: PostgreSQL creates an implicit savepoint (subtransaction) when entering any block that has an EXCEPTION handler. This savepoint is created at the START of the block, not when the exception is raised. COMMIT and ROLLBACK cannot execute while inside a subtransaction.

Impact on Oracle Compatibility: This affects:

  1. Any procedure using COMMIT/ROLLBACK with error handling
  2. Migration of Oracle PL/SQL code that uses COMMIT in procedures with exception handlers

Difference from Oracle:

FeatureOraclePostgreSQL/IvorySQL
EXCEPTION block implementationNo subtransactionCreates subtransaction (savepoint)
COMMIT in block with EXCEPTIONWorksFails
ROLLBACK in block with EXCEPTIONWorksFails

Workaround: Remove EXCEPTION handlers from procedures that need COMMIT/ROLLBACK, or restructure code to move COMMIT outside of exception-handling blocks.

References:

Oracle Database Test Results (Verified)

Tested on Oracle Database Free 23.26.0.0-lite to confirm expected Oracle behavior.

Test Setup (Oracle):

CREATETABLEtest_log (id NUMBER GENERATED ALWAYS AS IDENTITY, msg VARCHAR2(200));

Test 1: COMMIT without EXCEPTION block

BEGININSERT INTO test_log(msg) VALUES ('no exception block');
COMMIT;
END;
/-- Result: SUCCESS - row inserted

Test 2: COMMIT with EXCEPTION block

BEGININSERT INTO test_log(msg) VALUES ('with exception block');
DBMS_OUTPUT.PUT_LINE('Before COMMIT');
COMMIT;
DBMS_OUTPUT.PUT_LINE('After COMMIT');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Caught exception: '|| SQLERRM);
END;
/-- Result: SUCCESS - prints "Before COMMIT", "After COMMIT", row inserted

Test 3: Procedure with EXCEPTION handler

CREATE OR REPLACE PROCEDURE proc_with_exception(p_msg VARCHAR2) AS
v_err VARCHAR2(200);
BEGININSERT INTO test_log(msg) VALUES (p_msg);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
v_err :='caught: '|| SQLERRM;
INSERT INTO test_log(msg) VALUES (v_err);
COMMIT;
END;
/
EXEC proc_with_exception('test');
-- Result: SUCCESS - row inserted with msg='test'

Summary of Test Results:

TestIvorySQLOracle
Test 1: COMMIT without EXCEPTION block✅ SUCCESS✅ SUCCESS
Test 2: COMMIT with EXCEPTION block❌ FAILS✅ SUCCESS
Test 3: Procedure with EXCEPTION handler❌ FAILS✅ SUCCESS

IvorySQL Failure Details:

  • Test 2: COMMIT raises "cannot commit while a subtransaction is active", exception caught, insert rolled back
  • Test 3: COMMIT fails, EXCEPTION handler catches it and logs "caught: cannot commit while a subtransaction is active"

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions