Question

I am calling a function that returns a reference cursor, and I am using XMLType.createxml to convert the results to XML, e.g.

select XMLType.createxml(package_name.storedProcName('PARAM1', 'PARAM2', 'PARAM3')) as sresult from dual;

However, I have found this to have an unwelcome side-effect. It seems that the cursor used to retrieve the data for the XMLType is never closed. After calling the function many times using this technique, I always run into the following error:

ORA-01000: maximum open cursors exceeded

I do not have a handle to the cursor, thus I cannot manually close it. Also, we are using pooled connections, so there is no connection reset where these cursors can be automatically released. What can be done about this?


Here is my Oracle version (as returned from v$version):

Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi
PL/SQL Release 10.2.0.5.0 - Production                          
CORE    10.2.0.5.0  Production                                      
TNS for HPUX: Version 10.2.0.5.0 - Production                   
NLSRTL Version 10.2.0.5.0 - Production

(For those interested, here is a link to my previous question related to XMLType.)

Was it helpful?

Solution

There seems to be a bug, you should open a service request to Oracle support. I'll post a test case that reproduces your finding in 9i and 11.2.0.3:

SQL> SHOW parameter open_cursors

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
open_cursors                         integer     600

SQL> CREATE OR REPLACE FUNCTION ret_cursor RETURN SYS_REFCURSOR IS
  2     l SYS_REFCURSOR;
  3  BEGIN
  4     OPEN l FOR
  5        SELECT * FROM dual;
  6     RETURN l;
  7  END;
  8  /

Function created

XMLType will not close cursors correctly when called with the above function, whereas it works well with static SQL:

SQL> /* Works as expected with static cursor */
  2  DECLARE
  3     l XMLTYPE;
  4  BEGIN
  5     FOR i IN 1 .. 1e4 LOOP
  6        SELECT xmltype.createXML(CURSOR(SELECT * FROM DUAL)) INTO l FROM dual;
  7     END LOOP;
  8  END;
  9  /      

PL/SQL procedure successfully completed

SQL> /* Fails with call to dynamic cursor */
SQL> DECLARE
  2     l XMLTYPE;
  3  BEGIN
  4     FOR i IN 1 .. 1e4 LOOP
  5        SELECT xmltype.createXML(ret_cursor) INTO l FROM dual;
  6     END LOOP;
  7  END;
  8  /
DECLARE
*
ERROR at line 1:
ORA-01000: maximum open cursors exceeded
ORA-06512: at "APPS.RET_CURSOR", line 4
ORA-06512: at line 5

You should be able to use a wrapper function to prevent the ORA-01000 from happening (tested on 9iR2, 11gR2):

SQL> CREATE OR REPLACE FUNCTION wrap_xml(p SYS_REFCURSOR) RETURN XMLTYPE IS
  2     l XMLTYPE;
  3  BEGIN
  4     l := xmltype.CreateXML(p);
  5     IF p%ISOPEN THEN
  6        CLOSE p;
  7     END IF;
  8     RETURN l;
  9  END;
 10  /

Function created

SQL> DECLARE
  2     l XMLTYPE;
  3  BEGIN
  4     FOR i IN 1 .. 1e4 LOOP
  5        l := wrap_xml(ret_cursor); -- a SELECT FROM dual will still fail here
  6                                   -- on 9i but not on 11g 
  7     END LOOP;
  8  END;
  9  /

PL/SQL procedure successfully completed
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top