Okay… so more digging in this area throws up some more weirdness. Executing the
following query (via prepared statement):
INSERT INTO “foo” (KEY, "cell") values (?, ?)
where:
TABLE_NAME=foo; COLUMN_NAME=KEY; DATA_TYPE=-5; TYPE_NAME=JavaType(long) NOT
NULL;
TABLE_NAME=foo; COLUMN_NAME=cell; DATA_TYPE=-3; TYPE_NAME=JavaType(class [B);
seems to be impossible. Avatica wants to be passed a byte[] through setObject
or setBytes… which it hard casts and then wraps in a ByteString. The type
inference in Calcite infers the type that ultimately propagates in to the
EnumerableCalc as byte[] though so generates an cast of the ByteString back to
a byte[].
java.lang.ClassCastException: class org.apache.calcite.avatica.util.ByteString
cannot be cast to class [B (org.apache.calcite.avatica.util.ByteString is in
unnamed module of loader 'app'; [B is in module java.base of loader 'bootstrap')
at Baz$2.apply(Unknown Source)
at
org.apache.calcite.linq4j.EnumerableDefaults.longCount(EnumerableDefaults.java:2373)
at
org.apache.calcite.linq4j.EnumerableDefaults.count(EnumerableDefaults.java:397)
at
org.apache.calcite.linq4j.DefaultEnumerable.count(DefaultEnumerable.java:187)
at Baz.bind(Unknown Source)
at
org.apache.calcite.jdbc.CalcitePrepare$CalciteSignature.enumerable(CalcitePrepare.java:363)
at
org.apache.calcite.jdbc.CalciteConnectionImpl.enumerable(CalciteConnectionImpl.java:325)
at
org.apache.calcite.jdbc.CalciteMetaImpl._createIterable(CalciteMetaImpl.java:585)
at
org.apache.calcite.jdbc.CalciteMetaImpl.execute(CalciteMetaImpl.java:715)
at
org.apache.calcite.avatica.AvaticaConnection.executeQueryInternal(AvaticaConnection.java:551)
Unfortunately there are just too many places this could be “fixed” and I lack
the necessary context to know if I’m using something wrong or if a fix is
needed, and if so which layer of code is dropping the ball.
Thanks,
Chris
From: Chris Dennis <[email protected]>
Date: Friday, March 21, 2025 at 4:13 PM
To: [email protected] <[email protected]>
Subject: [EXTERNAL] Type Discrepancies between PreparedStatement, and row
RelDataType
Hi All,
Trying to figure out what’s amiss in my Calcite based driver and whether there
are bugs in this area in Avatica/Calcite or if I’m using something wrong.
I have a table in a database that reports its columns as: JavaType(long) NOT
NULL (BIGINT), JavaType(class java.lang.Character) (CHAR)
I then build a prepared statement against the same connection: INSERT INTO foo
(KEY, \"character\") values (?, ?)
The parameter metadata reports the parameter types as: java.lang.Object
(BIGINT). java.lang.Object (CHAR)
The Enumerable node that is input to my adapters part of the graph reports its
row type as: RecordType(JavaType(class java.lang.Long) KEY, JavaType(class
java.lang.Character) character)
At code generation I’m then presented with a field that claims it’s a
java.lang.Character, but at runtime I get a ClassCastException because
arbitrary java types (notably Strings) are getting all the way through from the
JDBC PreparedStatement unmodified. My understanding of the JDBC spec says that
the parameter values should get converted, at but it’s not clear to me who’s
responsibility that is.
Anyone have any thoughts on where I should look first?
Thanks,
Chris