7.6.2. DECLARE CURSOR

Used for

Declaring a named cursor

Available in

PSQL

Syntax

  1. DECLARE [VARIABLE] cursorname CURSOR FOR (<select>) [FOR UPDATE]
Table 82. DECLARE CURSOR Statement Parameters
ArgumentDescription

cursorname

Cursor name

select

SELECT statement

The DECLARE CURSOR …​ FOR statement binds a named cursor to the result set obtained in the SELECT statement specified in the FOR clause. In the body code, the cursor can be opened, used to walk row-by-row through the result set and closed. While the cursor is open, the code can perform positioned updates and deletes using the WHERE CURRENT OF in the UPDATE or DELETE statement.

Cursor Idiosyncrasies

  • The optional FOR UPDATE clause can be included in the SELECT statement but its absence does not prevent successful execution of a positioned update or delete

  • Care should be taken to ensure that the names of declared cursors do not conflict with any names used subsequently in statements for AS CURSOR clauses

  • If the cursor is needed only to walk the result set, it is nearly always easier and less error-prone to use a FOR SELECT statement with the AS CURSOR clause. Declared cursors must be explicitly opened, used to fetch data and closed. The context variable ROW_COUNT has to be checked after each fetch and, if its value is zero, the loop has to be terminated. A FOR SELECT statement checks it automatically.

    Nevertheless, declared cursors provide a high level of control over sequential events and allow several cursors to be managed in parallel.

  • The SELECT statement may contain parameters. For instance:

    1. SELECT NAME || :SFX FROM NAMES WHERE NUMBER = :NUM

    Each parameter has to have been declared beforehand as a PSQL variable, even if they originate as input and output parameters. When the cursor is opened, the parameter is assigned the current value of the variable.

Attention!

If the value of a PSQL variable used in the SELECT statement changes during the loop, its new value may (but not always) be used for the remaining rows. It is better to avoid having such situations arise unintentionally. If you really need this behaviour, you should test your code carefully to be certain that you know exactly how changes in the variable affect the result.

Note particularly that the behaviour may depend on the query plan, specifically on the indexes being used. No strict rules are in place for situations like this currently, but that could change in future versions of Firebird.

Examples Using Named Cursors

  1. Declaring a named cursor in the trigger.

    1. CREATE OR ALTER TRIGGER TBU_STOCK
    2. BEFORE UPDATE ON STOCK
    3. AS
    4. DECLARE C_COUNTRY CURSOR FOR (
    5. SELECT
    6. COUNTRY,
    7. CAPITAL
    8. FROM COUNTRY
    9. );
    10. BEGIN
    11. /* PSQL statements */
    12. END
  2. A collection of scripts for creating views with a PSQL block using named cursors.

    1. EXECUTE BLOCK
    2. RETURNS (
    3. SCRIPT BLOB SUB_TYPE TEXT)
    4. AS
    5. DECLARE VARIABLE FIELDS VARCHAR(8191);
    6. DECLARE VARIABLE FIELD_NAME TYPE OF RDB$FIELD_NAME;
    7. DECLARE VARIABLE RELATION RDB$RELATION_NAME;
    8. DECLARE VARIABLE SOURCE TYPE OF COLUMN RDB$RELATIONS.RDB$VIEW_SOURCE;
    9. DECLARE VARIABLE CUR_R CURSOR FOR (
    10. SELECT
    11. RDB$RELATION_NAME,
    12. RDB$VIEW_SOURCE
    13. FROM
    14. RDB$RELATIONS
    15. WHERE
    16. RDB$VIEW_SOURCE IS NOT NULL);
    17. -- Declaring a named cursor where
    18. -- a local variable is used
    19. DECLARE CUR_F CURSOR FOR (
    20. SELECT
    21. RDB$FIELD_NAME
    22. FROM
    23. RDB$RELATION_FIELDS
    24. WHERE
    25. -- It is important that the variable must be declared earlier
    26. RDB$RELATION_NAME = :RELATION);
    27. BEGIN
    28. OPEN CUR_R;
    29. WHILE (1 = 1) DO
    30. BEGIN
    31. FETCH CUR_R
    32. INTO :RELATION, :SOURCE;
    33. IF (ROW_COUNT = 0) THEN
    34. LEAVE;
    35. FIELDS = NULL;
    36. -- The CUR_F cursor will use the value
    37. -- of the RELATION variable initiated above
    38. OPEN CUR_F;
    39. WHILE (1 = 1) DO
    40. BEGIN
    41. FETCH CUR_F
    42. INTO :FIELD_NAME;
    43. IF (ROW_COUNT = 0) THEN
    44. LEAVE;
    45. IF (FIELDS IS NULL) THEN
    46. FIELDS = TRIM(FIELD_NAME);
    47. ELSE
    48. FIELDS = FIELDS || ', ' || TRIM(FIELD_NAME);
    49. END
    50. CLOSE CUR_F;
    51. SCRIPT = 'CREATE VIEW ' || RELATION;
    52. IF (FIELDS IS NOT NULL) THEN
    53. SCRIPT = SCRIPT || ' (' || FIELDS || ')';
    54. SCRIPT = SCRIPT || ' AS ' || ASCII_CHAR(13);
    55. SCRIPT = SCRIPT || SOURCE;
    56. SUSPEND;
    57. END
    58. CLOSE CUR_R;
    59. END

See also

OPEN, FETCH, CLOSE