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