Skip Headers

Oracle C++ Call Interface Programmer's Guide
Release 2 (9.2)

Part Number A96583-01
Go To Documentation Library
Home
Go To Product List
Book List
Go To Table Of Contents
Contents
Go To Index
Index

Master Index

Feedback

Go to previous page Go to next page

7
How to Use the Object Type Translator Utility

This chapter discusses the Object Type Translator (OTT) utility, which is used to map database object types, LOB types, and named collection types to C structures and C++ class declarations for use in OCCI, OCI, and Pro*C/C++ applications.


Note:

JDK 1.3.1 compatible Java copiler and Java interpreter must be correctly installed.


This chapter includes the following topics:

Overview of the Object Type Translator Utility

The Object Type Translator (OTT) utility assists in the development of applications that make use of user-defined types in an Oracle database server.

Through the use of SQL CREATE TYPE statements, you can create object types. The definitions of these types are stored in the database and can be used in the creation of database tables. Once these tables are populated, an Oracle C++ Call Interface (OCCI), Oracle Call Interface (OCI), or Pro*C/C++ programmer can access objects stored in the tables.

An application that accesses object data must be able to represent the data in a host language format. This is accomplished by representing object types as structures in C or as classes in C++.

You could code structures or classes manually to represent database object types, but this is time-consuming and error-prone. The OTT utility simplifies this step by automatically generating the appropriate structure declarations for C or the appropriate classes for C++.

For Pro*C/C++, the application only needs to include the header file generated by the OTT utility. In OCI, the application also needs to call an initialization function generated by the OTT utility.

For OCCI, the application must include and link the following files:

For C, in addition to creating C structures that represent stored datatypes, the OTT utility also generates parallel indicator structures that indicate whether an object type or its fields are null. This is not the case for C++.

How to Use the OTT Utility

To translate database types to C or C++ representation, you must explicitly invoke the OTT utility. In addition, OCI programmers must initialize a data structure called the Type Version Table with information about the user-defined types required by the program. Code to perform this initialization is generated by the OTT utility

In Pro*C/C++, the type version information is recorded in the OUTTYPE file which is passed as a parameter to Pro*C/C++.

OCCI programmers must invoke the function to register the mappings with the environment. This function is generated by the OTT utility.

On most operating systems, the OTT utility is invoked on the command line. It takes as input an INTYPE file, and it generates an OUTTYPE file and one or more C header files or one or more C++ header files and C++ method files. An optional implementation file is generated for OCI programmers. For OCCI programmers, an additional C++ methods file to register mappings is generated along with its corresponding header file containing the prototype.

Example for C

The following example is of a command line that invokes the OTT utility and generates C structs:

ott userid=scott/tiger intype=demoin.typ outtype=demoout.typ code=c hfile=demo.h

This command causes the OTT utility to connect to the database with username scott and password tiger, and to translate database types to C structures, based on instructions in the INTYPE file, demoin.typ. The resulting structures are output to the header file, demo.h, for the host language (C) specified by the code parameter. The OUTTYPE file, demoout.typ, receives information about the translation.

Each of these parameters is described in more detail in later sections of this chapter.

Sample demoin.typ and demoout.typ files

This is an example of a demoin.typ file:

CASE=LOWER
TYPE employee

This is an example of a demoout.typ file:

CASE = LOWER
TYPE SCOTT.EMPLOYEE AS employee
   VERSION = "$8.0"
   HFILE = demo.h

In this example, the demoin.typ file contains the type to be translated, preceded by the keyword TYPE. The structure of the OUTTYPE file is similar to the INTYPE file, with the addition of information obtained by the OTT utility.

Once the OTT utility has completed the translation, the header file contains a C structure representation of each type specified in the INTYPE file, and a null indicator structure corresponding to each type.

Let us assume the employee type listed in the INTYPE file is defined as follows:

CREATE TYPE employee AS OBJECT
(
   name       VARCHAR2(30),
   empno      NUMBER,
   deptno     NUMBER,
   hiredate   DATE,
   salary     NUMBER
);

The header file, demo.h, generated by the OTT utility includes, among other items, the following declarations:

struct employee
{
   OCIString * name;
   OCINumber empno;
   OCINumber deptno;
   OCIDate   hiredate;
   OCINumber salary;
};
typedef struct emp_type emp_type;

struct employee_ind
{
   OCIInd _atomic;
   OCIInd name;
   OCIInd empno;
   OCIInd deptno;
   OCIInd hiredate;
   OCIInd salary;
};
typedef struct employee_ind employee_ind;


Note:

Parameters in the INTYPE file control the way generated structures are named. In this example, the structure name employee matches the database type name employee. The structure name is in lowercase because of the line CASE=lower in the INTYPE file.


See Also:

"OTT Utility Datatype Mappings" for more information about types.

Example for C++

The following example is of an OTT command that invokes the OTT utility and generates C++ classes:

ott userid=scott/tiger intype=demoin.typ outtype=demoout.typ code=cpp 
hfile=demo.h cppfile=demo.cpp mapfile=RegisterMappings.cpp

This command causes the OTT utility to connect to the database as username scott with password tiger, and use the demoin.typ file as the INTYPE file, and the demoout.typ file as the OUTTYPE file. The resulting declarations are output to the file demo.h in C++, specified by the CODE=cpp parameter, the method implementations written to the file demo.cpp, and the functions to register mappings is written to RegisterMappings.cpp with its prototype written to RegisterMappings.h.

By using the same demoin.typ file and employee type as in the previous section, the OTT utility generates the following files:

The contents of these files are displayed in the following sections:

Contents of the demo.h File

#ifndef DEMO_ORACLE
# define DEMO_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif


/************************************************************/
//  generated declarations for the EMPLOYEE object type.
/************************************************************/

class employee : public oracle::occi::PObject {

protected:

   OCCI_STD_NAMESPACE::string name;
   oracle::occi::Number empno;
   oracle::occi::Number deptno;
   oracle::occi::Date hiredate;
   oracle::occi::Number salary;

public:

   void *operator new(size_t size);

   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);

   OCCI_STD_NAMESPACE::string getSQLTypeName() const;

   employee();

   employee(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };

   static void *readSQL(void *ctxOCCI_);

   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);

   static void writeSQL(void *objOCCI_, void *ctxOCCI_);

   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);

};

#endif

Contents of the demo.cpp File

#ifndef DEMO_ORACLE
# include "demo.h"
#endif


/*****************************************************************/
//  generated method implementations for the EMPLOYEE object type.
/*****************************************************************/

void *employee::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *employee::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.EMPLOYEE");
}

OCCI_STD_NAMESPACE::string employee::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.EMPLOYEE");
}

employee::employee()
{
}

void *employee::readSQL(void *ctxOCCI_)
{
  employee *objOCCI_ = new employee(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void employee::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   name = streamOCCI_.getString();
   empno = streamOCCI_.getNumber();
   deptno = streamOCCI_.getNumber();
   hiredate = streamOCCI_.getDate();
   salary = streamOCCI_.getNumber();
}

void employee::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  employee *objOCCI_ = (employee *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void employee::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setString(name);
   streamOCCI_.setNumber(empno);
   streamOCCI_.setNumber(deptno);
   streamOCCI_.setDate(hiredate);
   streamOCCI_.setNumber(salary);
}

Contents of the RegisterMappings.h File

#ifndef REGISTERMAPPINGS_ORACLE
# define REGISTERMAPPINGS_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif

#ifndef DEMO_ORACLE
# include "demo.h"
#endif

void RegisterMappings(oracle::occi::Environment* envOCCI_);

#endif

Contents of the RegisterMappings.cpp File


#ifndef REGISTERMAPPINGS_ORACLE
# include "registermappings.h"
#endif

void RegisterMappings(oracle::occi::Environment* envOCCI_)
{
  oracle::occi::Map *mapOCCI_ = envOCCI_->getMap();
  mapOCCI_->put("SCOTT.EMPLOYEE", employee::readSQL, employee::writeSQL);
}

Contents of the demoout.typ File

CASE = LOWER
MAPFILE = RegisterMappings.cpp
MAPFUNC = RegisterMappings

TYPE SCOTT.EMPLOYEE AS employee
  VERSION = "$8.0"
  HFILE = demo.h

See Also:

Example for Extending OTT Classes for a complete C++ example.

Creating Types in the Database

The first step in using the OTT utility is to create object types or named collection types and store them in the database. This is accomplished through the use of the SQL CREATE TYPE statement.

The following is an example of statements that create objects:

CREATE TYPE FULL_NAME AS OBJECT (first_name CHAR(20), last_name CHAR(20));
CREATE TYPE ADDRESS AS OBJECT (state CHAR(20), zip CHAR(20));
CREATE TYPE ADDRESS_TAB AS VARRAY(3) OF REF ADDRESS;
CREATE TYPE PERSON AS OBJECT (id NUMBER, name FULL_NAME, curr_addr REF ADDRESS,
   prev_addr_1 ADDRESS_TAB) NOT FINAL;
CREATE TYPE STUDENT UNDER PERSON (school_name CHAR(20));

Invoking the OTT Utility

After creating types in the database, the next step is to invoke the OTT utility.

Specifying OTT Parameters

You can specify OTT parameters either on the command line or in a configuration file. Certain parameters can also be specified in the INTYPE file.

If you specify a parameter in more than one place, then its value on the command line takes precedence over its value in the INTYPE file. The value in the INTYPE file takes precedence over its value in a user-defined configuration file, which takes precedence over its value in the default configuration file.

Parameter precedence then is as follows:

  1. OTT command line
  2. Value in INTYPE file
  3. User-defined configuration file
  4. Default configuration file

For global options (that is, options on the command line or options at the beginning of the INTYPE file before any TYPE statements), the value on the command line overrides the value in the INTYPE file. (The options that can be specified globally in the INTYPE file are CASE, INITFILE, INITFUNC, MAPFILE and MAPFUNC, but not HFILE or CPPFILE.) Anything in the INTYPE file in a TYPE specification applies to a particular type only and overrides anything on the command line that would otherwise apply to the type. So if you enter TYPE person HFILE=p.h, then it applies to person only and overrides the HFILE on the command line. The statement is not considered a command line parameter.

Setting Parameters on the Command Line

Parameters (also called options) set on the command line override any parameters or option set elsewhere.

See Also:

"Invoking the OTT Utility" for more information

Setting Parameters in the INTYPE File

The INTYPE file gives a list of types for the OTT utility to translate.

The parameters CASE, CPPFILE, HFILE, INITFILE, INITFUNC, MAPFILE, and MAPFUNC can appear in the INTYPE file.

See Also:

"Overview of the INTYPE File" for more information

Setting Parameters in the Configuration File

A configuration file is a text file that contains OTT parameters. Each nonblank line in the file contains one parameter, with its associated value or values. If more than one parameter is put on a line, then only the first one will be used. No blank space is allowed on any nonblank line of a configuration file.

A configuration file can be named on the command line. In addition, a default configuration file is always read. This default configuration file must always exist, but can be empty. The name of the default configuration file is ottcfg.cfg, and the location of the file is operating system-specific.

See Also:

Your operating system-specific documentation for more information about the location of the default configuration file

Invoking the OTT Utility on the Command Line

On most platforms, the OTT utility is invoked on the command line. You can specify the input and output files and the database connection information at the command line, among other things.

See Also:

Your operating system-specific documentation to see how to invoke the OTT utility on your operating system

Invoking the OTT Utility for C++

The following is an example of invoking the OTT utility that generates C++ classes:

ott userid=scott/tiger intype=demoin.typ outtype=demoout.typ code=cpp 
hfile=demo.h cppfile=demo.cpp mapfile=RegisterMappings.cpp

Note:

No spaces are permitted around the equals sign (=) on the OTT command line.


Description of Elements Used on the OTT Command Line

The following sections describe the elements of the command lines used in these examples:

ott Command

Causes the OTT utility to be invoked. It must be the first item on the command line.

userid Parameter

Specifies the database connection information that the OTT utility will use. In both of the preceding examples, the OTT utility attempts to connect with username scott and password tiger.

intype Parameter

Specifies the name of the INTYPE file. In both of the preceding examples, the name of the INTYPE file is specified as demoin.typ.

outtype Parameter

Specifies the name of the OUTTYPE file. When the OTT utility generates the header file, it also writes information about the translated types into the OUTTYPE file. This file contains an entry for each of the types that is translated, including its version string, and the header file to which its C or C++ representation is written.

In both of the preceding examples, the name of the OUTTYPE file is specified as demoout.typ.

code Parameter

Specifies the target language for the translation. The following values are valid:

There is currently no default value, so this parameter is required.

Structure declarations are identical for the C language options: C, ANSI_C, and KR_C. The style in which the initialization function is defined in the INITFILE file depends on whether KR_C is used. If the INITFILE parameter is not used, then the C language options are equivalent.


Note:

In the previous example for C, the target language is specified as C (code=c). In the previous example for C++, the language is C++ (code=cpp) and both CPPFILE and MAPFILE parameters are specified.


If you are generating C++ classes by setting the CODE parameter to cpp, then you must use the CPPFILE and the MAPFILE parameters.

hfile Parameter

Specifies the name of the C or C++ header file to which the generated C structures or C++ classes are written.

See Also:

"OTT Command Line Syntax" for information about the CPPFILE and MAPFILE parameters

cppfile Parameter

Specifies the name of the C++ source file into which the method implementations are written. The methods generated in this file are called by OCCI while instantiating the objects and are not to be called directly in the an application. This parameter is only needed for OCCI applications.

mapfile Parameter

Specifies the name of the C++ source file into which the function to register the mappings with the environment is written. A corresponding header file is created containing the prototype for the function. This function to register mappings is only used for OCCI applications.

Overview of the INTYPE File

When you run the OTT utility, the INTYPE file tells the OTT utility which database types should be translated. The INTYPE file also controls the naming of the generated structures or classes. You can either create an INTYPE file or use the OUTTYPE file of a previous invocation of the OTT utility. If you do not use an INTYPE file, then all types in the schema to which the OTT utility connects are translated.

The following is an example of a user-created INTYPE file:

CASE=LOWER
TYPE employee
   TRANSLATE SALARY$ AS salary
             DEPTNO AS department
TYPE ADDRESS
TYPE item
TYPE "Person"
TYPE PURCHASE_ORDER AS p_o

In the first line, the CASE parameter indicates that generated C identifiers should be in lowercase. However, this CASE parameter is only applied to those identifiers that are not explicitly mentioned in the INTYPE file. Thus, employee and ADDRESS would always result in C structures employee and ADDRESS, respectively. The members of these structures are named in lowercase.

The lines that begin with the TYPE keyword specify which types in the database should be translated. In this case, the EMPLOYEE, ADDRESS, ITEM, PERSON, and PURCHASE_ORDER types are set to be translated.

The TRANSLATE ... AS keywords specify that the name of an object attribute should be changed when the type is translated into a C structure. In this case, the SALARY$ attribute of the employee type is translated to salary.

The AS keyword in the final line specifies that the name of an object type should be changed when it is translated into a structure. In this case, the purchase_order database type is translated into a structure called p_o.

If you do not use AS to translate a type or attribute name, then the database name of the type or attribute will be used as the C identifier name, except that the CASE parameter will be observed, and any characters that cannot be mapped to a legal C identifier character will be replaced by an underscore character (_). Consider the following reasons for translating a type or attribute:

The OTT utility may need to translate additional types that are not listed in the INTYPE file. This is because the OTT utility analyzes the types in the INTYPE file for type dependencies before performing the translation, and it translates other types as necessary. For example, if the ADDRESS type were not listed in the INTYPE file, but the Person type had an attribute of type ADDRESS, then the OTT utility would still translate ADDRESS because it is required to define the Person type.


Note:

As of release 1 (9.0.1), you may indicate whether the OTT utility is to generate required object types that are not specified in the INTYPE file. Set TRANSITIVE=FALSE so the OTT utility will not to generate required object types. The default is TRANSITIVE=TRUE.


A normal case insensitive SQL identifier can be spelled in any combination of uppercase and lowercase in the INTYPE file, and is not quoted.

Use quotation marks, such as TYPE "Person" to reference SQL identifiers that have been created in a case sensitive manner, for example, CREATE TYPE "Person". A SQL identifier is case sensitive if it was quoted when it was declared. Quotation marks can also be used to refer to a SQL identifier that is an OTT-reserved word, for example, TYPE "CASE". In this case, the quoted name must be in uppercase if the SQL identifier was created in a case insensitive manner, for example, CREATE TYPE Case. If an OTT-reserved word is used to refer to the name of a SQL identifier but is not quoted, then the OTT utility will report a syntax error in the INTYPE file.

See Also:

OTT Utility Datatype Mappings

When the OTT utility generates a C structure or a C++ class from a database type, the structure or class contains one element corresponding to each attribute of the object type. The datatypes of the attributes are mapped to types that are used in Oracle object data types. The datatypes found in Oracle include a set of predefined, primitive types and provide for the creation of user-defined types, like object types and collections.

The set of predefined types includes standard types that are familiar to most programmers, including number and character types. It also includes large object datatypes (for example, BLOB or CLOB).

Oracle also includes a set of predefined types that are used to represent object type attributes in C structures or C++ classes. As an example, consider the following object type definition, and its corresponding OTT-generated structure declarations:

CREATE TYPE employee AS OBJECT
(  name       VARCHAR2(30),
   empno      NUMBER,
   deptno     NUMBER,
   hiredate   DATE,
   salary$    NUMBER);

The OTT utility, assuming that the CASE parameter is set to LOWER and there are no explicit mappings of type or attribute names, produces the following output:

struct employee
{  OCIString * name;
   OCINumber empno;
   OCINumber deptno;
   OCIDate   hiredate;
   OCINumber salary_;
};
typedef struct emp_type emp_type;
struct employee_ind
{  OCIInd _atomic;
   OCIInd name;
   OCIInd empno;
   OCIInd deptno;
   OCIInd hiredate;
   OCIInd salary_;
}
typedef struct employee_ind employee_ind;

The datatypes in the structure declarations--LNOCIString, LNOCINumber, LNOCIDate, LNOCIInd--are used here to map the datatypes of the object type attributes. The number datatype of the empno attribute, maps to the LNOCINumber datatype, for example. These datatypes can also be used as the types of bind and define variables.

See Also:

Mapping Object Datatypes to C

This section describes the mappings of object attribute types to C types, as generated by the OTT utility Table 7-1 lists the mappings from types that can be used as attributes to object datatypes that are generated by the OTT utility.

See Also:

"OTT Utility Type Mapping Example for C" includes examples of many of these different mappings.

Table 7-1 C Object Datatype Mappings for Object Type Attributes  
Object Attribute Types C Mapping

BFILE

LNOCIBFileLocator*

BLOB

LNOCIBlobLocator*

CHAR(n), CHARACTER(n)

LNOCIString*

CLOB

LNOCIClobLocator*

DATE

LNOCIDate*

DEC, DEC(n), DEC(n,n)

LNOCINumber

DECIMAL, DECIMAL(n), DECIMAL(n,n)

LNOCINumber

FLOAT, FLOAT(n), DOUBLE PRECISION

LNOCINumber

INT, INTEGER, SMALLINT

LNOCINumber

INTERVAL DAY TO SECOND

LNOCIInterval

INTERVAL YEAR TO MONTH

LNOCIInterval

Nested Object Type

C name of the nested object type

NESTED TABLE

Declared by using typedef; equivalent to LNOCITable*

NUMBER, NUMBER(n), NUMBER(n,n)

LNOCINumber

NUMERIC, NUMERIC(n), NUMERIC(n,n)

LNOCINumber

RAW

LNOCIRaw*

REAL

LNOCINumber

REF

Declared by using typedef; equivalent to LNOCIRef*

TIMESTAMP, TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE

LNOCIDateTime*

VARCHAR(n)

LNOCIString*

VARCHAR2(n)

LNOCIString*

VARRAY

Declared by using typedef; equivalent to LNOCIArray*


Note:

For REF, VARRAY, and NESTED TABLE types, the OTT utility generates a typedef. The type declared in the typedef is then used as the type of the data member in the structure declaration. For examples, see the next section, "OTT Utility Type Mapping Example for C".


If an object type includes an attribute of a REF or collection type, then a typedef for the REF or collection type is first generated. Then the structure declaration corresponding to the object type is generated. The structure includes an element whose type is a pointer to the REF or collection type.

If an object type includes an attribute whose type is another object type, then the OTT utility first generates the nested object type. It then maps the object type attribute to a nested structure of the type of the nested object type.

The C datatypes to which the OTT utility maps nonobject database attribute types are structures, which, except for LNOCIDate, are opaque.

Mapping Object Datatypes to C++

This section describes the mappings of object attribute types to C++ types generated by the OTT utility. Table 7-2 lists the mappings from types that can be used as attributes to object datatypes that are generated by the OTT utility.

Table 7-2 C++ Object Datatype Mappings for Object Type Attributes  
Object Attribute Types C++ Mapping

BFILE

Bfile

BLOB

Blob

CHAR(n), CHARACTER(n)

string

CLOB

Clob

DATE

Date

DEC, DEC(n), DEC(n,n)

Number

DECIMAL, DECIMAL(n), DECIMAL(n,n)

Number

FLOAT, FLOAT(n), DOUBLE PRECISION

Number

INT, INTEGER, SMALLINT

Number

INTERVAL DAY TO SECOND

IntervalDS

INTERVAL YEAR TO MONTH

IntervalYM

Nested Object Type

C++ name of the nested object type

NESTED TABLE

vector<attribute_type>

NUMBER, NUMBER(n), NUMBER(n,n)

Number

NUMERIC, NUMERIC(n), NUMERIC(n,n)

Number

RAW

Bytes

REAL

Number

REF

Ref<attribute_type>

TIMESTAMP,TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE

Timestamp

VARCHAR(n)

string

VARCHAR2(n)

string

VARRAY

vector<attribute_type>

OTT Utility Type Mapping Example for C

The example in this section demonstrates the various type mappings created by the OTT utility for a C program.

The example assumes that the following database types are created:

CREATE TYPE my_varray AS VARRAY(5) of integer;

CREATE TYPE object_type AS OBJECT
(object_name VARCHAR2(20));

CREATE TYPE other_type AS OBJECT
(object_number NUMBER);

CREATE TYPE my_table AS TABLE OF object_type;

CREATE TYPE many_types AS OBJECT
(  the_varchar    VARCHAR2(30),
   the_char       CHAR(3),
   the_blob       BLOB,
   the_clob       CLOB,
   the_object     object_type,
   another_ref    REF other_type,
   the_ref        REF many_types,
   the_varray     my_varray,
   the_table      my_table,
   the_date       DATE,
   the_num        NUMBER,
   the_raw        RAW(255));

The example also assumes that an INTYPE file exists and that it includes the following:

CASE = LOWER
TYPE many_types

The OTT utility would then generate the following C structures:


Note:

Comments are provided here to help explain the structures. These comments are not part of the OTT utility output.


#ifndef MYFILENAME_ORACLE
#define MYFILENAME_ORACLE

#ifndef OCI_ORACLE
#include <oci.h>
#endif

typedef OCIRef many_types_ref;
typedef OCIRef object_type_ref;
typedef OCIArray my_varray;             /* part of many_types */
typedef OCITable my_table;              /* part of many_types*/
typedef OCIRef other_type_ref;
struct object_type                      /* part of many_types */
{
   OCIString * object_name;
};
typedef struct object_type object_type;

struct object_type_ind                  /*indicator struct for*/
{                                       /*object_types*/
   OCIInd _atomic;
   OCIInd object_name;
};
typedef struct object_type_ind object_type_ind;

struct many_types
{
   OCIString *        the_varchar;
   OCIString *        the_char;
   OCIBlobLocator *   the_blob;
   OCIClobLocator *   the_clob;
   struct object_type the_object;
   other_type_ref *   another_ref;
   many_types_ref *   the_ref;
   my_varray *        the_varray;
   my_table *         the_table; 
   OCIDate            the_date;
   OCINumber          the_num;
   OCIRaw *           the_raw;
};
typedef struct many_types many_types;

struct many_types_ind                   /*indicator struct for*/
{                                       /*many_types*/
   OCIInd _atomic;
   OCIInd the_varchar;
   OCIInd the_char;
   OCIInd the_blob;
   OCIInd the_clob;
   struct object_type_ind the_object;   /*nested*/
   OCIInd another_ref;
   OCIInd the_ref;
   OCIInd the_varray;
   OCIInd the_table;
   OCIInd the_date;
   OCIInd the_num;
   OCIInd the_raw;
};
typedef struct many_types_ind many_types_ind;

#endif

Notice that even though only one item was listed for translation in the INTYPE file, two object types and two named collection types were translated. This is because the OTT utility parameter TRANSITIVE Parameter, has the default value of TRUE. When TRANSITIVE=TRUE, the OTT utility automatically translates any types which are used as attributes of a type being translated, in order to complete the translation of the listed type.

This is not the case for types which are only accessed by a pointer or by reference in an object type attribute. For example, although the many_types type contains the attribute another_ref REF other_type, a declaration of structure other_type was not generated.

This example also illustrates how typedefs are used to declare VARRAY, NESTED TABLE, and REF types.

In the preceeding example, the typedefs occur near the beginning of the file generated by the OTT utility:

typedef OCIRef many_types_ref;
typedef OCIRef object_type_ref;
typedef OCIArray my_varray;    
typedef OCITable my_table; 
typedef OCIRef other_type_ref;

In the structure many_types, the VARRAY, NESTED TABLE, and REF attributes are declared:

struct many_types
{
   ...
   other_type_ref *   another_ref;
   many_types_ref *   the_ref;
   my_varray *        the_varray;
   my_table *         the_table;
   ...
}

OTT Type Mapping Example for C++

The following is an example of the OTT type mappings for C++, given the types created in the example in the previous section, and an INTYPE file that includes the following:

CASE = LOWER
TYPE many_types

The OTT utility generates the following C++ class declarations:

#ifndef MYFILENAME_ORACLE
# define MYFILENAME_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif


/************************************************************/
//  generated declarations for the OBJECT_TYPE object type.
/************************************************************/

class object_type : public oracle::occi::PObject {

protected:
   OCCI_STD_NAMESPACE::string object_name;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   object_type();
   object_type(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

/************************************************************/
//  generated declarations for the OTHER_TYPE object type.
/************************************************************/

class other_type : public oracle::occi::PObject {

protected:
   oracle::occi::Number object_number;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   other_type();
   other_type(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

/************************************************************/
//  generated declarations for the MANY_TYPES object type.
/************************************************************/

class many_types : public oracle::occi::PObject {

protected:
   OCCI_STD_NAMESPACE::string the_varchar;
   OCCI_STD_NAMESPACE::string the_char;
   oracle::occi::Blob the_blob;
   oracle::occi::Clob the_clob;
   object_type * the_object;
   oracle::occi::Ref< other_type > another_ref;
   oracle::occi::Ref< many_types > the_ref;
   OCCI_STD_NAMESPACE::vector< oracle::occi::Number > the_varray;
   OCCI_STD_NAMESPACE::vector< object_type * > the_table;
   oracle::occi::Date the_date;
   oracle::occi::Number the_num;
   oracle::occi::Bytes the_raw;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   many_types();
   many_types(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

#endif

For C++, when TRANSITIVE=TRUE, the OTT utility automatically translates any types that are used as attributes of a type being translated, including types that are only being accessed by a pointer or REF in an object type attribute. Even though only the many_types object was specified in the INTYPE file for the C++ example, a class declaration was generated for all the object types, including the other_type object, which was only accessed by a REF in the many_types object.

Overview of the OUTTYPE File

The OUTTYPE file is named on the OTT command line. When the OTT utility generates a C or C++ header file, it also writes the results of the translation into the OUTTYPE file. This file contains an entry for each of the translated types, including its version string and the header file to which its C or C++ representation was written.

The OUTTYPE file from one OTT utility run can be used as the INTYPE file for a subsequent invocation of the OTT utility.

For example, consider the following simple INTYPE file used earlier in this chapter:

CASE=LOWER
TYPE employee
   TRANSLATE SALARY$ AS salary
             DEPTNO AS department
TYPE ADDRESS
TYPE item
TYPE "Person"
TYPE PURCHASE_ORDER AS p_o

In this INTYPE file, the programmer specifies the case for OTT-generated C identifiers, and provides a list of types that should be translated. In two of these types, naming conventions are specified.

The following example shows what the OUTTYPE file looks like after running the OTT utility:

CASE = LOWER
TYPE EMPLOYEE AS employee
  VERSION = "$8.0"
  HFILE = demo.h
  TRANSLATE SALARY$ AS salary
             DEPTNO AS department
TYPE ADDRESS AS ADDRESS
  VERSION = "$8.0"
  HFILE = demo.h
TYPE ITEM AS item
  VERSION = "$8.0"
  HFILE = demo.h
TYPE "Person" AS Person
  VERSION = "$8.0"
  HFILE = demo.h
TYPE PURCHASE_ORDER AS p_o
  VERSION = "$8.0"
  HFILE = demo.h

When examining the contents of the OUTTYPE file, you might discover types listed that were not included in the INTYPE file specification. For example, consider the case where the INTYPE file only specified that the person type was to be translated:

CASE = LOWER
TYPE PERSON

If the definition of the person type includes an attribute of type address, then the OUTTYPE file includes entries for both PERSON and ADDRESS. The person type cannot be translated completely without first translating address.

The OTT utility analyzes the types in the INTYPE file for type dependencies before performing the translation, and translates other types as necessary.


Note:

As of release 1 (9.0.1), you may indicate whether the OTT utility is to generate required object types that are not specified in the INTYPE file. Set TRANSITIVE=FALSE so the OTT utility will not to generate required object types. The default is TRANSITIVE=TRUE.


See Also:

"Invoking the OTT Utility" for details on these parameters.

The OTT Utility and OCCI Applications

The OTT utility generates objects and maps SQL datatypes to C++ classes. The OTT utility also implements a few methods called by OCCI when instantiating objects and a function that is called in the OCCI application to register the mappings with the environment. These declarations are stored in a header file that you include (#include) in your OCCI application. The prototype for the function that registers the mappings is written to a separate header file that you also include in your OCCI application.The method implementations are stored in a C++ source code file (with extension .cpp) that is linked with the OCCI application. The function that registers the mappings is stored in a separate C++ (.cpp) file that is also linked with the application.

Figure 7-1 shows the steps involved in using the OTT utility with OCCI. These steps are described following the figure.

Figure 7-1 The OTT Utility with OCCI

Text description of Figure 7-1 'The OTT Utility with OCCI' follows
Text description of Figure 7-1 'The OTT Utility with OCCI'


  1. Create the type definitions in the database by using the SQL DLL.
  2. Create the INTYPE file that contains the database types to be translated by the OTT utility.
  3. Specify that C++ should be generated and invoke the OTT utility.

    The OTT utility then generates the following files:

    • A header file (with the extension .h) that contains C++ class representations of object types. The filename is specified on the OTT command line by the HFILE parameter.
    • A header file containing the prototype of the function (MAPFUNC) that registers the mappings.
    • A C++ source file (with the extension .cpp) that contains the static methods to be called by OCCI while instantiating the objects. Do not call these methods directly from your OCCI application. The filename is specified on the OTT command line by the CPPFILE parameter.
    • A file that contains the function used to register the mappings with the environment (with the extension .cpp). The filename is specified on the OTT command line by the MAPFILE parameter.
    • A file (the OUTTYPE file) that contains an entry for each of the translated types, including the version string and the file into which it is written. The filename is specified on the OTT command line by the OUTTYPE parameter.
  4. Write the OCCI application and include the header files created by the OTT utility in the OCCI source code file.

    The application declares an environment and calls the function MAPFUNC to register the mappings.

  5. Compile the OCCI application to create the OCCI object code, and link the object code with the OCCI libraries to create the program executable.

OTT Utility Parameters for C++

To generate C++ using the OTT utility, the CODE parameter must be set to CODE=CPP. Once CODE=CPP is specified, you are required to specify the CPPFILE and MAPFILE parameters to define the filenames for the method implementation file and the mappings registration function file. The name of the mapping function is derived by the OTT utility from the MAPFILE or you may specify the name with the MAPFUNC parameter. ATTRACCESS is also an optional parameter that can be specified to change the generated code.

The following parameters are specific to C++ only and control the generation of C++ classes:

OTT-Generated C++ Classes

When the OTT utility generates a C++ class from a database object type, the class declaration contains one element corresponding to each attribute of the object type. The datatypes of the attribute are mapped to types that are used in Oracle object datatypes, as defined in Table 7-2.

For each class, two new operators, a getSQLTypeName method, two constructors, two readSQL methods and two writeSQL methods are generated. The getSQLTypeName method, the constructor, the readSQL and writeSQL methods are called by OCCI while unmarshalling and marshalling the object data.

By default, the OTT-generated C++ class for an object type is derived from the PObject class and so the generated constructor in the class also derives from the PObject class. For inherited database types, the class is derived from the parent type class as is the generated constructor and only the elements corresponding to attributes not already in the parent class are included.

Class declarations that include the elements corresponding to the database type attributes and the method declarations are included in the header file generated by the OTT utility. The method implementations are included in the CPPFILE file generated by the OTT utility.

The following is an example of the C++ classes generated by the OTT utility as a result of this series of steps:

  1. Define the types:
    CREATE TYPE FULL_NAME AS OBJECT (first_name CHAR(20), last_name CHAR(20));
    CREATE TYPE ADDRESS AS OBJECT (state CHAR(20), zip CHAR(20));
    CREATE TYPE ADDRESS_TAB AS VARRAY(3) of REF ADDRESS;
    CREATE TYPE PERSON AS OBJECT (id NUMBER, name FULL_NAME, curr_addr REF ADDRESS,
       prev_addr_l ADDRESS_TAB) NOT FINAL;
    CREATE TYPE STUDENT UNDER PERSON (school_name CHAR(20));
    
    
  2. Provide an INTYPE file:
    CASE = SAME
    MAPFILE = RegisterMappings_3.cpp
    TYPE FULL_NAME AS FullName
      TRANSLATE first_name as FirstName
                last_name as LastName
    TYPE ADDRESS
    TYPE PERSON
    TYPE STUDENT
    
    
  3. Invoke the OTT utility:
    ott userid=scott/tiger intype=demoin_3.typ outype=demoout_3.typ code=cpp 
    hfile=demo_3.h cppfile=demo_3.cpp
    

This example produces a header file named demo_3.h, a C++ source file named demo_3.cpp, and an OUTTYPE file named demoout_3.typ. These files generated by the OTT utility are displayed in the following sections:

Example of a Header File Generated by the OTT Utility: demo_3.h

This section contains the header file generated by the OTT utility (named demo_3.h) based on information contained in the previous section.

#ifndef DEMO_3_ORACLE
# define DEMO_3_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif


/************************************************************/
//  generated declarations for the FULL_NAME object type.
/************************************************************/

class FullName : public oracle::occi::PObject {

protected:
   OCCI_STD_NAMESPACE::string FirstName;
   OCCI_STD_NAMESPACE::string LastName;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   FullName();
   FullName(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

/************************************************************/
//  generated declarations for the ADDRESS object type.
/************************************************************/

class ADDRESS : public oracle::occi::PObject {

protected:
   OCCI_STD_NAMESPACE::string STATE;
   OCCI_STD_NAMESPACE::string ZIP;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   ADDRESS();
   ADDRESS(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

/************************************************************/
//  generated declarations for the PERSON object type.
/************************************************************/

class PERSON : public oracle::occi::PObject {

protected:
   oracle::occi::Number ID;
   FullName * NAME;
   oracle::occi::Ref< ADDRESS > CURR_ADDR;
   OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< ADDRESS > > PREV_ADDR_L;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   PERSON();
   PERSON(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

/************************************************************/
//  generated declarations for the STUDENT object type.
/************************************************************/

class STUDENT : public PERSON {

protected:
   OCCI_STD_NAMESPACE::string SCHOOL_NAME;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   STUDENT();
   STUDENT(void *ctxOCCI_) : PERSON (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

#endif

Example of a C++ Source File Generated by the OTT Utility: demo_3.cpp

This section contains the C++ source file generated by the OTT utility (named demo_3.cpp) based on information contained in the previous section.

#ifndef DEMO_3_ORACLE
# include "demo_3.h"
#endif


/*****************************************************************/
//  generated method implementations for the FULL_NAME object type.
/*****************************************************************/

void *FullName::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *FullName::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.FULL_NAME");
}

OCCI_STD_NAMESPACE::string FullName::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.FULL_NAME");
}

FullName::FullName()
{
}

void *FullName::readSQL(void *ctxOCCI_)
{
  FullName *objOCCI_ = new FullName(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void FullName::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   FirstName = streamOCCI_.getString();
   LastName = streamOCCI_.getString();
}

void FullName::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  FullName *objOCCI_ = (FullName *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void FullName::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setString(FirstName);
   streamOCCI_.setString(LastName);
}

/*****************************************************************/
//  generated method implementations for the ADDRESS object type.
/*****************************************************************/

void *ADDRESS::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *ADDRESS::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.ADDRESS");
}

OCCI_STD_NAMESPACE::string ADDRESS::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.ADDRESS");
}

ADDRESS::ADDRESS()
{
}

void *ADDRESS::readSQL(void *ctxOCCI_)
{
  ADDRESS *objOCCI_ = new ADDRESS(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void ADDRESS::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   STATE = streamOCCI_.getString();
   ZIP = streamOCCI_.getString();
}

void ADDRESS::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  ADDRESS *objOCCI_ = (ADDRESS *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void ADDRESS::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setString(STATE);
   streamOCCI_.setString(ZIP);
}

/*****************************************************************/
//  generated method implementations for the PERSON object type.
/*****************************************************************/

void *PERSON::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *PERSON::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.PERSON");
}

OCCI_STD_NAMESPACE::string PERSON::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.PERSON");
}

PERSON::PERSON()
{
   NAME = (FullName *) 0;
}

void *PERSON::readSQL(void *ctxOCCI_)
{
  PERSON *objOCCI_ = new PERSON(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void PERSON::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   ID = streamOCCI_.getNumber();
   NAME = (FullName *) streamOCCI_.getObject();
   CURR_ADDR = streamOCCI_.getRef();
   getVector(streamOCCI_, PREV_ADDR_L);
}

void PERSON::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  PERSON *objOCCI_ = (PERSON *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void PERSON::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setNumber(ID);
   streamOCCI_.setObject(NAME);
   streamOCCI_.setRef(CURR_ADDR);
   setVector(streamOCCI_, PREV_ADDR_L);
}

/*****************************************************************/
//  generated method implementations for the STUDENT object type.
/*****************************************************************/

void *STUDENT::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *STUDENT::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.STUDENT");
}

OCCI_STD_NAMESPACE::string STUDENT::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.STUDENT");
}

STUDENT::STUDENT()
{
}

void *STUDENT::readSQL(void *ctxOCCI_)
{
  STUDENT *objOCCI_ = new STUDENT(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void STUDENT::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   PERSON::readSQL(streamOCCI_);
   SCHOOL_NAME = streamOCCI_.getString();
}

void STUDENT::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  STUDENT *objOCCI_ = (STUDENT *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void STUDENT::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   PERSON::writeSQL(streamOCCI_);
   streamOCCI_.setString(SCHOOL_NAME);
}

Example of an OUTTYPE File Generated by the OTT Utility: demoout_3.typ

This section contains the OUTTYPE file generated by the OTT utility (named demoout_3.typ) based on information contained in the previous section:

CASE = SAME
MAPFILE = RegisterMappings_3.cpp
MAPFUNC = RegisterMappings

TYPE SCOTT.FULL_NAME AS FullName
  VERSION = "$8.0"
  HFILE = demo_3.h
TRANSLATE FIRST_NAME AS FirstName
          LAST_NAME AS LastName

TYPE SCOTT.ADDRESS AS ADDRESS
  VERSION = "$8.0"
  HFILE = demo_3.h

TYPE SCOTT.PERSON AS PERSON
  VERSION = "$8.0"
  HFILE = demo_3.h

TYPE SCOTT.STUDENT AS STUDENT
  VERSION = "$8.0"
  HFILE = demo_3.h

Example with ATTRACCESS=PRIVATE

To demonstrate the difference in generated code when ATTRACCESS=PRIVATE, consider an INTYPE file that contains:

CASE = SAME
TYPE PERSON

The OTT utility generates the following header file:

 #ifndef DEMO_4_ORACLE
 #define DEMO_4 _ORACLE
 #ifndef OCCI_ORACLE
 #include <occi.h>
 #endif

 /************************************************************/

 // generated declarations for the FULL_NAME object type.

 /************************************************************/

class FULL_NAME : public oracle::occi::PObject {

     private:
          OCCI_STD_NAMESPACE::string FIRST_NAME;
          OCCI_STD_NAMESPACE::string LAST_NAME;
 

     public:
         OCCI_STD_NAMESPACE::string getFirst_name() const;
         void setFirst_name(const OCCI_STD_NAMESPACE::string &value);
         OCCI_STD_NAMESPACE::string getLast_name() const;
         void setLast_name(const OCCI_STD_NAMESPACE::string &value);
         void *operator new(size_t size);
         void *operator new(size_t size, const oracle::occi::Connection * sess,
                   const OCCI_STD_NAMESPACE::string& table);
          OCCI_STD_NAMESPACE::string getSQLTypeName() const;
          FULL_NAME();
          FULL_NAME(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
          static void *readSQL(void *ctxOCCI_);
          virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
          static void writeSQL(void *objOCCI_, void *ctxOCCI_);
          virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
 
 /************************************************************/
 // generated declarations for the ADDRESS object type.
 /************************************************************/
class ADDRESS : public oracle::occi::PObject {
     private:
          OCCI_STD_NAMESPACE::string STATE;
          OCCI_STD_NAMESPACE::string ZIP;
 
     public:
          OCCI_STD_NAMESPACE::string getState() const;
          void setState(const OCCI_STD_NAMESPACE::string &value);
          OCCI_STD_NAMESPACE::string getZip() const;
          void setZip(const OCCI_STD_NAMESPACE::string &value);
          void *operator new(size_t size);
          void *operator new(size_t size, const oracle::occi::Connection * sess,
                    const OCCI_STD_NAMESPACE::string& table);
          OCCI_STD_NAMESPACE::string getSQLTypeName() const;
          ADDRESS();
          ADDRESS(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
          static void *readSQL(void *ctxOCCI_);
          virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
          static void writeSQL(void *objOCCI_, void *ctxOCCI_);
          virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
          };
  
/************************************************************/
// generated declarations for the PERSON object type.
/************************************************************/
class PERSON : public oracle::occi::PObject {
 private:
   oracle::occi::Number ID;
    FULLL_NAME * NAME;
    oracle::occi::Ref< ADDRESS > CURR_ADDR;
    OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< ADDRESS > > PREV_ADDR_L;

 public:
   oracle::occi::Number getId() const;
 void setId(const oracle::occi::Number &value);
 FULL_NAME * getName() const;
 void setName(FULL_NAME * value);
 oracle::occi::Ref< ADDRESS > getCurr_addr() const;
 void setCurr_addr(const oracle::occi::Ref< ADDRESS > &value);
 OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< ADDRESS > >& getPrev_addr_l();
 const OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< ADDRESS > >& getPrev_addr_l() const;
 void setPrev_addr_l(const OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< ADDRESS > > &value);
 void *operator new(size_t size);
 void *operator new(size_t size, const oracle::occi::Connection * sess,
    const OCCI_STD_NAMESPACE::string& table);
 OCCI_STD_NAMESPACE::string getSQLTypeName() const;
 PERSON();
 PERSON(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
 static void *readSQL(void *ctxOCCI_);
 virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
 static void writeSQL(void *objOCCI_, void *ctxOCCI_);
 virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
 };

 #endif
 

Since ATTRACCESS=PRIVATE, the access given to the attributes is private and the accessor (getxxx) and the mutator (setxxx) methods are generated for each of the attributes.

Map Registry Function

One function to register the mappings with the environment is generated by the OTT utility. The function contains the mappings for all the types translated by the invocation of the OTT utility. The function name is either specified in the MAPFUNC parameter or, if that parameter is not specified, derived from MAPFILE parameter. The only argument to the function is the pointer to Environment.

The function uses the provided Environment to get Map and then registers the mapping of each translated type.

Given the database type and INTYPE file listed in the previous section, and specifying MAPFILE=RegisterMappings_3.cpp, the map registering function generated takes the following form:

  >#ifndef REGISTERMAPPINGS_3_ORACLE
 #include "registermappings_3.h"
 #endif
 void RegisterMappings_3(oracle::occi::Environment* envOCCI_)
 {
  oracle::occi::Map *mapOCCI_ = envOCCI_->getMap();
  mapOCCI_->put("SCOTT.FULL_NAME", FullName::readSQL, FullName::writeSQL);
  mapOCCI_->put("SCOTT.ADDRESS", ADDRESS::readSQL, ADDRESS::writeSQL);
  mapOCCI_->put("SCOTT.PERSON", PERSON::readSQL, PERSON::writeSQL);
  mapOCCI_->put("SCOTT.STUDENT", STUDENT::readSQL, STUDENT::writeSQL);
 }

The prototype of the register mapping function is written to a corresponding header file, RegisterMapping.h, and looks like the following:

#ifndef REGISTERMAPPINGS_3_ORACLE
# define REGISTERMAPPINGS_3_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif

#ifndef DEMO_3_ORACLE
# include "demo_3.h"
#endif

void RegisterMappings_3(oracle::occi::Environment* envOCCI_);

#endif

Extending OTT C++ Classes

To enhance the functionality of a class generated by the OTT utility, you can derive new classes. You can also add methods to a class, but Oracle does not recommend doing so due to an inherent risk.

See Also:

"Carrying Forward User Added Code" for details on how to use OTT markers to retain code you want to add in OTT generated files.

For an example of deriving a new class from an OTT-generated class, assume you want to generate the class CAddress from the SQL object type ADDRESS. Assume also that you want to write a class MyAddress to represent ADDRESS objects. The MyAddress class can be derived from CAddress.

To perform this, the OTT utility must alter the code it generates:

To use the OTT utility to generate the CAddress class (that you derive the MyAddress class from), the following clause must be specified in the TYPE statement:

TYPE ADDRESS GENERATE CAdress AS MyAddress

Example for Extending OTT Classes

Given the database types FULL_NAME, ADDRESS, PERSON, and PFGRFDENT as they were created before and changing the INTYPE file to include the GENERATE ... AS clause:

CASE = SAME
MAPFILE = RegisterMappings_5.cpp

TYPE FULL_NAME GENERATE CFullName AS MyFullName
  TRANSLATE first_name as FirstName
            last_name as LastName

TYPE ADDRESS GENERATE CAddress AS MyAddress
TYPE PERSON GENERATE CPerson AS MyPerson
TYPE STUDENT GENERATE CStudent AS MyStudent

The following C++ source file (with the extension .cpp) is generated by the OTT utility:

#ifndef MYFILENAME_ORACLE
# define MYFILENAME_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif


/************************************************************/
//  generated declarations for the FULL_NAME object type.
/************************************************************/

class CFullName : public oracle::occi::PObject {

protected:
   OCCI_STD_NAMESPACE::string FirstName;
   OCCI_STD_NAMESPACE::string LastName;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   CFullName();
   CFullName(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

/************************************************************/
//  generated declarations for the ADDRESS object type.
/************************************************************/

class CAddress : public oracle::occi::PObject {

protected:
   OCCI_STD_NAMESPACE::string STATE;
   OCCI_STD_NAMESPACE::string ZIP;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   CAddress();
   CAddress(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

/************************************************************/
//  generated declarations for the PERSON object type.
//
//  Note the type name for the "name" attribute is MyFullName
//  and not CFullName, the "curr-addr" attribute is Ref< MyAddress >
//  and not Ref< CAddress >, and the "prev_addr_l" attribute is
//  vector< Ref< MyAddress > >.
/************************************************************/

class CPerson : public oracle::occi::PObject {

protected:
   oracle::occi::Number ID;
   MyFullName * NAME;
   oracle::occi::Ref< MyAddress > CURR_ADDR;
   OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< MyAddress > > PREV_ADDR_L;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   CPerson();
   CPerson(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

/************************************************************/
//  generated declarations for the STUDENT object type.
//
//  Note the parent class for CStudent is MyPerson and not
//  CPerson
/************************************************************/

class CStudent : public MyPerson {

protected:
   OCCI_STD_NAMESPACE::string SCHOOL_NAME;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   CStudent();
   CStudent(void *ctxOCCI_) : MyPerson (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

#endif

The method implementations are as follows:

#ifndef MYFILENAME_ORACLE
# include "myfilename.h"
#endif


/*****************************************************************/
//  generated method implementations for the FULL_NAME object type.
/*****************************************************************/

void *CFullName::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *CFullName::operator new(size_t size, const oracle::occi::Connection * 
sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.FULL_NAME");
}

OCCI_STD_NAMESPACE::string CFullName::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.FULL_NAME");
}

CFullName::CFullName()
{
}

void *CFullName::readSQL(void *ctxOCCI_)
{
  CFullName *objOCCI_ = new CFullName(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void CFullName::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   FirstName = streamOCCI_.getString();
   LastName = streamOCCI_.getString();
}

void CFullName::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  CFullName *objOCCI_ = (CFullName *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void CFullName::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setString(FirstName);
   streamOCCI_.setString(LastName);
}

/*****************************************************************/
//  generated method implementations for the ADDRESS object type.
/*****************************************************************/

void *CAddress::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *CAddress::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.ADDRESS");
}

OCCI_STD_NAMESPACE::string CAddress::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.ADDRESS");
}

CAddress::CAddress()
{
}

void *CAddress::readSQL(void *ctxOCCI_)
{
  CAddress *objOCCI_ = new CAddress(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void CAddress::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   STATE = streamOCCI_.getString();
   ZIP = streamOCCI_.getString();
}

void CAddress::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  CAddress *objOCCI_ = (CAddress *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void CAddress::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setString(STATE);
   streamOCCI_.setString(ZIP);
}

/*****************************************************************/
//  generated method implementations for the PERSON object type.
//
//  Note the type used in the casting in the readSQL method is
//  MyFullName and not CFullName.
/*****************************************************************/

void *CPerson::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *CPerson::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.PERSON");
}

OCCI_STD_NAMESPACE::string CPerson::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.PERSON");
}

CPerson::CPerson()
{
   NAME = (MyFullName *) 0;
}

void *CPerson::readSQL(void *ctxOCCI_)
{
  CPerson *objOCCI_ = new CPerson(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void CPerson::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   ID = streamOCCI_.getNumber();
   NAME = (MyFullName *) streamOCCI_.getObject();
   CURR_ADDR = streamOCCI_.getRef();
   getVector(streamOCCI_, PREV_ADDR_L);
}

void CPerson::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  CPerson *objOCCI_ = (CPerson *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void CPerson::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setNumber(ID);
   streamOCCI_.setObject(NAME);
   streamOCCI_.setRef(CURR_ADDR);
   setVector(streamOCCI_, PREV_ADDR_L);
}

/*****************************************************************/
//  generated method implementations for the STUDENT object type.
//
//  Note even though CStudent derives from MyPerson, the readSQL
//  and writeSQL methods called are those of CPerson.
/*****************************************************************/

void *CStudent::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *CStudent::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.STUDENT");
}

OCCI_STD_NAMESPACE::string CStudent::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.STUDENT");
}

CStudent::CStudent()
{
}

void *CStudent::readSQL(void *ctxOCCI_)
{
  CStudent *objOCCI_ = new CStudent(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void CStudent::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   CPerson::readSQL(streamOCCI_);
   SCHOOL_NAME = streamOCCI_.getString();
}

void CStudent::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  CStudent *objOCCI_ = (CStudent *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void CStudent::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   CPerson::writeSQL(streamOCCI_);
   streamOCCI_.setString(SCHOOL_NAME);
}

Carrying Forward User Added Code

To extend the functionality of OTT generated code, at times programmers may want to add code in the OTT generated file. The way OTT can distinguish between OTT generated code and code added by the user is by looking for some predefined markers (tags). OTT recognizes OTT_USERCODE_START as the "start of user code marker", and OTT_USERCODE_END as the "end of user code marker".

For OTT marker support, a user block is defined as

   OTT_USERCODE_START + user added code + OTT_USERCODE_END

OTT marker support enables carring forward the user added blocks across multiple runs of OTT.


Note: To use OTT marker support, you must use JDK version 1.3 or higher.

Properties of OTT Markers

Following bullets describe the properties of OTT markers support.

  1. User must use the command line option USE_MARKER=TRUE from the very first time OTT is invoked to generate a file.
  2. User should put the markers like another C++ statement; marker will be defined by OTT in the generated file as follows when the command line option USE_MARKER=TRUE is used:
             #ifndef OTT_USERCODE_START 
             # define OTT_USERCODE_START 
             #endif
             #ifndef OTT_USERCODE_END
             # define OTT_USERCODE_END
             #endif
    
    
  3. The markers, OTT_USERCODE_START and OTT_USERCODE_END, must be preceded and followed by white space.
  4. OTT will copy the text/code given within markers verbatim along with the markers while generating the code next time,

    User modified code:

             1  // --- modified generated code 
             2  OTT_USERCODE_START 
             3  // --- including "myfullname.h" 
             4  #ifndef MYFULLNAME_ORACLE 
             5  # include "myfullname.h" 
             6  #endif 
             7  OTT_USERCODE_END 
             8  // --- end of code addition 
    
    

    Carried forward code:

             1  OTT_USERCODE_START 
             2  // --- including "myfullname.h" 
             3  #ifndef MYFULLNAME_ORACLE 
             4  # include "myfullname.h" 
             5  #endif 
             6  OTT_USERCODE_END 
    
    

    In the preceeding example the 1st and 8th lines of the original code have not been carried forward.

  5. OTT will not be able to carry forward user added code properly if the database TYPE or INTYPE file under goes changes as shown in the following cases:
    1. If user modifies the case of the type name, OTT will fail to find out the class name with which the code was associated earlier as the case of the class name got modified by the user in the INTYPE file.
            CASE=UPPER                                 CASE=LOWER 
            TYPE employee                              TYPE employee 
              TRANSLATE SALARY$ AS salary              TRANSLATE SALARY$ AS salary 
                        DEPTNO AS department                   DEPTNO AS department 
            TYPE ADDRESS                               TYPE ADDRESS 
            TYPE item                                  TYPE item 
            TYPE "Person"                              TYPE "Person" 
            TYPE PURCHASE_ORDER AS p_o                 TYPE PURCHASE_ORDER AS p_o
      
      
    2. If user asks to generate the class with different name (GENERATE AS clause of INTYPE file), OTT will fail to find out the class name with which the code was associated earlier as the class name got modified by the user in the INTYPE file.
            CASE=LOWER                                 CASE=LOWER 
            TYPE employee                              TYPE employee 
            TRANSLATE SALARY$ AS salary                TRANSLATE SALARY$ AS salary 
            DEPTNO AS department                       DEPTNO AS department 
            TYPE ADDRESS                               TYPE ADDRESS 
            TYPE item                                  TYPE item 
            TYPE "Person"                              TYPE "Person" 
            TYPE PURCHASE_ORDER AS p_o                 TYPE PURCHASE_ORDER AS
                                                      purchase_order
      
      
  6. If OTT encounters an error while parsing a .h or .cpp file, it reports the error and leaves the file having error as it is so that the user can go back and correct the error reported, and rerun OTT.
  7. OTT will flag an error if
    • it does not find a matching OTT_USERCODE_END for OTT_USERCODE_START encountered
    • markers are nested (OTT finds next OTT_USERCODE_START before OTT_USERCODE_END is found for the previous OTT_USERCODE_START)
    • OTT_USERCODE_END is encountered before OTT_USERCODE_START

Where the Markers Can Be Used

To use OTT markers user must use command line option USE_MARKER=TRUE, to inform OTT that use of marker should be supported, while invoking OTT. User can use OTT markers as described later to carry forward user added code.

  1. User code added in .h file.
    1. User code added in global scope. This is typically the case when user needs to include different header files, forward declaration, and so on. Refer to the code example provided later.
    2. User code added in class declaration. At any point of time OTT generated class declaration will have private scope for data members and public scope for methods, or protected scope for data members and public scope for methods. User blocks can be added after all OTT generated declarations in either access specifiers.

    The following code example demonstrates where user code can be added in a .h file:

          #ifndef ...                                                 
          # define ...                                                
                                                                      
          #ifndef OTT_USERCODE_START                                  
          # define OTT_USERCODE_START 
          #endif
          #ifndef OTT_USERCODE_END
          # define OTT_USERCODE_END
          #endif           
    
          #ifndef OCCI_ORACLE
          # include <occi.h>
          #endif
    
          OTT_USERCODE_START     // user added code 
          ...
          OTT_USERCODE_END
    
          #ifndef ...            // OTT generated include
          # include " ... "
          #endif
    
          OTT_USERCODE_START     // user added code 
          ...
          OTT_USERCODE_END
    
          class <class_name_1> : public oracle::occi::PObject {
          protected:
            // OTT generated data members 
            ...
    
            OTT_USERCODE_START   // user added code 
            ...                  // data member / method declaration / 
            ...                  // inline method definition
            OTT_USERCODE_END
         
          public:
            void *operator new(size_t size);
            void *operator new(size_t size, const oracle::occi::Connection * sess,
                 const OCCI_STD_NAMESPACE::string& table);
            void *operator new(size_t, void *ctxOCCI_);
            OCCI_STD_NAMESPACE::string getSQLTypeName() const;
            ...
    
            OTT_USERCODE_START   // user added code 
            ...                  // data member / method declaration / 
            ...                  // inline method definition
            OTT_USERCODE_END
          };
      
          OTT_USERCODE_START     // user added code 
          ...
          OTT_USERCODE_END
    
          class <class_name_2> : public oracle::occi::PObject {
            ...
            ...
          };
    
          OTT_USERCODE_START     // user added code 
          ...                                                          
          OTT_USERCODE_END                                             
                                                                       
          #endif                 // end of .h file                     
     
    
  2. User code added in .cpp file. OTT will support adding a new user defined method within OTT markers. The user block must be added at the beginning of the file, just after the includes and before the definition of OTT generated methods. If there are more than one OTT generated includes, user code can also be added between OTT generated includes. User code added in any other part of a .cpp file will not be carried forward.

    The following code example demonstrates where user code can be added in a .cpp file:

          #ifndef OTT_USERCODE_START                                   
          # define OTT_USERCODE_START                                  
          #endif                                                       
                                                                       
          #ifndef OTT_USERCODE_END
          # define OTT_USERCODE_END
          #endif
    
          #ifndef ...
          # include " ... "
          #endif
    
          OTT_USERCODE_START    // user added code 
          ...
          ...
          OTT_USERCODE_END
    
          #ifndef ...
          # include " ... "
          #endif
    
          OTT_USERCODE_START    // user added code 
          ...
          ...
          OTT_USERCODE_END
    
          /*************************************************************/
          //  generated method implementations for the ... object type.
          /*************************************************************/
    
          void *<class_name_1>::operator new(size_t size)
          {
            return oracle::occi::PObject::operator new(size);
          }
    
         ...                                                          
                                                                      
         // end of .cpp file                                          
    

Code Samples Showing How To Use OTT Markers

Here is an example to demonstrate how OTT markers can be used to solve the problem introduced by a particular use of GENERATE AS clause.

In this example, because of the use of GENERATE AS clause, FULL_NAME_O was generated as FullName, which was intended to be an user extended class. Since FullName is an attribute of PERSON_O class, compiler will flag an error if it does not find the class declaration for FullName.

With marker support user now can add the header file where needed, or a forward declaration, or a class declaration and be assured of getting the user added block carried forward across runs of OTT.

In this example class declaration of FullName is put in mdemo1.h file.

Command line to invoke OTT:

   ott case=same userid=scott/tiger code=cpp intype=mdemo1.typ 
   hfile=mdemo1.h cppfile=mdemo1o.cpp use_marker=true

The build command:

   make -f demo_rdbms.mk mdemo1

Following are the files used for this demo program:

mdemo1.sql

// -----------------------------------------------------
//  mdemo1.sql : SQLs to create type, tables, and so on.
// -----------------------------------------------------
connect scott/tiger;

DROP TABLE PERSON_TAB;
DROP TABLE ADDR_TAB;
DROP TYPE PERSON_O;
DROP TYPE ADDRESS_O;
DROP TYPE FULL_NAME_O;

CREATE TYPE ADDRESS_O AS OBJECT (
   "state" CHAR(20),
   "zip" CHAR(20)
)
/
CREATE TABLE ADDR_TAB OF ADDRESS_O;

CREATE TYPE FULL_NAME_O AS OBJECT (
   "first_name" CHAR(20),
   "last_name" CHAR(20)
)
/
CREATE TYPE PERSON_O AS OBJECT (
   "id" integer,
   "name" FULL_NAME_O,
   "addr" REF ADDRESS_O
)
/
CREATE TABLE PERSON_TAB OF PERSON_O;

QUIT;

mdemo1.typ

// --------------------------
//  mdemo1.typ : INTYPE file
// --------------------------
CASE=SAME
MAPFILE=mdemo1m.cpp
TYPE FULL_NAME_O
 GENERATE FULL_NAME_O AS FullName
TYPE ADDRESS_O
TYPE PERSON_O
 GENERATE PERSON_O AS Person

mdemo1.h

// --------------------------------------------------------------
//  mdemo1.h   : OTT generated header file with user addeed code
// --------------------------------------------------------------
#ifndef MDEMO1_ORACLE
# define MDEMO1_ORACLE

#ifndef OTT_USERCODE_START
# define OTT_USERCODE_START
#endif

#ifndef OTT_USERCODE_END
# define OTT_USERCODE_END
#endif

#ifndef OCCI_ORACLE
# include <occi.h>
#endif

OTT_USERCODE_START
#include "mymdemo1.h"

OTT_USERCODE_END




/************************************************************/
//  generated declarations for the ADDRESS_O object type.
/************************************************************/

class ADDRESS_O : public oracle::occi::PObject {

protected:

   OCCI_STD_NAMESPACE::string state;
   OCCI_STD_NAMESPACE::string zip;

public:

   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   void *operator new(size_t, void *ctxOCCI_);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   ADDRESS_O();
   ADDRESS_O(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);

OTT_USERCODE_START

    ADDRESS_O(string state_i, string zip_i);
    void displayInfo();

OTT_USERCODE_END

};

/************************************************************/
//  generated declarations for the FULL_NAME_O object type.
/************************************************************/

class FULL_NAME_O : public oracle::occi::PObject {

protected:

   OCCI_STD_NAMESPACE::string first_name;
   OCCI_STD_NAMESPACE::string last_name;

public:
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   void *operator new(size_t, void *ctxOCCI_);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   FULL_NAME_O();
   FULL_NAME_O(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

OTT_USERCODE_START

class FullName : public FULL_NAME_O {
public:
   FullName(string FirstName, string LastName);
   void displayInfo();
   const string getFirstName() const { return first_name;}}; 

OTT_USERCODE_END

/************************************************************/ 
// generated declarations for the PERSON_O object type. 
/************************************************************/ 
class PERSON_O : public oracle::occi::PObject { 

protected: 
   oracle::occi::Number id;
   FullName * name;
   oracle::occi::Ref< ADDRESS_O > addr;

public:
   void *operator new(size_t size); 
   void *operator new(size_t size, const oracle::occi::Connection * sess, 
   const OCCI_STD_NAMESPACE::string& table); 
   void *operator new(size_t, void *ctxOCCI_); 
   OCCI_STD_NAMESPACE::string getSQLTypeName() const; 
   PERSON_O(); 
   PERSON_O(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { }; 
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_); 
   static void writeSQL(void *objOCCI_, void *ctxOCCI_); 
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_); 
}; 

OTT_USERCODE_START 

class Person : public PERSON_O { 

public: 
   Person(int id_i, 
   FullName* name_i, 
   Ref<ADDRESS_O>& addr_i); 
   void move(const Ref<ADDRESS_O>& new_addr); 
   void displayInfo(); 
}; 
OTT_USERCODE_END 

#endif 
 

mdemo1o.cpp

// ------------------------------------------------------------
//  mdemo1o.cpp : OTT generated .cpp file with user added code
// ------------------------------------------------------------
#ifndef OTT_USERCODE_START
# define OTT_USERCODE_START
#endif

#ifndef OTT_USERCODE_END
# define OTT_USERCODE_END
#endif

#ifndef MDEMO1_ORACLE
# include "mdemo1.h"
#endif

OTT_USERCODE_START

// initialize FullName
FullName::FullName(string FirstName, string LastName)
{
  first_name = FirstName;
  last_name = LastName;
}

// display all the information in FullName
void FullName::displayInfo()
{
  cout << "FIRST NAME is " << first_name << endl;
  cout << "LAST NAME is " << last_name << endl;
}

// initialize ADDRESS_O
ADDRESS_O::ADDRESS_O(string state_i, string zip_i)
{
 state = state_i;
 zip = zip_i;
}

// display all the information in ADDRESS_O
void ADDRESS_O::displayInfo()
{
  cout << "STATE is " << state << endl;
  cout << "ZIP is " << zip << endl;
}

// initialize Person
Person::Person(int id_i,
               FullName *name_i,
               Ref<ADDRESS_O>& addr_i)
{
  id = id_i;
  name = name_i;
  addr =addr_i ;
}

// Move Person from curr_addr to new_addr
void Person::move(const Ref<ADDRESS_O>& new_addr)
{
  addr = new_addr;
  this->markModified();   // mark the object as dirty
}

// Display all the information of Person
void Person::displayInfo() {
  cout << "ID is " << (int)id << endl;
  name->displayInfo();

  // de-referencing the Ref attribute using -> operator
  addr->displayInfo();

}

OTT_USERCODE_END




/*****************************************************************/
//  generated method implementations for the ADDRESS_O object type.
/*****************************************************************/

void *ADDRESS_O::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *ADDRESS_O::operator new(size_t size, const oracle::occi::Connection * 
sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "MDEMO1.ADDRESS_O");
}

void *ADDRESS_O::operator new(size_t size, void *ctxOCCI_)
{
 return oracle::occi::PObject::operator new(size, ctxOCCI_);
}

OCCI_STD_NAMESPACE::string ADDRESS_O::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("MDEMO1.ADDRESS_O");
}

ADDRESS_O::ADDRESS_O()
{
}

void *ADDRESS_O::readSQL(void *ctxOCCI_)
{
  ADDRESS_O *objOCCI_ = new(ctxOCCI_) ADDRESS_O(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void ADDRESS_O::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   state = streamOCCI_.getString();
   zip = streamOCCI_.getString();
}

void ADDRESS_O::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  ADDRESS_O *objOCCI_ = (ADDRESS_O *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void ADDRESS_O::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setString(state);
   streamOCCI_.setString(zip);
}

/*****************************************************************/
//  generated method implementations for the FULL_NAME_O object type.
/*****************************************************************/

void *FULL_NAME_O::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *FULL_NAME_O::operator new(size_t size, const oracle::occi::Connection * 
sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "MDEMO1.FULL_NAME_O");
}

void *FULL_NAME_O::operator new(size_t size, void *ctxOCCI_)
{
 return oracle::occi::PObject::operator new(size, ctxOCCI_);
}

OCCI_STD_NAMESPACE::string FULL_NAME_O::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("MDEMO1.FULL_NAME_O");
}

FULL_NAME_O::FULL_NAME_O()
{
}

void *FULL_NAME_O::readSQL(void *ctxOCCI_)
{
  FULL_NAME_O *objOCCI_ = new(ctxOCCI_) FULL_NAME_O(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void FULL_NAME_O::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   first_name = streamOCCI_.getString();
   last_name = streamOCCI_.getString();
}

void FULL_NAME_O::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  FULL_NAME_O *objOCCI_ = (FULL_NAME_O *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void FULL_NAME_O::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setString(first_name);
   streamOCCI_.setString(last_name);
}

/*****************************************************************/
//  generated method implementations for the PERSON_O object type.
/*****************************************************************/

void *PERSON_O::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *PERSON_O::operator new(size_t size, const oracle::occi::Connection * 
sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "MDEMO1.PERSON_O");
}

void *PERSON_O::operator new(size_t size, void *ctxOCCI_)
{
 return oracle::occi::PObject::operator new(size, ctxOCCI_);
}

OCCI_STD_NAMESPACE::string PERSON_O::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("MDEMO1.PERSON_O");
}

PERSON_O::PERSON_O()
{
   name = (FullName *) 0;
}

void *PERSON_O::readSQL(void *ctxOCCI_)
{
  PERSON_O *objOCCI_ = new(ctxOCCI_) PERSON_O(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void PERSON_O::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   id = streamOCCI_.getNumber();
   name = (FullName *) streamOCCI_.getObject();
   addr = streamOCCI_.getRef();
}

void PERSON_O::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  PERSON_O *objOCCI_ = (PERSON_O *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void PERSON_O::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setNumber(id);
   streamOCCI_.setObject(name);
   streamOCCI_.setRef(addr);
}

mdemo1m.cpp

// -------------------------------------
//  mdemo1m.cpp: OTT generated map file
// -------------------------------------
#ifndef MDEMO1M_ORACLE
# include "mdemo1m.h"
#endif

void mdemo1m(oracle::occi::Environment* envOCCI_)
{
  oracle::occi::Map *mapOCCI_ = envOCCI_->getMap();
  mapOCCI_->put("MDEMO1.ADDRESS_O", ADDRESS_O::readSQL, ADDRESS_O::writeSQL);
  mapOCCI_->put("MDEMO1.FULL_NAME_O", FULL_NAME_O::readSQL, FULL_NAME_
O::writeSQL);
  mapOCCI_->put("MDEMO1.PERSON_O", PERSON_O::readSQL, PERSON_O::writeSQL);
}

mdemo1m.h

// ----------------------------------------------------
//  mdemo1m.h : OTT generated header file for map file
// ----------------------------------------------------
#ifndef MDEMO1M_ORACLE
# define MDEMO1M_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif

#ifndef MDEMO1_ORACLE
# include "mdemo1.h"
#endif

void mdemo1m(oracle::occi::Environment* envOCCI_);

#endif

mymdemo1.h

// ---------------------------------------
//  mymdemo1.h : User defined header file
// ---------------------------------------
#include <iostream>

#define USERNAME "scott"
#define PASSWORD "tiger"

using namespace oracle::occi;
using namespace std;

mdemo1.cpp

// ----------------------------------------
//  mdemo1.cpp : User defined main program
// ----------------------------------------
#include "mdemo1.h"
#include "mdemo1m.h"

// global Oracle variables

Environment     *env;
Connection      *conn;
Statement       *stmt;
ResultSet       *rs;

void initialize() {

  // Create environment
  env = Environment::createEnvironment(Environment::OBJECT);

  // Call the OTT generated function to register the mappings
  mdemo1m(env);

  // Create Connection
  conn = env->createConnection( USERNAME, PASSWORD );

  // Create a statement
  stmt = conn->createStatement();
}

void terminate() {

  // Terminate statement
  conn->terminateStatement(stmt);

  // Terminate connection
  env->terminateConnection(conn);

  // Terminate environment
  Environment::terminateEnvironment(env);
}

/* Do the work.
   The environment is set up.
   A single new entry is created in the Address table.
   Then it is committed.
*/
void dowrite() {

  // Create an Address
  ADDRESS_O *addr1 = new(conn, "ADDR_TAB") ADDRESS_O("GE", "1211");
  Ref<ADDRESS_O> addr1_ref = (Ref<ADDRESS_O>) addr1->getRef();

  // Create joe black
  FullName *name1= new FullName("Joe", "Black");

  Person *person1 =
    new(conn, "PERSON_TAB") Person(1,name1,addr1_ref);
  Ref<Person> person1_ref = (Ref<Person>) person1->getRef();

  // Display, using reference
  cout<<"-------------------"<<endl;
  person1_ref->displayInfo();
  cout<<"-------------------"<<endl;

  // Commit the changes
  conn->commit();

  // Clean up
  delete name1;
}

void doread()
{
  // Retrieve joe black
  string sel_joe = "SELECT REF(p) from person_tab p where \"id\" = 1";
  
  rs =stmt->executeQuery (sel_joe);
  rs =stmt->getResultSet ();
  
  // Get reference
  rs->next();
  Ref<Person> joe_ref = (Ref<Person>) rs->getRef(1);

  // Display, using reference
  cout<<"-------------------"<<endl;
  joe_ref->displayInfo();
  cout<<"-------------------"<<endl;

}

int main() {

  try {
    initialize();
    dowrite();
    doread();
    terminate();
  }
  catch (SQLException &e) {
    cout << "SQL exception :" << e.getMessage() << endl;
  }

  return 0;
}

Output of the program

-------------------
ID is 1
FIRST NAME is Joe
LAST NAME is Black
STATE is GE
ZIP is 1211
-------------------
-------------------
ID is 1
FIRST NAME is Joe                 
LAST NAME is Black               
STATE is GE                  
ZIP is 1211                
-------------------

Example OCCI Application

This OCCI application example extends the OTT-generated C++ classes and translates inherited object types. Each class in this application contains a constructor to initialize class objects and a method to display the values assigned to the attributes of the object. The MyPerson class also has a method to change the curr_addr attribute. All the classes here are derived from the generated classes.

Create the needed types and tables for the OCCI application as illustrated in the following code example:

connect scott/tiger
create type full_name as object (first_name char(20), last_name char(20));
create type address as object (state char(20), zip char(20));
create type address_tab as varray(3) of ref address;
create type person as object (id number, name full_name, 
    curr_addr ref address, prev_addr_l address_tab) not final;
create type student under person (school_name char(20));

/* tables needed in the user-written occi application */
create table addr_tab of address;
create table person_tab of person;
create table student_tab of student;

The INTYPE file provided to the OTT utility contains the following information:

 CASE = SAME
 MAPFILE = registerMappings.cpp
 TYPE FULL_NAME GENERATE CFullName AS MyFullName
 HFILE=cfullname.h
 CPPFILE=cfullname.cpp
 TRANSLATE first_name as FirstName
 last_name as LastName
 TYPE ADDRESS GENERATE CAddress AS MyAddress
 HFILE=caddress.h
 CPPFILE=caddress.cpp
 TYPE PERSON GENERATE CPerson AS MyPerson
 HFILE=cperson.h
 CPPFILE=cperson.cpp
 TYPE STUDENT GENERATE CStudent AS MyStudent
 HFILE=cstudent.h
 CPPFILE=cstudent.cpp

Note:

PERSON and PFGRFDENT must be generated in separate files because PERSON is an extended class and it is the base class for PFGRFDENT.


To invoke the OTT utility, use the following command line statement:

ott userid=scott/tiger code=cpp attraccess=private intype=demoin.typ 
outtype=demoout.typ

Note:

attraccess=private is specified because accessors and mutators are used to access the attributes.


The files generated by the OTT utility for this example are shown in the following sections:

Example of the Declarations for Object Type FULL_NAME: cfullname.h

#ifndef CFULLNAME_ORACLE
# define CFULLNAME_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif


/************************************************************/
//  generated declarations for the FULL_NAME object type.
/************************************************************/

class CFullName : public oracle::occi::PObject {

private:

   OCCI_STD_NAMESPACE::string FirstName;
   OCCI_STD_NAMESPACE::string LastName;

public:
   OCCI_STD_NAMESPACE::string getFirstname() const;
   void setFirstname(const OCCI_STD_NAMESPACE::string &value);
   OCCI_STD_NAMESPACE::string getLastname() const;   void setLastname(const OCCI_STD_NAMESPACE::string &value);
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   CFullName();
   CFullName(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);

};

#endif

Example of the Declarations for Object Type ADDRESS: caddress.h

#ifndef CADDRESS_ORACLE
#define CADDRESS_ORACLE

#ifndef OCCI_ORACLE
#include <occi.h>
#endif


/************************************************************/
//  generated declarations for the ADDRESS object type.
/************************************************************/

class CAddress : public oracle::occi::PObject {

private:

   OCCI_STD_NAMESPACE::string STATE;
   OCCI_STD_NAMESPACE::string ZIP;

public:
   OCCI_STD_NAMESPACE::string getState() const;
   void setState(const OCCI_STD_NAMESPACE::string &value);
   OCCI_STD_NAMESPACE::string getZip() const;
   void setZip(const OCCI_STD_NAMESPACE::string &value);
   void *operator new(size_t size);
   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);
   OCCI_STD_NAMESPACE::string getSQLTypeName() const;
   CAddress();
   CAddress(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
   static void *readSQL(void *ctxOCCI_);
   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
   static void writeSQL(void *objOCCI_, void *ctxOCCI_);
   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};

#endif

Example of Declarations for Object Type PERSON: cperson.h

#ifndef CPERSON_ORACLE
# define CPERSON_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif

#ifndef MYFULLNAME_ORACLE
# include "myfullname.h"
#endif

#ifndef MYADDRESS_ORACLE
# include "myaddress.h"
#endif


/************************************************************/
//  generated declarations for the PERSON object type.
/************************************************************/

class CPerson : public oracle::occi::PObject {

private:

   oracle::occi::Number ID;
   MyFullName * NAME;
   oracle::occi::Ref< MyAddress > CURR_ADDR;
   OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< MyAddress > > PREV_ADDR_L;

public:

   oracle::occi::Number getId() const;

   void setId(const oracle::occi::Number &value);

   MyFullName * getName() const;

   void setName(MyFullName * value);

   oracle::occi::Ref< MyAddress > getCurr_addr() const;

   void setCurr_addr(const oracle::occi::Ref< MyAddress > &value);

   OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< MyAddress > >& getPrev_addr_
l();

   const OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< MyAddress > >& getPrev_
addr_l() const;

   void setPrev_addr_l(const OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< 
MyAddress > > &value);

   void *operator new(size_t size);

   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);

   OCCI_STD_NAMESPACE::string getSQLTypeName() const;

   CPerson();

   CPerson(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };

   static void *readSQL(void *ctxOCCI_);

   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);

   static void writeSQL(void *objOCCI_, void *ctxOCCI_);

   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);

};

#endif

Example for Declarations for Object Type STUDENT: cstudent.h

#ifndef CSTUDENT_ORACLE
# define CSTUDENT_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif

#ifndef myPERSON_ORACLE
# include "myperson.h"
#endif


/************************************************************/
//  generated declarations for the STUDENT object type.
/************************************************************/

class CStudent : public MyPerson {

private:

   OCCI_STD_NAMESPACE::string SCHOOL_NAME;

public:

   OCCI_STD_NAMESPACE::string getSchool_name() const;

   void setSchool_name(const OCCI_STD_NAMESPACE::string &value);

   void *operator new(size_t size);

   void *operator new(size_t size, const oracle::occi::Connection * sess,
      const OCCI_STD_NAMESPACE::string& table);

   OCCI_STD_NAMESPACE::string getSQLTypeName() const;

   CStudent();

   CStudent(void *ctxOCCI_) : MyPerson (ctxOCCI_) { };

   static void *readSQL(void *ctxOCCI_);

   virtual void readSQL(oracle::occi::AnyData& streamOCCI_);

   static void writeSQL(void *objOCCI_, void *ctxOCCI_);

   virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);

};

#endif

Example of C++ Source File for Object Type FULLNAME: cfullname.cpp

#ifndef CFULLNAME_ORACLE
# include "cfullname.h"
#endif


/*****************************************************************/
//  generated method implementations for the FULL_NAME object type.
/*****************************************************************/

OCCI_STD_NAMESPACE::string CFullName::getFirstname() const
{
  return FirstName;
}

void CFullName::setFirstname(const OCCI_STD_NAMESPACE::string &value)
{
  FirstName = value;
}

OCCI_STD_NAMESPACE::string CFullName::getLastname() const
{
  return LastName;
}

void CFullName::setLastname(const OCCI_STD_NAMESPACE::string &value)
{
  LastName = value;
}

void *CFullName::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *CFullName::operator new(size_t size, const oracle::occi::Connection * 
sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.FULL_NAME");
}

OCCI_STD_NAMESPACE::string CFullName::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.FULL_NAME");
}

CFullName::CFullName()
{
}

void *CFullName::readSQL(void *ctxOCCI_)
{
  CFullName *objOCCI_ = new CFullName(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void CFullName::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   FirstName = streamOCCI_.getString();
   LastName = streamOCCI_.getString();
}

void CFullName::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  CFullName *objOCCI_ = (CFullName *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void CFullName::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setString(FirstName);
   streamOCCI_.setString(LastName);
}

Example of C++ Source File for Object Type ADDRESS: caddress.cpp

#ifndef CADDRESS_ORACLE
# include "caddress.h"
#endif


/*****************************************************************/
//  generated method implementations for the ADDRESS object type.
/*****************************************************************/

OCCI_STD_NAMESPACE::string CAddress::getState() const
{
  return STATE;
}

void CAddress::setState(const OCCI_STD_NAMESPACE::string &value)
{
  STATE = value;
}

OCCI_STD_NAMESPACE::string CAddress::getZip() const
{
  return ZIP;
}

void CAddress::setZip(const OCCI_STD_NAMESPACE::string &value)
{
  ZIP = value;
}

void *CAddress::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *CAddress::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.ADDRESS");
}

OCCI_STD_NAMESPACE::string CAddress::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.ADDRESS");
}

CAddress::CAddress()
{
}

void *CAddress::readSQL(void *ctxOCCI_)
{
  CAddress *objOCCI_ = new CAddress(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void CAddress::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   STATE = streamOCCI_.getString();
   ZIP = streamOCCI_.getString();
}

void CAddress::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  CAddress *objOCCI_ = (CAddress *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void CAddress::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setString(STATE);
   streamOCCI_.setString(ZIP);
}

Example of C++ Source File for Object Type PERSON: cperson.cpp

#ifndef CPERSON_ORACLE
# include "cperson.h"
#endif


/*****************************************************************/
//  generated method implementations for the PERSON object type.
/*****************************************************************/

oracle::occi::Number CPerson::getId() const
{
  return ID;
}

void CPerson::setId(const oracle::occi::Number &value)
{
  ID = value;
}

MyFullName * CPerson::getName() const
{
  return NAME;
}

void CPerson::setName(MyFullName * value)
{
  NAME = value;
}

oracle::occi::Ref< MyAddress > CPerson::getCurr_addr() const
{
  return CURR_ADDR;
}

void CPerson::setCurr_addr(const oracle::occi::Ref< MyAddress > &value)
{
  CURR_ADDR = value;
}

OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< MyAddress > >& CPerson::getPrev_
addr_l() 
{
  return PREV_ADDR_L;
}

const OCCI_STD_NAMESPACE::vector< oracle::occi::Ref< MyAddress > >& 
CPerson::getPrev_addr_l() const
{
  return PREV_ADDR_L;
}

void CPerson::setPrev_addr_l(const OCCI_STD_NAMESPACE::vector< 
oracle::occi::Ref< MyAddress > > &value)
{
  PREV_ADDR_L = value;
}

void *CPerson::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *CPerson::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.PERSON");
}

OCCI_STD_NAMESPACE::string CPerson::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.PERSON");
}

CPerson::CPerson()
{
   NAME = (MyFullName *) 0;
}

void *CPerson::readSQL(void *ctxOCCI_)
{
  CPerson *objOCCI_ = new CPerson(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void CPerson::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   ID = streamOCCI_.getNumber();
   NAME = (MyFullName *) streamOCCI_.getObject();
   CURR_ADDR = streamOCCI_.getRef();
   getVector(streamOCCI_, PREV_ADDR_L);
}

void CPerson::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  CPerson *objOCCI_ = (CPerson *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void CPerson::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   streamOCCI_.setNumber(ID);
   streamOCCI_.setObject(NAME);
   streamOCCI_.setRef(CURR_ADDR);
   setVector(streamOCCI_, PREV_ADDR_L);
}

Example of C++ Source File for Object Type STUDENT: cstudent.cpp

#ifndef CSTUDENT_ORACLE
# include "cstudent.h"
#endif


/*****************************************************************/
//  generated method implementations for the STUDENT object type.
/*****************************************************************/

OCCI_STD_NAMESPACE::string CStudent::getSchool_name() const
{
  return SCHOOL_NAME;
}

void CStudent::setSchool_name(const OCCI_STD_NAMESPACE::string &value)
{
  SCHOOL_NAME = value;
}

void *CStudent::operator new(size_t size)
{
  return oracle::occi::PObject::operator new(size);
}

void *CStudent::operator new(size_t size, const oracle::occi::Connection * sess,
  const OCCI_STD_NAMESPACE::string& table)
{
  return oracle::occi::PObject::operator new(size, sess, table, 
            (char *) "SCOTT.STUDENT");
}

OCCI_STD_NAMESPACE::string CStudent::getSQLTypeName() const
{
  return OCCI_STD_NAMESPACE::string("SCOTT.STUDENT");
}

CStudent::CStudent()
{
}

void *CStudent::readSQL(void *ctxOCCI_)
{
  CStudent *objOCCI_ = new CStudent(ctxOCCI_);
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (streamOCCI_.isNull())
      objOCCI_->setNull();
    else
      objOCCI_->readSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    delete objOCCI_;
    excep.setErrorCtx(ctxOCCI_);
    return (void *)NULL;
  }
  return (void *)objOCCI_;
}

void CStudent::readSQL(oracle::occi::AnyData& streamOCCI_)
{
   CPerson::readSQL(streamOCCI_);
   SCHOOL_NAME = streamOCCI_.getString();
}

void CStudent::writeSQL(void *objectOCCI_, void *ctxOCCI_)
{
  CStudent *objOCCI_ = (CStudent *) objectOCCI_;
  oracle::occi::AnyData streamOCCI_(ctxOCCI_);

  try
  {
    if (objOCCI_->isNull())
      streamOCCI_.setNull();
    else
      objOCCI_->writeSQL(streamOCCI_);
  }
  catch (oracle::occi::SQLException& excep)
  {
    excep.setErrorCtx(ctxOCCI_);
  }
  return;
}

void CStudent::writeSQL(oracle::occi::AnyData& streamOCCI_)
{
   CPerson::writeSQL(streamOCCI_);
   streamOCCI_.setString(SCHOOL_NAME);
}

Example of Register Mappings Header File: registerMappings.h

#ifndef REGISTERMAPPINGS_ORACLE
# define REGISTERMAPPINGS_ORACLE

#ifndef OCCI_ORACLE
# include <occi.h>
#endif

#ifndef CFULLNAME_ORACLE
# include "cfullname.h"
#endif

#ifndef CADDRESS_ORACLE
# include "caddress.h"
#endif

#ifndef CPERSON_ORACLE
# include "cperson.h"
#endif

#ifndef CSTUDENT_ORACLE
# include "cstudent.h"
#endif

void registerMappings(oracle::occi::Environment* envOCCI_);

#endif

Example of C++ Source File for Register Mappings: registerMappings.cpp

#ifndef REGISTERMAPPINGS_ORACLE
 #include "registerMappings.h"
 #endif
 void registerMappings(oracle::occi::Environment* envOCCI_)
 {
 oracle::occi::Map *mapOCCI_ = envOCCI_->getMap();
 mapOCCI_->put("SCOTT.FULL_NAME", CFullName::readSQL, CFullName::writeSQL);
 mapOCCI_->put("SCOTT.ADDRESS", CAddress::readSQL, CAddress::writeSQL);
 mapOCCI_->put("SCOTT.PERSON", CPerson::readSQL, CPerson::writeSQL);
 mapOCCI_->put("SCOTT.STUDENT", CStudent::readSQL, CStudent::writeSQL);
}

Note:

This demo extends types that are used as attributes and base classes of other generated types. cperson.h #includes myfullname.h and myaddress.h. cstudent.h #includes myperson.h. PERSON and PFGRFDENT must be generated in separate files because PERSON is an extended class and it is the base class for PFGRFDENT.


Example of User-Written Extension File: myfullname.h

#ifndef MYFULLNAME_ORACLE
# define MYFULLNAME_ORACLE

using namespace oracle::occi;
using namespace std;

#ifndef CFULLNAME_ORACLE
#include "cfullname.h"
#endif

/*********************************************************************/
// declarations for the MyFullName class.
/*********************************************************************/
class MyFullName : public CFullName {
 public:
   MyFullName(string first_name, string last_name);
   void displayInfo();
};

#endif

Example of User-Written Extension File: myaddress.h

#ifndef MYADDRESS_ORACLE
# define MYADDRESS_ORACLE

using namespace oracle::occi;
using namespace std;

#ifndef CADDRESS_ORACLE
#include "caddress.h"
#endif

/*********************************************************************/
// declarations for the MyAddress class.
/*********************************************************************/
class MyAddress : public CAddress {
 public:
   MyAddress(string state_i, string zip_i);
   void displayInfo();
};

#endif

Example of User-Written Extension File: myperson.h

#ifndef MYPERSON_ORACLE
# define MYPERSON_ORACLE

using namespace oracle::occi;
using namespace std;

#ifndef CPERSON_ORACLE
#include "cperson.h"
#endif

/*********************************************************************/
// declarations for the MyPerson class.
/*********************************************************************/
class MyPerson : public CPerson {
 public:
   MyPerson();
   MyPerson(void *ctxOCCI_) : CPerson(ctxOCCI_) { };
   MyPerson(Number id_i, MyFullName *name_i,const Ref<MyAddress>& addr_i);
   void move(const Ref<MyAddress>& new_addr);
   void displayInfo();
};

#endif

Example of User-Written Extension File: mystudent.h

#ifndef MYSTUDENT_ORACLE
# define MYSTUDENT_ORACLE

using namespace oracle::occi;
using namespace std;

#ifndef CSTUDENT_ORACLE
#include "cstudent.h"
#endif

/*********************************************************************/
// declarations for the MyStudent class.
/*********************************************************************/
class MyStudent : public CStudent {
 public:
   MyStudent(Number id_i, MyFullName *name_i, Ref<MyAddress>& addr_i, string 
school_name);
   void displayInfo();
};

#endif

Example of User-Written Extension File: mydemo.cpp

#include <occi.h>

using namespace oracle::occi;
using namespace std;
#include "registerMappings.h"
#include "myfullname.h"
#include "myaddress.h"
#include "myperson.h"
#include "mystudent.h"
/*********************************************************************/
// method implementations for MyFullName class.
/********************************************************************/
 
/* initialize MyFullName */
MyFullName::MyFullName(string first_name, string last_name)
  {
   setFirstname(first_name);
   setLastname(last_name);
  }
 
/* display all the information in MyFullName */
void MyFullName::displayInfo()
  {
   cout << "FIRST NAME is: " << getFirstname() << endl;
   cout << "LAST NAME is: " << getLastname() << endl;
  }

/*********************************************************************/
// method implementations for MyAddress class.
/********************************************************************/
 
/* initialize MyAddress */
MyAddress::MyAddress(string state_i, string zip_i)
  {
   setState(state_i);
   setZip(zip_i);
  }
 
/* display all the information in MyAddress */
void MyAddress::displayInfo()
  {
   cout << "STATE is: " << getState() << endl;
   cout << "ZIP is: " << getZip() << endl;
  }
  
/**********************************************************************/
// method implementations for MyPerson class.
/**********************************************************************/
 
/* Default constructor needed because CStudent inherits from MyPerson */
MyPerson::MyPerson(){}
  
/* initialize MyPerson */
MyPerson::MyPerson(Number id_i, MyFullName* name_i, const Ref<MyAddress>& addr_i)
  {
   setId(id_i);
   setName(name_i);
   setCurr_addr(addr_i);
  }
 
/* Move Person from curr_addr to new_addr */
void MyPerson::move(const Ref<MyAddress>& new_addr)
  {
   // append curr_addr to the vector
   getPrev_addr_l().push_back(getCurr_addr());
   setCurr_addr(new_addr);
   this->markModified();
  }
 
/* Display all the information of MyPerson */
void MyPerson::displayInfo()
  {
   cout << "----------------------------------- " << endl;
   cout << "ID is: " << (int)getId() << endl;
   getName()->displayInfo();
  
   // de-referencing the Ref attribute using -> operator
   getCurr_addr()->displayInfo();
   cout << "Prev Addr List: " << endl;
   for (int i = 0; i < getPrev_addr_l().size(); i++)
      {
       // access the collection elements using [] operator
       getPrev_addr_l()[i]->displayInfo();
      }
  }
 
/*********************************************************************/
// method implementations for MyStudent class.
/********************************************************************/
 
/* initialize MyStudent */
MyStudent::MyStudent(Number id_i, MyFullName *name_i, Ref<MyAddress>& addr_i, string school_name_i)
  {
   setId(id_i);
   setName(name_i);
   setCurr_addr(addr_i);
   setSchool_name(school_name_i);
  }
 
/* display the information in MyStudent */
void MyStudent::displayInfo()
  {
   MyPerson::displayInfo();
   cout << "SCHOOL NAME is: " << getSchool_name() << endl;
  }
 
void process(Connection *conn)
  {
   /* creating a persistent object of type Address in the connection,
   conn, and the database table, ADDR_TAB */
   MyAddress *addr1 = new(conn, "ADDR_TAB") MyAddress("CA", "94065");

   /* commit the transaction which results in the newly created object, addr1,
   being flushed to the server */
   conn->commit();
   MyFullName name1("Joe", "Black");

   /* creating a persistent object of type Person in the connection,
   conn, and the database table, PERSON_TAB */
   MyPerson *person1 = new(conn, "PERSON_TAB") MyPerson(1,&name1,
      addr1->getRef());

   /* commit the transaction which results in the newly created object,
   person1 being flushed to the server */
   conn->commit();
   Statement *stmt = conn->createStatement(
     "SELECT REF(per) from person_tab per ");
   ResultSet *resultSet = stmt->executeQuery();
   if (!resultSet->next())
       {
        cout << "No record found \n";
       }
   RefAny joe_refany = resultSet->getRef(1);
   Ref <MyPerson> joe_ref(joe_refany);

   /* de-referencing Ref using ptr() operator. operator -> and operator *
   also could be used to de-reference the Ref. As part of de-referencing,
   if the referenced object is not found in the application cache, the object
   data is retrieved from the server and unmarshalled into Person instance
   through MyPerson::readSQL() method. */
   MyPerson *joe = joe_ref.ptr();
   joe->displayInfo();

   /* creating a persistent object of type MyAddress, in the connection,
   conn and the database table, ADDR_TAB */
   MyAddress *new_addr1 = new(conn, "ADDR_TAB") MyAddress("PA", "92140");
   conn->commit();
   joe->move(new_addr1->getRef());
   joe->displayInfo();

   /* commit the transaction which results in the newly created object,
   new_addr1 and the dirty object, joe to be flushed to the server. */
   conn->commit();
   MyAddress *addr2 = new(conn, "ADDR_TAB") MyAddress("CA", "95065");
   MyFullName name2("Jill", "White");
   Ref<MyAddress> addrRef = addr2->getRef();
   MyStudent *student2 = new(conn, "STUDENT_TAB") MyStudent(2, &name2,
      addrRef, "Stanford");
   conn->commit();
   Statement *stmt2 = conn->createStatement(
      "SELECT REF(Student) from student_tab Student where id = 2");
   ResultSet *resultSet2 = stmt2->executeQuery();
   if (!resultSet2->next())
     {
      cout << "No record found \n";
     }
   RefAny jillrefany = resultSet2->getRef(1);
   Ref <MyStudent> jill_ref(jillrefany);
   MyStudent *jill = jill_ref.ptr();
   cout << jill->getPrev_addr_l().size();
   jill->displayInfo();
   MyAddress *new_addr2 = new(conn, "ADDR_TAB") MyAddress("CO", "80021");
   conn->commit();
   jill->move(new_addr2->getRef());
   jill->displayInfo();
   jill->markModified();
   conn->commit();

   /* The following delete statements delete the objects only from the
   application cache. To delete the objects from the server, mark_deleted()
   should be used. */
   delete person1;>
   delete addr1;
   delete new_addr1;
   delete addr2;
   delete student2;
   delete new_addr2;
   conn->terminateStatement(stmt);
   conn->terminateStatement(stmt2);
 }

 /***************************************************************************/
 // main function of this OCCI application.
 // This application connects to the database as scott/tiger, creates
 // the Person (Joe Black) whose Address is in CA, and commits the changes.
 // The Person object is then retrieved from the database and its
 // information is displayed. A second Address object is created (in PA),
 // then the previously retrieved Person object (Joe Black) is moved to
 // this new address. The Person object is then displayed again.
 // The similar commands are executed for "Jill White", a Student at Stanford,
 // who is moved from CA to CO.
/***************************************************************************/
int main()
 {
 Environment *env = Environment::createEnvironment(Environment::OBJECT );
  
/* Call the OTT generated function to register the mappings */
registerMappings(env);
 Connection *conn = env->createConnection("scott","tiger","");
 process(conn);
 env->terminateConnection(conn);
 Environment::terminateEnvironment(env);
 return 0;
}

Note:

Each extension class declaration must #include the generated header file of the class it is extending. For example, myfullname.h must #include cperson.h and mystudent.h must #include cstudent.h. mydemo.cpp must #include registerMappings.h in order to call the registerMapping function to register the mappings.


Output Generated by Example OTT Application

The output generated from the example OCCI application is:

-----------------------------------  
ID is:  1
FIRST NAME is:  Joe                 
LAST NAME is:  Black               
STATE is:  CA                  
ZIP is:  94065               
Prev Addr List: 
-----------------------------------  
ID is:  1
FIRST NAME is:  Joe                 
LAST NAME is:  Black               
STATE is:  PA                  
ZIP is:  92140               
Prev Addr List: 
STATE is:  CA                  
ZIP is:  94065               
-----------------------------------  
ID is:  2
FIRST NAME is:  Jill                
LAST NAME is:  White               
STATE is:  CA                  
ZIP is:  95065               
Prev Addr List: 
SCHOOL NAME is:  Stanford            
-----------------------------------  
ID is:  2
FIRST NAME is:  Jill                
LAST NAME is:  White               
STATE is:  CO                  
ZIP is:  80021               
Prev Addr List: 
STATE is:  CA                  
ZIP is:  95065               
SCHOOL NAME is:  Stanford            

OTT Utility Reference

Behavior of the OTT utility is controlled by parameters that are specified either on the OTT command line or in a CONFIG file. Certain parameters may also appear in the INTYPE file.

This section provides detailed information about the following topics:

OTT Command Line Syntax

The OTT command-line interface is used when explicitly invoking the OTT utility to translate database types into C structures or C++ classes. This is always required when developing OCI, OCCI, or Pro*C/C++ applications that use objects.

An OTT command line statement consists of the command OTT, followed by a list of OTT utility parameters.

The parameters that can appear on the OTT command line statement are listed alphabetically as follows:

[ATTRACCESS={PRIVATE|PROTECTED}]

[CASE={SAME|LOWER|UPPER|OPPOSITE}]

CODE={C|ANSI_C|KR_C|CPP}

[CONFIG=filename]

[CPPFILE=filename]

[ERRTYPE=filename]

[HFILE=filename]

[INITFILE=filename]

[INITFUNC=filename]

[INTYPE=filename]

[MAPFILE=filename]

[MAPFUNC=filename]

OUTTYPE=filename

[SCHEMA_NAMES={ALWAYS|IF_NEEDED|FROM_INTYPE}]

[TRANSITIVE={TRUE|FALSE}]

[USE_MARKER={TRUE|FALSE}]

[USERID=username/password[@db_name]]


Note:

Generally, the order of the parameters following the OTT command does not matter. The OUTTYPE and CODE parameters are always required.


The HFILE parameter is almost always used. If omitted, then HFILE must be specified individually for each type in the INTYPE file. If the OTT utility determines that a type not listed in the INTYPE file must be translated, then an error will be reported. Therefore, it is safe to omit the HFILE parameter only if the INTYPE file was previously generated as an OTT OUTTYPE file.

If the INTYPE file is omitted, then the entire schema will be translated. See the parameter descriptions in the following section for more information.

The following is an example of an OTT command line statement (enter it as one line):

ott userid=scott/tiger intype=in.typ outtype=out.typ code=c hfile=demo.h 
errtype=demo.tls case=lower

Each of the OTT command line parameters is described in the following section.

OTT Utility Parameters

Enter parameters on the OTT command line using the following format:

parameter=value

In this example, parameter is the literal parameter string and value is a valid parameter setting. The literal parameter string is not case sensitive.

Separate command line parameters by using either spaces or tabs.

Parameters can also appear within a configuration file, but, in that case, no whitespace is permitted within a line, and each parameter must appear on a separate line. Additionally, the parameters CASE, CPPFILE, HFILE, INITFILE, INTFUNC, MAPFILE, and MAPFUNC can appear in the INTYPE file.

OTT utility parameters are described in the following sections:

ATTRACCESS Parameter

For C++ only. This parameter instructs the OTT utility whether to generate PRIVATE or PROTECTED access for the type attributes. If PRIVATE is specified, the OTT utility generates an accessor (getxxx) and mutator (setxxx) method for each of the type attributes.

ATTRACCESS=PRIVATE|PROTECTED

The default is PROTECTED.

CASE Parameter

This parameter affects the case of certain C or C++ identifiers generated by the OTT utility. The valid values of CASE are SAME, LOWER, UPPER, and OPPOSITE.

If CASE=SAME, the case of letters is not changed when converting database type and attribute names to C or C++ identifiers.

If CASE=LOWER, then all uppercase letters are converted to lowercase.

If CASE=UPPER, then all lowercase letters are converted to uppercase.

If CASE=OPPOSITE, then all uppercase letters are converted to lowercase, and all lowercase letters are converted to uppercase.

CASE=[SAME|LOWER|UPPER|OPPOSITE]

This parameter affects only those identifiers (attributes or types not explicitly listed) not mentioned in the INTYPE file. Case conversion takes place after a legal identifier has been generated.

The case of the C structure identifier for a type specifically mentioned in the INTYPE file is the same as its case in the INTYPE file. For example, consider this line included in the INTYPE file:

TYPE Worker

The OTT utility generates the following C structure:

struct Worker {...};

On the other hand, consider an INTYPE file that includes the following line:

TYPE wOrKeR

The OTT utility generates this C structure, which follows the case specified in the INTYPE file:

struct wOrKeR {...};

Case insensitive SQL identifiers not mentioned in the INTYPE file will appear in uppercase if CASE=SAME, and in lowercase if CASE=OPPOSITE. A SQL identifier is case insensitive if it was not quoted when it was declared.

CODE Parameter

This parameter indicates which host language is to be output by the OTT utility. CODE=C is equivalent to CODE=ANSI_C. CODE=CPP must be specified for the OTT utility to generate C++ code for OCCI applications.

CODE=C|KR_C|ANSI_C|CPP

This parameter is required, and there is no default value. You must specify one of the host languages.

CONFIG Parameter

This parameter specifies the name of the OTT configuration file to be used. The configuration file lists commonly used parameter specifications. Parameter specifications are also read from a system configuration file found in an operating system-dependent location. All remaining parameter specifications must appear either on the command line or in the INTYPE file.

CONFIG=filename 

Note:

The CONFIG parameter can only be specified on the OTT command line. It is not allowed in the CONFIG file.


CPPFILE Parameter

For C++ only. This parameter specifies the name of the C++ source file that will contain the method implementations generated by the OTT utility.

This parameter is required under the following conditions:

The restrictions to this are similar to that of the existing HFILE parameter restrictions already in place for Pro*C/C++ and OCI. This parameter is optional when the CPPFILE is specified for individual types in the INTYPE file.

CPPFILE=filename

ERRTYPE Parameter

If you supply this parameter, then a listing of the INTYPE file is written to the ERRTYPE file, along with all information and error messages. Information and error messages are sent to the standard output whether or not the ERRTYPE parameter is specified.

Essentially, the ERRTYPE file is a copy of the INTYPE file with error messages added. In most cases, an error message will include a pointer to the text that caused the error.

If the filename specified for the ERRTYPE parameter on the command line does not include an extension, a platform-specific extension such as .TLS or .tls is automatically added.

ERRTYPE=filename

HFILE Parameter

This parameter specifies the name of the header (.h) file to be generated by the OTT utility. The HFILE specified on the command line contains the declarations of types that are mentioned in the INTYPE file but whose header files are not specified there.

This parameter is required unless the header file for each type is specified individually in the INTYPE file. This parameter is also required if a type not mentioned in the INTYPE file must be generated because other types require it, and these other types are declared in two or more different files.

If the filename specified for the HFILE parameter on the command line or in the INTYPE file does not include an extension, a platform-specific extension such as H or .h is automatically added.

HFILE=filename

INITFILE Parameter

For OCI only. This parameter specifies the name of the initialization file to be generated by the OTT utility. If you omit this parameter, then the initialization file will not be generated.

For Pro*C/C++ programs, the INITFILE is not necessary, because the SQLLIB run-time library performs the necessary initializations. An OCI programmer must compile and link the INITFILE files, and must call the initialization functions when an environment handle is created.

If the filename specified for the INITFILE parameter on the command line or in the INTYPE file does not include an extension, a platform-specific extension such as C or .c is automatically added.

INITFILE=filename

INITFUNC Parameter

For OCI only. This parameter specifies the name of the initialization function to be generated by the OTT utility.

This parameter is optional. If you omit this parameter, then the name of the initialization function is derived from the name of the INITFILE.

INITFUNC=filename

INTYPE Parameter

This parameter specifies the name of the file from which to read the list of object type specifications. The OTT utility translates each type in the list.

INTYPE=filename

INTYPE= may be omitted if USERID and INTYPE are the first two parameters, in that order, and USERID= is omitted. For example,

OTT username/password filename...

If the INTYPE parameter is not specified, all types in the user's schema will be translated.

The INTYPE file can be thought of as a makefile for type declarations. It lists the types for which C structure declarations or C++ classes are needed. The format of the INTYPE file is described in "Structure of the INTYPE File".

If the filename specified for the INTYPE parameter on the command line does not include an extension, a platform-specific extension such as TYP or .typ is automatically added.

See Also:

"Structure of the INTYPE File" for more information about the format of the INTYPE file

MAPFILE Parameter

For C++ only. This parameter specifies the name of the mapping file (.cpp) and corresponding header file (.h) that is generated by the OTT utility. The .cpp file contains the implementation of the functions to register the mappings while the .h file contains the prototype for the function.

This parameter is required for the generation of C++. If you specify CODE=CPP, then you must also specify a value for the MAPFILE parameter. Otherwise, the OTT utility generates an error.

This parameter may be specified either on the command line or in the INTYPE file.

MAPFILE=filename

MAPFUNC Parameter

For C++ only. This parameter specifies the name of the function to be used to register the mappings generated by the OTT utility.

This parameter is optional for the generation of C++. If this parameter is omitted, then the name of the function to register the mappings is derived from the filename specified in the MAPFILE parameter.

This parameter may be specified either on the command line or in the INTYPE file.

MAPFUNC=functionname

OUTTYPE Parameter

This parameter specifies the name of the file into which the OTT utility writes type information for all the object datatypes it processes. This file includes all types explicitly named in the INTYPE file, and may include additional types that are translated because they are used in the declarations of other types that need to be translated. This file may be used as an INTYPE file in a future invocation of the OTT utility.

OUTTYPE=filename

If the INTYPE and OUTTYPE parameters refer to the same file, then the new INTYPE information replaces the old information in the INTYPE file. This provides a convenient way for the same INTYPE file to be used repeatedly in the cycle of altering types, generating type declarations, editing source code, precompiling, compiling, and debugging.

This parameter is required.

If the filename specified for the OUTTYPE parameter on the command line or in the INTYPE file does not include an extension, a platform-specific extension such as TYP or .typ is automatically added.

SCHEMA_NAMES Parameter

This parameter offers control in qualifying the database name of a type from the default schema with a schema name in the OUTTYPE file. The OUTTYPE file generated by the OTT utility contains information about the types processed by the OTT utility, including the type names.

SCHEMA_NAMES=ALWAYS|IF_NEEDED|FROM_INTYPE

The default value is ALWAYS.

See Also:

"SCHEMA_NAMES Usage" for further information

TRANSITIVE Parameter

This parameter indicates whether type dependencies not explicitly listed in the INTYPE file are to be translated. Valid values are TRUE and FALSE.

TRANSITIVE=TRUE|FALSE

The default value is TRUE.

If TRANSITIVE=TRUE is specified, then types needed by other types and not mentioned in the INTYPE file are generated.

If TRANSITIVE=FALSE is specified, then types not mentioned in the INTYPE file are not generated, even if they are used as attribute types of other generated types.

USE_MARKER Parameter

This parameter indicates whether OTT markers should be supported, if used, by OTT to carry forward user added. Valid values are TRUE and FALSE. The default value is FALSE.

USE_MARKER=TRUE|FALSE

The default value is FALSE.

If USE_MARKER=TRUE is specified, then the added code between the markers, OTT_USER_CODESTART and OTT_USERCODE_END will be carried forward when the same file is generated again.

If USE_MARKER=FALSE is specified, then the user added code will not be carried forward, even if the code is added between OTT_USERCODE_START and OTT_USERCODE_END markers.

USERID Parameter

This parameter specifies the Oracle username, password, and optional database name (Oracle Net database specification string). If the database name is omitted, the default database is assumed.

USERID=username/password[@db_name]

If this is the first parameter, then USERID= may be omitted as shown:

OTT username/password ...

This parameter is optional. If you omit this parameter, then the OTT utility automatically attempts to connect to the default database as user OPS$username, where username is the user's operating system username.

Where OTT Parameters Can Appear

Supply OTT parameters on the command line, in a CONFIG file named on the command line, or both. Some parameters are also allowed in the INTYPE file.

The OTT utility is invoked as follows:

OTT parameters

You can name a configuration file on the command line with the CONFIG parameter as follows:

CONFIG=filename

If you name this parameter on the command line, then additional parameters are read from the configuration file named filename.

In addition, parameters are also read from a default configuration file that resides in an operating system-dependent location. This file must exist, but can be empty. If you choose to enter data in the configuration file, note that no white space is allowed on a line and parameters must be entered one to a line.

If the OTT utility is executed without any arguments, then an online parameter reference is displayed.

The types for the OTT utility to translate are named in the file specified by the INTYPE parameter. The parameters CASE, CPPFILE, HFILE, INITFILE, INITFUNC, MAPFILE, and MAPFNC may also appear in the INTYPE file. OUTTYPE files generated by the OTT utility include the CASE parameter, and include the INITFILE, and INITFUNC parameters if an initialization file was generated or the MAPFILE and MAPFUNC parameters if C++ codes was generated. The OUTTYPE file, as well as the CPPFILE for C++, specifies the HFILE individually for each type.

The case of the OTT command is operating system-dependent.

Structure of the INTYPE File

The INTYPE and OUTTYPE files list the types translated by the OTT utility and provide all the information needed to determine how a type or attribute name is translated to a legal C or C++ identifier. These files contain one or more type specifications. These files also may contain specifications of the following options:

If the CASE, INITFILE, INITFUNC, MAPFILE, or MAPFUNC options are present, then they must precede any type specifications. If these options appear both on the command line and in the INTYPE file, then the value on the command line is used.

See Also:

"Overview of the OUTTYPE File" for an example of a simple user-defined INTYPE file and of the full OUTTYPE file that the OTT utility generates from it

INTYPE File Type Specifications

A type specification in the INTYPE file names an object datatype that is to be translated. The following is an example of a user-created INTYPE file:

TYPE employee
  TRANSLATE SALARY$ AS salary
            DEPTNO AS department
TYPE ADDRESS
TYPE PURCHASE_ORDER AS p_o

The structure of a type specification is as follows:

TYPE type_name
[GENERATE type_identifier]
[AS type_identifier]
[VERSION [=] version_string]
[HFILE [=] hfile_name]
[CPPFILE [=] cppfile_name]
[TRANSLATE{member_name [AS identifier]}...]

The type_name syntax follows this form:

[schema_name.]type_name

In this syntax, schema_name is the name of the schema that owns the given object datatype, and type_name is the name of the type. The default schema, if one is not specified, is that of the userID invoking the OTT utility. To use a specific schema, you must use schema_name.

The components of the type specification are:

An object datatype may need to be translated for one of two reasons:

If a type that is not mentioned explicitly is required by types declared in exactly one file, then the translation of the required type is written to the same files as the explicitly declared types that require it.

If a type that is not mentioned explicitly is required by types declared in two or more different files, then the translation of the required type is written to the global HFILE file.


Note:

As of release 1 (9.0.1), you may indicate whether the OTT utility is to generate required object types that are not specified in the INTYPE file. Set TRANSITIVE=FALSE so the OTT utility will not to generate required object types. The default is TRANSITIVE=TRUE.


Nested #include File Generation

HFILE files generated by the OTT utility #include other necessary files, and #define a symbol constructed from the name of the file. This symbol #defined can then be used to determine if the related HFILE file has already been #included. Consider, for example, a database with the following types:

create type px1 AS OBJECT (col1 number, col2 integer);
create type px2 AS OBJECT (col1 px1);
create type px3 AS OBJECT (col1 px1);

The INTYPE file contains the following information:

CASE=lower
type pxl
  hfile tott95a.h
type px3
  hfile tott95b.h

You invoke the OTT utility as follows:

ott scott/tiger tott95i.typ outtype=tott95o.typ code=c

The OTT utility then generates the following two header files, named tott95a.h and tott95b.h.

The content of the tott95a.h file is as follows:

#ifndef TOTT95A_ORACLE
#define TOTT95A_ORACLE
#ifndef OCI_ORACLE
#include <oci.h>
#endif
typedef OCIRef px1_ref;
struct px1
{
   OCINumber col1;
   OCINumber col2;
}
typedef struct px1 px1;
struct px1_ind
{
   OCIInd _atomic;
   OCIInd col1;
   OCIInd col2;
}
typedef struct px1_ind px1_ind;
#endif

The content of the tott95b.h file is as follows:

#ifndef TOTT95B_ORACLE
#define TOTT95B_ORACLE
#ifndef OCI_ORACLE
#include <oci.h>
#endif
#ifndef TOTT95A_ORACLE
#include "tott95a.h"
#endif
typedef OCIRef px3_ref;
struct px3
{
   struct px1 col1;
};
typedef struct px3 px3;
struct px3_ind
{
   OCIInd _atomic;
   struct px1_ind col1
};
typedef struct px3_ind px3_ind;
#endif

In the tott95b.h file, the symbol TOTT95B_ORACLE is #defined at the beginning of the file. This enables you to conditionally #include this header file in another file. To accomplish this, you would use the following construct:

#ifndef TOTT95B_ORACLE
#include "tott95b.h"
#endif

By using this technique, you can #include tott95b.h in, say foo.h, without having to know whether some other file #included in foo.h also #includes tott95b.h.

After the definition of the symbol TOTT95B_ORACLE, the file oci.h is #included. Every HFILE generated by the OTT utility includes oci.h, which contains type and function declarations that the Pro*C/C++ or OCI programmer will find useful. This is the only case in which the OTT utility uses angle brackets in a #include.

Next, the file tott95a.h is included because it contains the declaration of struct px1, that tott95b.h requires. When the INTYPE file requests that type declarations be written to more than one file, the OTT utility determines which other files each HFILE must #include, and generates each necessary #include.

Note that the OTT utility uses quotes in this #include. When a program including tott95b.h is compiled, the search for tott95a.h begins where the source program was found, and will thereafter follow an implementation-defined search rule. If tott95a.h cannot be found in this way, then a complete filename (for example, a UNIX absolute path name beginning with a slash character (/)) should be used in the INTYPE file to specify the location of tott95a.h.

SCHEMA_NAMES Usage

This parameter affects whether the name of a type from the default schema, to which the OTT utility is connected, is qualified with a schema name in the OUTTYPE file.

The name of a type from a schema other that the default schema is always qualified with a schema name in the OUTTYPE file.

The schema name, or its absence, determines in which schema the type is found during program execution.

There are three valid values for the SCHEMA_NAMES parameter:

The OUTTYPE file generated by the OTT utility is the Pro*C/C++ INTYPE file. This file matches database type names to C structure names. This information is used at runtime to make sure that the correct database type is selected into the structure. If a type appears with a schema name in the OUTTYPE file (Pro*C/C++ INTYPE file), then the type is found in the named schema during program execution. If the type appears without a schema name, then the type is found in the default schema to which the program connects, which may be different from the default schema the OTT utility used.

Example of SCHEMA_NAMES Parameter Usage

Consider an example where the SCHEMA_NAMES parameter is set to FROM_INTYPE, and the INTYPE file contains the following:

TYPE Person
TYPE joe.Dept
TYPE sam.Company

The Pro*C/C++ application that uses the OTT-generated structures uses the types sam.Company, joe.Dept, and Person. Person without a schema name refers to the Person type in the schema to which the application is connected.

If the OTT utility and the application both connect to schema joe, then the application uses the same type (joe.Person) that the OTT utility uses. If the OTT utility connects to schema joe but the application connects to schema mary, then the application uses the type mary.Person. This behavior is appropriate only if the same CREATE TYPE Person statement has been executed in schema joe and schema mary.

On the other hand, the application uses type joe.Dept regardless of which schema the application is connected to. If this is the behavior you want, then be sure to include schema names with your type names in the INTYPE file.

In some cases, the OTT utility translates a type that the user did not explicitly name. For example, consider the following SQL declarations:

CREATE TYPE Address AS OBJECT
(
street    VARCHAR2(40),
city      VARCHAR(30),
state     CHAR(2),
zip_code  CHAR(10)
);

CREATE TYPE Person AS OBJECT
(
name      CHAR(20),
age       NUMBER,
addr      ADDRESS
);

Suppose that the OTT utility connects to schema joe, SCHEMA_NAMES=FROM_INTYPE is specified, and the user's INTYPE files include either

TYPE Person

or

TYPE joe.Person

The INTYPE file does not mention the type joe.Address, which is used as a nested object type in type joe.Person.

If Type Person appears in the INTYPE file, then TYPE Person and TYPE Address appears in the OUTTYPE file.

If TYPE joe.Person appears in the INTYPE file, then TYPE joe.Person and TYPE joe.Address appear in the OUTTYPE file.

If the joe.Address type is embedded in several types translated by the OTT utility, but it is not explicitly mentioned in the INTYPE file, then the decision of whether to use a schema name is made the first time the OTT utility encounters the embedded joe.Address type. If, for some reason, the user wants type joe.Address to have a schema name but does not want type Person to have one, then you must explicitly request this in the INTYPE file as follows:

TYPE      joe.Address

In the usual case in which each type is declared in a single schema, it is safest for you to qualify all type names with schema names in the INTYPE file.

Default Name Mapping

When the OTT utility creates a C or C++ identifier name for an object type or attribute, it translates the name from the database character set to a legal C or C++ identifier. First, the name is translated from the database character set to the character set used by the OTT utility. Next, if a translation of the resulting name is supplied in the INTYPE file, that translation is used. Otherwise, the OTT utility translates the name character-by-character to the compiler character set, applying the character case specified in the CASE parameter. The following text describes this in more detail.

When the OTT utility reads the name of a database entity, the name is automatically translated from the database character set to the character set used by the OTT utility. In order for the OTT utility to read the name of the database entity successfully, all the characters of the name must be found in the OTT character set, although a character may have different encodings in the two character sets.

The easiest way to guarantee that the character set used by the OTT utility contains all the necessary characters is to make it the same as the database character set. Note, however, that the OTT character set must be a superset of the compiler character set. That is, if the compiler character set is 7-bit ASCII, then the OTT character set must include 7-bit ASCII as a subset, and if the compiler character set is 7-bit EBCDIC, then the OTT character set must include 7-bit EBCDIC as a subset. The user specifies the character set that the OTT utility uses by setting the NLS_LANG environment variable, or by some other operating system-specific mechanism.

Once the OTT utility has read the name of a database entity, it translates the name from the character set used by the OTT utility to the compiler's character set. If a translation of the name appears in the INTYPE file, then the OTT utility uses that translation.

Otherwise, the OTT utility attempts to translate the name as follows:

  1. If the OTT character set is a multibyte character set, all multibyte characters in the name that have single-byte equivalents are converted to those single-byte equivalents.
  2. The name is converted from the OTT character set to the compiler character set. The compiler character set is a single-byte character set such as US7ASCII.
  3. The case of letters is set according to how the CASE parameter is defined, and any character that is not legal in a C or C++ identifier, or that has no translation in the compiler character set, is replaced by an underscore character (_). If at least one character is replaced by an underscore, then the OTT utility gives a warning message. If all the characters in a name are replaced by underscores, the OTT utility gives an error message.

Character-by-character name translation does not alter underscores, digits, or single-byte letters that appear in the compiler character set, so legal C or C++ identifiers are not altered.

Name translation may, for example, translate accented single-byte characters such as o with an umlaut or an a with an accent grave to o or a, with no accent, and may translate a multibyte letter to its single-byte equivalent. Name translation will typically fail if the name contains multibyte characters that lack single-byte equivalents. In this case, the user must specify name translations in the INTYPE file.

The OTT utility will not detect a naming clash caused by two or more database identifiers being mapped to the same C name, nor will it detect a naming problem where a database identifier is mapped to a C keyword.

Restriction Affecting the OTT Utility: File Name Comparison

Currently, the OTT utility determines if two files are the same by comparing the filenames provided by the user either on the command line or in the INTYPE file. But one potential problem can occur when the OTT utility needs to know if two filenames refer to the same file. For example, if the OTT-generated file foo.h requires a type declaration written to foo1.h, and another type declaration written to /private/smith/foo1.h, then the OTT utility should generate one #include if the two files are the same, and two #includes if the files are different. In practice, though, it concludes that the two files are different, and generates two #includes as follows:

#ifndef FOO1_ORACLE
#include "foo1.h"
#endif
#ifndef FOO1_ORACLE
#include "/private/smith/foo1.h"
#endif

If foo1.h and /private/smith/foo1.h are different files, then only the first one will be included. If foo1.h and /private/smith/foo1.h are the same file, then a redundant #include will be written.

Therefore, if a file is mentioned several times on the command line or in the INTYPE file, then each mention of the file should use exactly the same filename.


Go to previous page Go to next page
Oracle
Copyright © 2001, 2002 Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Product List
Book List
Go To Table Of Contents
Contents
Go To Index
Index

Master Index

Feedback