This will be multi-part blog series on locking aspects of assertions. In this first part we’ll discuss why there’s a need to enforce a serial execution order on transactions that involve the same assertion.

An assertion can express a rule that depends on more data other than the row(s) being changed, added, or deleted by a DML statement. That makes concurrency important: after execution of a DML statement, Oracle may need to examine other rows—possibly in other tables—to determine whether the change still satisfies the assertion.

Consider this assertion:

CREATE ASSERTION purchase_order_1 check
(NOT EXISTS
    (SELECT 'Open order line in canceled purchase order'
       FROM ORDERS o,
            ORDER_LINES ol,
            ORDER_EVENT_HISTORY oeh
      WHERE o.ORDER# = ol.ORDER#
        AND o.ORDER# = oeh.ORDER#
        AND o.TYPE = 'PURCHASE'
        AND ol.STATUS = 'OPEN'
        AND oeh.EVENT = 'CANCELED')
);

It says that a purchase order must not have both an open order line and a cancellation event.

Now suppose transaction A inserts an open line for a not yet canceled purchase order: this change satisfies the assertion. Assume this is the only currently OPEN order line for that order, there may be other order lines present already, but they all have a different status. At the same time, transaction B records a CANCELED event for that order: this change too satisfies the assertion, as this transaction cannot yet see the one uncommitted open order line of transaction A. Each transaction’s assertion check will query the related (joining) rows from the other two tables to come to the conclusion that its changes are “good to go”. If both checks proceed without coordination, each missing the other transaction’s uncommitted row, then after both transactions commit, there will be an open order line for a canceled purchase order.

TimeTransaction ATransaction BComments
t1Insert 1st OPEN order line Check succeeds
t2 Insert CANCELED eventCheck succeeds as we cannot see uncommitted open order line
t3commit  
t4 commitAssertion is violated

The assertion therefore needs a way to keep relevant data stable while its check is being validated. When another transaction makes a change that could affect the same assertion, it must wait for the first transaction to finish. Once the first transaction commits, the second can proceed and validate against that committed outcome. This is serialization at the assertion’s conflict boundary. It does not mean that all transactions across the database must run one at a time. Only transactions whose changes could interfere with the same assertion need coordination.

A traditional foreign key already handles a similar race condition. If one transaction inserts the first child row referencing a parent key while another deletes that parent row, Oracle coordinates the operations so they cannot both commit in a way that leaves an orphaned child row. Depending on which transaction executes its DML first, the other transaction’s DML must wait and then, depending on commit or rollback of the first transaction that took effect, either fail or succeed the constraint check.

TimeTransaction ATransaction BComments
t1Insert 1st child for parent Check succeeds as the parent exists
t2 Delete parentThis blocks and waits for transaction A to commit or rollback
t3commit Assume it commits
t4 ORA-02292Delete receives foreign key violation message

Assertions generalize this idea beyond a simple parent–child relationship. Because an assertion can depend on joins and conditions across several tables, Oracle must coordinate transactions whose changes could jointly violate the assertion. Without that coordination, a valid check of each transaction’s individual change would not guarantee valid committed data.

Part 2: Potentially Violating DML Statements