OCCI - Oracle

advertisement
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
Download