I'm trying to get the Oracle COLLECT() aggregation function to work from JDBC.
My schema looks like this
CREATE TABLE t_warehouse (
id NUMBER(5) NOT NULL PRIMARY KEY,
warehouse_name VARCHAR2(64) NOT NULL
);
CREATE TABLE t_warehouse_detail (
id NUMBER(5) NOT NULL PRIMARY KEY,
warehouse_id NUMBER(5) NOT NULL,
detail_value VARCHAR2(128) NOT NULL,
CONSTRAINT fk_warehouse
FOREIGN KEY (warehouse_id)
REFERENCES t_warehouse(id)
);
INSERT INTO t_warehouse (id, warehouse_name)
VALUES (1, 'warehouse 1');
INSERT INTO t_warehouse_detail (id, warehouse_id, detail_value)
VALUES (1, 1, 'detail 1');
INSERT INTO t_warehouse_detail (id, warehouse_id, detail_value)
VALUES (2, 1, 'detail 2');
CREATE OR REPLACE TYPE warehouse_detail_t AS TABLE OF VARCHAR2(128);
my query looks like this
SELECT wh.id, CAST(COLLECT(detail_value) AS warehouse_detail_t) AS "Details"
FROM t_warehouse wh
JOIN t_warehouse_detail whd ON (wh.id = whd.warehouse_id)
GROUP BY wh.id;
my code looks like this
String url = ...;
String username = ...;
String password = ...;
OracleDataSource ds = new oracle.jdbc.pool.OracleDataSource();
ds.setURL(url);
ds.setUser(username);
ds.setPassword(password);
try (Connection connection = ds.getConnection()) {
connection.setTypeMap(Collections.singletonMap("SCHEMA_NAME.WAREHOUSE_DETAIL_T", DetailValues.class));
try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT wh.id, CAST(COLLECT(detail_value) AS warehouse_detail_t) AS \"Details\""
+ " FROM t_warehouse wh "
+ " JOIN t_warehouse_detail whd ON (wh.id = whd.warehouse_id) "
+ " GROUP BY wh.id");
ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
int id = resultSet.getInt("id");
Set<String> detailValues = Collections.emptySet();
}
}
and I have the following SQLData class
public static final class DetailValues implements SQLData {
private String typeName;
@Override
public String getSQLTypeName() throws SQLException {
return this.typeName;
}
@Override
public void readSQL(SQLInput stream, String typeName) throws SQLException {
this.typeName = typeName;
Array array = stream.readArray();
if (array != null) {
try {
} finally {
array.free();
}
}
System.out.println("readSQL");
}
@Override
public void writeSQL(SQLOutput stream) throws SQLException {
System.out.println("writeSQL");
}
}
and I get the following exception
java.sql.SQLException: Fail to construct descriptor: Unable to resolve type "SCHEMA_NAME.WAREHOUSE_DETAIL_T"
at oracle.sql.TypeDescriptor.getTypeDescriptor(TypeDescriptor.java:1002)
at oracle.jdbc.driver.NamedTypeAccessor.otypeFromName(NamedTypeAccessor.java:82)
at oracle.jdbc.driver.TypeAccessor.initMetadata(TypeAccessor.java:75)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:860)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:983)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1168)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3666)
at oracle.jdbc.driver.T4CPreparedStatement.executeInternal(T4CPreparedStatement.java:1426)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3713)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1167)
at com.acme.CollectTests.collect(CollectTests.java:48)
This is with ojdbc8-19.7.0.0 and Oracle 19.3.
The query also fails in Oracle SQL Developer with the same exception.
Update
FINEST output from the _g JAR is:
[oracle.jdbc.pool.OracleDataSource oracle.jdbc.pool.OracleDataSource ] Enter: void
[oracle.jdbc.pool.OracleDataSource setConnectionProperty ] 47542153 Enter: "oracle.jdbc.enableACSupport", "false"
[oracle.jdbc.pool.OracleDataSource setConnectionProperty ] 47542153 Return: void
[oracle.jdbc.pool.OracleDataSource setConnectionProperty ] 47542153 Exit: [0.370177 ms]
[oracle.jdbc.pool.OracleDataSource processFastConnectionFailoverSysProperty ] 47542153 Enter: void
[oracle.jdbc.pool.OracleDataSource processFastConnectionFailoverSysProperty ] 47542153 Return: void
[oracle.jdbc.pool.OracleDataSource processFastConnectionFailoverSysProperty ] 47542153 Exit: [0.133466 ms]
[oracle.jdbc.pool.OracleDataSource oracle.jdbc.pool.OracleDataSource ] Return: void
[oracle.jdbc.pool.OracleDataSource oracle.jdbc.pool.OracleDataSource ] Exit: [0.386721 ms]
[oracle.jdbc.pool.OracleDataSource setURL ] 47542153 Enter: "jdbc:oracle:thin:@localhost:1521/ORCLPDB1?oracle.net.disableOob=true"
[oracle.jdbc.pool.OracleDataSource setURL ] 47542153 Return: void
[oracle.jdbc.pool.OracleDataSource setURL ] 47542153 Exit: [0.13673 ms]
[oracle.jdbc.pool.OracleDataSource setUser ] 47542153 Enter: "schema_name"
[oracle.jdbc.pool.OracleDataSource setUser ] 47542153 Return: void
[oracle.jdbc.pool.OracleDataSource setUser ] 47542153 Exit: [0.121062 ms]
[oracle.jdbc.pool.OracleDataSource setPassword ] 47542153 Enter: "*****"
[oracle.jdbc.pool.OracleDataSource setPassword ] 47542153 Enter: oracle.jdbc.internal.OpaqueString@67d0ff08
[oracle.jdbc.pool.OracleDataSource setPassword ] 47542153 Return: void
[oracle.jdbc.pool.OracleDataSource setPassword ] 47542153 Exit: [0.128787 ms]
[oracle.jdbc.pool.OracleDataSource setPassword ] 47542153 Return: void
[oracle.jdbc.pool.OracleDataSource setPassword ] 47542153 Exit: [0.379598 ms]
[oracle.jdbc.pool.OracleDataSource getConnection ] 47542153 Enter: void
[oracle.jdbc.pool.OracleDataSource getConnection ] 47542153 Enter: "schema_name", "*****"
[oracle.jdbc.pool.OracleDataSource getConnection ] OracleDataSource.getConnection(user, passwd): URL isjdbc:oracle:thin:@localhost:1521/ORCLPDB1?oracle.net.disableOob=true
[oracle.jdbc.pool.OracleDataSource createConnectionBuilder ] 47542153 Enter: void
[oracle.jdbc.pool.OracleDataSource createConnectionBuilder ] 47542153 Return: oracle.jdbc.pool.OracleDataSource$1@5e316c74
[oracle.jdbc.pool.OracleDataSource createConnectionBuilder ] 47542153 Exit: [2.499096 ms]
[oracle.jdbc.pool.OracleDataSource getConnection ] 47542153 Enter: oracle.jdbc.pool.OracleDataSource$1@5e316c74
[oracle.jdbc.pool.OracleDataSource makeURL ] 47542153 Enter: void
[oracle.jdbc.pool.OracleDataSource makeURL ] 47542153 Return: void
[oracle.jdbc.pool.OracleDataSource makeURL ] 47542153 Exit: [0.10966 ms]
[oracle.jdbc.pool.OracleDataSource getPhysicalConnection ] 47542153 Enter: {password=redacted, oracle.jdbc.enableACSupport=false, connection_url=jdbc:oracle:thin:@localhost:1521/ORCLPDB1?oracle.net.disableOob=true, user=schema_name}, null
[oracle.jdbc.pool.OracleDataSource getPhysicalConnection ] OracleDataSource.getPhysicalConnection(prop): URL isjdbc:oracle:thin:@localhost:1521/ORCLPDB1?oracle.net.disableOob=true, user: schema_name, password: *****
[oracle.jdbc.driver.HAManager oracle.jdbc.driver.HAManager ] Enter: void
[oracle.jdbc.driver.HAManager oracle.jdbc.driver.HAManager ] Return: void
[oracle.jdbc.driver.HAManager oracle.jdbc.driver.HAManager ] Exit: [0.675662 ms]
[oracle.jdbc.driver.NoSupportHAManager oracle.jdbc.driver.NoSupportHAManager] Enter: void
[oracle.jdbc.driver.NoSupportHAManager oracle.jdbc.driver.NoSupportHAManager] Return: void
[oracle.jdbc.driver.NoSupportHAManager oracle.jdbc.driver.NoSupportHAManager] Exit: [0.101079 ms]
[oracle.jdbc.driver.NoSupportHAManager getInstance ] Enter: void
[oracle.jdbc.driver.NoSupportHAManager getInstance ] Return: oracle.jdbc.driver.NoSupportHAManager@bccb269
[oracle.jdbc.driver.NoSupportHAManager getInstance ] Exit: [0.104732 ms]
[oracle.jdbc.driver.HAManager enableHAIfNecessary ] Enter: "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCLPDB1)))", oracle.jdbc.driver.T4CConnection@3c0be339
[oracle.jdbc.driver.HAManager enableHAIfNecessary ] ========= simplefan.jar or ons.jar is not on the classpath, HA is disabled, java.lang.ClassNotFoundException: oracle.simplefan.FanManager
[oracle.jdbc.driver.HAManager enableHAIfNecessary ] ========= HA is explicitly disabled
[oracle.jdbc.driver.HAManager enableHAIfNecessary ] Return: void
[oracle.jdbc.driver.HAManager enableHAIfNecessary ] Exit: [0.660915 ms]
[oracle.jdbc.pool.OracleDataSource getPhysicalConnection ] 47542153 Return: oracle.jdbc.driver.T4CConnection@3c0be339
[oracle.jdbc.pool.OracleDataSource getPhysicalConnection ] 47542153 Exit: [0.946502 ms]
[oracle.jdbc.pool.OracleDataSource getConnection ] 47542153 Return: oracle.jdbc.driver.T4CConnection@3c0be339
[oracle.jdbc.pool.OracleDataSource getConnection ] 47542153 Exit: [1.244383 ms]
[oracle.jdbc.pool.OracleDataSource getConnection ] 47542153 Return: oracle.jdbc.driver.T4CConnection@3c0be339
[oracle.jdbc.pool.OracleDataSource getConnection ] 47542153 Exit: [1.471857 ms]
[oracle.jdbc.pool.OracleDataSource getConnection ] 47542153 Return: oracle.jdbc.driver.T4CConnection@3c0be339
[oracle.jdbc.pool.OracleDataSource getConnection ] 47542153 Exit: [1.732571 ms]
[oracle.jdbc.driver.NoSupportHAManager dropConnection ] BCCB269 Enter: oracle.jdbc.driver.T4CConnection@3c0be339
[oracle.jdbc.driver.NoSupportHAManager dropConnection ] NoSupportHAManager.dropConnection()
[oracle.jdbc.driver.NoSupportHAManager dropConnection ] BCCB269 Return: void
[oracle.jdbc.driver.NoSupportHAManager dropConnection ] BCCB269 Exit: [0.180062 ms]
Exception in thread "main" java.sql.SQLException: Fail to construct descriptor: Unable to resolve type "SCHEMA_NAME.WAREHOUSE_DETAIL_T"
at oracle.sql.TypeDescriptor.getTypeDescriptor(TypeDescriptor.java:998)
at oracle.jdbc.driver.NamedTypeAccessor.otypeFromName(NamedTypeAccessor.java:78)
at oracle.jdbc.driver.TypeAccessor.initMetadata(TypeAccessor.java:71)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:856)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:979)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1164)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3662)
at oracle.jdbc.driver.T4CPreparedStatement.executeInternal(T4CPreparedStatement.java:1422)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3709)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1163)