The database server throws a state-transition event when it changes its processing state.
Within a state-transition callback, use the mi_transition_type( ) function on the transition descriptor to determine the state-transition type (begin, normal end, or abort end) that caused the event. The processing required is typically different for each transition type.
To provide required DataBlade processing at a state-transition point, your DataBlade API module must register state-transition callbacks with the mi_register_callback( ) function.
The way that your DataBlade API module handles a state-transition event depends on whether the DataBlade API module is a C UDR or a client LIBMI application.
In a C UDR, the following state-transition events might occur:
For these state-transition events, the mi_transition_type( ) function returns a state-transaction type of normal end (MI_NORMAL_END) or abort end (MI_ABORT_END). In a UDR, state-transition callbacks are always called at the end of a transaction (normal or aborted), never at the beginning.
If your code allocates memory for user data that the callback function needs, this memory must have a duration long enough to persist until the execution of the callback. Otherwise, the callback cannot access the user data. This user data might include information that the callback function needs to handle the event or to notify users of the cause of the event.
The following table shows the memory durations associated with callback and event types.
At the end of the memory duration associated with the callback, the database server deallocates the memory as part of its final cleanup.
For more information on memory durations, see Choosing the Memory Duration.
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.
For transactions that consist of operations on both internal and external objects, you can use one of the following types of callbacks to commit or to undo (if possible) the operations on the external objects, based on the transaction status:
Each SQL statement behaves like a subtransaction when in a transaction block or like a transaction when not in a transaction block.
Registration of a commit-abort callback is preferable.
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.
To cause an event to be aborted or rolled back, you can raise an exception from a state-transition callback by calling the mi_db_error_raise( ) function. When a state-transition callback raises an exception, the DataBlade API takes the following actions:
An end-of-transaction callback executes within a C UDR when the MI_EVENT_END_XACT event occurs. The following code implements an end-of-transaction callback named endxact_callback( ), which inserts a row into a database table, tran_state, to indicate the state of the current transaction:
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; }
The database server invokes the endxact_callback( ) callback with a transition state of MI_NORMAL_END just before it commits the transaction. The endxact_callback( ) function executes as follows:
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.
If endxact_callback( ) had not registered its own exception callback, then when mi_exec( ) in the MI_NORMAL_END case fails, execution would proceed as follows:
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 62.
In a client LIBMI application, the only state-transition event that might occur is MI_Xact_State_Change. The MI_Xact_State_Change event occurs only within a client application.
In a client LIBMI application, a state-change callback is invoked for the following state-transition types:
You execute an explicit begin with the SQL statement, BEGIN WORK.
In databases that are ANSI compliant, every SQL statement is a separate transaction. Therefore, ANSI-compliant databases execute an implicit begin for each SQL statement.
You execute an explicit end transaction with one of the following SQL statements: COMMIT WORK (normal end) or ROLLBACK WORK (aborted end).