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 |
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 |
例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;
次の例は、表カーソルおよび読取り専用スクロール可能リスト・カーソルを宣言し、リストのセグメント間を前後にスクロールすることによってリスト情報を取得しています。
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;
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
実行時にパラメータで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文は、実行時にカーソル名と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;