This example shows how to use the CLI XA transaction connection attributes.
/************************************************************************* ** file = CLIXAEXMP1.c ** ** Example of a typical flow of work in an XA transaction using the CLI. ** ** XA Functions used: ** ** xa_open() -- Open an XA resource for use in a transaction ** xa_prepare() -- Prepare for commitment of work in the transaction ** xa_commit() -- Commit work done in the transaction ** ** CLI Functions used: ** ** SQLAllocHanle SQLBindParameter SQLDisconnect ** SQLError SQLExecute SQLFreeHandle ** SQLPrepare SQLSetConnectAttr SQLSetEnvAttr ** ** This example will: ** - Open the XA transaction manager ** - Open a CLI connection and start a transaction for it using SQL_TXN_CREATE ** - Do some commitable CLI work under this transaction ** - End the transaction on the first connection using SQL_TXN_END ** - Close the first CLI connection and open a second connection ** - Use the SQL_TXN_FIND option to find the previous transaction ** - Do more commitable work on this transaction and end the transaction ** - Use the XA APIs to prepare and commit the work ************************************************************************************/ #define _XA_PROTOTYPES #define _MULTI_THREADED #include <xa.h> #include <stdio.h> #include <string.h> #include <sqlcli.h> #include <time.h> #include <stdlib.h> void genXid(XID *xid) { time_t t; memset(xid, 0, sizeof(xid)); xid->formatID = 69; xid->gtrid_length = 4; xid->bqual_length = 4; /* xid->data must be a globally unique naming identifier when taking gtrid and bqual together - the example below is most likely not unique */ /* gtrid contents */ xid->data[0] = 0xFA; xid->data[1] = 0xED; xid->data[2] = 0xFA; xid->data[3] = 0xED; time(&t); /* bqual contents */ xid->data[4] = (((int)t) >> 24) & 0xFF; xid->data[5] = (((int)t) >> 16) & 0xFF; xid->data[6] = (((int)t) >> 8) & 0xFF; xid->data[7] = (((int)t) >> 0) & 0xFF; } int main(int argc, char **argv) { /***************************************************/ /* Declarations Section */ /***************************************************/ SQLHENV henv; SQLHDBC hdbc; SQLHSTMT hstmt; SQLRETURN rtnc; SQLINTEGER attr; SQLINTEGER int_buffer; SQLINTEGER rlength; SQLINTEGER buffint; SQLINTEGER ilen; SQLCHAR s[80]; SQLCHAR state[10]; SQLCHAR buffer[600]; SQLCHAR sqlstr[600]; SQLINTEGER natErr; SQLSMALLINT len; /* Declare local XA variables */ struct TXN_STRUCT new; XID xid; char xaOpenFormat[128]; int mainRmid = 1; int xaRc; /* Initialize the XA structure variable's (defined in sqlcli.h) */ strcpy(new.tminfo,"MYPRODUCT"); strcpy(new.reserved1,""); new.timeoutval = 0; new.locktimeout = 0; strcpy(new.reserved2,""); genXid(&xid); new.XID = &xid; /* Use the XA APIs to start the transaction manager */ /* The xa_info argument for xa_open MUST include the THDCTL=C keyword and value when using using CLI with XA transactions */ sprintf(xaOpenFormat, "RDBNAME=*LOCAL THDCTL=C"); xaRc = xa_open(xaOpenFormat, mainRmid, TMNOFLAGS); printf("xa_open(%s, %d, TMNOFLAGS) = %d\n", xaOpenFormat, mainRmid, xaRc); /* Setup the CLI resources */ attr=SQL_TRUE; rtnc=SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv); rtnc=SQLSetEnvAttr(henv,SQL_ATTR_SERVER_MODE,&attr,0); /* set server mode */ rtnc=SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc); /* Mark the connection as an external transaction and connect */ rtnc=SQLSetConnectAttr(hdbc,SQL_ATTR_TXN_EXTERNAL,&attr,0); rtnc=SQLConnect(hdbc,NULL,0,NULL,0,NULL,0); /* Start the transaction */ new.operation = SQL_TXN_CREATE; rtnc=SQLSetConnectAttr(hdbc,SQL_ATTR_TXN_INFO,&new,0); /* Do some CLI work */ rtnc=SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt); strcpy(sqlstr,"insert into tab values(?)"); rtnc=SQLPrepare(hstmt,sqlstr,SQL_NTS); rtnc= SQLBindParameter(hstmt,1,1,SQL_INTEGER,SQL_INTEGER,10,2,&buffint,0,&ilen); buffint=10; /* set the integer value to insert */ rtnc=SQLExecute(hstmt); if (rtnc!=SQL_SUCCESS) { printf("SQLExecute failed with return code: %i \n", rtnc); rtnc=SQLError(0, 0,hstmt, state, &natErr, buffer, 600, &len); printf("%i is the SQLCODE\n",natErr); printf("%i is the length of error text\n",len); printf("%s is the state\n",state ); printf("%s \n",buffer); } else printf("SQLExecute succeeded, value %i inserted \n", buffint); /* End the transaction */ new.operation = SQL_TXN_END; rtnc=SQLSetConnectAttr(hdbc,SQL_ATTR_TXN_INFO,&new,0); /* Cleanup and disconnect from the first connection */ rtnc=SQLFreeHandle(SQL_HANDLE_STMT,hstmt); rtnc=SQLDisconnect(hdbc); /* Mark the second connection as an external transaction and connect */ attr=SQL_TRUE; rtnc=SQLSetConnectAttr(hdbc,SQL_ATTR_TXN_EXTERNAL,&attr,0); rtnc=SQLConnect(hdbc,NULL,0,NULL,0,NULL,0); /* Find the open transaction from the first connection */ new.operation = SQL_TXN_FIND; rtnc=SQLSetConnectAttr(hdbc,SQL_ATTR_TXN_INFO,&new,0); /* Do some CLI work on the second connection */ rtnc=SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt); strcpy(sqlstr,"insert into tab values(?)"); rtnc=SQLPrepare(hstmt,sqlstr,SQL_NTS); rtnc= SQLBindParameter(hstmt,1,1,SQL_INTEGER,SQL_INTEGER,10,2,&buffint,0,&ilen); buffint=15; /* set the integer value to insert */ rtnc=SQLExecute(hstmt); if (rtnc!=SQL_SUCCESS) { printf("SQLExecute failed with return code: %i \n", rtnc); rtnc=SQLError(0, 0,hstmt, state, &natErr, buffer, 600, &len); printf("%i is the SQLCODE\n",natErr); printf("%i is the length of error text\n",len); printf("%s is the state\n",state ); printf("%s \n",buffer); } else printf("Second SQLExecute succeeded, value %i inserted \n", buffint); /* End the transaction */ new.operation = SQL_TXN_END; rtnc=SQLSetConnectAttr(hdbc,SQL_ATTR_TXN_INFO,&new,0); /* Now, use XA to prepare/commit transaction */ /* Prepare to commit */ xaRc = xa_prepare(&xid, mainRmid, TMNOFLAGS); printf("xa_prepare(xid, %d, TMNOFLAGS) = %d\n",mainRmid, xaRc); /* Commit */ if (xaRc != XA_RDONLY) { xaRc = xa_commit(&xid, mainRmid, TMNOFLAGS); printf("xa_commit(xid, %d, TMNOFLAGS) = %d\n", mainRmid, xaRc); } else { printf("xa_commit() skipped for read only TX\n"); } /* Cleanup the CLI resources */ rtnc=SQLFreeHandle(SQL_HANDLE_STMT,hstmt); rtnc=SQLDisconnect(hdbc); rtnc=SQLFreeHandle(SQL_HANDLE_DBC,hdbc); rtnc=SQLFreeHandle(SQL_HANDLE_ENV,henv); return 0; }