home *** CD-ROM | disk | FTP | other *** search
- /*
- * Program type: API Interface
- *
- * Description:
- * This program has several active transactions:
- *
- * Sales order records are entered continuously (transaction 1).
- *
- * If it is discovered during transaction 1, that the customer
- * placing the order is new, then a new customer record must be
- * added (transaction 2).
- *
- * If the customer record uses a country that does not exist
- * in the 'country' table, a new country record is added (transaction 3).
- *
- * Transaction 2 can be committed after the country is added.
- * Transaction 1 can be committed after the customer record is added.
- *
- * Transactions 1, 2, and 3 can be undone individually, if the user
- * decides not to save the sales, customer, or country changes.
- * If transaction 3 is undone, transactions 1 and 2 must be undone.
- * If transaction 2 is undone, transaction 1 must be undone.
- *
- * In addition, several independent transactions, selecting the
- * customer number and the country records, take place during
- * the three update transactions.
- */
-
- #include <stdlib.h>
- #include <string.h>
- #include <ibase.h>
- #include <stdio.h>
- #include "example.h"
-
- #define BUFLEN 512
-
- char ISC_FAR * more_orders PROTO((void));
- int do_trans PROTO((void));
- int cleanup PROTO((void));
-
- char *customer = "Maritime Museum";
- char *country = "Cayman Islands";
- char *currency = "CmnDlr";
-
- isc_db_handle db = NULL;
- isc_tr_handle sales_trans = NULL,
- cust_trans = NULL,
- cntry_trans = NULL,
- trans = NULL;
- long status[20];
-
- static char *Sales[] = {"V88005", 0};
- int Inp_ptr = 0;
-
- char *trans_str = "SET TRANSACTION ISOLATION LEVEL READ COMMITTED";
-
-
- int main (ARG(int, argc), ARG(char **, argv))
- ARGLIST(int argc)
- ARGLIST(char **argv)
- {
- char empdb[128];
-
- if (argc > 1)
- strcpy(empdb, argv[1]);
- else
- strcpy(empdb, "employee.gdb");
-
- /* Zero the transaction handles. */
-
- if (isc_attach_database(status, 0, empdb, &db, 0, NULL))
- {
- ERREXIT(status, 1)
- }
-
- /* Do the updates */
- do_trans();
- if (trans)
- isc_rollback_transaction(status, &trans);
- if (cust_trans)
- isc_rollback_transaction(status, &cust_trans);
- if (cntry_trans)
- isc_rollback_transaction(status, &cntry_trans);
- if (sales_trans)
- isc_rollback_transaction(status, &sales_trans);
-
- /* Remove them again */
- cleanup();
-
- if (trans)
- isc_rollback_transaction(status, &trans);
-
- isc_detach_database(status, &db);
-
- return 0;
- }
-
- /*
- * Function does all the work.
- */
- int do_trans PROTO((void))
- {
- long cust_no;
- char sales_str[BUFLEN + 1];
- char cust_str[BUFLEN + 1];
- char cntry_str[BUFLEN + 1];
- char sel_str[BUFLEN + 1];
- XSQLDA ISC_FAR *sqlda1, *sqlda2, *sqlda3;
- isc_stmt_handle stmt0 = NULL,
- stmt1 = NULL,
- stmt2 = NULL;
- short flag0 = 0, flag1 = 0;
- long fetch_stat;
- long sqlcode;
-
- /* Prepare a query for fetching data. Make it read committed, so you
- * can see your own updates.
- */
-
- if (isc_dsql_execute_immediate(status, &db, &trans, 0, trans_str,
- 1, NULL))
- {
- ERREXIT(status, 1)
- }
-
- sprintf(sel_str, "SELECT cust_no FROM customer WHERE customer = '%s'",
- customer);
-
- if (isc_dsql_allocate_statement(status, &db, &stmt0))
- {
- ERREXIT(status, 1)
- }
-
- sqlda1 = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH(1));
- sqlda1->sqln = 1;
- sqlda1->version = 1;
-
- if (isc_dsql_prepare(status, &trans, &stmt0, 0, sel_str, 1, sqlda1))
- {
- ERREXIT(status, 1)
- }
-
- sqlda1->sqlvar[0].sqldata = (char ISC_FAR *) &cust_no;
- sqlda1->sqlvar[0].sqltype = SQL_LONG + 1;
- sqlda1->sqlvar[0].sqlind = &flag0;
-
- /* Prepare a query for checking if a country exists. */
-
- sprintf(sel_str, "SELECT country FROM country WHERE country = '%s'",
- country);
-
- sqlda2 = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH(1));
- sqlda2->sqln = 1;
- sqlda2->version = 1;
-
- if (isc_dsql_allocate_statement(status, &db, &stmt2))
- {
- ERREXIT(status, 1)
- }
-
- if (isc_dsql_prepare(status, &trans, &stmt2, 0, sel_str, 1, sqlda2))
- {
- ERREXIT(status, 1)
- }
-
- sqlda2->sqlvar[0].sqldata = (char ISC_FAR *) country;
- sqlda2->sqlvar[0].sqltype = SQL_TEXT + 1;
- sqlda2->sqlvar[0].sqlind = &flag1;
-
- /*
- * Start transaction 1 -- add a sales order.
- * for a customer.
- */
-
- cust_no = 9999;
- /* This transaction is also read committed so it can see the results of
- * other transactions
- */
- if (isc_dsql_execute_immediate(status, &db, &sales_trans, 0, trans_str,
- 1, NULL))
- {
- ERREXIT(status, 1)
- }
-
- sprintf(sales_str, "INSERT INTO sales (po_number, cust_no, \
- order_status, total_value) VALUES ('V88005', ?, \
- 'new', 2000)");
-
- if (isc_dsql_allocate_statement(status, &db, &stmt1))
- {
- ERREXIT(status, 1)
- }
-
- if (isc_dsql_prepare(status, &trans, &stmt1, 0, sales_str, 1, NULL))
- {
- ERREXIT(status, 1)
- }
-
- /* Insert parameter (cust_no) used for sales insert */
-
- sqlda3 = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH(1));
- sqlda3->sqln = 1;
- sqlda3->version = 1;
-
- isc_dsql_describe_bind(status, &stmt1, 1, sqlda3);
- sqlda3->sqlvar[0].sqldata = (char ISC_FAR *) &cust_no;;
- sqlda3->sqlvar[0].sqlind = &flag0;
-
- isc_dsql_execute(status, &sales_trans, &stmt1, 1, sqlda3);
- sqlcode = isc_sqlcode(status);
-
- if (sqlcode == -530)
- {
- /* Integrity constraint indicates missing primary key*/
- printf ("No customer number %ld -- adding new customer \n", cust_no);
- /*
- * This a new customer.
- * Start transaction 2 -- add a customer record.
- */
- if (isc_start_transaction(status, &cust_trans, 1, &db, 0, NULL))
- {
- ERREXIT(status, 1)
- }
-
- sprintf(cust_str, "INSERT INTO customer (customer, country) \
- VALUES ('%s', '%s')", customer, country);
-
- printf("Adding a customer record for %s\n", customer );
-
- /* Does the customer country exist in the validation table?
- * Do a lookup this time instead of waiting for the constraint
- * violation. Because trans is read committed, it will see
- * updates on other transactions.
- */
-
- if (isc_dsql_execute(status, &trans, &stmt2, 1, NULL))
- {
- ERREXIT(status, 1)
- }
-
- fetch_stat = isc_dsql_fetch(status, &stmt2, 1, sqlda2);
-
- /*
- * Country was not found in the validation table.
- * Start transaction 3 -- add a country record.
- */
- if (fetch_stat == 100L)
- {
- printf("Missing country record, adding %s\n", country);
- if (isc_start_transaction(status, &cntry_trans, 1, &db, 0, NULL))
- {
- ERREXIT (status, 1)
- }
-
- sprintf(cntry_str, "INSERT INTO country VALUES ('%s', '%s')",
- country, currency);
-
- if (isc_dsql_execute_immediate(status, &db, &cntry_trans, 0,
- cntry_str, 1, NULL))
- {
- ERREXIT(status, 1)
- }
-
- /* This must be committed to be visible */
- isc_commit_transaction(status, &cntry_trans);
- }
-
- /*
- * End transaction 2.
- * Add the customer record, now with a reference.
- */
- if (isc_dsql_execute_immediate(status, &db, &cust_trans, 0, cust_str,
- 1, NULL))
- {
- ERREXIT(status, 1)
- }
-
- /* Commit to make this reference visible */
- if (isc_commit_transaction(status, &cust_trans))
- {
- ERREXIT(status, 1)
- }
-
- /* Lookup the new cust_no for this record */
- if (isc_dsql_execute(status, &trans, &stmt0, 1, NULL))
- {
- ERREXIT(status, 1)
- }
-
- if (!isc_dsql_fetch(status, &stmt0, 1, sqlda1))
- printf("New customer number: %ld\n", cust_no);
-
- /* Then try to add the sales record again */
- if (isc_dsql_execute(status, &sales_trans, &stmt1, 1, sqlda3))
- {
- ERREXIT(status, 1)
- }
- }
-
- if (isc_commit_transaction(status, &sales_trans))
- {
- ERREXIT (status, 1)
- }
-
- printf("Added sales record for V88055\n");
- isc_commit_transaction(status, &trans);
-
- isc_dsql_free_statement(status, &stmt0, DSQL_close);
- isc_dsql_free_statement(status, &stmt1, DSQL_close);
- isc_dsql_free_statement(status, &stmt2, DSQL_close);
- free(sqlda1);
- free(sqlda2);
- free(sqlda3);
-
- return 0;
- }
-
- /* Cleanup removes all updates that might have been done
- * Make sure to cleanup in reverse order to avoid primary
- * key violations
- */
- int cleanup PROTO((void))
- {
- char del_str[100];
-
- printf ("Cleaning up...\n");
-
- if (isc_start_transaction(status, &trans, 1, &db, 0, NULL))
- {
- ERREXIT(status, 1)
- }
-
- strcpy(del_str, "DELETE FROM SALES WHERE PO_NUMBER = \"V88005\"");
- if (isc_dsql_execute_immediate(status, &db, &trans, 0, del_str, 1, NULL))
- {
- ERREXIT(status, 1)
- }
-
- strcpy (del_str, "DELETE FROM CUSTOMER WHERE COUNTRY LIKE \"Cayman%\"");
- if (isc_dsql_execute_immediate(status, &db, &trans, 0, del_str, 1, NULL))
- {
- ERREXIT (status, 1)
- }
-
- strcpy (del_str, "DELETE FROM COUNTRY WHERE COUNTRY LIKE \"Cayman%\"");
- if (isc_dsql_execute_immediate(status, &db, &trans, 0, del_str, 1, NULL))
- {
- ERREXIT(status, 1)
- }
-
- if (isc_commit_transaction(status, &trans))
- {
- ERREXIT(status, 1)
- }
-
- return 0;
- }
-
- /*
- * Return the order number for the next sales order to be entered.
- */
- char *more_orders PROTO((void))
- {
- return Sales[Inp_ptr++];
- }
-