2

参照カーソルを返す関数を呼び出しておりXMLType.createxml、結果を XML に変換するために使用しています。

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

ただし、これには望ましくない副作用があることがわかりました。XMLType のデータを取得するために使用されるカーソルが閉じられていないようです。この手法を使用して関数を何度も呼び出した後、常に次のエラーが発生します。

ORA-01000: maximum open cursors exceeded

カーソルへのハンドルがないため、手動で閉じることができません。また、プールされた接続を使用しているため、これらのカーソルが自動的に解放される接続リセットはありません。これについて何ができるでしょうか?


これが私のOracleバージョンです(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

(興味のある方は、 XMLType に関する以前の質問へのリンクを参照してください。)

4

1 に答える 1

5

バグがあるようです。Oracle サポートにサービス リクエストを開いてください。9i および 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 は、上記の関数でコールされた場合、カーソルを正しくクローズしませんが、静的 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

ラッパー関数を使用して、ORA-01000 が発生しないようにする必要があります (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
于 2013-03-18T14:55:07.430 に答える