[ 
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)

Reply via email to