home *** CD-ROM | disk | FTP | other *** search
/ PC World 1999 May / PCWorld_1999-05_cd.bin / software / Vyzkuste / inprise / INTRBASE_55 / EXAMPLES / API / API12.C < prev    next >
C/C++ Source or Header  |  1998-10-18  |  11KB  |  366 lines

  1. /*
  2.  *    Program type:  API Interface
  3.  *
  4.  *    Description:
  5.  *        This program has several active transactions:
  6.  *
  7.  *        Sales order records are entered continuously (transaction 1).
  8.  *
  9.  *        If it is discovered during transaction 1, that the customer
  10.  *        placing the order is new, then a new customer record must be
  11.  *        added (transaction 2).
  12.  *
  13.  *        If the customer record uses a country that does not exist
  14.  *        in the 'country' table, a new country record is added (transaction 3).
  15.  *
  16.  *        Transaction 2 can be committed after the country is added.
  17.  *        Transaction 1 can be committed after the customer record is added.
  18.  *
  19.  *        Transactions 1, 2, and 3 can be undone individually, if the user
  20.  *        decides not to save the sales, customer, or country changes.
  21.  *        If transaction 3 is undone, transactions 1 and 2 must be undone.
  22.  *        If transaction 2 is undone, transaction 1 must be undone.
  23.  *
  24.  *        In addition, several independent transactions, selecting the
  25.  *        customer number and the country records, take place during
  26.  *        the three update transactions.
  27.  */
  28.  
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <ibase.h>
  32. #include <stdio.h>
  33. #include "example.h"
  34.  
  35. #define BUFLEN        512
  36.     
  37. char ISC_FAR * more_orders PROTO((void));
  38. int do_trans PROTO((void));
  39. int cleanup PROTO((void));
  40.  
  41. char    *customer    = "Maritime Museum";
  42. char    *country    = "Cayman Islands";
  43. char    *currency    = "CmnDlr";
  44.  
  45. isc_db_handle       db = NULL;
  46. isc_tr_handle       sales_trans = NULL,
  47.                     cust_trans = NULL,
  48.                     cntry_trans = NULL,
  49.                     trans = NULL;
  50. long                status[20];
  51.  
  52. static char *Sales[] = {"V88005", 0};
  53. int Inp_ptr = 0;
  54.  
  55. char    *trans_str = "SET TRANSACTION ISOLATION LEVEL READ COMMITTED";
  56.  
  57.  
  58. int main (ARG(int, argc), ARG(char **, argv))
  59. ARGLIST(int argc)
  60. ARGLIST(char **argv)
  61. {
  62.     char empdb[128];
  63.  
  64.     if (argc > 1)
  65.         strcpy(empdb, argv[1]);
  66.     else
  67.         strcpy(empdb, "employee.gdb");
  68.  
  69.     /* Zero the transaction handles. */
  70.  
  71.     if (isc_attach_database(status, 0, empdb, &db, 0, NULL))
  72.     {
  73.         ERREXIT(status, 1)
  74.     }
  75.  
  76.     /* Do the updates */
  77.     do_trans();
  78.     if (trans)
  79.         isc_rollback_transaction(status, &trans);
  80.     if (cust_trans)
  81.         isc_rollback_transaction(status, &cust_trans);
  82.     if (cntry_trans)
  83.         isc_rollback_transaction(status, &cntry_trans);
  84.     if (sales_trans)
  85.         isc_rollback_transaction(status, &sales_trans);
  86.  
  87.     /* Remove them again */
  88.     cleanup();
  89.  
  90.     if (trans)
  91.         isc_rollback_transaction(status, &trans);
  92.  
  93.     isc_detach_database(status, &db);
  94.  
  95.     return 0;
  96. }
  97.  
  98. /* 
  99.  * Function does all the work.
  100. */
  101. int do_trans PROTO((void))
  102. {                   
  103.     long            cust_no;
  104.     char            sales_str[BUFLEN + 1];
  105.     char            cust_str[BUFLEN + 1];
  106.     char            cntry_str[BUFLEN + 1];
  107.     char            sel_str[BUFLEN + 1];
  108.     XSQLDA  ISC_FAR *sqlda1, *sqlda2, *sqlda3;
  109.     isc_stmt_handle stmt0 = NULL,
  110.                     stmt1 = NULL,
  111.                     stmt2 = NULL;
  112.     short           flag0 = 0, flag1 = 0;
  113.     long            fetch_stat;
  114.     long            sqlcode;
  115.                     
  116.     /* Prepare a query for fetching data.  Make it read committed, so you
  117.      * can see your own updates.  
  118.      */
  119.  
  120.     if (isc_dsql_execute_immediate(status, &db, &trans, 0, trans_str,
  121.                                    1, NULL))
  122.     {
  123.         ERREXIT(status, 1)
  124.     }
  125.  
  126.     sprintf(sel_str, "SELECT cust_no FROM customer WHERE customer = '%s'",
  127.             customer);
  128.  
  129.     if (isc_dsql_allocate_statement(status, &db, &stmt0))
  130.     {
  131.         ERREXIT(status, 1)
  132.     }
  133.  
  134.     sqlda1 = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH(1));
  135.     sqlda1->sqln = 1;
  136.     sqlda1->version = 1;
  137.  
  138.     if (isc_dsql_prepare(status, &trans, &stmt0, 0, sel_str, 1, sqlda1))
  139.     {
  140.         ERREXIT(status, 1)
  141.     }
  142.  
  143.     sqlda1->sqlvar[0].sqldata = (char ISC_FAR *) &cust_no;
  144.     sqlda1->sqlvar[0].sqltype = SQL_LONG + 1;
  145.     sqlda1->sqlvar[0].sqlind  = &flag0;
  146.  
  147.     /* Prepare a query for checking if a country exists. */
  148.  
  149.     sprintf(sel_str, "SELECT country FROM country WHERE country = '%s'",
  150.             country);
  151.  
  152.     sqlda2 = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH(1));
  153.     sqlda2->sqln = 1;
  154.     sqlda2->version = 1;
  155.  
  156.     if (isc_dsql_allocate_statement(status, &db, &stmt2))
  157.     {
  158.         ERREXIT(status, 1)
  159.     }
  160.  
  161.     if (isc_dsql_prepare(status, &trans, &stmt2, 0, sel_str, 1, sqlda2))
  162.     {
  163.         ERREXIT(status, 1)
  164.     }
  165.  
  166.     sqlda2->sqlvar[0].sqldata = (char ISC_FAR *) country;
  167.     sqlda2->sqlvar[0].sqltype = SQL_TEXT + 1;
  168.     sqlda2->sqlvar[0].sqlind  = &flag1;
  169.                              
  170.     /*
  171.      *    Start transaction 1 -- add a sales order.
  172.      *    for a customer. 
  173.      */
  174.  
  175.     cust_no = 9999;
  176.     /* This transaction is also read committed so it can see the results of
  177.      *  other transactions 
  178.      */
  179.     if (isc_dsql_execute_immediate(status, &db, &sales_trans, 0, trans_str,
  180.                                    1, NULL))
  181.     {
  182.         ERREXIT(status, 1)
  183.     }
  184.  
  185.     sprintf(sales_str, "INSERT INTO sales (po_number, cust_no, \
  186.             order_status, total_value) VALUES ('V88005', ?, \
  187.             'new', 2000)"); 
  188.  
  189.     if (isc_dsql_allocate_statement(status, &db, &stmt1))
  190.     {
  191.         ERREXIT(status, 1)
  192.     }
  193.  
  194.     if (isc_dsql_prepare(status, &trans, &stmt1, 0, sales_str, 1, NULL))
  195.     {
  196.         ERREXIT(status, 1)
  197.     }
  198.     
  199.     /* Insert parameter (cust_no) used for sales insert */
  200.  
  201.     sqlda3 = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH(1));
  202.     sqlda3->sqln = 1;
  203.     sqlda3->version = 1;
  204.  
  205.     isc_dsql_describe_bind(status, &stmt1, 1, sqlda3);
  206.     sqlda3->sqlvar[0].sqldata = (char ISC_FAR *) &cust_no;;
  207.     sqlda3->sqlvar[0].sqlind  = &flag0;
  208.  
  209.     isc_dsql_execute(status, &sales_trans, &stmt1, 1, sqlda3);
  210.     sqlcode = isc_sqlcode(status);
  211.  
  212.     if (sqlcode == -530)
  213.     {
  214.         /* Integrity constraint indicates missing primary key*/
  215.         printf ("No customer number %ld -- adding new customer \n", cust_no);
  216.         /*
  217.          *    This a new customer.
  218.          * Start transaction 2 -- add a customer record.
  219.          */
  220.         if (isc_start_transaction(status, &cust_trans, 1, &db, 0, NULL))
  221.         {
  222.             ERREXIT(status, 1)
  223.         }
  224.  
  225.         sprintf(cust_str, "INSERT INTO customer (customer, country) \
  226.                 VALUES ('%s', '%s')", customer, country);
  227.         
  228.         printf("Adding a customer record for %s\n", customer );
  229.  
  230.         /* Does the customer country exist in the validation table? 
  231.          * Do a lookup this time instead of waiting for the constraint
  232.          * violation.  Because trans is read committed, it will see
  233.          * updates on other transactions.
  234.          */
  235.  
  236.         if (isc_dsql_execute(status, &trans, &stmt2, 1, NULL))
  237.         {
  238.             ERREXIT(status, 1)
  239.         }
  240.  
  241.         fetch_stat = isc_dsql_fetch(status, &stmt2, 1, sqlda2);
  242.         
  243.         /*
  244.          *    Country was not found in the validation table.
  245.          *    Start transaction 3 -- add a country record.
  246.          */
  247.         if (fetch_stat == 100L)
  248.         {
  249.             printf("Missing country record, adding %s\n", country);
  250.             if (isc_start_transaction(status, &cntry_trans, 1, &db, 0, NULL))
  251.             {
  252.                 ERREXIT (status, 1)
  253.             }
  254.  
  255.             sprintf(cntry_str, "INSERT INTO country VALUES ('%s', '%s')",
  256.                     country, currency);
  257.  
  258.             if (isc_dsql_execute_immediate(status, &db, &cntry_trans, 0,
  259.                 cntry_str, 1, NULL))
  260.             {
  261.                 ERREXIT(status, 1)
  262.             }
  263.  
  264.             /* This must be committed to be visible */
  265.             isc_commit_transaction(status, &cntry_trans);
  266.         }
  267.  
  268.         /*
  269.          *    End transaction 2.
  270.          *    Add the customer record, now with a reference.
  271.          */
  272.         if (isc_dsql_execute_immediate(status, &db, &cust_trans, 0, cust_str,
  273.                                        1, NULL))
  274.         {
  275.             ERREXIT(status, 1)
  276.         }
  277.  
  278.         /* Commit to make this reference visible */
  279.         if (isc_commit_transaction(status, &cust_trans))
  280.         {
  281.             ERREXIT(status, 1)
  282.         }
  283.  
  284.         /* Lookup the new cust_no for this record */
  285.         if (isc_dsql_execute(status, &trans, &stmt0, 1, NULL))
  286.         {
  287.             ERREXIT(status, 1)
  288.         }
  289.  
  290.         if (!isc_dsql_fetch(status, &stmt0, 1, sqlda1))
  291.             printf("New customer number: %ld\n", cust_no);
  292.  
  293.         /* Then try to add the sales record again */
  294.         if (isc_dsql_execute(status, &sales_trans, &stmt1, 1, sqlda3))
  295.         {
  296.             ERREXIT(status, 1)
  297.         }
  298.     }
  299.  
  300.     if (isc_commit_transaction(status, &sales_trans))
  301.     {
  302.         ERREXIT (status, 1)
  303.     }
  304.  
  305.     printf("Added sales record for V88055\n");
  306.     isc_commit_transaction(status, &trans);
  307.  
  308.     isc_dsql_free_statement(status, &stmt0, DSQL_close);
  309.     isc_dsql_free_statement(status, &stmt1, DSQL_close);
  310.     isc_dsql_free_statement(status, &stmt2, DSQL_close);
  311.     free(sqlda1);
  312.     free(sqlda2);
  313.     free(sqlda3);
  314.  
  315.     return 0;
  316. }
  317.  
  318. /* Cleanup removes all updates that might have been done
  319.  * Make sure to cleanup in reverse order to avoid primary
  320.  * key violations
  321.  */
  322. int cleanup PROTO((void))
  323. {
  324.     char del_str[100];
  325.  
  326.     printf ("Cleaning up...\n");
  327.  
  328.     if (isc_start_transaction(status, &trans, 1, &db, 0, NULL))
  329.     {
  330.         ERREXIT(status, 1)
  331.     }
  332.  
  333.     strcpy(del_str, "DELETE FROM SALES WHERE PO_NUMBER =  \"V88005\"");
  334.     if (isc_dsql_execute_immediate(status, &db, &trans, 0, del_str, 1, NULL))
  335.     {
  336.         ERREXIT(status, 1)
  337.     }
  338.  
  339.     strcpy (del_str, "DELETE FROM CUSTOMER WHERE COUNTRY LIKE \"Cayman%\"");
  340.     if (isc_dsql_execute_immediate(status, &db, &trans, 0, del_str, 1, NULL))
  341.     {
  342.         ERREXIT (status, 1)
  343.     }
  344.     
  345.     strcpy (del_str, "DELETE FROM COUNTRY WHERE COUNTRY LIKE \"Cayman%\"");
  346.     if (isc_dsql_execute_immediate(status, &db, &trans, 0, del_str, 1, NULL))
  347.     {
  348.         ERREXIT(status, 1)
  349.     }
  350.  
  351.     if (isc_commit_transaction(status, &trans))
  352.     {
  353.         ERREXIT(status, 1)
  354.     }
  355.  
  356.     return 0;
  357. }
  358.  
  359. /*
  360.  *    Return the order number for the next sales order to be entered.
  361.  */
  362. char *more_orders PROTO((void))
  363. {
  364.     return Sales[Inp_ptr++];
  365. }
  366.