ORAC++©  is a shared C++ class library developed for Oracle8i (Release 2) on Linux (Red Hat 8.0).
It serves as an C++ interface to Oracle OCI package.

To use ORAC++, programs have to be compiled using standard GNU C++ compiler and linked with ORAC++ library and Oracle client shared library (created at Oracle build time).

This document describes basic features of ORAC++. For more detailed description, please see the following documents (in Word format): ORAC++ User Documentation, ORAC++ Programming Examples and ORAC++ Additional Features.

ORAC++ provide a quick and easy way to write programs to select, insert, update and delete records from a table. It also works with joins, views, stored procedures, functions and packages. ORAC++ can be regarded as an excellent tool for writing quick reports, with its formatting capabilities.

Being closely connected to Oracle-specific SQL and SQL*Plus makes it extremely easy for Oracle developer to write small ( by number of code lines ) and efficient C++ programs.

All Oracle basic data types are supported including CLOB and BLOB. ORAC++ makes also use of SQL set operators like union, intersect, minus and outer-joins. To improve SQL performance Oracle hints can also be used.

A full reusability of created objects allows to minimize effort needed to write even most complicated programs. Integrated error checking allows programmer to identify any problems without writing additional lines of code. ORAC++ library also supports multithreaded processing.
 
To illustrate, how easy is to write program with ORAC++ let's take a look at the following example of a SQL statement:
 
       select prod_id, prod_desc, prod_price
       from products
       where prod_id = 100001;
 
Below is a full listing of corresponding C++ program using ORAC++:
 
#include <orac_lib.h>
int main()
{
        Connect c;
        try  {
                Database d = c.OpenDatabase("scott", "tiger");
                Table tb = d.GetTable("products");
                Select sel(tb);
                sel << tb["prod_id"]                                  // select prod_id,
                      << tb["prod_desc"]                             // prod_desc,
                      << tb["prod_price"];                           // prod_price from products
                sel >> tb["prod_id"] == 100001;                 // where prod_id = 100001
                while (sel.Row())         {
                        sel << prod_id << prod_name << prod_price;
                        cout << prod_id << prod_name << prod_price << endl;
                }
                d.Close();
        }
        catch (OException& e)  {
                cout << e << endl;
        }
        catch (...)  {
                cout << "Error ..." << endl;
        }
        return 0;
}
 
Let's assume now, that we want to write C++ program which corresponds to a SQL statement:
 
        select * from products
        where prod_id = 100001;
 
Listing of the C++ program using default (Line) output is shown below (code within try block):
 
        Database d = c.OpenDatabase("scott", "tiger");
        Table t = d.GetTable("products");
        Select s(t);                                              // select * from products
        s >> t["prod_id"] == 100001;                       // where prod_id = 100001        
        while (s.Row())
                cout << s;                                       // display Line (default) formatted Select
 
The program (when run against test data) will produce output:
 
PROD_ID    PROD_DESC                 PROD_PRICE               PROD_TYPE
 
100001       BOOKSHELF                             108.5                                3
 
If we call AsRecord() function:
 
        s.AsRecord()                
        while (s.Row())
                cout << s;
 
all data will be displayed in the following way:
 
                          PROD_ID : 100001
                    PROD_DESC : BOOKSHELF
                    PROD_PRICE : 108.5
                      PROD_TYPE : 3
 
Data from the fetched row can be also loaded directly into output variables:
 
        Select s(t);                                                // select * from products
        s >> t["prod_id"] == 100001;                       // where prod_id = 100001
        while (s.Row())         {
                s << id << desc;                                // load in a table columns order
                cout << "ID = " << id << endl;
                cout << "DESC = " << desc << endl;
        }
 
Let's consider now a SQL join statement:
 
        select products.prod_desc,
        products.prod_price,
                      orders.ord_id,
                orders.ord_date,
                      orders.ord_qty,
                      product_types.type_desc
        from products, orders, product_types
        where products.prod_id = orders.prod_id
        and product_types.type_id = products.prod_type
        and products.prod_desc = BREAD
        and orders.ord_qty = 20;
 
A corresponding C++ program using ORAC++ will look as follows
(code within try block is shown only):
 
        Database d = c.OpenDatabase("scott", "tiger");
        Table tb = d.GetTable("products");
        Table tc = d.GetTable("orders");
        Table td = d.GetTable("product_types");
 
        Select sel(tb);                // create join of three tables
        sel += tc;
        sel += td;
        sel << tb["prod_desc"] << tb["prod_price"]
                        << tc["ord_id"] << tc["ord_date"]
                        << tc["ord_qty"] << td["type_desc"];
        sel >> tb["prod_id"] == tc["prod_id"];
        sel >> and_ >> td["type_id"] == tb["prod_type"];
        sel >> and_ >> tb["prod_desc"] == "BREAD";
        sel >> and_ >> tc["ord_qty"] == 20;
 
        sel.AsRecord();                // use Record display
        while(sel.Row())
                cout << sel;
 
The program (using test data) will create output:
 
                    PROD_DESC : BREAD
                   PROD_PRICE : 1.35
                    ORD_ID : 20003214
                    ORD_DATE : 13-MAR-00
                    ORD_QTY : 20
                    TYPE_DESC : FOOD
 
Above program examples demontstrated use of Select class. It is worth noting, that is possible to use formats on selected and query columns. The format must be entered after column name using convention : column('format') if numeric/date or column('size') if varchar2.
 
        tb["prod_id('000999')"]                                                // column type number(n)
        tb["prod_price('$99999.99')"]                                       // column type number(n,p)
        tc["ord_date('DD/MM/YY HH24:MI:SS')"]                       // column type date
        tb["prod_desc('15')"]                                                    // set column size to 15
       
All Oracle defined formats are supported. Sometimes there is a need to use a  sub-queries within a program. Example below, demonstrates use of SQL sub-query in a C++ program using ORAC++ (only code within try block shown):
 
        Database d = c.OpenDatabase("scott", "tiger");
        Table tb = d.GetTable("product_types");
        Table tc = d.GetTable("products");
        Select sel(tb);
        sel << tb["type_id"] << tb["type_desc"];
        Select sel1(tc);
        sel1 << tc["prod_id"] << tc["prod_desc"] << tc["prod_type"];
        sel1 >> tc["prod_type"] == ":";                     // (1) placeholder here
 
        while(sel.Row())  {
                sel << type_id << desc;
                cout << " (outer)--- " << type_id << ":" << desc << endl;
                sel1 >> type_id;                                  // (2) substitute it by type_id
                while (sel1.Row())  {
                        sel1 << id << name << proc_type;
                        cout << "         (inner)--- " << id << ":"
                             << name << ":" << proc_type << endl;
                }
        }

ORAC++ allow to simplify writing programs to insert, update and delete records from the table. To insert rows into the table all we have to write is (try block shown only)
 
        Database d = c.OpenDatabase("scott", "tiger");
        Table t = d.GetTable("products");
        Insert ins(t);
        ins << t["prod_id"] << t["prod_desc"] << t["prod_type"];
        ins >> 100010 >> "TV STAND" >> 2;
        cout <<  ins.Row()  << " rows inserted" << endl;
 
Array insert is also supported. Lets assume that we want to insert an array of 10 records.
A corresponding program code is shown below:
 
        #define ARR 10
        int prod_id[ARR];
        char *prod_desc[ARR];
        int prod_type[ARR];
 
after populating arrays of data, following lines have to be added:
 
        ins << t["prod_id"] << t["prod_desc"] << t["prod_type"];
        ins >> prod_id >> prod_desc >> prod_type;        
        ins.Array(ARR);
        cout <<  ins.Row()  << " rows inserted" << endl;
 
number of rows inserted will be equal to ARR (upon successful insertion).
 
A following program code shows that table update is also very easy task when using ORAC++ ( only code within try block is shown ):
 
        Database d = c.OpenDatabase("scott", "tiger");
        Table t = d.GetTable("products");
        Update upd(t);                                        
        upd << t["prod_desc"] << t["prod_type"];               // updated columns
        upd >> "PRINTER  STAND" >> 2;                        // updated data
        upd >> t["prod_id"] == 100100;                               // where prod_id = 100100
        cout <<  upd.Row()  << " rows updated" << endl;
 
The same simplicity exists in case of deleting records from a table:
 
        Database d = c.OpenDatabase("scott", "tiger");
        Table t = d.GetTable("products");
        Delete del(t);                                                         // delete from products
        del  >> t["prod_id"] == 100001;                           // where prod_id = 100001
        cout << del.Row()  << " rows deleted" << endl;
 
Stored procedures and functions can also be easily accessed and executed using ORAC++. Lets take look at the following Oracle stored procedure:
 
        create or replace procedure p_get_prod_name (
           p_id in number,
           p_name out varchar2)
        is
          cursor c(pid in number) is
          select prod_desc
          from products
          where prod_id = pid;
 
        begin
          open c(p_id);
          fetch c into p_name;
          if c%notfound then
        p_name := not found;
          end if;
          close c;
        end;
 
To access this stored procedure from C++ program using ORAC++ we have to write just a few lines of code (only code within try block is shown):
 
        int id = 100001;
        char *name = new char[30];
        Connect c;
        Database d = c.OpenDatabase("scott", "tiger");
        Procedure p = d.GetProcedure("p_get_prod_name");
        p >> id >> name;        // load all input/output arguments
        p.Execute();
        p << id << name;        // reload all variables
        cout << "product id   :" << id << endl;
        cout << "product desc :" << name << endl;
 
Class Sql allows to process any user entered SQL statement. Program below, shows how Sql class can be used to process select and update statements. (only code within try block is shown).

        int prod_id;
        double price;
        TStr id_str(10), name_str(30), price_str(10);

        Connect c;
        Database d = c.OpenDatabase("scott", "tiger");

        Sql st = d.GetSql("select * from products where prod_id = :1");
        st << id_str << name_str << price_str; // fetch into strings
        st >> 100001;           // bind data

        while (st.Execute())
        {
            st << id_str << name_str << price_str;
            cout << id_str << ":" << name_str << ":" << price_str << endl;
        }

        st = "update products"; // reload Sql object with new statement
        st += "set prod_desc = :1";
        st += "where prod_id = :2";
        st >> "updated description" >> 100001;
        st.Execute();

        st = "select * from products"; // reload Sql object again
        st << prod_id << name_str << price; // fetch into proper data types
        while (st.Execute())
        {
            st << prod_id << name_str << price;
            cout << prod_id << ":" << name_str << ":" << price << endl;
        }

In this brief document only basic features of ORAC++ library of classes were presented.
For detailed description of all features and more programming examples please refer to the following documents: ORAC++ User Documentation, ORAC++ Programming Examples and ORAC++ Additional Features.