Rechercher sur arkzoyd.com

14 août 2011

REF CURSOR gets OUT ?

Après avoir détricoté des erreurs ORA-00604 et ORA-01001 qui apparaissaient en manipulant des REF CURSOR comme paramètres depuis des clients ODP.NET et Java, je suis tombé sur une section de la documentation assez étonnante... Celle-ci suggère que vous ne devez pas utiliser de paramètre OUT de type REF CURSOR ; mais plutôt IN OUT. Voici ce que vous pouvez lire dans le manuel de référence PL/SQL d'Oracle 11.2, ce qui suit :
When declaring a cursor variable as the formal parameter of a subprogram:
  • If the subprogram opens or assigns a value to the cursor variable, then the parameter mode must be IN OUT.
  • If the subprogram only fetches from, or closes, the cursor variable, then the parameter mode can be either IN or IN OUT.
Il n'y a donc pas de cas pour lesquels utiliser les REF CURSOR comme paramètres OUT, et... Il se trouve que lorsque vous le faites, comme dans le programme ci-dessous, que vous manipulez le curseur en IN OUT dans la clause USING d'un EXECUTE IMMEDIATE et que passer ce curseur en OUT dans la procédure, cela fonctionne bien en PL/SQL mais pas à partir d'un programme y accédant via les OCI :
create or replace package arkz AS
  type TYPE_CURSOR is ref cursor;
  PROCEDURE test(pC OUT TYPE_CURSOR);
END arkz;
/

create or replace package body arkz as
procedure test(pC OUT type_cursor) is
  begin
     execute immediate 
         'begin open :rcCurseur for ''select 1 from dual''; end;' 
         USING IN OUT pC;
  END test;
END arkz;
/
Voilà comment se manifeste le problème :
java Test604
Exception in thread "main" java.sql.SQLException: ORA-00604: error occurred at recursive SQL level 1
ORA-01001: invalid cursor
    at oracle.jdbc.driver.T2CConnection.checkError(T2CConnection.java:759)
    at oracle.jdbc.driver.T2CConnection.checkError(T2CConnection.java:661)
    at oracle.jdbc.driver.T2CCallableStatement.executeForDescribe(T2CCallableStatement.java:544)
    at oracle.jdbc.driver.T2CCallableStatement.executeForRows(T2CCallableStatement.java:727)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1315)
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3576)
    at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:3677)
    at oracle.jdbc.driver.OracleCallableStatement.execute(OracleCallableStatement.java:4714)
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1374)
    at TestWHITE604.main(TestWHITE604.java:19)
Le contournement simple ; le correctif n'est pas disponible sur ma plateforme mais ça fonctionnait bien en 10.2. Si vous êtes curieux, celui-ci est décrit dans la note "When Trying to Return a Ref Cursor Results in Ora-01001 Or Ora-00604 After Upgrade to 11.1.0.7 / 11.2 [ID 1106914.1]".

Aucun commentaire: