2
0

api12.c 11 KB

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