DECLARE CURSOR
The DECLARE CURSOR statement defines a cursor.
Invocation
This statement can only be embedded in an application program. It is not an executable statement. It must not be specified in Java.
Authorization
For each table or view identified in the SELECT statement of the cursor, the privilege set must include at least one of the following:
- The SELECT privilege
- Ownership of the object
- DBADM authority for the corresponding database (tables only)
- SYSADM authority
- SYSCTRL authority (catalog tables only)
- DATAACCESS authority
If the select-statement contains an SQL data change statement, the authorization requirements of that statement also apply to the DECLARE CURSOR statement.
The SELECT statement of the cursor is one of the following:
- The prepared select statement identified by statement-name
- The specified select-statement
If statement-name is specified:
- The privilege set is determined by the DYNAMICRULES behavior in effect (run, bind, define, or invoke) and is summarized in Table 1. (For more information on these behaviors, including a list of the DYNAMICRULES bind option values that determine them, see Authorization IDs and dynamic SQL.)
- The authorization check is performed when the SELECT statement is prepared.
- The cursor cannot be opened unless the SELECT statement is successfully prepared.
If select-statement is specified:
- The privilege set consists of the privileges that are held by the authorization ID of the owner of the plan or package.
- If the plan or package is bound with VALIDATE(BIND), the authorization check is performed at bind time, and the bind is unsuccessful if any required privilege does not exist.
- If the plan or package is bound with VALIDATE(RUN), an authorization check is performed at bind time, but all required privileges need not exist at that time. If all privileges exist at bind time, no authorization checking is performed when the cursor is opened. If any privilege does not exist at bind time, an authorization check is performed the first time the cursor is opened within a unit of work. The OPEN is unsuccessful if any required privilege does not exist.
Syntax
.-NO SCROLL------------------------. >>-DECLARE--cursor-name--+----------------------------------+---> | .-ASENSITIVE------------. | '-+-----------------------+-SCROLL-' +-INSENSITIVE-----------+ | .-DYNAMIC-. | '-SENSITIVE-+---------+-' '-STATIC--' .-----------------------------. V (1) | >--CURSOR---------+--------------------+-+----------------------> +-holdability--------+ +-returnability------+ '-rowset-positioning-' >--FOR--+-select-statement-+----------------------------------->< '-statement-name---'
- The same clause must not be specified more than once.
holdability:
.-WITHOUT HOLD-. >>-+--------------+-------------------------------------------->< '-WITH HOLD----'
returnability:
.-WITHOUT RETURN-------------. >>-+----------------------------+------------------------------>< | .-TO CALLER-. | '-WITH RETURN--+-----------+-' '-TO CLIENT-'
rowset-positioning:
.-WITHOUT ROWSET POSITIONING-. >>-+----------------------------+------------------------------>< '-WITH ROWSET POSITIONING----'
Description
- cursor-name
- Names the cursor. The name must not identify a cursor that has already been declared in the source program. The name is usually VARCHAR(128); however, if the cursor is defined WITH RETURN, the name is limited to VARCHAR(30).
- NO SCROLL or SCROLL
- Specifies whether the cursor is scrollable or not scrollable.
- NO SCROLL
- Specifies that the cursor is not scrollable. This is the default.
- SCROLL
- Specifies
that the cursor is scrollable. For a scrollable cursor, whether the
cursor has sensitivity to inserts, updates, or deletes depends on
the cursor sensitivity option in effect for the cursor. If a sensitivity
option is not specified, ASENSITIVE is the default.
- ASENSITIVE
- Specifies
that the cursor should be as sensitive as possible. This is the default.
A cursor that defined as ASENSITIVE will be either insensitive or sensitive dynamic; it will not be sensitive static. For information about how the effective sensitivity of the cursor is returned to the application with the GET DIAGNOSTICS statement or in the SQLCA, see OPEN.
The sensitivity of a cursor is a factor in the choice of access path. Explicitly specify the sensitivity level that you need, instead of specifying ASENSITIVE.
- INSENSITIVE
- Specifies that the cursor does not have sensitivity to inserts, updates, or deletes that are made to the rows underlying the result table. As a result, the size of the result table, the order of the rows, and the values for each row do not change after the cursor is opened. In addition, the cursor is read-only. The SELECT statement or attribute-string of the PREPARE statement cannot contain a FOR UPDATE clause, and the cursor cannot be used for positioned updates or deletes.
- SENSITIVE
- Specifies
that the cursor has sensitivity to changes that are made to the database
after the result table is materialized. The cursor is always sensitive
to updates and deletes that are made using the cursor (that is, positioned
updates and deletes using the same cursor). When the current value
of a row no longer satisfies the select-statement or statement-name,
that row is no longer visible through the cursor. When a row of the
result table is deleted from the underlying base table, the row is
no longer visible through the cursor.
If DB2® cannot make changes visible to the cursor, then an error is issued at bind time for OPEN CURSOR. DB2 cannot make changes visible to the cursor when the cursor implicitly becomes read-only. For example, when the result table must be materialized, as when the FROM clause of the SELECT statement contains more than one table or view. The current list of conditions that result in an implicit read-only cursor can be found in Read-only cursors.
The default is DYNAMIC.
- DYNAMIC
- Specifies that the result table of
the cursor is dynamic, meaning that the size of the result table might change after the cursor is
opened as rows are inserted into or deleted from the underlying table, and the order of the rows
might change. Rows that are inserted, deleted, or updated by statements that are executed by the
same application process as the cursor are visible to the cursor immediately. Rows that are
inserted, deleted, or updated by statements that are executed by other application processes are
visible only after the statements are committed. If a column for an ORDER BY clause is updated via a
cursor or any means outside the process, the next FETCH statement behaves as if the updated row was
deleted and re-inserted into the result table at its correct location. At the time of a positioned
update, the cursor is positioned before the next row of the original location and there is no
current row, making the row appear to have moved.
If a SENSITIVE DYNAMIC cursor is not possible, an error is returned. For example, if a temporary table is needed an error is returned. The SELECT statement of a cursor that is defined as SENSITIVE DYNAMIC cannot contain an SQL data change statement.
The FETCH FIRST n ROWS ONLY clause must not be specified for the outermost fullselect for a sensitive dynamic cursor.
- STATIC
- Specifies
that the size of the result table and the order of the rows do not
change after the cursor is opened. Rows inserted into the underlying
table are not added to the result table regardless of how the rows
are inserted. Rows in the result table do not move if columns in the
ORDER BY clause are updated in rows that have already been materialized.
Positioned updates and deletes are allowed if the result table is
updatable. The SELECT statement of a cursor that is defined as SENSITIVE
STATIC cannot contain an SQL data change statement.
A STATIC cursor has visibility to changes made by this cursor using positioned updates or deletes. Committed changes made outside this cursor are visible with the SENSITIVE option of the FETCH statement. A FETCH SENSITIVE can result in a hole in the result table (that is, a difference between the result table and its underlying base table). If an updated row in the base table of a cursor no longer satisfies the predicate of its SELECT statement, an update hole occurs in the result table. If a row of a cursor was deleted in the base table, a delete hole occurs in the result table. When a FETCH SENSITIVE detects an update hole, no data is returned (a warning is issued), and the cursor is left positioned on the update hole. When a FETCH SENSITIVE detects a delete hole, no data is returned (a warning is issued), and the cursor is left positioned on the delete hole.
Updates through a cursor result in an automatic re-fetch of the row. This re-fetch means that updates can create a hole themselves. The re-fetched row also reflects changes as a result of triggers updating the same row. It is important to reflect these changes to maintain the consistency of data in the row.
Using a function that is not deterministic (built-in or user-defined) in the WHERE clause of the select-statement or statement-name of a SENSITIVE STATIC cursor can cause misleading results. This situation occurs because DB2 constructs a temporary result table and retrieves rows from this table for FETCH INSENSITIVE statements. When DB2 processes a FETCH SENSITIVE statement, rows are fetched from the underlying table and predicates are re-evaluated. Using a function that is not deterministic can yield a different result on each FETCH SENSITIVE of the same row, which could also result in the row no longer being considered a match.
A FETCH INSENSITIVE on a SENSITIVE STATIC SCROLL cursor is not sensitive to changes made outside the cursor, unless a previous FETCH SENSITIVE has already refreshed that row; however, positioned updates and delete changes with the cursor are visible.
STATIC cursors are insensitive to insertions.
- WITHOUT HOLD or WITH HOLD
- Specifies whether
the cursor should be prevented from being closed as a consequence
of a commit operation.
- WITHOUT HOLD
- Does not prevent the cursor from being closed as a consequence of a commit operation. This is the default.
- WITH HOLD
- Prevents the cursor from being closed as a consequence of a commit
operation. A cursor declared with WITH HOLD is closed at commit time
if one of the following is true:
- The connection associated with the cursor is in the release pending status.
- The bind option DISCONNECT(AUTOMATIC) is in effect.
- The environment is one in which the option WITH HOLD is ignored.
When WITH HOLD is specified, a commit operation commits all of the changes in the current unit of work. For example, with a non-scrollable cursor, an initial FETCH statement is needed after a COMMIT statement to position the cursor on the row that follows the row that the cursor was positioned on before the commit operation.
WITH HOLD has no effect on an SQL data change statement within a SELECT statement. When a COMMIT is issued, the changes caused by the SQL data change statement are committed, regardless of whether or not the cursor is declared WITH HOLD.
All cursors are implicitly closed by a connect (Type 1) or rollback operation. A cursor is also implicitly closed by a commit operation if WITH HOLD is ignored or not specified.
Cursors that are declared with WITH HOLD in CICS® or in IMS™ non-message-driven programs will not be closed by a rollback operation if the cursor was opened in a previous unit of work and no changes have been made to the database in the current unit of work. The cursor cannot be closed because CICS and IMS do not broadcast the rollback request to DB2 for a null unit of work.
If a cursor is closed before the commit operation, the effect is the same as if the cursor was declared without the option WITH HOLD.
WITH HOLD is ignored in IMS message driven programs (MPP, IFP, and message-driven BMP). WITH HOLD maintains the cursor position in a CICS pseudo-conversational program until the end-of-task (EOT).
For details on restrictions that apply to declaring cursors with WITH HOLD, see DB2 Application Programming and SQL Guide.
- WITHOUT RETURN or WITH RETURN
- Specifies whether
the result table of the cursor is intended to be used as a result
set that will be returned from a procedure. If statement-name is
specified, the default is the corresponding prepare attribute of the
statement. Otherwise, the default is WITHOUT RETURN.
- WITHOUT RETURN
- Specifies that the result table of the cursor is not intended to be used as a result set that will be returned from a procedure.
- WITH RETURN
- Specifies that the result table of the cursor is intended to be
used as a result set that will be returned from a procedure. WITH
RETURN is relevant only if the DECLARE CURSOR statement is contained
within the source code for a procedure. In other cases, the precompiler
might accept the clause, but it has not effect.
When a cursor that is declared using the WITH RETURN TO CALLER clause remains open at the end of a program or routine, that cursor defines a result set from the program or routine. Use the CLOSE statement to close a cursor that is not intended to be a result set from the program or routine. Although DB2 will automatically close any cursors that are not declared using with a WITH RETURN clause, the use of the CLOSE statement is recommended to increase the portability of applications.
For non-scrollable cursors, the result set consists of all rows from the current cursor position to the end of the result table. For scrollable cursors, the result set consists of all rows of the result table.
- TO CALLER
- Specifies that the cursor can return a result set to the caller
of the procedure. The caller is the program or routine that executed
the SQL CALL statement that invokes the procedure that contains the
DECLARE CURSOR statement. For example, if the caller is a procedure,
the result set, is returned to the procedure. If the caller is a client
application, the result set is returned to the client application.
If the statement is contained within the source code for a procedure, WITH RETURN TO CALLER specifies that the cursor can be used as a result set cursor. A result set cursor is used when the result table of a cursor is to be returned from a procedure. Specifying TO CALLER is optional.
In other cases, the clause is ignored and the cursor cannot be used as a result set cursor.
- TO CLIENT
- Specifies that the cursor can return a result set to the client application. This cursor is invisible to any intermediate nested procedures. If a function or trigger calls the procedure (either directly or indirectly), the result set cannot be returned to the client and the cursor will be closed after the procedure finishes.
- rowset-positioning
- Specifies
whether multiple rows of data can be accessed as a rowset on a single
FETCH statement for the cursor. The default is WITHOUT ROWSET POSITIONING.
- WITHOUT ROWSET POSITIONING
- Specifies that the cursor can be used only with row-positioned FETCH statements. The cursor is to return a single row for each FETCH statement and the FOR n ROWS clause cannot be specified on a FETCH statement for this cursor. WITHOUT ROWSET POSITIONING or single row access refers to how data is fetched from the database engine. For remote access, data might be blocked and returned to the client in blocks.
- WITH ROWSET POSITIONING
- Specifies that the cursor can be used with either row-positioned or
rowset-positioned FETCH statements. This cursor can be used to return either a single row or
multiple rows, as a rowset, with a single FETCH statement. ROWSET POSITIONING refers to how data is
fetched from the database engine. For remote access, if any row qualifies, at least 1 row is
returned as a rowset. The size of the rowset depends on the number of rows specified on the FETCH
statement and on the number of rows that qualify. Data might be blocked and returned to the client
in blocks.
DB2 REXX applications do not support cursors that are declared WITH ROWSET POSITIONING. To allow a cursor for a SELECT statement in a DB2 REXX application to be used with row-positioned or rowset-positioned FETCH statements, specify WITH ROWSET POSITIONING in the attribute string of the PREPARE statement for the SELECT statement.
- select-statement
- Specifies the result table of the cursor. See select-statement for
an explanation of select-statement.
The select-statement must not include parameter markers (except for REXX), but can include references to host variables. In host languages, other than REXX, the declarations of the host variables must precede the DECLARE CURSOR statement in the source program. In REXX, parameter markers must be used in place of host variables and the statement must be prepared.
The USING clause of the OPEN statement can be used to specify host variables that will override the values of the host variables or parameter markers that are specified as part of the statement in the DECLARE CURSOR statement.
The select-statement must not contain an SQL data change statement if the cursor is defined as SENSITIVE DYNAMIC or SENSITIVE STATIC.
- statement-name
- Identifies the prepared select-statement that specifies
the result table of the cursor whenever the cursor is opened. The statement-name must
not be identical to a statement name specified in another DECLARE
CURSOR statement of the source program. For an explanation of prepared
SELECT statements, see PREPARE.
The prepared select-statement must not contain an SQL data change statement if the cursor is defined as SENSITIVE DYNAMIC or SENSITIVE STATIC.
Notes
A cursor in the open state designates a result table and a position relative to the rows of that table. The table is the result table specified by the SELECT statement of the cursor.
- Read-only cursors:
- If the result table is read-only, the cursor is read-only. The cursor that references a view with instead of triggers are read-only since positioned UPDATE and positioned DELETE statements are not allowed using those cursors. The result table is read-only if one or more of the following statements is true about the select-statement of the cursor:
- The first FROM clause identifies or contains any of the following:
- More than one table or view
- A catalog table with no updatable columns
- A read-only view
- A nested table expression
- A table function
- A system-maintained materialized query table
- A single table that is a system-period temporal table and a period specification is used
- The first SELECT clause specifies the keyword DISTINCT, contains an aggregate function, or uses both
- It contains an SQL data change statement
- The outer subselect contains a GROUP BY clause, a HAVING clause, or both clauses
- It contains a subquery such that the base object of the outer subselect, and of the subquery, is the same table
- Any of the following operators or clauses are specified:
- A set operator
- An ORDER BY clause (except when the cursor is declared as SENSITIVE STATIC scrollable)
- A FOR READ ONLY clause
- It is executed with isolation level UR and a FOR UPDATE clause is not specified.
- It is a VALUES clause.
If the result table is not read-only, the cursor can be used to update or delete the underlying rows of the result table.
- The first FROM clause identifies or contains any of the following:
- Tables for which row or column access controls are enforced:
- The select-statement of the cursor can reference a table for which row or column access controls are enforced. The row or column access controls do not effect the determination of whether the cursor is read-only and do not effect the cursor sensitivity.
- Work file database requirement for static scrollable cursors:
- To use a static scrollable cursor, you must first create a work file database and at least one
table space with a 32KB page size in this database because a static scrollable cursor requires a
temporary table for its result table while the cursor is open. DB2 chooses a table space to use for the temporary result table. Dynamic scrollable cursors do
not require a declared temporary table.
For static scrollable cursor declarations that contain empty strings, DB2 assigns one byte in the temporary table space for each empty string. The following example shows a scrollable cursor declaration with an empty string:
EXEC SQL DECLARE CSROWSTAT SENSITIVE STATIC SCROLL CURSOR WITH ROWSET POSITIONING WITH HOLD FOR SELECT ID1,'' FROM TB;
- Cursors in COBOL and Fortran programs:
- In COBOL and Fortran source programs, the DECLARE CURSOR statement must precede all statements that explicitly refer to the cursor by name. This rule does not necessarily apply to the other host languages because the precompiler provides a two-pass option for these languages. This rule applies to other host languages if the two-pass option is not used.
- Cursors in REXX:
- If host variables are used in a DECLARE CURSOR statement within a REXX procedure, the DECLARE CURSOR statement must be the object of a PREPARE and EXECUTE.
- Scope of a cursor:
- The scope of cursor-name is the source program in which it is defined;
that is, the application program submitted to the precompiler. Thus, you can only refer to a cursor
by statements that are precompiled with the cursor declaration. For example, a COBOL program called
from another program cannot use a cursor that was opened by the calling program. Furthermore, a
cursor defined in a Fortran subprogram can only be referred to in that subprogram. Cursors that
specify WITH RETURN in a procedure and are left open are returned as result sets.Although the scope of a cursor is the program in which it is declared, each package (or DBRM of a plan) created from the program includes a separate instance of the cursor, and more than one instance of the cursor can be used in the same execution of the program. For example, assume a program is precompiled with the CONNECT(2) option and its DBRM is used to create a package at location X and a package at location Y. The program contains the following SQL statements:
DECLARE C CURSOR FOR ... CONNECT TO X OPEN C FETCH C INTO ... CONNECT TO Y OPEN C FETCH C INTO ...
The second OPEN C statement does not cause an error because it refers to a different instance of cursor C. The same notion applies to a single location if the packages are in different collections.
A SELECT statement is evaluated at the time the cursor is opened. If the same cursor is opened, closed, and then opened again, the results can be different. If the SELECT statement of the cursor contains CURRENT DATE, CURRENT TIME or CURRENT TIMESTAMP, all references to these special registers yields the same respective datetime value on each FETCH operation. The value is determined when the cursor is opened. Multiple cursors using the same SELECT statement can be opened concurrently. They are each considered independent activities.
- Blocking of data:
- To process data more efficiently, DB2 might block data for read-only cursors. If a cursor is not going to be used in a positioned UPDATE or positioned DELETE statement, define the cursor as FOR READ ONLY.
- Positioned deletes and isolation level UR:
- Specify FOR UPDATE if you want to use the cursor for a positioned DELETE and the isolation level is UR because of a BIND option. In this case, the isolation level is CS.
- Returning a result set from a stored procedure:
- A cursor that is declared in a stored procedure returns a result set when all of the following
conditions are true:
- The cursor is declared with the WITH RETURN option. In a distributed environment, blocks of each result set of the cursor's data are returned with the CALL statement reply.
- The cursor is left open after exiting from the stored procedure. A cursor declared with the SCROLL option must be left positioned before the first row before exiting from the stored procedure.
- The cursor is declared with the WITH HOLD option if the stored procedure is defined to commit on return.
The result set is the set of all rows after the current position of the cursor after exiting the stored procedure. The result set is assumed to be read-only. If that same procedure is invoked again, open result set cursors for a stored procedure at a given site are automatically closed by the database management system.
- Scrollable cursors specified with user-defined functions:
- A row can be fetched more than once with a scrollable cursor. Therefore, if a scrollable cursor
is defined with a function that is not deterministic in the select list of the cursor, a row can be
fetched multiple times with different results for each fetch. (However, the value of a function that
is not deterministic in the WHERE clause of a scrollable cursor is captured when the cursor is
opened and remains unchanged until the cursor is closed.) Similarly, if a scrollable cursor is
defined with a user-defined function with external action, the action is executed with every
fetch.
Multiple instances of a cursor that is defined with RETURN TO CLIENT: If the cursor is declared in a native SQL procedure, a cursor that is declared as WITH RETURN TO CLIENT can be opened even when a cursor with the same name is already in the open state. In this case, the already open cursor becomes a result set cursor and is no longer accessible by using its cursor name. A new cursor is opened and becomes accessible by using the cursor name. When a CLOSE statement is issued, the last instance of the cursor will be closed. Closing the new cursor does not make the cursor that was previously accessible by that name accessible by the cursor name again. Cursors that become result set cursors in this way cannot be accessed at the server and can be processed only at the client.
Examples
The statements in the following examples are assumed to be in PL/I programs.
EXEC SQL DECLARE C1 CURSOR FOR
SELECT DEPTNO, DEPTNAME, MGRNO
FROM DSN8A10.DEPT
WHERE ADMRDEPT = 'A00';
EXEC SQL DECLARE C1 CURSOR FOR
SELECT DEPTNO, DEPTNAME, MGRNO
FROM DSN8A10.DEPT
WHERE ADMRDEPT = 'A00'
FOR READ ONLY WITH RS USE AND KEEP EXCLUSIVE LOCKS;
EXEC SQL DECLARE C2 CURSOR FOR STMT2;
EXEC SQL DECLARE C3 CURSOR WITH HOLD FOR
SELECT * FROM DSN8A10.EMP
FOR UPDATE OF WORKDEPT, PHONENO, JOB, EDLEVEL, SALARY;
Instead of specifying which columns should be updated, you could use a FOR UPDATE clause without the
names of the columns to indicate that all updatable columns are updated. EXEC SQL DECLARE C4 CURSOR WITH HOLD WITH RETURN FOR
SELECT PROJNO, PROJNAME
FROM DSN8A10.PROJ
WHERE DEPTNO = 'A01';
EXEC SQL DECLARE C5 SENSITIVE STATIC SCROLL CURSOR FOR
SELECT DEPTNO, DEPTNAME, MGRNO
FROM DSN8A10.DEPT
WHERE ADMRDEPT = 'A00';
EXEC SQL DECLARE C6 INSENSITIVE SCROLL CURSOR FOR
SELECT DEPTNO, DEPTNAME, MGRNO
FROM DSN8A10.DEPT
WHERE DEPTNO;
CREATE TABLE ORDER
(ORDERNUM INTEGER,
CUSTNUM INTEGER,
CUSTNAME VARCHAR(20),
ORDERDATE CHAR(8),
ORDERAMT DECIMAL(8,3),
COMMENTS VARCHAR(20));
Populate the table by inserting or loading about 500 rows.
EXEC SQL DECLARE CURSOR ORDERSCROLL
SENSITIVE DYNAMIC SCROLL FOR
SELECT ORDERNUM, CUSTNAME, ORDERAMT, ORDERDATE FROM ORDER
WHERE ORDERAMT > 1000
FOR UPDATE OF COMMENTS;
Open
the scrollable cursor. OPEN CURSOR ORDERSCROLL;
Fetch forward from the
scrollable cursor.
-- Loop-to-fill-screen
-- do 10 times
FETCH FROM ORDERSCROLL INTO :HV1, :HV2, :HV3, :HV4;
-- end
Fetch
RELATIVE from the scrollable cursor. -- Skip-forward-100-rows
FETCH RELATIVE +100
FROM ORDERSCROLL INTO :HV1, :HV2, :HV3, :HV4;
-- Skip-backward-50-rows
FETCH RELATIVE -50
FROM ORDERSCROLL INTO :HV1, :HV2, :HV3, :HV4;
Fetch
ABSOLUTE from the scrollable cursor.
-- Re-read-the-third-row
FETCH ABSOLUTE +3
FROM ORDERSCROLL INTO :HV1, :HV2, :HV3, :HV4;
Fetch
RELATIVE from scrollable cursor.
-- Read-the-third-row-from current position
FETCH SENSITIVE RELATIVE +3
FROM ORDERSCROLL INTO :HV1, :HV2, :HV3, :HV4;
Do
a positioned update through the scrollable cursor.
-- Update-the-current-row
UPDATE ORDER SET COMMENTS = "Expedite"
WHERE CURRENT OF ORDERSCROLL;
Close
the scrollable cursor. CLOSE CURSOR ORDERSCROLL;
EXEC SQL DECLARE C1 CURSOR
WITH ROWSET POSITIONING FOR MYCURSOR;