[ 
https://issues.apache.org/jira/browse/CALCITE-7848?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18126196#comment-18126196
 ] 

Vladimir Sitnikov commented on CALCITE-7848:
--------------------------------------------

The same metadata defect also breaks the remote driver 
(CalciteRemoteDriverTest.getRemoteConnection). There, a query that returns a 
collection of a numeric type does not execute at all, even select array[1, 2]:

{noformat}
java.sql.SQLException: Error while executing SQL "select array[1, 2]": null
Caused by: java.lang.UnsupportedOperationException
    at 
org.apache.calcite.avatica.ColumnMetaData$AvaticaType.setRep(ColumnMetaData.java:551)
    at org.apache.calcite.avatica.ColumnMetaData.setRep(ColumnMetaData.java:317)
    at 
org.apache.calcite.avatica.remote.AbstractService.finagle(AbstractService.java:78)
{noformat}

AbstractService.finagle rewrites a PRIMITIVE_INT rep to NUMBER, and the 
column's ArrayType does not allow it. With the fix in 
https://github.com/apache/calcite/pull/5322 the column carries Rep.ARRAY, and 
the query returns [1, 2]. CalciteRemoteDriverTest.testRemoteIntegerCollections 
covers it.

Still failing through the remote driver after the fix, and not addressed in 
this PR: getString on multiset[multiset[1, 2]] throws ClassCastException 
(java.util.ArrayList cannot be cast to java.lang.Integer).

> Array.getArray() throws ClassCastException for an ARRAY or MULTISET of 
> INTEGER ARRAYs or MULTISETs
> --------------------------------------------------------------------------------------------------
>
>                 Key: CALCITE-7848
>                 URL: https://issues.apache.org/jira/browse/CALCITE-7848
>             Project: Calcite
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 1.42.0
>            Reporter: Vladimir Sitnikov
>            Priority: Major
>              Labels: pull-request-available
>
> Reading a nested collection through the standard JDBC path fails when the 
> inner collection holds a primitive type such as INTEGER. ResultSet.getObject 
> returns a java.sql.Array, and calling getArray() on it throws 
> ClassCastException. getString on the same column returns the correct value, 
> and the same query with VARCHAR elements works.
> Reproduced with calcite-core 1.42.0 (avatica-core 1.28.0, JDK 21.0.9) and on 
> main at 843f468405 (Avatica 1.29.0):
> {code:java}
> try (Connection c = DriverManager.getConnection("jdbc:calcite:");
>      ResultSet rs = c.createStatement()
>          .executeQuery("select array[array[1, 2], array[3, 4]]")) {
>   rs.next();
>   System.out.println(rs.getString(1));
>   Array array = (Array) rs.getObject(1);
>   System.out.println(Arrays.toString((Object[]) array.getArray()));
> }
> {code}
> Output for three queries:
> {noformat}
> select array[array[1, 2], array[3, 4]]
>   getString:           [[1, 2], [3, 4]]
>   getObject.getArray:  java.lang.ClassCastException: class 
> org.apache.calcite.avatica.util.ArrayImpl cannot be cast to class 
> java.lang.Integer (org.apache.calcite.avatica.util.ArrayImpl is in unnamed 
> module of loader 'app'; java.lang.Integer is in module java.base of loader 
> 'bootstrap')
>       at 
> org.apache.calcite.avatica.util.ArrayImpl.getArray(ArrayImpl.java:115)
>       at org.apache.calcite.avatica.util.ArrayImpl.getArray(ArrayImpl.java:50)
> select multiset[multiset[1, 2], multiset[3, 4]]
>   getString:           [[1, 2], [3, 4]]
>   getObject.getArray:  java.lang.ClassCastException: class 
> org.apache.calcite.avatica.util.ArrayImpl cannot be cast to class 
> java.lang.Integer (...)
> select array[array['a', 'b'], array['c', 'd']]
>   getString:           [[a, b], [c, d]]
>   getObject.getArray:  [[a, b], [c, d]]
> {noformat}
> The same exception occurs on main for multiset[array[1, 2]], 
> array[multiset[1, 2]] and multiset[multiset[array[1, 2]]].
> h3. Expected
> For select array[array[1, 2], array[3, 4]], getArray() returns an Object[] of 
> two java.sql.Array elements whose own getArray() returns int[] {1, 2} and 
> int[] {3, 4}. This is what the java.sql.Array contract describes for an ARRAY 
> base type, and it is what Calcite already returns when the inner elements are 
> VARCHAR.
> h3. Analysis (a guess; the report above stands without it)
> CalcitePrepareImpl.avaticaType passes the Rep of the component's Java class 
> to ColumnMetaData.array, so the metadata of INTEGER ARRAY carries 
> Rep.PRIMITIVE_INT. ArrayImpl.getArray of the outer collection switches on the 
> component type's rep, takes the PRIMITIVE_INT branch, and casts each inner 
> ArrayImpl to Integer. VARCHAR maps to Rep.STRING, falls through to the 
> Object[] branch, and works. CALCITE-910 (commit 4000edd8e6, 2015) introduced 
> the component-based rep; before it the rep came from the collection's own 
> class. Passing Rep.ARRAY or Rep.MULTISET, as the Avatica test for 
> CALCITE-3557 (ArrayAccessorTest.resultSetFromMultisetArray) does, makes all 
> the queries above return nested java.sql.Array values, and the core test 
> suite passes.
> h3. Related
> CALCITE-3557 fixed the ClassCastException on the getString path (Avatica 
> 1.23.0); this report is about getObject().getArray(), which still fails. 
> CALCITE-1335 is about getArray() returning internal representations of DATE 
> and TIMESTAMP, not this exception.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to