Session management is different in a C UDR than in a client LIBMI application. Unlike a client LIBMI application, which can simultaneously connect to several databases, a UDR inherits a particular session context. That is, it is within an existing session and uses a database that is already opened. For information, see Establishing a UDR Connection (Server).
Because a C UDR can establish only a UDR connection, not a client connection, restrictions apply in the following areas:
The following restrictions exist within a UDR with respect to the session:
A UDR runs within an existing session. It can only obtain a connection to this session after a client application has already begun the session. However, a UDR can obtain more than one connection to the session.
The scope of temporary tables created in a logging database is the current session. Temporary tables created in a database that does not use logging or with a CREATE TABLE statement that includes the WITH NO LOG clause persist until beyond the CLOSE DATABASE statement.
Violations that are associated with the execution of the UDR are added to a violation temporary table. Therefore, if the SET CONSTRAINTS statement sets the constraint mode to IMMEDIATE, constraint checking is done per statement. Otherwise, constraint checking is deferred to the time when the transaction is committed. If the constraint mode is set to IMMEDIATE, the constraint is checked after each statement in the UDR. If you want per-UDR constraint checking, change the constraint mode to DEFERRED at the beginning of the UDR and back to IMMEDIATE at the end of the UDR.
Against databases that use logging, a UDR inherits the transaction state that is started by the SQL statement that invoked the UDR. All statements in a UDR occur inside a transaction because the UDR is called from within an SQL statement. An SQL statement is always part of a transaction. The type of transaction that the SQL statement is part of is based on the type of database and whether it uses transaction logging, as Table 84 shows.
You can obtain the transaction ID of the current transaction with the mi_get_transaction_id( ) function.
As a rule, a C UDR must not issue any of the following SQL transaction statements because they interfere with transaction boundaries:
In all databases that use logging, an SQL statement is within a transaction. In such databases, a DML statement (SELECT, INSERT, UPDATE, DELETE) implicitly starts a transaction, if a transaction is not already in effect. If a UDR that executes one of these SQL transaction statements is called from a DML statement, the database server raises an error (-535).
However, the EXECUTE PROCEDURE and EXECUTE FUNCTION statements do not implicitly start another transaction, if they are not already in a transaction. If a UDR is called from an EXECUTE PROCEDURE or EXECUTE FUNCTION statement, the database server only raises an error if the UDR interferes with the current transaction boundaries.
For example, suppose you have a UDR named udr1( ) that uses the mi_exec( ) function to execute two SQL statements:
void udr1(...) { mi_exec(...DML statement 1...); mi_exec(...DML statement 2...); }
Suppose also that you execute this UDR with the EXECUTE PROCEDURE statement, as follows:
EXECUTE PROCEDURE udr1( );
If a transaction has not already been started, this UDR would have two transactions, one for each call to mi_exec( ).
To get a single transaction, you could surround these SQL statements with a begin and end work, as udr2( ) shows:
void udr2(...) { mi_exec(...'begin work'..); mi_exec(...DML statement 1...); mi_exec(...DML statement 2...); mi_exec(...'commit work'...); }
However, you can only start a transaction within a UDR if you are not already in a transaction. Therefore, you can only invoke a UDR that starts a transaction when the following restrictions are met:
Because udr2( ) is a user-defined procedure, you must use EXECUTE PROCEDURE to invoke it, as follows:
EXECUTE PROCEDURE udr2( );
Suppose you tried to invoke udr2( ) with the following SELECT statement:
SELECT udr2( ) FROM tab WHERE x=y;
If a transaction had not started, the SELECT operation starts its own implicit transaction. The database server raises an error when execution reaches the first call to mi_exec( ) in udr2( ):
mi_exec(...'begin work'..);
The following code fragment fails because the EXECUTE PROCEDURE statement is already within a transaction block and udr2( ) attempts to start another transaction:
BEGIN WORK; ... EXECUTE PROCEDURE udr2( ); /* This statement fails. */ ... COMMIT WORK:
The database server raises an error when execution reaches the first call to mi_exec( ) in udr2( ):
mi_exec(...'begin work'..);
You can execute an SQL transaction statement in a UDR that you call directly from a DataBlade API module (not from within an SQL statement). You can also choose whether to commit or rollback the current transaction from within an end-of-statement or end-of-transaction callback function. For more information, see State Transitions in a C UDR (Server).
In a database with logging, the database server creates an internal savepoint before execution of each statement within a UDR that might affect the database state. If one of these statements fails, the database server performs a rollback to this internal savepoint. At this point, the database server does not release table locks. However, the same user can obtain a lock on the same table in the same transaction. The database server releases the table lock when the entire transaction ends (commit or rollback).