ORACLE C++ CALL INTERFACE(OCCI) Shankar Iyer, Oracle India. Oracle C++ Call Interface(OCCI) 1 OCCI – Today’s Agenda Session I - Introduction - SQL/PLSQL Execution - Data classes Session III - Scalability Features - 10i features Session II - Object Features - MetaData access Session IV - Interoperability with OCI - OCCI Performance Tuning - Demo application -Q&A Oracle C++ Call Interface(OCCI) 2 OCCI – Introduction C++ API to access Oracle database Designed as small set of well encapsulated classes and interfaces for ease of use Extensive features for relational access, object-relational access and scalability Introduced in 9i, growing customer base Oracle C++ Call Interface(OCCI) 3 OCCI - Benefits Easy to learn and use, similar to JDBC in relational access Based on Standard C++ and object oriented design Higher productivity and quality in application development Develop client-server, middle-tier and complex object modeling applications Continuing enhancements by Oracle to add more features Oracle C++ Call Interface(OCCI) 4 OCCI – Features Complete SQL/PLSQL execution support Scalability options to serve increasing number of users and requests Seamless interface to manipulate objects of user-defined types as C++ class instances Support for all Oracle data types and large object(LOB) types Database metadata access Oracle C++ Call Interface(OCCI) 5 OCCI – Building an application Application source files (use OCCI API and classes) C++ compiler OCCI API header files OTT generated C++ class headers OTT generated C++ class implementations OCCI header files •occi.h •occiCommon.h OCCI library •occiControl.h Linker •occiData.h •occiObjects.h OCCI library •libocci.so/libocci.a/oraocci9.dll Oracle C++ Call Interface(OCCI) 6 Application (static or dynamic) OCCI – Application Initialization A OCCI application is initialized by creating an Environment class instance A Environment instance specifies :- Application modes : OBJECT/THREADED/MUTEXED etc - object cache settings - memory heap for OCCI classes The Environment is the base for creating connections for further database access To create an Environment, call createEnvironment static method of Environment class Oracle C++ Call Interface(OCCI) 7 OCCI – Initialize Environment – Examples Creating default Environment //include 1 header file for all OCCI classes/interfaces #include <occi.h> //create Environment Environment *env = Environment::createEnvironment(); //use the Environment instance to create connections, //database access … //terminate Environment by calling static method //Environment::terminateEnvironment Environment::terminateEnvironment(env); Creating Environment for object access //create Environment – specify OBJECT mode Environment *env = Environment::createEnvironment(Environment::OBJECT); Oracle C++ Call Interface(OCCI) 8 OCCI – Control classes Environment Create Create Create ConnectionPool Get Get MetaData Connection Create Statement Get Execute ResultSet Oracle C++ Call Interface(OCCI) 9 Get StatelessConnection Pool OCCI – Connecting to database A user connection is represented by a Connection class instance Call the createConnection method of Environment class to create a connection - Connection *Environment::createConnection( const string &userName, const string &password, const string &connectString) Use the Connection object to access data, execute SQL commands, work with objects End connection by calling Environment::terminateConnection Advanced mechanisms like connection pooling, session pooling, proxy authentication also supported Oracle C++ Call Interface(OCCI) 10 OCCI – Create Connection - Example //First need Environment Environment *env = Environment::createEnvironment(); Connection *conn=env->createConnection(“scott”,”tiger”,””); //3rd parameter is db name/TNS alias ..//database access – use the Connection object .. .. //logoff and terminate connection env->terminateConnection(conn); Oracle C++ Call Interface(OCCI) 11 OCCI – Executing SQL/PLSQL Execute DDL/DML statements, SELECT queries, PL/SQL blocks and retrieve results Statement class for preparing & executing SQL/PLSQL statements, getting PL/SQL OUT results ResultSet class for fetching SELECT query results Uniform interface for binding and getting values of all data types - setXXX methods of Statement - getXXX methods of Statement & ResultSet Data type conversions automatically handled by OCCI Oracle C++ Call Interface(OCCI) 12 OCCI – Executing SQL – Usage Create a Statement object with Connection::createStatement() Specify SQL command(DDL/DML/query) as argument to :Connection::createStatement(string &sql); Statement::setSQL(string &sql); Statement::execute(string &sql); - can be used for any SQL, returns status Statement::executeUpdate(string &sql); - returns Insert/Update/Delete count Statement::executeQuery(string &sql); - returns ResultSet Use setXXX methods of Statement to pass input bind values Execute the SQL statement using one of the execute methods of Statement For SELECT queries, fetch the results using ResultSet class object Oracle C++ Call Interface(OCCI) 13 OCCI – Executing SQL – Examples Simple DML Insert //createStatement() on Connection class gives a Statement //instance Statement *stmt = conn->createStatement(“ insert into Dept(Deptno,Dname, Loc) values (1, ‘ACCOUNTS’, ‘ZONE1’ ”); //executeUpdate for all INSERT/UPDATE/DELETE stmt->executeUpdate(); conn->terminateStatement(stmt); DML Insert with bind Statement *stmt = conn->createStatement(“ insert into Emp(EmpNo,Ename) values(:1, :2) ”); //1 and 2 are bind placeholders int empno = 2; string empname = “JOHN W”; //first parameter is bind position, second is value stmt->setInt(1, empno); stmt->setString(2, empname); stmt->executeUpdate(); Oracle C++ Call Interface(OCCI) 14 OCCI – Executing SELECT – Examples Executing Select queries and fetching results Statement *stmt = conn->createStatement(“ select Empno, Ename, Sal from Emp where Hiredate >= :1”); //automatically converted to Date stmt->setString(1, “01-JAN-1987”); //executeQuery returns a ResultSet ResultSet *rs = stmt->executeQuery(); //ResultSet::next fetches rows and returns FALSE //when no more rows while (rs->next() == true) { //get values using the getXXX methods of ResultSet empno = rs->getInt(1); empname = rs->getString(2); empsalary = rs->getFloat(3); } stmt->closeResultSet(rs);//to free resources Oracle C++ Call Interface(OCCI) 15 OCCI – DML on multiple rows using Iterations DML(INSERT/UPDATE/DELETE) of multiple rows in single roundtrip Statement *stmt = conn->createStatement(“insert into emp (empno, ename) values (:1, :2)”); //specify max iterations stmt->setMaxIterations(10);//number of rows //specify maximum data size for types like string stmt->setMaxParamSize(2, 100); //set values and add iterations stmt->setInt(1, 1001); stmt->setString(2, “JOHN”); stmt->addIteration(); stmt->setInt(1, 1002); stmt->setString(2, “JOE”); stmt->addIteration(); …//repeat iterations,do not call addIteration after last set stmt->executeUpdate();//will insert 10 rows in single trip Oracle C++ Call Interface(OCCI) 16 OCCI – SQL Execution – Streaming Bind/fetch data in pieces, typically used for LONG columns Set binary/character streaming mode on Statement/ResultSet and use getStream() to get Stream Use read/write methods of Stream Statement *stmt = conn->createStatement(“Select LongCol…”); ResultSet *rs = rs->executeQuery(); //indicate character streaming mode rs->setCharacterStreamMode(1, 100000);//col=1,maxsize=100000 while (rs->next()) { Stream *col = rs->getStream(1); char buffer[1024]; while (col->readBuffer(buffer, 1024) != -1) //process data } //similary use Stream::writeBuffer(),writeLastBuffer() Oracle C++ Call Interface(OCCI) 17 OCCI – Executing PL/SQL Create a Statement object and specify PL/SQL block to be executed Pass any input arguments(IN and IN/OUT) to the PLSQL function/procedure/block by setXXX methods of Statement Specify any OUT parameters by Statement::registerOutParam, sizes of OUT parameters by Statement::setMaxParamSize Execute the PL/SQL block using Statement::execute() Retrieve function result/OUT/IN OUT parameters by getXXX methods of Statement Oracle C++ Call Interface(OCCI) 18 OCCI – PLSQL – Examples Calling PL/SQL function/procedure //PLSQL function : function CalculateBonus(EmpNo IN Number, // EmpStatus IN OUT VARCHAR2, // Bonus OUT Number) RETURN VARCHAR2 //call function using anonymous block Statement *stmt = conn->createStatement(“ begin :1 := CalculateBonus( :2, :3, :4); end;”); //bind position 1 is the function’s return value stmt->setInt(2, 100); //IN parameter stmt->setString(3, “Active”); //IN OUT parameter //call registerOutParam for each OUT parameter stmt->registerOutParam(1, OCCISTRING, 1000);//function’s return value stmt->setMaxParamSize(1, 100);//setMaxParamSize for STRING types stmt->registerOutParam(4, OCCIFLOAT); stmt->execute(); //use getXXX methods of Statement to get OUT parameters, return value string msg = stmt->getString(1); //function return value string newstatus = stmt->getString(3);//IN OUT parameter float bonus = stmt->getFloat(4); //OUT parameter Oracle C++ Call Interface(OCCI) 19 OCCI – SQL/PLSQL – Data buffer interface To provide and receive data in user buffers for Statement and ResultSet Bypasses OCCI and C++ specific datatypes like string/Date etc, minimizing data copies Used in array inserts(any DML) and array fetches - array DML : Statement::executeArrayUpdate(int nrows) - array fetch : ResultSet::next(int nrows) setXXX and getXXX methods should not be used if data buffer interface is used for a column Oracle C++ Call Interface(OCCI) 20 OCCI – SQL/PLSQL – Array fetch example char enames[10][20];//10 elements of length 20 chars each ub2 elens[10];//to receive the length of each element Statement *stmt = conn->createStatement("Select Ename from EMP"); ResultSet *rs = stmt->executeQuery(); //ResultSet::setDataBuffer(colIndex,buffer,type,elemsize, //lengths,ind,rc) //OCCI_SQLT_STR for char buffer rs->setDataBuffer(1, enames, OCCI_SQLT_STR, 20, elens, NULL, NULL); rs->next(5); //will fetch 5 rows in enames //do not call rs->getString(1) Oracle C++ Call Interface(OCCI) 21 OCCI – SQL/PLSQL – Array insert example int empnos[5]; empnos[0] = 801; empnos[1] = 802; stmt = conn->createStatement("insert into emp (empno) values (:1)"); //Statement::setDataBuffer(colIndex,buffer,type,elemsize, //lengths,ind,rc) //OCCIINT for int datatype stmt->setDataBuffer(1, empnos, OCCIINT, sizeof(int), NULL, NULL, NULL); stmt->executeArrayUpdate(2); //inserts 2 rows conn->commit(); Oracle C++ Call Interface(OCCI) 22 OCCI – Error Handling OCCI uses C++ exception mechanism to return all errors(in Oracle client/server or C++ STL) Applications should have a try-catch block to handle exceptions The exception object thrown is of SQLException class if error is in Oracle SQLException is derived from standard C++ exception class getErrorCode and getMessage methods of SQLException return Oracle error information Oracle C++ Call Interface(OCCI) 23 OCCI – Error Handling – Example Handling Oracle and C++ STL errors separately try { ResultSet *rs = stmt->executeQuery(); while (rs->next()) ………. } catch (SQLException &oraex) //Oracle/OCCI errors { int errno = oraex->getErrorCode();//returns the ORA number string errmsg = oraex->getMessage(); //more application error handling } catch (exception &ex) //any other C++/STL error { cout << “Error “ << ex.what() << endl; } Oracle C++ Call Interface(OCCI) 24 OCCI – Data classes Classes for using Oracle data types Oracle data type OCCI class NUMBER/REAL/INT etc Number DATE Date INTERVAL YEAR TO MONTH IntervalYM INTERVAL DAY TO SECOND IntervalDS TIMESTAMP WITH TZ/LTZ Timestamp RAW Bytes Easy to use with comprehensive functionality Used with Statement and ResultSet to insert/fetch values of these types Oracle C++ Call Interface(OCCI) 25 OCCI – Data classes - Number // inserting a number Number bignum; bignum.fromText(env, “43613923333.233”, “99999999999999.999”); stmt->setNumber(1, bignum);//stmt is Statement // Create a Number from a double value double value = 2345.123; Number nu1 (value); // Some common Number methods Number abs = nu1.abs(); /* absolute value */ Number sin = nu1.sin(); /* sine */ // Cast operators can be used long lnum = (long) nu1; // Unary increment/decrement prefix/postfix notation nu1++; Oracle C++ Call Interface(OCCI) 26 OCCI – Data classes – Date // inserting a Date // Create a Date object and bind it to the statement Date edate(env, 2000, 9, 3, 23, 30, 30); stmt->setDate(1, edate);//stmt is Statement // fetching and displaying a Date Date odate = rs->getDate(1); //rs is ResultSet Cout << odate.toText(“DD-MON-YYYY”, “GERMAN”); // interval between 2 dates IntervalDS diff; diff = odate.daysBetween(edate); Oracle C++ Call Interface(OCCI) 27 OCCI – Large Object(LOB) support Support for BLOB, CLOB/NCLOB and BFILE data types Simple, consistent, object-oriented interface OCCI classes :- Bfile, Clob, Blob Used in relational insert/fetch(column of LOB type) or as object attributes :- Statement::setBfile(int column, Bfile &value); Statement::setClob(int column, Clob &value); Statement::setBlob(int column, Blob &value); Bfile Statement/ResultSet::getBfile(int column); Clob Statement/ResultSet::getClob(int column); Blob Statement/ResultSet::getBlob(int column); Streamed read/write support Oracle C++ Call Interface(OCCI) 28 OCCI – LOB support – Examples Reading a BLOB Statement *stmt = conn->createStatement(“select resume from emp”); ResultSet *rs = stmt->executeQuery(); rs->next(); //fetch 1 row //Blob ResultSet::getBlob(int column) Blob resume = rs->getBlob(1); char buffer[100]; int bytesRead, offset = 1; while ((bytesRead = resume.read(100, buffer, 100, offset)) > 0) { //process data read //move offset to read next offset = offset + bytesRead; } Oracle C++ Call Interface(OCCI) 29 OCCI – LOB support - Examples Inserting/updating a CLOB Statement *stmt = conn->createStatement(“ insert into documents values (:1) ”); //create empty Clob Clob doccontents(conn); doccontents.setEmpty(); //1st insert will create LOB locator in database stmt->setClob(1, doccontents); stmt->executeUpdate(); conn->commit(); //now select the Clob again and add contents stmt = conn->createStatement(“select body from documents for update”); ResultSet *rs = stmt->executeQuery() doccontents = rs->getClob(1); doccontents.write (100, buffer, 100, 1); conn->commit(); Oracle C++ Call Interface(OCCI) 30 OCCI – Objects Access data from tables as C++ class instances Automatic and intuitive mapping of object types to C++ class, no user code Single data model for application and database Develop complex and powerful object-oriented applications using Oracle’s object features, OCCI and C++ Client-side cache for database transparency and performance Oracle C++ Call Interface(OCCI) 31 OCCI – Objects – Oracle basics Create object types to model application entities :create type employee as object ( empno number(5), name varchar2(30), hiredate date ); Object types can be used to create object tables or as column types in relational table :create table emptab of employee; -- object table create table person (name varchar2, age number, addr Address); -- column Terminology :- Object : a row/item in a object table - Reference : logical pointer/address of a object. Every object in a object table has a reference Oracle C++ Call Interface(OCCI) 32 OCCI – Objects – Oracle basics REF datatype represents a reference to a object in a object table create type employee as object (… Dept REF Department, -- Reference to another object ); Use REFs to model relationships (one-to-one or one-to-many) - create type LineItem as object (… Item REF Product; -- reference to Product in Products table ) - create LineItems as varray(1000) of REF LineItem; -- collection type create type PurchaseOrder as object (… ItemList LineItems; -- references to all LineItem’s of this order … In a client application, references are used to fetch objects and navigate object relationships Oracle C++ Call Interface(OCCI) 33 OCCI – Objects – Access methods Navigational access :- no SQL - Access database objects through references (REFs) - create/modify/delete/fetch ‘persistent’ objects with normal C++ code - complete transaction support - objects are maintained in the client cache Associative access :- use SQL - create/fetch object values with Statement::setObject/Statement::getObject and ResultSet::getObject - no caching of objects since they are ‘values’ Objects in a object table are accessed with navigational access. Columns of object types can be accessed with associative access Oracle C++ Call Interface(OCCI) 34 OCCI – Object Type Translator(OTT) Generates C++ class representations for Oracle object types Application uses the C++ classes for creating & accessing persistent and transient objects Object attributes are declared as member variables, with optional get/set access methods Simple format input specification file Generated code to be compiled & linked with the application Oracle C++ Call Interface(OCCI) 35 OCCI – OTT – Data type mappings Oracle data type of attribute C++/OCCI type of class member All numeric types : NUMBER,INT,REAL etc Number VARCHAR/CHAR string(C++) BFILE Bfile BLOB Blob CLOB Clob DATE Date INTERVAL YEAR TO MONTH IntervalYM INTERVAL DAY TO SECOND IntervalDS TIMESTAMP WITH TZ/LTZ Timestamp NESTED TABLE/VARRAY vector<attribute_type>(C++) REF Ref<attribute_type> Embedded object Pointer to C++ class of the embedded object type. Oracle C++ Call Interface(OCCI) 36 OCCI – OTT – Example generated class //Database type :create type employee as object ( empno number(5), name varchar2(30), hiredate date ); //C++ class generated by OTT :class EmployeeT : public oracle::occi::PObject { private: oracle::occi::Number EMPNO; string NAME; oracle::occi::Date HIREDATE; public: oracle::occi::Number getEmpno() const; void setEmpno(const oracle::occi::Number &value); string getName() const; void setName(const string &value); oracle::occi::Date getHiredate() const; void setHiredate(const oracle::occi::Date &value); Oracle C++ Call Interface(OCCI) 37 OCCI – Using OTT #input type specification file (emp.typ) $ cat emp.typ TYPE employee As EmployeeT $ #Running OTT $ ott attraccess=private code=cpp cppfile=empo.cpp hfile=emph.h intype=emp.typ mapfile=empm.cpp userid=scott/tiger #generates emph.h, empo.cpp, empm.h, empm.cpp #OTT command-line options :attraccess : attributes to be private(with get/set methods) or protected code : cpp for OCCI cppfile : name of C++ file for class implementations hfile : name of include file containing class declarations intype : input type specification file mapfile : name of C++ file containing the mapping register function userid : userid & password of the schema owning the object types Oracle C++ Call Interface(OCCI) 38 OCCI – OTT – Example code fragments 1.//Database type :create type employee as object ( Dept REF Department, -- Reference to another object ); //C++ class generated by OTT :class EmployeeT : public oracle::occi::PObject { private: Ref< DepartmentT > DEPT; 2.//Database type :create type employee as object ( Addr Address, -- embedded object ); //C++ class generated by OTT :class EmployeeT : public oracle::occi::PObject { private: AddressT *ADDR; Oracle C++ Call Interface(OCCI) 39 OCCI – OTT – Example code fragments 3.//Database type :create type PhoneList as varray(10) of varchar2(30); create type customer as object ( PhoneNumbers PhoneList, -- attribute of collection type ); //C++ class generated by OTT :class CustomerT : public oracle::occi::PObject { private: vector< string > PHONENUMBERS; 4.//Database type :create type contractemployee under employee -- inheritance ( ); //C++ class generated by OTT :class ContractEmployeeT : public EmployeeT { //C++ inheritance Oracle C++ Call Interface(OCCI) 40 OCCI – Navigational Access Retrieve objects and navigate relationships using references A reference is represented in OCCI by Ref<T> class type, where T is the class generated by OTT for the object type - Ref <AddressT> addrref; Fetch initial REFs using SQL - Statement *stmt = conn->createStatement(“Select Ref(a) from EmpTab a”); ResultSet *rs = rs->executeQuery(); rs->next(); Ref<EmployeeT> empref = rs->getRef(1); Access the object (‘pin’) using the C++ dereference operator (->) on the Ref<T> variable string empname = empref->getName(); //the -> operator returns a object pointer to type T Oracle C++ Call Interface(OCCI) 41 OCCI – Object cache Client-side memory and fast lookup for objects Maintains a fast lookup table between a reference and the corresponding C++ object When a reference is dereferenced the first time, the cache fetches the object from the server, subsequent accesses get the object from the cache Objects modified in the cache are updated in the database on transaction commit When the cache exhausts memory, it frees up unused objects in a LRU style garbage collector Oracle C++ Call Interface(OCCI) 42 OCCI – Pinning/unpinning of objects A object is ‘pinned’ in the object cache when a reference (Ref<T>) to the object is dereferenced (-> operator) The pin count of a object is incremented when additional Ref<T>’s point to the same object Application can access/modify(get/set attributes) a object after it is dereferenced and pinned A object is ‘unpinned’ and pin count decremented when the reference to it goes out of scope or points to a different object When the pin count of a object is zero, it is eligible for garbage collection and will be freed when cache memory is full Oracle C++ Call Interface(OCCI) 43 OCCI – Object cache – Example Ref<EmployeeT> empref = rs->getRef(1) //fetch and pin object string ename = empref->getName() //pass to another function by value //pin count increases by 1 Client Object Cache Oracle Database PrintEmployee(empref); //pin count decreases by 1 on return function //navigate to address object Ref <AddressT> addrref = empref->getAddr(); string city = addrref->getCity(); //Modify street in address addrref->setStreet(“1, PARK AV”); addrref->markModify(); //process another Employee object //earlier object is unpinned empref = rs->getRef(1); Oracle C++ Call Interface(OCCI) 44 012 OCCI – Modifying/Deleting objects – Example //fetch initial REF using SQL Statement *stmt = conn->createStatement(“Select Ref(a) From EmpTab a”); ResultSet *rs = stmt->executeQuery(); rs->next(); //fetch the Ref Ref<EmployeeT> empref = rs->getRef(1); //to modify a object, change attributes using set methods empref->setSalary(newsal);//pin and modify object //call markModified() method to indicate to OCCI/cache empref->markModified(); //Modified object will be written to database on commit conn->commit(); //to delete a object, call markDelete on Ref or pinned object empref.markDelete(); //or empref->markDelete(); Oracle C++ Call Interface(OCCI) 45 OCCI – Creating new persistent objects OTT generates a overloaded new operator in each class :void *operator new(size_t size, const oracle::occi::Connection * sess, const string& table); Use the new operator to create persistent objects in a database table :EmployeeT *newemp = new (conn, “SCOTT.EMPTAB”) EmployeeT() Set attribute values of the new object Object is saved in database when commit is done New object will be managed by client cache after commit Oracle C++ Call Interface(OCCI) 46 OCCI – Creating persistent object - Example Connection *conn = env->createConnection(“scott”,”tiger”); //EmployeeT class generated by OTT for type Employee //EMPTAB is object table of type Employee EmployeeT *newemp = new (conn, “SCOTT.EMPTAB”) EmployeeT(); newemp->setEmpno(1000); newemp->setEmpname(“JOHN W”); //use OCCI Date class Date hdate(env, 1, 1, 2003); newemp->setHiredate(hdate); //object will be saved in database on commit conn->commit(); //to get REF of object, use getRef() Ref <EmployeeT> = newemp->getRef(); Oracle C++ Call Interface(OCCI) 47 OCCI – Objects – Associative Access Use SQL to create and fetch object values Can be used with object tables or with object type columns - create type DepartmentT; - create table DeptTab of DepartMentT; -- object table - create table Region (…., Dept DepartmentT, …); -- object type column Objects are not managed by cache since they are transient Extensive support for collections Easy way of using Oracle Object-Relational features Oracle C++ Call Interface(OCCI) 48 OCCI – Associative Access – Examples Insert into a object table Statement *stmt = conn->createStatement(“ insert into DeptTab values (:1) ”); DepartmentT *dept = new DepartmentT();//create transient instance //set values into dept members dept->setDeptNo(1); dept->setDeptName(“HR”); stmt->setObject(1, dept); stmt->executeUpdate(); Insert into a table with object type column Statement *stmt = conn->createStatement(“ insert into Region(Area, Dept) values (:1, :2) ”); stmt->setString(1, “North”); DepartmentT *dept = new DepartmentT();//create transient instance //set values into dept members stmt->setObject(2, dept); stmt->executeUpdate(); Oracle C++ Call Interface(OCCI) 49 OCCI – Associative Access – Examples Selecting a object value Statement *stmt = conn->createStatement(“select value(a) from DeptTab a”); //or “select dept from Region” ResultSet *rs = stmt->executeQuery(); rs->next();//fetch DepartmentT *dept = rs->getObject(1); //access dept members cout << dept->getDeptNo() << endl; cout << dept->getDeptName() << endl; Oracle C++ Call Interface(OCCI) 50 OCCI – Collections Oracle provides VARRAY and Nested Table data types for modeling a set/list of values of a type OCCI uses the C++ STL vector class for representing varray and nested table of any type :- Database type : create type PhoneList as varray(50) of varchar2(100) OCCI representation : vector< string > - Database type : create type Addresses as table of Address OCCI representation : vector< AddressT * > vector<T> can be used in relational/associative or navigational access :- Relational/Associative access :- Statement IN/OUT binds and ResultSet fetch - Navigational access : Attributes of object types Oracle C++ Call Interface(OCCI) 51 OCCI – Collections – Relational access setVector and getVector interfaces on Statement and ResultSet for inserting/fetching data from varray/nested table columns Comprehensive support for collections of all Oracle data types ://to insert/pass a collection - void setVector(Statement *stmt, unsigned int column, const vector<T> &vect, const string &sqltype) ; //to get a PL/SQL OUT param/result of collection type - void getVector( Statement *rs, unsigned int column, vector<T> &vect) ; //to fetch a collection column - void getVector(ResultSet *rs, unsigned int column, vector<T> &vect) ; ‘T’ can be any type : int/Number/Date/Blob/string/PObject */Ref<T> … Oracle C++ Call Interface(OCCI) 52 OCCI – Collections – Example Insert into a VARRAY column -- create type PhoneList as varray(50) of varchar2(100); -- create table customer(cname varchar2(100), cphones PhoneList); Statement *stmt = conn->createStatement (“ insert into Customer values (:1, :2) “); stmt->setString (1, “JOHN W”); //add 3 phone numbers vector<string> phonenos; phonenos.push_back(“111-222-3333”); phonenos.push_back(“447-555-2323”); phonenos.push_back(“575-232-5885”); //setVector(Statement *, int col, vector<T> &val, string dbtype) setVector(stmt, 2, phonenos, “SCOTT.PHONELIST”); stmt->executeUpdate(); Oracle C++ Call Interface(OCCI) 53 OCCI – Collections – Example Selecting a VARRAY column -- create type Marks as varray(50) of Number; -- create table student(cname varchar2(100), cphones PhoneList); Statement *stmt = conn->createStatement (“ select * from customer“); ResultSet *rs = stmt->executeQuery(); while (rs->next()) { cout << “customer name : “ << rs->getString(1); vector<string> phonenos; getVector(rs, 2, phonenos); for (int i = 0; i < phonenos.size(); i++) cout << phonenos[i] << “,”; } Oracle C++ Call Interface(OCCI) 54 OCCI – Collections – Objects support VARRAY and Nested table types can be used as attribute types of objects In the OTT generated C++ class, collection type attributes are declared as vector<T> type members create type PhoneNumbersType as varray(10) of varchar2(20); create type Customer as object (… PhoneNumbers PhoneNumbersType; ) OTT class :class CustomerT : public oracle::occi::PObject { private: vector< string > PHONENUMBERS; Oracle C++ Call Interface(OCCI) 55 OCCI – MetaData access Dynamically discover the attributes(e.g name,type,size, count) of database objects(e.g tables,procedures,types) and query results MetaData class and its getXXX methods provide extensive attribute information of database objects and query result columns Use Connection::getMetaData() and ResultSet::getColumnListMetaData() to retrieve needed MetaData objects Oracle C++ Call Interface(OCCI) 56 OCCI – MetaData access – Examples MetaData of a schema object //Connection::getMetaData(string &object, ParamType ptype) //ptype = PTYPE_TABLE/PTYPE_VIEW etc or PTYPE_UNK MetaData md = conn->getMetaData(“EMP”, PTYPE_UNK); //ATTR_OBJ_PTYPE returns PTYPE_TABLE/PTYPE_VIEW … int objectType = md.getInt(MetaData::ATTR_OBJ_PTYPE); int columnCount = md.getInt(MetaData::ATTR_OBJ_NUM_COLS); Timestamp objts = md.getTimestamp(MetaData::ATTR_TIMESTAMP); vector<MetaData> cols = md.getVector(MetaData::ATTR_LIST_COLUMS); //each MetaData in the vector is for 1 column cout << “column 1 name = “ << cols[0].getString(MetaData::ATTR_NAME); Oracle C++ Call Interface(OCCI) 57 OCCI – MetaData Access - Examples MetaData of a ResultSet Statement *stmt = conn->createStatement(“select * from emp”); ResultSet *rs = rs->executeQuery(); //each element in the vector<> is a column vector<MetaData> selectcols = rs->getColumnListMetaData(); int columnCount = selectcols.size(); for (int i = 0; i < columnCount; i++) { cout <<“column name“<<selectcols[i].getString(MetaData::ATTR_NAME); cout <<“column type”<<selectcols[i].getInt(MetaData::ATTR_DATA_TYPE); } Oracle C++ Call Interface(OCCI) 58 OCCI – Scalability features Connection pooling Stateless Connection pooling(10i) Statement caching(10i) Thread safety Oracle C++ Call Interface(OCCI) 59 OCCI – Connection pooling Use a small group of physical connections to support many user sessions Saves on connection time and server-side processes & resources Oracle dynamically selects one of the free connections to execute a statement, and then releases the connection to the pool immediately after the execution Support for proxy connections through the connection pool owner Suited for middle-tier, multi-threaded applications that need to handle many users Oracle C++ Call Interface(OCCI) 60 OCCI – Connection pooling – Usage To create a connection pool :ConnectionPool* Environment::createConnectionPool( const string &poolUserName, const string &poolPassword, const string &connectString ="", unsigned int minConn=0,unsigned int maxConn=1, unsigned int incrConn=1) Maximum connections, minimum connections, increment can be reconfigured after the pool has been created Getting a connection from the pool :Connection* ConnectionPool::createConnection( const string &userName, const string &password) Releasing a connection to the pool :void ConnectionPool::terminateConnection(Connection *conn); A Connection will be automatically released if it has been idle for the timeout value specified by setTimeOut Oracle C++ Call Interface(OCCI) 61 OCCI – Connection pooling – Other interfaces To create proxy connections :- Connection* ConnectionPool::createProxyConnection(cont string &name, Connection::ProxyType proxyType = Connection::PROXY_DEFAULT); - Connection* ConnectionPool::createProxyConnection(const string &name, string roles[], int numRoles, Connection::ProxyType proxyType = Connection::PROXY_DEFAULT); Get number of open/busy connections in the pool - int ConnectionPool::getOpenConnections(); - int ConnectionPool::getBusyConnections(); Reconfigure the pool min/max/incr connections - void ConnectionPool::setPoolSize(int minConn, int maxConn, int incr) Oracle C++ Call Interface(OCCI) 62 OCCI – Connection Pool – Example //Create a connection pool, max connections = 10, //min connections = 4, increment connections = 2 ConnectionPool *appPool = env->createConnectionPool(“app1”, ”app1”, “”, 4, 10, 2); //get a connection from the pool Connection *conn = appPool->createConnection(“scott”,”tiger”); //database access – use the Connection object .. .. //release connection to pool appPool->terminateConnection(conn); Oracle C++ Call Interface(OCCI) 63 OCCI – Thread Safety Multiple threads in a application improve performance and response times Multiple threads can make OCCI calls concurrently OCCI classes : Environment, Connection, ConnectionPool are thread-safe. Statement, ResultSet … are not thread-safe, multiple threads should not operate on the same object simultaneously Either application or OCCI can handle serialization for threadsafe objects, by specifying mode in createEnvironment :THREADED_MUTEXED – OCCI manages serialization(using mutexes) THREADED_UNMUTEXED – Application manages serialization Oracle C++ Call Interface(OCCI) 64 OCCI – New features in 10i Advanced Queuing Globalization and Unicode XA support Stateless connection pooling Statement caching IEEE float and double datatypes Oracle C++ Call Interface(OCCI) 65 OCCI – Advanced Queuing Database integrated message queuing for enterprise applications OCCI provides classes and interfaces for applications to create, send, receive, and access messages Access queues of Raw, AnyData, Object types Numerous options for messages, enqueue and dequeue. E.g : priority, recipient list, dequeue mode, listen etc Integrate messaging, object and relational access in a single application Oracle C++ Call Interface(OCCI) 66 OCCI – AQ Classes Queue user Oracle C++ Call Interface(OCCI) 67 Data + options Read Message Send Message Wait for messages OCCI – AQ – Examples Enqueue/Dequeue RAW messages //instantiate a Message object Message msg(conn); //a Agent identifies a Queue user – consumer/producer vector<Agent> receiveList; //construct a Bytes object char msgstring[] = “ABCDE”; Bytes rawBytes(msgstring, strlen(msgstring); //set Bytes as message payload msg.setBytes(rawBytes); //instantiate a Producer Producer prod(conn); prod.send(msg, “QUEUE1”);//enqueue the message //now dequeue Consumer cons(conn); Message msg2 = cons.receive(“QUEUE1”, “RAW”, “SYS”); Oracle C++ Call Interface(OCCI) 68 OCCI – AQ – Examples Enqueue/Dequeue AnyData messages //AnyData class is for generic data AnyData any1(conn); any1.setFromString(“STRING MSG”);//use setFromXXX methods Message msg; msg.setAnyData(any1);//set AnyData as payload prod.send(msg, “ANYQUEUE”);//enqueue any1.setFromDate(dt);//dt is of type Date msg.setAnyData(any1);//now set Date as the payload prod.send(msg, “ANYQUEUE”);//same queue //dequeue Message msg2; msg2 = cons.receive(“ANYQUEUE”,”ANYDATA”,”SYS”);//dequeue //get value AnyData msgany = msg2.getAnyData(); string stringmsg = msgany.getAsString();//use other getAsXXX Oracle C++ Call Interface(OCCI) 69 OCCI – AQ – Examples Enqueue/Dequeue Object Type messages //construct transient instance of object OrderT *neworder = new OrderT();//OrderT is OTT generated class //set attributes neworder->setOrderDate(…); … //set object as Message payload Message newmessage(conn); newmessage.setObject(neworder); //enqueue prod.send(newmessage, “ORDERSQUEUE”); //now dequeue Message recv = cons.receive(“ORDERSQUEUE”, “ORDERTYPE”, “SCOTT”); //get the object from the message OrderT *processorder = (OrderT *)recv.getObject(); Oracle C++ Call Interface(OCCI) 70 OCCI – Globalization & Unicode Supports multibyte charactersets(including UTF8) and Unicode (UTF16) characterset for application development Applications can specify client characterset and national characterset when the Environment is initialized Environment *Environment::createEnvironment(string charset, string ncharset) Client characterset is for all SQL statements, schema elements & data for all CHAR types. National characterset is for data of all NCHAR types New datatype UString represents Unicode data in UTF16, each character is 2 bytes Use existing string interfaces for multibyte data Oracle C++ Call Interface(OCCI) 71 OCCI – Unicode Interfaces All string interfaces have new equivalent UTF16 interfaces that take/return Ustring. E.g :- Statement::setUString(int col, UString &value) - UString ResultSet::getUString(int col) - Environment::createConnection(UString &user, UString &password, UString &dbname) - Statement::execute(UString &sqlquery) - getVector( ResultSet *rs, unsigned int index, vector<UString> &vect) In Windows platforms, UString is equivalent to Standard C++ wstring datatype OTT generates CHAR/VARCHAR attributes as UString type member variables for a Unicode application Oracle C++ Call Interface(OCCI) 72 OCCI – Globalization support – Examples Specifying client application charactersets //OCCIUTF16 Environment Environment Environment is for indicating UTF16 characterset *env1 = Environment::createEnvironment(“WE8DEC”,”OCCIUTF16”); *env2 = Environment::createEnvironment(“JA16SJIS”,”JA16SJIS”); *env3 = Environment::createEnvironment(“ZHT16BIG5”,”UTF8”); //complete Unicode application :Environment *env4 = Environment::createEnvironment(“OCCIUTF16”,”OCCIUTF16”); Binding UTF16 data(UString) //client national characterset is OCCIUTF16 //for column types NCHAR/NVARCHAR, call setDatabaseNCHARParam(col,true) stmt->setDatabaseNCHARParam(3, true); //the 2 Katakana Unicode characters for 'Japan' in japanese unsigned short japanunicodechars[] = {0x65E5,0x672C}; UString uJapan(japanunicodechars, 2); stmt->setUString(3, uJapan);//binding UTF16 string Oracle C++ Call Interface(OCCI) 73 OCCI – Globalization Support - Examples Using wstring in Windows //complete Unicode application Environment *env = Environment::createEnvironment(“OCCIUTF16”,”OCCIUTF16”); //wstring datatype is same as UString in Windows wstring wusername = L”scott”;//’L’ creates Unicode string wstring wpassword = L”tiger”; Connection *conn = env->createConnection(wusername, wpassword, L””); //create a Statement with Unicode query //this will call Connection::createStatement(UString *sql) Statement *stmt = conn->createStatement(L”Select * From …”); //bind wstring wstring name = //from input terminal stmt->setUString(1, name); Oracle C++ Call Interface(OCCI) 74 OCCI – XA Support Oracle XA conforms to X/Open DTP standard for transaction monitors(TM) Application uses TM for connecting to multiple, distributed ‘resources’ and transaction control(2-phase commit) OCCI interfaces for getting the underlying Oracle Environment & Connection in a XA application The Environment & Connection object can then be used as in a typical application for further database access Oracle C++ Call Interface(OCCI) 75 OCCI – XA Application Architecture Uses OCCI Oracle C++ Call Interface(OCCI) 76 OCCI – XA Support – Interfaces Get/release Oracle environment - Environment *Environment::getXAEnvironment(const string &dbname) - void Environment::releaseXAEnvironment(Environment *env) Get/release Oracle connection - Connection *Environment::getXAConnection(const string &dbname) - void Environment::releaseXAConnection(const string &dbname) Check if a error(exception) is in XA or Oracle - int SQLException::getXAErrorCode(const string &dbname) dbname is the xa_open string specified by the application to the TM to connect to Oracle Oracle C++ Call Interface(OCCI) 77 OCCI – XA Support – Example //define the db open string according to Oracle XA specification string xaopen_str = "oracle_xa+ACC=P/SCOTT/TIGER+SESTM=50+logdir=.+SqlNet=inst1"; //connect to database and other ‘resources’ using TM interfaces tx_open(); //to manipulate data need access to Connection Environment *xaenv = Environment::getXAEnvironment(xaopen_str); Connection *xaconn = xaenv->getXAConnection(xaopen_str); //access database – use SQL etc tx_begin();//TM call Statement *stmt = xaconn->createStatement(“Update Emp..”); stmt->executeUpdate(); //for transaction control use TM calls, not Oracle calls tx_commit(); //release Connection & Environment xaenv->releaseXAConnection(xaconn); Environment::releaseXAEnvironment(xaenv); Oracle C++ Call Interface(OCCI) 78 OCCI – Stateless Connection Pooling Maintain a pool of open, authenticated user connections No roundtrip for authentication, connection is ready to be used when got from pool Connections are ‘stateless’, applications should not leave open transactions Connections can be ‘tagged’ with a descriptive name and then retrieved using tag Support for proxy connections through the connection pool owner Oracle C++ Call Interface(OCCI) 79 OCCI – Stateless Connection Pooling – II Suited for middle-tier, multi-threaded applications that do short database access Stateless Connection pool can be HOM0GENOUS – All connections with same user HETEROGENOUS – Connections can have different user/proxy OCCI will not do commit/rollback, user’s responsibility to not leave any ‘state’ when connection is released Interfaces similar to ConnectionPool Oracle C++ Call Interface(OCCI) 80 OCCI – Stateless Connection Pool – Examples Homogenous ConnectionPool StatlessConnectionPool *spool = Environment::createStatelessConnectionPool(“scott”, “tiger”, “”, 10, 4, 2, HOMOGENOUS);//MaxConn=10, MinConn=4, IncrConn=2 //get a connection from the pool Connection *conn = spool->getConnection(); //use Connection as earlier Statement *stmt = conn->createStatement(“alter session set Nls_Language=‘French’”); … //release Connection with tag spool->releaseConnection(conn, “FR”); //get Connection with tag Connection *conn2 = spool->getConnection(“FR”); //destroy pool env->terminateConnectionPool(spool); Oracle C++ Call Interface(OCCI) 81 OCCI – Stateless Connection Pool - Examples Heterogenous ConnectionPool StatlessConnectionPool *spool = Environment::createStatelessConnectionPool(“scott”, “tiger”, “”, 10, 4, 2, HETEROGENOUS);//MaxConn=10, MinConn=4, IncrConn=2 //get a connection from the pool with a different user Connection *conn = spool->getConnection(“acme”, “acme”); //use Connection as earlier Statement *stmt = conn->createStatement(“Select * From Emp”); … //release Connection without tag spool->releaseConnection(conn); //get Connection again Connection *conn2 = spool->getConnection(“acme”, “acme”); //get Proxy Connection Connection *conn3 = spool->getProxyConnection(“proxyuser1”); //destroy pool env->terminateConnectionPool(spool); Oracle C++ Call Interface(OCCI) 82 OCCI – Statement Caching Cache and reuse frequently executed SQL statements In the server, cursors are ready to be used without the need to parse the statement again Client-side resources and data structures are effectively reused Statements can be ‘tagged’ with a descriptive name and then retrieved from the cache by tag Works with connection pooling and stateless connection pooling Oracle C++ Call Interface(OCCI) 83 OCCI – Statement Caching – Usage Enable statement caching on a Connection :- Connection::setStmtCacheSize(unsigned int stmtCacheSize) On createStatement, the cache will be searched for statement. If not found, then a new statement is created On terminateStatement(with optional tag), the statement will be added to cache On next createStatement, the statement will be got from the cache Oracle C++ Call Interface(OCCI) 84 OCCI – Statement Caching – Example //enable statement caching conn->setStmtCacheSize(10); //get cache size int csize = conn->getStmtCacheSize(); //create a statement Statement *stmt = conn->createStatement(sqlquery); //release the statement to cache with tag conn->terminateStatement(stmt, “tagA”); //retrieve statement again with SQL or tag stmt = conn->createStatement(sqlquery); //Or stmt = conn->createStatement(“”,”tagA”); Oracle C++ Call Interface(OCCI) 85 OCCI – Interoperability with OCI OCCI is designed and implemented on top of OCI Underlying OCI ‘handles’ of database access classes can be retrieved :- OCIEnv *Environment::getOCIEnv() OCIServer *Connection::getOCIServer() OCISvcCtx *Connection::getOCIServiceContext() OCISession *Connection::getOCISession() OCIStmt *Statement::getOCIStatement() Handles can be used when migrating and reusing existing OCI code OCI ‘C’ code for relational access can be mixed in a OCCI application OCI objects interfaces cannot be used in OCCI application Oracle C++ Call Interface(OCCI) 86 OCCI – OCI Interoperability – Examples //get OCI Environment & Service Context OCIEnv *ocienv = env->getOCIEnv();//env is OCCI Environment OCISvcCtx *ocisvc = conn->getOCISvcCtx();//conn is Connection //use OCI calls OCIHandleAlloc(ocienv, &dpctx, OCI_HTYPE_DIRPATH_CTX,…); //do more OCI stuff DoDirectPathLoad(ocienv, ocisvc, dpctx, …); //reuse of existing code Statement *stmt = conn->createStatement(“Select * From Emp”); ResultSet *rs = stmt->executeQuery(); //display MetaData using existing C function OCIStmt *stmthp = stmt->getOCIStmt(); DisplayMetaDataInGUI(stmthp); //do not use OCIObject* calls Oracle C++ Call Interface(OCCI) 87 OCCI – Performance Tuning Relational access - Use iterative DML execution to reduce roundtrips Scalability - Use Stateless Connection pooling to get authenticated connections - Use Connection pooling to use less number of physical connections Objects access & navigation - Complex Object Retrieval for prefetching related objects - Tune the object cache Oracle C++ Call Interface(OCCI) 88 OCCI – Complex Object Retrieval(COR) Object oriented applications model their data as a set of interrelated objects to form graphs (using REFs) PurchaseOrder Cust REF Customer; RelatedOrder REF PurchaseOrder; LineItems LineItemRefArray Customer PurchaseOrder LineItem 1 LineItem 2 Performance of such models can be increased using COR to prefetch a set of linked objects in a single network trip Prefetch attributes(type and depth) are specified on the ‘root’ Ref<T>. When the root is pinned, linked objects are also fetched - Ref<T>::setPrefetch(const string &typeName, unsigned int depth); - Ref<T>::setPrefetch(unsigned int depth); Oracle C++ Call Interface(OCCI) 89 OCCI – COR – Example //OTT class ://class PurchaseOrder : { // Date OrderDate; // Ref <Customer> Customer; // Ref <PurchaseOrder> RelatedOrder; // vector < Ref<LineItem> > LineItems; } Ref<PurchaseOrder> poref; //set COR prefetching to get Customer object also poref.setPrefetch(“Customer”, 1); Date odate = poref->getOrderDate();//this will fetch & pin PO //the linked Customer object will also now be in the cache Ref<Customer> cust = poref->getCustomer(); string cname = cust->getName();//no round-trip //to get all linked objects at depth 1 – customer, related //purchase order, line items :poref.setPrefetch(1); Oracle C++ Call Interface(OCCI) 90 OCCI – Tuning object cache The cache is configured by optimal size and maximum size(%) parameters :- Maximum cache size = optimal size + (optimal size * maximum size/100) - Environment::setCacheOptSize(), Environment::setCacheMaxSize() For C++ datatype attributes(string, vector<T>), the memory comes from C++ heap Size the cache according to application needs Consider periodic flushes of objects instead of sending all objects at commit - ref->flush() Oracle C++ Call Interface(OCCI) 91 OCCI – In closing… Natural interface to Oracle object features C++ and object oriented paradigm for better productivity and quality Simple and easy to use for relational access References :Oracle C++ Call Interface Programmer’s Guide Oracle Application Developer’s Guide – Object-Relational Features OTN Discussion forums – otn.oracle.com Oracle C++ Call Interface(OCCI) 92 Demo and Q&A Oracle C++ Call Interface(OCCI) 93