Skip to Main Content

Java Database Connectivity (JDBC)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

Regression in ojdbc 23.2.0.0 when reading PL/SQL TABLE OF TABLE OF RECORD

Lukas EderNov 15 2023 — edited Nov 15 2023

On the server side, I'm using the latest 23c free version from here: https://hub.docker.com/r/gvenzl/oracle-free

With this example package:

CREATE PACKAGE p AS 
  TYPE t IS RECORD (a NUMBER); 
  TYPE tt IS TABLE OF t; 
  TYPE ttt IS TABLE OF tt; 
  FUNCTION f RETURN ttt; 
END p; 

CREATE PACKAGE BODY p AS 
  FUNCTION f RETURN ttt IS 
  BEGIN 
    RETURN ttt(tt(t(1))); 
  END f; 
END p; 

It used to be possible using com.oracle.database.jdbc:ojdbc11:21.9.0.0 to read function results like this:

try (CallableStatement c = connection.prepareCall("{ ? = call test.p.f }")) { 
  c.registerOutParameter(1, OracleTypes.ARRAY, "TEST.P.TTT"); 
  c.executeUpdate(); 
  Array a1 = c.getArray(1); 
  Object[] o1 = (Object[]) a1.getArray(); 
  Array a2 = (Array) o1[0]; 
  Object[] o2 = (Object[]) a2.getArray(); 
  Struct a3 = (Struct) o2[0]; 
  Object[] o3 = a3.getAttributes(); 
  System.out.println(Arrays.asList(o3)); 
}

This would then print:

[1]

But with ojdbc versions 23.2.0.0 or 23.3.0.23.09, this no longer works. The following exception is thrown instead, from within the driver:

Exception in thread "main" java.sql.SQLException: ORA-01403: no data found
ORA-06512: at line 1

    at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:702)
    at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:608)
    at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1335)
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:1041)
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:443)
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:533)
    at oracle.jdbc.driver.T4CCallableStatement.doOall8(T4CCallableStatement.java:216)
    at oracle.jdbc.driver.T4CCallableStatement.executeForRows(T4CCallableStatement.java:1346)
    at oracle.jdbc.driver.OracleStatement.executeSQLStatement(OracleStatement.java:1877)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1520)
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3751)
    at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:4180)
    at oracle.jdbc.driver.OracleCallableStatement.execute(OracleCallableStatement.java:4203)
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1015)
    at oracle.jdbc.oracore.OracleTypeCOLLECTION.initCollElemTypeName(OracleTypeCOLLECTION.java:1003)
    at oracle.jdbc.oracore.OracleTypeCOLLECTION.getAttributeType(OracleTypeCOLLECTION.java:1067)
    at oracle.jdbc.oracore.OracleTypeADT.createStructDescriptor(OracleTypeADT.java:3288)
    at oracle.jdbc.oracore.OracleTypeADT.unpickle81(OracleTypeADT.java:2244)
    at oracle.jdbc.oracore.OracleTypeUPT.unpickle81UPT(OracleTypeUPT.java:295)
    at oracle.jdbc.oracore.OracleTypeUPT.unpickle81rec(OracleTypeUPT.java:252)
    at oracle.jdbc.oracore.OracleTypeCOLLECTION.unpickle81ImgBodyElements(OracleTypeCOLLECTION.java:643)
    at oracle.jdbc.oracore.OracleTypeCOLLECTION.unpickle81ImgBody(OracleTypeCOLLECTION.java:562)
    at oracle.jdbc.oracore.OracleTypeCOLLECTION.unpickle81(OracleTypeCOLLECTION.java:378)
    at oracle.jdbc.oracore.OracleTypeCOLLECTION.unlinearizeInternal(OracleTypeCOLLECTION.java:244)
    at oracle.jdbc.oracore.OracleTypeCOLLECTION.unlinearize(OracleTypeCOLLECTION.java:223)
    at oracle.sql.ArrayDescriptor.toJavaArray(ArrayDescriptor.java:932)
    at oracle.jdbc.driver.OracleArray.getArray(OracleArray.java:246)
    at oracle.sql.ARRAY.getArray(ARRAY.java:363)
    at org.jooq.testscripts.JDBC.main(JDBC.java:47)
Caused by: Error : 1403, Position : 0, SQL = DECLARE   the_owner VARCHAR2(100);   the_type  VARCHAR2(100); BEGIN  SELECT TABLE_NAME, TABLE_OWNER INTO THE_TYPE, THE_OWNER  FROM ALL_SYNONYMS  WHERE TABLE_NAME IN (SELECT TYPE_NAME FROM ALL_TYPES)  START WITH SYNONYM_NAME = :1 AND OWNER = 'PUBLIC'  CONNECT BY NOCYCLE PRIOR TABLE_NAME = SYNONYM_NAME AND TABLE_OWNER = OWNER; OPEN :2 FOR SELECT ELEM_TYPE_NAME, ELEM_TYPE_OWNER FROM ALL_COLL_TYPES  WHERE TYPE_NAME = THE_TYPE and OWNER = THE_OWNER; END;, Original SQL = DECLARE   the_owner VARCHAR2(100);   the_type  VARCHAR2(100); BEGIN  SELECT TABLE_NAME, TABLE_OWNER INTO THE_TYPE, THE_OWNER  FROM ALL_SYNONYMS  WHERE TABLE_NAME IN (SELECT TYPE_NAME FROM ALL_TYPES)  START WITH SYNONYM_NAME = :1 AND OWNER = 'PUBLIC'  CONNECT BY NOCYCLE PRIOR TABLE_NAME = SYNONYM_NAME AND TABLE_OWNER = OWNER; OPEN :2 FOR SELECT ELEM_TYPE_NAME, ELEM_TYPE_OWNER FROM ALL_COLL_TYPES  WHERE TYPE_NAME = THE_TYPE and OWNER = THE_OWNER; END;, Error Message = ORA-01403: no data found
ORA-06512: at line 1

    at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:710)
    ... 28 more

Here's a formatted version of that PL/SQL block:

DECLARE 
  the_owner VARCHAR2(100); 
  the_type VARCHAR2(100); 
BEGIN 
  SELECT TABLE_NAME, TABLE_OWNER 
  INTO THE_TYPE, THE_OWNER 
  FROM ALL_SYNONYMS 
  WHERE TABLE_NAME IN ( 
    SELECT TYPE_NAME FROM ALL_TYPES 
  ) 
  START WITH SYNONYM_NAME = :1 
  AND OWNER = 'PUBLIC' 
  CONNECT BY NOCYCLE 
  PRIOR TABLE_NAME = SYNONYM_NAME 
  AND TABLE_OWNER = OWNER; 

  OPEN :2 FOR 
  SELECT ELEM_TYPE_NAME, ELEM_TYPE_OWNER 
  FROM ALL_COLL_TYPES 
  WHERE TYPE_NAME = THE_TYPE 
  and OWNER = THE_OWNER; 
END;

With a debugger, I found that the bind variable :1 has value P.TT (weird), so I reverse engineered the following hack to make the query above no longer fail:

CREATE TYPE "PUBLIC.X" AS OBJECT(o INT);     -- To satisfy the IN (SELECT TYPE_NAME ..) subquery
CREATE PUBLIC SYNONYM "P.TT" FOR "PUBLIC.X"; -- To satisfy the recursion

With these dummy objects in place, the latest ojdbc versions no longer fail, and the above Java program again prints:

[1]
This post has been answered by C S Krishna Mahidhara-Oracle on Nov 21 2023
Jump to Answer

Comments

Post Details

Added on Nov 15 2023
2 comments
667 views