ヘッダーをスキップ
Oracle Rdb SQLリファレンス・マニュアル
リリース7.2
E06178-01
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 


SQL> -- Define a cursor of Board Manufacturing Department Managers:
SQL> --
SQL> DECLARE BM_MGR CURSOR FOR
cont> SELECT EMPLOYEE_ID, RESUME FROM RESUMES R, CURRENT_INFO CI
cont> WHERE R.EMPLOYEE_ID = CI.ID AND DEPARTMENT
cont> CONTAINING "BOARD MANUFACTURING" AND JOB = "Department Manager";
SQL> --
SQL> -- Define a cursor for resumes of those managers:
SQL> DECLARE THE_RESUME LIST CURSOR FOR
cont> SELECT RESUME WHERE CURRENT OF BM_MGR;
SQL> --
SQL> -- Build the manager's cursor:
SQL> OPEN BM_MGR;
SQL> --
SQL> -- Fetch the manager's row:
SQL> FETCH BM_MGR;
 R.EMPLOYEE_ID   R.RESUME
 00164                           72:2:3
SQL> --
SQL> -- Get part of the resume:
SQL> OPEN THE_RESUME;
SQL> FETCH THE_RESUME;
 RESUME
 This is the resume for Alvin Toliver
SQL> --
SQL> -- Do not close the resume, and access the next manager:
SQL> FETCH BM_MGR;
 R.EMPLOYEE_ID   R.RESUME
 00166                           72:2:9
SQL> -- SQL continues to fetch from Toliver's resume (00164)
SQL> -- because the list cursor was not closed.
SQL> -- If it were a new resume, you would see
SQL> -- a new "This is the resume for ..." line.
SQL> FETCH THE_RESUME;
 RESUME
 Boston, MA

  • 宣言カーソルは、TSET TRANSACTION RESERVING句またはLOCK TABLE文で指定された同じ表または表のリストを参照する必要があります。次に例を示します。


    SQL> SET TRANSACTION RESERVING jobs FOR WRITE;
    SQL> DECLARE curs1 CURSOR WITH HOLD FOR
    cont> SELECT first_name,last_name FROM employees;
    SQL> OPEN CURS1;
    %RDB-E-UNRES_REL, relation EMPLOYEES in specified request is not a relation
    reserved in specified transaction
    

  • 表カーソルにはWITH HOLD句のみを指定できます。

  • 一部の問合せでは、RdbはOPEN文の実行時にカーソル用のデータをプリフェッチできます。例にはORDER BY句を含むカーソルがあります。ORDER BY句では、結果の最初の行を配布する前にデータを読み取ってソートする必要があります。フェッチされた行はここではOPEN時のデータのスナップショットになり、COMMIT文の実行後は不要になることがあります。
    たとえば、ユーザーBROWNが従業員表にアクセスするカーソルを宣言およびオープンし、後でトランザクションをコミットしますが、WITH HOLDカーソルをオープンしたままとします。BROWNがカーソルをオープンしているときに、ユーザーJONESが従業員表からある従業員を削除します。BROWNにはまだJONESによって削除された従業員が表示されています。BROWNは元の状態の表からの一時コピーにアクセスしているためです。

  • SET HOLD CURSORS文を使用して、保持可能カーソルのSQLセッションのデフォルト設定を定義できます。詳細は、「SET HOLD CURSORS文」を参照してください。

  • WITH HOLD PRESERVE ALL句は、カーソルのODBCドライバの動作に準拠しています。

  • アウトラインが存在する場合は、OPTIMIZE USING句で指定されているアウトラインが使用されます。ただし、アウトラインのディレクティブを1つ以上順守できない場合は除きます。たとえば、アウトラインの準拠レベルが必須で、アウトラインのディレクティブで指定されている索引の1つが削除された場合、そのアウトラインは使用されません。既存のアウトラインを使用できない場合は、エラー・メッセージが発行されます。
    存在しないアウトラインの名前を指定すると、問合せがコンパイルされ、そのアウトライン名は無視され、問合せと同じアウトラインIDを持つ既存のアウトラインが検索されます。同じアウトラインIDのアウトラインが検出されると、そのアウトラインのディレクティブを使用して問合せを実行しようとします。同じアウトラインIDを持つアウトラインが検出されない場合、問合せ実行のための計画がオプティマイザで選択されます。
    問合せアウトラインの詳細は、『Oracle Rdb7 Guide to Database Performance and Tuning』を参照してください。


    例1: 対話型SQLにおける表カーソルの宣言

    次の例は、SALARY_INFOというカーソルを宣言しています。SALARY_INFOの結果表には、従業員の名前および現在の給与が格納され、姓でソートされています。


    SQL> --
    SQL> DECLARE SALARY_INFO CURSOR FOR
    cont>  SELECT  E.FIRST_NAME, E.LAST_NAME, S.SALARY_AMOUNT
    cont>  FROM    EMPLOYEES E, SALARY_HISTORY S
    cont>  WHERE   E.EMPLOYEE_ID = S.EMPLOYEE_ID
    cont>          AND
    cont>          S.SALARY_END IS NULL
    cont>  ORDER BY
    cont>          E.LAST_NAME ASC;
    SQL> --
    SQL> -- Use an OPEN statement to open the cursor and
    SQL> -- position it before the first row of the
    SQL> -- result table:
    SQL> OPEN SALARY_INFO;
    SQL> --
    SQL> -- Finally, use two FETCH statements to see the
    SQL> -- first two rows of the cursor:
    SQL> FETCH SALARY_INFO;
     E.FIRST_NAME   E.LAST_NAME      S.SALARY_AMOUNT
     Louie          Ames                  $26,743.00
    SQL> FETCH SALARY_INFO;
     E.FIRST_NAME   E.LAST_NAME      S.SALARY_AMOUNT
     Leslie         Andriola              $50,424.00
    

    例2: Cプログラムにおける表カーソルの宣言

    この単純なプログラムでは埋め込まれたDECLARE CURSOR文、OPEN文およびFETCH文が使用され、マネージャの名前および部門が取得および出力されます。


    #include <stdio.h>
    
    void main ()
    {
    int SQLCODE;
    char FNAME[15];
    char LNAME[15];
    char DNAME[31];
    
    /* Declare the cursor: */
    exec sql
        DECLARE MANAGER CURSOR FOR
            SELECT E.FIRST_NAME, E.LAST_NAME, D.DEPARTMENT_NAME
            FROM EMPLOYEES E, DEPARTMENTS D
            WHERE E.EMPLOYEE_ID = D.MANAGER_ID ;
    
    /* Open the cursor: */
    exec sql
        OPEN MANAGER;
    
    /* Start a loop to process the rows of the cursor: */
    for (;;)
        {
        /* Retrieve the rows of the cursor
        and put the value in host language variables: */
        exec sql
            FETCH MANAGER INTO :FNAME, :LNAME, :DNAME;
        if (SQLCODE != 0) break;
        /* Print the values in the variables: */
        printf ("%s %s %s\n", FNAME, LNAME, DNAME);
        }
    
    /* Close the cursor: */
    exec sql
        CLOSE MANAGER;
    }
    

    例3: 対話型SQLにおける表カーソルおよびリスト・カーソルを使用したリスト・データの取得

    次の例は、リスト情報を取得する表カーソルおよびリスト・カーソルを宣言しています。


    SQL> DECLARE TBLCURSOR INSERT ONLY TABLE CURSOR FOR
    cont> SELECT EMPLOYEE_ID, RESUME FROM RESUMES;
    SQL> DECLARE LSTCURSOR INSERT ONLY LIST CURSOR FOR SELECT RESUME WHERE
    CURRENT OF TBLCURSOR;
    SQL> OPEN TBLCURSOR;
    SQL> INSERT INTO CURSOR TBLCURSOR (EMPLOYEE_ID) VALUES ('00164');
    1 row inserted
    SQL> OPEN LSTCURSOR;
    SQL> INSERT INTO CURSOR LSTCURSOR VALUES ('This is the resume for 00164');
    SQL> INSERT INTO CURSOR LSTCURSOR VALUES ('Boston, MA');
    SQL> INSERT INTO CURSOR LSTCURSOR VALUES ('Oracle Corporation');
    SQL> CLOSE LSTCURSOR;
    SQL> CLOSE TBLCURSOR;
    SQL> COMMIT;
    SQL> DECLARE TBLCURSOR2 CURSOR FOR SELECT EMPLOYEE_ID,
    cont> RESUME FROM RESUMES;
    SQL> DECLARE LSTCURSOR2 LIST CURSOR FOR SELECT RESUME WHERE
    CURRENT OF TBLCURSOR2;
    SQL> OPEN TBLCURSOR2;
    SQL> FETCH TBLCURSOR2;
      00164
    SQL> OPEN LSTCURSOR2;
    SQL> FETCH LSTCURSOR2;
     RESUME
     This is the resume for 00164
    SQL> FETCH LSTCURSOR2;
     RESUME
     Boston, MA
    SQL> FETCH LSTCURSOR2;
     RESUME
     Oracle Corporation
    SQL> FETCH LSTCURSOR2;
     RESUME
    %RDB-E-STREAM_EOF, attempt to fetch past end of record stream
    SQL> CLOSE LSTCURSOR2;
    SQL> SELECT * FROM RESUMES;
      EMPLOYEE_ID    RESUME
     00164                     1:701:2
    1 row selected
    SQL> CLOSE TBLCURSOR2;
    SQL> COMMIT;
    

    例4: リスト・カーソルのスクロール属性の使用

    次の例は、表カーソルおよび読取り専用スクロール可能リスト・カーソルを宣言し、リストのセグメント間を前後にスクロールすることによってリスト情報を取得しています。


    SQL> DECLARE CURSOR_ONE
    cont>   TABLE CURSOR FOR
    cont>   (SELECT EMPLOYEE_ID,RESUME FROM RESUMES);
    SQL> --
    SQL> DECLARE CURSOR_TWO
    cont>    READ ONLY
    cont>    SCROLL
    cont>    LIST CURSOR
    cont>    FOR SELECT RESUME
    cont>    WHERE CURRENT OF CURSOR_ONE;
    

    例5: 保持可能カーソルの宣言


    SQL> -- Declare a holdable cursor that remains open on COMMIT
    SQL> --
    SQL> DECLARE curs1 CURSOR
    cont>     WITH HOLD PRESERVE ON COMMIT
    cont>     FOR SELECT e.first_name, e.last_name
    cont>         FROM employees e
    cont>         ORDER BY e.last_name;
    SQL> OPEN curs1;
    SQL> FETCH curs1;
     FIRST_NAME   LAST_NAME
     Louie        Ames
    SQL> FETCH curs1;
     FIRST_NAME   LAST_NAME
     Leslie       Andriola
    SQL> COMMIT;
    SQL> FETCH curs1;
     FIRST_NAME   LAST_NAME
     Joseph       Babbin
    SQL> FETCH curs1;
     FIRST_NAME   LAST_NAME
     Dean         Bartlett
    SQL> ROLLBACK;
    SQL> FETCH curs1;
    %SQL-F-CURNOTOPE, Cursor CURS1 is not opened
    SQL> --
    SQL> -- Declare another holdable cursor that remains open always
    SQL> --
    SQL> DECLARE curs2 CURSOR
    cont>     WITH HOLD PRESERVE ALL
    cont>     FOR SELECT e.first_name, e.last_name
    cont>         FROM employees e
    cont>         ORDER BY e.last_name;
    SQL> OPEN curs2;
    SQL> FETCH curs2;
     FIRST_NAME   LAST_NAME
     Louie        Ames
    SQL> FETCH curs2;
     FIRST_NAME   LAST_NAME
     Leslie       Andriola
    SQL> COMMIT;
    SQL> FETCH curs2;
     FIRST_NAME   LAST_NAME
     Joseph       Babbin
    SQL> FETCH curs2;
     FIRST_NAME   LAST_NAME
     Dean         Bartlett
    SQL> ROLLBACK;
    SQL> FETCH curs2;
     FIRST_NAME   LAST_NAME
     Wes          Bartlett
    


    DECLARE CURSOR文、動的

    実行時にパラメータでSELECT文が指定されるカーソルを宣言します。

    動的および非動的の両方のDECLARE CURSOR文に適用される文要素の詳細は、「DECLARE CURSOR文」を参照してください。


    環境

    動的DECLARE CURSOR文は次の環境で使用できます。

    • プリコンパイル対象のホスト言語プログラムに埋め込まれる場合

    • SQLモジュールのDECLARE文のセクションの一部として


    形式




    引数

    cursor-name

    宣言するカーソルの名前です。モジュールのすべてのカーソル名の間で一意の名前を指定します。有効なSQL名を使用します。識別子の詳細は、第2.2節を参照してください。

    FOR statement-name

    実行時に生成された、準備されたSELECT文を識別する名前です。

    INSERT ONLY

    新規リストまたは新規行を作成またはオープンするように指定します。

    LIST CURSOR

    リスト内の要素にアクセスするカーソルを宣言していることを指定します。

    PRESERVE ON COMMIT

    PRESERVE ON ROLLBACK

    PRESERVE ALL

    PRESERVE NONE

    カーソルがオープン状態を保持するタイミングを指定します。

    • PRESERVE ON COMMIT
      コミット時に、WITH HOLD PRESERVE ON COMMIT構文で定義したものを除き、すべてのカーソルがクローズします。ロールバック時に、WITH HOLD PRESERVE ON COMMIT構文で定義したものを含めて、すべてのカーソルがクローズします。
      これは保存オプションなしでWITH HOLD句を指定することと同じです。

    • PRESERVE ON ROLLBACK
      ロールバック時に、WITH HOLD PRESERVE ON ROLLBACK構文で定義したものを除き、すべてのカーソルがクローズします。コミット時に、WITH HOLD PRESERVE ON ROLLBACK構文で定義したものを含めて、すべてのカーソルがクローズします。

    • PRESERVE ALL
      コミットまたはロールバックの後、すべてのカーソルがオープンしたままです。カーソルはCLOSE文の使用により、またはセッションの終了時に、クローズします。

    • PRESERVE NONE
      すべてのカーソルがクローズするのは、CLOSE文、COMMIT文またはROLLBACK文の後の、プログラム停止時、または対話型SQL終了時です。
      これはWITH HOLD句を指定しないことと同じです。

    READ ONLY

    データベースの更新にカーソルが使用されないことを指定します。

    SCROLL

    Oracle Rdbでリストの項目をいずれかの方向(上下)またはランダムに読み取ることができることを指定します。

    TABLE CURSOR

    表内の行にアクセスするカーソルを宣言していることを指定します。

    UPDATE ONLY

    データベースの更新にカーソルが使用されることを指定します。

    WITH HOLD

    カーソルがオープンしたままでトランザクションの終了後にその位置を保持することを指示します。これは保持可能カーソルと呼ばれます。

    使用方法

    • 動的DECLARE CURSOR文では、カーソル名はコンパイルされますが、SELECT文は実行時に確認されます。

    • 動的DECLARE CURSOR文は非実行可能文であるため、この文は静的DECLARE CURSOR文と同様に、SQLモジュールのDECLAREセクションに配置する必要があります。

    • 主問合せにGROUP BY句、UNION句、EXCEPT (MINUS)句またはINTERSECT句を含むカーソルおよびビューには、DBKEYによるアクセスを必要とする動的カーソルを使用してアクセスすることはできません。ユーザーが動的カーソルでこれらのビューのいずれかにアクセスしようとすると、カーソルのオープン時に次のエラーが返されます。


      "RDMS-F-VIEWNORET, view cannot be retrieved by database key".
      


      この問題を回避するには、非動的カーソルを使用してビューにアクセスします。動的カーソルを使用する必要がある場合は、文はビュー自体ではなく(必要に応じてGROUP BY句およびUNION句を指定して)ビューを構成する実表にアクセスする必要があります。

    • 「DECLARE CURSOR文」の「使用方法」も参照してください。


    例1: 文名に対するパラメータの使用


       .
       .
       .
    * This program prepares a statement for dynamic execution from the string
    * passed to it, and uses a dynamic cursor to fetch a row from a table.
    *
    */
    #include <stdio.h>
    #include <descrip.h>
    
    struct SQLDA_STRUCT {
              char SQLDAID[8];
              int SQLDABC;
              short SQLN;
              short SQLD;
              struct {
                short SQLTYPE;
                short SQLLEN;
                char *SQLDATA;
                short *SQLIND;
                short SQLNAME_LEN;
                char SQLNAME[30];
                  } SQLVAR[];
            } *SQLDA;
    main()
    {
    
    /*
     *  General purpose locals
     */
    int     i;
    long    sqlcode;
    
    char    command_string[256];
    
    
    /*
     *  Allocate SQLDA structures.
     */
    
    SQLDA = malloc(500);
    SQLDA->SQLN = 20;
    
    /* Get the SELECT statement at run time. */
    
    printf("\n Enter a SELECT statement.\n");
    printf("\n Do not end the statement with a semicolon.\n");
    gets(command_string);
    
    /* Prepare the SELECT statement. */
    PREP_STMT( &sqlcode, &command_string, SQLDA );
    if (sqlcode != 0)
        goto err;
    
    
    /* Open the cursor. */
    OPEN_CURSOR( &sqlcode );
    if (sqlcode != 0)
        goto err;
    
    /* Allocate memory.   */
    for (i=0; i < SQLDA->SQLD; i++) {
        SQLDA->SQLVAR[i].SQLDATA = malloc( SQLDA->SQLVAR[i].SQLLEN );
        SQLDA->SQLVAR[i].SQLIND  = malloc( 2 );
    }
    
    /* Fetch a row. */
    FETCH_CURSOR( &sqlcode, SQLDA );
    if (sqlcode != 0)
        goto err;
    
    /* Use the SQLDA to determine the data type of each column in the row
       and print the column.  For simplicity, test for only two data types.
       CHAR and INT. */
    
    for (i=0; i < SQLDA->SQLD; i++) {
    
        switch (SQLDA->SQLVAR[i].SQLTYPE) {
    
        case SQLDA_CHAR;    /* Character */
            printf( "%s", SQLDA->SQLVAR[i].SQLDATA );
            break;
        case SQLDA_INTEGER:   /* Integer */
            printf( "%d", SQLDA->SQLVAR[i].SQLDATA );
            break;
        default:
            printf( "Some other datatype encountered\n");
        }
    }
    
    /* Close the cursor. */
    CLOSE_CURSOR( &sqlcode );
    
    ROLLBACK(&sqlcode );
    return;
       .
       .
       .
    }
    

    例2: プログラム・コールの前のSQLモジュール・ファイル


    --  This program uses dynamic cursors to fetch a row.
    --
    --
    MODULE          C_MOD_DYN_CURS
    LANGUAGE        C
    AUTHORIZATION   RDB$DBHANDLE
    
    DECLARE ALIAS FOR FILENAME personnel
    
    -- Declare the dynamic cursor. Use a statement name to identify a
    -- prepared SELECT statement.
    
    DECLARE CURSOR1 CURSOR FOR STMT_NAME
    
    -- Prepare the statement from a statement entered at run time
    -- and specify that SQL write information about the number and
    -- data type of select list items to the SQLDA.
    
    PROCEDURE PREP_STMT
        SQLCODE
        COMMAND_STRING  CHAR (256)
        SQLDA;
    
          PREPARE STMT_NAME SELECT LIST INTO SQLDA FROM COMMAND_STRING;
    
    
    PROCEDURE OPEN_CURSOR
         SQLCODE;
    
        OPEN CURSOR1;
    
    PROCEDURE FETCH_CURSOR
        SQLCODE
        SQLDA;
    
        FETCH CURSOR1 USING DESCRIPTOR SQLDA;
    
    PROCEDURE CLOSE_CURSOR
        SQLCODE;
    
        CLOSE CURSOR1;
    
    PROCEDURE ROLLBACK
        SQLCODE;
    
        ROLLBACK;
    


    DECLARE CURSOR文、拡張動的

    拡張動的カーソルを宣言します。拡張動的DECLARE CURSOR文は、実行時にカーソル名とSELECT文の両方をパラメータに指定するDECLARE CURSOR文です。

    動的および非動的の両方のDECLARE CURSOR文に適用される文要素の詳細は、「DECLARE CURSOR文」を参照してください。


    環境

    拡張動的DECLARE CURSOR文は次の環境で使用できます。

    • プリコンパイル対象のホスト言語プログラムに埋め込まれる場合

    • SQLモジュールのプロシージャの一部として


    形式




    引数

    cursor-name-parameter

    宣言するカーソルの名前を格納します。文字列パラメータを使用して実行時にプログラムによって指定されるカーソル名を保持します。

    FOR statement-id-parameter

    準備されたSELECT文を識別する整数を含むパラメータです。整数パラメータを使用して、PREPARE文の実行時に生成されてパラメータに割り当てられる文識別子を保持します。

    INSERT ONLY

    新規リストまたは新規行を作成またはオープンするように指定します。

    LIST CURSOR FOR

    リスト内の要素にアクセスするカーソルを宣言していることを指定します。

    PRESERVE ON COMMIT

    PRESERVE ON ROLLBACK

    PRESERVE ALL

    PRESERVE NONE

    カーソルがオープン状態を保持するタイミングを指定します。

    • PRESERVE ON COMMIT
      コミット時に、WITH HOLD PRESERVE ON COMMIT構文で定義したものを除き、すべてのカーソルがクローズします。ロールバック時に、WITH HOLD PRESERVE ON COMMIT構文で定義したものを含めて、すべてのカーソルがクローズします。
      これは保存オプションなしでWITH HOLD句を指定することと同じです。

    • PRESERVE ON ROLLBACK
      ロールバック時に、WITH HOLD PRESERVE ON ROLLBACK構文で定義したものを除き、すべてのカーソルがクローズします。コミット時に、WITH HOLD PRESERVE ON ROLLBACK構文で定義したものを含めて、すべてのカーソルがクローズします。

    • PRESERVE ALL
      コミットまたはロールバックの後、すべてのカーソルがオープンしたままです。カーソルはCLOSE文の使用により、またはセッションの終了時に、クローズします。

    • PRESERVE NONE
      すべてのカーソルがクローズするのは、CLOSE文、COMMIT文またはROLLBACK文の後の、プログラム停止時、または対話型SQL終了時です。
      これはWITH HOLD句を指定しないことと同じです。

    READ ONLY

    データベースの更新にカーソルが使用されないことを指定します。

    SCROLL

    Oracle Rdbでリストの項目をいずれかの方向(上下)またはランダムに読み取ることができることを指定します。

    TABLE CURSOR FOR

    表内の行にアクセスするカーソルを宣言していることを指定します。

    UPDATE ONLY

    データベースの更新にカーソルが使用されることを指定します。

    WITH HOLD

    カーソルがオープンしたままでトランザクションの終了後にその位置を保持することを指示します。これは保持可能カーソルと呼ばれます。

    使用方法

    • 拡張動的DECLARE CURSOR文は、動的SQLの実行可能文です。パラメータを介して、カーソル名と、カーソルの実行時に元になるSELECT文の識別子の両方を指定できます。通常、拡張動的SQLを使用すると、1セットのSQLプロシージャは、任意の数の準備された文を同時に制御できます。

    • 拡張動的DECLARE CURSOR文によって、複数の動的に生成されたSELECT文に対して1つのDECLARE CURSOR文とPREPARE文の組合せを使用できます。これによって、動的に生成された各SELECT文に対するDECLARE CURSOR文およびPREPARE文のコーディングが不要になります。

    • 拡張動的DECLARE CURSOR文で、パラメータを使用してカーソル名と文識別子の両方を指定する必要があります。パラメータを介してカーソル名と文識別子の両方ではなくいずれか一方を明示的に指定すると、エラーが生成されます。カーソル名と文識別子の両方を明示的に指定すると、カーソルが非動的カーソルに、DECLARE CURSOR文が非実行可能文になります。

    • 拡張動的DECLARE CURSOR文は実行可能文であるため、実行時に実行ステータス(SQLSTATEまたはSQLCODE)を返します。拡張動的DECLARE CURSOR文の実行後にプログラムでステータスをチェックする必要があります。
      拡張動的DECLARE CURSOR文は実行可能文であるため、実行可能文が使用できるプログラムおよびSQLモジュールに配置する必要があります。たとえば、拡張動的DECLARE CURSOR文は、静的または動的なDECLARE CURSOR文と同様に、DECLAREセクションではなく、SQLモジュールのプロシージャ内に配置する必要があります。

    • 「DECLARE CURSOR文」の「使用方法」も参照してください。


    例1: 文名およびカーソル名に対するパラメータの使用

    次の例は、オンライン・サンプル・プログラムSQL$MULTI_STMT_DYN.SQLADAからの2つのプロシージャを示しています。このプロシージャは、文名およびカーソル名に対するパラメータの使用方法を示しています。


    .
    .
    .
    -- This procedure prepares a statement for dynamic execution from the string
    -- passed to it.  This procedure can prepare any number of statements
    -- because the statement is passed to it as the parameter, cur_procid.
    
    procedure PREPARE_SQL is
        CUR_CURSOR : string(1..31) := (others => ' ');
        CUR_PROCID : integer := 0;
        CUR_STMT : string(1..1024) := (others => ' ');
    
    begin
    -- Allocate separate SQLDAs for parameter markers (sqlda_in) and select list
    -- items (sqlda_out).  Assign the value of the constant MAXPARMS (set in the
    -- declarations section) to the SQLN field of both SQLDA structures. SQLN
    -- specifies to SQL the maximum size of the SQLDA.
    
    sqlda_in := new sqlda_record;
    sqlda_in.sqln := maxparms;
    sqlda_out := new sqlda_record;
    sqlda_out.sqln := maxparms;
    
    -- Assign the SQL statement that was constructed in the procedure
    -- CONSTRUCT_SQL to the variable cur_stmt.
    
    cur_stmt := sql_stmt;
    
    -- Use the PREPARE...SELECT LIST statement to prepare the dynamic statement
    -- and write information about any select list items in it to sqlda_out.
    -- It prepares a statement for dynamic execution from the string passed to
    -- it.  It also writes information about the number and data type of any
    -- select list items in the statement to an SQLDA (specifically, the
    -- sqlda_out SQLDA specified).
    --
    -- Note that the PREPARE statement could have prepared the statement without
    -- writing to an SQLDA.  Instead, a separate DESCRIBE...SELECT LIST statement
    -- would have written information about any select list items to an SQLDA.
    EXEC SQL PREPARE :cur_procid SELECT LIST INTO :sqlda_out FROM :cur_stmt;
    case sqlca.sqlcode is
        when sql_success => null;
        when others => raise syntax_error;
    end case;
    
    -- Use the DESCRIBE...MARKERS statement to write information about any
    -- parameter markers in the dynamic statement to sqlda_in.  This statement
    -- writes information to an SQLDA (specifically, the sqlda_in SQLDA
    -- specified) about the number and data type of any parameter markers in
    -- the prepared dynamic statement.  Note that SELECT statements may also
    -- have parameter markers.
    
    EXEC SQL DESCRIBE :cur_procid MARKERS INTO sqlda_in;
    case sqlca.sqlcode is
        when sql_success => null;
        when others => raise syntax_error;
    end case;
    
    -- If the operation is "Read," create a unique name for the cursor name
    -- so that the program can pass the cursor name to the dynamic DECLARE
    -- CURSOR statement.
    
    if cur_op(1) = 'R' then
        cur_cursor(1) := 'C';
        cur_cursor(2..name_strlng) := cur_name(1..name_strlng - 1);
    
    -- Declare the dynamic cursor.
    
        EXEC SQL DECLARE :cur_cursor CURSOR FOR :cur_procid;
        case sqlca.sqlcode is
            when sql_success => null;
            when others => raise syntax_error;
        end case;
    end if;
    
    number_of_procs := number_of_procs + 1;
    sqlda_in_array(number_of_procs) := sqlda_in;
    sqlda_out_array(number_of_procs) := sqlda_out;
    procedure_names(number_of_procs) := cur_name;
    procedure_ids(number_of_procs) := cur_procid;
    if cur_op(1) = 'R' then
        cursor_names(number_of_procs) := cur_cursor;
    end if;
    
    exception
        when syntax_error =>
            sql_get_error_text(get_error_buffer,get_error_length);
            put_line(get_error_buffer(1..integer(get_error_length)));
            put("Press RETURN to continue. ");
            get_line(terminal,release_screen,last);
            new_line;
    end PREPARE_SQL;
    .
    .
    .
    begin  -- procedure body DISPLAY_DATA
    
    -- Before displaying any data, allocate buffers to hold the data
    -- returned by SQL.
    --
        allocate_buffers;
    
    -- Allocate and assign SQLDAs for the requested SQL procedure.
    --
    sqlda_in := new sqlda_record;
    sqlda_in := sqlda_in_array(stmt_index);
    sqlda_out := new sqlda_record;
    sqlda_out := sqlda_out_array(stmt_index);
    cur_cursor := cursor_names(stmt_index);
    -- Open the previously declared cursor.  The statement specifies
    -- an SQLDA (specifically, sqlda_in) as the source of addresses for any
    -- parameter markers in the cursor's SELECT statement.
    --
    EXEC SQL OPEN :cur_cursor USING DESCRIPTOR sqlda_in;
    case sqlca.sqlcode is
        when sql_success => null;
        when others => raise unexpected_error;
    end case;
    
    -- Fetch the first row from the result table.  This statement fetches a
    -- row from the opened cursor and writes it to the addresses specified
    -- in an SQLDA (specifically, sqlda_out).
    --
    EXEC SQL FETCH :cur_cursor USING DESCRIPTOR sqlda_out;
    case sqlca.sqlcode is
    --  Check to see if the result table has any rows.
        when sql_success => null;
        when stream_eof =>
            put_line("No records found.");
            new_line;
        when others => raise unexpected_error;
    end case;
    
    -- Set up a loop to display the first row, then fetch and display second
    -- and subsequent rows.
    
        rowcount := 0;
        while sqlca.sqlcode = 0 loop
            rowcount := rowcount + 1;
    --      Execute the DISPLAY_ROW procedure.
            display_row;
    --      To only display 5 rows, exit the loop if the loop counter
    --      equals MAXROW (coded as 5 in this program).
            if rowcount = maxrows then exit; end if;
    --      Fetch another row, exit the loop if no more rows.
            EXEC SQL FETCH :cur_cursor USING DESCRIPTOR sqlda_out;
            case sqlca.sqlcode is
                when sql_success => null;
                when stream_eof => exit;
                when others => raise unexpected_error;
            end case;
        end loop;
    -- Close the cursor.
    EXEC SQL CLOSE :cur_cursor;
    case sqlca.sqlcode is
        when sql_success => null;
        when others => raise unexpected_error;
    end case;
    exception
        when unexpected_error =>
            sql_get_error_text(get_error_buffer,get_error_length);
            EXEC SQL ROLLBACK;
            put_line("This condition was not expected.");
            put_line(get_error_buffer(1..integer(get_error_length)));
            put("Press RETURN to continue. ");
            get_line(terminal,release_screen,last);
    
    -- Stop and let the user look before returning.
        skip;
        put_line("Press RETURN to proceed. ");
        get_line(terminal,release_screen,last);
    
    end DISPLAY_DATA;