home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / sql / msdtc / dblib / dblib.cpp next >
Encoding:
C/C++ Source or Header  |  1996-04-03  |  12.5 KB  |  468 lines

  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. **  This sample uses the DBLib interface to communicate
  10. **  with both MS DTC and SQL server.
  11. **
  12. **    In this particular example, the pre-installed SQL server
  13. **    table "Authors" is used.
  14. **
  15. **  Build Instructions:
  16. **  This sample must link with the following files:  ntwdblib.lib, xolehlp.lib
  17. **
  18. **  Usage Instructions:
  19. **  Please run this program with the '-h' flag.
  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 MS DTC specific header files.
  34. //------------------------------------------------------------------------------
  35. #define INITGUID
  36.  
  37. #include "txdtc.h"
  38. #include "xolehlp.h"
  39.  
  40. //------------------------------------------------------------------------------
  41. // Include DBLib specific header files
  42. //------------------------------------------------------------------------------
  43. #ifndef DBNTWIN32
  44. #define DBNTWIN32
  45.  
  46. #include <SQL.h>
  47. #include <SQLEXT.h>
  48. #include <sqlfront.h>
  49. #include <sqldb.h>
  50.  
  51. #endif /* DBNTWIN32 */
  52.  
  53. //------------------------------------------------------------------------------
  54. // Define constants
  55. //------------------------------------------------------------------------------
  56. #define STR_LEN    40
  57.  
  58. #define TABLE_NAME        "Authors"    
  59.  
  60. //------------------------------------------------------------------------------
  61. // Define datatypes
  62. //------------------------------------------------------------------------------
  63. typedef struct DBCONN
  64. {
  65.     TCHAR    pszSrv    [STR_LEN];            // data source name, configured through control panel
  66.     TCHAR    pszUser [STR_LEN];            // Login user name
  67.     TCHAR    pszPasswd[STR_LEN];            // Login user password
  68.     TCHAR    pszTableName[STR_LEN];        // not used - should remove.
  69.  
  70. }    DBCONN;
  71.  
  72.  
  73. //------------------------------------------------------------------------------
  74. // Define Globals
  75. //------------------------------------------------------------------------------
  76. static DBCONN    gSrv1, gSrv2;        // global DB connection struct for server 1 and 2
  77.  
  78. static TCHAR gAuthorID[STR_LEN];        // use 11 chars only - per Authors table.
  79. static TCHAR gNewAddress[STR_LEN+1];    // max. address length in the Author's table.
  80.  
  81. //-------------------------------------------------------------------------------    
  82. //  DBLib specific global vars...
  83. //-------------------------------------------------------------------------------
  84. DBPROCESS    *dbproc_server1;
  85. DBPROCESS    *dbproc_server2;
  86. LOGINREC    *login;
  87.  
  88.  
  89. //-------------------------------------------------------------------------------    
  90. // Forward declaration of routines used.
  91. //-------------------------------------------------------------------------------    
  92.  
  93. void InitGlobals(int argc, char **argv);
  94. void LogonToDB(DBPROCESS **dbp, DBCONN *ptr);
  95. void Enlist(DBCONN *ptr,DBPROCESS *dbp, ITransaction *pTransaction);
  96. void ExecuteStatement(DBCONN *ptr, DBPROCESS *dbp, LPTSTR pszBuf);
  97.  
  98. //-------------------------------------------------------------------------------
  99. // DBLib error and message handlers
  100. //-------------------------------------------------------------------------------
  101. int err_handler(DBPROCESS*, int, int, int, char*, char*);
  102. int msg_handler(DBPROCESS*, DBINT, int, int, char*);
  103.  
  104.  
  105. //-------------------------------------------------------------------------------    
  106. // main()
  107. //-------------------------------------------------------------------------------    
  108.  
  109. void main(int argc, char **argv)
  110. {
  111.  
  112.     ITransactionDispenser        *pTransactionDispenser;
  113.     ITransaction                *pTransaction;
  114.     HRESULT                        hr = S_OK ;
  115.     TCHAR                        SqlStatement[STR_LEN*2];
  116.  
  117.  
  118.     // Initialize globals & validate command line arguments
  119.     InitGlobals(argc,argv);
  120.  
  121.     // set error/msg handlers for this program
  122.     dbmsghandle((DBMSGHANDLE_PROC)msg_handler);
  123.     dberrhandle((DBERRHANDLE_PROC)err_handler);
  124.  
  125.     // initialize LOGINREC structure
  126.     login = dblogin();
  127.  
  128.     // Obtain the ITransactionDispenser Interface pointer
  129.     // by calling DtcGetTransactionManager()
  130.     hr = DtcGetTransactionManager(     NULL,                             // LPTSTR    pszHost,
  131.                                     NULL,                             // LPTSTR    pszTmName,
  132.                                     IID_ITransactionDispenser,        // /* in */ REFIID    rid,
  133.                                     0,                                // /* in */ DWORD    dwReserved1,
  134.                                     0,                                 // /* in */ WORD    wcbReserved2,
  135.                                     0,                                // /* in */ void    FAR * pvReserved2,
  136.                                     (void **)&pTransactionDispenser // /*out */ void**    ppvObject
  137.                                     ) ;
  138.     if (FAILED (hr))
  139.     {
  140.         printf("DtcGetTransactionManager failed: %x\n", hr);
  141.            exit (1);
  142.     }
  143.  
  144.     // Establish connection to database on server#1
  145.     LogonToDB(&dbproc_server1,&gSrv1);
  146.                      
  147.     // Establish connection to database on server#2
  148.     LogonToDB(&dbproc_server2,&gSrv2);
  149.  
  150.     // Loop performing distributed transactions
  151.     for (INT i = 0; i < 5; i++)
  152.     {
  153.  
  154.         // Initiate an MS DTC transaction
  155.         hr = pTransactionDispenser->BeginTransaction( 
  156.                 NULL,                            //    /* [in]  */ IUnknown __RPC_FAR *punkOuter,
  157.                 ISOLATIONLEVEL_ISOLATED,        //    /* [in]  */ ISOLEVEL isoLevel,
  158.                 ISOFLAG_RETAIN_DONTCARE,        //     /* [in]  */ ULONG isoFlags,
  159.                 NULL,                            //    /* [in]  */    ITransactionOptions *pOptions 
  160.                 &pTransaction                    //    /* [out] */ ITransaction **ppTransaction
  161.                 ) ;
  162.             
  163.         if (FAILED (hr))
  164.         {    
  165.             printf("BeginTransaction failed: %x\n",hr);
  166.             exit(1);
  167.         }
  168.  
  169.         // Enlist each of the data sources on the transaction
  170.         Enlist(&gSrv1,dbproc_server1,pTransaction);
  171.         Enlist(&gSrv2,dbproc_server2,pTransaction);
  172.  
  173.         // Generate the SQL statement to execute on each of the databases
  174.         sprintf(SqlStatement,
  175.                 "update authors set address = '%s_%d' where au_id = '%s'",
  176.                  gNewAddress,i,gAuthorID);
  177.         
  178.         // Perform updates on both of the DBs participating in the transaction
  179.         ExecuteStatement(&gSrv1,dbproc_server1,SqlStatement);
  180.         ExecuteStatement(&gSrv2,dbproc_server2,SqlStatement);
  181.  
  182.         // Commit the transaction 
  183.         hr = pTransaction->Commit(0,0,0);
  184.         if (FAILED(hr))
  185.         {
  186.             printf("pTransaction->Commit() failed: %x\n",hr);
  187.             exit(1);
  188.         }
  189.  
  190.         // At end of each transaction, pTransaction-Release() must be called.
  191.         hr = pTransaction->Release();
  192.         if (FAILED(hr))
  193.         {
  194.             printf("pTransaction->Release() failed: %x\n",hr);
  195.             exit(1);
  196.         }
  197.  
  198.         printf("Successfully committed Transaction #%d\n",i);
  199.  
  200.     } // for 
  201.  
  202.  
  203.     // release the transaction dispenser
  204.     pTransactionDispenser->Release();
  205.  
  206.     // release DBLib resources and exit
  207.     dbexit();
  208. }
  209.  
  210.  
  211.  
  212. //-------------------------------------------------------------------------------    
  213.  
  214. void InitGlobals(INT argc, char **argv)
  215. {
  216.  
  217.     TCHAR Usage[] = "\n           [-S1  server_1] \n"        \
  218.                     "           [-U1  user_name_1]\n"    \
  219.                     "           [-P1  passwd_1]\n"        \
  220.                     "           [-S2  server_2]\n"        \
  221.                     "           [-U2  user_name_2]\n"    \
  222.                     "           [-P2  passwd_2]\n"        \
  223.                     "           [-ID  au_id]\n"            \
  224.                     "           [-Ad  new_address\n"    \
  225.                     "           [-h   Usage]\n";
  226.  
  227.     // Init Table name 
  228.     lstrcpy(gSrv1.pszTableName,TABLE_NAME);
  229.     lstrcpy(gSrv2.pszTableName,TABLE_NAME);
  230.  
  231.  
  232.     // Null login info, set defaults as appropriate
  233.  
  234.     lstrcpy(gSrv1.pszSrv,"");
  235.     lstrcpy(gSrv1.pszUser,"sa");
  236.     lstrcpy(gSrv1.pszPasswd,"");
  237.     lstrcpy(gSrv2.pszSrv,"");
  238.     lstrcpy(gSrv2.pszUser,"sa");
  239.     lstrcpy(gSrv2.pszPasswd,"");
  240.  
  241.     lstrcpy(gAuthorID,"172-32-1176");    // default au_id value from authors table in pubs db.
  242.  
  243.     // scan command line arguments for user input.
  244.     for (INT i = 1; i < argc; i++)
  245.     {
  246.         if (*argv[i] == '-' || *argv[i] == '/')
  247.         {
  248.             switch (argv[i][1])
  249.             {
  250.                 // get the server or DSN name
  251.                 case 's':
  252.                 case 'S':
  253.                          switch (argv[i][2])
  254.                          {
  255.  
  256.                          case '1':
  257.                              lstrcpy(gSrv1.pszSrv,argv[++i]);
  258.                              break;
  259.  
  260.                          case '2':
  261.                              lstrcpy(gSrv2.pszSrv,argv[++i]);
  262.                              break;
  263.  
  264.                          default:
  265.                              printf("Invalid Input %s\n",argv[i]);
  266.                              printf("\nUsage: %s %s",argv[0],Usage);
  267.                              exit(1);
  268.                          };
  269.                          break;
  270.  
  271.                 // get user name
  272.                 case 'u':
  273.                 case 'U':
  274.                          switch (argv[i][2])
  275.                          {
  276.  
  277.                          case '1':
  278.                              lstrcpy(gSrv1.pszUser,argv[++i]);
  279.                              break;
  280.  
  281.                          case '2':
  282.                              lstrcpy(gSrv2.pszUser,argv[++i]);
  283.                              break;
  284.  
  285.                          default:
  286.                              printf("Invalid Input %s\n",argv[i]);
  287.                              printf("\nUsage: %s %s",argv[0],Usage);
  288.                              exit(1);
  289.                          };
  290.                          break;
  291.  
  292.                 // get password
  293.                 case 'p':
  294.                 case 'P':
  295.                          switch (argv[i][2])
  296.                          {
  297.  
  298.                          case '1':
  299.                              lstrcpy(gSrv1.pszPasswd,argv[++i]);
  300.                              break;
  301.  
  302.                          case '2':
  303.                              lstrcpy(gSrv2.pszPasswd,argv[++i]);
  304.                              break;
  305.  
  306.                          default:
  307.                              printf("Invalid Input %s\n",argv[i]);
  308.                              printf("\nUsage: %s %s",argv[0],Usage);
  309.                              exit(1);
  310.                           };
  311.                          break;
  312.                 
  313.                 // get au_id, overriding default value.
  314.                 case 'i':
  315.                 case 'I':
  316.                             lstrcpy(gAuthorID,argv[++i]);
  317.                             break;
  318.                 // get new address to associate with the au_id
  319.                 case 'a':
  320.                 case 'A':
  321.                             lstrcpy(gNewAddress,argv[++i]);
  322.                             break;
  323.                 case '?':
  324.                 case 'h':
  325.                 case 'H':
  326.                         printf("\nUsage: %s %s",argv[0],Usage);
  327.                         exit(1);
  328.                         break;
  329.                         
  330.                 default:
  331.                         printf("Invalid Input: %s\n",argv[i]);
  332.                         printf("\nUsage: %s %s",argv[0],Usage);
  333.                         exit(1);
  334.             }
  335.         }
  336.         else 
  337.         {
  338.             printf("Illegal command line argument #%d, %s\n",i,argv[i]);
  339.             printf("\nUsage: %s %s",argv[0],Usage);
  340.             exit(1);
  341.         }
  342.     }
  343.  
  344.     printf("-----------------------------\n");
  345.  
  346.     printf("MS DTC/DBLib Sample Configuration parameters\n");
  347.     printf( "server_1:      %s\n"            \
  348.             "user_name_1:   %s\n"            \
  349.             "passwd_1:      %s\n"            \
  350.             "server_2:      %s\n"            \
  351.             "user_name_2:   %s\n"            \
  352.             "passwd_2:      %s\n",
  353.  
  354.             gSrv1.pszSrv,gSrv1.pszUser,gSrv1.pszPasswd,
  355.             gSrv2.pszSrv,gSrv2.pszUser,gSrv2.pszPasswd);
  356.             
  357.     printf("-----------------------------\n");
  358.  
  359. }
  360.  
  361. //-------------------------------------------------------------------------------    
  362.  
  363. void LogonToDB(DBPROCESS **dbp, DBCONN *ptr)
  364. {
  365.  
  366.     DBSETLUSER(login, ptr->pszUser);
  367.     DBSETLPWD(login, ptr->pszPasswd);
  368.     DBSETLAPP(login, "example");
  369.  
  370.     *dbp = dbopen (login, ptr->pszSrv);
  371.     if (*dbp == NULL)
  372.     {
  373.         printf ("\nLogin to server: %s failed, exiting!\n",ptr->pszSrv);
  374.         exit (ERREXIT);
  375.     }
  376.  
  377.     /* Use the "pubs" database. */
  378.     dbuse(*dbp, "pubs");
  379. }
  380.  
  381.  
  382. //-------------------------------------------------------------------------------    
  383.  
  384. void Enlist(DBCONN *ptr, DBPROCESS *dbp, ITransaction *pTransaction)
  385. {
  386.     RETCODE rc = 0;
  387.     
  388.     rc = dbenlisttrans (dbp, pTransaction);
  389.                 
  390.     if (FAIL == rc) 
  391.     {
  392.         printf("\ndbenlisttrans() failed: %x\n",rc);
  393.         exit(1);
  394.     }
  395.  
  396. }
  397.  
  398.  
  399. // ---------------------------------------------------------------------------
  400.  
  401. void ExecuteStatement(DBCONN *ptr, DBPROCESS *dbp, char *pszBuf)
  402. {
  403.     RETCODE rc = 0;
  404.  
  405.     dbcmd(dbp,pszBuf);
  406.     
  407.     rc = dbsqlexec(dbp);
  408.     if (FAIL == rc)
  409.     {
  410.         // one or both of the servers failed to prepare
  411.         printf("dbsqlexec() failed\n");
  412.         exit(1);
  413.     }
  414.  
  415.     rc = dbresults(dbp);
  416.     if (rc != SUCCEED)
  417.     {
  418.         printf("dbresults() failed: %x\n",rc);
  419.         exit(1);
  420.     }
  421. }
  422.  
  423. // ---------------------------------------------------------------------------
  424.  
  425. /* Message and error handling functions. */
  426.  
  427. int msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext)
  428. {
  429.     /*    Msg 5701 is just a USE DATABASE message, so skip it.    */
  430.     if (msgno == 5701)
  431.         return (0);
  432.  
  433.     /*    Print any severity 0 message as is, without extra stuff.    */
  434.     if (severity == 0)
  435.     {
  436.         printf ("%s\n",msgtext);
  437.         return (0);
  438.     }
  439.  
  440.     printf("SQL Server message %ld, severity %d:\n\t%s\n",
  441.         msgno, severity, msgtext);
  442.  
  443.     if (severity >>= 16)
  444.     {
  445.         printf("Program Terminated! Fatal SQL Server error.\n");
  446.         exit(ERREXIT);
  447.     }
  448.     return (0);
  449. }
  450.  
  451. // ---------------------------------------------------------------------------
  452.  
  453. int err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
  454.    
  455. {
  456.     if ((dbproc == NULL) || (DBDEAD(dbproc)))
  457.         return (INT_EXIT);
  458.     else
  459.     {
  460.         printf ("DB-LIBRARY error: \n\t%s\n", dberrstr);
  461.  
  462.         if (oserr != DBNOERR)
  463.             printf ("Operating system error:\n\t%s\n", oserrstr);
  464.     }
  465.     return (INT_CANCEL);
  466. }
  467.  
  468. // ---------------------------------------------------------------------------