[ https://issues.apache.org/jira/browse/CALCITE-3364?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Anton Haidai updated CALCITE-3364: ---------------------------------- Description: I was not able to find a suitable test, so I'll describe the issue using a custom minimal table function returning single value as an example. I believe, that it should be reproducible against any table function. There is a simple table function my_dummy() that just prints numbers 1 to 5. Simple select works as expected: {code} SQL: select val from table(my_dummy()) Result: val : INTEGER 5 4 3 2 1 {code} However, when trying to make an aggregation on top of it, there is a class cast error: {code} SQL: select val from table(my_dummy()) group by val Error: java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to java.lang.Integer at org.apache.calcite.avatica.util.AbstractCursor$IntAccessor.getInt(AbstractCursor.java:541) at org.apache.calcite.avatica.AvaticaSite.get(AvaticaSite.java:340) at org.apache.calcite.avatica.AvaticaResultSet.getObject(AvaticaResultSet.java:393) {code} Actually, this array Object[] contains a single integer produced by the table function. Also I faced similar class cast errors in a generated code making hashJoin (in a complex production code), I believe, the cause should be the same as in this minimal example. Here is this my_dummy() table function implementation (single file): {code} package com.myapp.tf; import org.apache.calcite.DataContext; import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.Enumerator; import org.apache.calcite.linq4j.tree.Types; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.schema.ScannableTable; import org.apache.calcite.schema.TableFunction; import org.apache.calcite.schema.impl.AbstractTable; import org.apache.calcite.schema.impl.TableFunctionImpl; import org.apache.calcite.sql.SqlIdentifier; import org.apache.calcite.sql.SqlOperatorBinding; import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.sql.validate.SqlUserDefinedTableFunction; import java.util.Collections; import java.util.concurrent.atomic.AtomicInteger; import static org.apache.calcite.sql.type.OperandTypes.family; public class DummyFunction extends SqlUserDefinedTableFunction { public static String DUMMY_FUNCTION_NAME = "my_dummy"; public static final TableFunction DUMMY_TABLE_FUNCTION = TableFunctionImpl.create(Types.lookupMethod( DummyFunction.class, "createDummyTable" )); public static DummyTable createDummyTable() { return new DummyTable(); } public DummyFunction() { super(new SqlIdentifier(DUMMY_FUNCTION_NAME, SqlParserPos.ZERO), null, null, family(), Collections.emptyList(), DUMMY_TABLE_FUNCTION ); } @Override public RelDataType inferReturnType(SqlOperatorBinding opBinding) { RelDataTypeFactory typeFactory = opBinding.getTypeFactory(); return typeFactory.builder() .add("val", SqlTypeName.INTEGER) .build(); } } class DummyTable extends AbstractTable implements ScannableTable { private final AtomicInteger cnt = new AtomicInteger(6); @Override public Enumerable<Object[]> scan(DataContext root) { return new AbstractEnumerable<Object[]>() { public Enumerator<Object[]> enumerator() { return new Enumerator<Object[]> () { @Override public Object[] current() { return new Object[] { cnt.intValue() }; } @Override public boolean moveNext() { return cnt.decrementAndGet() > 0; } @Override public void reset() { } @Override public void close() { } }; } }; } @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) { return typeFactory.builder() .add("val", SqlTypeName.INTEGER) .build(); } } {code} And adding it into a schema: {code} mySchemaPlus.add(DUMMY_FUNCTION_NAME, DummyFunction.DUMMY_TABLE_FUNCTION); {code} was: I was not able to find a suitable test, so I'll describe the issue using a custom minimal table function as an example. I believe, that it should be reproducible against any table function. There is a simple table function my_dummy() that just prints numbers 1 to 5. Simple select works as expected: {code} SQL: select val from table(my_dummy()) Result: val : INTEGER 5 4 3 2 1 {code} However, when trying to make an aggregation on top of it, there is a class cast error: {code} SQL: select val from table(my_dummy()) group by val Error: java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to java.lang.Integer at org.apache.calcite.avatica.util.AbstractCursor$IntAccessor.getInt(AbstractCursor.java:541) at org.apache.calcite.avatica.AvaticaSite.get(AvaticaSite.java:340) at org.apache.calcite.avatica.AvaticaResultSet.getObject(AvaticaResultSet.java:393) {code} Actually, this array Object[] contains a single integer produced by the table function. Also I faced similar class cast errors in a generated code making hashJoin (in a complex production code), I believe, the cause should be the same as in this minimal example. Here is this my_dummy() table function implementation (single file): {code} package com.myapp.tf; import org.apache.calcite.DataContext; import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.Enumerator; import org.apache.calcite.linq4j.tree.Types; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.schema.ScannableTable; import org.apache.calcite.schema.TableFunction; import org.apache.calcite.schema.impl.AbstractTable; import org.apache.calcite.schema.impl.TableFunctionImpl; import org.apache.calcite.sql.SqlIdentifier; import org.apache.calcite.sql.SqlOperatorBinding; import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.sql.validate.SqlUserDefinedTableFunction; import java.util.Collections; import java.util.concurrent.atomic.AtomicInteger; import static org.apache.calcite.sql.type.OperandTypes.family; public class DummyFunction extends SqlUserDefinedTableFunction { public static String DUMMY_FUNCTION_NAME = "my_dummy"; public static final TableFunction DUMMY_TABLE_FUNCTION = TableFunctionImpl.create(Types.lookupMethod( DummyFunction.class, "createDummyTable" )); public static DummyTable createDummyTable() { return new DummyTable(); } public DummyFunction() { super(new SqlIdentifier(DUMMY_FUNCTION_NAME, SqlParserPos.ZERO), null, null, family(), Collections.emptyList(), DUMMY_TABLE_FUNCTION ); } @Override public RelDataType inferReturnType(SqlOperatorBinding opBinding) { RelDataTypeFactory typeFactory = opBinding.getTypeFactory(); return typeFactory.builder() .add("val", SqlTypeName.INTEGER) .build(); } } class DummyTable extends AbstractTable implements ScannableTable { private final AtomicInteger cnt = new AtomicInteger(6); @Override public Enumerable<Object[]> scan(DataContext root) { return new AbstractEnumerable<Object[]>() { public Enumerator<Object[]> enumerator() { return new Enumerator<Object[]> () { @Override public Object[] current() { return new Object[] { cnt.intValue() }; } @Override public boolean moveNext() { return cnt.decrementAndGet() > 0; } @Override public void reset() { } @Override public void close() { } }; } }; } @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) { return typeFactory.builder() .add("val", SqlTypeName.INTEGER) .build(); } } {code} And adding it into a schema: {code} mySchemaPlus.add(DUMMY_FUNCTION_NAME, DummyFunction.DUMMY_TABLE_FUNCTION); {code} > Can't group table function result due to a type cast error if table functions > returns a single value > ---------------------------------------------------------------------------------------------------- > > Key: CALCITE-3364 > URL: https://issues.apache.org/jira/browse/CALCITE-3364 > Project: Calcite > Issue Type: Bug > Affects Versions: 1.21.0 > Reporter: Anton Haidai > Priority: Major > > I was not able to find a suitable test, so I'll describe the issue using a > custom minimal table function returning single value as an example. I > believe, that it should be reproducible against any table function. > There is a simple table function my_dummy() that just prints numbers 1 to 5. > Simple select works as expected: > {code} > SQL: > select val from table(my_dummy()) > Result: > val : INTEGER > 5 > 4 > 3 > 2 > 1 > {code} > However, when trying to make an aggregation on top of it, there is a class > cast error: > {code} > SQL: > select val from table(my_dummy()) > group by val > Error: > java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to > java.lang.Integer > at > org.apache.calcite.avatica.util.AbstractCursor$IntAccessor.getInt(AbstractCursor.java:541) > at org.apache.calcite.avatica.AvaticaSite.get(AvaticaSite.java:340) > at > org.apache.calcite.avatica.AvaticaResultSet.getObject(AvaticaResultSet.java:393) > {code} > Actually, this array Object[] contains a single integer produced by the table > function. Also I faced similar class cast errors in a generated code making > hashJoin (in a complex production code), I believe, the cause should be the > same as in this minimal example. > Here is this my_dummy() table function implementation (single file): > {code} > package com.myapp.tf; > import org.apache.calcite.DataContext; > import org.apache.calcite.linq4j.AbstractEnumerable; > import org.apache.calcite.linq4j.Enumerable; > import org.apache.calcite.linq4j.Enumerator; > import org.apache.calcite.linq4j.tree.Types; > import org.apache.calcite.rel.type.RelDataType; > import org.apache.calcite.rel.type.RelDataTypeFactory; > import org.apache.calcite.schema.ScannableTable; > import org.apache.calcite.schema.TableFunction; > import org.apache.calcite.schema.impl.AbstractTable; > import org.apache.calcite.schema.impl.TableFunctionImpl; > import org.apache.calcite.sql.SqlIdentifier; > import org.apache.calcite.sql.SqlOperatorBinding; > import org.apache.calcite.sql.parser.SqlParserPos; > import org.apache.calcite.sql.type.SqlTypeName; > import org.apache.calcite.sql.validate.SqlUserDefinedTableFunction; > import java.util.Collections; > import java.util.concurrent.atomic.AtomicInteger; > import static org.apache.calcite.sql.type.OperandTypes.family; > public class DummyFunction extends SqlUserDefinedTableFunction { > public static String DUMMY_FUNCTION_NAME = "my_dummy"; > public static final TableFunction DUMMY_TABLE_FUNCTION = > TableFunctionImpl.create(Types.lookupMethod( > DummyFunction.class, > "createDummyTable" > )); > public static DummyTable createDummyTable() { > return new DummyTable(); > } > public DummyFunction() { > super(new SqlIdentifier(DUMMY_FUNCTION_NAME, SqlParserPos.ZERO), > null, > null, > family(), > Collections.emptyList(), > DUMMY_TABLE_FUNCTION > ); > } > @Override > public RelDataType inferReturnType(SqlOperatorBinding opBinding) { > RelDataTypeFactory typeFactory = opBinding.getTypeFactory(); > return typeFactory.builder() > .add("val", SqlTypeName.INTEGER) > .build(); > } > } > class DummyTable extends AbstractTable implements ScannableTable { > private final AtomicInteger cnt = new AtomicInteger(6); > @Override > public Enumerable<Object[]> scan(DataContext root) { > return new AbstractEnumerable<Object[]>() { > public Enumerator<Object[]> enumerator() { > return new Enumerator<Object[]> () { > @Override > public Object[] current() { > return new Object[] { cnt.intValue() }; > } > @Override > public boolean moveNext() { > return cnt.decrementAndGet() > 0; > } > @Override > public void reset() { > } > @Override > public void close() { > } > }; > } > }; > } > @Override > public RelDataType getRowType(RelDataTypeFactory typeFactory) { > return typeFactory.builder() > .add("val", SqlTypeName.INTEGER) > .build(); > } > } > {code} > And adding it into a schema: > {code} > mySchemaPlus.add(DUMMY_FUNCTION_NAME, DummyFunction.DUMMY_TABLE_FUNCTION); > {code} -- This message was sent by Atlassian Jira (v8.3.4#803005)