OCI Programming Basics

 

Skip Headers
Oracle® Call Interface Programmer's Guide,
10g Release 2 (10.2)

Part Number B14250-02

Home

Book List

Contents

Index

Master Index

Contact Us


Previous

Next
View PDF

2 OCI Programming Basics

This chapter introduces you to the basic concepts involved in programming with the OCI.

This chapter contains these topics:

  • Overview of OCI Programming

  • Header Files

  • OCI Program Structure

  • OCI Data Structures

  • Handles

  • OCI Descriptors

  • OCI Programming Steps

  • OCI Environment Initialization

  • Commit or Rollback

  • Terminating the Application

  • Error Handling in OCI

  • Additional Coding Guidelines

  • Using PL/SQL in an OCI Program

  • OCI Globalization Support

Overview of OCI Programming

This chapter provides an introduction to the concepts and procedures involved in developing an OCI application. After reading this chapter, you should have most of the tools necessary to understand and create a basic OCI application.

This chapter is broken down into the following major sections:

  • Header Files - gives the location of header files for OCI client application development.

  • OCI Program Structure - covers the basic structure of, and the major steps involved in creating an OCI application.

  • OCI Data Structures - discusses handles and descriptors.

  • OCI Programming Steps - discusses in detail each of the steps involved in coding an OCI application.

  • Error Handling in OCI - covers error handling in OCI applications.

  • Additional Coding Guidelines - provides useful information for coding an OCI application.

  • Using PL/SQL in an OCI Program - discusses important points for working with PL/SQL in an OCI application.

New users should pay particular attention to the information presented in this chapter, because it forms the basis for the rest of the material presented in this guide. The information in this chapter is supplemented by information in later chapters.

See Also:

  • For a discussion of the OCI functions that apply to a multilingual environment, see the Oracle Database Globalization Support Guide

  • For a discussion of the OCI functions that apply to cartridge services, see the Oracle Database Data Cartridge Developer's Guide.

Header Files

With the current release, the OCI/OCCI header files that are required for OCI and OCCI client application development on UNIX platforms reside in the $ORACLE_HOME/rdbms/public directory. The demo_rdbms.mk file remains in.the $ORACLE_HOME/rdbms/demo directory and continues to serve as an example makefile.

Unless you significantly modified the demo_rdbms.mk file, you are not affected. This is because the demo_rdbms.mk file already includes the $ORACLE_HOME/rdbms/public directory. Ensure that your highly customized makefiles have the $ORACLE_HOME/rdbms/public directory in the INCLUDE path.

All demonstration programs and header files continue to reside in the $ORACLE_HOME/rdbms/demo directory. As with all demonstrations, these files are only installed from the Companion CD. See Appendix B, "OCI Demonstration Programs" for the names of these programs and their purposes.

The OCI/OCCI header files required for development, located in $ORACLE_HOME/rdbms/public, are available both with the Oracle Database Server installation, and with the Oracle Database Client Administration and Custom installations.

OCI Program Structure

The general goal of an OCI application is to operate on behalf of multiple users. In an n-tiered configuration, multiple users are sending HTTP requests to the client application. The client application may need to perform some data operations that include exchanging data and performing data processing.

OCI uses the following basic program structure:

  1. Initialize the OCI programming environment and threads.

  2. Allocate necessary handles, and establish server connections and user sessions.

  3. Exchange data with the database server by executing SQL statements on the server, and perform necessary application data processing.

  4. Execute prepared statements, or prepare a new statement for execution.

  5. Terminate user sessions and server connections.

  6. Free handles.

Figure 2-1, "Basic OCI Program Flow" illustrates the flow of steps in an OCI application. Each step is described in more detail in the section "OCI Programming Steps".

Figure 2-1 Basic OCI Program Flow


Description of "Figure 2-1 Basic OCI Program Flow"

Keep in mind that the diagram and the list of steps present a simple generalization of OCI programming steps. Variations are possible, depending on the functionality of the program. OCI applications that include more sophisticated functionality, such as managing multiple sessions and transactions and using objects, require additional steps.

All OCI function calls are executed in the context of an environment. There can be multiple environments within an OCI process. If an environment requires any process-level initialization, then it is performed automatically.

Note:

It is possible to have more than one active connection and statement in an OCI application.

See Also:

For information about accessing and manipulating objects, see Chapter 10, "OCI Object-Relational Programming" and the subsequent chapters

OCI Data Structures

Handles and descriptors are opaque data structures which are defined in OCI applications. They can be allocated directly, through specific allocate calls, or they can be implicitly allocated by OCI functions.

7.x Upgrade Note:

Programmers who have previously written 7.x OCI applications need to become familiar with these new data structures which are used by most OCI calls.

Handles and descriptors store information pertaining to data, connections, or application behavior. Handles are defined in more detail in the next section:

See Also:

Descriptors are discussed in the section "OCI Descriptors"

Handles

Almost all OCI calls include in their parameter list one or more handles. A handle is an opaque pointer to a storage area allocated by the OCI library. You use a handle to store context or connection information, (for example, an environment or service context handle), or it may store information about OCI functions or data (for example, an error or describe handle). Handles can make programming easier, because the library, rather than the application, maintains this data.

Most OCI applications need to access the information stored in handles. The get and set attribute OCI calls, OCIAttrGet() and OCIAttrSet(), access and set this information.

See Also:

"Handle Attributes"

Table 2-1 lists the handles defined for the OCI. For each handle type, the C datatype and handle type constant used to identify the handle type in OCI calls are listed.

Table 2-1 OCI Handle Types

Description C Datatype Handle Type Constant

OCI environment handle

OCIEnv

OCI_HTYPE_ENV

OCI error handle

OCIError

OCI_HTYPE_ERROR

OCI service context handle

OCISvcCtx

OCI_HTYPE_SVCCTX

OCI statement handle

OCIStmt

OCI_HTYPE_STMT

OCI bind handle

OCIBind

OCI_HTYPE_BIND

OCI define handle

OCIDefine

OCI_HTYPE_DEFINE

OCI describe handle

OCIDescribe

OCI_HTYPE_DESCRIBE

OCI server handle

OCIServer

OCI_HTYPE_SERVER

OCI user session handle

OCISession

OCI_HTYPE_SESSION

OCI authentication information handle

OCIAuthInfo

OCI_HTYPE_AUTHINFO

OCI connection pool handle

OCICPool

OCI_HTYPE_CPOOL

OCI session pool handle

OCISPool

OCI_HTYPE_SPOOL

OCI transaction handle

OCITrans

OCI_HTYPE_TRANS

OCI complex object retrieval (COR) handle

OCIComplexObject

OCI_HTYPE_COMPLEXOBJECT

OCI thread handle

OCIThreadHandle

N/A

OCI subscription handle

OCISubscription

OCI_HTYPE_SUBSCRIPTION

OCI direct path context handle

OCIDirPathCtx

OCI_HTYPE_DIRPATH_CTX

OCI direct path function context handle

OCIDirPathFuncCtx

OCI_HTYPE_DIRPATH_FN_CTX

OCI direct path column array handle

OCIDirPathColArray

OCI_HTYPE_DIRPATH_COLUMN_ARRAY

OCI direct path stream handle

OCIDirPathStream

OCI_HTYPE_DIRPATH_STREAM

OCI process handle

OCIProcess

OCI_HTYPE_PROCESS

OCI administration handle

OCIAdmin

OCI_HTYPE_ADMIN

OCI HA event handle

OCIEvent

N/A


Allocating and Freeing Handles

Your application allocates all handles (except the bind, define, and thread handles) with respect to a particular environment handle. You pass the environment handle as one of the parameters to the handle allocation call. The allocated handle is then specific to that particular environment.

The bind and define handles are allocated with respect to a statement handle, and contain information about the statement represented by that handle.

Note:

The bind and define handles are implicitly allocated by the OCI library, and do not require user allocation.

The environment handle is allocated and initialized with a call to OCIEnvCreate() or to OCIEnvNlsCreate(), one of which is required by all OCI applications.

All user-allocated handles are initialized using the OCI handle allocation call, OCIHandleAlloc().

Here are the various types of handles: session handle, direct path context handle, thread handle, COR handle, subscription handle, describe handle, statement handle, service context handle, error handle, server handle, connection pool handle, event handle, and administration handle.

The thread handle is allocated with the OCIThreadHndInit() call.

An application must free all handles when they are no longer needed. The OCIHandleFree() function frees all handles.

Note:

When a parent handle is freed, all child handles associated with it are also freed, and can no longer be used. For example, when a statement handle is freed, any bind and define handles associated with it are also freed.

Handles lessen the need for global variables. Handles also make error reporting easier. An error handle is used to return errors and diagnostic information.

See Also:

For sample code demonstrating the allocation and use of OCI handles, see the example programs listed in Appendix B, "OCI Demonstration Programs"

Environment Handle

The environment handle defines a context in which all OCI functions are invoked. Each environment handle contains a memory cache, which enables fast memory access. All memory allocation under the environment handle is done from this cache. Access to the cache is serialized if multiple threads try to allocate memory under the same environment handle. When multiple threads share a single environment handle, they may block on access to the cache.

The environment handle is passed as the parent parameter to the OCIHandleAlloc() call to allocate all other handle types. Bind and define handles are allocated implicitly.

Error Handle

The error handle is passed as a parameter to most OCI calls. The error handle maintains information about errors that occur during an OCI operation. If an error occurs in a call, the error handle can be passed to OCIErrorGet() to obtain additional information about the error that occurred.

Allocating the error handle is one of the first steps in an OCI application because most OCI calls require an error handle as one of its parameters.

Service Context and Associated Handles

A service context handle defines attributes that determine the operational context for OCI calls to a server. The service context contains three handles as its attributes, that represent a server connection, a user session, and a transaction. These attributes are illustrated in Figure 2-2, "Components of a Service Context":

Figure 2-2 Components of a Service Context


Description of "Figure 2-2 Components of a Service Context"

  • A server handle identifies a connection to a database. It translates into a physical connection in a connection-oriented transport mechanism.

  • A user session handle defines a user's roles and privileges (also known as the user's security domain), and the operational context in which the calls execute.

  • A transaction handle defines the transaction in which the SQL operations are performed. The transaction context includes user session state information, including any fetch state and package instantiation.

Breaking the service context down in this way provides scalability and enables programmers to create sophisticated multitiered applications and transaction processing (TP) monitors for execute requests on behalf of multiple users on multiple application servers and different transaction contexts.

You must allocate and initialize the service context handle with OCIHandleAlloc() or OCILogon() before you can use it. The service context handle is allocated explicitly by OCIHandleAlloc(). It can be initialized using OCIAttrSet() with the server, session, and transaction handle. If the service context handle is allocated implicitly using OCILogon(), it is already initialized.

Applications maintaining only a single user session for each database connection at any time can call OCILogon() to get an initialized service context handle.

In applications requiring more complex session management, the service context must be explicitly allocated, and the server and user session handles must be explicitly set into the service context. OCIServerAttach() and OCISessionBegin() calls initialize the server and user session handle respectively.

An application will only define a transaction explicitly if it is a global transaction or there are multiple transactions active for sessions. It will be able to work correctly with the implicit transaction created automatically by OCI when the application makes changes to the database.

See Also:

  • "OCI Support for Transactions"

  • For more information about establishing a server connection and user session, see the sections "OCI Environment Initialization", and "Password and Session Management"

Statement, Bind, and Define Handles

A statement handle is the context that identifies a SQL or PL/SQL statement and its associated attributes.

Figure 2-3 Statement Handles


Description of "Figure 2-3 Statement Handles"

Information about input and output bind variables is stored in bind handles. The OCI library allocates a bind handle for each placeholder bound with the OCIBindByName() or OCIBindByPos() function. The user does not need to allocate bind handles. They are implicitly allocated by the bind call.

Fetched data returned by a query (select statement) is converted and retrieved according to the specifications of the define handles. The OCI library allocates a define handle for each output variable defined with OCIDefineByPos(). The user does not need to allocate define handles. They are implicitly allocated by the define call.

Bind and define handles are freed when the statement handle is freed or when a new statement is prepared on the statement handle.

Describe Handle

The describe handle is used by the OCI describe call, OCIDescribeAny(). This call obtains information about schema objects in a database (for example, functions, procedures). The call takes a describe handle as one of its parameters, along with information about the object being described. When the call completes, the describe handle is populated with information about the object. The OCI application can then obtain describe information through the attributes of parameter descriptors.

See Also:

Chapter 6, "Describing Schema Metadata", for more information about using the OCIDescribeAny() function

Complex Object Retrieval Handle

The complex object retrieval (COR) handle is used by some OCI applications that work with objects in an Oracle database server. This handle contains COR descriptors, which provide instructions for retrieving objects referenced by another object.

See Also :

"Complex Object Retrieval"

Thread Handle

For information about the thread handle, which is used in multithreaded applications:

See Also:

"The OCIThread Package"

Subscription Handle

The subscription handle is used by an OCI client application that registers and subscribes to receive notifications of database events or events in the AQ namespace. The subscription handle encapsulates all information related to a registration from a client.

See Also:

"Publish-Subscribe Notification in OCI"

Direct Path Handles

The direct path handles are necessary for an OCI application that uses the direct path load engine in the Oracle database server. The direct path load interface enables the application to access the direct block formatter of the Oracle server.

Figure 2-4 Direct Path Handles


Description of "Figure 2-4 Direct Path Handles"

See Also:

  • "Direct Path Loading Overview"

  • "Direct Path Loading Handle Attributes"

Connection Pool Handle

The connection pool handle is used for applications that pool physical connections into virtual connections by calling specific OCI functions.

See Also:

"Connection Pooling in OCI"

Handle Attributes

All OCI handles have attributes that represent data stored in that handle. You can read handle attributes using the attribute get call, OCIAttrGet(), and you can change them with the attribute set call, OCIAttrSet().

For example, the following statements set the user name in the session handle by writing to the OCI_ATTR_USERNAME attribute:

text username[] = "hr";
err = OCIAttrSet ((dvoid*) mysessp, OCI_HTYPE_SESSION, (dvoid*)username,
      (ub4) strlen((char *)username), OCI_ATTR_USERNAME, (OCIError *) myerrhp);

Some OCI functions require that particular handle attributes be set before the function is called. For example, when OCISessionBegin() is called to establish a user's login session, the user name and password must be set in the user session handle before the call is made.

Other OCI functions provide useful return data in handle attributes after the function completes. For example, when OCIStmtExecute() is called to execute a SQL query, describe information relating to the select-list items is returned in the statement handle.

ub4 parmcnt;
/* get the number of columns in the select list */
err = OCIAttrGet ((dvoid *)stmhp, (ub4)OCI_HTYPE_STMT, (dvoid *)
         &parmcnt, (ub4 *) 0, (ub4)OCI_ATTR_PARAM_COUNT, errhp);

See Also:

  • The description of OCIAttrGet() for an example showing the user name and password handle attributes being set

  • Appendix A, "Handle and Descriptor Attributes"

OCI Descriptors

OCI descriptors and locators are opaque data structures that maintain data-specific information. Table 2-2 lists them, along with their C datatype, and the OCI type constant that allocates a descriptor of that type in a call to OCIDescriptorAlloc(). The OCIDescriptorFree() function frees descriptors and locators.

Table 2-2 Descriptor Types

Description C Datatype OCI Type Constant

snapshot descriptor

OCISnapshot

OCI_DTYPE_SNAP

result set descriptor

OCIResult

OCI_DTYPE_RSET

LOB datatype locator

OCILobLocator

OCI_DTYPE_LOB

BFILE datatype locator

OCILobLocator

OCI_DTYPE_FILE

read-only parameter descriptor

OCIParam

OCI_DTYPE_PARAM

ROWID descriptor

OCIRowid

OCI_DTYPE_ROWID

ANSI DATE descriptor

OCIDateTime

OCI_DTYPE_DATE

TIMESTAMP descriptor

OCIDateTime

OCI_DTYPE_TIMESTAMP

TIMESTAMP WITH TIME ZONE descriptor

OCIDateTime

OCI_DTYPE_TIMESTAMP_TZ

TIMESTAMP WITH LOCAL TIME ZONE descriptor

OCIDateTime

OCI_DTYPE_TIMESTAMP_LTZ

INTERVAL YEAR TO MONTH descriptor

OCIInterval

OCI_DTYPE_INTERVAL_YM

INTERVAL DAY TO SECOND descriptor

OCIInterval

OCI_DTYPE_INTERVAL_DS

user callback descriptor

OCIUcb

OCI_DTYPE_UCB

the distinguished names of the database servers in a registration request

OCIServerDNs

OCI_DTYPE_SRVDN

complex object descriptor

OCIComplexObjectComp

OCI_DTYPE_COMPLEXOBJECTCOMP

advanced queuing enqueue options

OCIAQEnqOptions

OCI_DTYPE_AQENQ_OPTIONS

advanced queuing dequeue options

OCIAQDeqOptions

OCI_DTYPE_AQDEQ_OPTIONS

advanced queuing message properties

OCIAQMsgProperties

OCI_DTYPE_AQMSG_PROPERTIES

advanced queuing agent

OCIAQAgent

OCI_DTYPE_AQAGENT

advanced queuing notification

OCIAQNotify

OCI_DTYPE_AQNFY

advanced queuing listen options

OCIAQListenOpts

OCI_DTYPE_AQLIS_OPTIONS

advanced queuing message properties

OCIAQLisMsgProps

OCI_DTYPE_AQLIS_MSG_PROPERTIES

change notification

none

OCI_DTYPE_CHDES

table change

none

OCI_DTYPE_TABLE_CHDES

row change

none

OCI_DTYPE_ROW_CHDES


Note:

Although there is a single C type for OCILobLocator, this locator is allocated with a different OCI type constant for internal and external LOBs. The section below on LOB locators discusses this difference.

The main purpose of each descriptor type is listed here, and each descriptor type is described in the following sections:

  • OCISnapshot - used in statement execution

  • OCILobLocator - used for LOB (OCI_DTYPE_LOB) or BFILE (OCI_DTYPE_FILE) calls

  • OCIParam - used in describe calls

  • OCIRowid - used for binding or defining ROWID values

  • OCIDateTime and OCIInterval - used for datetime and interval datatypes

  • OCIComplexObjectComp - used for complex object retrieval

  • OCIAQEnqOptions, OCIAQDeqOptions, OCIAQMsgProperties, OCIAQAgent - used for Advanced Queuing

  • OCIAQNotify - used for publish-subscribe notification

  • OCIServerDNs - used for LDAP-based publish-subscribe notification

Snapshot Descriptor

The snapshot descriptor is an optional parameter to the execute call, OCIStmtExecute(). It indicates that a query is being executed against a particular database snapshot which represents the state of a database at a particular point in time.

Allocate a snapshot descriptor with a call to OCIDescriptorAlloc(), by passing OCI_DTYPE_SNAP as the type parameter.

See Also:

For more information about OCIStmtExecute() and database snapshots, see the section "Execution Snapshots"

LOB and BFILE Locators

A large object (LOB) is an Oracle datatype that can hold binary (BLOB) or character (CLOB) data. In the database, an opaque data structure called a LOB locator is stored in a LOB column of a database row, or in the place of a LOB attribute of an object. The locator serves as a pointer to the actual LOB value, which is stored in a separate location.

Note:

Depending on your application, you may or may not want to use LOB locators. You can use the data interface for LOBs, which does not require LOB locators. In this interface, you can bind or define character data for CLOB columns or RAW data for BLOB columns.

See Also:

  • "Binding LOB Data"

  • "Defining LOB Data"

The OCI LOB locator is used to perform OCI operations against a LOB (BLOB or CLOB) or FILE (BFILE). OCILobXXX functions take a LOB locator parameter instead of the LOB value. OCI LOB functions do not use actual LOB data as parameters. They use the LOB locators as parameters and operate on the LOB data referenced by them.

The LOB locator is allocated with a call to OCIDescriptorAlloc(), by passing OCI_DTYPE_LOB as the type parameter for BLOBs or CLOBs, and OCI_DTYPE_FILE for BFILEs.

Caution:

The two LOB locator types are not interchangeable. When binding or defining a BLOB or CLOB, the application must take care that the locator is properly allocated using OCI_DTYPE_LOB. Similarly, when binding or defining a BFILE, the application must be sure to allocate the locator using OCI_DTYPE_FILE.

An OCI application can retrieve a LOB locator from the server by issuing a SQL statement containing a LOB column or attribute as an element in the select list. In this case, the application would first allocate the LOB locator and then use it to define an output variable. Similarly, a LOB locator can be used as part of a bind operation to create an association between a LOB and a placeholder in a SQL statement.

See Also:

  • Chapter 7, "LOB and BFILE Operations"

  • "Binding LOB Data"

  • "Defining LOB Data"

Parameter Descriptor

OCI applications use parameter descriptors to obtain information about select-list columns or schema objects. This information is obtained through a describe operation.

The parameter descriptor is the only descriptor type that is not allocated using OCIDescriptorAlloc(). You can obtain it only as an attribute of a describe handle, statement handle, or through a complex object retrieval handle by specifying the position of the parameter using an OCIParamGet() call.

See Also:

Chapter 6, "Describing Schema Metadata", and "Describing Select-list Items" for more information about obtaining and using parameter descriptors

ROWID Descriptor

The ROWID descriptor, OCIRowid, is used by applications that need to retrieve and use Oracle ROWIDs. To work with a ROWID using OCI release 8 or later, an application can define a ROWID descriptor for a rowid position in a SQL select-list, and retrieve a ROWID into the descriptor. This same descriptor can later be bound to an input variable in an INSERT statement or WHERE clause.

ROWIDs are also redirected into descriptors using OCIAttrGet() on the statement handle following an execute.

Date, Datetime, and Interval Descriptors

These descriptors are used by applications which use the date, datetime, or interval datatypes (OCIDate, OCIDateTime, and OCIInterval). These descriptors can be used for binding and defining, and are passed as parameters to the functions OCIDescAlloc() and OCIDescFree() to allocate and free memory.

See Also:

  • For more information about these datatypes refer to Chapter 3, "Datatypes".

  • The functions which operate on these datatypes are described in Chapter 18, "OCI Datatype Mapping and Manipulation Functions"

Complex Object Descriptor

Application performance when dealing with objects may be increased through the use of complex object retrieval (COR).

See Also:

For information about the complex object descriptor and its use, refer to "Complex Object Retrieval".

Advanced Queuing Descriptors

Oracle AQ provides message queuing as an integrated part of the Oracle server.

See Also:

  • "OCI and Streams Advanced Queuing"

  • "Publish-Subscribe Registration Functions in OCI"

User Memory Allocation

The OCIDescriptorAlloc() call has an xtramem_sz parameter in its parameter list. This parameter is used to specify an amount of user memory which should be allocated along with a descriptor or locator.

Typically, an application uses this parameter to allocate an application-defined structure that has the same lifetime as the descriptor or locator. This structure maybe used for application bookkeeping or storing context information.

Using the xtramem_sz parameter means that the application does not need to explicitly allocate and deallocate memory as each descriptor or locator is allocated and deallocated. The memory is allocated along with the descriptor or locator, and freeing the descriptor or locator (with OCIDescriptorFree()) frees the user's data structures as well.

The OCIHandleAlloc() call has a similar parameter for allocating user memory which has the same lifetime as the handle.

The OCIEnvCreate() and OCIEnvInit() calls have a similar parameter for allocating user memory which has the same lifetime as the environment handle.

OCI Programming Steps

Each of the steps in developing an OCI application is described in detail in the following sections. Some of the steps are optional. For example, you do not need to describe or define select-list items if the statement is not a query.

See Also:

  • Appendix B, "OCI Demonstration Programs" for an example showing the use of OCI calls for processing SQL statements. See the first sample program.

  • The special case of dynamically providing data at run time is described in detail in the section "Runtime Data Allocation and Piecewise Operations in OCI".

  • Special considerations for operations involving arrays of structures are described in the section "Binding and Defining Arrays of Structures in OCI".

  • Refer to the section "Error Handling in OCI" for an outline of the steps involved in processing a SQL statement within an OCI program.

  • For information on using the OCI to write multithreaded applications, refer to "Overview of OCI Multithreaded Development".

  • For more information about types of SQL statements, refer to the section "SQL Statements".

The following sections describe the steps that are required of an OCI application:

  • OCI Environment Initialization

  • Processing SQL Statements in OCI

  • Commit or Rollback

  • Terminating the Application

  • Error Handling in OCI

Application-specific processing will also occur in between any and all of the OCI function steps.

OCI Environment Initialization

This section describes how to initialize the OCI environment, establish a connection to a server, and authorize a user to perform actions against the database.

First, the three main steps in initializing the OCI environment are described in the following sections:

  • "Creating the OCI Environment"

  • "Allocating Handles and Descriptors"

  • "Application Initialization, Connection, and Session Creation"

Creating the OCI Environment

Each OCI function call is executed in the context of an environment that is created with the OCIEnvCreate() call. This call must be invoked before any other OCI call is executed. The only exception is the setting of a process-level attribute for the OCI shared mode.

The mode parameter of OCIEnvCreate() specifies whether the application calling the OCI library functions will:

  • Run in a threaded environment (mode = OCI_THREADED).

  • Use objects (mode = OCI_OBJECT).

  • Use subscriptions (mode = OCI_EVENTS).

The mode can be set independently in each environment.

It is necessary to initialize in object mode if the application binds and defines objects, or if it uses the OCI's object navigation calls. The program may also choose to use none of these features (mode = OCI_DEFAULT) or some combination of them, separating the options with a vertical bar. For example if mode = (OCI_THREADED | OCI_OBJECT), then the application runs in a threaded environment and uses objects.

You can specify user-defined memory management functions for each OCI environment.

See Also:

  • OCIEnvCreate() and OCIInitialize() for more information about the initialization calls.

  • "Overview of OCI Multithreaded Development".

  • Chapter 10, "OCI Object-Relational Programming" and the chapters that follow it.

  • "Publish-Subscribe Notification in OCI".

Allocating Handles and Descriptors

Oracle provides OCI functions to allocate and deallocate handles and descriptors. You must allocate handles using OCIHandleAlloc() before passing them into an OCI call, unless the OCI call, such as OCIBindByPos(), allocates the handles for you.

You can allocate the types of handles listed in Table 2-1, "OCI Handle Types"with OCIHandleAlloc() Depending on the functionality of your application, it needs to allocate some or all of these handles.

Application Initialization, Connection, and Session Creation

An application must call OCIEnvNlsCreate() to initialize the OCI environment handle. Existing applications may have used OCIEnvCreate().

Following this step, the application has several options for establishing a server connection and beginning a user session.

Note:

OCIEnvCreate() or OCIEnvNlsCreate() should be used instead of the OCIInitialize() and OCIEnvInit() calls. OCIInitialize() and OCIEnvInit() calls are supported for backward compatibility.

Single User, Single Connection

This option is the simplified logon method, which can be used if an application maintains only a single user session for each database connection at any time.

When an application calls OCILogon2(), the OCI library initializes the service context handle that is passed to it, and creates a connection to the specified server for the user making the request.

The following is an example of what a call to OCILogon2() looks like for a single user session with user name hr, password hr, and database oracledb:

OCILogon2(envhp, errhp, &svchp, (text *)"hr", (ub4)strlen("hr"), (text *)"hr",
          (ub4)strlen("hr"), (text *)"oracledb", (ub4)strlen("oracledb"),
          OCI_DEFAULT);

The parameters to this call include the service context handle (which has been initialized), the user name, the user's password, and the name of the database that are used to establish the connection. With the last parameter, mode, set to OCI_DEFAULT, this call has the same effect as calling the older OCILogon(). Use OCILogon2() for any new applications. The server and user session handles are implicitly allocated by this function.

If an application uses this logon method, the service context, server, and user session handles will all be read-only; the application cannot switch session or transaction by changing the appropriate attributes of the service context handle by means of an OCIAttrSet() call.

An application that initializes its session and authorization using OCILogon2() must terminate them using OCILogoff().

Client Access Through a Proxy

Proxy authentication is a process typically employed in an environment with a middle tier such as a firewall, in which the end user authenticates to the middle tier, which then authenticates to the database on the user's behalf—as its proxy. The middle tier logs into the database as a proxy user. A proxy user can switch identities and, once logged into the database, switch to the end user's identity. It can perform operations on the end user's behalf, using the authorization appropriate to that particular end user.

Proxy to database users is supported by means of OCI and the ALTER USER statement, whose BNF syntax is:

ALTER USER <targetuser> GRANT CONNECT THROUGH  [AUTHENTICATION REQUIRED];

The ALTER USER statement is used once in an application. Connections can be made multiple times afterwards. In OCI, you can either use connect strings or the function OCIAttrSet() with the parameter OCI_ATTR_PROXY_CLIENT.

After a proxy switch is made, the current and connected user is the target user of the proxy. The identity of the original user is not used for any privilege calculations. The original user can be a local or external user.

The following examples show connect strings that can be used in functions such as OCILogon2() (set mode = OCI_DEFAULT), OCILogon(), OCISessionBegin() with OCIAttrSet() (pass the attribute OCI_ATTR_USERNAME of the session handle), and so on:

  1. Local user acting on behalf of a local user.

    Dilbert and Joe are two local database users. To enable Dilbert to proxy on behalf of Joe, use the following SQL statement:

    ALTER USER joe GRANT CONNECT THROUGH dilbert;
    
    

    When user name dilbert is acting on behalf of joe, the connection string is (dilbert has password tiger):

    dilbert[joe]/tiger@db1
    
    

    The "[" and "]" are actually entered in the connection string.

  2. Local user acting on behalf of local user, where user names must be quoted.

    "Dilbert" and "Joe" are two local database users. The names are case sensitive and need to be quoted. To enable "Dilbert" to proxy on behalf of "Joe", use the following statement:

    ALTER USER "Joe" GRANT CONNECT THROUGH "Dilbert";
    
    

    When "Dilbert" is acting on behalf of "Joe" the connection string is (be sure to also include the " characters):

    "Dilbert"["Joe"]/tiger@db1
    
    
  3. Local user dilbert[mybert] connecting to database.

    There is a user in the database "dilbert[mybert]" and the way this user will connect to the database is (the "[" and "]" are actually entered in the connection string):

    "dilbert[mybert]"/tiger
    
    rem the user was already created this way:
    rem CREATE USER "dilbert[mybert]" IDENTIFIED BY tiger;
    
    
  4. Local user acting on behalf of local user, where the user name has [].

    dilbert[mybert] and joe[myjoe] are two database users that contain the characters "[" and "]". If dilbert[mybert] wants to act on behalf of joe[myjoe], the connect statement is:

    "dilbert[mybert]"["joe[myjoe]"]/tiger
    
    
  5. You can set the target user name by means of the ALTER USER statement, followed by an OCI program in which OCIAttrSet() sets the attribute OCI_ATTR_PROXY_CLIENT and the proxy dilbert. For example:

    ALTER USER joe GRANT CONNECT THROUGH dilbert;
    
    

    In your program, use these statements to connect multiple times:

    OCIAttrSet(session, OCI_HTYPE_SESSION, (dvoid *)"dilbert",
               (ub4)strlen("dilbert"), OCI_ATTR_USERNAME, 
               error_handle);
    OCIAttrSet(session, OCI_HTYPE_SESSION, (dvoid *)"tiger", 
               (ub4)strlen("tiger"), OCI_ATTR_PASSWORD, 
               error_handle);
    OCIAttrSet(session, OCI_HTYPE_SESSION, (dvoid *)"joe",
               (ub4)strlen("joe"), OCI_ATTR_PROXY_CLIENT, 
               error_handle);
    
    

See Also:

  • "OCI_ATTR_PROXY_CLIENT"

  • Oracle Database Security Guide for a discussion of proxy authentication

  • "Password and Session Management"

  • "OCIAttrSet()"

Compatibility Issues of Client Access Through a Proxy

Since this feature was introduced in release 10.2, pre-10.2 clients do not have it. If newer clients use the feature with pre-10.2 databases, the connect will fail and the client will return an error after checking the database release level.

Non-Proxy Multiple Sessions or Connections

This option uses explicit attach and begin-session calls to maintain multiple user sessions and connections on a database connection. Specific calls to attach to the server and begin sessions are:

  • OCIServerAttach()- creates an access path to the data server for OCI operations.

  • OCISessionBegin()- establishes a session for a user against a particular server. This call is required for the user to execute operations on the server.

A subsequent call to OCISessionBegin() using different service context and session context handles logs off the previous user and causes an error. To run two simultaneous non-migratable sessions, a second OCISessionBegin() call must be made with the same service context handle and a new session context handle.

These calls set up an operational environment that enables you to execute SQL and PL/SQL statements against a database.

See Also:

  • "Connect, Authorize, and Initialize Functions" .

  • Chapter 9, " OCI Programming Advanced Topics", for more information about maintaining multiple sessions, transactions, and connections.

  • "Client Character Set Control from OCI" for the use of OCIEnvNlsCreate().

Example of Creating and Initializing an OCI Environment

The following example demonstrates the use of creating and initializing an OCI environment.

  • A server context is created and set in the service handle.

  • Then a user session handle is created and initialized using a database user name and password.

  • For the sake of simplicity, error checking is not included.

#include 
...
main()
{
...
OCIEnv     *myenvhp;    /* the environment handle */
OCIServer  *mysrvhp;    /* the server handle */
OCIError   *myerrhp;    /* the error handle */
OCISession *myusrhp;    /* user session handle */
OCISvcCtx  *mysvchp;    /* the  service handle */
...
/* initialize the mode to be the threaded and object environment */
(void) OCIEnvCreate(&myenvhp, OCI_THREADED|OCI_OBJECT, (dvoid *)0,
                    0, 0, 0, (size_t) 0, (dvoid **)0);

     /* allocate a server handle */
(void) OCIHandleAlloc ((dvoid *)myenvhp, (dvoid **)&mysrvhp,
      OCI_HTYPE_SERVER, 0, (dvoid **) 0);

      /* allocate an error handle */
(void) OCIHandleAlloc ((dvoid *)myenvhp, (dvoid **)&myerrhp,
      OCI_HTYPE_ERROR, 0, (dvoid **) 0);

      /* create a server context */
(void) OCIServerAttach (mysrvhp, myerrhp, (text *)"inst1_alias",
      strlen ("inst1_alias"), OCI_DEFAULT);

     /* allocate a service handle */
(void) OCIHandleAlloc ((dvoid *)myenvhp, (dvoid **)&mysvchp,
      OCI_HTYPE_SVCCTX, 0, (dvoid **) 0);

 /* set the server attribute in the service context handle*/
(void) OCIAttrSet ((dvoid *)mysvchp, OCI_HTYPE_SVCCTX,
       (dvoid *)mysrvhp, (ub4) 0, OCI_ATTR_SERVER, myerrhp);

      /* allocate a user session handle */
(void) OCIHandleAlloc ((dvoid *)myenvhp, (dvoid **)&myusrhp,
     OCI_HTYPE_SESSION, 0, (dvoid **) 0);

      /* set user name attribute in user session handle */
 (void) OCIAttrSet ((dvoid *)myusrhp, OCI_HTYPE_SESSION,
      (dvoid *)"hr", (ub4)strlen("hr"),
      OCI_ATTR_USERNAME, myerrhp);

      /* set password attribute in user session handle */
 (void) OCIAttrSet ((dvoid *)myusrhp, OCI_HTYPE_SESSION,
      (dvoid *)"hr", (ub4)strlen("hr"),
      OCI_ATTR_PASSWORD, myerrhp);

 (void) OCISessionBegin ((dvoid *) mysvchp, myerrhp, myusrhp,
      OCI_CRED_RDBMS, OCI_DEFAULT);

    /* set the user session attribute in the service context handle*/
 (void) OCIAttrSet ((dvoid *)mysvchp, OCI_HTYPE_SVCCTX,
       (dvoid *)myusrhp, (ub4) 0, OCI_ATTR_SESSION, myerrhp);
...
}

The demonstration program cdemo81.c in the demo directory illustrates this process, with error checking.

Processing SQL Statements in OCI

A chapter of this manual outlines the specific steps involved in processing SQL statements in OCI.

See Also:

Chapter 4, "Using SQL Statements in OCI"

Commit or Rollback

An application commits changes to the database by calling OCITransCommit(). This call uses a service context as one of its parameters. The transaction is associated with the service context whose changes are committed. This transaction can be explicitly created by the application or implicitly created when the application modifies the database.

Note:

Using the OCI_COMMIT_ON_SUCCESS mode of the OCIExecute() call, the application can selectively commit transactions at the end of each statement execution, saving an extra round trip.

To roll back a transaction, use the OCITransRollback() call.

If an application disconnects from Oracle in some way other than a normal logoff, such as losing a network connection, and OCITransCommit() has not been called, all active transactions are rolled back automatically.

See Also:

  • "Service Context and Associated Handles", and

  • "OCI Support for Transactions"

Terminating the Application

An OCI application should perform the following three steps before it terminates:

  1. Delete the user session by calling OCISessionEnd() for each session.

  2. Delete access to the data source(s) by calling OCIServerDetach() for each source.

  3. Explicitly deallocate all handles by calling OCIHandleFree() for each handle.

  4. Delete the environment handle, which deallocates all other handles associated with it.

    Note:

    When a parent OCI handle is freed, any child handles associated with it are freed automatically

The calls to OCIServerDetach() and OCISessionEnd() are not mandatory, but are recommended. If the application terminates, and OCITransCommit() (transaction commit) has not been called, any pending transactions are automatically rolled back

See Also:

For an example showing handles being freed at the end of an application, refer to the first sample program in Appendix B, "OCI Demonstration Programs"

Note:

If the application uses the simplified logon method of OCILogon(), then a call to OCILogoff() terminates the session, disconnects from the server, and frees the service context and associated handles. The application is still responsible for freeing other handles it allocated.

Error Handling in OCI

OCI function calls have a set of return codes, listed in Table 2-3, "OCI Return Codes", which indicate the success or failure of the call, such as OCI_SUCCESS or OCI_ERROR, or provide other information that may be required by the application, such as OCI_NEED_DATA or OCI_STILL_EXECUTING. Most OCI calls return one of these codes.

To verify that the connection to the server is not terminated by the OCI_ERROR, an application can check the value of the attribute OCI_ATTR_SERVER_STATUS in the server handle. If the value of the attribute is OCI_SERVER_NOT_CONNECTED, then the connection to the server and the user session must be reestablished.

See Also:

  • For exceptions, see "Functions Returning Other Values"

  • For complete details and an example of usage, see "OCIErrorGet()"

  • "Server Handle Attributes"

Table 2-3 OCI Return Codes

OCI Return Code Description

OCI_SUCCESS

The function completed successfully.

OCI_SUCCESS_WITH_INFO

The function completed successfully; a call to OCIErrorGet() returns additional diagnostic information. This may include warnings.

OCI_NO_DATA

The function completed, and there is no further data.

OCI_ERROR

The function failed; a call to OCIErrorGet() returns additional information.

OCI_INVALID_HANDLE

An invalid handle was passed as a parameter or a user callback is passed an invalid handle or invalid context. No further diagnostics are available.

OCI_NEED_DATA

The application must provide runtime data.

OCI_STILL_EXECUTING

The service context was established in nonblocking mode, and the current operation could not be completed immediately. The operation must be called again to complete. OCIErrorGet() returns ORA-03123 as the error code.

OCI_CONTINUE

This code is returned only from a callback function. It indicates that the callback function wants the OCI library to resume its normal processing.


If the return code indicates that an error has occurred, the application can retrieve Oracle-specific error codes and messages by calling OCIErrorGet(). One of the parameters to OCIErrorGet() is the error handle passed to the call that caused the error.

Note:

Multiple diagnostic records can be retrieved by calling OCIErrorGet() repeatedly until there are no more records ( OCI_NO_DATA is returned). OCIErrorGet() returns at most a single diagnostic record.

Return and Error Codes for Data

In Table 2-4, the OCI return code, error number, indicator variable, and column return code are specified when the data fetched is normal, null, or truncated.

See Also:

"Indicator Variables" for a discussion of indicator variables.

Table 2-4 Return and Error Codes

State of Data Return Code Indicator - not provided Indicator - provided

not null or truncated

not provided

OCI_SUCCESS

error = 0

OCI_SUCCESS

error = 0

indicator = 0

not null or truncated

provided

OCI_SUCCESS

error = 0

return code = 0

OCI_SUCCESS

error = 0

indicator = 0

return code = 0

null data

not provided

OCI_ERROR

error = 1405

OCI_SUCCESS

error = 0

indicator = -1

null data

provided

OCI_ERROR

error = 1405

return code = 1405

OCI_SUCCESS

error = 0

indicator = -1

return code = 1405

truncated data

not provided

OCI_ERROR

error = 1406

OCI_ERROR

error = 1406

indicator = data_len

truncated data

provided

OCI_SUCCESS_WITH_INFO

error = 24345

return code = 1405

OCI_SUCCESS_WITH_INFO

error = 24345

indicator = data_len

return code = 1406


For truncated data, data_len is the actual length of the data that has been truncated if this length is less than or equal to SB2MAXVAL. Otherwise, the indicator is set to -2.

Functions Returning Other Values

Some functions return values other than the OCI error codes listed in Table 2-3. When using these function be aware that they return values directly from the function call, rather than through an OUT parameter. More detailed information about each function and its return values is listed in the reference chapters.

Additional Coding Guidelines

This section explains some additional issues when coding OCI applications.

Parameter Types

OCI functions take a variety of different types of parameters, including integers, handles, and character strings. Special considerations must be taken into account for some types of parameters, as described in the following sections.

See Also:

"Connect, Authorize, and Initialize Functions" for more information about parameter datatypes and parameter passing conventions.

Address Parameters

Address parameters are used to pass the address of the variable to Oracle. You should be careful when developing in C, since it normally passes scalar parameters by value.

Integer Parameters

Binary integer and short binary integer parameters are numbers whose size is system-dependent. See your Oracle system-specific documentation for the size of these integers on your system.

Character String Parameters

Character strings are a special type of address parameter. Each OCI routine that enables a character string to be passed as a parameter also has a string length parameter. The length parameter should be set to the length of the string.

7.x Upgrade Note:

Unlike earlier versions of the OCI, you do not pass -1 for the string length parameter of a null-terminated string.

Inserting Nulls into a Column

You can insert a null into a database column in several ways.

  1. One method is to use a literal NULL in the text of an INSERT or UPDATE statement. For example, the SQL statement

INSERT INTO emp1 (ename, empno, deptno)
        VALUES (NULL, 8010, 20)

makes the ENAME column NULL.

  1. Use indicator variables in the OCI bind call.

    See Also:

    "Indicator Variables"
  2. Insert a NULL is to set the buffer length and maximum length parameters both to zero on a bind call.

    Note:

    Following SQL92 requirements, Oracle returns an error if an attempt is made to fetch a null select-list item into a variable that does not have an associated indicator variable specified in the define call.

Indicator Variables

Each bind and define OCI call has a parameter that associates an indicator variable, or an array of indicator variables, with a DML statement, a PL/SQL statement, or a query.

The C language does not have the concept of null values; therefore you associate indicator variables with input variables to specify whether the associated placeholder is a NULL. When data is passed to Oracle, the values of these indicator variables determine whether or not a NULL is assigned to a database field.

For output variables, indicator variables determine whether the value returned from Oracle is a NULL or a truncated value. In the case of a NULL fetch in an OCIStmtFetch() call, or a truncation in an OCIStmtExecute() call, the OCI call returns OCI_SUCCESS_WITH_INFO. The output indicator variable is set.

The datatype of indicator variables is sb2. In the case of arrays of indicator variables, the individual array elements should be of type sb2.

Input

For input host variables, the OCI application can assign the following values to an indicator variable:

Input Indicator Value Action Taken by Oracle
-1 Oracle assigns a NULL to the column, ignoring the value of the input variable.
>=0 Oracle assigns the value of the input variable to the column.

Output

On output, Oracle can assign the following values to an indicator variable:

Output Indicator Value Meaning
-2 The length of the item is greater than the length of the output variable; the item has been truncated. Additionally, the original length is longer than the maximum data length that can be returned in the sb2 indicator variable.
-1 The selected value is null, and the value of the output variable is unchanged.
0 Oracle assigned an intact value to the host variable.
>0 The length of the item is greater than the length of the output variable; the item has been truncated. The positive value returned in the indicator variable is the actual length before truncation.

Indicator Variables for Named Data Types and REFs

Indicator variables for most datatypes introduced after release 8.0 behave as described earlier. The only exception is SQLT_NTY (a named datatype). For data of type SQLT_NTY, the indicator variable must be a pointer to an indicator structure. Data of type SQLT_REF uses a standard scalar indicator, just like other variable types.

When database types are translated into C struct representations using the Object Type Translator (OTT), a null indicator structure is generated for each object type. This structure includes an atomic null indicator, plus indicators for each object attribute.

See Also:

  • Documentation for the OTT in Chapter 14, "Using the Object Type Translator with OCI", and section "NULL Indicator Structure" of this manual for information about null indicator structures

  • Descriptions of OCIBindByName() and OCIBindByPos() in"Bind, Define, and Describe Functions" , and the sections "Information for Named Datatype and REF Binds", and "Information for Named Datatype and REF Defines, and PL/SQL OUT Binds", for more information about setting indicator parameters for named datatypes and REFs

Canceling Calls

On most operating systems, you can cancel long-running or repeated OCI calls, by entering the operating system's interrupt character (usually CTRL-C) from the keyboard.

Note:

This is not to be confused with cancelling a cursor, which is accomplished by calling OCIStmtFetch() with the nrows parameter set to zero.

When you cancel the long-running or repeated call using the operating system interrupt, the error code ORA-01013 ("user requested cancel of current operation") is returned.

Given a particular service context pointer or server context pointer, the OCIBreak() function performs an immediate (asynchronous) stop of any currently executing OCI function associated with the server. It is normally used to stop a long-running OCI call being processed on the server. The OCIReset() function is necessary to perform a protocol synchronization on a nonblocking connection after an OCI application stops a function with OCIBreak().

Note:

OCIBreak() works on Windows systems, including Windows 2000, and Windows XP.

The status of potentially long-running calls can be monitored through the use of nonblocking calls. Use multithreading for new applications.

See Also:

  • "Overview of OCI Multithreaded Development"

  • "The OCIThread Package"

Positioned Updates and Deletes

You can use the ROWID associated with a SELECT...FOR UPDATE OF... statement in a later UPDATE or DELETE statement. The ROWID is retrieved by calling OCIAttrGet() on the statement handle to retrieve the handle's OCI_ATTR_ROWID attribute.

For example, for a SQL statement such as

SELECT ename FROM emp1 WHERE empno = 7499 FOR UPDATE OF sal

when the fetch is performed, the ROWID attribute in the handle contains the row identifier of the selected row. You can retrieve the ROWID into a buffer in your program by calling OCIAttrGet() as follows:

OCIRowid *rowid;   /* the rowid in opaque format */
/* allocate descriptor with OCIDescriptorAlloc() */
status = OCIDescriptorAlloc ((dvoid *) envhp, (dvoid **) &rowid,
     (ub4) OCI_DTYPE_ROWID, (size_t) 0, (dvoid **) 0);
status = OCIAttrGet ((dvoid*) mystmtp, OCI_HTYPE_STMT,
     (dvoid*) rowid, (ub4 *) 0, OCI_ATTR_ROWID, (OCIError *) myerrhp);

You can then use the saved ROWID in a DELETE or UPDATE statement. For example, if rowid is the buffer in which the row identifier has been saved, you can later process a SQL statement such as

UPDATE emp1 SET sal = :1 WHERE rowid = :2

by binding the new salary to the :1 placeholder and rowid to the :2 placeholder. Be sure to use datatype code 104 (ROWID descriptor) when binding rowid to :2.

Using prefetching, an array of ROWIDs can be selected for use in subsequent batch updates.

See Also:

For more information on ROWIDs, see "UROWID" and "DATE".

Reserved Words

Some words are reserved by Oracle. That is, they have a special meaning to Oracle and cannot be redefined. For this reason, you cannot use them to name database objects such as columns, tables, or indexes.

See Also:

To view the lists of the Oracle keywords or reserved words for SQL and PL/SQL, see the Oracle Database SQL Reference and the Oracle Database PL/SQL User's Guide and Reference

Oracle Reserved Namespaces

Table 2-5, "Oracle Reserved Namespaces" contains a list of namespaces that are reserved by Oracle. The initial characters of function names in Oracle libraries are restricted to the character strings in this list. Because of potential name conflicts, do not use function names that begin with these characters.

Table 2-5 Oracle Reserved Namespaces

Namespace Library

XA

external functions for XA applications only

SQ

external SQLLIB functions used by Oracle Precompiler and SQL*Module applications

O, OCI

external OCI functions internal OCI functions

UPI, KP

function names from the Oracle UPI layer

NA

NC

ND

NL

NM

NR

NS

NT

NZ

OS

TTC

Oracle Net Native Services Product

Oracle Net Rpc Project

Oracle Net Directory

Oracle Net Network Library Layer

Oracle Net Management Project

Oracle Net Interchange

Oracle Net Transparent Network Service

Oracle Net Drivers

Oracle Net Security Service

SQL*Net V1

Oracle Net Two Task

GEN, L, ORA

Core library functions

LI, LM, LX

function names from the Oracle Globalization Support layer

S

function names from system-dependent libraries

KO

Kernel Objects


For a complete list of functions within a particular namespace, refer to the document that corresponds to the appropriate Oracle library.

Nonblocking Mode in OCI

Because nonblocking mode increases the number of round trips and the CPU usage, use multithreaded calls for new applications.

See Also:

  • "Overview of OCI Multithreaded Development"

  • "The OCIThread Package"

The OCI provides the ability to establish a server connection in blocking mode or nonblocking mode. When a connection is made in blocking mode, an OCI call returns control to an OCI client application only when the call completes, either successfully or in error. With the nonblocking mode, control is immediately returned to the OCI program if the call could not complete, and the call returns a value of OCI_STILL_EXECUTING.

In nonblocking mode, an application must test the return code of each OCI function to see if it returns OCI_STILL_EXECUTING. If it does, the OCI client can continue to process program logic while waiting to retry the OCI call to the server. This mode is particularly useful in Graphical User Interface (GUI) applications, real-time applications, and in distributed environments.

The nonblocking mode is not interrupt-driven. Rather, it is based on a polling paradigm, which means that the client application has to check whether the pending call is finished at the server by executing the call again with the exact same parameters.

Note:

While waiting to retry a nonblocking OCI call, the application cannot issue other OCI calls, or an ORA-03124 error will occur; the only exceptions to this rule are the calls OCIBreak() and OCIReset().

Setting Blocking Modes

You can modify or check an application's blocking status by calling OCIAttrSet() to set the status, or OCIAttrGet() to read the status on the server context handle with the attrtype parameter set to OCI_ATTR_NONBLOCKING_MODE. You must set this attribute only after OCISessionBegin() or OCILogon2() has been called. Otherwise, an error will be returned.

See Also:

"Server Handle Attributes"

Note:

Only functions that have a server context or a service context handle as a parameter may return OCI_STILL_EXECUTING.

Cancelling a Nonblocking Call

You can cancel a long-running OCI call by using the OCIBreak() function while the OCI call is in progress. You must then issue an OCIReset() call to reset the asynchronous operation and protocol.

Using PL/SQL in an OCI Program

PL/SQL is Oracle's procedural extension to the SQL language. PL/SQL supports tasks that are more complicated than simple queries and SQL data manipulation language (DML) statements. PL/SQL lets you group a number of constructs into a single block and execute it as a unit. These constructs include:

  • One or more SQL statements

  • Variable declarations

  • Assignment statements

  • Procedural control statements such as IF...THEN...ELSE statements and loops

  • Exception handling

You can use PL/SQL blocks in your OCI program to perform the following operations:

  • Call Oracle stored procedures and stored functions

  • Combine procedural control statements with several SQL statements, to be executed as a single unit

  • Access special PL/SQL features such as tables, CURSOR FOR loops, and exception handling

  • Use cursor variables

  • Operate on objects in a server

    Note:

    • While the OCI can only directly process anonymous blocks, and not named packages or procedures, you can always put the package or procedure call within an anonymous block and process that block.

    • Note that all OUT variables have to be initialized to NULL (through an indicator of -1, or an actual length of 0) prior to executing a PL/SQL begin-end block in OCI.

    • OCI does not support the PL/SQL RECORD datatype.

    • When binding a PL/SQL VARCHAR2 variable in OCI, the maximum size of the bind variable is 32512 bytes, because of the overhead of control structures.

    Caution:

    When writing PL/SQL code, it is important to keep in mind that the parser treats everything that starts with "--" to a carriage return as a comment. So if comments are indicated on each line by "--", the C compiler can concatenate all lines in a PL/SQL block into a single line without putting a carriage return "/n" for each line. In this particular case, the parser fails to extract the PL/SQL code of a line if the previous line ends with a comment. To avoid the problem, the programmer should put "/n" after each "--" comment to make sure the comment ends there.

    See Also:

    Oracle Database PL/SQL User's Guide and Reference for information about coding PL/SQL blocks

OCI Globalization Support

The following sections introduce OCI functions that can be used for globalization purposes, such as deriving locale information, manipulating strings, character set conversion, and OCI messaging. These functions are also described in detail in other chapters of this guide because they have multiple purposes and functionality.

Client Character Set Control from OCI

The function OCIEnvNlsCreate() enables you to set character set information in applications, independently from NLS_LANG and NLS_NCHAR settings. One application can have several environment handles initialized within the same system environment using different client side character set IDs and national character set IDs.

OCIEnvNlsCreate(OCIEnv **envhp, ..., csid, ncsid); 

where csid is the value for character set ID, and ncsid is the value for national character set ID. Either can be 0 or OCI_UTF16ID. If both are 0, this is equivalent to using OCIEnvCreate() instead. The other arguments are the same as for the OCIEnvCreate() call.

OCIEnvNlsCreate() is an enhancement for programmatic control of character sets, because it validates OCI_UTF16ID.

When character set IDs are set through the function OCIEnvNlsCreate(), they will replace the settings in NLS_LANG and NLS_NCHAR. In addition to all character sets supported by NLSRTL, OCI_UTF16ID is also allowed as a character set ID in the OCIEnvNlsCreate() function, although this ID is not valid in NLS_LANG or NLS_NCHAR.

Any Oracle character set ID, except AL16UTF16, can be specified through the OCIEnvNlsCreate() function to specify the encoding of metadata, SQL CHAR data, and SQL NCHAR data.

You can retrieve character sets in NLS_LANG and NLS_NCHAR through another function, OCINlsEnvironmentVariableGet().

See Also:

"OCIEnvNlsCreate()"

Code Example for Character Set Control in OCI

For a pseudocode fragment that illustrates a sample usage of these calls:

See Also:

"Setting Client Character Sets in OCI"

Character Control and OCI Interfaces

OCINlsGetInfo() returns information about OCI_UTF16ID if this value has been used in OCIEnvNlsCreate().

OCIAttrGet() returns the character set ID and national character set ID that were passed into OCIEnvNlsCreate(). This is used to get OCI_ATTR_ENV_CHARSET_ID and OCI_ATTR_ENV_NCHARSET_ID. This includes the value OCI_UTF16ID.

If both charset and ncharset parameters were set to NULL by OCIEnvNlsCreate(), the character set IDs in NLS_LANG and NLS_NCHAR will be returned.

OCIAttrSet() sets character IDs as the defaults if OCI_ATTR_CHARSET_FORM is reset through this function. The eligible character set IDs include OCI_UTF16ID if OCIEnvNlsCreate() has it passed as charset or ncharset.

OCIBindByName() and OCIBindByPos() bind variables with default character set in the OCIEnvNlsCreate() call, including OCI_UTF16ID. The actual length and the returned length are always in bytes if OCIEnvNlsCreate() is used.

OCIDefineByPos() defines variables with the value of charset in OCIEnvNlsCreate(), including OCI_UTF16ID, as the default. The actual length and returned length are always in bytes if OCIEnvNlsCreate() is used. This behavior for bind and define handles is different from that when OCIEnvCreate() is used and OCI_UTF16ID is the character set ID for the bind and define handles.

Character Length Semantics in OCI

OCI works as a translator between server and client, and passes around character information for constraint checking.

There are two kinds of character sets, variable-width and fixed-width, as a single byte character set is just a special case of a fixed-width character set where each byte stands for one character.

For fixed-width character sets, constraint checking is easier as number of bytes is simply equal to a multiple of number of characters. Therefore, no scanning of the entire string is needed to determine the number of characters for fixed-width character sets. However, for variable-width ones, complete scanning is needed to determine the number of characters.

Character Set Support in OCI

See "Character Length Semantics Support in Describing" and "Character Conversion in OCI Binding and Defining" for a complete discussion.

Other OCI Globalization Support Functions

Many globalization support functions accept either the environment handle or the user session handle. The OCI environment handle is associated with the client NLS environment variables. This environment does not change when ALTER SESSION statements are issued to the server. The character set associated with the environment handle is the client character set. The OCI session handle (returned by OCISessionBegin()) is associated with the server session environment. The NLS settings change when the session environment is modified with an ALTER SESSION statement. The character set associated with the session handle is the database character set.

Note that the OCI session handle does not have NLS settings associated with it until the first transaction begins in the session. SELECT statements do not begin a transaction.

For complete details and discussions of the functions that follow:

See Also:

  • Chapter 21, "OCI Globalization Support Functions"

  • Oracle Database Globalization Support Guide

Getting Locale Information in OCI

An Oracle locale consists of language, territory, and character set definitions. The locale determines conventions such as day and month names, as well as date, time, number, and currency formats. A globalized application follows a user's locale setting and cultural conventions. For example, when the locale is set to German, users expect to see day and month names in German.

See Also:

  • "OCI Locale Functions"

  • "OCINlsEnvironmentVariableGet()"

You can retrieve the following information with the OCINlsGetInfo() function:

  • Days of the week (translated)

  • Abbreviated days of the week (translated)

  • Month names (translated)

  • Abbreviated month names (translated)

  • Yes/no (translated)

  • AM/PM (translated)

  • AD/BC (translated)

  • Numeric format

  • Debit/credit

  • Date format

  • Currency formats

  • Default language

  • Default territory

  • Default character set

  • Default linguistic sort

  • Default calendar

Example of Getting Locale Information in OCI

This example code retrieves information and checks for errors.

sword MyPrintLinguisticName(envhp, errhp)
OCIEnv   *envhp;
OCIError *errhp;
{
  OraText  infoBuf[OCI_NLS_MAXBUFSZ];
  sword ret;
  
  ret = OCINlsGetInfo(envhp,                           /* environment handle */
                      errhp,                                 /* error handle */
                      infoBuf,                         /* destination buffer */
                      (size_t) OCI_NLS_MAXBUFSZ,              /* buffer size */
                      (ub2) OCI_NLS_LINGUISTIC_NAME);                /* item */

  if (ret != OCI_SUCCESS) 
  {
    checkerr(errhp, ret, OCI_HTYPE_ERROR);
    ret = OCI_ERROR; 
  }
  else
  {
    printf("NLS linguistic: %s/n", infoBuf);
   }
  return(ret);
}

Manipulating Strings in OCI

Multibyte strings and wide character strings are supported for string manipulation:

Multibyte strings are encoded in native Oracle character sets. Functions that operate on multibyte strings take the string as a whole unit with the length of the string calculated in bytes. Wide character string (wchar) functions provide more flexibility in string manipulation. They support character-based and string-based operations where the length the string calculated in characters.

The wide character datatype, OCIWchar, is Oracle-specific and should not be confused with the wchar_t datatype defined by the ANSI/ISO C standard. The Oracle wide character datatype is always 4 bytes in all operating systems, while the size of wchar_t depends on the implementation and the operating system. The Oracle wide character datatype normalizes multibyte characters so that they have a uniform fixed width for easy processing. This guarantees no data loss for round trip conversion between the Oracle wide character set and the native character set.

String manipulation can be classified into the following categories:

  • Conversion of strings between multibyte and wide character

  • Character classifications

  • Case conversion

  • Calculations of display length

  • General string manipulation, such as comparison, concatenation, and searching

    See Also:

    "OCI String Manipulation Functions"

Example of Manipulating Strings in OCI

The following example shows a simple case of manipulating strings.

size_t MyConvertMultiByteToWideChar(envhp, dstBuf, dstSize, srcStr)
OCIEnv     *envhp;
OCIWchar   *dstBuf;
size_t      dstSize;
OraText    *srcStr;                         /* null terminated source string */
{
  sword  ret;
  size_t dstLen = 0;
  size_t srcLen;

  /* get length of source string */
  srcLen = OCIMultiByteStrlen(envhp, srcStr);
  
  ret = OCIMultiByteInSizeToWideChar(envhp,            /* environment handle */
                 dstBuf,                               /* destination buffer */
                 dstSize,                         /* destination buffer size */
                 srcStr,                                    /* source string */
                 srcLen,                          /* length of source string */
                 &dstLen);                  /* pointer to destination length */

  if (ret != OCI_SUCCESS)                                          
  {
    checkerr(envhp, ret, OCI_HTYPE_ENV);                 
  }
  return(dstLen);
}

Example of Classifying Characters in OCI

The OCI character classification functions are described in detail.

See Also:

"OCI Character Classification Functions"

The following example shows how to classify characters in OCI.

boolean MyIsNumberWideCharString(envhp, srcStr)
OCIEnv   *envhp;
OCIWchar *srcStr;                                 /* wide char source string */
{
  OCIWchar *pstr = srcStr;                        /* define and init pointer */
  boolean status = TRUE;            /* define and initialize status variable */

  /* Check input */
  if (pstr == (OCIWchar*) NULL)
    return(FALSE);


  if (*pstr == (OCIWchar) NULL)
    return(FALSE);

                                            /* check each character for digit */
  do 
  {
    if (OCIWideCharIsDigit(envhp, *pstr) != TRUE)
    {
      status = FALSE;
      break;                                  /* non-decimal digit character */
    }
  } while ( *++pstr != (OCIWchar) NULL);

  return(status);
}

Converting Character Sets in OCI

Conversion between Oracle character sets and Unicode (16-bit, fixed-width Unicode encoding) is supported. Replacement characters are used if a character has no mapping from Unicode to the Oracle character set. Therefore, conversion back to the original character set is not always possible without data loss.

Character set conversion functions involving Unicode character sets require data bind and define buffers to be aligned at a ub2 address, or else an error is raised.

See Also:

"OCI Character Set Conversion Functions"

Example of Converting Character Sets in OCI

The following example shows a simple conversion into Unicode.

/* Example of Converting Character Sets in OCI
--------------------------------------------*/

size_t MyConvertMultiByteToUnicode(envhp, errhp, dstBuf, dstSize, srcStr)
OCIEnv   *envhp;
OCIError *errhp;
ub2 *dstBuf;
size_t dstSize;
OraText *srcStr;
{
  size_t dstLen = 0;
  size_t srcLen = 0;
  OraText tb[OCI_NLS_MAXBUFSZ];   /* NLS info buffer */
  ub2    cid;                     /* OCIEnv character set id */

  /* get OCIEnv character set */
  checkerr(errhp, OCINlsGetInfo(envhp, errhp, tb, sizeof(tb),
                                OCI_NLS_CHARACTER_SET));
  cid = OCINlsCharSetNameToId(envhp, tb);

  if (cid == OCI_UTF16ID)
  {
    ub2    *srcStrUb2 = (ub2*)srcStr;
    while (*srcStrUb2++) ++srcLen;
    srcLen *= sizeof(ub2);
  }
  else
    srcLen = OCIMultiByteStrlen(envhp, srcStr);

  checkerr(errhp,
    OCINlsCharSetConvert(
      envhp,       /* environment handle */
      errhp,       /* error handle */
      OCI_UTF16ID, /* Unicode character set id */
      dstBuf,      /* destination buffer */
      dstSize,     /* size of destination buffer */
      cid,         /* OCIEnv character set id */
      srcStr,      /* source string */
      srcLen,      /* length of source string */
      &dstLen));   /* pointer to destination length */

  return dstLen/sizeof(ub2);
}

OCI Messaging Functions

The user message API provides a simple interface for cartridge developers to retrieve their own messages and Oracle messages.

See Also:

  • Oracle Database Data Cartridge Developer's Guide

  • "OCI Messaging Functions"

Example of Retrieving a Message from a Text Message File

This example creates a message handle, initializes it to retrieve messages from impus.msg, retrieves message number 128, and closes the message handle. It assumes that OCI environment handles, OCI session handles, product, facility, and cache size have been initialized properly.

OCIMsg msghnd;                                              /* message handle */
         /* initialize a message handle for retrieving messages from impus.msg*/
err = OCIMessageOpen(hndl,errhp, &msghnd, prod,fac,OCI_DURATION_SESSION);
if (err != OCI_SUCCESS)
                                                            /* error handling */
...
                            /* retrieve the message with message number = 128 */
msgptr = OCIMessageGet(msghnd, 128, msgbuf, sizeof(msgbuf));
                         /* do something with the message, such as display it */
...
      /* close the message handle when there are no more messages to retrieve */
OCIMessageClose(hndl, errhp, msghnd);

lmsgen Utility

The lmsgen utility converts text-based message files (.msg) into binary format (.msb) so that Oracle messages and OCI messages provided by the user can be returned to OCI functions in the desired language.

BNF Syntax of lmsgen

lmsgen text_file product facility [language]

where:

  • text_file is a message text file.

  • product is the name of the product.

  • facility is the name of the facility.

  • language is the optional message language corresponding to the language specified in the NLS_LANG parameter. The language parameter is required if the message file is not tagged properly with language.

Guidelines for Text Message Files

  • Lines that start with "/" and "//" are treated as internal comments and are ignored.

  • To tag the message file with a specific language, include a line similar to the following:

    #   CHARACTER_SET_NAME= Japanese_Japan.JA16EUC
    
    
  • Each message contains 3 fields:

    message_number, warning_level, message_text
    
    
  • The message number must be unique within a message file.

  • The warning level is not currently used. Set to 0.

  • The message text cannot be longer than 76 bytes.

The following is an example of an Oracle message text file:

/ Copyright (c) 2001 by the Oracle Corporation.  All rights reserved.
/ This is a test us7ascii message file
# CHARACTER_SET_NAME= american_america.us7ascii
/
00000, 00000, "Export terminated unsuccessfully/n"
00003, 00000, "no storage definition found for segment(%lu, %lu)"

Example: Creating a Binary Message File from a Text Message File

The following table contains sample values for the lmsgen parameters:

lmsgen Parameter Value
product $HOME/myApplication
facility imp
language AMERICAN
text_file impus.msg

The text message file is found in the following location:

$HOME/myApp/mesg/impus.msg

One of the lines in the text message file is:

00128,2, "Duplicate entry %s found in %s"

The lmsgen utility converts the text message file (impus.msg) into binary format, resulting in a file called impus.msb:

% lmsgen impus.msg $HOME/myApplication imp AMERICAN

The following output results:

Generating message file impus.msg -->
/home/scott/myApplication/mesg/impus.msb

NLS Binary Message File Generation Utility: Version 9.2.0.0.0 -Production

Copyright (c) Oracle Corporation 1979, 2001.  All rights reserved.

CORE    9.2.0.0.0       Production

你可能感兴趣的:(Oracle,C/C++)