You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@calcite.apache.org by "Anton Haidai (Jira)" <ji...@apache.org> on 2019/09/20 17:23:00 UTC
[jira] [Created] (CALCITE-3364) Can't group table function result
due to a type cast error
Anton Haidai created CALCITE-3364:
-------------------------------------
Summary: Can't group table function result due to a type cast error
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
I was not able to find a suitable test, so I'll describe the issue using a custom minimal table function as 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.
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)