Here's the specification for this function: FUNCTION DBMS_SQL.LAST_ERROR RETURN INTEGER; You must call this function immediately after a call to EXECUTE or EXECUTE_AND_FETCH in order to
Trang 1fdbk INTEGER;
BEGIN
DBMS_SQL.PARSE
(cur, 'BEGIN ' || proc || '(' || arglist || ', :outparam); END;',
DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE (cur, 'outparam', 1);
fdbk := DBMS_SQL.EXECUTE (cur);
DBMS_SQL.VARIABLE_VALUE (cur, 'outparam', outval);
DBMS_SQL.CLOSE_CURSOR (cur);
END;
/
Now if I have the following procedure defined:
CREATE OR REPLACE PROCEDURE testdyn
(in1 IN NUMBER, in2 IN DATE, out1 OUT NUMBER)
IS
BEGIN
out1 := in1 + TO_NUMBER (TO_CHAR (in2, 'YYYY'));
END;
/
Then I can execute testdyn dynamically as follows:
DECLARE
n NUMBER;
BEGIN
runproc ('testdyn', '1, sysdate', n);
DBMS_OUTPUT.PUT_LINE (n);
END;
/
As you have likely discerned, this is not a very good general−purpose program It will work only with
procedures that have parameter lists in which the last argument is a numeric OUT parameter and that
argument must be the only OUT or IN OUT parameter in the list
There can be many complications when attempting to execute dynamic PL/SQL For suggestions on how best
to perform these tasks, see the "Tips on Using Dynamic SQL" section
2.3.9 Closing the Cursor
When you are done working with a cursor, you should close it and release associated memory
2.3.9.1 The DBMS_SQL.CLOSE_CURSOR procedure
The CLOSE_CURSOR procedure closes the specified cursor and sets the cursor handle to NULL It releases all memory associated with the cursor The specification for the procedure is,
PROCEDURE DBMS_SQL.CLOSE_CURSOR
(c IN OUT INTEGER);
where c is the handle or pointer to the cursor that was originally returned by a call to OPEN_CURSOR The parameter is IN OUT because once the cursor is closed, the pointer is set to NULL
If you try to close a cursor that is not open or that is not a valid cursor ID, this program will raise the
INVALID_CURSOR exception You might consider building a "wrapper" for CLOSE_CURSOR to avoid
Trang 2this exception.
CREATE OR REPLACE PROCEDURE closeif (c IN OUT INTEGER)
IS
BEGIN
IF DBMS_SQL.IS_OPEN (c)
THEN
DBMS_SQL.CLOSE_CURSOR (c);
END IF;
END;
/
2.3.10 Checking Cursor Status
Several functions allow you to check the status of a cursor
2.3.10.1 The DBMS_SQL.LAST_ERROR_POSITION function
The LAST_ERROR_POSITION function returns the byte offset in the SQL statement where the error
occurred The first character in the statement is at position 0 This function offers the same kind of feedback SQL*Plus offers you when it displays a syntax or value error while executing a SQL statement: it displays the problematic text with an asterisk (*) under the character that caused the problem Here's the specification for this function:
FUNCTION DBMS_SQL.LAST_ERROR RETURN INTEGER;
You must call this function immediately after a call to EXECUTE or EXECUTE_AND_FETCH in order to obtain meaningful results The following script demonstrates when and how this function's return value can come in handy:
/* Filename on companion disk: file errpos.sql */*
DECLARE
cur BINARY_INTEGER := DBMS_SQL.OPEN_CURSOR;
errpos BINARY_INTEGER;
fdbk BINARY_INTEGER;
BEGIN
DBMS_SQL.PARSE (cur, 'SELECT empno, ^a FROM emp', DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN (cur, 1, 1);
fdbk := DBMS_SQL.EXECUTE_AND_FETCH (cur, false);
DBMS_SQL.CLOSE_CURSOR (cur);
EXCEPTION
WHEN OTHERS
THEN
errpos := DBMS_SQL.LAST_ERROR_POSITION;
DBMS_OUTPUT.PUT_LINE (SQLERRM || ' at pos ' || errpos);
DBMS_SQL.CLOSE_CURSOR (cur);
END;
/
When I run this script in SQL*Plus, I get the following output:
SQL> @errpos
ORA−00936: missing expression at pos 14
One of the greatest frustrations with dynamic SQL is getting your string strung together improperly It is very easy to introduce syntax errors The DBMS_SQL.LAST_ERROR_POSITION function can be a big help in uncovering the source of your problem
NOTE: Some readers may be wondering why I declared a local variable called errpos and
assigned the value to it before calling DBMS_OUTPUT.PUT_LINE to examine the error
Trang 3The reason (discovered by Eric Givler, ace technical reviewer for this book) is that if I do not
grab the value from this function before calling SQLERRM, the function will return 0 instead
of the 14 for which I am looking
If my exception section looks, for example, as follows,
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE
(SQLERRM || ' at pos ' || DBMS_SQL.LAST_ERROR_POSITION);
DBMS_SQL.CLOSE_CURSOR (cur);
then the output from running the program will become:
SQL> @errpos
ORA−00936: missing expression at pos 0
Why does this happen? The SQLERRM function must be executing an implicit SQL statement (probably a query!) This action resets the values returned by this DBMS_SQL function, since it is tied to the underlying, generic implicit cursor attribute
2.3.10.2 The DBMS_SQL.LAST_ROW_COUNT function
The LAST_ROW_COUNT function returns the total number of rows fetched at that point This function corresponds to the %ROWCOUNT attribute of a normal, static cursor in PL/SQL Here's the specification for this function:
FUNCTION DBMS_SQL.LAST_ROW_COUNT RETURN INTEGER;
You must call this function immediately after a call to EXECUTE_AND_FETCH or FETCH_ROWS in order
to obtain meaningful results You will most likely use this function when fetching from within a loop:
CREATE OR REPLACE PROCEDURE show_n_emps (lim IN INTEGER)
IS
cur PLS_INTEGER := DBMS_SQL.OPEN_CURSOR;
fdbk PLS_INTEGER;
v_ename emp.ename%TYPE;
BEGIN
DBMS_SQL.PARSE (cur, 'SELECT ename FROM emp', DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN (cur, 1, v_ename, 100);
fdbk := DBMS_SQL.EXECUTE (cur);
LOOP
EXIT WHEN DBMS_SQL.FETCH_ROWS (cur) = 0;
IF DBMS_SQL.LAST_ROW_COUNT <= lim
THEN
DBMS_SQL.COLUMN_VALUE (cur, 1, v_ename);
DBMS_OUTPUT.PUT_LINE (v_ename);
ELSE
/* Hit maximum Display message and exit */
DBMS_OUTPUT.PUT_LINE
('Displayed ' || TO_CHAR (lim) || ' employees.');
EXIT;
END IF;
END LOOP;
DBMS_SQL.CLOSE_CURSOR (cur);
END;
/
Trang 42.3.10.3 The DBMS_SQL.LAST_ROW_ID function
The LAST_ROW_ID function returns the ROWID of the row fetched most recently The specification for this function is as follows:
FUNCTION DBMS_SQL.LAST_ROW_ID RETURN ROWID;
You must call this function immediately after a call to EXECUTE_AND_FETCH or FETCH_ROWS in order
to obtain meaningful results This function is useful mostly for debugging purposes and perhaps to log which records have been affected
2.3.10.4 The DBMS_SQL.LAST_SQL_FUNCTION_CODE function
The LAST_SQL_FUNCTION_CODE function returns the SQL function code for the SQL statement The specification for this function is as follows:
FUNCTION DBMS_SQL.LAST_SQL_FUNCTION_CODE RETURN INTEGER;
You must call this function immediately after a call to EXECUTE_AND_FETCH or EXECUTE in order to obtain meaningful results It will tell you which type of SQL statement was executed
The SQL function codes are listed in Table 2.3
Table 2.3: SQL Function Codes
Code SQL Function Code SQL Function Code SQL Function
COST
LOG
LOG
LOG
DATABASE
76 DROP SNAPSHOT
DATABASE
77 CREATE TYPE
SEGMENT
80 ALTER TYPE
13 CREATE SEQUENCE 47 ALTER ROLLBACK
SEGMENT
81 CREATE TYPE BODY
Trang 514 ALTER SEQUENCE 48 DROP ROLLBACK
SEGMENT
82 ALTER TYPE BODY
23 VALIDATE INDEX 57 CREATE CONTROL FILE 91 CREATE FUNCTION
BODY
BODY
BODY
32 ALTER SYSTEM SWITCH
LOG
2.3.11 Describing Cursor Columns
With PL/SQL8, you can now obtain information about the structure of the columns of your dynamic cursor
2.3.11.1 The DBMS_SQL.DESCRIBE_COLUMNS procedure
The DESCRIBE_COLUMNS procedure obtains information about your dynamic cursor Here is the header:
PROCEDURE DBMS_SQL.DESCRIBE_COLUMNS
(c IN INTEGER
,col_cnt OUT INTEGER
,desc_t OUT DBMS_SQL.DESC_TAB);
The parameters for the DESCRIBE_COLUMNS procedure are summarized in the following table
Parameter Description
c The pointer to the cursor
col_cnt The number of columns in the cursor, which equals the number of rows defined in the PL/SQL
table