Programmer's Guide to the Oracle7 Server Call Interface Go to Product Documentation Library
Library
Go to books for this product
Product
Go to Contents for this book
Contents
Go to Index
Index



Go to previous file in sequence Go to next file in sequence

Writing an OCI Program


This chapter introduces you to the basic concepts involved in writing a program using the Oracle Call Interface (OCI). The following topics are covered:


Basic Program Structure

When you write an application using the Oracle Call Interface, there are certain steps that you follow to ensure that the program works properly. At a minimum, your OCI application must perform the following steps

Step 1. Allocate data structures that allow you to connect to an Oracle Server/database and process cursors.

Step 2. Connect to one or more Oracle databases.

Step 3. Open one or more cursors to process SQL or PL/SQL statements, as needed by the program.

Step 4. Process the SQL or PL/SQL statements required to perform the application's tasks.

Step 5. Close the cursors.

Step 6. Disconnect from the databases.


OCI Data Structures

In an OCI program you define data structures that enable the program to connect to Oracle and process SQL and PL/SQL statements. The data structures that you use to connect to an Oracle database are called the logon data area (LDA) and the host data area (HDA). You declare one LDA-HDA pair for each concurrent connection that your program requires, and pass references to them in the OLOG call that makes the connection. Your program can reuse an LDA and associated HDA after it severs the database connection controlled by that LDA-HDA. See the introductory material on pages 4 - 2, 5 - 2, or 6 - 2 for examples of declaring these data structures.

To process a SQL or PL/SQL statement, you must define a cursor. The cursor is defined using a cursor data area (CDA) together with the OOPEN routine. Each concurrently active cursor requires a separate CDA structure. When you close a cursor, you can reuse the CDA that was associated with the old cursor for a new cursor.

Both the LDA and the CDA have a field called the return code field. This field holds a binary 16-bit value. It contains zero after an OCI call that referenced the LDA or CDA returns without error. Otherwise, the return code field contains the Oracle error code. See the Oracle7 Server Messages for a listing of the error codes and the associated error messages. In the program, you can also call the OERHMS routine to obtain the error message corresponding to an error return code.

Logon Data Area (LDA)

A logon data area (LDA) is a data area that you associate with an active connection to Oracle using the OLOG call. The format of the LDA for a typical 32-bit system is shown in Figure 2 - 1.

Figure 2 - 1. A Typical LDA (Logon Data Area)

The lengths and byte offsets of the fields in the LDA are system dependent. However, all fields are present for all systems. Check your Oracle system-specific documentation to see exactly how the LDA is configured. C programmers should use the definition of the LDA in the file ocidfn.h, which is listed in Appendix A and is available online. ocidfn.h is defined for each OCI platform, with the correct offsets.

The most commonly used field in the LDA is return code. Other named fields in the LDA are the same as the corresponding fields in the cursor data area. In new OCI programs, do not check the V2 return code field for error information. This field is present only for backward compatibility.

Note: Once you have established a connection, do not move the HDA or LDA data areas. The Oracle Server uses the address of these areas in processing OCI calls, and these addresses must remain the same during the life of a connection.

Host Data Area (HDA)

A host data area (HDA) is usually a 256-byte data structure that you must allocate in your program when you connect to an Oracle Server. You allocate one LDA and one HDA for each simultaneous connection to Oracle which passes the addresses of these data areas to the server when you log on to the database with the OCI OLOG routine.

The HDA is 256 bytes long on 32-bit systems only. On 64-bit systems the HDA is typically 512 bytes long. If your system is of a different size, check your Oracle system-specific documentation for the correct size of the HDA. Even on 32-bit systems it is possible to allocate a 512-byte HDA if memory permits. This may increase the portability of applications

Warning: The HDA must be properly declared and initialized before it is used in an OCI program. The HDA must be initialized to all zeros (binary zeros, not the "0" character) before the first call to OLOG, or runtime errors will occur. See the descriptions of the OLOG call[*] (for C), Chapter 5 (for COBOL) and Chapter 6 (for FORTRAN) for language-specific methods to perform the initialization.

Many existing OCI programs, including the demos and sample code in this manual, have defined the HDA as a block of 256 one-byte integers (e.g., ub1[256] in C). On some platforms this may cause errors or unpredictable behavior as a result of the integers in the data block not being properly aligned. If your system automatically aligns four-byte integers, you can eliminate the problem by defining the HDA as a block of 64 four-byte integers (e.g., ub4[64] in C).

Cursor Data Area (CDA)

A cursor data area (CDA) provides a mapping between the user cursor in your program and the parsed representation of the SQL statement in the server. Information about a SQL or PL/SQL statement is preserved in the system global area (SGA) and the private SQL area. As Oracle processes the SQL statements in your program, it updates fields in the CDA to show the progress and status of the statement processing.

Figure 2 - 2 shows the structure of a CDA for a typical 32-bit system. The lengths of the fields in the CDA, and hence the offsets of the fields, are system dependent. However, all fields are present for all systems. The CDA is always 64 bytes, but check your Oracle system-specific documentation for the exact configuration of the CDA.

Note: C programmers should use the definition of the CDA listed in "Calling OCI Routines" [*] (and available online in the header file ocidfn.h). Also, see the example programs in Appendix A.

In particular, the size of the Oracle ROWID field in the CDA can be system dependent. Figure 2 - 2 shows a 13-byte ROWID, typical on systems that byte-align C structure fields. Check your Oracle system-specific documentation for the exact size and offsets of the members of the CDA data structure for your system. Also, see the description of ROWID in "External Datatypes" [*].

Figure 2 - 2. The CDA (Cursor Data Area)

Each of the fields in the CDA that an OCI program requires is described in the following sections.

V2 Return Code

In C, OCI calls return a two-byte binary integer. If the V2 return code is zero, no error has occurred, and if it is non-zero an error has occurred. At present this return code is the same as the Oracle V2 (version 2) Return Code. The V2 Return Code field contains the same number.

Note: This field is for backward compatibility only. It might not be supported in future OCI versions. Use the return code field described below in new OCI applications.

Code SQL FUNCTION Code SQL FUNCTION Code SQL FUNCTION
01 CREATE TABLE 26 ALTER TABLE 51 DROP TABLESPACE
02 SET ROLE 27 EXPLAIN 52 ALTER SESSION
03 INSERT 28 GRANT 53 ALTER USER
04 SELECT 29 REVOKE 54 COMMIT
05 UPDATE 30 CREATE SYNONYM 55 ROLLBACK
06 DROP ROLE 31 DROP SYNONYM 56 SAVEPOINT
07 DROP VIEW 32 ALTER SYSTEM SWITCH LOG 57 CREATE CONTROL FILE
08 DROP TABLE 33 SET TRANSACTION 58 ALTER TRACING
09 DELETE 34 PL/SQL EXECUTE 59 CREATE TRIGGER
10 CREATE VIEW 35 LOCK TABLE 60 ALTER TRIGGER
11 DROP USER 36 (not used) 61 DROP TRIGGER
12 CREATE ROLE 37 RENAME 62 ANALYZE TABLE
13 CREATE SEQUENCE 38 COMMENT 63 ANALYZE INDEX
14 ALTER SEQUENCE 39 AUDIT 64 ANALYZE CLUSTER
15 (not used) 40 NOAUDIT 65 CREATE PROFILE
16 DROP SEQUENCE 41 ALTER INDEX 66 DROP PROFILE
17 CREATE SCHEMA 42 CREATE EXTERNAL DATABASE 67 ALTER PROFILE
18 CREATE CLUSTER 43 DROP EXTERNAL DATABASE 68 DROP PROCEDURE
19 CREATE USER 44 CREATE DATABASE 69 (not used)
20 CREATE INDEX 45 ALTER DATABASE 70 ALTER RESOURCE COST
21 DROP INDEX 46 CREATE ROLLBACK SEGMENT 71 CREATE SNAPSHOT LOG
22 DROP CLUSTER 47 ALTER ROLLBACK SEGMENT 72 ALTER SNAPSHOT LOG
23 VALIDATE INDEX 48 DROP ROLLBACK SEGMENT 73 DROP SNAPSHOT LOG
24 CREATE PROCEDURE 49 CREATE TABLESPACE 74 CREATE SNAPSHOT
25 ALTER PROCEDURE 50 ALTER TABLESPACE 75 ALTER SNAPSHOT
76 DROP SNAPSHOT
Table 2 - 1. SQL Function Codes

SQL Function Code

The SQL function code is a two-byte binary integer used internally by Oracle. There is a SQL function code for each SQL command. The SQL function codes are subject to change between OCI versions. They are shown in Table 2 - 1.

Note: The SQL function code is not valid until the parse is performed. This happens on the call to OPARSE, unless the parse has been deferred, in which case it happens on the next describe or execute call. If the statement you parse is a PL/SQL block, the SQL function code is 34.

Rows Processed Count

This field contains a four-byte binary integer that counts the number of rows processed by a SQL statement. The count indicates the number of rows inserted, updated, or deleted by a data manipulation statement, or the cumulative number of rows fetched for the result set of a query.

The rows processed count field is valid only after an OEXEC, OEXN, OEXFET, OFEN, or OFETCH call. For queries, it is reset to zero when OEXEC or OEXN is called and is incremented after OFETCH or OFEN. For OEXFET, the count is reset to zero on the execute part of the call and is set when the fetch completes.

Note: If a query returns a number of rows which is too large to fit into a four-byte integer, the contents of the rows processed field is undefined. Additionally, it is undesirable to issue queries which will return such a large number of rows, due to the extensive time required for Oracle to process such a query.

Parse Error Offset

This field contains a two-byte binary integer that indicates the starting byte position in the SQL statement where a parse error was detected. The first character of the SQL statement is at position zero. If the statement is longer than 64K bytes, the parse error offset is undefined.

A parse error can have many causes. Among them are a syntax error in the statement, a security violation, or a non-existent table or column. The parse error offset field is valid only after an OPARSE call. OCI calls other than OPARSE might leave a value in this field, but it is not meaningful.

When dealing with national language support (NLS) servers, be aware that the parse error offset may be incorrect due to a difference in character length between the client and server machines.

Note: The parse error offset field is not valid until the parse is performed. This happens on the call to OPARSE, unless the parse has been deferred, in which case it happens on the next describe or execute call.

OCI Function Code

The OCI function code field contains a one-byte binary integer that indicates the most recently completed OCI routine. There is a function code for each OCI routine that uses the cursor data area. Routines that reference only the LDA (like OLOG) do not have a function code.

Table 2 - 2 lists the OCI function codes for routines that use the CDA. Codes for which no OCI routine is listed are unused.

# OCI ROUTINE # OCI ROUTINE # OCI ROUTINE
04 OEXEC, OEXN 26 OSQL3 58 OFLNG
08 ODEFIN 28 OBNDRV 60 ODESCR
12 OFETCH, OFEN 30 OBNDRN 62 OBNDRA
14 OOPEN 34 OOPT 63 OBINDPS
16 OCLOSE 52 OCAN 64 ODEFINPS
22 ODSC 54 OPARSE 65 OGETPI
24 ONAME 56 OEXFET 66 OSETPI
Table 2 - 2. OCI Function Codes

Return Code

The return code is a two-byte positive binary integer that contains the Oracle error code for the most recently executed statement. Error codes and messages are listed in Oracle7 Server Messages. Use the OERHMS call to retrieve error message text associated with the return code.

Warning Flags

The warning flags field contains bit warning flags. More than one bit can be set. The table below lists the flags by bit position.

Bit Value Hex Description
1 1 There is a warning. This is set when any other bit in warning flags is set.
2 2 Set if any data item was truncated on a fetch.
4 4 This is set if a NULL was encountered during aggregate function evaluation.
8 8 This bit is not used.
16 10 Set if an UPDATE or DELETE statement does not contain a WHERE clause. This is set by OPARSE when the parse is performed (it may be deferred).
32 20 A PL/SQL package or procedure was compiled and entered in the database; however, there were compilation errors. This flag is set when a CREATE PROCEDURE, CREATE FUNCTION, CREATE TRIGGER, CREATE PACKAGE, or CREATE PACKAGE BODY statement caused the compilation error.
64 40 Set when a fatal error occurred and a transaction was completely rolled back. Not used in Version 6 and later versions of the Oracle Server.
128 80 This bit is not used.

Oracle ROWID

This field holds the ROWID in Oracle internal binary format (equivalent to external datatype 11) and is valid after INSERT, UPDATE, DELETE, and SELECT FOR UPDATE operations. It is not valid after a SELECT that does not contain the FOR UPDATE clause.

If a multi-row operation is performed, the Oracle ROWID field gets set to the ROWID of the last row that was operated on.

Note: The contents of the Oracle ROWID field are also undefined for OCI programs that are connected to non-Oracle data managers using an Oracle Open Gateway. These programs must use the ROWID pseudocolumn directly in SELECT statements and then use the returned ROWID in INSERT, UPDATE, and DELETE statements to identify specific rows in the non-Oracle data manager. See the section "Using ROWID" [*] for an example of this.

See the descriptions of ROWID in "External Datatypes" [*] for more information. The size of the Oracle ROWID field is system dependent. You can determine the size in several ways:

OSD Error Code

This field contains an operating system-dependent (OSD) error code associated with an Oracle error. For example, if Oracle7 receives an error when trying to perform disk I/O, the OSD error code field is set to an operating system-dependent I/O system failure code. These codes are not documented in this manual.


SQL Statement Processing

An OCI application processes SQL statements differently depending on the kind of statement. You must remember the kind of SQL statement being processed when writing your OCI code. If the application is processing dynamic statements (statements whose contents are not known at compile time), you can check the SQL function code after the statement is parsed to determine the steps needed to process the statement. The second sample program [*] (for C), B - 11 (for COBOL), and C - 12 (for FORTRAN) demonstrates this.

There are eight kinds of SQL statements in Oracle7:

Queries represent an additional kind of statement when using the OCI. Queries are often classified as DML statements, but OCI applications process queries differently, so they are considered separately here.

Data Definition Language Statements

Data Definition Language (DDL) statements manage entities in the database. DDL statements create new tables, drop old tables, and establish other schema objects. They also control access to schema objects. For example:

CREATE TABLE wine_list
    (name CHAR(20), type CHAR(20), year NUMBER(4),
     bin NUMBER(4))
DROP TABLE wine_list
GRANT UPDATE, INSERT, DELETE ON wine_list TO scott
REVOKE UPDATE ON wine_list FROM scott

Control Statements

OCI applications treat Transaction Control, Session Control, and System Control statements like DML statements. See Oracle7 Server SQL Reference for information about these statements.

Data Manipulation Language Statements

Data Manipulation Language (DML) statements can change data in the database tables. These statements are used to

DML statements can require the program to input data to the database using input (bind) variables.

PL/SQL

PL/SQL is Oracle's procedural language extension to the SQL language. PL/SQL processes tasks that are more complicated than simple queries and SQL Data Manipulation Language statements. PL/SQL allows a number of constructs to be grouped into a single block and executed as a unit. Among these constructs are

You can use PL/SQL blocks in your OCI program to

See the PL/SQL User's Guide and Reference for information about coding PL/SQL blocks.

Queries

Queries are statements that retrieve data from a database. A query can return zero, one, or many rows of data. All queries begin with the SQL keyword SELECT. Queries access data in tables; they are often classified with DML statements. However, OCI applications process queries differently, so they are considered separately in this guide.

Embedded SQL Statements

An OCI application never uses embedded SQL statements. They are used for the Oracle Precompilers (Pro*C/C++, Pro*COBOL, Pro*FORTRAN, Pro*Ada, Pro*PL/I, Pro*Pascal) only.

The Steps in Processing a Statement

When you write OCI code to process a SQL statement, there are several distinct steps you must accomplish. Some SQL statements require only one step, but others can require four or five steps. Piecewise operations require extra steps, which are described in the section "Piecewise Insert, Update and Fetch" later in this chapter.

For information on deferring the parse, see the next section, "Deferred Statement Execution."

Once you have connected to Oracle and opened a cursor, the basic steps in processing a SQL statement are the following:

Step 1. Parse the statement using OPARSE. DDL statements, which do not accept input values or return results, can be executed directly by OPARSE if the program is linked in non-deferred mode or if it is linked in deferred mode and the OPARSE parameter DEFFLG is zero. No further processing is required. Transaction control statements must execute after the parse.

Step 2. For DML statements and queries, call OBNDRA, OBNDRV, OBNDRN or OBINDPS to bind the address of each input variable (or PL/SQL output variable) or array to each placeholder in the statement. OBINDPS is valid only in deferred mode and is necessary if piecewise operations or arrays of structures are used.

Step 3. For queries, describe the select-list items using ODESCR. This is an optional step; it is not required if the number of select-list items and the attributes of each item (such as its length and datatype) are known at compile time. If the parse was deferred, it is performed when the query is described. If the SQL statement being processed is not a query, ODESCR will generate an error.

Step 4. For queries, call ODEFIN or ODEFINPS to define an output variable for each select-list item in the SQL statement. Note that you do not use ODEFIN or ODEFINPS to define the output variables in an anonymous PL/SQL block, OBNDRV or OBNDRA is used instead. ODEFINPS is valid only in deferred mode and is necessary if piecewise operations or arrays of structures are used.

Step 5. For DML and transaction control statements, call OEXN to execute the statement. If the parse was deferred, it will be performed at this point.

Step 6. For queries, call OEXFET or the combination of OEXEC and OFETCH to execute the statement and then fetch the rows that satisfy the statement. If all the rows in the result set are not retrieved by an OEXFET call, it is necessary to call OFEN, perhaps more than once, to fetch the remaining rows. If the parse was deferred, and ODESCR was not called, the parse is performed at this point.

Following these steps, the application can close the statement cursor and log off of Oracle. Each of the steps above is described in detail in the section "Steps in Developing an OCI Program" [*].


Deferred Statement Execution

Before Oracle7 Server, Release 7.0, each call to an OCI routine required a corresponding call to the server. For example, when you parsed a SQL statement using OSQL3, the text of the SQL statement was transmitted to the server, and the statement was parsed and stored in the process global area (PGA). If placeholders were present in the statement, addresses of the input variables were bound to the placeholders by passing their addresses to the server. This required one call to the server for each input variable. A query required additional server calls to define addresses of program variables to hold select-list items. Finally, when the statement was executed, Oracle would request the values of any input variables, execute the statement, and, for a query, return the results. This required an additional server call.

When the OCI application and the Oracle Server are running on the same machine, multiple calls to Oracle have only a slight impact on performance. In a networked client/server environment, in which the OCI program runs on a client machine and the Oracle Server to which the program is connected runs on a different system (that might be thousands of kilometers away), separate calls to the database server may decrease performance.

To enhance performance, the OCI and Oracle7 now allow you to defer the execution of one or more steps in the processing of a SQL statement. For example, you can defer the processing of the step that parses the SQL statement and the steps that bind input variables and define output variables until the statement is actually executed.

If there is no describe (ODESCR) call, an entire query can be executed and the results fetched in one server call requiring only a single network round-trip.

Controlling Deferred Execution

Two factors control deferred execution of the parse, bind, and define steps:

Deferred Mode Linking

When you link your OCI program using deferred mode linking and your program is connected to an Oracle7 Server, the bind and define steps are always deferred until the statement executes. This behavior does not depend upon the particular OCI calls that your application uses, only on the link option that you select. For example, if you relink existing Version 6 OCI programs with the deferred mode link option, the bind and define calls are always deferred, (but not necessarily the parse).

Deferred mode linking selects new Oracle7 OCI libraries that buffer bind and define variable information on the client system using dynamically allocated memory, until that information is required by Oracle to process a SQL statement. This method does require additional memory on the client system.

Deferred mode linking is the default. See your Oracle system-specific documentation for information on setting non-deferred mode linking.

Deferring the Parse Step

When you link your program in deferred mode and you use the Oracle7 OPARSE call to parse a SQL statement with the DEFFLG flag set to a non-zero value, the parse step is similarly deferred. Thus, you can defer all OCI operations until the statement actually executes. Version 6 OCI programs must be recoded using OPARSE (replacing OSQL3) to obtain deferred parse behavior.

Note: If you use ODESCR to describe properties of select-list items of a query, any pending bind and define call information for that cursor is sent to Oracle immediately. The statement is parsed if necessary, then the describe operation is performed.

Non-Deferred Linking

Non-deferred linking results in behavior similar to that of Version 6 OCI applications. Version 6 programs can be relinked using non- deferred linking and run without change against the Oracle7 Server.

Deferred mode linking requires additional memory on the client system to buffer call data. If memory resources on the client system are scarce, you might want to use non-deferred linking.

The new release 7.3 routines for binding and defining variables, OBINDPS and ODEFINPS are not valid when an application is linked in non-deferred mode. Deferred linking is necessary to utilize these calls and the functionality they provide for piecewise operations and arrays of structures.

Relinking Version 6 OCI Applications

You must be careful when relinking existing Version 6 OCI applications if you wish to take advantage of deferred OCI statement execution.

While existing applications can be relinked in deferred mode, changes in the time that errors are reported can affect program behavior. For example, some bind and define errors, which formerly were identified immediately when the bind or define call was executed, now will not be identified until the SQL statement is executed or described.

You should examine existing version 6 OCI applications carefully to determine if you can use deferred mode execution without changes to application logic.

Comparing Deferred and Non-deferred Linking

The figures on the following pages show how the parse, bind, define, and execute/fetch OCI calls communicate with Oracle using both deferred and non-deferred parsing.

The numbers in the figures indicate the order in which the particular calls are made. The hollow circles in Figure 2 - 4 indicate calls which are made before execution (as demonstrated in Figure 2 - 3) but which are deferred (not sent to the server) until after Step 4.

In this example, the OPARSE, OBNDRA and ODEFIN calls are deferred until an execute or describe call is performed.

Figure 2 - 3. Statement Processing Deferred Parse (Before Execution)

Figure 2 - 4. Statement Processing Deferred Parse (After Execution)

Figure 2 - 5. Statement Processing Non-Deferred Parse

As Figure 2 - 5 demonstrates, when the parse is not deferred, error codes are returned as soon as each call is made to the server. When the parse is deferred, as in Figure 2 - 3 and Figure 2 - 4, error codes for the parse, bind, and define steps are not returned until the describe or execute call is performed.


Developing an OCI Program

Each of the steps that you perform to develop an OCI application is described in greater detail in this section. 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.

The special case of piecewise inserts, updates and fetches is described in detail in the section "Piecewise Insert, Update and Fetch" later in this chapter.

Special considerations for operations involving arrays of structures are described in the section "Arrays of Structures" later in this chapter.

For special information and calls related to the use of multi-threaded programming in the C language, see the section "Thread Safety" later in this chapter.

Refer to the section "The Steps in Processing a Statement" [*] for an outline of the steps involved in processing a SQL statement within an OCI program.

The following sections explain how to perform these steps:

Define the OCI Data Structures

Before connecting to Oracle, your program must define at least one LDA. If the program requires multiple simultaneous connections, define one LDA for each simultaneous connection. The way you define these data areas depends on the language you are using. You must also define a HDA for each LDA. There must be one HDA/LDA pair per database connection. For examples showing the use of the LDA and HDA, see the description of the OLOG call [*] for C, 5 - 76 for COBOL, or 6 - 70 for FORTRAN, and the sample OCI programs in Appendix A, B, and C.

To process SQL statements, you define one or more CDAs, one for each SQL statement that is simultaneously active. If your program processes SQL statements serially, you might need only one CDA. The CDAs are defined in the same way as the LDAs.

Connect to the Oracle Server

Your program establishes communication with one or more Oracle databases by calling OLOG. To connect to Oracle, first define a LDA and a HDA in your program. Communication with Oracle is established at connect time; it takes place using the LDA and HDA that you define.

If your OCI program requires only a single database connection at a time, you can use OLOG and OLOGOF alternately to make and terminate that connection.

Any number of simultaneous connections can be made using OLOG.

Restrictions on Connections

When you link a program using the single-task driver, it can only connect to one database at a time, which is implicitly the default database. If another database is desired, it must be explicitly referenced in the OLOG call. Additional connections to the same database, if desired, must be made using OLOG.

There are two communications modes of connecting to an Oracle database, blocking and non-blocking. With the blocking mode, an OCI call returns only when it completes, either successfully or in error. With the non-blocking mode, control is immediately returned to the OCI program if the call could not complete (with ORA-03123 message). In this case, the OCI client can continue to process other statements while waiting to retry the OCI call to the server.

Note: The non-blocking mode is based on a polling paradigm, which means that the client application must check whether the pending call has finished at the server by executing the call again with the same parameters.

See the section "Non-Blocking Mode" [*] for more information about connection modes.

Open the Cursors

To process a SQL statement, you must have an open cursor. You make the association between the data structures representing a valid cursor that are maintained by Oracle and a CDA in your program by calling the OOPEN routine. Perform this step after connecting to Oracle, because a valid LDA is a required parameter for the OOPEN call. This step must be performed before the CDA can be used to parse a SQL statement.

Each open cursor in an OCI application is associated with a particular server/database. If an OCI program has connections to more than one database, the total number of cursors which may be open concurrently within the program is the sum of the OPEN_CURSORS parameters of the two databases. For example, if an OCI client is connected to both db1, which has OPEN_CURSORS set to 50, and db2, which has OPEN_CURSORS set to 100, the OCI client can have up to 150 open cursors. It is important to keep in mind, however, that no more than 50 of those can be associated with db1, and no more than 100 can be associated with db2.

You can use cursors to execute the same SQL statement repeatedly or to execute a new SQL statement. When a cursor is reused, the contents of the corresponding CDA in your program are reset when the new SQL statement is parsed. It is never necessary to close and reopen a cursor before reusing it.

Parse the Statement

Every SQL statement must be parsed using the OPARSE routine.

Parsing the statement associates it with the CDA in your program. The exact semantics of the OPARSE routine are documented [*] for C, 5 - 87 for COBOL, or 6 - 80 for FORTRAN.

Data Definition Language statements are executed on the parse if you have linked in non-deferred mode or if you have linked with the deferred option and the DEFFLG parameter of OPARSE is zero. If you have linked in deferred mode and the DEFFLG parameter is non-zero, you must call OEXN or OEXEC to execute the statement.

Oracle recommends that you use the deferred parse capability whenever possible. This results in increased performance, especially in a networked environment. Note, however, that errors in the SQL statement that would be detected when OPARSE is called in non-deferred mode are not detected in deferred mode until the first non-deferred call is made (usually an execute or describe call).

All DML statements, PL/SQL blocks, and queries require further processing after the parse step.

Bind the Addresses of Input Variables

Most DML statements, and some queries (such as those having a WHERE clause), require that program data be passed to Oracle as part of a SQL or PL/SQL statement.

Such data can be constant or literal data, known when your program is compiled. For example, the SQL statement

INSERT INTO wine_list (name, type, year, bin_no) VALUES
    ('Joseph Swan Vineyards', 'ZINFANDEL', NULL, 112)

contains several literals, such as 'ZINFANDEL' and 112.

This kind of statement is very limited, to say the least. You would not want to change and recompile the program each time a new bottle is added to the cellar. Instead, you write the program so that the input data is supplied at runtime.

Placeholders

When you define a SQL statement or PL/SQL block that contains input data to be supplied at runtime, placeholders in the SQL statement or PL/SQL block mark where data must be supplied. For example, the SQL statement

INSERT INTO wine_list (name, type, year, bin_no) VALUES
    (:Name, :Type, :Year, :Bin_Number)

contains four placeholders, indicated by the leading colons, that show where input data must be supplied by the program.

The following short PL/SQL block contains two placeholders:

char plsql_statement[] = "BEGIN\
                           RAISE_SALARY(:EMP_NUMBER, :NEW_SAL);\
                          END;" ;

You can use placeholders for input variables in any DELETE, INSERT, SELECT, or UPDATE statement, or PL/SQL block, in any position in the statement where you can use an expression or a literal value.

Note: Placeholders cannot be used to name other Oracle objects such as tables or columns.

For each placeholder in the SQL statement or PL/SQL block, you must call an OCI routine that binds the address of a variable in your program to the placeholder. Thus when the statement executes, Oracle gets the data that your program placed in the input, or bind, variables.

Data does not have to be in a bind variable when you perform the bind step. At the bind step, you are only telling Oracle the address, datatype, and length of the variable. Make sure, however, that the variable contains valid data when you execute the SQL statement or PL/SQL block.

Note: If you change only the value of a bind variable, it is not necessary to rebind in order to execute the statement again. The bind is a bind by reference, so as long as the address of the bind variable remains valid, it is possible to re-execute a statement that references the variable without rebinding.

Routines that Bind Addresses

There are four OCI routines that you can use to bind addresses to placeholders: OBNDRV, OBNDRN, OBNDRA and OBINDPS.

OBNDRV When you use OBNDRV, you must specify the name of the placeholder. Thus, for the statement above, you specify ":Year" as the name of the placeholder for the year value.

OBNDRV can be used in interactive applications, where the user will enter a SQL statement at runtime. In this case, however, your program must scan the SQL statement to obtain the placeholder names. For an example, see the second sample program [*] for C, B - 11 for COBOL, and C - 12 for FORTRAN.

The name of a placeholder for the OBNDRV routine cannot be a reserved word. For example, the following SQL statement is not legal, because ROWID is a reserved word:

SELECT ename FROM emp WHERE rowid = :ROWID

A list of Oracle reserved words, keywords and namespaces can be found in Appendix H.

OBNDRN To use OBNDRN, each placeholder must be in the form :N, where N is a literal integer between 1 and 255. Consider the following example:

SELECT ename, sal FROM emp
    WHERE (job = :1 AND sal > :2)
    OR
    (job != :1 AND sal < :2)

is a valid SQL statement for the OBNDRN routine. Note that in this statement there are four instances of a placeholder, but really only two placeholders. Thus only two bind variables are needed. You only need to call OBNDRN twice for this statement. All occurrences of a placeholder in a SQL statement are bound on a single call.

The OBNDRN routine allows you to use an index variable to iterate through a set of placeholders.

Note: You cannot use OBNDRN to bind variables in a PL/SQL block. You must use OBNDRA or OBNDRV.

OBNDRA The OBNDRA routine binds addresses of scalars or arrays in your program to placeholders in a SQL statement or a PL/SQL block. OBNDRA is similar to OBNDRV, but it provides additional parameters that indicate the maximum size of an array, the number and lengths of array elements returned, and return errors on a column-by-column basis. OBNDRA is also used to bind C arrays or COBOL tables to PL/SQL tables.

OBINDPS The OBINDPS routine subsumes much of the functionality of the OBNDRA and OBNDRN routines for binding placeholders in SQL statements or PL/SQL blocks. Additionally, the OPCODE parameter can signal that an application will be providing inserted or updated data incrementally at runtime. OBINDPS is also used when the application will be inserting data stored in an array of structures.

OBINDPS is supported only when applications are linked in deferred mode and run against Oracle Server release 7.3 or later. If applications are linked in non-deferred mode or run against a release 7.2 or earlier server, another bind routine must be used. In that case, the ability to handle piecewise operations and arrays of structures is not supported.

For information about using OBINDPS with piecewise operations or arrays of structures, see the sections "Piecewise Insert, Update and Fetch" and "Arrays of Structures" later in this chapter.

Describe Select-List Items

If the SQL statement is a query, you might need to obtain more information about the select-list items. This is particularly true for dynamic queries, that is, queries whose contents are not known until runtime. In this case, the program might not have prior information about the datatypes, column lengths, or display sizes of the select-list items.

For example, a user might enter a query such as

SELECT * FROM wine_list

where the program has no prior information about the columns in the table WINE_LIST.

You can obtain this information using the ODESCR (describe) routine. ODESCR returns information about the nth select-list item, where n is an IN parameter. You can use this information to determine how to convert, display, or store the data that will be returned when the rows are fetched for the query.

To process dynamic select lists, call ODESCR in a loop. Set an index variable to one at the start of the loop, then increment it, doing the describe at each iteration, until a "variable not in select list" error (ORA-01007) is returned in the return code field of the CDA. The following C language code fragment demonstrates this process. For a more complete example, see the description of the odescr() routine [*], or the cdemo2 example program in Appendix A (for C), Appendix B (for COBOL) or Appendix C (for FORTRAN).

for (pos = 1; pos <= NPOS; pos++) {
  cbufl[pos] = sizeof cbuf[pos];
  if (odescr(&cda, pos, &dbsize[pos], &dbtype[pos],
             &cbuf[pos], &cbufl[pos], &dsize[pos],
             &prec[pos], &scale[pos], &nullok[pos])) {
    if (cda.rc == 1007)
      break;
    oci_error();
    continue;
  }

Note: If you have deferred the parse, then the statement will be parsed when ODESCR is called.

Execute the Statement

If the SQL statement is a DML statement, you must execute the statement. The execute operation inputs the values in all bind variables to Oracle.

There are different ways to input data to Oracle. You can execute a SQL statement repeatedly using the OEXEC routine and supply different input values on each iteration. Alternatively, you can use the Oracle array interface and input many values with a single statement by using the OEXN routine. (You can also use OEXN to execute a statement that processes only a single row of data.)

Note: If you change only the value of a bind variable, it is not necessary to rebind in order to execute the statement again. The bind is a bind by reference, so as long as the address of the bind variable remains valid, it is possible to re-execute a statement that references the variable without rebinding.

The array interface significantly reduces communications traffic with Oracle when you need to update or insert a large volume of data. This can lead to considerable performance gains, especially in a client/server environment. For example, consider an application that needs to insert 10 rows into the database. Calling OEXEC ten times with different values results in ten network round-trips to insert all the data. The same result is possible with a single call to OEXN which involves only one network round-trip.

Define Select-List Items

For a query, you use the ODEFIN or ODEFINPS routine to associate the address of an output variable (or array) in your program with each select-list item in the query. If you do not know in advance the number of select-list items, as in the case

SELECT * FROM wine_list

you might first call ODESCR repeatedly to determine the number. You can also call ODESCR and then ODEFIN or ODEFINPS in the same loop, and exit the loop when ODESCR returns the "variable not in select-list" error. See the cdemo2 example program in Appendix A (for C), Appendix B (for COBOL) or Appendix C (for FORTRAN), for an example showing the use of ODESCR and ODEFIN in a loop.

Note: You do not use ODEFIN or ODEFINPS to define select-list items in a SQL SELECT statement in a PL/SQL block. You must use OBNDRA or OBINDPS (or OBNDRV) in this case.

You can call ODEFIN or ODEFINPS again to redefine the output variables without having to reparse or re-execute the SQL statement.

ODEFINPS provides additional functionality for piecewise fetches and fetches into arrays of structures. For information about using ODEFINPS in these situations, see the sections "Piecewise Insert, Update and Fetch" and "Arrays of Structures" later in this chapter.

Fetch the Rows for the Query

After you have defined the addresses of output variables, you can fetch the rows that satisfy a query by calling one of the following routines:

If you plan to use OEXFET or OFEN to fetch multiple rows, you must make sure that the output variables you define for the select-list items are arrays. There are also optional OUT parameters that must be arrays if you are using the array interface. For example, output variables for indicator variables and column return code values must also be arrays. See the descriptions of OEXFET, page 4 - 65 for C, 5 - 59 for COBOL, or 6 - 56 for FORTRAN, and OFEN, page 4 - 70 for C, 5 - 64 for COBOL, or 6 - 61 for FORTRAN, for more information.

Close the Cursors

Before your program exits, close each open cursor using the OCLOSE routine. Once a cursor is closed, the CDA is no longer associated with the Oracle Server, and any memory areas in the server used by that cursor are freed.

Note: After using a cursor to execute a SQL statement or PL/SQL block, you can reuse that cursor for a new SQL statement or PL/SQL block without closing and reopening it.

If it is necessary to issue an OOPEN call on a cursor that has already been opened by your application and used to execute a SQL statement or PL/SQL block, be sure to call OCLOSE to close that cursor before making the call to OOPEN.

Note: The SQL92 standard requires that a cursor be closed on a commit. Repeatedly opening the same cursor when committing small transactions is inefficient and is a performance issue. Oracle7 permits a fetch after a commit without closing a cursor as a performance enhancement. This applies only to interoperating Oracle7, release 7.0 or higher servers. This does not apply to Oracle gateways accessing non-Oracle data sources. When an Oracle server interoperates with an Oracle gateway server, a cursor must be explicitly closed and opened again before another fetch can occur.

Commit or Rollback

Disconnecting from Oracle using OLOGOF causes an implicit commit. You can force a commit by using the OCOM routine. If you want to roll back the transactions, use the OROL routine.

Note: If an application disconnects from Oracle in some way other than a call to OLOGOF (for example, losing a network connection), and OCOM has not been called, the transaction is rolled back automatically.

Disconnect from Oracle

Call OLOGOF before the program exits to close connections to Oracle. Call OLOGOF for each LDA that was referenced in an OLOG call.


Coding Rules

This section explains some of the general rules that you should follow when coding an OCI application.

Parameter Datatypes

OCI calls use the following types of parameters:

Address parameters pass the address of the variable to Oracle. You should be careful when developing in C, which normally passes scalar parameters by value, to make sure that the parameter is an address. For example, if a parameter for a routine is specified as the address of a short integer, and rcode is the variable in your program for that parameter, be sure to pass it as &rcode in C.

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

For language-specific information about parameter datatypes and parameter passing conventions, refer to the introductory section in the chapter that covers the language you are using: page 4 - 2 for C, 5 - 2 for COBOL, or 6 - 2 for FORTRAN.

Character Strings

Character strings are a special type of address parameter. The following discussion describes additional rules that apply to character string address parameters.

Each OCI routine that allows a character string to be passed as a parameter also has a string length parameter. The length parameter should be set to the exact length of the string. If the string is terminated by a null character (as is often the case in C), you can specify -1 for the length parameter (do not use zero).

Literal character strings can be passed if permitted by the compiler. Note, however, that since character strings are address parameters, your compiler must actually pass the address of the literal.

Indicator Variables

The bind and define OCI calls (OBNDRA, OBNDRV, OBNDRN, OBINDPS, ODEFINPS and ODEFIN) each have a parameter that allows you to associate an indicator variable, or an array of indicator variables if you are using arrays, with a DML statement, PL/SQL statement, or query.

Because host languages do not have the concept of a null, you associate indicator variables with input variables to specify whether the associated placeholder is a NULL value.

For output variables, indicator variables are used to determine whether the value returned from Oracle is in fact a NULL or a truncated value.

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

-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.

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

-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, which is the maximum value for an unsigned short integer, minus one (usually 2^16 - 1).

-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.

Nulls

You can insert a null into a database column in several ways. One method is to use a literal NULL in the text of an INSERT or UPDATE statement. For example, the SQL statement

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

makes the ENAME column null.

Another method is to use indicator variables in the OCI bind call. See "Indicator Variables" [*] for more information.

To detect when nulls are fetched from the database, you can specify indicator parameters in the bind or define routine and then check the values returned after OEXFET, OFEN, or OFETCH. Nulls can also be detected using the column-level RCODE parameter. See the description of OFEN[*], 5, and 6 for an example of this.

Note: Following SQL92 requirements, Oracle7 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. Use LNGFLG for Version 6 behavior with no error.

Canceling Calls

On most platforms, the user can interactively cancel a long-running or repeated OCI call, such as OEXN, OEXEC, OEXFET, OFETCH, or OFEN. You do this by entering the operating system's interrupt character (usually CTRL-C) from the keyboard. Programs that are linked single-task and two-task support this interrupt capability.

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 in the return code field of the CDA.

The OCI program can use an OCAN call to cancel a query once the desired number of rows have been fetched.

If the OCI program needs to cancel a long-running call with a mechanism such as a timer, you might be able to use the OBREAK routine. See the description of obreak() [*] for an example. Note that you cannot use OBREAK with all operating systems, nor with all supported languages, nor with all transport protocols.

The same effect may be achieved more efficiently through the use of non-blocking calls. See the section "Non-Blocking Mode" [*] for more information.

Maximum Array Size

The maximum size of an array is 32512 items. That is, the ITERS or NROWS parameters of OEXN, OFEN, or OEXFET cannot be set to a value greater than this limit, regardless of the datatypes of these parameters.

Positioned Updates and Deletes

You can use the binary ROWID that is returned in the CDA after a SELECT ... FOR UPDATE OF ... statement in a later UPDATE or DELETE statement. For example, for a SQL statement such as

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

when the FETCH is performed, the ROWID field in the CDA contains the row identifier of the SELECTed row. You can copy this ROWID into a buffer in your program, then use the saved ROWID in a DELETE or UPDATE statement. For example, if MY_ROWID is the buffer in which the row identifier has been saved, you can later process a SQL statement such as

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

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

Optimizing Compilers

Many compilers optimize the generated code so that program variable addresses do not accurately reflect the actual location of a variable in storage at all times. For example, optimizers frequently place commonly used variables in machine registers, and only store them in memory locations when they are referenced in a subroutine call.

When the address of a variable used in a subsequent call is passed to Oracle as a parameter, you must be certain that the addressed variable is actually at the specified location when it is used in the subsequent execute or fetch call. This applies to the ODEFIN, ODEFINPS, OBNDRN, OBNDRV, OBNDRA and OBINDPS calls.

Caution: This rule applies to all local variables whose addresses are passed as parameters to these routines. For example, if the variable value is declared as a local variable and its address is passed to OBNDRV, program errors may occur as a result of the address of value not being in the specified location when it is used in a subsequent call.

The simplest way to ensure currency of variable addresses is to disable the compiler's optimizer. Many compilers provide mechanisms to disable optimizations selectively. For example, there might be options to disable certain optimizations for local sections or routines. For most ANSI C compilers, declaring variables as volatile disables optimization for them. Refer to your compiler's manual for more information.

If you cannot switch your compiler's optimization on and off within a single file, an alternative is to put all OCI code in a separate file that you compile with optimization turned off. Then you can link it in with the rest of your program.


Non-Blocking Mode

Before Oracle7 Server, Release 7.2, connections between Oracle and an OCI program were only in blocking mode. Release 7.2 included a new non-blocking mode.

Note: To use the non-blocking feature with Oracle7 Server release 7.2, you need version 7.2 of the OCI libraries and version 2.2 of SQL*Net. To use the non-blocking feature with Oracle7 Server release 7.3, you need version 7.2 or 7.3 of the OCI libraries and version 2.3 of SQL*Net. Release 7.3 of the OCI libraries is not compatible with release 7.2 of the Server. Non-blocking calls are not supported against release 7.1 or earlier of the Server.

The non-blocking mode returns control to an OCI program so that it may perform other computations while the OCI call is being processed by the server. This mode is particularly useful in Graphical User Interface (GUI) applications, realtime applications, and in distributed environments.

This new 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.

The following three OCI routines are used specifically with non-blocking connections:

These new calls are described for C[*] (on pages 4 - 88, 4 - 89, and 4 - 94), for COBOL[*] (on pages 5 - 81, 5 - 82, and 5 - 83), and for FORTRAN[*] (on pages 6 - 74, 6 - 75, and 6 - 76).

The OLOG logon call allows the programmer to specify whether a database connection is to be made in blocking or non-blocking mode. The mode parameter can take one of two values OCI_LM_DEF (default, for blocking mode) or OCI_LM_NBL (for non-blocking mode). These values are defined in ocidfn.h.

Making a Non-Blocking Connection

You can establish a non-blocking connection between Oracle and your OCI program by using either:

For an example program in C illustrating the use of the non-blocking mode, see page 4 - 89.


Thread Safety

The introduction of thread safety in release 7.3 of the Oracle7 Server and OCI libraries allows developers to use the OCI in a multi-threaded environment. OCI code can now be reentrant, with multiple threads of a user program making OCI calls without side effects from one thread to another. Previous releases had a non-reentrant architecture in which only one thread of execution could make OCI calls.

Note: The availability of thread safety for the OCI is subject to the following limitations:

The following sections describe how you can use the OCI to develop multi-threaded applications.

Advantages of Thread Safety in the OCI

The implementation of thread safety in the Oracle Call Interface provides the following benefits and advantages:

Thread Safety and Three-tier Architectures

In addition to client-server applications, where the client can be a multi-threaded program, a typical use of multi-threaded applications is in three-tier (also called client-agent-server) architectures. In this architecture the client is only concerned with presentation services. The agent (or application server) processes the application logic for the client application. Typically, this relationship is a many-to-one relationship, with multiple clients sharing the same application server.

The server tier in this scenario is an Oracle database. The applications server (agent) is very well suited to being a multi-threaded application server, with each thread serving a client application. In an Oracle environment this application server is an OCI or Precompiler program.

This type of architecture is similar to Oracle's XA interface used in X/Open DTP applications. See the section "Developing X/Open DTP Applications" [*] for more information.

Basic Concepts of Multi-threaded Development

Threads are lightweight processes which exist within a larger process. Threads share the same code and data segments, but have their own program counters, machine registers and stack. Global and static variables are common to all threads, and a mutual exclusivity mechanism may be required to manage access to these variables from multiple threads within an application.

The sharing of resources by program threads is analogous to a shared system resource area of a database accessed by multiple processes. Access to shared resources by different processes must be synchronized using mutual exclusivity locking and latching mechanisms to prevent conflicts. In contrast, if a process owns a private structure in the resource area, it does not need a lock to access that structure safely.

Once spawned, threads run asynchronously to one another. They can access common data elements and make OCI calls in any order. In Oracle Servers through release 7.3, the host can process only one call at a time for a given database connection. Therefore, if multiple threads within an application are sharing the same database connection and can make independent calls, their access to the connection must be serialized. Only one thread at a time may access the connection.

Note: Application developers are responsible for managing access to the database connection by multiple threads. Care must be taken to insure that different threads access the connection serially, rather than concurrently.

Managing Access to the Database Connection

The mechanism to manage access to the connection may take the form of a semaphore which keeps track of in-progress calls to the host on a particular connection. Any thread wishing to make an OCI call must wait to get the semaphore, make the call, and then release the semaphore. Any other thread trying to get the semaphore while a call is in progress will be blocked from execution by the operating system. This semaphore is one way to implement the mutual exclusivity locking necessary to insure that there are no conflicts between multiple threads which are accessing shared resources within an application.

Single vs. Multiple Connections

The situation of multiple threads accessing a single connection from within a program can be contrasted with an application which has multiple threads but also multiple connections. Figure 2 - 6 on the following page shows an application running in a multi-threaded environment through a single connection.

Figure 2 - 6. Connection Sharing Among Threads

In this environment, the various threads of execution must take turns accessing a single database connection to process a SQL statement, and this access is managed by the main program. This figure also demonstrates the use of mutual exclusivity (mutex) locking, as described earlier.

In contrast to Figure 2 - 6, Figure 2 - 7 shows an application running multiple threads of execution across multiple database connections.

Figure 2 - 7. No Connection Sharing Among Threads

In this situation it is not necessary for the application to limit thread access to the connections, since each thread has a dedicated connection.

Although it is not shown in these two figures, it is also possible to develop applications in which a particular thread accesses multiple database connections.

Programming Multi-threaded OCI Applications

Before issuing any other OCI calls in an application, you must tell the OCI layer whether your environment is single-threaded or multi-threaded. This is accomplished with the OCI process initialization call, opinit() which takes one parameter, mode. The mode parameter, which is defined in ocidfn.h, takes one of two values:

OCI_EV_DEF

OCI Environment Default, for single-threaded environments.

OCI_EV_TSF

OCI Environment Thread-Safe, for thread-safe environments.

To maintain backward compatibility, if the opinit() call is skipped a single-threaded environment is assumed.

Even in a single-threaded application it is advisable to make the call to opinit() with mode set to OCI_EV_DEF, rather than skipping it. In addition to setting the proper environment, the call to opinit() also provides explicit documentation that the application is not thread-safe.

Warning: Skipping the call to opinit() in a multi-threaded environment will result in undefined behavior of OCI calls.

To benefit from the thread-safe OCI libraries, OCI programs must connect to an Oracle database using the olog() call, rather than the older olon() or orlon() calls. Use of the older calls implies that the application is running in a single-threaded environment, and subsequent OCI calls will not be thread-safe. Users who make a call to olog() may still run single-threaded programs if they so choose. A single-threaded environment can be specified with the opinit() call, described above.

The olog() function uses local data structures (LDA and HDA) which contain host and connection information. Only one logon can be active at any time on a single connection with a given set of these data structures. Therefore, it is the user's responsibility to make sure that only one logon exists at any time for a given LDA and HDA. Multiple threads should not issue logon calls with the same host and connection data structures. After a logoff, however, the same structures can be reused by another thread for another logon.

For more discussion of HDAs and LDAs, see the sections "Host Data Area" and "Logon Data Area" earlier in this chapter.

Similarly, the ologof() call must be made only once for a connection. Only one thread should issue an ologof() call for a given set of host and connection data structures.

See the description of the opinit() call in Chapter 4 for sample code showing the use of thread-safe SQL statement processing.


Piecewise Insert, Update and Fetch

Prior to Oracle Server release 7.3, OCI applications had to allocate memory for an entire column before it could be inserted or updated. This could cause serious memory problems in the case of LONG columns, which have a maximum size of 2 gigabytes.

Prior to release 7.3, piecewise fetches were possible using OFLNG, which is still available. The OFLNG call may still be useful when it is necessary to perform a piecewise fetch from a certain offset within a column.

With release 7.3, users have the option of using new OCI calls to perform piecewise inserts and updates, and more flexible piecewise fetches. A very large column may now be inserted or retrieved as a series of chunks of smaller size, minimizing client-side memory requirements.

Piecewise fetches are now more efficient. Unlike OFLNG or non-piecewise fetches, the new piecewise fetch operations are buffered locally and individual fetches access the local buffer, rather than accessing the main database across a network. This can improve application performance.

Piecewise operations are now more flexible. The size of individual pieces is determined at runtime by the application. Each piece may be of the same size as other pieces, or it may be of a different size.

This new piecewise functionality may be particularly useful when performing operations on extremely large blocks of string or binary data. An example of this would be operations involving database columns which store LONG or LONG RAW data. See the description of the ftype parameter [*] for information about which datatypes are valid for piecewise operations.

In addition to SQL statements, piecewise operations are also valid for PL/SQL blocks. PL/SQL is subject to the same limitations on datatypes which are mentioned as part of the ftype parameter description [*].

Figure 2 - 8 shows a single long column being inserted piecewise into a database table through a series of insert operations (i1, i2, i3...in). In this example the inserted pieces are of varying sizes.

Figure 2 - 8. Piecewise Insert of a LONG Column

Four new calls have been added to the OCI to handle piecewise operations: OBINDPS (OCI Bind Piecewise), ODEFINPS (OCI Define Piecewise), OGETPI (OCI Get Piece Information) and OSETPI (OCI Set Piece Information). These calls are used in conjunction with new Oracle error codes to coordinate a piecewise operation.

The next two sections explain the steps that are involved in performing a piecewise insert and fetch. These are followed by additional comments about piecewise operations. For information about logging on, opening cursors, parsing statements and logging off, see the section "Developing an OCI Program" [*].

Performing a Piecewise Insert

Once a database connection is established and a cursor is opened, a piecewise insert begins with calls to parse a SQL or PL/SQL statement and to bind input values. The bind call for columns to be inserted piecewise must use the new OBINDPS routine. Bind calls for other placeholders may use any of the supported bind routines (OBNDRV, OBNDRN, OBNDRA or OBINDPS).

Following the parse and bind, the application performs a series of calls to OEXEC, OGETPI and OSETPI. Each time OEXEC is called it returns a value which is used in determining what action should be performed next. In general, the application retrieves a value indicating that the next piece needs to be inserted, populates a buffer with that piece and then executes an insert. When the last piece has been inserted, the operation is complete.

It is important to keep in mind that the insert buffer can be of arbitrary size and is allocated at runtime. In addition, each inserted piece does not need to be of the same size. The size of each piece to be inserted is established by each OSETPI call.

Note that if the same piece size is used for all inserts and the size of the data being inserted is not evenly divisible by the piece size, the final inserted piece will be smaller than the pieces which preceded it. For example, it a data value 18,536 bytes long is inserted in chunks of 50 bytes each, the last remaining piece will be only 36 bytes. The programmer must account for this by indicating the smaller size in the final OSETPI call.

The following steps outline the procedure involved in performing a piecewise insert.

Step 1. Log on to the database (OLOG), open a cursor (OOPEN) and parse a SQL statement (OPARSE).

Step 2. Bind a placeholder using OBINDPS. At this point you specify the maximum column length to be inserted, but you need not specify the actual size of the pieces you will use. There is an optional context pointer parameter which may be used by your application. The pointer is returned to the application in the OGETPI call.

Step 3. Call OEXEC for the first time. At this point no data is actually inserted, and error code ORA-03129 ('the next piece to be inserted is required') is returned to the application. If any other value is returned, it indicates that an error occurred.

Step 4. Call OGETPI to retrieve information about the piece which needs to be inserted. The parameters of OGETPI include a pointer which returns a value indicating whether the required piece is the first piece (OCI_FIRST_PIECE) or a subsequent piece (OCI_NEXT_PIECE). The possible parameter values are defined in ocidfn.h.

Step 5. The application populates a buffer with the piece of data to be inserted and calls OSETPI. The parameters passed to OSETPI include a pointer to the piece, a pointer to the length of the piece and a value indicating whether this is the first piece (OCI_FIRST_PIECE), an intermediate piece (OCI_NEXT_PIECE) or the last piece (OCI_LAST_PIECE).

Step 6. Call OEXEC again. If OCI_LAST_PIECE was indicated in Step 6 and OEXEC returns zero, all pieces were inserted successfully. If OEXEC returns ORA-03129, go back to Step 4 for the next insert. If OEXEC returns any other value, it indicates that an error occurred.

The piecewise operation is complete when the final piece has been successfully inserted. This is indicated by the zero return value from the final OEXEC call.

Piecewise updates are performed in a similar manner. For a piecewise update operation the insert buffer is populated with the data which is being updated and OEXEC is called to execute the update.

Performing a Piecewise Fetch

Once a database connection is established and a cursor is opened, a piecewise fetch begins with calls to parse a SQL or PL/SQL statement and define output variables. The define step must use the new ODEFINPS call for output variables which will be used in piecewise operations.

Following the parse, define and execute, the application performs a series of calls to OFETCH, OGETPI and OSETPI. Each time OFETCH is called it returns a value which is used in determining what action should be performed next. In general, the application retrieves a value indicating that the next piece needs to be fetched and then fetches the piece into a buffer.

It is important to keep in mind that the fetch buffer can be of arbitrary size and is allocated at runtime. In addition, each fetched piece does not need to be of the same size. The only requirement is that size of the final fetch must be exactly the size of the last remaining piece. The size of the piece to be fetched is established by each OSETPI call.

The following steps outline the method for fetching a row piecewise.

Step 1. Log on to the database (OLOG), open a cursor (OOPEN), and parse (OPARSE) and execute (OEXEC) a SQL statement.

Step 2. Call ODEFINPS. The OPCODE parameter for this call specifies that the operation is going to be performed piecewise. There is an optional context pointer parameter which may be used by your application. The pointer is returned to the application in the OGETPI call.

Step 3. Call OFETCH for the first time. At this point no data is actually retrieved, and error code ORA-03130 ('the buffer for the next piece to be fetched is required') is returned to the application. If any other value is returned, it indicates that an error occurred.

Step 4. Call OGETPI to obtain information about the piece to be fetched. The piecep parameter indicates whether it is the first piece (OCI_FIRST_PIECE) or a subsequent piece (OCI_NEXT_PIECE).

Step 5. Call OSETPI to specify the buffer into which you wish to fetch the piece.

Step 6. Call OFETCH again to retrieve the actual piece. If OFETCH returns zero, all the pieces have been fetched successfully. If OFETCH returns ORA-03130 then return to Step 4 to process the next piece. If any other value is returned, it indicates that an error occurred.

The piecewise fetch is complete when the final OFETCH call returns a value of zero.

Using Piecewise Operations in OCI Programs

In both the piecewise fetch and insert, it is important to understand the sequence of calls which are necessary for the operation to complete successfully. In particular, the programmer must keep in mind that for a piecewise insert it is necessary to call OEXEC one time more than the number of pieces to be inserted. This is because the first time OEXEC is called it merely returns a value indicating that the first piece to be inserted is required. As a result, if n pieces are being inserted, OEXEC ends up being called n+1 times.

Similarly, when a piecewise fetch is being performed, OFETCH ends up being called once more than the number of pieces to be fetched.

Users who are working in an NLS (National Language Support) environment which uses multibyte characters must take special care when performing piecewise operations. The new OCI calls assume that multibyte character strings will be provided in pieces by the application such that each piece is a complete multibyte string by itself.

Users who are binding to PL/SQL tables can retrieve a pointer to the current index of the table during the OGETPI calls.

See the descriptions of the osetpi() and ogetpi() calls in Chapter 4 for C language code examples showing how these calls can be used in an OCI application. See the descriptions of the OBINDPS and ODEFINPS calls[*] (for C), Chapter 5 (for COBOL) and Chapter 6 (for FORTRAN) for parameter descriptions and further information about those calls.


Arrays of Structures

Prior to release 7.3 of the Oracle7 Server, applications performing multi-row, multi-column operations were required to allocate a set of parallel arrays for the operation, one for each column being inserted, updated or fetched. For example, when fetching multiple rows of data from three columns, NAME, AGE and SALARY, the data would be fetched into a NAME array, an AGE array and a SALARY array, each of which would contain the data for several rows.

This method complicates the task of the application programmer, because related data which should be part of a single array of structures or records ends up being split across several parallel arrays of scalars.

With Oracle7 Server release 7.3, the OCI application developer can place related scalars in a single structure. Database operations are performed using an array of these structures. This new functionality provides increased flexibility for developers. In the above example, a single structure could contain separate fields to hold the NAME, AGE and SALARY data from one row in the database table. Data would then be fetched into an array of these structures.

In order to perform a multi-row, multi-column operation using an array of structures, the developer associates each column involved in the operation with a field in a structure. This association, which is part of the new OBINDPS and ODEFINPS calls, specifies where fetched data will be stored, or where inserted or updated data will be found.

Figure 2 - 9 is a graphical representation of this process. In the figure, the various fields in a database row are fetched into a single structure in an array of structures. Each column being fetched corresponds to one of the fields in the structure.

Figure 2 - 9. Database Fetch Into an Array of Structures

Skip Parameters

When column data is split across an array of structures it is no longer contiguous. The single array of structures stores data as though it were composed of several interleaved arrays of scalars. Because of this fact, developers must specify a "skip parameter" for each field being bound or defined. This skip parameter specifies the number of bytes that need to be skipped in the array of structures before the same field is encountered again. In general this will be equivalent to the byte size of one structure.

Figure 2 - 10 demonstrates how a skip parameter is determined. In this case the skip parameter is the sum of the sizes of the fields f1, f2 and f3, which is 8 bytes. This equals the size of one structure.

Figure 2 - 10. Determining Skip Parameters

On some systems it may be necessary to set the skip parameter to be sizeof(one array element) rather than sizeof(struct). This is because in some cases some compilers may insert padding into a structure. For example, consider an array of C structures consisting of two fields, a ub4 and a ub1.

struct demo {
    ub4 field1;
    ub1 field2;
};
struct demo demo_array[MAXSIZE];

Some compilers insert three bytes of padding after the ub1 so that the ub4 which begins the next structure in the array is properly aligned. In this case, the following statement may return an incorrect value:

skip_parameter = sizeof(struct demo);

On some systems this will produce a proper skip parameter of eight. On other systems, the skip_parameter will be set to five bytes by this statement. In this case, use the following to get the correct value for the skip parameter:

skip_parameter = sizeof(demo_array[0]);

The ability to work with arrays of structures is an extension of the existing functionality for binding and defining arrays of program variables. It is still possible for programmers to work with standard arrays (as opposed to arrays of structures) in release 7.3 applications. When specifying a standard array operation the related skip will be equal to the size of the datatype of the array under consideration. For example, for an array declared as

text emp_names[4][20]

the skip parameter for the bind or define operation will be 20. Each data element in the array is then recognized as a separate unit, rather than being part of a structure.

OCI Calls Used With Arrays of Structures

Two new OCI calls must be used when performing operations involving arrays of structures: OBINDPS (for binding fields in arrays of structures for input variables) and ODEFINPS (for defining arrays of structures for output variables).

Note: These calls are supported only when deferred mode linking is used. Using OBINDPS or ODEFINPS in non-deferred mode will result in an error being generated. If it is necessary to link in non-deferred mode, other bind and define calls must be used, and operations involving arrays of structures are not supported.

The implementation of arrays of structures also supports the use of indicator variables and return codes. OCI application developers can declare parallel arrays of column-level indicator variables and return codes, corresponding to the arrays of information being fetched, inserted or updated. These arrays can have their own skip parameters, which are specified during a call to OBINDPS or ODEFINPS.

There are many ways in which arrays of structures of program values and indicator variables could be set up. As one possible example, consider an application which fetches data from three database columns into an array of structures containing three fields. There can be a corresponding array of indicator variable structures of three fields, each of which is a column-level indicator variable for one of the columns being fetched from the database.

See the section "Indicator Variables" [*] for more information about indicator variables.

See the description of the obindps() and odefinps() calls[*] for C language code examples showing how to use these calls in an OCI program.


Using PL/SQL in an OCI Program

PL/SQL is Oracle's procedural language extension to the SQL language. PL/SQL processes tasks that are more complicated than simple queries and SQL Data Manipulation Language statements. PL/SQL allows a number of constructs to be grouped into a single block and executed as a unit. Among these constructs are the following:

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

See the PL/SQL User's Guide and Reference for information about coding PL/SQL blocks.

Binding Placeholders in a PL/SQL Block

You process a PL/SQL block by placing the block in a string variable, then parsing the string, binding any variables, and executing the statement containing the block, just as you would with a single SQL statement.

When you bind placeholders in a PL/SQL block to program variables, you must use either OBNDRA, OBINDPS or OBNDRV to perform the binds. OBNDRN cannot be used. You can use OBNDRA and OBINDPS to bind host variables that are either scalars or arrays. You can only bind scalar variables using OBNDRV.

For example, in a PL/SQL block such as

BEGIN
    SELECT ename,sal,comm INTO :emp_name, :salary, :commission
        WHERE ename = :emp_number;
END;

you would use OBNDRV or OBINDPS to bind variables in place of the :EMP_NAME, :SALARY, and :COMMISSION placeholders, and in place of the input placeholder :EMP_NUMBER.

Note: You cannot use ODEFIN or ODEFINPS to bind host variables in a PL/SQL block. You must use OBNDRV, OBINDPS or OBNDRA.

If a PL/SQL block raises an unhandled exception, the values of bind variables are not returned.

A Program Example

Perhaps the most common use for PL/SQL blocks in an OCI program is to call stored procedures or stored functions. For example, assume that there is a procedure called RAISE_SALARY stored in the database, and you want to call this procedure from an OCI program. You do this by embedding a call to that procedure in an anonymous PL/SQL block, then processing the PL/SQL block in the OCI program.

The following program fragment, written in C, shows how to embed a stored procedure call in an OCI application. The program is heavily commented for the benefit of those who are not familiar with the C language. Comments occur between the beginning (/*) and ending (*/) comment delimiters. For brevity, this example does not check for errors.

The program fragment asks the user for an employee ID number and the employee's new salary. Then, by calling the OEXEC routine, the PL/SQL block that calls the stored procedure RAISE_SALARY is performed.

/* Define a string and initialize it with the text of
   the PL/SQL block. The '\' character continues lines
   inside a string literal. */

char plsql_statement[] = "BEGIN\
                           RAISE_SALARY(:EMP_NUMBER, :NEW_SAL);\
                          END;" ;

/* Declare an integer and a real variable. */

int    empnum;
float  salary;
char   empnum_stg[10];
char   salary_stg[10];

/* After connecting to Oracle and opening a cursor,
   parse the statement. Because the text of the block is
   null terminated, -1 is passed for the length parameter. */

    if (oparse(&cda, plsql_statement, -1, 1, 2))
        oci_error(&cda);

/* Bind the host variables. In C, an ampersand (&) before
  a variable means take the address of the variable. This is
  required here because C normally passes scalar parameters by
  value. 3 and 4 are the datatype codes for INTEGER and FLOAT. */

   if (obndrv(&cda, ":EMP_NUMBER", -1, &empnum, sizeof (int), 3,
          -1, 0, 0, -1, -1))
         oci_error (&cda);
   if (obndrv(&cda, ":NEW_SAL", -1, &salary, sizeof (float), 4,
          -1, 0, 0, -1, -1))
         oci_error(&cda);

/*  Query the user for an employee number, */
    printf("Enter the employee number: ");
    gets(empnum_stg);
    empnum = atoi(empnum_stg);

/*  and the new salary. */
    printf("Enter the new salary: ");
    gets(salary_stg);
    salary = atoi(salary_stg);

/*  Execute the PL/SQL block, which executes the
    called stored procedure. */
    if (oexec(&cda))
        oci_error(&cda);

/*  Commit the transaction. */
    if (ocom(&lda))
        oci_error(&cda);

Cursor Variables

Starting with Oracle7, Release 7.2, you can bind PL/SQL cursor variables to cursors (CDAs) in your OCI applications. A cursor variable is a reference to a cursor that is defined and opened on a Oracle 7.2 Server.

Some of the advantages of cursor variables are

See the PL/SQL User's Guide and Reference for complete information about cursor variables.

Using a Cursor Variable

The basic steps to using a cursor variable are:

Step 1. Declare at least two CDAs.

Step 2. Open one of the cursors with OOPEN (cursor in the example below).

Step 3. Using OPARSE, parse a PL/SQL block that contains a cursor variable. (The PL/SQL cursor variable can either be in a PL/SQL anonymous block or in a PL/SQL stored function or procedure.)

Step 4. In general, you must bind variables in a SQL statement or a PL/SQL block to variables in your OCI application. For cursor variables, you must bind (using OBNDRA or OBNDRV) the PL/SQL cursor variable to a second cursor in your application. You must indicate that the cursor's type is SQLT_CUR.

Step 5. Execute (using OEXEC or OEXN) the PL/SQL block. This associates the select statement with the cursor variable. From this point on, you can treat the newly bound cursor (cursor_emp in the example below) just like any other opened OCI cursor.

Step 6. Use ODESCR or ODEFIN to associate the select-list items of the previously bound and executed cursor (cursor_emp) to variables in your OCI program.

Step 7. Now every fetch (OFEN or OFETCH) will store its results in the OCI variables that you defined in the preceding step.

A Program Example

The following code fragment illustrates how to use cursor variables in an OCI application written in C. For the complete program see the sample program cdemo5.c [*].

/* excerpt from cdemo5.c */
/* Define a string and initialize it with the text of
   the PL/SQL block. The '\' character is used to continue lines
   inside a string literal. */
static text plsql_block[] =
   "BEGIN \
      OPEN :cursor1 FOR select empno from emp; \
    END;" ;
static Cda_Def cursor, cursor_emp; /* the two cursors */
static Lda_Def lda;                        /* the LDA */
ub4 empno;
int rv;
...
/* After connecting to Oracle and opening a cursor,
   parse the statement. Since the text of the block is
   null terminated, -1 is passed for the length parameter. */
if (oparse(&cursor, plsql_block, (sb4) -1, (sword) TRUE, (ub4) 2))
        oci_error(&cursor);

/* Bind the host variables. */
if (obndra(&cursor, (text *) ":cursor1", -1, (ub1 *) &cursor_emp,
       -1, SQLT_CUR, -1, (sb2 *) 0, (ub2 *) 0, (ub2 *) 0,
       (ub4) 0, (ub4 *) 0, (text *) 0, 0, 0))
        oci_error(&cursor_emp);

/* Execute the PL/SQL block. */
if (oexec(&cursor))
        oci_error(&cursor);

/* Close the cursor. */
if (oclose(&cursor))
        oci_error(&cursor);
...

/* Define the output variable for empno. */
if (odefin(&cursor_emp, 1, (ub1 *) empno, (sword) sizeof(ub4), 
       SQLT_INT, -1, (sb2 *) -1, (text *) 0, (sword) 0,
       (sword) 0, (ub2 *) 0, (ub2 *) 0))
       oci_error(&cursor_emp);

while (!(ofetch(&cursor)))             /* until an error occurs */
{
      printf("%d\n", empno);
}
if cursor_emp.rc <> 1403   /* ORA-01403 means fetch is complete */
      oci_error(&cursor);

Note: If a cursor variable has OPEN FOR applied to it in the PL/SQL block, then the equivalent OCI calls are OBNDRA (or OBNDRV), OPARSE, and OEXN (or OEXEC). If any of these operations are attempted after PL/SQL returns, an error occurs. You may not rebind or re-execute a cursor variable before it has been reparsed.

Obtaining PL/SQL Error Numbers and Messages

When an error occurs in a PL/SQL block, an Oracle error number in the 6500 PL/SQL errors is returned in the return code field of the CDA. However, if the error was generated by a user exception, the error number is in the -20000 to -20999 range. You obtain the PL/SQL-specific error codes and error messages by calling the OERHMS routine and passing it the error code. More than one PL/SQL error message can be returned on a single call to OERHMS, so you should allocate a large buffer for the message. A buffer size of 2000 bytes is usually sufficient.

For more information about PL/SQL error codes and messages, see the PL/SQL User's Guide and Reference.

Restrictions on Arrays

When you use OBNDRA to bind arrays in your OCI program to PL/SQL tables, there are limitations on the datatypes that can be bound. The full set of conversions that are described in Table 3 - 5[*] do not apply when binding arrays to PL/SQL tables.

Table 2 - 3 shows checkmarks for the conversions which can be performed between PL/SQL tables and host arrays.

PL/SQL Table
Host Array CHAR DATE LONG LONG RAW NUMBER RAW ROWID VARCHAR2
CHARF _/
CHARZ _/
DATE _/
DECIMAL _/
DISPLAY _/
FLOAT _/
INTEGER _/
LONG _/ _/
LONG VARCHAR _/ _/ _/ _/
LONG VARRAW _/ _/
NUMBER _/
RAW _/ _/
ROWID _/
STRING _/ _/ _/ _/
UNSIGNED _/
VARCHAR _/ _/ _/ _/
VARCHAR2 _/ _/ _/ _/
VARNUM _/
VARRAW _/ _/
Table 2 - 3. Supported PL/SQL Array Element Conversions


Developing X/Open DTP Applications

An X/Open application is an application that operates in a distributed transaction processing (DTP) environment. In an abstract model, applications call on resource managers to provide many kinds of services. A database resource manager offers access to data in a database for an application. Transaction processing monitors that use the standard X/Open interface to resource managers incorporate a transaction manager for transaction coordination.

Figure 2 - 11. One Possible DTP Model

Figure 2 - 11 shows one way that the components of the DTP model can interact to provide consistent and efficient access to data in an Oracle database. The DTP model specifies the XA interface. Oracle provides an XA-compliant library to be linked into your applications. The native interface is the OCI API.

The DTP model that specifies how transaction and resource managers interact with application code is described in the X/Open Guide Distributed Transaction Processing Reference Model and related publications. These publications are available from X/Open Company, Ltd. 1010 El Camino Real, Suite 380 Menlo Park CA 94025 USA

For more information on the XA interface, see the documentation provided with your transaction process (TP) monitor.

Oracle-Specific Information

You can use the Oracle Call Interfaces to develop applications that adhere to the X/Open standards. To do this, you must follow certain restrictions, as described in the next sections.

Connections

The application does not create and maintain the connections to a database. The transaction manager and the XA interface handle database connections and disconnections transparently. (The XA interface is supplied by Oracle.) This means that you normally do not use OLOG calls in an X/Open-compliant application, nor do you call OLOGOF to disconnect.

An OCI application requires a valid LDA (for example in the OOPEN call). Use the SQLLD2 routine to obtain a valid LDA for a specified connection, where the connection was established through the XA interface. See pages 4 - 115 (for C), 5 - 93 (for COBOL), or 6 - 86 (for FORTRAN) for a complete description of the SQLLD2 call.

Transaction Control Statements

Application code must not issue SQL statements or make OCI calls that affect the state of global transactions. You cannot issue a COMMIT for a global transaction in the application, because the transaction manager code must handle COMMITs. Also, you cannot issue a SQL DDL command, because DDL commands perform implicit COMMITs. And, of course, you do not use the OCI call OCOM for global transactions. The section "Illegal Operations" [*] lists all of the SQL commands and OCI calls that are not permitted for global transactions in the code you write to implement an application server.

Rollback

Applications can perform an internal ROLLBACK if they detect an error that prevents further SQL operations.

Note: This is subject to change in later versions of the XA interface.

Linking Resource Manager Applications

You must link in the XA library with your application's object modules to obtain the XA interface functionality. Also, SQLLD2 is supplied with the Oracle Precompiler runtime library, SQLLIB. You must link SQLLIB with your application's modules. See your Oracle system-specific documentation for complete instructions on linking XOPEN applications.

Illegal Operations

You cannot use the following OCI calls in an application server:

In addition, you cannot issue SQL DDL commands, because they cause implicit commits. See Chapter 5 of the Oracle7 Server SQL Reference for a complete list of these commands.

You cannot use the following Transaction Control SQL commands:




Go to previous file in sequence Go to next file in sequence
Prev Next
Oracle
Copyright © 1996 Oracle Corporation.
All Rights Reserved.
Go to Product Documentation Library
Library
Go to books for this product
Product
Go to Contents for this book
Contents
Go to Index
Index