この項には、C++構造体を含んでいるサンプルのPro*C/C++プログラムを3つ記載しています。これらのプログラムはそれぞれdemo
ディレクトリにオンラインで利用可能な形で入っています。
/* cppdemo1.pc * * Prompts the user for an employee number, then queries the * emp table for the employee's name, salary and commission. * Uses indicator variables (in an indicator struct) to * determine if the commission is NULL. */ #include <iostream.h> #include <stdio.h> #include <string.h> // Parse=partial by default when code=cpp, // so preprocessor directives are recognized and parsed fully. #define UNAME_LEN 20 #define PWD_LEN 40 // Declare section is required when CODE=CPP or // PARSE={PARTIAL|NONE} or both. EXEC SQL BEGIN DECLARE SECTION; VARCHAR username[UNAME_LEN]; // VARCHAR is an ORACLE pseudotype varchar password[PWD_LEN]; // can be in lower case also // Define a host structure for the output values // of a SELECT statement struct empdat { VARCHAR emp_name[UNAME_LEN]; float salary; float commission; } emprec; // Define an indicator struct to correspond to the // host output struct struct empind { short emp_name_ind; short sal_ind; short comm_ind; } emprec_ind; // Input host variables int emp_number; int total_queried; EXEC SQL END DECLARE SECTION; // Define a C++ class object to match the desired // struct from the preceding declare section. class emp { char ename[UNAME_LEN]; float salary; float commission; public: // Define a constructor for this C++ object that // takes ordinary C objects. emp(empdat&, empind&); friend ostream& operator<<(ostream&, emp&); }; emp::emp(empdat& dat, empind& ind) { strncpy(ename, (char *)dat.emp_name.arr, dat.emp_name.len); ename[dat.emp_name.len] = '\0'; this->salary = dat.salary; this->commission = (ind.comm_ind < 0) ? 0 : dat.commission; } ostream& operator<<(ostream& s, emp& e) { return s << e.ename << " earns " << e.salary << " plus " << e.commission << " commission." << endl << endl; } // Include the SQL Communications Area // You can use #include or EXEC SQL INCLUDE #include <sqlca.h> // Declare error handling function void sql_error(char *msg); main() { char temp_char[32]; // Register sql_error() as the error handler EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE error:"); // Connect to ORACLE. Program calls sql_error() // if an error occurs // when connecting to the default database. // Note the (char *) cast when // copying into the VARCHAR array buffer. username.len = strlen(strcpy((char *)username.arr, "SCOTT")); password.len = strlen(strcpy((char *)password.arr, "TIGER")); EXEC SQL CONNECT :username IDENTIFIED BY :password; // Here again, note the (char *) cast when using VARCHARs cout << "\nConnected to ORACLE as user: " << (char *)username.arr << endl << endl; // Loop, selecting individual employee's results total_queried = 0; while (1) { emp_number = 0; printf("Enter employee number (0 to quit): "); gets(temp_char); emp_number = atoi(temp_char); if (emp_number == 0) break; // Branch to the notfound label when the // 1403 ("No data found") condition occurs EXEC SQL WHENEVER NOT FOUND GOTO notfound; EXEC SQL SELECT ename, sal, comm INTO :emprec INDICATOR :emprec_ind // You can also use // C++ style FROM EMP // Comments in SQL statemtents. WHERE EMPNO = :emp_number; { // Basic idea is to pass C objects to // C++ constructors thus // creating equivalent C++ objects used in the // usual C++ way emp e(emprec, emprec_ind); cout << e; } total_queried++; continue; notfound: cout << "Not a valid employee number - try again." << endl << endl; } // end while(1) cout << endl << "Total rows returned was " << total_queried << endl; cout << "Have a nice day!" << endl << endl; // Disconnect from ORACLE EXEC SQL COMMIT WORK RELEASE; exit(0); } void sql_error(char *msg) { EXEC SQL WHENEVER SQLERROR CONTINUE; cout << endl << msg << endl; cout << sqlca.sqlerrm.sqlerrmc << endl; EXEC SQL ROLLBACK RELEASE; exit(1); }
次のアプリケーションは、簡単なモジュール化の例です。最初にSQL*Plusの次のSQLスクリプトcppdemo2.sql
を実行します。
Rem This is the SQL script that accompanies the cppdemo2 C++ Demo Rem Program. Run this prior to Precompiling the empclass.pc file. / CONNECT SCOTT/TIGER / CREATE OR REPLACE VIEW emp_view AS SELECT ename, empno FROM EMP / CREATE OR REPLACE PACKAGE emp_package AS TYPE emp_cursor_type IS REF CURSOR RETURN emp_view%ROWTYPE; PROCEDURE open_cursor(curs IN OUT emp_cursor_type); END emp_package; / CREATE OR REPLACE PACKAGE BODY emp_package AS PROCEDURE open_cursor(curs IN OUT emp_cursor_type) IS BEGIN OPEN curs FOR SELECT ename, empno FROM emp_view ORDER BY ename ASC; END; END emp_package; / EXIT /
ヘッダー・ファイルempclass.h
では、emp
クラスが定義されます。
// This class definition may be included in a Pro*C/C++ application // program using the EXEC SQL INCLUDE directive only. Because it // contains EXEC SQL syntax, it may not be included using a #include // directive. Any program that includes this header must be // precompiled with the CODE=CPP option. This emp class definition // is used when building the cppdemo2 C++ Demo Program. class emp { public: emp(); // Constructor: ALLOCATE Cursor Variable ~emp(); // Desctructor: FREE Cursor Variable void open(); // Open Cursor void fetch() throw (int); // Fetch (throw NOT FOUND condition) void close(); // Close Cursor void emp_error(); // Error Handler EXEC SQL BEGIN DECLARE SECTION; // When included using EXEC SQL INCLUDE, class variables have // global scope and are thus basically treated as ordinary // global variables by Pro*C/C++ during precompilation. char ename[10]; int empno; EXEC SQL END DECLARE SECTION; private: EXEC SQL BEGIN DECLARE SECTION; // Pro*C/C++ treats this as a simple global variable also. SQL_CURSOR emp_cursor; EXEC SQL END DECLARE SECTION; };
empclass.pc
のコードには、emp
メソッドが含まれています。
#include <stdio.h> #include <stdlib.h> // This example uses a single (global) SQLCA that is shared by the // emp class implementation as well as the main program for this // application. #define SQLCA_STORAGE_CLASS extern #include <sqlca.h> // Include the emp class specification in the implementation of the // class body as well as the application program that makes use of it. EXEC SQL INCLUDE empclass.h; emp::emp() { // The scope of this WHENEVER statement spans the entire module. // Note that the error handler function is really a member function // of the emp class. EXEC SQL WHENEVER SQLERROR DO emp_error(); EXEC SQL ALLOCATE :emp_cursor; // Constructor - ALLOCATE Cursor. } emp::~emp() { EXEC SQL FREE :emp_cursor; // Destructor - FREE Cursor. } void emp::open() { EXEC SQL EXECUTE BEGIN emp_package.open_cursor(:emp_cursor); END; END-EXEC; } void emp::close() { EXEC SQL CLOSE :emp_cursor; } void emp::fetch() throw (int) { EXEC SQL FETCH :emp_cursor INTO :ename, :empno; if (sqlca.sqlcode == 1403) throw sqlca.sqlcode; // Like a WHENEVER NOT FOUND statement. } void emp::emp_error() { printf("%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc); EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL ROLLBACK WORK RELEASE; exit(1); }
メイン・プログラムcppdemo2.pc
では、カーソル変数が使用されます。
// Pro*C/C++ sample program demonstrating a simple use of Cursor Variables // implemented within a C++ class framework. Build this program as follows // // 1. Execute the cppdemo2.sql script within SQL*Plus // 2. Precompile the empclass.pc program as follows // > proc code=cpp sqlcheck=full user=scott/tiger lines=yes empclass // 3. Precompile the cppdemo2.pc program as follows // > proc code=cpp lines=yes cppdemo2 // 4. Compile and Link // // Note that you may have to specify various include directories using the // include option when precompiling. #include <stdio.h> #include <stdlib.h> #include <sqlca.h> static void sql_error() { printf("%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc); EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL ROLLBACK WORK RELEASE; exit(1); } // Physically include the emp class definition in this module. EXEC SQL INCLUDE empclass.h; int main() { EXEC SQL BEGIN DECLARE SECTION; char *uid = "scott/tiger"; EXEC SQL END DECLARE SECTION; EXEC SQL WHENEVER SQLERROR DO sql_error(); EXEC SQL CONNECT :uid; emp *e = new emp(); // Invoke Constructor - ALLOCATE Cursor Variable. e->open(); // Open the Cursor. while (1) { // Fetch from the Cursor, catching the NOT FOUND condition // thrown by the fetch() member function. try { e->fetch(); } catch (int code) { if (code == 1403) break; } printf("Employee: %s[%d]\n", e->ename, e->empno); } e->close(); // Close the Cursor. delete e; // Invoke Destructor - FREE Cursor Variable. EXEC SQL ROLLBACK WORK RELEASE; return (0); }
/* * cppdemo3.pc : An example of C++ Inheritance * * This program finds all salesman and prints their names * followed by how much they earn in total (ie; including * any commissions). */ #include <iostream.h> #include <stdio.h> #include <sqlca.h> #include <string.h> #define NAMELEN 10 class employee { // Base class is a simple employee public: char ename[NAMELEN]; int sal; employee(char *, int); }; employee::employee(char *ename, int sal) { strcpy(this->ename, ename); this->sal = sal; } // A salesman is a kind of employee class salesman : public employee { int comm; public: salesman(char *, int, int); friend ostream& operator<<(ostream&, salesman&); }; // Inherits employee attributes salesman::salesman(char *ename, int sal, int comm) : employee(ename, sal), comm(comm) {} ostream& operator<<(ostream& s, salesman& m) { return s << m.ename << m.sal + m.comm << endl; } void print(char *ename, int sal, int comm) { salesman man(ename, sal, comm); cout << man; } main() { EXEC SQL BEGIN DECLARE SECTION; char *uid = "scott/tiger"; char ename[NAMELEN]; int sal, comm; short comm_ind; EXEC SQL END DECLARE SECTION; EXEC SQL WHENEVER SQLERROR GOTO error; EXEC SQL CONNECT :uid; EXEC SQL DECLARE c CURSOR FOR SELECT ename, sal, comm FROM emp WHERE job = 'SALESMAN' ORDER BY ename; EXEC SQL OPEN c; cout << "Name Salary" << endl << "------ ------" << endl; EXEC SQL WHENEVER NOT FOUND DO break; while(1) { EXEC SQL FETCH c INTO :ename, :sal, :comm:comm_ind; print(ename, sal, (comm_ind < 0) ? 0 : comm); } EXEC SQL CLOSE c; exit(0); error: cout << endl << sqlca.sqlerrm.sqlerrmc << endl; exit(1); }