Programmer's Guide to the Oracle7 Server Call Interface | ![]() Library |
![]() Product |
![]() Contents |
![]() Index |
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.
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.
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.
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).
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.
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.
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.
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.
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.
Table 2 - 2 lists the OCI function codes for routines that use the CDA. Codes for which no OCI routine is listed are unused.
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. |
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:
There are eight kinds of SQL statements in Oracle7:
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
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" .
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.
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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
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.
Note: The availability of thread safety for the OCI is subject to the following limitations:
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.
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.
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.
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.
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" .
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.
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.
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.
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.
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
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.
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.
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.
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);
Some of the advantages of cursor variables 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.
/* 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.
For more information about PL/SQL error codes and messages, see the PL/SQL User's Guide and Reference.
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 | _/ | _/ | ||||||
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.
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.
Note: This is subject to change in later versions of the XA interface.
You cannot use the following Transaction Control SQL commands:
![]() ![]() Prev Next |
![]() Copyright © 1996 Oracle Corporation. All Rights Reserved. |
![]() Library |
![]() Product |
![]() Contents |
![]() Index |