wasabii opened a new pull request, #5150: URL: https://github.com/apache/calcite/pull/5150
https://issues.apache.org/jira/browse/CALCITE-7690 `DELETE` against a table with exactly one `NOT NULL` column of a primitive type fails at runtime: ```sql create table t (i int not null); insert into t values (1); delete from t where i = 1; ``` ``` java.lang.RuntimeException: Error while compiling generated Java code: ... Caused by: org.codehaus.commons.compiler.CompileException: Cannot cast "java.lang.Object" to "int" ``` ### Cause `EnumerableTableModify.deleteFromCollection` declares the sink row as `Object` and then casts it to the table's Java row type: ```java final ParameterExpression sinkRow = Expressions.parameter(Object.class, "sinkRow"); final Expression typedSinkRow = Expressions.convert_(sinkRow, tablePhysType.getJavaRowType()); ``` 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: ``` (int) o -> Cannot cast "java.lang.Object" to "int" (java.lang.Integer) o -> compiles ((java.lang.Integer) o).intValue() -> compiles ``` ### Fix Box the target type. `Primitive.box` leaves `Object[]` unchanged, so the multi-column case generates exactly what it generated before, and the sink values are read with a storage type of `Object`, so boxing loses nothing. ### Tests `ServerTest.testDeleteSingleColumn` and `ServerTest.testDeleteSingleNullableColumn`. Every test added by [CALCITE-7510] uses a two-column table (`create table t (i int not null, j int not null)`), so the single-column shape was never exercised. The nullable case was never broken — its Java row type is already a box — and is covered to document that boundary. Verified with `./gradlew :server:test`: the two new tests pass with the fix, and `testDelete`, `testDeleteDuplicateRows` and `testUpdate` are unaffected. `checkstyleMain`, `checkstyleTest` and `autostyleCheck` pass for `core` and `server`. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
