この項には、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);
}