![]() |
|
Use the DECLARE statement to associate a cursor with a group of rows.
Use this statement with ESQL/C.
A cursor is an identifier that you associate with a group of rows. The DECLARE statement associates the cursor with one of the following database objects:
The DECLARE statement assigns an identifier to the cursor, specifies its uses, and directs the preprocessor to allocate storage to hold the cursor.
The DECLARE statement must precede any other statement that refers to the cursor during the execution of the program.
The maximum length of a DECLARE statement is 64 kilobytes.
The number of prepared items in a single program is limited by the available memory. These items include both statement identifiers that are named in PREPARE statements (statement_id or statement_id_var) and declared cursors. To avoid exceeding the limit, use a FREE statement to release some statements or cursors.
A program can consist of one or more source-code files. By default, the scope of a cursor is global to a program, so a cursor declared in one file can be referenced from another file. In a multiple-file program, if you want to limit the scope of cursors to the files in which they are declared, you must preprocess all the files with the -local command-line option.
To declare multiple cursors, use a single statement identifier. For instance, the following ESQL/C example does not return an error:
If you include the -ansi compilation flag (or if DBANSIWARN is set), warnings are generated for statements that use dynamic cursor names or dynamic statement identifier names and statements that use derived table names. Some error checking is performed at runtime. The following list indicates the typical checks:
Checks for multiple declarations of a cursor of the same name are performed at compile time only if the cursor or statement is an identifier. The following example uses a host variable to hold the cursor name.
Functionally, you can declare the following types of cursors with the DECLARE statement:
Any of these cursor types can have cursor characteristics: sequential, scroll, and hold. These characteristics determine the structure of the cursor. For more information, see Cursor Characteristics. In addition, a select or function cursor can have a cursor mode: read-only or update. For more information, see Select Cursor or Function Cursor.
The following table summarizes types of cursors that are available.
Cursor Type | Cursor Mode | Cursor Characteristic | ||||
---|---|---|---|---|---|---|
Read-Only | Update | Sequential | Scroll | Hold | ||
Select and Function |
![]() |
![]() | ||||
![]() |
![]() |
![]() | ||||
![]() |
![]() | |||||
![]() |
![]() |
![]() | ||||
![]() |
![]() | |||||
![]() |
![]() |
![]() | ||||
Insert |
![]() | |||||
![]() |
![]() |
A cursor can also be associated with a statement identifier, enabling you to use a cursor with an INSERT, SELECT, EXECUTE FUNCTION (or EXECUTE PROCEDURE) statement that is prepared dynamically and to use different statements with the same cursor at different times. In this case, the type of cursor depends on the statement that is prepared at the time the cursor is opened. For more information, see Associating a Cursor With a Prepared Statement.
The following sections describe each of these cursor types.
Tip: Cursors for functions behave the same as select cursors that are enabled as update cursors.
Select Cursor or Function Cursor
When an SQL statement returns more than one group of values to an ESQL/C program, you must declare a cursor to save the multiple groups, or rows, of data and to access these rows one at a time. You must associate the following SQL statements with cursors:
In Enterprise Decision Server, to create a function cursor, you must use the EXECUTE PROCEDURE statement. Enterprise Decision Server does not support the EXECUTE FUNCTION statement.
In Dynamic Server, for backward compatibility, if an SPL function was created with the CREATE PROCEDURE statement, you can create a function cursor with the EXECUTE PROCEDURE statement. With external functions, you must use the EXECUTE FUNCTION statement.
When you associate a SELECT or EXECUTE FUNCTION (or EXECUTE PROCEDURE) statement with a cursor, the statement can include an INTO clause. However, if you prepare the SELECT or EXECUTE FUNCTION (or EXECUTE PROCEDURE) statement, you must omit the INTO clause in the PREPARE statement and use the INTO clause of the FETCH statement to retrieve the values from the collection cursor.
A select or function cursor enables you to scan returned rows of data and to move data row by row into a set of receiving variables, as the following steps describe:
Use the FOR READ ONLY keywords to define a cursor as a read-only cursor. A cursor declared to be read-only cannot be used to update (or delete) any row that it fetches.
The need for the FOR READ ONLY keywords depends on whether your database is an ANSI-compliant database or a database that is not ANSI compliant.
In a database that is not ANSI compliant, the cursor that the DECLARE statement defines is a read-only cursor by default. So you do not need to specify the FOR READ ONLY keywords if you want the cursor to be a read-only cursor. The only advantage of specifying the FOR READ ONLY keywords explicitly is for better program documentation.
In an ANSI-compliant database, the cursor associated with a SELECT statement through the DECLARE statement is an update cursor by default, provided that the SELECT statement conforms to all of the restrictions for update cursors listed in Subset of SELECT Statement Associated with Cursors. If you want a select cursor to be read only, you must use the FOR READ ONLY keywords when you declare the cursor.
The database server can use less stringent locking for a read-only cursor than for an update cursor.
The following example creates a read-only cursor:
Use the FOR UPDATE option to declare an update cursor. You can use the update cursor to modify (update or delete) the current row.
In an ANSI-compliant database, you can use a select cursor to update or delete data as long as the cursor was not declared with the FOR READ ONLY keywords and it follows the restrictions on update cursors that are described in Subset of SELECT Statement Associated with Cursors. You do not need to use the FOR UPDATE keywords when you declare the cursor.
The following example declares an update cursor:
In an update cursor, you can update or delete rows in the active set. After you create an update cursor, you can update or delete the currently selected row by using an UPDATE or DELETE statement with the WHERE CURRENT OF clause. The words CURRENT OF refer to the row that was most recently fetched; they take the place of the usual test expressions in the WHERE clause.
An update cursor lets you perform updates that are not possible with the UPDATE statement because the decision to update and the values of the new data items can be based on the original contents of the row. Your program can evaluate or manipulate the selected data before it decides whether to update. The UPDATE statement cannot interrogate the table that is being updated.
You can specify particular columns that can be updated.
Using FOR UPDATE with a List of ColumnsWhen you declare an update cursor, you can limit the update to specific columns by including the OF keyword and a list of columns. You can modify only those named columns in subsequent UPDATE statements. The columns need not be in the select list of the SELECT clause.
The following example declares an update cursor and specifies that this cursor can update only the fname and lname columns in the customer_notansi table:
By default, a select cursor in a database that is ANSI compliant is an update cursor. Therefore, the FOR UPDATE keywords are optional. However, if you want an update cursor to be able to modify only some of the columns in a table, you must specify these columns in the FOR UPDATE option.
The principal advantage to specifying columns is documentation and preventing programming errors. (The database server refuses to update any other columns.) An additional advantage is speed, when the SELECT statement meets the following criteria:
If the columns that you intend to update are part of the index that is used to process the SELECT statement, the database server must keep a list of each row that is updated to ensure that no row is updated twice. When you use the OF keyword to specify the columns that can be updated, the database server determines whether to keep the list of updated rows. If the database server determines that the list is unnecessary, then eliminating the work of keeping the list results in a performance benefit. If you do not use the OF keyword, the database server keeps the list of updated rows, although it might be unnecessary.
The following example contains ESQL/C code that uses an update cursor with a DELETE statement to delete the current row. Whenever the row is deleted, the cursor remains between rows. After you delete data, you must use a FETCH statement to advance the cursor to the next row before you can refer to the cursor in a DELETE or UPDATE statement.
When you use the FOR UPDATE keywords you notify the database server that updating is possible and cause it to use more stringent locking than with a select cursor. You declare an update cursor to let the database server know that the program might update (or delete) any row that it fetches as part of the SELECT statement. The update cursor employs promotable locks for rows that the program fetches. Other programs can read the locked row, but no other program can place a promotable or write lock. Before the program modifies the row, the row lock is promoted to an exclusive lock.
Although it is possible to declare an update cursor with the WITH HOLD keywords, the only reason to do so is to break a long series of updates into smaller transactions. You must fetch and update a particular row in the same transaction.
If an operation involves fetching and updating a very large number of rows, the lock table that the database server maintains can overflow. The usual way to prevent this overflow is to lock the entire table that is being updated. If this action is impossible, an alternative is to update through a hold cursor and to execute COMMIT WORK at frequent intervals. However, you must plan such an application very carefully because COMMIT WORK releases all locks, even those that are placed through a hold cursor.
As indicated in the diagram for DECLARE, to create an insert cursor, you associate a sequential cursor with a restricted form of the INSERT statement. The INSERT statement must include a VALUES clause; it cannot contain an embedded SELECT statement.
The following example contains ESQL/C code that declares an insert cursor:
The insert cursor simply inserts rows of data; it cannot be used to fetch data. When an insert cursor is opened, a buffer is created in memory to hold a block of rows. The buffer receives rows of data as the program executes PUT statements. The rows are written to disk only when the buffer is full. You can use the CLOSE, FLUSH, or COMMIT WORK statement to flush the buffer when it is less than full. This topic is discussed further under the PUT and CLOSE statements. You must close an insert cursor to insert any buffered rows into the database before the program ends. You can lose data if you do not close the cursor properly.
For a complete description of INSERT syntax and usage, see INSERT.
When you associate an INSERT statement with a cursor, the cursor is called an insert cursor. An insert cursor is a data structure that represents the rows that the INSERT statement is to add to the database. The insert cursor simply inserts rows of data; it cannot be used to fetch data. To create an insert cursor, you associate a cursor with a restricted form of the INSERT statement. The INSERT statement must include a VALUES clause; it cannot contain an embedded SELECT statement.
Create an insert cursor if you want to add multiple rows to the database in an INSERT operation. An insert cursor allows bulk insert data to be buffered in memory and written to disk when the buffer is full, as the following steps describe:
An insert cursor increases processing efficiency (compared with embedding the INSERT statement directly). This process reduces communication between the program and the database server and also increases the speed of the insertions.
In addition to select and function cursors, insert cursors can also have the sequential cursor characteristic. To create an insert cursor, you associate a sequential cursor with a restricted form of the INSERT statement. (For more information, see Insert Cursor.) The following example contains Informix ESQL/C code that declares a sequential insert cursor:
Structurally, you can declare a cursor as a sequential cursor (the default condition), a scroll cursor (using the SCROLL keyword), or a hold cursor (using the WITH HOLD keywords). The following sections explain these structural characteristics.
A select or function cursor can be either a sequential or a scroll cursor. An insert cursor can only be a sequential cursor. Select, function, and insert cursors can optionally be hold cursors. For a graphical representation of this information, see Overview of Cursor Types.
If you use only the CURSOR keyword, you create a sequential cursor, which can fetch only the next row in sequence from the active set. The sequential cursor can read through the active set only once each time it is opened. If you are using a sequential cursor for a select cursor, on each execution of the FETCH statement, the database server returns the contents of the current row and locates the next row in the active set.
The following example creates a read-only sequential cursor in a database that is not ANSI compliant and an update sequential cursor in an ANSI-compliant database:
In addition to select and function cursors, insert cursors can also have the sequential cursor characteristic. To create an insert cursor, you associate a sequential cursor with a restricted form of the INSERT statement. (For more information, see Insert Cursor.) The following example declares a sequential insert cursor:
Use the SCROLL keyword to create a scroll cursor, which can fetch rows of the active set in any sequence.
The database server retains the active set of the cursor as a temporary table until the cursor is closed. You can fetch the first, last, or any intermediate rows of the active set as well as fetch rows repeatedly without having to close and reopen the cursor. (See FETCH.)
On a multiuser system, the rows in the tables from which the active-set rows were derived might change after the cursor is opened and a copy is made in the temporary table. If you use a scroll cursor within a transaction, you can prevent copied rows from changing either by setting the isolation level to Repeatable Read or by locking the entire table in share mode during the transaction. (See SET ISOLATION and LOCK TABLE.)
The following example creates a scroll cursor for a SELECT:
You can create scroll cursors for select and function cursors but not for insert cursors. Scroll cursors cannot be declared as FOR UPDATE.
Use the WITH HOLD keywords to create a hold cursor. A hold cursor allows uninterrupted access to a set of rows across multiple transactions. Ordinarily, all cursors close at the end of a transaction. A hold cursor does not close; it remains open after a transaction ends.
A hold cursor can be either a sequential cursor or a scroll cursor.
You can use the WITH HOLD keywords to declare select and function cursors (sequential and scroll), and insert cursors. These keywords follow the CURSOR keyword in the DECLARE statement. The following example creates a sequential hold cursor for a SELECT:
You can use a select hold cursor as the following ESQL/C code example shows. This code fragment uses a hold cursor as a master cursor to scan one set of records and a sequential cursor as a detail cursor to point to records that are located in a different table. The records that the master cursor scans are the basis for updating the records to which the detail cursor points. The COMMIT WORK statement at the end of each iteration of the first WHILE loop leaves the hold cursor c_master open but closes the sequential cursor c_detail and releases all locks. This technique minimizes the resources that the database server must devote to locks and unfinished transactions, and it gives other users immediate access to updated rows.
Use either the CLOSE statement to close the hold cursor explicitly or the CLOSE DATABASE or DISCONNECT statements to close it implicitly. The CLOSE DATABASE statement closes all cursors.
Using an Insert Cursor with HoldIf you associate a hold cursor with an INSERT statement, you can use transactions to break a long series of PUT statements into smaller sets of PUT statements. Instead of waiting for the PUT statements to fill the buffer and trigger an automatic write to the database, you can execute a COMMIT WORK statement to flush the row buffer. If you use a hold cursor, the COMMIT WORK statement commits the inserted rows but leaves the cursor open for further inserts. This method can be desirable when you are inserting a large number of rows, because pending uncommitted work consumes database server resources.
As indicated in the diagram for DECLARE, not all SELECT statements can be associated with a read-only or update cursor. If the DECLARE statement includes one of these options, you must observe certain restrictions on the SELECT statement that is included in the DECLARE statement (either directly or as a prepared statement).
If the DECLARE statement includes the FOR READ ONLY option, the SELECT statement must conform to the following restrictions:
For a complete description of SELECT syntax and usage, see SELECT.
If the DECLARE statement includes the FOR UPDATE option, the SELECT statement must conform to the following restrictions:
In a database that is not ANSI compliant, a cursor associated with a SELECT statement is a read-only cursor by default. The following example declares a read-only cursor in a non-ANSI database:
If you want to make it clear in the program code that this cursor is a read-only cursor, you can specify the FOR READ ONLY option as shown in the following example:
If you want this cursor to be an update cursor, you need to specify the FOR UPDATE option in your DECLARE statement. The following example declares an update cursor:
If you want an update cursor to be able to modify only some of the columns in a table, you need to specify these columns in the FOR UPDATE option. The following example declares an update cursor and specifies that this cursor can update only the fname and lname columns in the customer_notansi table:
In an ANSI-compliant database, a cursor associated with a SELECT statement is an update cursor by default. The following example declares an update cursor in an ANSI-compliant database:
If you want to make it clear in the program documentation that this cursor is an update cursor, you can specify the FOR UPDATE option as shown in the following example:
If you want an update cursor to be able to modify only some of the columns in a table, you must specify these columns in the FOR UPDATE option. The following example declares an update cursor and specifies that this cursor can update only the fname and lname columns in the customer_ansi table:
If you want a cursor to be a read-only cursor, you must override the default behavior of the DECLARE statement by specifying the FOR READ ONLY option in your DECLARE statement. The following example declares a read-only cursor:
The PREPARE statement lets you assemble the text of an SQL statement at runtime and pass the statement text to the database server for execution. If you anticipate that a dynamically prepared SELECT, EXECUTE FUNCTION (or EXECUTE PROCEDURE) statement that returns values could produce more than one row of data, the prepared statement must be associated with a cursor. (See PREPARE.)
The result of a PREPARE statement is a statement identifier (statement id or id variable), which is a data structure that represents the prepared statement text. To declare a cursor for the statement text, associate a cursor with the statement identifier.
You can associate a sequential cursor with any prepared SELECT or EXECUTE FUNCTION (or EXECUTE PROCEDURE) statement. You cannot associate a scroll cursor with a prepared INSERT statement or with a SELECT statement that was prepared to include a FOR UPDATE clause.
After a cursor is opened, used, and closed, a different statement can be prepared under the same statement identifier. In this way, it is possible to use a single cursor with different statements at different times. The cursor must be redeclared before you use it again.
The following example contains ESQL/C code that prepares a SELECT statement and declares a sequential cursor for the prepared statement text. The statement identifier st_1 is first prepared from a SELECT statement that returns values; then the cursor c_detail is declared for st_1.
If you want to use a prepared SELECT statement to modify data, add a FOR UPDATE clause to the statement text that you wish to prepare, as the following ESQL/C example shows:
The DECLARE statement allows you to declare a cursor for an ESQL/C collection variable. Such a cursor is called a collection cursor. You use a collection variable to access the elements of a collection (SET, MULTISET, LIST) column. Use a cursor when you want to access one or more elements in a collection variable.
The Collection Derived Table segment identifies the collection variable for which to declare the cursor. For more information, see Collection Derived Table.
The diagram for DECLARE refers to this section.
To declare a select cursor for a collection variable, include the Collection Derived Table segment with the SELECT statement that you associate with the collection cursor. A select cursor allows you to select one or more elements from the collection variable.
For a complete description of SELECT syntax and usage, see SELECT.
RestrictionsWhen you declare a select cursor for a collection variable, the DECLARE statement has the following restrictions:
In addition, the SELECT statement that you associate with the collection cursor has the following restrictions:
A collection cursor that includes a SELECT statement with the Collection Derived Table clause allows you to access the elements in a collection variable.
To select more than one element, follow these general steps:
The following DECLARE statement declares a select cursor for a collection variable:
For an extended code example that uses a collection cursor for a SELECT statement, see Fetching From a Collection Cursor.
The diagram for DECLARE refers to this section.
To declare an insert cursor for a collection variable, include the Collection Derived Table segment with the INSERT statement that you associate with the collection cursor. An insert cursor allows you to insert one or more elements in the collection.
For a complete description of INSERT syntax and usage, see INSERT.
RestrictionsThe insert cursor must be a sequential cursor, that is the DECLARE statement cannot contain the WITH HOLD keywords.
When you declare an insert cursor for a collection variable, the Collection- Derived Table clause of the INSERT statement must contain the name of the collection variable. You cannot specify an input parameter (the question-mark (?) symbol) for the collection variable. However, you can use an input parameter in the VALUES clause of the INSERT statement. This parameter indicates that the collection element is to be provided later by the FROM clause of the PUT statement.
Using an INSERT Cursor with a Collection VariableA collection cursor that includes an INSERT statement with the Collection- Derived Table clause allows you to insert more than one element into a collection variable.
To insert more than one element, follow these general steps:
For example, the following DECLARE statement declares an insert cursor for the a_set collection variable:
To insert the elements into the collection variable, use the PUT statement with the FROM clause. For a code example that uses a collection cursor for an INSERT statement, see Inserting into a Collection Cursor.
To roll back a modification, you must perform the modification within a transaction. A transaction in a database that is not ANSI compliant begins only when the BEGIN WORK statement is executed.
In an ANSI-compliant database, transactions are always in effect.
The database server enforces the following guidelines for select and update cursors. These guidelines ensure that modifications can be committed or rolled back properly:
The database server lets you open and close a hold cursor for an update outside a transaction; however, you should fetch all the rows that pertain to a given modification and then perform the modification all within a single transaction. You cannot open and close hold or update cursors outside a transaction.
The following example uses an update cursor within a transaction:
When you update a row within a transaction, the row remains locked until the cursor is closed or the transaction is committed or rolled back. If you update a row when no transaction is in effect, the row lock is released when the modified row is written to disk.
If you update or delete a row outside a transaction, you cannot roll back the operation.
In a database that uses transactions, you cannot open an insert cursor outside a transaction unless it was also declared with the with hold keywords.
Related statements: CLOSE, DELETE, EXECUTE PROCEDURE, FETCH, FREE, INSERT, OPEN, PREPARE, PUT, SELECT, and UPDATE
For discussions of cursors and data modification, see the Informix Guide to SQL: Tutorial.
For more advanced issues related to cursors or information about using cursors with collection variables, see the Informix ESQL/C Programmer's Manual.