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)