The driver enables support for distributed transactions by implementing the XA interface. In an X/Open Distributed Transaction Processing (DTP) system, the XA interface provides a method for the Transaction Manager (TM) to call xa_ routines to interact with the Resource Manager (RM).

For more information on the X/Open DTP system, the XA interface, and the XA components discussed in the following procedure, refer to Distributed Transaction Processing: The XA Specification.

To perform distributed transactions:

  1. Establish a connection between your application and the RM (the database server you want to connect to) in AUTOCOMMIT_OFF mode. For example:
    rc = SQLConnect((HDBC)hdbc, (SQLCHAR*)dataSource, SQL_NTS, 
    (SQLWCHAR*)"user", SQL_NTS, (SQLWCHAR*)"password", SQL_NTS);
    rc = SQLSetConnectAttr((HDBC)hdbc, SQL_ATTR_AUTOCOMMIT, 
    SQL_AUTOCOMMIT_OFF, SQL_NTS);

    where:

    user
    is the user name required to connect to the RM.
    password
    is the password required to connect to the RM.
  2. Load the driver library and call the GetXaSwitch() function. GetXaSwitch() returns the XA switch data structure (xa_switch_t) exposed by the RM. xa_switch_t contains function pointers to the xa_ routines that must be invoked by the TM to interact with the RM. For example:
    #ifndef WIN32
            LPCSTR libFile = "ddora28.dll";
            HMODULE oraLib = LoadLibrary(libFile);
            xaSwitch = (XaSwitch)GetProcAddress(oraLib, "GetXaSwitch");
    #else // Unix
            handle = dlopen("ddora28.so", RTLD_LAZY);
            xaSwitch = (XaSwitch)dlsym(handle, "GetXaSwitch_");
    #endif // End of WIN32
            xaSwitch(0, &xaSwitchPtr);
  3. Establish an XA connection between TM and RM. As a result, a global transaction is created. For example:
    int RMID = rmid_value;
    // Use xa_open_entry with XA connection string, RMID, and flag to establish the connection.
    rc = xaSwitchPtr->xa_open_entry("Oracle_XA+HostName=host_name+
    PortNumber=1521+Sid=sid_value+ACC=account_credentials+
    SesTM=session_timeout+LogDir=log_dir_path",rmid,flag);

    where:

    rmid_value
    is the RM identifier.
    host_name
    is the name or IP address of the RM you want to connect to.
    sid_value
    is the system identifier that refers to the instance of Oracle running on the server.
    account_credentials
    are the credentials required to connect to the RM. They must be provided in the following format: P/USER/PASSWORD.
    session_timeout
    is the number of seconds the session remains active.
    log_dir_path
    is the path to the directory where log files are stored.
    flag
    determines the function that is called after the connection ends. For example, TMASYNC and TMNOFLAGS.
  4. Create an XID for the transaction branch you want to associate with the global transaction. For example:
    void DoMakeXid(int id, XID *xaXid){
    int *dataPtr;
    memset(xaXid, 0, sizeof(*xaXid));
    xaXid->formatID = format_id
    xaXid->gtrid_length = gtrid_length;
    xaXid->bqual_length = bqual_length;
    dataPtr = (int*)&xaXid->data;
    dataPtr[0] = GetCurrentThreadId();
    dataPtr[1] = GetCurrentThreadId();
    }

    where:

    format_id
    is the identifier that indicates the naming convention used by the TM.
    gtrid_length
    is the length of the global transaction ID. It should not exceed 64 bytes.
    bqual_length
    is the length of the branch qualifier ID. It should not exceed 64 bytes.
    Note: In the above example, the GetCurrentThreadId() function returns the global transaction and branch qualifier IDs. However, if you are using an Oracle TM, you can use the IDs obtained from the TM instead of those returned by the GetCurrentThreadId() function.
  5. Start the transaction branch, enlist the connection, and then execute the required query.
    // Use xa_start_entry to start the transaction branch.
    rc = xaSwitchPtr->xa_start_entry(&xId, rmid, flag);
    
    // Enlist connection.
    rc = SQLSetConnectOption(hDbc, SQL_ATTR_ENLIST_IN_XA, (UDWORD)1);
    
    // Execute query.
    rc = SQLExecDirect(hstmt, (unsigned char*)"INSERT INTO table_name VALUES(value_1, 'value_2')", SQL_NTS);
    
  6. Prepare and commit the transaction branch; then, delist the connection.
    // Use xa_prepare_entry to prepare the trasaction branch.
    rc = xaSwitchPtr->xa_prepare_entry(&xId, rmid, TMNOFLAGS);
    
    // Use xa_commit_entry to commit the transaction branch.
    rc = xaSwitchPtr->xa_commit_entry(&xId, rmid, TMNOFLAGS);
    
    // Delist connection.
    rc = SQLSetConnectOption(hDbc, SQL_ATTR_ENLIST_IN_XA, (UDWORD)0);
  7. End the transaction branch.
    // Use xa_end_entry to end the transaction branch.
    rc = xaSwitchPtr->xa_end_entry(&xId, rmid, flag);