#ifdef RCSID static char *RCSid = "$Header: atmoci.c 24-feb-99.17:25:09 jmcdonal Exp $ "; #endif /* RCSID */ /* Copyright (c) 1995, 1997, 1999 by Oracle Corporation */ /* NAME atmoci.c - DESCRIPTION PUBLIC FUNCTION(S) PRIVATE FUNCTION(S) RETURNS NOTES MODIFIED (MM/DD/YY) jmcdonal 02/24/99 - 806: remove tabs re bug 708695 (and trim lines) jmcdonal 02/08/99 - 815xx: init OCI indicator variables jmcdonal 08/06/98 - Convert to oci8 calls cchriste 09/17/97 - fix API_VERSION, error reporting gwood 01/11/96 - Creation */ /* Copyright (c) Oracle Corporation 1995, 1997, 1999. All Rights Reserved. */ /* NAME atmoci.c -- Trace ATM sample application using OCI interface to access data in Oracle database. DESCRIPTION Simulates an ATM, allowing balance inquiries, deposits and withdrawals */ #ifndef ORATYPES_ORACLE # include #endif #ifndef ORASTDIO # include # define ORASTDIO #endif #ifndef ORASTDLIB # include # define ORASTDLIB #endif #ifndef ORASTRING # include # define ORASTRING #endif #ifndef EPC_ORACLE # include #endif #ifndef OCI_ORACLE # include #endif /*----------------------------------------------------------------------------- Literals -----------------------------------------------------------------------------*/ #define S_LONG 4 /* use instead of sizeof(long) */ #define TRUE 1 #define FALSE 0 #define MAXLINE 80 /* maximum length of input line */ #define API_VERSION 2 #define FDF_NAME "atm.fdf" /* name of facility definition file */ #define VENDOR 192216243 /* vendor ID from FDF file */ #define FAC_NUMBER 1 /* facility ID from FDF file */ #define FAC_VERSION "V1.0" /* facility version string */ #define MAX_EVENT 9 /* number of events */ #define BALANCES 1 /* event numbers */ #define DEPOSIT 2 #define WITHDRAWAL 3 #define TRANSFER 4 #define QUICK_WITHDRAW 5 #define OVERDRAFT 6 #define USER_SESSION 7 #define VALIDATION_OK 8 #define VALIDATION_ERR 9 #define COLLECTION_NAME "sampatm" /* name of collection file */ #define OCI_ERROR_MAXMSG_SIZE 1024 /*----------------------------------------------------------------------------- Macros to simplify input/output -----------------------------------------------------------------------------*/ #define DISPLAY(text) if (!FromFile) printf(text) #define READ(text) if (FromFile) fgets(text, MAXLINE, InFile); else gets(text) /*----------------------------------------------------------------------------- Function declarations -----------------------------------------------------------------------------*/ void init_atm(/* int argc, char *argv[] */); void end_atm(/* void */); long login_user(/* void */); void init_user_session(/* void */); void end_user_session(/* void */); long display_main_menu(/* void */); void get_balances(/* long acct_num */); void make_deposit(/* long acct_num */); void make_withdrawal(/* long acct_num */); void make_transfer(/* long acct_num */); long make_quick_withdrawal(/* long acct_num */); long atm_valid_acct_num(/* long acct_num */); long atm_valid_xfer_acct(/* long acct_num */); float atm_sav_balance(/* long acct_num */); float atm_chk_balance(/* long acct_num */); void atm_update_balance (/* long acct_num, float new_bal, text *sql_stmt */); void atm_sav_deposit(/* long acct_num, long amount */); void atm_chk_deposit(/* long acct_num, long amount */); void atm_sav_withdrawal(/* long acct_num, long amount, float old_bal */); void atm_chk_withdrawal(/* long acct_num, long amount, float old_bal */); void atm_txn(/* text *sql_stmt */); void atm_start_rw(/* void */); void atm_start_ro(/* void */); void atm_commit(/* void */); void atm_rollback(/* void */); void report_epc_error(/* char routine[20], char message[80], long status */); /*----------------------------------------------------------------------------- Global declarations -----------------------------------------------------------------------------*/ OCIBind *oci_bndap = (OCIBind *)NULL; OCIBind *oci_bndbp = (OCIBind *)NULL; OCIDefine *oci_defp = (OCIDefine *)NULL; OCIEnv *oci_envhp = (OCIEnv *)NULL; OCIError *oci_errhp = (OCIError *)NULL; OCISvcCtx *oci_svchp = (OCISvcCtx *)NULL; OCIStmt *oci_stmthp = (OCIStmt *)NULL; FILE *InFile; /* input file */ char FromFile; /* true if reading from input file */ EPCFCTX Facctx = (EPCFCTX) 0; /* facility context, initialized */ long *Event_Flags; /* Trace event flags set by epc_init */ char Regist_ID[80]; /* reusable registration ID text */ long Session_Handle; /* event instance handles */ long Txn_Handle; /*----------------------------------------------------------------------------- Main ----------------------------------------------------------------------------*/ main (argc, argv) int argc; char *argv[]; { char user = TRUE; /* we're accepting users */ char session; /* we have a valid user */ long acct_num; /* user's account number */ long choice; /* user's menu choice */ long exit_early; /* user finished without picking */ /* exit from menu */ init_atm (argc, argv); while (user) { acct_num = login_user(); /* returns valid acct_num or 0 */ if (acct_num == 0) { session = FALSE; user = FALSE; } else { session = TRUE; init_user_session(); /* start user_session event */ } while (session) { choice = display_main_menu(); switch (choice) { case 1: get_balances(acct_num); break; case 2: make_deposit(acct_num); break; case 3: make_withdrawal(acct_num); break; case 4: make_transfer(acct_num); break; case 5: exit_early = make_quick_withdrawal(acct_num); if (exit_early) { session = FALSE; } /* exit after good quick withdraw */ break; case 0: session = FALSE; break; default: DISPLAY("\nInvalid choice.\n"); break; } /* end of switch */ } /* end of while (session) */ if (user) { end_user_session(); } /* finish this user */ } /* end of while (user) */ end_atm(); return 0; } /*----------------------------------------------------------------------------- init_atm Session-wide settings: input and output, Trace initialization, database -----------------------------------------------------------------------------*/ void init_atm (argc, argv) int argc; char *argv[]; { long status; text *username = (text *) "atm"; text *password = (text *) "sampleatm"; text *service = (text *) ""; /* assume local default database */ text oci_msgbuf[OCI_ERROR_MAXMSG_SIZE]; sword oci_ret = OCI_SUCCESS; /* return status for OCI calls */ sb4 oci_errcode = 0; /* returned as OCIErrorGet arg */ /****************************************************************************** Set up input and output files ******************************************************************************/ if (argc == 1) /* no input file; use stdin, stdout */ FromFile = FALSE; if (argc == 2) /* input file, use it */ { if (argv[1] == NULL) fprintf(stderr, "Input filename is NULL\n"); else { fprintf(stdout, "Input filename is %s\n", argv[1]); if ((InFile = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "Can't open file %s\n", argv[1]); exit(1); } else /* we have an input file */ FromFile = TRUE; } } if (argc > 2) { fprintf(stderr, "Too many arguments on command line\n"); exit(1); } /****************************************************************************** Set up OCI for use ... ******************************************************************************/ /* Init OCI and environment ... */ oci_ret = OCIInitialize ((ub4)OCI_DEFAULT, (dvoid *)0, (dvoid *(*)(dvoid *, size_t))0, (dvoid *(*)(dvoid *, dvoid *, size_t))0, (void (*)(dvoid *, dvoid *))0); if (oci_ret != OCI_SUCCESS) { fprintf(stderr, "\n OCIInitialize error: %d \n", oci_ret); exit(1); } oci_ret = OCIEnvInit ((OCIEnv **)&oci_envhp, OCI_DEFAULT, (size_t)0, (dvoid **)0); if (oci_ret != OCI_SUCCESS) { fprintf(stderr, "\n OCIEnvInit error: %d \n", oci_ret); exit(1); } /* Allocate OCI error and statement handles ... */ oci_ret = OCIHandleAlloc ((dvoid *)oci_envhp, (dvoid **)&oci_errhp, OCI_HTYPE_ERROR, (size_t)0, (dvoid **)0); if (oci_ret != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_envhp, (ub4)1, (text *)NULL, &oci_errcode, (text *)oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ENV); fprintf(stderr, "\n OCIHandleAlloc error: %s \n", oci_msgbuf); exit(1); } oci_ret = OCIHandleAlloc ((dvoid *)oci_envhp, (dvoid **)&oci_stmthp, OCI_HTYPE_STMT, (size_t)0, (dvoid **)0); if (oci_ret != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n OCIHandleAlloc error: %s \n", oci_msgbuf); exit(1); } /****************************************************************************** Connect to database; ******************************************************************************/ oci_ret = OCILogon (oci_envhp, oci_errhp, &oci_svchp, username, (ub4)strlen((char *)username), password, (ub4)strlen((char *)password), service, (ub4)strlen((char *)service)); if (oci_ret != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n OCILogon error: %s \n", oci_msgbuf); if (oci_errhp != (OCIError *)NULL) OCIHandleFree ((dvoid *)oci_errhp, (ub4)OCI_HTYPE_ERROR); if (oci_svchp != (OCISvcCtx *)NULL) OCIHandleFree ((dvoid *)oci_svchp, (ub4)OCI_HTYPE_SVCCTX); exit(1); } /****************************************************************************** Initialize Trace session and start collection ******************************************************************************/ status = epc_init(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, NULL, NULL, &Event_Flags, MAX_EVENT, EPC_K_ALLOC, 0, 0, NULL, NULL, &Facctx); if (status == epc_s_success) status = epc_collect(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, 0, COLLECTION_NAME, FDF_NAME, 0, 0,&Facctx); else report_epc_error("init_atm", "Error on epc_init: ", status); if (status != epc_s_success) report_epc_error("init_atm", "Error on epc_collect: ", status); return; } /*----------------------------------------------------------------------------- end_atm Clean up session: close files, end Trace collection, exit database -----------------------------------------------------------------------------*/ void end_atm () { long status; if (FromFile) fclose(InFile); /* End DB connection, and free any allocated OCI handles ... */ OCILogoff (oci_svchp, oci_errhp); if (oci_stmthp != (OCIStmt *)NULL) OCIHandleFree ((dvoid *)oci_stmthp, (ub4)OCI_HTYPE_STMT); if (oci_errhp != (OCIError *)NULL) OCIHandleFree ((dvoid *)oci_errhp, (ub4)OCI_HTYPE_ERROR); /* Stop the Trace collection ... */ status = epc_cancel(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, COLLECTION_NAME, 0,&Facctx); if (status != epc_s_success) report_epc_error("end_atm", "Error on epc_cancel: ", status); status = epc_drop_fac(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, &Facctx); if (status != epc_s_success) report_epc_error("end_atm", "Error on epc_drop_fac: ", status); return; } /*----------------------------------------------------------------------------- login_user Get account number from user and validate against database -----------------------------------------------------------------------------*/ long login_user () { char good_input; char line[MAXLINE]; long acct_num; long val_num; long status; char *record; /* event record */ good_input = FALSE; record = malloc(S_LONG); DISPLAY("\n\n Trace Manhattan Bank\n"); DISPLAY("Automated Teller Machine\n\n\n"); DISPLAY("Please enter your account number\n"); DISPLAY("or enter 0 to exit: "); do { READ(line); acct_num = atoi(line); if (acct_num == 0) /* allow user to exit without */ { good_input = TRUE; } /* logging in */ if (acct_num != 0) { atm_start_ro(); val_num = atm_valid_acct_num(acct_num); /* valid acct num or -1 */ atm_rollback(); if (val_num == -1) /* no account in database */ { if (Event_Flags[VALIDATION_ERR]) { memcpy(record, &acct_num, S_LONG); status = epc_event(API_VERSION, VENDOR, FAC_NUMBER, VALIDATION_ERR, 0, record, S_LONG, 0, 0, 0, &Facctx); if (status != epc_s_success) report_epc_error("login_user", "Error on epc_event: ", status); } DISPLAY("\nInvalid account number. Enter your account number"); DISPLAY("\nor enter 0 to exit: "); } else /* account in database */ { if (Event_Flags[VALIDATION_OK]) { memcpy(record, &acct_num, S_LONG); status = epc_event(API_VERSION, VENDOR, FAC_NUMBER, VALIDATION_OK, 0, record, S_LONG, 0, 0, 0, &Facctx); if (status != epc_s_success) report_epc_error("login_user", "Error on epc_event: ", status); } good_input = TRUE; } } } while (!good_input); free(record); return (acct_num); } /*----------------------------------------------------------------------------- init_user_session Start user_session event -----------------------------------------------------------------------------*/ void init_user_session () { long status; if (Event_Flags[USER_SESSION]) { status = epc_start_event(API_VERSION, VENDOR, FAC_NUMBER, USER_SESSION, &Session_Handle, 0, NULL, 0, 0, 0, 0,&Facctx); if (status != epc_s_success) report_epc_error("init_user_session", "Error on epc_start_event: ", status); } return; } /*----------------------------------------------------------------------------- end_user_session End user_session event -----------------------------------------------------------------------------*/ void end_user_session () { long status; /* Reset cross_fac_1 now that we're done */ status = epc_cf_value(API_VERSION, 1, 0, NULL, NULL); if (status != epc_s_success) report_epc_error("end_user_session", "Error on epc_cf_value: ", status); if (Event_Flags[USER_SESSION]) { status = epc_end_event(API_VERSION, VENDOR, FAC_NUMBER, USER_SESSION, &Session_Handle, 0, NULL, 0, 0, 0, 0,&Facctx); if (status != epc_s_success) report_epc_error("end_user_session", "Error on epc_end_event: ", status); } return; } /*----------------------------------------------------------------------------- display_main_menu Display main menu and get user's choice -----------------------------------------------------------------------------*/ long display_main_menu () { char line[MAXLINE]; long choice; char good_input; good_input = FALSE; DISPLAY("\n\nTrace Manhattan Bank\n"); DISPLAY(" ATM Main Menu\n"); DISPLAY("1. Balance\n"); DISPLAY("2. Deposit\n"); DISPLAY("3. Withdrawal\n"); DISPLAY("4. Transfer\n"); DISPLAY("5. Quick Withdrawal $50\n\n"); DISPLAY("0. Exit\n\n"); DISPLAY("Enter choice: "); do { READ(line); choice = atoi(line); if ((choice > -1) && (choice < 6)) { good_input = TRUE; } else { DISPLAY("\nInvalid choice. Enter choice: "); } } while (!good_input); return (choice); } /*----------------------------------------------------------------------------- get_balances Display balances of savings and checkings acct -----------------------------------------------------------------------------*/ void get_balances (acct_num) long acct_num; { long status; float sav_amt; float chk_amt; char line[MAXLINE]; strcpy(Regist_ID, "Balances"); status = epc_cf_value(API_VERSION, 1, BALANCES, NULL, NULL); if (status != epc_s_success) report_epc_error("get_balances", "Error on epc_cf_value: ", status); status = epc_add_reg_id(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, Regist_ID, 1,&Facctx); if (status != epc_s_success) report_epc_error("get_balances", "Error on epc_add_reg_id: ", status); if (Event_Flags[BALANCES]) { status = epc_start_event(API_VERSION, VENDOR, FAC_NUMBER, BALANCES, &Txn_Handle, 0, NULL, 0, 0, 0, 0,&Facctx); if (status != epc_s_success) report_epc_error("get_balances", "Error on epc_start_event: ", status); } atm_start_ro(); sav_amt = atm_sav_balance (acct_num); chk_amt = atm_chk_balance (acct_num); atm_commit(); if (Event_Flags[BALANCES]) { status = epc_end_event(API_VERSION, VENDOR, FAC_NUMBER, BALANCES, &Txn_Handle, 0, NULL, 0, 0, 0, 0,&Facctx); if (status != epc_s_success) report_epc_error("get_balances", "Error on epc_end_event: ", status); } status = epc_remove_reg_id(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, Regist_ID, 1,&Facctx); if (status != epc_s_success) report_epc_error("get_balances", "Error on epc_remove_reg_id: ", status); DISPLAY("\n\nAccount Balances\n\n"); if (!FromFile) { printf("Checking: %-.2f\n", chk_amt); printf("Savings : %-.2f\n", sav_amt); } DISPLAY("\nPress ENTER to return to Main Menu: "); READ(line); return; } /*----------------------------------------------------------------------------- make_deposit Deposit money into either savings or checkings. -----------------------------------------------------------------------------*/ void make_deposit (acct_num) long acct_num; { char line[MAXLINE]; long acct_type; char good_type; char good_amount; long txn_amt = 0; long status; char *record; /* event record */ good_type = FALSE; good_amount = FALSE; record = malloc(S_LONG); strcpy(Regist_ID, "Deposit"); status = epc_cf_value(API_VERSION, 1, DEPOSIT, NULL, NULL); if (status != epc_s_success) report_epc_error("make_deposit", "Error on epc_cf_value: ", status); status = epc_add_reg_id(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, Regist_ID, 1, &Facctx); if (status != epc_s_success) report_epc_error("make_deposit", "Error on epc_add_reg_id: ", status); DISPLAY("\n\nAccount Deposit\n\n"); DISPLAY("Deposit into:\n"); DISPLAY("1. Checking\n"); DISPLAY("2. Savings\n"); DISPLAY("\nEnter choice or 0 to cancel: "); do /* get account type */ { READ(line); acct_type = atoi(line); if ((acct_type < 0) || (acct_type > 2)) /* bad input */ { DISPLAY("\nInvalid choice. Enter choice: "); } else { good_type = TRUE; } /* valid account type */ } while (!good_type); if (acct_type == 0) /* cancel transaction */ { txn_amt = 0; good_amount = TRUE; } while (!good_amount) { DISPLAY("\nEnter dollar amount to deposit or 0 to cancel: "); READ(line); txn_amt = atoi(line); if (txn_amt < 0) { DISPLAY("\nInvalid amount."); } else { good_amount = TRUE; } } if (txn_amt > 0) { if (Event_Flags[DEPOSIT]) { memset(record, 0, S_LONG); status = epc_start_event(API_VERSION, VENDOR, FAC_NUMBER, DEPOSIT, &Txn_Handle, 0, record, S_LONG, 0, 0, 0, &Facctx); if (status != epc_s_success) report_epc_error("make_deposit", "Error on epc_start_event: ", status); } atm_start_rw(); if (acct_type == 1) { atm_chk_deposit(acct_num, txn_amt); } if (acct_type == 2) { atm_sav_deposit(acct_num, txn_amt); } atm_commit(); if (Event_Flags[DEPOSIT]) { memcpy(record, &txn_amt, S_LONG); status = epc_end_event(API_VERSION, VENDOR, FAC_NUMBER, DEPOSIT, &Txn_Handle, 0, record, S_LONG, 0, 0, 0, &Facctx); if (status != epc_s_success) report_epc_error("make_deposit", "Error on epc_end_event: ", status); } } status = epc_remove_reg_id(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, Regist_ID, 1, &Facctx); if (status != epc_s_success) report_epc_error("make_deposit", "Error on epc_remove_reg_id: ", status); free(record); return; } /*----------------------------------------------------------------------------- make_withdrawal Withdraw money from either savings or checkings. If withdrawal is more than balance, record an overdraft event -----------------------------------------------------------------------------*/ void make_withdrawal (acct_num) long acct_num; { long status; char line[MAXLINE]; char txn_complete; long acct_type; char good_type; long txn_amt = 0; char good_amount; float acct_bal; char *wrecord, *orecord; /* event records for withdraw, overdraft */ txn_complete = FALSE; wrecord = malloc(S_LONG); orecord = malloc(S_LONG); strcpy(Regist_ID, "Withdrawal"); status = epc_cf_value(API_VERSION, 1, WITHDRAWAL, NULL, NULL); if (status != epc_s_success) report_epc_error("make_withdrawal", "Error on epc_cf_value: ", status); status = epc_add_reg_id(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, Regist_ID, 1, &Facctx); if (status != epc_s_success) report_epc_error("make_withdrawal", "Error on epc_add_reg_id: ", status); do /* get transaction input */ { good_type = FALSE; DISPLAY("\n\nAccount Withdrawal\n\n"); DISPLAY("Withdraw from:\n"); DISPLAY("1. Checking\n"); DISPLAY("2. Savings\n"); DISPLAY("\nEnter choice or 0 to cancel: "); do { READ(line); acct_type = atoi(line); if ((acct_type < 0) || (acct_type > 2)) /* bad input */ { DISPLAY("\nInvalid choice. Enter choice: "); } else { good_type = TRUE; } /* valid account type */ } while (!good_type); if (acct_type == 0) /* cancel transaction */ { txn_complete = TRUE; good_amount = TRUE; } else { good_amount = FALSE; } while (!good_amount) { DISPLAY("\nEnter dollar amount to withdraw or 0 to cancel: "); READ(line); txn_amt = atoi(line); if (txn_amt < 0) { DISPLAY("\nInvalid amount."); } else if (txn_amt > 0) { good_amount = TRUE; } else /* txn_amt = 0; cancel */ { txn_complete = TRUE; } } /* end of good amount loop */ if (!txn_complete) { if (Event_Flags[WITHDRAWAL]) { memset(wrecord, 0, S_LONG); status = epc_start_event(API_VERSION, VENDOR, FAC_NUMBER, WITHDRAWAL, &Txn_Handle, 0, wrecord, S_LONG, 0, 0, 0, &Facctx); if (status != epc_s_success) report_epc_error("make_withdrawal", "Error on epc_start_event: ", status); } atm_start_rw(); if (acct_type == 1) { acct_bal = atm_chk_balance(acct_num); } if (acct_type == 2) { acct_bal = atm_sav_balance(acct_num); } if (acct_bal > txn_amt) /* sufficient funds */ { if (acct_type == 1) { atm_chk_withdrawal(acct_num, txn_amt, acct_bal); } if (acct_type == 2) { atm_sav_withdrawal(acct_num, txn_amt, acct_bal); } atm_commit(); txn_complete = TRUE; if (Event_Flags[WITHDRAWAL]) { memcpy(wrecord, &txn_amt, S_LONG); status = epc_end_event(API_VERSION, VENDOR, FAC_NUMBER, WITHDRAWAL, &Txn_Handle, 0, wrecord, S_LONG, 0, 0, 0,&Facctx); if (status != epc_s_success) report_epc_error("make_withdrawal", "Error on epc_end_event: ", status); } } else /* Record an overdraft; end the Withdrawal event with a txn_amt of 0 */ /* to show that a transaction really didn't happen */ { atm_rollback(); /* cancel transaction */ if (Event_Flags[OVERDRAFT]) { memcpy(orecord, &txn_amt, S_LONG); status = epc_event(API_VERSION, VENDOR, FAC_NUMBER, OVERDRAFT, 0, orecord, S_LONG, 0, 0, 0, &Facctx); if (status != epc_s_success) report_epc_error("make_withdrawal", "Error on epc_event: ", status); } if (Event_Flags[WITHDRAWAL]) { memset(wrecord, 0, S_LONG); status = epc_end_event(API_VERSION, VENDOR, FAC_NUMBER, WITHDRAWAL, &Txn_Handle, 0, wrecord, S_LONG, 0, 0, 0, &Facctx); if (status != epc_s_success) report_epc_error("make_withdrawal", "Error on epc_end_event: ", status); } DISPLAY("\nBalance insufficient for withdrawal\n"); } } } while (!txn_complete); /* until txn complete or cancelled */ status = epc_remove_reg_id(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, Regist_ID, 1,&Facctx); if (status != epc_s_success) report_epc_error("make_withdrawal", "Error on epc_remove_reg_id: ", status); free(wrecord); free(orecord); return; } /*----------------------------------------------------------------------------- make_transfer Transfer money from one account to other. Destination account might not be in this bank. -----------------------------------------------------------------------------*/ void make_transfer (acct_num) long acct_num; { long status; char line[MAXLINE]; char txn_complete; char good_source; long acct_type; char good_amount; long txn_amt = 0; long dest_num; char good_dest; long dest_type; float acct_bal; char *trecord, *orecord; /* event records for transfer, overdraft */ char *t_ptr; /* pointer to trecord */ txn_complete = FALSE; trecord = malloc(S_LONG + S_LONG); orecord = malloc(S_LONG); strcpy(Regist_ID, "Transfer"); status = epc_cf_value(API_VERSION, 1, TRANSFER, NULL, NULL); if (status != epc_s_success) report_epc_error("make_transfer", "Error on epc_cf_value: ", status); status = epc_add_reg_id(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, Regist_ID, 1, &Facctx); if (status != epc_s_success) report_epc_error("make_transfer", "Error on epc_add_reg_id: ", status); do /* get transaction input */ { DISPLAY("\n\nAccount Transfer\n\n"); DISPLAY("Transfer from:\n"); DISPLAY("1. Checking\n"); DISPLAY("2. Savings\n"); DISPLAY("\nEnter choice or 0 to cancel: "); good_source = FALSE; do { READ(line); acct_type = atoi(line); if ((acct_type < 0) || (acct_type > 2)) /* bad input */ { DISPLAY("\nInvalid choice. Enter choice: "); } else { good_source = TRUE; } /* valid account type */ } while (!good_source); if (acct_type == 0) /* cancel transaction */ { return; } good_amount = FALSE; while (!good_amount) { DISPLAY("\nEnter dollar amount to transfer or 0 to cancel: "); READ(line); txn_amt = atoi(line); if (txn_amt < 0) { DISPLAY("\nInvalid amount."); } if (txn_amt > 0) { good_amount = TRUE; } if (txn_amt == 0) /* cancel transaction */ { return; } } DISPLAY("\nEnter destination account number or 0 to cancel: "); READ(line); dest_num = atoi(line); if (dest_num == 0) /* cancel transaction */ { return; } DISPLAY("\nTransfer to:\n"); DISPLAY("1. Checking\n"); DISPLAY("2. Savings\n"); DISPLAY("\nEnter choice or 0 to cancel: "); good_dest = FALSE; do { READ(line); dest_type = atoi(line); if ((dest_type < 0) || (dest_type > 2)) /* bad input */ { DISPLAY("\nInvalid choice. Enter choice: "); } else { good_dest = TRUE; } /* valid account type */ } while (!good_dest); if (dest_type == 0) /* cancel transaction */ { return; } /*---------------------------------------------------------------------------- Now we have good source, destination, amount -----------------------------------------------------------------------------*/ if (Event_Flags[TRANSFER]) { t_ptr = trecord; memset(t_ptr, 0, S_LONG); t_ptr += S_LONG; memcpy(t_ptr, &dest_num, S_LONG); status = epc_start_event(API_VERSION, VENDOR, FAC_NUMBER, TRANSFER, &Txn_Handle, 0, trecord, (S_LONG + S_LONG), 0, 0, 0, &Facctx); if (status != epc_s_success) report_epc_error("make_transfer", "Error on epc_start_event: ", status); } atm_start_rw(); if (acct_type == 1) { acct_bal = atm_chk_balance(acct_num); } if (acct_type == 2) { acct_bal = atm_sav_balance(acct_num); } if (acct_bal > txn_amt) /* sufficient funds */ { if (acct_type == 1) { atm_chk_withdrawal(acct_num, txn_amt, acct_bal); } if (acct_type == 2) { atm_sav_withdrawal(acct_num, txn_amt, acct_bal); } /* Returns 0 if the account number is not for this branch of the bank */ dest_num = atm_valid_xfer_acct(dest_num); if (dest_num) { if (dest_type == 1) { atm_chk_deposit(dest_num, txn_amt); } if (dest_type == 2) { atm_sav_deposit(dest_num, txn_amt); } } atm_commit(); if (Event_Flags[TRANSFER]) { t_ptr = trecord; memcpy(t_ptr, &txn_amt, S_LONG); t_ptr += S_LONG; memcpy(t_ptr, &dest_num, S_LONG); status = epc_end_event(API_VERSION, VENDOR, FAC_NUMBER, TRANSFER, &Txn_Handle, 0, trecord, (S_LONG + S_LONG), 0, 0, 0, &Facctx); if (status != epc_s_success) report_epc_error("make_transfer", "Error on epc_end_event: ", status); } txn_complete = TRUE; } else /* insufficient funds */ { atm_rollback; /* cancel transaction */ if (Event_Flags[OVERDRAFT]) { memcpy(orecord, &txn_amt, S_LONG); status = epc_event(API_VERSION, VENDOR, FAC_NUMBER, OVERDRAFT, 0, orecord, S_LONG, 0, 0, 0,&Facctx); if (status != epc_s_success) report_epc_error("make_transfer", "Error on epc_event: ", status); } if (Event_Flags[TRANSFER]) { t_ptr = trecord; memset(t_ptr, 0, S_LONG); t_ptr += S_LONG; memcpy(t_ptr, &dest_num, S_LONG); status = epc_end_event(API_VERSION, VENDOR, FAC_NUMBER, TRANSFER, &Txn_Handle, 0, trecord, (S_LONG + S_LONG), 0, 0, 0, &Facctx); if (status != epc_s_success) report_epc_error("make_transfer", "Error on epc_end_event: ", status); } DISPLAY("\nInsufficient funds.\n"); } } while (!txn_complete); status = epc_remove_reg_id(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, Regist_ID, 1, &Facctx); if (status != epc_s_success) report_epc_error("make_transfer", "Error on epc_remove_reg_id: ", status); free(trecord); free(orecord); return; } /*----------------------------------------------------------------------------- make_quick_withdrawal Withdraw $50 from checking. If withdrawal is more than balance, record an overdraft event. -----------------------------------------------------------------------------*/ long make_quick_withdrawal (acct_num) long acct_num; { long status; float chk_bal; long good_txn; long txn_amt = 50; char *qrecord, *orecord; qrecord = malloc(S_LONG); orecord = malloc(S_LONG); strcpy(Regist_ID, "Quick Withdrawal"); status = epc_cf_value(API_VERSION, 1, QUICK_WITHDRAW, NULL, NULL); if (status != epc_s_success) report_epc_error("make_quick_withdrawal", "Error on epc_start_event: ", status); status = epc_add_reg_id(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, Regist_ID, 1, &Facctx); if (status != epc_s_success) report_epc_error("make_quick_withdrawal", "Error on epc_start_event: ", status); if (Event_Flags[QUICK_WITHDRAW]) { memset(qrecord, 0, S_LONG); status = epc_start_event(API_VERSION, VENDOR, FAC_NUMBER, QUICK_WITHDRAW, &Txn_Handle, 0, qrecord, S_LONG, 0, 0, 0,&Facctx); if (status != epc_s_success) report_epc_error("make_quick_withdrawal", "Error on epc_start_event: ", status); } atm_start_rw(); chk_bal = atm_chk_balance(acct_num); if (chk_bal > 50) { atm_chk_withdrawal(acct_num, txn_amt, chk_bal); atm_commit(); if (Event_Flags[QUICK_WITHDRAW]) { memcpy(qrecord, &txn_amt, S_LONG); status = epc_end_event(API_VERSION, VENDOR, FAC_NUMBER, QUICK_WITHDRAW, &Txn_Handle, 0, qrecord, S_LONG, 0, 0, 0,&Facctx); if (status != epc_s_success) report_epc_error("make_quick_withdrawal", "Error on epc_collect: ", status); } good_txn = TRUE; } else /* insufficient funds */ { atm_rollback; /* cancel transaction */ if (Event_Flags[OVERDRAFT]) { memcpy(orecord, &txn_amt, S_LONG); status = epc_event(API_VERSION, VENDOR, FAC_NUMBER, OVERDRAFT, 0, orecord, S_LONG, 0, 0, 0,&Facctx); if (status != epc_s_success) report_epc_error("make_quick_withdrawal", "Error on epc_collect: ", status); } if (Event_Flags[QUICK_WITHDRAW]) { memset(qrecord, 0, S_LONG); status = epc_end_event(API_VERSION, VENDOR, FAC_NUMBER, QUICK_WITHDRAW, &Txn_Handle, 0, qrecord, S_LONG, 0, 0, 0,&Facctx); if (status != epc_s_success) report_epc_error("make_quick_withdrawal", "Error on epc_collect: ", status); } DISPLAY("\nInsufficient funds.\n"); good_txn = FALSE; } status = epc_remove_reg_id(API_VERSION, VENDOR, FAC_NUMBER, FAC_VERSION, Regist_ID, 1, &Facctx); if (status != epc_s_success) report_epc_error("make_quick_withdrawal", "Error on epc_collect: ", status); free(qrecord); free(orecord); return (good_txn); } /*********************************************************** * * * Database access routines using OCI. Datatypes are * * defined by s.h, part of the Oracle core library. These * * datatypes are also defined by oratypes.h, which can be * * found in $ORACLE_HOME/rdbms/demo along with the OCI * * header files. * * * ***********************************************************/ /*----------------------------------------------------------------------------- atm_valid_acct_num Return acct_num if found in database; otherwise, return -1 -----------------------------------------------------------------------------*/ long atm_valid_acct_num (acct_num) long acct_num; { text *sql_stmt = (text *)"SELECT count(*) FROM savings \ WHERE account_number = :acct_num"; volatile sb4 rec_cnt; /* for OCI volatile prevents register use */ sb2 ind_cnt = 0; sb2 ind_acct = 0; sword oci_ret = OCI_SUCCESS; sb4 oci_errcode = 0; text oci_msgbuf[OCI_ERROR_MAXMSG_SIZE]; /* Prepare SQL stmt ... */ if ((oci_ret = OCIStmtPrepare (oci_stmthp, oci_errhp, sql_stmt, (ub4)strlen((char *)sql_stmt), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)) != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIStmtPrepare error: %s \n", oci_msgbuf); return(-1); /* ie same as not found condition */ } /* Define output record count variable ... */ if ((oci_ret = OCIDefineByPos (oci_stmthp, &oci_defp, oci_errhp, (ub4)1, (dvoid *)&rec_cnt, (sb4)sizeof(sb4), (ub2)SQLT_INT, (dvoid *)&ind_cnt, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT)) != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIDefineByPos error: %s \n", oci_msgbuf); return(-1); /* ie same as not found condition */ } /* Bind input account number param ... */ if ((oci_ret = OCIBindByName (oci_stmthp, &oci_bndap, oci_errhp, (text *)":acct_num", (sb4)-1, (dvoid *)&acct_num, (sb4)sizeof(acct_num), (ub2)SQLT_INT, (dvoid *)&ind_acct, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIBindByName error: %s \n", oci_msgbuf); return(-1); /* ie same as not found condition */ } /* Execute SQL stmt ... */ oci_ret = OCIStmtExecute (oci_svchp, oci_stmthp, oci_errhp, (ub4)1, (ub4)0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT); if (oci_ret != OCI_SUCCESS) { if (oci_ret == OCI_NO_DATA) { return (-1); /* shouldn't occur, but ... */ } OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIStmtExecute error: %s \n", oci_msgbuf); return (-1); } else if (rec_cnt == 0) { return (-1); /* for no records found */ } return (acct_num); /* success: found requested record */ } /*----------------------------------------------------------------------------- atm_valid_xfer_acct Return acct_num if found in database; otherwise, return 0 Note: this routine performs same search of Savings table for acct_num as the atm_valid_acct_num routine does, other than difference in returned value for failure to validate acct_num, so just use atm_valid_acct_num here with suitable return value. -----------------------------------------------------------------------------*/ long atm_valid_xfer_acct (acct_num) long acct_num; { if (atm_valid_acct_num(acct_num) == acct_num) return(acct_num); else return (0); } /*----------------------------------------------------------------------------- atm_balance Return savings or checking account balance for specified account number -----------------------------------------------------------------------------*/ float atm_balance (acct_num, sql_stmt) long acct_num; text *sql_stmt; { volatile float balance = 0; sb2 ind_bal = 0; sb2 ind_acct = 0; sword oci_ret = OCI_SUCCESS; sb4 oci_errcode = 0; text oci_msgbuf[OCI_ERROR_MAXMSG_SIZE]; /* Prepare SQL stmt ... */ if ((oci_ret = OCIStmtPrepare (oci_stmthp, oci_errhp, sql_stmt, (ub4)strlen((char *)sql_stmt), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)) != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIStmtPrepare error: %s \n", oci_msgbuf); exit(1); } /* Define output balance variable ... */ if ((oci_ret = OCIDefineByPos (oci_stmthp, &oci_defp, oci_errhp, (ub4)1, (dvoid *)&balance, (sb4)sizeof(float), (ub2)SQLT_FLT, (dvoid *)&ind_bal, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT)) != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIDefineByPos error: %s \n", oci_msgbuf); exit(1); } /* Bind input account number param ... */ if ((oci_ret = OCIBindByName (oci_stmthp, &oci_bndap, oci_errhp, (text *)":acct_num", (sb4)-1, (dvoid *)&acct_num, (sb4)sizeof(acct_num), (ub2)SQLT_INT, (dvoid *)&ind_acct, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIBindByName error: %s \n", oci_msgbuf); exit(1); } /* Execute SQL stmt ... */ oci_ret = OCIStmtExecute (oci_svchp, oci_stmthp, oci_errhp, (ub4)1, (ub4)0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT); if (oci_ret != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIStmtExecute error: %s \n", oci_msgbuf); exit(1); } return (balance); /* success: return requested account balance */ } /*----------------------------------------------------------------------------- atm_sav_balance Return savings account balance for account number -----------------------------------------------------------------------------*/ float atm_sav_balance (acct_num) long acct_num; { text *sql_stmt = (text *) "SELECT balance FROM savings \ WHERE account_number = :acct_num"; return (atm_balance(acct_num, sql_stmt)); } /*----------------------------------------------------------------------------- atm_chk_balance Return checking account balance for account number -----------------------------------------------------------------------------*/ float atm_chk_balance (acct_num) long acct_num; { text *sql_stmt = (text *) "SELECT balance FROM checking \ WHERE account_number = :acct_num"; return (atm_balance(acct_num, sql_stmt)); } /*----------------------------------------------------------------------------- atm_update_balance Update balance in savings/checking account to reflect deposit/withdrawl -----------------------------------------------------------------------------*/ void atm_update_balance (acct_num, new_balance, sql_stmt) long acct_num; float new_balance; text *sql_stmt; { volatile float balance = (float)new_balance; sb2 ind_bal = 0; sb2 ind_acct = 0; sword oci_ret = OCI_SUCCESS; sb4 oci_errcode = 0; text oci_msgbuf[OCI_ERROR_MAXMSG_SIZE]; /* Prepare SQL stmt ... */ if ((oci_ret = OCIStmtPrepare (oci_stmthp, oci_errhp, sql_stmt, (ub4)strlen((char *)sql_stmt), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)) != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIStmtPrepare error: %s \n", oci_msgbuf); exit(1); } /* Bind input params ... */ if ((oci_ret = OCIBindByName (oci_stmthp, &oci_bndbp, oci_errhp, (text *)":balance", (sb4)-1, (dvoid *)&balance, (sb4)sizeof(balance), (ub2)SQLT_FLT, (dvoid *)&ind_bal, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIBindByName error: %s \n", oci_msgbuf); exit(1); } if ((oci_ret = OCIBindByName (oci_stmthp, &oci_bndap, oci_errhp, (text *)":acct_num", (sb4)-1, (dvoid *)&acct_num, (sb4)sizeof(acct_num), (ub2)SQLT_INT, (dvoid *)&ind_acct, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT)) != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIBindByName error: %s \n", oci_msgbuf); exit(1); } /* Execute SQL stmt ... */ oci_ret = OCIStmtExecute (oci_svchp, oci_stmthp, oci_errhp, (ub4)1, (ub4)0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT); if (oci_ret != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIStmtExecute error: %s \n", oci_msgbuf); exit(1); } return; } /*----------------------------------------------------------------------------- atm_sav_deposit Add amount to balance in savings account -----------------------------------------------------------------------------*/ void atm_sav_deposit (acct_num, amount) long acct_num; long amount; { float new_balance; text *sql_stmt = (text *) "UPDATE savings SET balance = :balance \ WHERE account_number = :acct_num"; new_balance = amount + atm_sav_balance(acct_num); atm_update_balance (acct_num, new_balance, sql_stmt); return; } /*----------------------------------------------------------------------------- atm_chk_deposit Add amount to balance in checking account -----------------------------------------------------------------------------*/ void atm_chk_deposit (acct_num, amount) long acct_num; long amount; { float new_balance; text *sql_stmt = (text *) "UPDATE checking SET balance = :balance \ WHERE account_number = :acct_num"; new_balance = amount + atm_chk_balance(acct_num); atm_update_balance (acct_num, new_balance, sql_stmt); return; } /*----------------------------------------------------------------------------- atm_sav_withdrawal Subtract amount from balance in savings account; assumes amount is less than balance (we checked balance before calling) -----------------------------------------------------------------------------*/ void atm_sav_withdrawal (acct_num, amount, sav_bal) long acct_num; long amount; float sav_bal; { text *sql_stmt = (text *) "UPDATE savings SET balance = :balance \ WHERE account_number = :acct_num"; sav_bal = sav_bal - amount; atm_update_balance (acct_num, sav_bal, sql_stmt); return; } /*----------------------------------------------------------------------------- atm_chk_withdrawal Subtract amount from balance in checking account; assumes amount is less than balance (we checked balance before calling) -----------------------------------------------------------------------------*/ void atm_chk_withdrawal (acct_num, amount, chk_bal) long acct_num; long amount; float chk_bal; { text *sql_stmt = (text *) "UPDATE checking SET balance = :balance \ WHERE account_number = :acct_num"; chk_bal = chk_bal - amount; atm_update_balance (acct_num, chk_bal, sql_stmt); return; } /*----------------------------------------------------------------------------- atm_txn Start, commit, or rollback (RO or RW) transaction -----------------------------------------------------------------------------*/ void atm_txn (sql_stmt) text *sql_stmt; { sword oci_ret = OCI_SUCCESS; sb4 oci_errcode = 0; text oci_msgbuf[OCI_ERROR_MAXMSG_SIZE]; /* Prepare SQL stmt ... */ if ((oci_ret = OCIStmtPrepare (oci_stmthp, oci_errhp, sql_stmt, (ub4)strlen((char *)sql_stmt), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)) != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIStmtPrepare error: %s \n", oci_msgbuf); exit(1); } /* Execute SQL stmt ... */ oci_ret = OCIStmtExecute (oci_svchp, oci_stmthp, oci_errhp, (ub4)1, (ub4)0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT); if (oci_ret != OCI_SUCCESS) { OCIErrorGet ((dvoid *)oci_errhp, (ub4)1, (text *)NULL, &oci_errcode, oci_msgbuf, (ub4)sizeof(oci_msgbuf), OCI_HTYPE_ERROR); fprintf(stderr, "\n %s \n", sql_stmt); fprintf(stderr, "\n OCIStmtExecute error: %s \n", oci_msgbuf); exit(1); } return; } /*----------------------------------------------------------------------------- atm_start_rw Start read-write transaction -----------------------------------------------------------------------------*/ void atm_start_rw () { text *sql_stmt = (text *) "SET TRANSACTION READ WRITE"; atm_txn (sql_stmt); return; } /*----------------------------------------------------------------------------- atm_start_ro Start read-only transaction -----------------------------------------------------------------------------*/ void atm_start_ro () { text *sql_stmt = (text *) "SET TRANSACTION READ ONLY"; atm_txn (sql_stmt); return; } /*----------------------------------------------------------------------------- atm_commit Commit transaction -----------------------------------------------------------------------------*/ void atm_commit () { text *sql_stmt = (text *) "COMMIT"; atm_txn (sql_stmt); return; } /*----------------------------------------------------------------------------- atm_rollback Rollback transaction -----------------------------------------------------------------------------*/ void atm_rollback () { text *sql_stmt = (text *) "ROLLBACK"; atm_txn (sql_stmt); return; } /*----------------------------------------------------------------------------- report_epc_error On error from Trace API call, print message and exit with status -----------------------------------------------------------------------------*/ void report_epc_error (routine, message, status) char routine[20]; char message[80]; long status; { fprintf(stderr, "Error in %s\n", routine); fprintf(stderr, "%s%d\n", message, status); fprintf(stderr, "Exiting\n"); exit(status); }