INFORMIX
Informix-ESQL/C Programmer's Manual
Chapter 14: Using Dynamic SQL
Home Contents Index Master Index New Book

Using a Database Cursor

A database cursor is an identifier associated with a group of rows. It is, in a sense, a pointer to the current row in a buffer. You must use a cursor in the following cases:

The following sections summarize how to use cursors in an ESQL/C application. For information about how to use cursors, see the Informix Guide to SQL: Tutorial.

Receiving More Than One Row

Statements that return one row of data include a singleton SELECT and an EXECUTE FUNCTION statement whose user-defined function returns only one row of data. Statements that can return more than one row of data include:

    When a SELECT statement returns more than one row, define a select cursor with the DECLARE statement.

    When an EXECUTE FUNCTION statement executes a user-defined function that returns more than one row, define a function cursor with the DECLARE statement.

For the select or function cursor, you can use a sequential, scroll, hold, or update cursor. Figure 14-5 summarizes the SQL statements that manage a select or function cursor.

Figure 14-5
SQL Statements That Manage a Select or Function Cursor

Task Select Cursor Function Cursor

Declare the cursor identifier

DECLARE associated with a SELECT statement

DECLARE associated with an EXECUTE FUNCTION statement

Execute the statement

OPEN

OPEN

Access a single row from the fetch buffer into the program

FETCH

FETCH

Close the cursor

CLOSE

CLOSE

Free cursor resources

FREE

FREE

For more information on any of these statements, see their entries in the Informix Guide to SQL: Syntax. You can change the size of the select or fetch buffer with the Fetch-Buffer-Size feature. For more information, see "Sizing the Cursor Buffer".

A Select Cursor

A select cursor enables you to scan multiple rows of data that a SELECT statement returns. The DECLARE statement associates the SELECT statement with the select cursor. In the DECLARE statement, the SELECT statement can be in either of the following formats:

    The following DECLARE statement associates a literal SELECT statement with the slct1_curs cursor:

EXEC SQL declare slct1_curs for select * from customer;

    The following DECLARE statement associates a prepared SELECT statement with the slct2_curs cursor:

EXEC SQL prepare slct_stmt from
'select * from customer';
EXEC SQL declare slct2_curs for slct_stmt;

If the SELECT returns only one row, it is called a singleton SELECT and it does not require a select cursor to execute.

A Function Cursor

A function cursor enables you to scan multiple rows of data that the user-defined function returns. The following user-defined functions can return more than one row:

You execute a user-defined function with the EXECUTE FUNCTION statement. The DECLARE statement associates the EXECUTE FUNCTION with the function cursor. In the DECLARE statement, the EXECUTE FUNCTION statement can be in either of the following formats:

    The following DECLARE statement associates a literal EXECUTE FUNCTION statement with the func1_curs cursor:

EXEC SQL declare func1_curs for execute function func1();

    The following DECLARE statement associates a prepared EXECUTE FUNCTION statement with the func2_curs cursor:

EXEC SQL prepare func_stmt from
'execute function func1()';
EXEC SQL declare func2_curs for func_stmt;

If the external or SPL function returns only one row, it does not require a function cursor to execute.

Sending More Than One Row

When you execute the INSERT statement, the statement sends one row of data to the database server. When an INSERT statement sends more than one row, define an insert cursor with the DECLARE statement. An insert cursor enables you to buffer multiple rows of data for insertion at one time. The DECLARE statement associates the INSERT statement with the insert cursor. In the DECLARE statement, the INSERT statement can be in either of the following formats:

    The following DECLARE statement associates a literal INSERT statement with the ins1_curs cursor:

EXEC SQL declare ins1_curs for
insert into customer values (?);

    The following DECLARE statement associates a prepared INSERT statement with the ins2_curs cursor:

EXEC SQL prepare ins_stmt from
'insert into customer values (?)';
EXEC SQL declare ins2_curs for ins_stmt;

If you use an insert cursor it can be much more efficient than if you insert rows one at a time, because the application process does not need to send new rows to the database as often. You can use a sequential or hold cursor for the insert cursor. Figure 14-6 summarizes the SQL statements that manage an insert cursor.

Figure 14-6
SQL Statements That Manage an Insert Cursor
(1 of 2)

Task Insert Cursor

Declare the cursor ID

DECLARE associated with an INSERT statement

Execute the statement

OPEN

Send a single row from the program into the insert buffer

PUT

Clear the insert buffer and send the contents to the database server

FLUSH

Close the cursor

CLOSE

Free cursor resources

FREE

For more information on any of these statements, see their entries in the Informix Guide to SQL: Syntax. You can change the size of the insert buffer with the Fetch-Buffer-Size feature. For more information, see "Sizing the Cursor Buffer".

Naming the Cursor

In an ESQL/C program, you can specify a cursor name with any of the following items:

Figure 14-7
A Sample ESQL/C Function That Uses a Dynamic Cursor

Optimizing Cursor Execution

INFORMIX-ESQL/C supports the following features that allow you to minimize network traffic when an ESQL/C application fetches rows from a database server:

Sizing the Cursor Buffer

The cursor buffer is the buffer that an ESQL/C application uses to hold the data (except simple large-object data) in a cursor. ESQL/C has the following uses for the cursor buffer:

    When the database server returns rows from the active set of a query, ESQL/C stores these rows in the fetch buffer.

    ESQL/C stores the rows to be inserted in the insert buffer then sends this buffer as a whole to the database server for insertion.

With a fetch buffer, the client application performs the following tasks:

1. Sends the size of the buffer to the database server and requests rows when it executes the first FETCH statement.

    2. Retrieves the rows from the database server and puts them in the fetch buffer.

    3. Takes the first row out of the fetch buffer and puts the data in the host variables that the user has provided.

For subsequent FETCH statements, the application checks whether more rows exist in the fetch buffer. If they do, it takes the next row out of the fetch buffer. If no more rows are in the fetch buffer, the application requests more rows from the database server, sending the fetch-buffer size.

The client application uses an insert buffer to perform the following tasks:

1. Put the data from the first PUT statement into the insert buffer.

    2. Check whether more room exists in the insert buffer for subsequent PUT statements.

    If more rows can fit, the application puts the next row into the insert buffer. If no more rows can fit into the insert buffer, the application sends the contents of the insert buffer to the database server.

The application continues this procedure until no more rows are put into the insert buffer. It sends the contents of the insert buffer to the database server when:

Default Buffer Size
The client application sends the prepared statement that is associated with the cursor to the database server and requests DESCRIBE information about the statement. If the cursor has an associated prepared statement, ESQL/C makes this request when the PREPARE statement executes. If the cursor does not have an associated statement, ESQL/C makes the request when the DECLARE statement executes.

When it receives this request, the database server sends the DESCRIBE information about each column in the projection list to the application. With this information, ESQL/C can determine the size of a row of data. By default, ESQL/C sizes this cursor buffer to hold one row of data. It uses the following algorithm to determine the default size of the cursor buffer:

1. If one row fits in a 4096-byte buffer, the default buffer size is 4096 bytes (4 kilobytes).

    2. If the size of one row exceeds 4096 bytes, the default buffer size is the size of that row.

Once it has the buffer size, ESQL/C allocates the cursor buffer.

Changing Size of Cursor Buffer
An ESQL/C application might want to increase the size of the cursor buffer to increase the number of rows that can be passed at one time between the client application and the database server. When you increase the number of rows that can be passed, you reduce the number of round-trip message requests that need to be sent between the client application and the database server. The bigger the cursor buffer, the more data that can be sent in one round trip.

To increase the size of the cursor buffer, you can set either of the following variables in the client environment:

    For example, the following command sets the FET_BUF_SIZE environment variable in the C-shell environment to 20,000 bytes (20 kilobytes):

setenv FET_BUF_SIZE 20000

    The FetBufSize global variable is defined in the ESQL/C sqlhdr.h header file. (The ESQL/C processor automatically includes the sqlhdr.h header file in all ESQL/C programs.) You set the size of the cursor buffer at the point that you make the assignment to the FetBufSize variable. This new size takes effect the next time ESQL/C checks the buffer size. ESQL/C checks the size of the cursor buffer when it allocates the cursor buffer. ESQL/C also checks the size of a fetch buffer when it tells the database server how many rows to send at one time.

FetBufSize = 30000;

Tip: Contrary to what the names might imply, the FET_BUF_SIZE environment variable and the FetBufSize global ESQL/C variable do not change the size of only the fetch buffer. They change the size of the cursor buffer, which is used for both the fetch buffer and the insert buffer.
In a client-server environment, you must set the cursor buffer size on the client side of the application because this buffer resides in the application process. Specify the size of the cursor buffer in bytes, up to the maximum size of a small integer (short data type) on your system. For most 32-bit platforms, this maximum is 32,767 bytes. If you specify a buffer size that is less than the default size or greater than the system maximum, the new size is ignored. If you do not specify a buffer size, the database server uses the default size.

Important: Informix extends ANSI-standard syntax to set the size of the cursor buffer.
If you increase the size of the cursor buffer, you reduce the overhead of refilling the buffer. The database server can buffer more data before it sends it to the application. A larger fetch buffer can enhance performance when you fetch a large number of rows or when a single row is large. The greater the size of the fetch buffer, the fewer number of times the application needs to wait while the database server retrieves a large number of rows or a few large rows. However, when you fetch only a few rows (unless the row is very large), the performance gain is not as apparent.

ODS

Automatically Freeing a Cursor

When an ESQL/C application uses a cursor, it usually sends a FREE statement to the database server to deallocate memory assigned to a select cursor once it no longer needs that cursor. Execution of this statement involves a round trip of message requests between the application and the database server. The Automatic-FREE feature (AUTOFREE) reduces the number of round trips by one.

When the AUTOFREE feature is enabled, ESQL/C saves a round trip of message requests because it does not need to execute the FREE statement. When the database server closes a select cursor, it automatically frees the memory that it has allocated for it. Suppose you enable the AUTOFREE feature for the following select cursor:

When the database server closes the sel_curs cursor, it automatically performs the equivalent of the following FREE statement:

If the cursor had an associated prepared statement, the database server also frees memory allocated to the prepared statement. Suppose you enable the AUTOFREE feature for the following select cursor:

When the database server closes the sel_curs2 cursor, it automatically performs the equivalent of the following FREE statements:

You must enable the AUTOFREE feature before you open or reopen the cursor.

Enabling the AUTOFREE Feature
You can enable the AUTOFREE feature for an ESQL/C application in either of the following ways:

    When you use the IFX_AUTOFREE environment variable to enable the AUTOFREE feature, you automatically free cursor memory when cursors in any thread of the program are closed.

    With the SET AUTOFREE statement, you can enable the AUTOFREE feature for a particular cursor. You can also enable or disable the feature in a particular connection or thread.

Warning: Be careful when you enable the AUTOFREE feature in legacy ESQL/C applications. If a legacy application uses the same cursor twice, it generates an error when it tries to open the cursor for the second time. When the AUTOFREE feature is enabled, the database server automatically frees the cursor when it closes it. Therefore, the cursor does not exist when the legacy application attempts to open it a second time, even though the application does not explicitly execute the FREE statement.
For more information on the syntax and use of the SET AUTOFREE statement, see "Using the SET AUTOFREE Statement". For more information on the IFX_AUTOFREE environment variable, see the Informix Guide to SQL: Reference.

Using the SET AUTOFREE Statement
You can use the SQL statement, SET AUTOFREE, to enable and disable the AUTOFREE feature. The SET AUTOFREE statement allows you to take the following actions in an ESQL/C program:

    These statements are equivalent because the default action of the SET AUTOFREE statement is to enable all cursors.

The SET AUTOFREE statement overrides any value of the IFX_AUTOFREE environment variable.

The following code fragment uses the FOR clause of the SET AUTOFREE statement to enable the AUTOFREE feature for the curs1 cursor only. After the database server executes the CLOSE statement for curs1, it automatically frees the cursor and the prepared statement. The curs2 cursor and its prepared statement are not automatically freed.

When you use the AUTOFREE feature, make sure you do not cause a prepared statement to become detached. This situation can occur if you declare more than one cursor on the same prepared statement. A prepared statement is associated or attached to the first cursor that specifies it in a DECLARE statement. If the AUTOFREE feature is enabled for this cursor, then the database server frees the cursor and its associated prepared statement when it executes the CLOSE statement on the cursor.

A prepared statement becomes detached when either of the following events occur:

This second condition can occur if the AUTOFREE feature is not enabled for a cursor and you free only the cursor, not the prepared statement. The prepared statement becomes detached. To reattach the prepared statement, declare a new cursor for the prepared statement. Once a prepared statement has been freed, it cannot be used to declare any new cursor.

The following code fragment declares the following cursors on the slct1 prepared statement:

The following code fragment shows how a detached prepared statement can occur:

For more information on the syntax and use of the SET AUTOFREE statement, see the Informix Guide to SQL: Syntax.

ODS

Deferring Execution of the PREPARE Statement

When an ESQL/C application uses a PREPARE/DECLARE/OPEN statement block to execute a cursor, each statement involves a round trip of message requests between the application and the database server. The Deferred-PREPARE feature reduces the number of round trips by one. When the Deferred-PREPARE feature is enabled, ESQL/C saves a round trip of message requests because it does not need to send a separate command to execute the PREPARE statement. Instead, the database server automatically executes the PREPARE statement when it receives the OPEN statement.

Suppose you enable the Deferred-PREPARE feature for the following select cursor:

The ESQL/C application does not send the PREPARE statement to the database server when it encounters the PREPARE before the DECLARE statement. Instead, it sends the PREPARE and the OPEN to the database server together when it executes the OPEN statement.

You can use the Deferred-PREPARE feature in ESQL/C applications that contain dynamic SQL statements that use statement blocks of PREPARE, DECLARE, and OPEN to execute the following statements:

For example, the Deferred-PREPARE feature reduces network round trips for the following select cursor:

Restrictions on Deferred-PREPARE
When you enable the deferred-PREPARE feature, the client application does not send PREPARE statements to the database server when it encounters them. The database server receives a description of the prepared statement when it executes the OPEN statement.

The database server generates an error if you execute a DESCRIBE statement on a prepared statement before the first OPEN of the cursor. The error occurs because the database server has not executed the PREPARE statement that the DESCRIBE statement specifies. When the deferred-PREPARE features is enabled, you must execute the DESCRIBE statement after the first OPEN of a cursor.

Important: The deferred-PREPARE feature eliminates execution of the PREPARE statement as a separate step. Therefore, the application does not receive any error conditions that might exist in the prepared statement until after the initial OPEN.
For more information, see "Using the SETDEFERRED_PREPARE Statement".

Enabling the Deferred-PREPARE Feature
You can enable the Deferred-PREPARE feature for an ESQL/C application in either of the following ways:

    When you use the IFX_DEFERRED_PREPARE environment variable to enable the Deferred-PREPARE feature, you automatically defer execution of the PREPARE statement until just before the OPEN statement executes for every PREPARE statement in any thread of the application.

    With the SET DEFERRED_PREPARE statement, you can enable the Deferred-PREPARE feature for a particular PREPARE statement. You can also enable or disable the feature in a particular connection or thread.

For more information on the syntax and use of the SET DEFERRED PREPARE statement, see "Using the SETDEFERRED_PREPARE Statement." For more information on the IFX_DEFERRED_PREPARE environment variable, see the Informix Guide to SQL: Reference.

Using the SETDEFERRED_PREPARE Statement
From within an ESQL/C application you can use the SQL statement, SET DEFERRED_PREPARE, to enable and disable the Deferred-PREPARE feature. The SET DEFERRED_PREPARE statement allows you to take the following actions in an ESQL/C program:

The SET DEFERRED_PREPARE statement overrides any value of the IFX_DEFERRED_PREPARE environment variable.

The following code fragment shows how to enable the Deferred-PREPARE feature for the ins_curs insert cursor:

To execute a DESCRIBE statement on a prepared statement, you must execute the DESCRIBE after the initial OPEN statement for the cursor. In the following code fragment the first DESCRIBE statement fails because it executes before the first OPEN statement on the cursor. The second DESCRIBE statement succeeds because it follows an OPEN statement.




Informix-ESQL/C Programmer's Manual, version 9.1
Copyright © 1998, Informix Software, Inc. All rights reserved.