home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / interb / InterBase_WI-V6.0-server.exe / server / examples / api / api12.c < prev    next >
C/C++ Source or Header  |  2000-06-23  |  12KB  |  385 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.  * The contents of this file are subject to the Interbase Public
  28.  * License Version 1.0 (the "License"); you may not use this file
  29.  * except in compliance with the License. You may obtain a copy
  30.  * of the License at http://www.Interbase.com/IPL/
  31.  *
  32.  * Software distributed under the License is distributed on an
  33.  * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
  34.  * or implied. See the License for the specific language governing
  35.  * rights and limitations under the License.
  36.  *
  37.  * The Original Code was created by Interbase Software Corporation
  38.  * and its successors. Portions created by Borland/Inprise are
  39.  * Copyright (C) 1992-1998 and 1999-2000 Borland/Inprise. Portions
  40.  * created by InterBase Software Corporation are Copyright (C)
  41.  * 1998-1999 InterBase Software Corporation.
  42.  *
  43.  * Copyright (C) 2000 InterBase Software Corporation
  44.  * All Rights Reserved.
  45.  * Contributor(s): ______________________________________.
  46.  */
  47.  
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include <ibase.h>
  51. #include <stdio.h>
  52. #include "example.h"
  53.  
  54. #define BUFLEN        512
  55.     
  56. char ISC_FAR * more_orders (void);
  57. int do_trans (void);
  58. int cleanup (void);
  59.  
  60. char    *customer    = "Maritime Museum";
  61. char    *country    = "Cayman Islands";
  62. char    *currency    = "CmnDlr";
  63.  
  64. isc_db_handle       db = NULL;
  65. isc_tr_handle       sales_trans = NULL,
  66.                     cust_trans = NULL,
  67.                     cntry_trans = NULL,
  68.                     trans = NULL;
  69. long                status[20];
  70.  
  71. static char *Sales[] = {"V88005", 0};
  72. int Inp_ptr = 0;
  73.  
  74. char    *trans_str = "SET TRANSACTION ISOLATION LEVEL READ COMMITTED";
  75.  
  76.  
  77. int main (ARG(int, argc), ARG(char **, argv))
  78. ARGLIST(int argc)
  79. ARGLIST(char **argv)
  80. {
  81.     char empdb[128];
  82.  
  83.     if (argc > 1)
  84.         strcpy(empdb, argv[1]);
  85.     else
  86.         strcpy(empdb, "employee.gdb");
  87.  
  88.     /* Zero the transaction handles. */
  89.  
  90.     if (isc_attach_database(status, 0, empdb, &db, 0, NULL))
  91.     {
  92.         ERREXIT(status, 1)
  93.     }
  94.  
  95.     /* Do the updates */
  96.     do_trans();
  97.     if (trans)
  98.         isc_rollback_transaction(status, &trans);
  99.     if (cust_trans)
  100.         isc_rollback_transaction(status, &cust_trans);
  101.     if (cntry_trans)
  102.         isc_rollback_transaction(status, &cntry_trans);
  103.     if (sales_trans)
  104.         isc_rollback_transaction(status, &sales_trans);
  105.  
  106.     /* Remove them again */
  107.     cleanup();
  108.  
  109.     if (trans)
  110.         isc_rollback_transaction(status, &trans);
  111.  
  112.     isc_detach_database(status, &db);
  113.  
  114.     return 0;
  115. }
  116.  
  117. /* 
  118.  * Function does all the work.
  119. */
  120. int do_trans (void)
  121. {                   
  122.     long            cust_no;
  123.     char            sales_str[BUFLEN + 1];
  124.     char            cust_str[BUFLEN + 1];
  125.     char            cntry_str[BUFLEN + 1];
  126.     char            sel_str[BUFLEN + 1];
  127.     XSQLDA  ISC_FAR *sqlda1, *sqlda2, *sqlda3;
  128.     isc_stmt_handle stmt0 = NULL,
  129.                     stmt1 = NULL,
  130.                     stmt2 = NULL;
  131.     short           flag0 = 0, flag1 = 0;
  132.     long            fetch_stat;
  133.     long            sqlcode;
  134.                     
  135.     /* Prepare a query for fetching data.  Make it read committed, so you
  136.      * can see your own updates.  
  137.      */
  138.  
  139.     if (isc_dsql_execute_immediate(status, &db, &trans, 0, trans_str,
  140.                                    1, NULL))
  141.     {
  142.         ERREXIT(status, 1)
  143.     }
  144.  
  145.     sprintf(sel_str, "SELECT cust_no FROM customer WHERE customer = '%s'",
  146.             customer);
  147.  
  148.     if (isc_dsql_allocate_statement(status, &db, &stmt0))
  149.     {
  150.         ERREXIT(status, 1)
  151.     }
  152.  
  153.     sqlda1 = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH(1));
  154.     sqlda1->sqln = 1;
  155.     sqlda1->version = 1;
  156.  
  157.     if (isc_dsql_prepare(status, &trans, &stmt0, 0, sel_str, 1, sqlda1))
  158.     {
  159.         ERREXIT(status, 1)
  160.     }
  161.  
  162.     sqlda1->sqlvar[0].sqldata = (char ISC_FAR *) &cust_no;
  163.     sqlda1->sqlvar[0].sqltype = SQL_LONG + 1;
  164.     sqlda1->sqlvar[0].sqlind  = &flag0;
  165.  
  166.     /* Prepare a query for checking if a country exists. */
  167.  
  168.     sprintf(sel_str, "SELECT country FROM country WHERE country = '%s'",
  169.             country);
  170.  
  171.     sqlda2 = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH(1));
  172.     sqlda2->sqln = 1;
  173.     sqlda2->version = 1;
  174.  
  175.     if (isc_dsql_allocate_statement(status, &db, &stmt2))
  176.     {
  177.         ERREXIT(status, 1)
  178.     }
  179.  
  180.     if (isc_dsql_prepare(status, &trans, &stmt2, 0, sel_str, 1, sqlda2))
  181.     {
  182.         ERREXIT(status, 1)
  183.     }
  184.  
  185.     sqlda2->sqlvar[0].sqldata = (char ISC_FAR *) country;
  186.     sqlda2->sqlvar[0].sqltype = SQL_TEXT + 1;
  187.     sqlda2->sqlvar[0].sqlind  = &flag1;
  188.                              
  189.     /*
  190.      *    Start transaction 1 -- add a sales order.
  191.      *    for a customer. 
  192.      */
  193.  
  194.     cust_no = 9999;
  195.     /* This transaction is also read committed so it can see the results of
  196.      *  other transactions 
  197.      */
  198.     if (isc_dsql_execute_immediate(status, &db, &sales_trans, 0, trans_str,
  199.                                    1, NULL))
  200.     {
  201.         ERREXIT(status, 1)
  202.     }
  203.  
  204.     sprintf(sales_str, "INSERT INTO sales (po_number, cust_no, \
  205.             order_status, total_value) VALUES ('V88005', ?, \
  206.             'new', 2000)"); 
  207.  
  208.     if (isc_dsql_allocate_statement(status, &db, &stmt1))
  209.     {
  210.         ERREXIT(status, 1)
  211.     }
  212.  
  213.     if (isc_dsql_prepare(status, &trans, &stmt1, 0, sales_str, 1, NULL))
  214.     {
  215.         ERREXIT(status, 1)
  216.     }
  217.     
  218.     /* Insert parameter (cust_no) used for sales insert */
  219.  
  220.     sqlda3 = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH(1));
  221.     sqlda3->sqln = 1;
  222.     sqlda3->version = 1;
  223.  
  224.     isc_dsql_describe_bind(status, &stmt1, 1, sqlda3);
  225.     sqlda3->sqlvar[0].sqldata = (char ISC_FAR *) &cust_no;;
  226.     sqlda3->sqlvar[0].sqlind  = &flag0;
  227.  
  228.     isc_dsql_execute(status, &sales_trans, &stmt1, 1, sqlda3);
  229.     sqlcode = isc_sqlcode(status);
  230.  
  231.     if (sqlcode == -530)
  232.     {
  233.         /* Integrity constraint indicates missing primary key*/
  234.         printf ("No customer number %ld -- adding new customer \n", cust_no);
  235.         /*
  236.          *    This a new customer.
  237.          * Start transaction 2 -- add a customer record.
  238.          */
  239.         if (isc_start_transaction(status, &cust_trans, 1, &db, 0, NULL))
  240.         {
  241.             ERREXIT(status, 1)
  242.         }
  243.  
  244.         sprintf(cust_str, "INSERT INTO customer (customer, country) \
  245.                 VALUES ('%s', '%s')", customer, country);
  246.         
  247.         printf("Adding a customer record for %s\n", customer );
  248.  
  249.         /* Does the customer country exist in the validation table? 
  250.          * Do a lookup this time instead of waiting for the constraint
  251.          * violation.  Because trans is read committed, it will see
  252.          * updates on other transactions.
  253.          */
  254.  
  255.         if (isc_dsql_execute(status, &trans, &stmt2, 1, NULL))
  256.         {
  257.             ERREXIT(status, 1)
  258.         }
  259.  
  260.         fetch_stat = isc_dsql_fetch(status, &stmt2, 1, sqlda2);
  261.         
  262.         /*
  263.          *    Country was not found in the validation table.
  264.          *    Start transaction 3 -- add a country record.
  265.          */
  266.         if (fetch_stat == 100L)
  267.         {
  268.             printf("Missing country record, adding %s\n", country);
  269.             if (isc_start_transaction(status, &cntry_trans, 1, &db, 0, NULL))
  270.             {
  271.                 ERREXIT (status, 1)
  272.             }
  273.  
  274.             sprintf(cntry_str, "INSERT INTO country VALUES ('%s', '%s')",
  275.                     country, currency);
  276.  
  277.             if (isc_dsql_execute_immediate(status, &db, &cntry_trans, 0,
  278.                 cntry_str, 1, NULL))
  279.             {
  280.                 ERREXIT(status, 1)
  281.             }
  282.  
  283.             /* This must be committed to be visible */
  284.             isc_commit_transaction(status, &cntry_trans);
  285.         }
  286.  
  287.         /*
  288.          *    End transaction 2.
  289.          *    Add the customer record, now with a reference.
  290.          */
  291.         if (isc_dsql_execute_immediate(status, &db, &cust_trans, 0, cust_str,
  292.                                        1, NULL))
  293.         {
  294.             ERREXIT(status, 1)
  295.         }
  296.  
  297.         /* Commit to make this reference visible */
  298.         if (isc_commit_transaction(status, &cust_trans))
  299.         {
  300.             ERREXIT(status, 1)
  301.         }
  302.  
  303.         /* Lookup the new cust_no for this record */
  304.         if (isc_dsql_execute(status, &trans, &stmt0, 1, NULL))
  305.         {
  306.             ERREXIT(status, 1)
  307.         }
  308.  
  309.         if (!isc_dsql_fetch(status, &stmt0, 1, sqlda1))
  310.             printf("New customer number: %ld\n", cust_no);
  311.  
  312.         /* Then try to add the sales record again */
  313.         if (isc_dsql_execute(status, &sales_trans, &stmt1, 1, sqlda3))
  314.         {
  315.             ERREXIT(status, 1)
  316.         }
  317.     }
  318.  
  319.     if (isc_commit_transaction(status, &sales_trans))
  320.     {
  321.         ERREXIT (status, 1)
  322.     }
  323.  
  324.     printf("Added sales record for V88055\n");
  325.     isc_commit_transaction(status, &trans);
  326.  
  327.     isc_dsql_free_statement(status, &stmt0, DSQL_close);
  328.     isc_dsql_free_statement(status, &stmt1, DSQL_close);
  329.     isc_dsql_free_statement(status, &stmt2, DSQL_close);
  330.     free(sqlda1);
  331.     free(sqlda2);
  332.     free(sqlda3);
  333.  
  334.     return 0;
  335. }
  336.  
  337. /* Cleanup removes all updates that might have been done
  338.  * Make sure to cleanup in reverse order to avoid primary
  339.  * key violations
  340.  */
  341. int cleanup (void)
  342. {
  343.     char del_str[100];
  344.  
  345.     printf ("Cleaning up...\n");
  346.  
  347.     if (isc_start_transaction(status, &trans, 1, &db, 0, NULL))
  348.     {
  349.         ERREXIT(status, 1)
  350.     }
  351.  
  352.     strcpy(del_str, "DELETE FROM SALES WHERE PO_NUMBER =  \"V88005\"");
  353.     if (isc_dsql_execute_immediate(status, &db, &trans, 0, del_str, 1, NULL))
  354.     {
  355.         ERREXIT(status, 1)
  356.     }
  357.  
  358.     strcpy (del_str, "DELETE FROM CUSTOMER WHERE COUNTRY LIKE \"Cayman%\"");
  359.     if (isc_dsql_execute_immediate(status, &db, &trans, 0, del_str, 1, NULL))
  360.     {
  361.         ERREXIT (status, 1)
  362.     }
  363.     
  364.     strcpy (del_str, "DELETE FROM COUNTRY WHERE COUNTRY LIKE \"Cayman%\"");
  365.     if (isc_dsql_execute_immediate(status, &db, &trans, 0, del_str, 1, NULL))
  366.     {
  367.         ERREXIT(status, 1)
  368.     }
  369.  
  370.     if (isc_commit_transaction(status, &trans))
  371.     {
  372.         ERREXIT(status, 1)
  373.     }
  374.  
  375.     return 0;
  376. }
  377.  
  378. /*
  379.  *    Return the order number for the next sales order to be entered.
  380.  */
  381. char *more_orders (void)
  382. {
  383.     return Sales[Inp_ptr++];
  384. }
  385.