Manage the transaction
The transaction system of the database server only guarantees transaction semantics on all objects that are internal to the database. However, transactions might also include operations on external objects. A UDR might perform such operations, such as creating a temporary file or sending a message.
- Commit-abort callback (MI_EVENT_COMMIT_ABORT)
- End-of-statement callback (MI_EVENT_END_STMT)
Each SQL statement behaves like a subtransaction when in a transaction block or like a transaction when not in a transaction block.
- End-of-transaction callback (MI_EVENT_END_XACT)
Registration of a commit-abort callback is preferable.
- Savepoint callback (MI_EVENT_SAVEPOINT)
Each cursor flush behaves like a subtransaction when in a transaction block.
To enable these callbacks to roll back a transaction, the DataBlade API allows end-of-statement and end-of-transaction callbacks to raise an exception and register their own exception callbacks.
The database server calls an end-of-statement or end-of-transaction callback before it attempts to commit the transaction. When called before a commit, these callbacks receive a transition descriptor that has a transition state of MI_NORMAL_END. However, if either of these callbacks encounters an error during its execution, you probably do not want to allow the transaction to commit.
- Terminates further processing of the end-of-statement or end-of-transaction callback.
- Terminates the current transaction and changes the transition state from MI_NORMAL_END (commit) to MI_ABORT_END (rollback).
- Invokes any end-of-statement or end-of-transaction callbacks again, this time with the MI_ABORT_END transition state.
- Invokes any exception callback that the end-of-statement or end-of-transaction callback has registered to handle the exception.
MI_CALLBACK_STATUS MI_PROC_CALLBACK
endxact_callback(event_type, conn, event_data, user_data)
MI_EVENT_TYPE event_type;
MI_CONNECTION *conn;
void *event_data;
void *user_data;
{
MI_CONNECTION *cb_conn;
cb_conn = mi_open(NULL, NULL, NULL);
(void) mi_register_callback(cb_conn, MI_Exception,
eox_excpt_callback(), NULL, NULL);
if ( event_type == MI_EVENT_END_XACT )
{
mi_integer change_type;
change_type = mi_transition(event_data);
switch ( change_type )
{
case MI_NORMAL_END:
ret = mi_exec(cb_conn,"insert \
into tran_state \
values(\"Transaction Committed.\")\;",
0);
if ( ret == MI_ERROR )
mi_db_error_raise(cb_conn, MI_EXCEPTION,
"Unable to save transaction \
state: Commit.");
break;
case MI_ABORT_END:
ret = mi_exec(cb_conn,"insert \
into tran_state \
values(\"Transaction Aborted.\")\;",
0);
if ( ret == MI_ERROR )
make_log_entry(log_file,
"Unable to save transaction state: \
Roll Back.");
break;
default:
mi_exec(cb_conn,"insert into tran_state \
values(\"Unhandled Transaction \
Event.\")\;", 0);
break;
}
}
else
{
mi_exec(cb_conn, "insert into tran_state \
values(\"Unhandled Event.\");", 0);
break;
}
mi_close(cb_conn);
return MI_CB_CONTINUE;
}
MI_CALLBACK_STATUS MI_PROC_CALLBACK
eox_excpt_callback(event_type, conn, event_data, user_data)
MI_EVENT_TYPE event_type;
MI_CONNECTION *conn;
void *event_data;
void *user_data;
{
... Perform clean-up tasks ...
return MI_CB_CONTINUE;
}
- It executes the MI_NORMAL_END case in the switch statement.
- If mi_exec() in the MI_NORMAL_END case fails, mi_exec() returns MI_ERROR, as does any DataBlade API function except mi_db_error_raise().
- The condition in the if statement evaluates to TRUE and mi_db_error_raise() executes, which raises an exception.
- The DataBlade API invokes the registered exception callback, eox_excpt_callback().
- Because eox_excpt_callback() returns a status
of MI_CB_CONTINUE, the database server aborts the transaction. If eox_excpt_callback() had instead returned MI_CB_EXC_HANDLED, execution would continue at the next statement of the endxact_callback() callback:
mi_close(cb_conn);
The endxact_callback() function would then return MI_CB_CONTINUE, which would cause the database server to commit current transaction.
- Before the database server aborts the transaction, it invokes endxact_callback() with
a transition state of MI_ABORT_END. This second invocation of endxact_callback() proceeds
as follows:
- It executes the MI_ABORT_END case in the switch statement.
- It calls mi_exec() to execute the INSERT statement.
- If mi_exec() fails, the database server invokes the registered exception callback eox_excpt_callback(). The mi_exec() function does not return MI_ERROR. Because eox_excpt_callback() returns MI_CB_CONTINUE, control does not return to endxact_callback().
- The mi_exec() function returns MI_ERROR.
- The condition in the if statement evaluates to TRUE and mi_db_error_raise() executes, which raises an exception.
- When mi_db_error_raise() throws an exception, the database server aborts the transaction.
- Before the database server aborts the transaction, it invokes endxact_callback() with
a transition state of MI_ABORT_END. This second invocation of endxact_callback() proceeds
as follows:
- Execute the MI_ABORT_END case in the switch statement.
- Call mi_exec() to execute the INSERT statement.
- If mi_exec() fails, it returns MI_ERROR.
- The condition in the if statement evaluates to TRUE and the user-defined make_log_entry() function makes a log entry in a text file.
Unlike some other types of callbacks, an end-of-transaction callback can register callbacks of its own. The preceding end-of-transaction callback registers the excpt_callback() to handle database server exceptions that might arise from the INSERT statements that mi_exec() executes. For a sample implementation of the excpt_callback() callback, see Figure 1.