/*
Assume the following TestDistributedTransaction table exists on both the servers.
Create this table before running this sample.
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[TestDistributedTransaction]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[TestDistributedTransaction]
GO
CREATE TABLE [dbo].[TestDistributedTransaction] (
[Col1] [int] NULL ,
[Col2] [varchar] (100) NULL
) ON [PRIMARY]
GO
*/
#include <windows.h>
#include <stdio.h>
#include <oledb.h>
#include <oledberr.h>
#include <txdtc.h>
#include <xolehlp.h>
#include <sql.h>
#include <sqlext.h>
#include <Odbcss.h>
void main()
{
HRESULT hr;
ITransactionDispenser *pTransactionDispenser = NULL;
ITransaction * pITransaction;
SQLHDBC hdbc = NULL;
SQLHENV henv;
SQLHDBC hdbc1;
SQLHDBC hdbc2;
SQLHSTMT hstmt1;
SQLHSTMT hstmt2;
SQLRETURN sr;
//SQLRETURN hr;
SQLCHAR* theDiagState = new SQLCHAR[50];
SQLINTEGER theNativeState;
SQLCHAR* theMessageText = new SQLCHAR[255];
SQLSMALLINT iOutputNo;
short iStringLength2;
char sOutConnectionString[1000];
//CoInitialize call is not needed for DtcGetTransactionManager call, but if you are using the other
//OLE object, you need to call it first.
//hr = CoInitialize( NULL );
// Allocate two different hdbc handles. We will connect to two different computers that are running SQL Server.
hr = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);
hr = SQLSetEnvAttr(henv,SQL_ATTR_ODBC_VERSION,(SQLPOINTER) SQL_OV_ODBC3,0);
hr = SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc1);
hr = SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc2);
//Get the Distributed Transaction Coordinator Manager.
hr = DtcGetTransactionManager(NULL, NULL,
IID_ITransactionDispenser, 0, 0, NULL,
(void**) &pTransactionDispenser);
//Connecting to first server.
hr = SQLDriverConnect(hdbc1,NULL,(SQLCHAR*)"DSN=YourDSN#1;uid=USERID;pwd=PASSWORD" ,SQL_NTS, (SQLCHAR*) sOutConnectionString,100,&iStringLength2,SQL_DRIVER_NOPROMPT);
if (hr != SQL_SUCCESS)
{
SQLGetDiagRec(SQL_HANDLE_DBC,hdbc1,1,(SQLCHAR*)theDiagState,&theNativeState,(SQLCHAR*)theMessageText,100,&iOutputNo);
}
//Connecting to second server.
hr = SQLDriverConnect(hdbc2,NULL,(SQLCHAR*) "DSN=YourDSN#2;uid=UID;pwd=PASSWORD" ,SQL_NTS,(SQLCHAR*) sOutConnectionString,100,&iStringLength2,SQL_DRIVER_NOPROMPT);
if (hr != SQL_SUCCESS)
{
SQLGetDiagRec(SQL_HANDLE_DBC,hdbc2,1,(SQLCHAR*)theDiagState,&theNativeState,(SQLCHAR*)theMessageText,100,&iOutputNo);
}
//Start the transaction on DTC.
hr = pTransactionDispenser->BeginTransaction (
NULL, // Controlling IUnknown
ISOLATIONLEVEL_READCOMMITTED, // Isolation level
0, // Isolation Flags
NULL, // Reserved
&pITransaction); // Ptr to the Transaction Object
//Enlist the two connections (hdbc) in DTC.
//You need to do this AFTER you make the connection (for example, after you call SQLDriverConnect or SQLConnect).
hr = SQLSetConnectAttr(hdbc1,
SQL_COPT_SS_ENLIST_IN_DTC,
(SQLPOINTER)pITransaction,SQL_IS_INTEGER);
if (hr != SQL_SUCCESS)
{
SQLGetDiagRec(SQL_HANDLE_DBC,hdbc1,1,(SQLCHAR*)theDiagState,&theNativeState,(SQLCHAR*)theMessageText,100,&iOutputNo);
printf( "Error :%s\n", theMessageText);
}
hr =SQLSetConnectAttr(hdbc2,
SQL_COPT_SS_ENLIST_IN_DTC,
(SQLPOINTER)pITransaction,SQL_IS_INTEGER);
if (hr != SQL_SUCCESS)
{
SQLGetDiagRec(SQL_HANDLE_DBC,hdbc2,1,(SQLCHAR*)theDiagState,&theNativeState,(SQLCHAR*)theMessageText,100,&iOutputNo);
printf( "Error :%s\n", theMessageText);
}
//Allocate statement handle and run a query.
hr = SQLAllocHandle(SQL_HANDLE_STMT,hdbc1,&hstmt1);
hr = SQLAllocHandle(SQL_HANDLE_STMT,hdbc2,&hstmt2);
hr = SQLExecDirect(hstmt1, (SQLCHAR*) "Insert Into TestDistributedTransaction (Col1, Col2) Values (1,'Test 1')", SQL_NTS);
if (hr != SQL_SUCCESS)
{
SQLGetDiagRec(SQL_HANDLE_STMT,hstmt1,1,(SQLCHAR*)theDiagState,&theNativeState,(SQLCHAR*)theMessageText,100,&iOutputNo);
printf( "Error :%s\n", theMessageText);
pITransaction->Abort(NULL,FALSE,FALSE);
}
else
{
//Allocate and run the second query in the second server
hr = SQLExecDirect(hstmt2, (SQLCHAR*) "Insert Into TestDistributedTransaction (Col1, Col2) Values (1,'Test 2')", SQL_NTS);
if (hr != SQL_SUCCESS)
{
SQLGetDiagRec(SQL_HANDLE_STMT,hstmt2,1,(SQLCHAR*)theDiagState,&theNativeState,(SQLCHAR*)theMessageText,100,&iOutputNo);
pITransaction->Abort(NULL,FALSE,FALSE);
}
else
{
hr = pITransaction->Commit( 0, XACTTC_SYNC_PHASEONE, 0 );
}
}
pITransaction->Release();
hr = SQLFreeHandle(SQL_HANDLE_STMT,hstmt1);
hr = SQLDisconnect(hdbc1);
hr = SQLFreeHandle(SQL_HANDLE_STMT,hstmt2);
hr = SQLDisconnect(hdbc2);
hr = SQLFreeHandle(SQL_HANDLE_DBC,hdbc1);
hr = SQLFreeHandle(SQL_HANDLE_DBC,hdbc2);
hr = SQLFreeHandle(SQL_HANDLE_ENV,henv);
//CoUninitialize();
}