[
https://issues.apache.org/jira/browse/CALCITE-7690?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
ASF GitHub Bot updated CALCITE-7690:
------------------------------------
Labels: pull-request-available (was: )
> DELETE on a single-column table fails with "Cannot cast java.lang.Object to
> int"
> --------------------------------------------------------------------------------
>
> Key: CALCITE-7690
> URL: https://issues.apache.org/jira/browse/CALCITE-7690
> Project: Calcite
> Issue Type: Bug
> Affects Versions: 1.43.0
> Reporter: Jerome Isaac Haltom
> Priority: Major
> Labels: pull-request-available
>
> DELETE against a table with exactly one NOT NULL column of a primitive type
> fails at runtime. Reproduced on master (fc95bb0e6) and on 1.43.0-SNAPSHOT;
> 1.42.0 is unaffected.
> {code:sql}
> create table t (i int not null);
> insert into t values (1);
> delete from t where i = 1;
> {code}
> {noformat}
> java.lang.RuntimeException: Error while compiling generated Java code:
> ...
> Caused by: org.codehaus.commons.compiler.CompileException: Cannot cast
> "java.lang.Object" to "int"
> {noformat}
> h3. Cause
> {{EnumerableTableModify.deleteFromCollection}} declares the sink row as
> {{Object}} and then casts it to the table's Java row type:
> {code:java}
> final ParameterExpression sinkRow = Expressions.parameter(Object.class,
> "sinkRow");
> final Expression typedSinkRow =
> Expressions.convert_(sinkRow, tablePhysType.getJavaRowType());
> {code}
> For a single-column table that row type is a primitive.
> {{EnumerableTableScan.deduceFormat}} returns ARRAY, because the table's
> element type is {{Object[]}}, and the optimising {{PhysTypeImpl.of}} then
> rewrites ARRAY to SCALAR for a one-field row type, so {{getJavaRowType()}} is
> {{int}}. The generated source is therefore {{(int) sinkRow}}.
> {{(int) someObject}} is legal Java -- JLS 5.5 permits a narrowing reference
> conversion followed by an unboxing conversion, and javac compiles it -- but
> Janino does not implement it, and Janino is what compiles the generated code.
> Measured against the Janino on the classpath:
> {noformat}
> (int) o -> Cannot cast "java.lang.Object" to
> "int"
> (java.lang.Integer) o -> compiles
> ((java.lang.Integer) o).intValue() -> compiles
> {noformat}
> h3. Suggested fix
> Box the target type:
> {code:java}
> final Expression typedSinkRow =
> Expressions.convert_(sinkRow,
> Primitive.box(tablePhysType.getJavaRowType()));
> {code}
> {{Primitive.box}} leaves {{Object[]}} unchanged, so the multi-column case
> generates exactly what it generates today. The sink values are read with a
> storage type of {{Object}}, so boxing loses nothing.
> h3. Notes
> Introduced by CALCITE-7510. Every test that change added uses a two-column
> table ({{create table t (i int not null, j int not null)}}), so the
> single-column shape was never exercised. A nullable single column is
> unaffected, because its Java row type is already {{Integer}}.
> I have a patch with tests in {{ServerTest}} and will open a PR.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)