930 likes | 1.58k Views
ORACLE C++ CALL INTERFACE(OCCI) Shankar Iyer, Oracle India. OCCI – Today’s Agenda. Session I - Introduction - SQL/PLSQL Execution - Data classes Session II - Object Features - MetaData access. Session III - Scalability Features - 10i features Session IV - Interoperability with OCI
E N D
ORACLE C++ CALL INTERFACE(OCCI) Shankar Iyer, Oracle India. Oracle C++ Call Interface(OCCI)
OCCI – Today’s Agenda • Session I - Introduction - SQL/PLSQL Execution - Data classes Session II - Object Features - MetaData access • Session III - Scalability Features - 10i features Session IV - Interoperability with OCI - OCCI Performance Tuning - Demo application - Q & A Oracle C++ Call Interface(OCCI)
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)
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)
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)
OCCI – Building an application Application source files (use OCCI API and classes) OCCI API header files OTT generated C++ class headers C++ compiler OTT generated C++ class implementations OCCI header files • occi.h • occiCommon.h • occiControl.h • occiData.h • occiObjects.h OCCI library • libocci.so/libocci.a/oraocci9.dll OCCI library (static or dynamic) Linker Application Oracle C++ Call Interface(OCCI)
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)
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)
OCCI – Control classes Environment Create Create Create ConnectionPool Connection StatelessConnectionPool Get Get Get Create MetaData Statement Get Execute ResultSet Oracle C++ Call Interface(OCCI)
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)
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)
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 methodsof Statement & ResultSet • Data type conversions automatically handled by OCCI Oracle C++ Call Interface(OCCI)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
OCCI – Data classes • Classes for using Oracle data types • Easy to use with comprehensive functionality • Used with Statement and ResultSet to insert/fetch values of these types Oracle C++ Call Interface(OCCI)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
OCCI – OTT – Data type mappings Oracle C++ Call Interface(OCCI)
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)
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)
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)
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)
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)
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)
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)
OCCI – Object cache – Example Ref<EmployeeT> empref = rs->getRef(1) //fetch and pin object string ename = empref->getName() Oracle Database //pass to another function by value //pin count increases by 1 PrintEmployee(empref); Client Object Cache 0 1 1 2 //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)
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)
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)
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)
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)
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)
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)