home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Internet Business Development Kit / PRODUCT_CD.iso / sqlsvr / ptk / i386 / mainodbc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-08  |  13.3 KB  |  492 lines

  1. /*    MSDTC Sample
  2. **
  3. **    This example uses the MSDTC (distributed transaction
  4. **    coordinator) to perform simultaneous update 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 the ODBC SQL driver with data source 
  11. **  names for use with this sample. 
  12. **
  13. **    In this particular example, table Authors in the pubs
  14. **  database that is installed with SQL server is utilized.
  15. **  Although the same update is performed on both servers,
  16. **  you can perform completely different updates on each server
  17. **  within the same transaction.
  18. **
  19. **
  20. */
  21.  
  22.  
  23.  
  24. //------------------------------------------------------------------------------
  25. // Include standard header files
  26. //------------------------------------------------------------------------------
  27. #include <windows.h>
  28. #include <stdio.h>
  29. #include <conio.h>
  30. #include <ctype.h>
  31.  
  32. //------------------------------------------------------------------------------
  33. // Include MSDTC specific header files.
  34. //------------------------------------------------------------------------------
  35. #define INITGUID
  36.  
  37. #include "txdtc.h"
  38. #include "xolehlp.h"
  39.  
  40.  
  41. //------------------------------------------------------------------------------
  42. // Include ODBC specific header file.
  43. //------------------------------------------------------------------------------
  44. #ifndef DBNTWIN32
  45. #define DBNTWIN32
  46.  
  47. #include <SQL.h>
  48. #include <SQLEXT.h>
  49. #include "odbcss.h"
  50. #include <ODBCINST.h>
  51.  
  52. #endif /* DBNTWIN32 */
  53.  
  54. //------------------------------------------------------------------------------
  55. // Define constants
  56. //------------------------------------------------------------------------------
  57. #define STR_LEN    40
  58.  
  59. #define TABLE_NAME        "Authors"    
  60.  
  61. //------------------------------------------------------------------------------
  62. // Define datatypes
  63. //------------------------------------------------------------------------------
  64. typedef struct DBCONN
  65. {
  66.     char    pszDSN    [STR_LEN];            // data source name, configured through control panel
  67.     char    pszUser [STR_LEN];            // Login user name
  68.     char    pszPasswd[STR_LEN];            // Login user password
  69.     HDBC    hdbc;                        // handle to an ODBC database connection
  70.     HSTMT    hstmt;                        // an ODBC statement handle, for use with SQLExecDirect
  71.  
  72. }    DBCONN;
  73.  
  74.  
  75. //------------------------------------------------------------------------------
  76. // Define Globals
  77. //------------------------------------------------------------------------------
  78. static DBCONN    gSrv1, gSrv2;        // global DB connection struct for server 1 and 2
  79.  
  80. static char gAuthorID[STR_LEN];        // use 11 chars only - per Authors table.
  81. static char gNewAddress[STR_LEN+1];    // max. address length in the Author's table.
  82.  
  83. //-------------------------------------------------------------------------------    
  84. //  ODBC specific global vars...
  85. //-------------------------------------------------------------------------------
  86. HENV        gHenv = SQL_NULL_HENV;
  87.  
  88. //-------------------------------------------------------------------------------    
  89. // Forward declaration of routines used.
  90. //-------------------------------------------------------------------------------    
  91.  
  92. void InitGlobals(int argc, char **argv);
  93. void LogonToDB(DBCONN *ptr);
  94. void InitODBC();
  95. void Enlist(DBCONN *ptr, ITransaction *pTransaction);
  96. void ExecuteStatement(DBCONN *ptr, char *pszBuf);
  97. void EndEnlistment(DBCONN *ptr, ITransaction *pTransaction);
  98. BOOL ProcessRC(LPTSTR pszFuncName, DBCONN *ptr, RETCODE rc);
  99. void DoSQLError(DBCONN *ptr);
  100. void FreeODBCHandles(DBCONN *ptr);
  101.  
  102.  
  103. //-------------------------------------------------------------------------------    
  104. // main()
  105. //-------------------------------------------------------------------------------    
  106.  
  107. void main(int argc, char **argv)
  108. {
  109.  
  110.     ITransactionDispenser *pTransactionDispenser;
  111.     ITransaction *pTransaction;
  112.     HRESULT    hr = S_OK ;
  113.     BOOL        tf = 0 ;
  114.     char    SqlStatement[STR_LEN*2];
  115.     
  116.  
  117.  
  118.     printf("/////////////////////////////////\n");
  119.     printf("//      MSDTC - ODBC Sample    //\n");
  120.     printf("/////////////////////////////////\n");
  121.  
  122.  
  123.     // Initialize globals & validate command line arguments
  124.     InitGlobals(argc,argv);
  125.  
  126.  
  127.     // Obtain an interface pointer from MSDTC proxy.
  128.     hr = DtcGetTransactionManager(     0,                             // LPTSTR  pszHost,
  129.                                     0,                             // LPTSTR    pszTmName,
  130.                                     IID_ITransactionDispenser,    // /* in */ REFIID rid,
  131.                                     0,                            // /* in */ DWORD    dwReserved1,
  132.                                     0,                             // /* in */ WORD    wcbReserved2,
  133.                                     0,                            // /* in */ void FAR * pvReserved2,
  134.                                     (void **)&pTransactionDispenser     // /*out */ void** ppvObject )    ;
  135.                                     ) ;
  136.     if (FAILED (hr))
  137.     {
  138.         printf("DtcGetTransactionManager failed: %x\n", hr);
  139.            exit (1);
  140.     }
  141.  
  142.     // Initialize the ODBC environment handle.
  143.     // Can only be done once in a given process.
  144.     InitODBC();
  145.  
  146.     // Establish connection to database on server#1
  147.     LogonToDB(&gSrv1);
  148.                      
  149.     // Establish connection to database on server#2
  150.     LogonToDB(&gSrv2);
  151.  
  152.     // Initiate an MSDTC transaction
  153.     printf("----------------------------------\n");
  154.     printf("Initiating BeginTransaction -- ");
  155.     hr = pTransactionDispenser->BeginTransaction( 
  156.             0,                                //    /* [in] */ IUnknown __RPC_FAR *punkOuter,
  157.             ISOLATIONLEVEL_ISOLATED,        //    /* [in] */ ISOLEVEL isoLevel,
  158.             ISOFLAG_RETAIN_DONTCARE,        //     /* [in] */ ULONG isoFlags,
  159.             0,                                //    /* [in] */ ULONG ulTimeout,
  160.             &pTransaction                    //    /* [out] */ ITransaction **ppTransaction) = 0;
  161.             ) ;
  162.         
  163.     if (FAILED (hr))
  164.     {    
  165.         printf("BeginTransaction failed: %x\n",hr);
  166.         exit(1);
  167.     }
  168.     else
  169.         printf("BeginTransaction Succeeded\n");
  170.  
  171.     // Enlist each of the data sources in the transaction
  172.     Enlist(&gSrv1,pTransaction);
  173.     Enlist(&gSrv2,pTransaction);
  174.  
  175.     // Generate the SQL statement to execute on each of the databases
  176.     sprintf(SqlStatement,
  177.             "update authors set address = '%s' where au_id = '%s'",
  178.              gNewAddress,gAuthorID
  179.            );
  180.     
  181.     // Perform updates on both of the DBs participating in the transaction
  182.     ExecuteStatement(&gSrv1,SqlStatement);
  183.     ExecuteStatement(&gSrv2,SqlStatement);
  184.  
  185.     // Commit the transaction 
  186.     printf("----------------------------------\n");
  187.     printf("Issuing Commit() -- ");
  188.     hr = pTransaction->Commit(0,0,0);
  189.     if (FAILED(hr))
  190.     {
  191.         printf("pTransaction->Commit() failed: %x\n",hr);
  192.         exit(1);
  193.     }
  194.  
  195.     printf("Commit() Succeeded\n");
  196.  
  197.     // Release Transaction
  198.  
  199.     printf("----------------------------------\n");
  200.     printf("Releasing Transaction --");
  201.  
  202.     hr = pTransaction->Release();
  203.     if (FAILED(hr))
  204.     {
  205.         printf("pTransaction->Commit() failed: %x\n",hr);
  206.         exit(1);
  207.     }
  208.     printf("Released Transactions\n");
  209.  
  210.     // release transaction dispenser
  211.     pTransactionDispenser->Release();
  212.  
  213.     // End ODBC enlistment mechanism
  214.     EndEnlistment(&gSrv1,pTransaction);
  215.     EndEnlistment(&gSrv2,pTransaction);
  216.  
  217.  
  218.     // Free ODBC handles
  219.     FreeODBCHandles(&gSrv1);
  220.     FreeODBCHandles(&gSrv2);
  221.  
  222.     // Free the global ODBC environment handle.
  223.     SQLFreeEnv(gHenv);
  224.     
  225. }
  226.  
  227.  
  228.  
  229. //-------------------------------------------------------------------------------    
  230. #define ARGS    9    // Requires 9 arguments (strings) to run this program.
  231.  
  232. void InitGlobals(int argc, char **argv)
  233. {
  234.  
  235.     if (argc != ARGS)
  236.     {
  237.         printf("Usage: %s DSN1  Logon1 Passwd1  DSN2 Logon2 Passwd2 AuthorID NewAddress\n",*argv);
  238.         printf("Note: Null arguments must be supplied as \"\"\n");
  239.         exit(1);
  240.     }
  241.  
  242.     // Init Server1
  243.     strcpy(gSrv1.pszDSN,*++argv);
  244.     strcpy(gSrv1.pszUser,*++argv);
  245.     strcpy(gSrv1.pszPasswd,*++argv);
  246.  
  247.     // Init Server2
  248.     strcpy(gSrv2.pszDSN,*++argv);
  249.     strcpy(gSrv2.pszUser,*++argv);
  250.     strcpy(gSrv2.pszPasswd,*++argv);
  251.  
  252.     // Init the author ID
  253.     strcpy(gAuthorID,*++argv);
  254.  
  255.     // Init the global new address
  256.     strcpy(gNewAddress,*++argv);
  257.  
  258.     // Init ODBC handles to be invalid
  259.     gSrv1.hdbc = SQL_NULL_HDBC;
  260.     gSrv1.hstmt= SQL_NULL_HSTMT;
  261.  
  262.     gSrv2.hdbc = SQL_NULL_HDBC;
  263.     gSrv2.hstmt= SQL_NULL_HSTMT;
  264.  
  265. } // InitGlobals(int argc, char **argv)
  266.  
  267. //-------------------------------------------------------------------------------    
  268.  
  269. void LogonToDB(DBCONN *ptr)
  270. {
  271.     RETCODE rc = 0;
  272.  
  273.     rc = SQLAllocConnect(gHenv, &(ptr->hdbc) );
  274.  
  275.     if (ProcessRC("SQLAllocConnect",ptr,rc))
  276.     {
  277.         printf("Connecting to DSN: %s\n",ptr->pszDSN);
  278.          
  279.         rc = SQLConnect(ptr->hdbc, 
  280.                         (unsigned char *)(ptr->pszDSN),
  281.                         SQL_NTS,
  282.                         (unsigned char *)(ptr->pszUser),
  283.                         SQL_NTS,
  284.                         (unsigned char *)(ptr->pszPasswd),
  285.                         SQL_NTS
  286.                         );
  287.  
  288.         ProcessRC("SQLConnect",ptr,rc);
  289.     }
  290. }
  291.  
  292. //-------------------------------------------------------------------------------    
  293.  
  294. void InitODBC()
  295. {
  296.     RETCODE rc = 0;
  297.  
  298.     // Initialize the ODBC environment handle, done once for all connections.
  299.  
  300.     if (SQL_NULL_HENV == gHenv)
  301.     {
  302.         rc =  SQLAllocEnv(&gHenv);
  303.     
  304.         ProcessRC("SQLAllocEnv",0,rc);
  305.     }
  306.  
  307. }
  308.  
  309. //-------------------------------------------------------------------------------    
  310.  
  311. void Enlist(DBCONN *ptr, ITransaction *pTransaction)
  312. {
  313.     RETCODE rc = 0;
  314.  
  315.     // Enlist database in the transaction
  316.     printf("----------------------------------\n");
  317.     printf("Enlisting DataSource: %s\n",ptr->pszDSN);
  318.  
  319.     rc = SQLSetConnectOption (ptr->hdbc, SQL_COPT_SS_ENLIST_IN_DTC, (UDWORD)pTransaction);
  320.  
  321.     ProcessRC("SQLSetConnectOption",ptr,rc);
  322.  
  323.     printf("Enlistment Succeeded\n");
  324. }
  325.  
  326.  
  327. // ---------------------------------------------------------------------------
  328.  
  329. void ExecuteStatement(DBCONN *ptr, char *pszBuf)
  330. {
  331.     RETCODE rc = 0;
  332.  
  333.     // Allocate a statement handle for use with SQLExecDirect
  334.     rc = SQLAllocStmt(ptr->hdbc,&(ptr->hstmt));
  335.     
  336.     ProcessRC("SQLAllocStmt",ptr,rc);
  337.     
  338.  
  339.     // Execute the passed string as a SQL statement
  340.     printf("----------------------------------\n");
  341.     printf("Executing the following SQL statement on DataSource: %s\n",ptr->pszDSN);
  342.     printf("%s\n",pszBuf);
  343.     rc = SQLExecDirect(ptr->hstmt,(unsigned char *)pszBuf,SQL_NTS);
  344.     
  345.     ProcessRC("SQLExecDirect",ptr,rc);
  346.  
  347.     printf("Executing the SQL statement succeeded\n");
  348.  
  349.     // Free the statement handle 
  350.     rc = SQLFreeStmt(ptr->hstmt, SQL_DROP);
  351.     ptr->hstmt = SQL_NULL_HSTMT;
  352.  
  353.     ProcessRC("SQLFreeStmt",ptr,rc);
  354.     
  355. }
  356.  
  357. // ---------------------------------------------------------------------------
  358.  
  359. void EndEnlistment(DBCONN *ptr, ITransaction *pTransaction)
  360. {
  361.     RETCODE rc = 0;
  362.  
  363.     // remove the ODBC connection handle from the transaction
  364.     
  365.     printf("----------------------------------\n");
  366.     printf("Ending Enlistment\n");
  367.  
  368.     rc = SQLSetConnectOption (ptr->hdbc, SQL_DTC_DONE, (UDWORD)pTransaction);
  369.     
  370.     ProcessRC("SQLSetConnectOption",ptr,rc);
  371.  
  372. }
  373.  
  374. // ---------------------------------------------------------------------------
  375.  
  376. void FreeODBCHandles(DBCONN *ptr)
  377. {
  378.  
  379.     printf("----------------------------------\n");
  380.     printf("Freeing ODBC handles\n");
  381.  
  382.     SQLDisconnect(ptr->hdbc);
  383.     
  384.     SQLFreeConnect(ptr->hdbc);
  385.     
  386.     ptr->hdbc   = SQL_NULL_HDBC;
  387.     ptr->hstmt  = SQL_NULL_HSTMT;
  388. }
  389.  
  390.  
  391. // ---------------------------------------------------------------------------
  392.  
  393. BOOL ProcessRC(LPTSTR pszFuncName, DBCONN *ptr,RETCODE rc)
  394. {
  395.  
  396.     switch (rc)
  397.     {
  398.         
  399.     case SQL_SUCCESS:
  400.             printf("----------------------------------\n");
  401.             printf("%s succeeded\n",pszFuncName);
  402.             return TRUE;
  403.             break;
  404.  
  405.     case SQL_SUCCESS_WITH_INFO:
  406.             printf("----------------------------------\n");
  407.             printf("%s succeeded with info\n",pszFuncName);
  408.             DoSQLError(ptr);
  409.             return TRUE;
  410.             break;
  411.  
  412.     case SQL_ERROR:
  413.             printf("----------------------------------\n");
  414.             printf("%s Failed - see more info\n",pszFuncName);
  415.             DoSQLError(ptr);
  416.             exit(-1);
  417.             return FALSE;
  418.             break;
  419.  
  420.     case SQL_INVALID_HANDLE:
  421.             printf("----------------------------------\n");
  422.             printf("%s Failed - SQL_INVALID_HANDLE\n",pszFuncName);
  423.             exit(-1);
  424.             return FALSE;
  425.             break;
  426.  
  427.     case SQL_NO_DATA_FOUND:
  428.             printf("----------------------------------\n");
  429.             printf("%s Failed - SQL_NO_DATA_FOUND\n",pszFuncName);
  430.             return FALSE;
  431.             break;
  432.  
  433.     case SQL_STILL_EXECUTING:
  434.             printf("----------------------------------\n");
  435.             printf("%s Failed - SQL_STILL_EXECUTING\n",pszFuncName);
  436.             return FALSE;
  437.             break;
  438.  
  439.     case SQL_NEED_DATA:
  440.             printf("----------------------------------\n");
  441.             printf("%s Failed - SQL_NEED_DATA\n",pszFuncName);
  442.             return FALSE;
  443.             break;
  444.  
  445.     default:
  446.             printf("----------------------------------\n");
  447.             printf("%s Failed - unexpected error, rc = %x\n",pszFuncName,rc);
  448.             DoSQLError(ptr);
  449.             exit(-1);
  450.             return FALSE;
  451.             break;
  452.     }
  453.  
  454. }
  455.  
  456. // ---------------------------------------------------------------------------
  457.  
  458. void DoSQLError(DBCONN *ptr)
  459. {
  460.  
  461.     const     int    MSG_BUF_SIZE = 300;
  462.     unsigned char     szSqlState[MSG_BUF_SIZE];
  463.     unsigned char    szErrorMsg[MSG_BUF_SIZE];
  464.     
  465.     SQLINTEGER    fNativeError    = 0;
  466.     SWORD        cbErrorMsg        = MSG_BUF_SIZE;
  467.     RETCODE        rc;
  468.  
  469.     rc = SQLError(gHenv,
  470.                   ptr ? ptr->hdbc : 0,
  471.                   ptr ? ptr->hstmt : 0,
  472.                   szSqlState,
  473.                   &fNativeError,
  474.                   szErrorMsg,
  475.                   MSG_BUF_SIZE,
  476.                   &cbErrorMsg
  477.                   );
  478.  
  479.     if (rc != SQL_NO_DATA_FOUND || rc != SQL_ERROR)
  480.     {
  481.         
  482.         printf("SQLError info:\n");
  483.         printf("SqlState: %s, fNativeError: %x\n",szSqlState,fNativeError);
  484.         printf("Error Message: %s\n",szErrorMsg);
  485.     }
  486.     else
  487.     {    
  488.         printf("SQLError() failed: %x, NO_DATA_FOUND OR SQL_ERROR\n",rc);
  489.     }
  490.  
  491. }
  492. // ---------------------------------------------------------------------------