/* * vb1.pc * * Prompts the user for a branch number, * then queries the branch table for the branch's * address, phone and fax. * 2003, Siegfried Nijssen (snijssen@liacs.nl) */ #include #include #include #include #include #include // Define constants for VARCHAR lengths. #define UNAME_LEN 20 #define PWD_LEN 40 //* Declare variables. EXEC SQL BEGIN DECLARE SECTION; VARCHAR username[UNAME_LEN]; VARCHAR password[PWD_LEN]; // Define a host structure for the output values of a SELECT statement. struct { VARCHAR branch_no[10]; VARCHAR address[60]; VARCHAR phone[13]; VARCHAR fax[13]; } branchrec; // Input host variable. VARCHAR branch_no[10]; EXEC SQL END DECLARE SECTION; // Declare error handling function. void sql_error(char *msg) { char err_msg[128]; size_t buf_len, msg_len; EXEC SQL WHENEVER SQLERROR CONTINUE; /* after executing this line, sql_error is no longer used as * error handling function. In this way, infinite * recursion is avoided if the next SQL statement * in this function fails. */ // Print the error message: cout << msg << endl; buf_len = sizeof (err_msg); sqlglm(err_msg, &buf_len, &msg_len); cout << msg_len << "*" << err_msg << endl; // Make sure the database is consistent: EXEC SQL ROLLBACK RELEASE; // Stop the program. exit(EXIT_FAILURE); } void main() { char temp_char[32]; /* strings are of type VARCHAR in Oracle and not \0 * terminated. We use this temporary variable * whenever a \0 terminated string is necessary. */ cout << "Enter your ORACLE username: " << endl; cin >> temp_char; /* Connect to ORACLE-- * Copy the username into the VARCHAR. */ strncpy((char *) username.arr, temp_char, UNAME_LEN); // Set the length component of the VARCHAR. This is always required! username.len = (unsigned short) strlen((char *) username.arr); cout << "Enter your ORACLE password: " << endl; cin >> temp_char; // Copy the password. strncpy((char *) password.arr, temp_char, PWD_LEN); password.len = (unsigned short) strlen((char *) password.arr); // Register sql_error() as the error handler. */ EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE error--\n"); /* Connect to ORACLE. Program will call sql_error() * if an error occurs when connecting to the default database. */ EXEC SQL CONNECT :username IDENTIFIED BY :password; cout << "Connected to ORACLE as user: " << username.arr << endl; /* Loop, asking for branch IDs */ do { cout << "Enter branch number: (0 to quit) "; cin >> temp_char; if ( strcmp ( temp_char, "0" ) == 0 ) break; // stop the while loop // Fill in branch_no that we will use in the query. strncpy((char *) branch_no.arr, temp_char, 10); branch_no.len = (unsigned short) strlen((char *) branch_no.arr); /* Branch to the notfound label when the * 1403 ("No data found") condition occurs. * Although labels are required here, this does not mean that * using labels in general is good programming practice! * You are only allowed to use labels as target for an SQL GOTO statement. */ EXEC SQL WHENEVER NOT FOUND GOTO notfound; EXEC SQL SELECT branch_no, address, phone, fax INTO :branchrec FROM Branch WHERE branch_no = :branch_no; /* Print data. * The branchrec.address VARCHAR is not \0 terminated. We have * to make it \0 terminated first to print it. */ branchrec.address.arr[branchrec.address.len] = '\0'; cout << "Address: " << branchrec.address.arr << endl; branchrec.phone.arr[branchrec.phone.len] = '\0'; cout << "Phone: " << branchrec.phone.arr << endl; branchrec.fax.arr[branchrec.fax.len] = '\0'; cout << "Fax: " << branchrec.fax.arr << endl; // Continue the loop, the other lines in this loop are // for error handling: continue; notfound: cout << endl << "Not a valid branch number - try again." << endl; } while ( true ); // continue after an invalid branch number. // Disconnect from ORACLE. EXEC SQL ROLLBACK WORK RELEASE; exit(EXIT_SUCCESS); }