ODBC.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:14k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /* MS DTC Sample
  2. **
  3. ** This example uses MS DTC (distributed transaction
  4. ** coordinator) to perform simultaneous updates on two
  5. ** SQL servers.  The transaction in this example is 
  6. ** client initiated. The client also initiates the
  7. ** commit operation.
  8. **
  9. **  As this sample uses the ODBC interface, you'll need
  10. **  to configure ODBC data source names for 2 SQL servers
  11. **  that you can use to run this sample.  Each DSN; data
  12. **  source name,  must point to the pubs database in
  13. **  a separate SQL server. The authors table in the pubs
  14. **  database is used in this sample.
  15. **
  16. **  Build Instructions:
  17. **  This sample must link with the following files:  xolehlp.lib, odbc32.lib, odbccp32.lib
  18. **
  19. **  Usage Instructions:
  20. **  Please run this program with the '-h' flag.
  21. **
  22. */
  23. //------------------------------------------------------------------------------
  24. // Include standard header files
  25. //------------------------------------------------------------------------------
  26. #include <windows.h>
  27. #include <stdio.h>
  28. #include <conio.h>
  29. #include <ctype.h>
  30. //------------------------------------------------------------------------------
  31. // Include MS DTC specific header files.
  32. //------------------------------------------------------------------------------
  33. #define INITGUID
  34. #include "txdtc.h"
  35. #include "xolehlp.h"
  36. //------------------------------------------------------------------------------
  37. // Include ODBC specific header file.
  38. //------------------------------------------------------------------------------
  39. #ifndef DBNTWIN32
  40. #define DBNTWIN32
  41. #include <SQL.h>
  42. #include <SQLEXT.h>
  43. #include "odbcss.h"
  44. #include <ODBCINST.h>
  45. #endif /* DBNTWIN32 */
  46. //------------------------------------------------------------------------------
  47. // Define constants
  48. //------------------------------------------------------------------------------
  49. #define STR_LEN 40
  50. //------------------------------------------------------------------------------
  51. // Define datatypes
  52. //------------------------------------------------------------------------------
  53. typedef struct DBCONN
  54. {
  55. TCHAR pszSrv [STR_LEN]; // data source name, configured through control panel
  56. TCHAR pszUser [STR_LEN]; // Login user name
  57. TCHAR pszPasswd[STR_LEN]; // Login user password
  58. HDBC hdbc; // handle to an ODBC database connection
  59. HSTMT hstmt; // an ODBC statement handle, for use with SQLExecDirect
  60. } DBCONN;
  61. //------------------------------------------------------------------------------
  62. // Define Globals
  63. //------------------------------------------------------------------------------
  64. static DBCONN gSrv1, gSrv2; // global DB connection struct for server 1 and 2
  65. static TCHAR gAuthorID[STR_LEN]; // use 11 chars only - per Authors table.
  66. static TCHAR gNewAddress[STR_LEN+1]; // max. address length in the Author's table.
  67. //-------------------------------------------------------------------------------
  68. //  ODBC specific global vars...
  69. //-------------------------------------------------------------------------------
  70. HENV gHenv = SQL_NULL_HENV;
  71. //-------------------------------------------------------------------------------
  72. // Forward declaration of routines used.
  73. //-------------------------------------------------------------------------------
  74. void InitGlobals(int argc, char **argv);
  75. void LogonToDB(DBCONN *ptr);
  76. void Enlist(DBCONN *ptr, ITransaction *pTransaction);
  77. void ExecuteStatement(DBCONN *ptr, LPTSTR pszBuf);
  78. BOOL ProcessRC(LPTSTR pszFuncName, DBCONN *ptr, RETCODE rc);
  79. void DoSQLError(DBCONN *ptr);
  80. void FreeODBCHandles(DBCONN *ptr);
  81. //-------------------------------------------------------------------------------
  82. // main()
  83. //-------------------------------------------------------------------------------
  84. void main(int argc, char **argv)
  85. {
  86. ITransactionDispenser *pTransactionDispenser;
  87. ITransaction *pTransaction;
  88. HRESULT hr = S_OK ;
  89. BOOL tf = 0 ;
  90. TCHAR SqlStatement[STR_LEN*2];
  91. // Initialize globals & validate command line arguments
  92. InitGlobals(argc,argv);
  93. // Obtain the ITransactionDispenser Interface pointer
  94. // by calling DtcGetTransactionManager()
  95. hr = DtcGetTransactionManager(
  96. NULL, // LPTSTR  pszHost,
  97. NULL, // LPTSTR  pszTmName,
  98. IID_ITransactionDispenser, // /* in  */ REFIID rid,
  99. 0, // /* in  */ DWORD dwReserved1,
  100. 0,  // /* in  */ WORD wcbReserved2,
  101. NULL, // /* in  */ void FAR * pvReserved2,
  102. (void **)&pTransactionDispenser  // /* out */ void** ppvObject
  103. );
  104. if (FAILED (hr))
  105. {
  106. printf("DtcGetTransactionManager failed: %xn", hr);
  107.     exit (1);
  108. }
  109. // Initialize the ODBC environment handle.
  110. if (SQL_NULL_HENV == gHenv)
  111. {
  112. ProcessRC("SQLAllocEnv",0,SQLAllocEnv(&gHenv));
  113. }
  114. // Establish connection to database on server#1
  115. LogonToDB(&gSrv1);
  116.  
  117. // Establish connection to database on server#2
  118. LogonToDB(&gSrv2);
  119. // Loop performing distributed transactions
  120. for (INT i = 0; i < 5; i++)
  121. {
  122. // Initiate an MS DTC transaction
  123. hr = pTransactionDispenser->BeginTransaction( 
  124. NULL, // /* [in]  */ IUnknown __RPC_FAR *punkOuter,
  125. ISOLATIONLEVEL_ISOLATED, // /* [in]  */ ISOLEVEL isoLevel,
  126. ISOFLAG_RETAIN_DONTCARE, //  /* [in]  */ ULONG isoFlags,
  127. NULL, // /* [in]  */ ITransactionOptions *pOptions 
  128. &pTransaction // /* [out] */ ITransaction **ppTransaction
  129. ) ;
  130. if (FAILED (hr))
  131. {
  132. printf("BeginTransaction failed: %xn",hr);
  133. exit(1);
  134. }
  135. // Enlist each of the data sources in the transaction
  136. Enlist(&gSrv1,pTransaction);
  137. Enlist(&gSrv2,pTransaction);
  138. // Generate the SQL statement to execute on each of the databases
  139. sprintf(SqlStatement,
  140. "update authors set address = '%s_%d' where au_id = '%s'",
  141.  gNewAddress,i,gAuthorID);
  142. // Perform updates on both of the DBs participating in the transaction
  143. ExecuteStatement(&gSrv1,SqlStatement);
  144. ExecuteStatement(&gSrv2,SqlStatement);
  145. // Commit the transaction 
  146. hr = pTransaction->Commit(0,0,0);
  147. if (FAILED(hr))
  148. {
  149. printf("pTransaction->Commit() failed: %xn",hr);
  150. exit(1);
  151. }
  152. // At end of each transaction, pTransaction-Release() must be called.
  153. hr = pTransaction->Release();
  154. if (FAILED(hr))
  155. {
  156. printf("pTransaction->Release() failed: %xn",hr);
  157. exit(1);
  158. }
  159. printf("Successfully committed Transaction #%dn",i);
  160. } // for 
  161. // release the transaction dispenser
  162. pTransactionDispenser->Release();
  163. // Free ODBC handles
  164. FreeODBCHandles(&gSrv1);
  165. FreeODBCHandles(&gSrv2);
  166. // Free the global ODBC environment handle.
  167. SQLFreeEnv(gHenv);
  168. }
  169. //-------------------------------------------------------------------------------
  170. void InitGlobals(INT argc, char **argv)
  171. {
  172. TCHAR Usage[] = "n           [-S1  server_1] n"
  173. "           [-U1  user_name_1]n"
  174. "           [-P1  passwd_1]n"
  175. "           [-S2  server_2]n"
  176. "           [-U2  user_name_2]n"
  177. "           [-P2  passwd_2]n"
  178.         "           [-ID  au_id]n"
  179. "           [-Ad  new_addressn"
  180. "           [-h   Usage]n";
  181. // Init ODBC handles to be invalid
  182.     gSrv1.hdbc = SQL_NULL_HDBC;
  183. gSrv1.hstmt= SQL_NULL_HSTMT;
  184.     gSrv2.hdbc = SQL_NULL_HDBC;
  185. gSrv2.hstmt= SQL_NULL_HSTMT;
  186. // Null login info, set defaults as appropriate
  187. lstrcpy(gSrv1.pszSrv,"");
  188. lstrcpy(gSrv1.pszUser,"sa");
  189. lstrcpy(gSrv1.pszPasswd,"");
  190. lstrcpy(gSrv2.pszSrv,"");
  191. lstrcpy(gSrv2.pszUser,"sa");
  192. lstrcpy(gSrv2.pszPasswd,"");
  193. lstrcpy(gAuthorID,"172-32-1176"); // default au_id value from authors table in pubs db.
  194. // scan command line arguments for user input.
  195. for (INT i = 1; i < argc; i++)
  196. {
  197. if (*argv[i] == '-' || *argv[i] == '/')
  198. {
  199. switch (argv[i][1])
  200. {
  201. // get the server or DSN name
  202. case 's':
  203. case 'S':
  204.  switch (argv[i][2])
  205.  {
  206.  case '1':
  207.  lstrcpy(gSrv1.pszSrv,argv[++i]);
  208.  break;
  209.  case '2':
  210.  lstrcpy(gSrv2.pszSrv,argv[++i]);
  211.  break;
  212.  default:
  213.  printf("Invalid Input %sn",argv[i]);
  214.  printf("nUsage: %s %s",argv[0],Usage);
  215.  exit(1);
  216.  };
  217.  break;
  218. // get user name
  219. case 'u':
  220. case 'U':
  221.  switch (argv[i][2])
  222.  {
  223.  case '1':
  224.  lstrcpy(gSrv1.pszUser,argv[++i]);
  225.  break;
  226.  case '2':
  227.  lstrcpy(gSrv2.pszUser,argv[++i]);
  228.  break;
  229.  default:
  230.  printf("Invalid Input %sn",argv[i]);
  231.  printf("nUsage: %s %s",argv[0],Usage);
  232.  exit(1);
  233.  };
  234.  break;
  235. // get password
  236. case 'p':
  237. case 'P':
  238.  switch (argv[i][2])
  239.  {
  240.  case '1':
  241.  lstrcpy(gSrv1.pszPasswd,argv[++i]);
  242.  break;
  243.  case '2':
  244.  lstrcpy(gSrv2.pszPasswd,argv[++i]);
  245.  break;
  246.  default:
  247.  printf("Invalid Input %sn",argv[i]);
  248.  printf("nUsage: %s %s",argv[0],Usage);
  249.  exit(1);
  250.    };
  251.  break;
  252. // get au_id, overriding default value.
  253. case 'i':
  254. case 'I':
  255. lstrcpy(gAuthorID,argv[++i]);
  256. break;
  257. // get new address to associate with the au_id
  258. case 'a':
  259. case 'A':
  260. lstrcpy(gNewAddress,argv[++i]);
  261. break;
  262. case '?':
  263. case 'h':
  264. case 'H':
  265. printf("nUsage: %s %s",argv[0],Usage);
  266. exit(1);
  267. break;
  268. default:
  269. printf("Invalid Input: %sn",argv[i]);
  270. printf("nUsage: %s %s",argv[0],Usage);
  271. exit(1);
  272. }
  273. }
  274. else 
  275. {
  276. printf("Illegal command line argument #%d, %sn",i,argv[i]);
  277. printf("nUsage: %s %s",argv[0],Usage);
  278. exit(1);
  279. }
  280. }
  281. printf("-----------------------------n");
  282. printf("MS DTC/ODBC Sample Configuration parametersn");
  283. printf( "server_1:      %sn"
  284. "user_name_1:   %sn"
  285. "passwd_1:      %sn"
  286. "server_2:      %sn"
  287. "user_name_2:   %sn"
  288. "passwd_2:      %sn",
  289. gSrv1.pszSrv,gSrv1.pszUser,gSrv1.pszPasswd,
  290. gSrv2.pszSrv,gSrv2.pszUser,gSrv2.pszPasswd);
  291. printf("-----------------------------n");
  292. }
  293. //-------------------------------------------------------------------------------
  294. void LogonToDB(DBCONN *ptr)
  295. {
  296. RETCODE rc = 0;
  297. rc = SQLAllocConnect(gHenv, &(ptr->hdbc) );
  298. if (ProcessRC("SQLAllocConnect",ptr,rc))
  299. {
  300. rc = SQLConnect(ptr->hdbc, 
  301. (UCHAR *)(ptr->pszSrv),
  302. SQL_NTS,
  303. (UCHAR *)(ptr->pszUser),
  304. SQL_NTS,
  305. (UCHAR *)(ptr->pszPasswd),
  306. SQL_NTS
  307. );
  308. ProcessRC("SQLConnect",ptr,rc);
  309. }
  310. }
  311. //-------------------------------------------------------------------------------
  312. void Enlist(DBCONN *ptr, ITransaction *pTransaction)
  313. {
  314. RETCODE rc = 0;
  315. // Enlist database in the transaction
  316.     rc = SQLSetConnectOption (ptr->hdbc, SQL_COPT_SS_ENLIST_IN_DTC, (UDWORD)pTransaction);
  317. ProcessRC("SQLSetConnectOption",ptr,rc);
  318. }
  319. // ---------------------------------------------------------------------------
  320. void ExecuteStatement(DBCONN *ptr, LPTSTR pszBuf)
  321. {
  322. RETCODE rc = 0;
  323. // Allocate a statement handle for use with SQLExecDirect
  324. rc = SQLAllocStmt(ptr->hdbc,&(ptr->hstmt));
  325. ProcessRC("SQLAllocStmt",ptr,rc);
  326. // Execute the passed string as a SQL statement
  327.     rc = SQLExecDirect(ptr->hstmt,(UCHAR *)pszBuf,SQL_NTS);
  328. ProcessRC("SQLExecDirect",ptr,rc);
  329. // Free the statement handle 
  330. rc = SQLFreeStmt(ptr->hstmt, SQL_DROP);
  331. ptr->hstmt = SQL_NULL_HSTMT;
  332. ProcessRC("SQLFreeStmt",ptr,rc);
  333. }
  334. // ---------------------------------------------------------------------------
  335. void FreeODBCHandles(DBCONN *ptr)
  336. {
  337. SQLDisconnect(ptr->hdbc);
  338. SQLFreeConnect(ptr->hdbc);
  339. ptr->hdbc   = SQL_NULL_HDBC;
  340. ptr->hstmt  = SQL_NULL_HSTMT;
  341. }
  342. // ---------------------------------------------------------------------------
  343. BOOL ProcessRC(LPTSTR pszFuncName, DBCONN *ptr,RETCODE rc)
  344. {
  345. switch (rc)
  346. {
  347. case SQL_SUCCESS:
  348. return TRUE;
  349. break;
  350. case SQL_SUCCESS_WITH_INFO:
  351. DoSQLError(ptr);
  352. return TRUE;
  353. break;
  354. case SQL_ERROR:
  355. printf("%s Failed - see more infon",pszFuncName);
  356. DoSQLError(ptr);
  357. exit(-1);
  358. return FALSE;
  359. break;
  360. case SQL_INVALID_HANDLE:
  361. printf("%s Failed - SQL_INVALID_HANDLEn",pszFuncName);
  362. exit(-1);
  363. return FALSE;
  364. break;
  365. case SQL_NO_DATA_FOUND:
  366. printf("%s Failed - SQL_NO_DATA_FOUNDn",pszFuncName);
  367. return FALSE;
  368. break;
  369. case SQL_STILL_EXECUTING:
  370. printf("%s Failed - SQL_STILL_EXECUTINGn",pszFuncName);
  371. return FALSE;
  372. break;
  373. case SQL_NEED_DATA:
  374. printf("%s Failed - SQL_NEED_DATAn",pszFuncName);
  375. return FALSE;
  376. break;
  377. default:
  378. printf("%s Failed - unexpected error, rc = %xn",pszFuncName,rc);
  379. DoSQLError(ptr);
  380. exit(-1);
  381. return FALSE;
  382. break;
  383. }
  384. }
  385. // ---------------------------------------------------------------------------
  386. void DoSQLError(DBCONN *ptr)
  387. {
  388. const INT MSG_BUF_SIZE = 300;
  389. UCHAR    szSqlState[MSG_BUF_SIZE];
  390. UCHAR szErrorMsg[MSG_BUF_SIZE];
  391. SQLINTEGER fNativeError = 0;
  392. SWORD cbErrorMsg = MSG_BUF_SIZE;
  393. RETCODE rc;
  394. rc = SQLError(gHenv,
  395.   ptr ? ptr->hdbc : 0,
  396.   ptr ? ptr->hstmt : 0,
  397.   szSqlState,
  398.   &fNativeError,
  399.   szErrorMsg,
  400.   MSG_BUF_SIZE,
  401.   &cbErrorMsg
  402.   );
  403. if (rc != SQL_NO_DATA_FOUND || rc != SQL_ERROR)
  404. {
  405. if (fNativeError != 0x1645) // ignore change database to master context message
  406. {
  407. printf("SQLError info:n");
  408. printf("SqlState: %s, fNativeError: %xn",szSqlState,fNativeError);
  409. printf("Error Message: %sn",szErrorMsg);
  410. }
  411. }
  412. else
  413. {
  414. printf("SQLError() failed: %x, NO_DATA_FOUND OR SQL_ERRORn",rc);
  415. }
  416. }
  417. // ---------------------------------------------------------------------------