home *** CD-ROM | disk | FTP | other *** search
- /* MSDTC Sample
- **
- ** This example uses the MSDTC (distributed transaction
- ** coordinator) to perform simultaneous update on two
- ** SQL servers. The transaction in this example is
- ** client initiated. The client also initiates the
- ** commit operation.
- **
- ** As this sample uses the ODBC interface, you'll need
- ** to configure the ODBC SQL driver with data source
- ** names for use with this sample.
- **
- ** In this particular example, table Authors in the pubs
- ** database that is installed with SQL server is utilized.
- ** Although the same update is performed on both servers,
- ** you can perform completely different updates on each server
- ** within the same transaction.
- **
- **
- */
-
-
-
- //------------------------------------------------------------------------------
- // Include standard header files
- //------------------------------------------------------------------------------
- #include <windows.h>
- #include <stdio.h>
- #include <conio.h>
- #include <ctype.h>
-
- //------------------------------------------------------------------------------
- // Include MSDTC specific header files.
- //------------------------------------------------------------------------------
- #define INITGUID
-
- #include "txdtc.h"
- #include "xolehlp.h"
-
-
- //------------------------------------------------------------------------------
- // Include ODBC specific header file.
- //------------------------------------------------------------------------------
- #ifndef DBNTWIN32
- #define DBNTWIN32
-
- #include <SQL.h>
- #include <SQLEXT.h>
- #include "odbcss.h"
- #include <ODBCINST.h>
-
- #endif /* DBNTWIN32 */
-
- //------------------------------------------------------------------------------
- // Define constants
- //------------------------------------------------------------------------------
- #define STR_LEN 40
-
- #define TABLE_NAME "Authors"
-
- //------------------------------------------------------------------------------
- // Define datatypes
- //------------------------------------------------------------------------------
- typedef struct DBCONN
- {
- char pszDSN [STR_LEN]; // data source name, configured through control panel
- char pszUser [STR_LEN]; // Login user name
- char pszPasswd[STR_LEN]; // Login user password
- HDBC hdbc; // handle to an ODBC database connection
- HSTMT hstmt; // an ODBC statement handle, for use with SQLExecDirect
-
- } DBCONN;
-
-
- //------------------------------------------------------------------------------
- // Define Globals
- //------------------------------------------------------------------------------
- static DBCONN gSrv1, gSrv2; // global DB connection struct for server 1 and 2
-
- static char gAuthorID[STR_LEN]; // use 11 chars only - per Authors table.
- static char gNewAddress[STR_LEN+1]; // max. address length in the Author's table.
-
- //-------------------------------------------------------------------------------
- // ODBC specific global vars...
- //-------------------------------------------------------------------------------
- HENV gHenv = SQL_NULL_HENV;
-
- //-------------------------------------------------------------------------------
- // Forward declaration of routines used.
- //-------------------------------------------------------------------------------
-
- void InitGlobals(int argc, char **argv);
- void LogonToDB(DBCONN *ptr);
- void InitODBC();
- void Enlist(DBCONN *ptr, ITransaction *pTransaction);
- void ExecuteStatement(DBCONN *ptr, char *pszBuf);
- void EndEnlistment(DBCONN *ptr, ITransaction *pTransaction);
- BOOL ProcessRC(LPTSTR pszFuncName, DBCONN *ptr, RETCODE rc);
- void DoSQLError(DBCONN *ptr);
- void FreeODBCHandles(DBCONN *ptr);
-
-
- //-------------------------------------------------------------------------------
- // main()
- //-------------------------------------------------------------------------------
-
- void main(int argc, char **argv)
- {
-
- ITransactionDispenser *pTransactionDispenser;
- ITransaction *pTransaction;
- HRESULT hr = S_OK ;
- BOOL tf = 0 ;
- char SqlStatement[STR_LEN*2];
-
-
-
- printf("/////////////////////////////////\n");
- printf("// MSDTC - ODBC Sample //\n");
- printf("/////////////////////////////////\n");
-
-
- // Initialize globals & validate command line arguments
- InitGlobals(argc,argv);
-
-
- // Obtain an interface pointer from MSDTC proxy.
- hr = DtcGetTransactionManager( 0, // LPTSTR pszHost,
- 0, // LPTSTR pszTmName,
- IID_ITransactionDispenser, // /* in */ REFIID rid,
- 0, // /* in */ DWORD dwReserved1,
- 0, // /* in */ WORD wcbReserved2,
- 0, // /* in */ void FAR * pvReserved2,
- (void **)&pTransactionDispenser // /*out */ void** ppvObject ) ;
- ) ;
- if (FAILED (hr))
- {
- printf("DtcGetTransactionManager failed: %x\n", hr);
- exit (1);
- }
-
- // Initialize the ODBC environment handle.
- // Can only be done once in a given process.
- InitODBC();
-
- // Establish connection to database on server#1
- LogonToDB(&gSrv1);
-
- // Establish connection to database on server#2
- LogonToDB(&gSrv2);
-
- // Initiate an MSDTC transaction
- printf("----------------------------------\n");
- printf("Initiating BeginTransaction -- ");
- hr = pTransactionDispenser->BeginTransaction(
- 0, // /* [in] */ IUnknown __RPC_FAR *punkOuter,
- ISOLATIONLEVEL_ISOLATED, // /* [in] */ ISOLEVEL isoLevel,
- ISOFLAG_RETAIN_DONTCARE, // /* [in] */ ULONG isoFlags,
- 0, // /* [in] */ ULONG ulTimeout,
- &pTransaction // /* [out] */ ITransaction **ppTransaction) = 0;
- ) ;
-
- if (FAILED (hr))
- {
- printf("BeginTransaction failed: %x\n",hr);
- exit(1);
- }
- else
- printf("BeginTransaction Succeeded\n");
-
- // Enlist each of the data sources in the transaction
- Enlist(&gSrv1,pTransaction);
- Enlist(&gSrv2,pTransaction);
-
- // Generate the SQL statement to execute on each of the databases
- sprintf(SqlStatement,
- "update authors set address = '%s' where au_id = '%s'",
- gNewAddress,gAuthorID
- );
-
- // Perform updates on both of the DBs participating in the transaction
- ExecuteStatement(&gSrv1,SqlStatement);
- ExecuteStatement(&gSrv2,SqlStatement);
-
- // Commit the transaction
- printf("----------------------------------\n");
- printf("Issuing Commit() -- ");
- hr = pTransaction->Commit(0,0,0);
- if (FAILED(hr))
- {
- printf("pTransaction->Commit() failed: %x\n",hr);
- exit(1);
- }
-
- printf("Commit() Succeeded\n");
-
- // Release Transaction
-
- printf("----------------------------------\n");
- printf("Releasing Transaction --");
-
- hr = pTransaction->Release();
- if (FAILED(hr))
- {
- printf("pTransaction->Commit() failed: %x\n",hr);
- exit(1);
- }
- printf("Released Transactions\n");
-
- // release transaction dispenser
- pTransactionDispenser->Release();
-
- // End ODBC enlistment mechanism
- EndEnlistment(&gSrv1,pTransaction);
- EndEnlistment(&gSrv2,pTransaction);
-
-
- // Free ODBC handles
- FreeODBCHandles(&gSrv1);
- FreeODBCHandles(&gSrv2);
-
- // Free the global ODBC environment handle.
- SQLFreeEnv(gHenv);
-
- }
-
-
-
- //-------------------------------------------------------------------------------
- #define ARGS 9 // Requires 9 arguments (strings) to run this program.
-
- void InitGlobals(int argc, char **argv)
- {
-
- if (argc != ARGS)
- {
- printf("Usage: %s DSN1 Logon1 Passwd1 DSN2 Logon2 Passwd2 AuthorID NewAddress\n",*argv);
- printf("Note: Null arguments must be supplied as \"\"\n");
- exit(1);
- }
-
- // Init Server1
- strcpy(gSrv1.pszDSN,*++argv);
- strcpy(gSrv1.pszUser,*++argv);
- strcpy(gSrv1.pszPasswd,*++argv);
-
- // Init Server2
- strcpy(gSrv2.pszDSN,*++argv);
- strcpy(gSrv2.pszUser,*++argv);
- strcpy(gSrv2.pszPasswd,*++argv);
-
- // Init the author ID
- strcpy(gAuthorID,*++argv);
-
- // Init the global new address
- strcpy(gNewAddress,*++argv);
-
- // Init ODBC handles to be invalid
- gSrv1.hdbc = SQL_NULL_HDBC;
- gSrv1.hstmt= SQL_NULL_HSTMT;
-
- gSrv2.hdbc = SQL_NULL_HDBC;
- gSrv2.hstmt= SQL_NULL_HSTMT;
-
- } // InitGlobals(int argc, char **argv)
-
- //-------------------------------------------------------------------------------
-
- void LogonToDB(DBCONN *ptr)
- {
- RETCODE rc = 0;
-
- rc = SQLAllocConnect(gHenv, &(ptr->hdbc) );
-
- if (ProcessRC("SQLAllocConnect",ptr,rc))
- {
- printf("Connecting to DSN: %s\n",ptr->pszDSN);
-
- rc = SQLConnect(ptr->hdbc,
- (unsigned char *)(ptr->pszDSN),
- SQL_NTS,
- (unsigned char *)(ptr->pszUser),
- SQL_NTS,
- (unsigned char *)(ptr->pszPasswd),
- SQL_NTS
- );
-
- ProcessRC("SQLConnect",ptr,rc);
- }
- }
-
- //-------------------------------------------------------------------------------
-
- void InitODBC()
- {
- RETCODE rc = 0;
-
- // Initialize the ODBC environment handle, done once for all connections.
-
- if (SQL_NULL_HENV == gHenv)
- {
- rc = SQLAllocEnv(&gHenv);
-
- ProcessRC("SQLAllocEnv",0,rc);
- }
-
- }
-
- //-------------------------------------------------------------------------------
-
- void Enlist(DBCONN *ptr, ITransaction *pTransaction)
- {
- RETCODE rc = 0;
-
- // Enlist database in the transaction
- printf("----------------------------------\n");
- printf("Enlisting DataSource: %s\n",ptr->pszDSN);
-
- rc = SQLSetConnectOption (ptr->hdbc, SQL_COPT_SS_ENLIST_IN_DTC, (UDWORD)pTransaction);
-
- ProcessRC("SQLSetConnectOption",ptr,rc);
-
- printf("Enlistment Succeeded\n");
- }
-
-
- // ---------------------------------------------------------------------------
-
- void ExecuteStatement(DBCONN *ptr, char *pszBuf)
- {
- RETCODE rc = 0;
-
- // Allocate a statement handle for use with SQLExecDirect
- rc = SQLAllocStmt(ptr->hdbc,&(ptr->hstmt));
-
- ProcessRC("SQLAllocStmt",ptr,rc);
-
-
- // Execute the passed string as a SQL statement
- printf("----------------------------------\n");
- printf("Executing the following SQL statement on DataSource: %s\n",ptr->pszDSN);
- printf("%s\n",pszBuf);
- rc = SQLExecDirect(ptr->hstmt,(unsigned char *)pszBuf,SQL_NTS);
-
- ProcessRC("SQLExecDirect",ptr,rc);
-
- printf("Executing the SQL statement succeeded\n");
-
- // Free the statement handle
- rc = SQLFreeStmt(ptr->hstmt, SQL_DROP);
- ptr->hstmt = SQL_NULL_HSTMT;
-
- ProcessRC("SQLFreeStmt",ptr,rc);
-
- }
-
- // ---------------------------------------------------------------------------
-
- void EndEnlistment(DBCONN *ptr, ITransaction *pTransaction)
- {
- RETCODE rc = 0;
-
- // remove the ODBC connection handle from the transaction
-
- printf("----------------------------------\n");
- printf("Ending Enlistment\n");
-
- rc = SQLSetConnectOption (ptr->hdbc, SQL_DTC_DONE, (UDWORD)pTransaction);
-
- ProcessRC("SQLSetConnectOption",ptr,rc);
-
- }
-
- // ---------------------------------------------------------------------------
-
- void FreeODBCHandles(DBCONN *ptr)
- {
-
- printf("----------------------------------\n");
- printf("Freeing ODBC handles\n");
-
- SQLDisconnect(ptr->hdbc);
-
- SQLFreeConnect(ptr->hdbc);
-
- ptr->hdbc = SQL_NULL_HDBC;
- ptr->hstmt = SQL_NULL_HSTMT;
- }
-
-
- // ---------------------------------------------------------------------------
-
- BOOL ProcessRC(LPTSTR pszFuncName, DBCONN *ptr,RETCODE rc)
- {
-
- switch (rc)
- {
-
- case SQL_SUCCESS:
- printf("----------------------------------\n");
- printf("%s succeeded\n",pszFuncName);
- return TRUE;
- break;
-
- case SQL_SUCCESS_WITH_INFO:
- printf("----------------------------------\n");
- printf("%s succeeded with info\n",pszFuncName);
- DoSQLError(ptr);
- return TRUE;
- break;
-
- case SQL_ERROR:
- printf("----------------------------------\n");
- printf("%s Failed - see more info\n",pszFuncName);
- DoSQLError(ptr);
- exit(-1);
- return FALSE;
- break;
-
- case SQL_INVALID_HANDLE:
- printf("----------------------------------\n");
- printf("%s Failed - SQL_INVALID_HANDLE\n",pszFuncName);
- exit(-1);
- return FALSE;
- break;
-
- case SQL_NO_DATA_FOUND:
- printf("----------------------------------\n");
- printf("%s Failed - SQL_NO_DATA_FOUND\n",pszFuncName);
- return FALSE;
- break;
-
- case SQL_STILL_EXECUTING:
- printf("----------------------------------\n");
- printf("%s Failed - SQL_STILL_EXECUTING\n",pszFuncName);
- return FALSE;
- break;
-
- case SQL_NEED_DATA:
- printf("----------------------------------\n");
- printf("%s Failed - SQL_NEED_DATA\n",pszFuncName);
- return FALSE;
- break;
-
- default:
- printf("----------------------------------\n");
- printf("%s Failed - unexpected error, rc = %x\n",pszFuncName,rc);
- DoSQLError(ptr);
- exit(-1);
- return FALSE;
- break;
- }
-
- }
-
- // ---------------------------------------------------------------------------
-
- void DoSQLError(DBCONN *ptr)
- {
-
- const int MSG_BUF_SIZE = 300;
- unsigned char szSqlState[MSG_BUF_SIZE];
- unsigned char szErrorMsg[MSG_BUF_SIZE];
-
- SQLINTEGER fNativeError = 0;
- SWORD cbErrorMsg = MSG_BUF_SIZE;
- RETCODE rc;
-
- rc = SQLError(gHenv,
- ptr ? ptr->hdbc : 0,
- ptr ? ptr->hstmt : 0,
- szSqlState,
- &fNativeError,
- szErrorMsg,
- MSG_BUF_SIZE,
- &cbErrorMsg
- );
-
- if (rc != SQL_NO_DATA_FOUND || rc != SQL_ERROR)
- {
-
- printf("SQLError info:\n");
- printf("SqlState: %s, fNativeError: %x\n",szSqlState,fNativeError);
- printf("Error Message: %s\n",szErrorMsg);
- }
- else
- {
- printf("SQLError() failed: %x, NO_DATA_FOUND OR SQL_ERROR\n",rc);
- }
-
- }
- // ---------------------------------------------------------------------------