Rodrigo Setti created CALCITE-7846:
--------------------------------------
Summary: Set operations on one-column table functions can throw or
return incorrect rows
Key: CALCITE-7846
URL: https://issues.apache.org/jira/browse/CALCITE-7846
Project: Calcite
Issue Type: Bug
Components: core
Affects Versions: 1.42.0
Environment: Calcite core and {{linq4j}} 1.42.0; Enumerable
convention; {{{}{{EnumerableRel.Prefer.ARRAY}}{}}}. Reproduced in a Java test
on macOS.
Reporter: Rodrigo Setti
A one-column user-defined table function and a one-column table can use
different Enumerable row representations. Set operations between them can throw
a {{ClassCastException}} or return incorrect rows.
Reproducer on Calcite 1.42.0:
* Register {{numbers_fn()}} using {{{}TableFunctionImpl{}}}. It returns a
{{ScannableTable}}
with one {{INTEGER}} column, n, and {{Object[]}} rows [1] and [2].
* Register numbers_table as a {{ScannableTable}} with the same row type and
{{Object[]}} rows [2] and [3].
* Compile and execute the following query with the Enumerable convention
and {{{}EnumerableRel.Prefer.ARRAY{}}}:
{code:java}
SELECT n FROM TABLE(numbers_fn())
EXCEPT
SELECT n FROM numbers_table{code}
Expected: one row, n = 1.
Actual: execution throws
{code:java}
java.lang.ClassCastException: java.lang.Integer cannot be cast to
[Ljava.lang.Object; at
org.apache.calcite.linq4j.function.Functions$ArrayEqualityComparer.hashCode.{code}
The same mixed table/function shape should also yield correct results when the
operand order is reversed, and with {{UNION}} and {{{}INTERSECT{}}}.
Suspected cause: {{EnumerableTableFunctionScan.defaultTableFunctionImplement
}}retains {{JavaRowFormat.ARRAY}} for this non-QueryableTable function, while a
one-column {{EnumerableTableScan}} uses scalar rows. The set-operation comparer
then receives incompatible representations.
This is related to CALCITE-1907, which fixed a prior one-column table function
failure affecting downstream operators. The set-operation reproducer above
still fails on 1.42.0. As a downstream workaround, placing an identity
{{EnumerableCalc}} immediately above the one-column
{{EnumerableTableFunctionScan}} makes the query return the expected row.
A regression test should cover {{EXCEPT}} in both directions, {{{}UNION{}}}, and
{{INTERSECT}} with the same one-column table and function.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)