datatype: PROCEDURE DBMS_SQL.COLUMN_VALUE_CHAR (c IN INTEGER, position IN INTEGER, value OUT CHAR, [, column_error OUT NUMBER] [, actual_length OUT INTEGER ]); PROCEDURE DBMS_SQL.COLUMN_VALUE_RAW (c IN INTEGER, position IN INTEGER, value OUT RAW, [, column_error OUT NUMBER] [, actual_length OUT INTEGER ]); PROCEDURE DBMS_SQL.COLUMN_VALUE_ROWID (c IN INTEGER, position IN INTEGER, value OUT ROWID, [, column_error OUT NUMBER] [, actual_length OUT INTEGER ]); You call COLUMN_VALUE after a row has been fetched to transfer the value from the SELECT list of the cursor into a local variable. For each call to the single−row COLUMN_VALUE, you should have made a call to DEFINE_COLUMN in order to define that column in the cursor. If you want to use the multiple−row version of COLUMN_VALUE, use the DEFINE_ARRAY procedure to define that column as capable of holding an array of values. The following procedure displays employees by defining a cursor with two columns and, after fetching a row, calls COLUMN_VALUE to retrieve both column values: /* Filename on companion disk: showemps.sp */ CREATE OR REPLACE PROCEDURE showemps (where_in IN VARCHAR2 := NULL) IS cur INTEGER := DBMS_SQL.OPEN_CURSOR; rec emp%ROWTYPE; fdbk INTEGER; BEGIN DBMS_SQL.PARSE (cur, 'SELECT empno, ename FROM emp ' || ' WHERE ' || NVL (where_in, '1=1'), DBMS_SQL.NATIVE); DBMS_SQL.DEFINE_COLUMN (cur, 1, rec.empno); DBMS_SQL.DEFINE_COLUMN (cur, 2, rec.ename, 30); fdbk := DBMS_SQL.EXECUTE (cur); LOOP /* Fetch next row. Exit when done. */ EXIT WHEN DBMS_SQL.FETCH_ROWS (cur) = 0; DBMS_SQL.COLUMN_VALUE (cur, 1, rec.empno); DBMS_SQL.COLUMN_VALUE (cur, 2, rec.ename); DBMS_OUTPUT.PUT_LINE (TO_CHAR (rec.empno) || '=' || rec.ename); END LOOP; DBMS_SQL.CLOSE_CURSOR (cur); END; / This next PL/SQL8 block fetches the hiredate and employee ID for all rows in the emp table and deposits values into two separate PL/SQL tables. Notice that since I know there are just 14 rows in the emp table, I need only one call to the EXECUTE_AND_FETCH function to fetch all rows. [Appendix A] What's on the Companion Disk? 2.3.8 Retrieving Values 71 /* Filename on companion disk: arrayemp.sp */ CREATE OR REPLACE PROCEDURE showall IS cur INTEGER := DBMS_SQL.OPEN_CURSOR; fdbk INTEGER; empno_tab DBMS_SQL.NUMBER_TABLE; hiredate_tab DBMS_SQL.DATE_TABLE; BEGIN DBMS_SQL.PARSE (cur, 'SELECT empno, hiredate FROM emp', DBMS_SQL.NATIVE); /* Allow fetching of up to 100 rows. */ DBMS_SQL.DEFINE_ARRAY (cur, 1, empno_tab, 100, 1); DBMS_SQL.DEFINE_ARRAY (cur, 2, hiredate_tab, 100, 1); fdbk := DBMS_SQL.EXECUTE_AND_FETCH (cur); /* This will show total numbers of rows fetched. */ DBMS_OUTPUT.PUT_LINE (fdbk); /* Get values for all rows in one call. */ DBMS_SQL.COLUMN_VALUE (cur, 1, empno_tab); DBMS_SQL.COLUMN_VALUE (cur, 2, hiredate_tab); FOR rowind IN empno_tab.FIRST empno_tab.LAST LOOP DBMS_OUTPUT.PUT_LINE (empno_tab(rowind)); DBMS_OUTPUT.PUT_LINE (hiredate_tab(rowind)); END LOOP; DBMS_SQL.CLOSE_CURSOR (cur); END; / The Section 2.5, "DBMS_SQL Examples"" section provides other examples of array processing in DBMS_SQL. 2.3.8.2 The DBMS_SQL.COLUMN_VALUE_LONG procedure DBMS_SQL provides a separate procedure, COLUMN_VALUE_LONG, to allow you to retrieve LONG values from a dynamic query. The header for this program is as follows: PROCEDURE DBMS_SQL.COLUMN_VALUE_LONG (c IN INTEGER ,position IN INTEGER ,length IN INTEGER ,offset IN INTEGER ,value OUT VARCHAR2 ,value_length OUT INTEGER); The COLUMN_VALUE_LONG parameters are summarized in the following table. Parameter Description c Pointer to the cursor. position Relative position of the column in the select list. length The length in bytes of the portion of the LONG value to be retrieved. offset The byte position in the LONG column at which the retrieval is to start. value The variable that will receive part or all of the LONG column value. [Appendix A] What's on the Companion Disk? 2.3.8 Retrieving Values 72 value_length The actual length of the retrieved value. The COLUMN_VALUE_LONG procedure offers just about the only way to obtain a LONG value from the database and move it into PL/SQL data structures in your program. You cannot rely on a static SELECT to do this. Instead, use DBMS_SQL and both the DEFINE_COLUMN_LONG and COLUMN_VALUE_LONG procedures. The following example demonstrates the technique, and, in the process, offers a generic procedure called dump_long that you can use to dump the contents of a long column in your table into a local PL/SQL table. The dump_long procedure accepts a table name, column name, and optional WHERE clause. It returns a PL/SQL table with the LONG value broken up into 256−byte chunks. /* Filename on companion disk: dumplong.sp */ CREATE OR REPLACE PROCEDURE dump_long ( tab IN VARCHAR2, col IN VARCHAR2, whr IN VARCHAR2 := NULL, pieces IN OUT DBMS_SQL.VARCHAR2S) /* Requires Oracle 7.3 or above */ IS cur PLS_INTEGER := DBMS_SQL.OPEN_CURSOR; fdbk PLS_INTEGER; TYPE long_rectype IS RECORD ( piece_len PLS_INTEGER, pos_in_long PLS_INTEGER, one_piece VARCHAR2(256), one_piece_len PLS_INTEGER ); rec long_rectype; BEGIN if whr is NULL */ DBMS_SQL.PARSE ( cur, 'SELECT ' || col || ' FROM ' || tab || ' WHERE ' || NVL (whr, '1 = 1'), DBMS_SQL.NATIVE); /* Define the long column and then execute and fetch */ DBMS_SQL.DEFINE_COLUMN_LONG (cur, 1); fdbk := DBMS_SQL.EXECUTE (cur); fdbk := DBMS_SQL.FETCH_ROWS (cur); /* If a row was fetched, loop through the long value until || all pieces are retrieved. */ IF fdbk > 0 THEN rec.piece_len := 256; rec.pos_in_long := 0; LOOP DBMS_SQL.COLUMN_VALUE_LONG ( cur, 1, rec.piece_len, rec.pos_in_long, rec.one_piece, rec.one_piece_len); EXIT WHEN rec.one_piece_len = 0; /* Always put the new piece in the next available row */ pieces (NVL (pieces.LAST, 0) + 1) := rec.one_piece; rec.pos_in_long := rec.pos_in_long + rec.one_piece_len; [Appendix A] What's on the Companion Disk? 2.3.8 Retrieving Values 73 END LOOP; END IF; DBMS_SQL.CLOSE_CURSOR (cur); END; / To test this procedure, I created a table with a LONG column as follows (the table creation, INSERT, and test script may all be found in dumplong.tst): DROP TABLE nextbook; CREATE TABLE nextbook (title VARCHAR2(100), text LONG); INSERT INTO nextbook VALUES ('Oracle PL/SQL Quick Reference', RPAD ('INSTR ', 256, 'blah1 ') || RPAD ('SUBSTR ', 256, 'blah2 ') || RPAD ('TO_DATE ', 256, 'blah3 ') || RPAD ('TO_CHAR ', 256, 'blah4 ') || RPAD ('LOOP ', 256, 'blah5 ') || RPAD ('IF ', 256, 'blah6 ') || RPAD ('CURSOR ', 256, 'blah7 ') ); I then put together this short test script. It extracts the single value from the table. (I pass a NULL WHERE clause, so it simply returns the first −− and only −− row fetched.) It then uses a numeric FOR loop to scan through the returned table to display the results. DECLARE mytab DBMS_SQL.VARCHAR2S; BEGIN dump_long ('nextbook', 'text', NULL, mytab); FOR longind IN 1 mytab.COUNT LOOP DBMS_OUTPUT.PUT_LINE (SUBSTR (mytab(longind), 1, 60)); END LOOP; END; / Here is the output displayed in my SQL*Plus window: INSTR blah1 blah1 blah1 blah1 blah1 blah1 blah1 blah1 blah1 SUBSTR blah2 blah2 blah2 blah2 blah2 blah2 blah2 blah2 blah2 TO_DATE blah3 blah3 blah3 blah3 blah3 blah3 blah3 blah3 blah TO_CHAR blah4 blah4 blah4 blah4 blah4 blah4 blah4 blah4 blah LOOP blah5 blah5 blah5 blah5 blah5 blah5 blah5 blah5 blah5 b IF blah6 blah6 blah6 blah6 blah6 blah6 blah6 blah6 blah6 bla CURSOR blah7 blah7 blah7 blah7 blah7 blah7 blah7 blah7 blah7 2.3.8.3 The DBMS_SQL.VARIABLE_VALUE procedure The VARIABLE_VALUE procedure retrieves the value of a named variable from the specified PL/SQL block. You can retrieve the value for a single variable, or, with PL/SQL8, you can retrieve the values for an array or PL/SQL table of values. This is the header for the single−row version of the procedure: PROCEDURE DBMS_SQL.VARIABLE_VALUE (c IN INTEGER ,name IN VARCHAR2 ,value OUT <datatype>); The VARIABLE_VALUE parameters are summarized in the following table. Parameter Description [Appendix A] What's on the Companion Disk? 2.3.8 Retrieving Values 74 c The handle or pointer to the cursor originally returned by a call to OPEN_CURSOR. name The name of the host variable included in the PL/SQL statement passed to PARSE. value The PL/SQL data structure (either a scalar variable, <datatype>, or a PL/SQL table, <table_type>) that receives the value from the cursor. <datatype> can be one of the following: NUMBER DATE MLSLABEL VARCHAR2 CHARACTER SET ANY_CS BLOB CLOB CHARACTER SET ANY_CS BFILE The header for the multiple−row version of VARIABLE_VALUE is the following: PROCEDURE DBMS_SQL.VARIABLE_VALUE (c IN INTEGER ,name IN VARCHAR2 ,value IN <table_type>); <table_type> can be one of the following: DBMS_SQL.NUMBER_TABLE DBMS_SQL.VARCHAR2_TABLE DBMS_SQL.DATE_TABLE DBMS_SQL.BLOB_TABLE DBMS_SQL.CLOB_TABLE DBMS_SQL.BFILE_TABLE The DBMS_SQL package also offers more specific variants of VARIABLE_VALUE for less common datatypes: PROCEDURE DBMS_SQL.VARIABLE_VALUE_CHAR (c IN INTEGER ,name IN VARCHAR2 ,value OUT CHAR CHARACTER SET ANY_CS); PROCEDURE DBMS_SQL.VARIABLE_VALUE_RAW (c IN INTEGER ,name IN VARCHAR2 ,value OUT RAW); PROCEDURE DBMS_SQL.VARIABLE_VALUE_ROWID (c IN INTEGER ,name IN VARCHAR2 ,value OUT ROWID); If you use the multiple−row version of VARIABLE_VALUE, you must have used the BIND_ARRAY procedure to define the bind variable in the PL/SQL block as an array of values. The following program allows you to provide the name of a stored procedure, a list of IN parameters, and a single OUT variable. It then uses dynamic PL/SQL to construct and execute that stored procedure, and finally retrieves the OUT value and returns it to the calling block. /* Filename on companion disk: runprog.sp */ CREATE OR REPLACE PROCEDURE runproc (proc IN VARCHAR2, arglist IN VARCHAR2, outval OUT NUMBER) IS cur INTEGER := DBMS_SQL.OPEN_CURSOR; [Appendix A] What's on the Companion Disk? 2.3.8 Retrieving Values 75 . VARCHAR2, col IN VARCHAR2, whr IN VARCHAR2 := NULL, pieces IN OUT DBMS_SQL.VARCHAR2S) /* Requires Oracle 7.3 or above */ IS cur PLS_INTEGER := DBMS_SQL.OPEN_CURSOR; fdbk PLS_INTEGER; TYPE long_rectype. nextbook; CREATE TABLE nextbook (title VARCHAR2(100), text LONG); INSERT INTO nextbook VALUES (&apos ;Oracle PL/SQL Quick Reference', RPAD ('INSTR ', 256, 'blah1 ') || RPAD