7

I need to add a user-defined function to Calcite that takes an integer as a parameter and returns an integer.

    public class SquareFunction  {
        public int eval(int a) {
            return a*a;
        }
    }

and the relevant code that creates a schema and adds the function is

     SchemaPlus rootSchema = Frameworks.createRootSchema(false);
     rootSchema.add("SQUARE_FUNC", 
                    ScalarFunctionImpl.create(SquareFunction.class,"eval"); 

But a simple SQL like

select SQUARE_FUNC(1) from test;

fails during the validation with the following message:

No match found for function signature SQUARE_FUNC(<NUMERIC>)

The stack trace is:

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
    at org.apache.calcite.runtime.Resources$ExInstWithCause.ex(Resources.java:463)
    at org.apache.calcite.sql.SqlUtil.newContextException(SqlUtil.java:804)
    at org.apache.calcite.sql.SqlUtil.newContextException(SqlUtil.java:789)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.newValidationError(SqlValidatorImpl.java:4386)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.handleUnresolvedFunction(SqlValidatorImpl.java:1670)
    at org.apache.calcite.sql.SqlFunction.deriveType(SqlFunction.java:278)
    at org.apache.calcite.sql.SqlFunction.deriveType(SqlFunction.java:223)
    at org.apache.calcite.sql.validate.SqlValidatorImpl$DeriveTypeVisitor.visit(SqlValidatorImpl.java:4965)
    at org.apache.calcite.sql.validate.SqlValidatorImpl$DeriveTypeVisitor.visit(SqlValidatorImpl.java:1)
    at org.apache.calcite.sql.SqlCall.accept(SqlCall.java:137)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.deriveTypeImpl(SqlValidatorImpl.java:1586)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.deriveType(SqlValidatorImpl.java:1571)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.expandSelectItem(SqlValidatorImpl.java:453)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.validateSelectList(SqlValidatorImpl.java:3668)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.validateSelect(SqlValidatorImpl.java:3186)
    at org.apache.calcite.sql.validate.SelectNamespace.validateImpl(SelectNamespace.java:60)
    at org.apache.calcite.sql.validate.AbstractNamespace.validate(AbstractNamespace.java:84)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.validateNamespace(SqlValidatorImpl.java:937)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.validateQuery(SqlValidatorImpl.java:918)
    at org.apache.calcite.sql.SqlSelect.validate(SqlSelect.java:220)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.validateScopedExpression(SqlValidatorImpl.java:893)
    at org.apache.calcite.sql.validate.SqlValidatorImpl.validate(SqlValidatorImpl.java:603)
    at org.apache.calcite.prepare.PlannerImpl.validate(PlannerImpl.java:188) ... 26 more

I followed the Calcite's UdfTest.testUserDefinedFunctionInView implementation but still couldn't make it work. What am I doing wrong?

4

3 回答 3

2

Calcite 如何验证函数是否存在?

据我所知,SqlOperatorTable它定义了一个目录接口,用于枚举和查找 SQL 运算符和函数,并lookupOperatorOverloads检索具有给定名称和语法的运算符列表。

对于,Frameworks默认SqlOperatorTable值为。但是您添加的功能仅在. 所以下面的代码可以工作:FrameworkConfigSqlStdOperatorTable.instance()CalciteCatalogReader

   public class UdfTest {
    private static final String SQL      = "select SQUARE_FUNC(1)";
    private static final String FUN_NAME = "SQUARE_FUNC";

    public static void main(String[] args) throws Exception {
        useFramworksExec();
    }

    private static void useFramworksExec() throws Exception {
        CalciteSchema rootSchema = CalciteSchema.createRootSchema(false, false);
        SchemaPlus schema = rootSchema.plus();
        schema.add(FUN_NAME, ScalarFunctionImpl.create(SquareFunction.class, "eval"));
        CalciteCatalogReader reader = new CalciteCatalogReader(rootSchema,
            SqlParser.Config.DEFAULT.caseSensitive(),
            rootSchema.path(null),
            new JavaTypeFactoryImpl());
        FrameworkConfig config = Frameworks.newConfigBuilder().operatorTable(reader).defaultSchema(schema).build();
        Planner planner = Frameworks.getPlanner(config);
        SqlNode ast = planner.parse(SQL);
        SqlNode validatedAst = planner.validate(ast);
        System.out.println(validatedAst.toString());
    }
} 
于 2017-07-07T03:38:30.960 回答
1

SquareFunction内部类吗?如果是这样,请尝试将其设为静态。

如果这不起作用,请尝试制作eval一个静态方法。

于 2017-05-24T18:07:03.157 回答
0

由于 CalciteCatalogReader 对象需要上下文,还有另一种注册自定义函数的方法。

SqlFunction countRelation = new SqlFunction("COUNT_RELATION",
                SqlKind.OTHER_FUNCTION,
                ReturnTypes.INTEGER,
                null,
                OperandTypes.STRING,
                SqlFunctionCategory.NUMERIC);

        SqlStdOperatorTable sqlStdOperatorTable = SqlStdOperatorTable.instance();
        sqlStdOperatorTable.register(countRelation);

        this.frameworkConfig = Frameworks.newConfigBuilder()
                .parserConfig(parserConfig)
                .defaultSchema(schemaPlus)
                .programs(Programs.sequence(Programs.ofRules(Programs.RULE_SET), Programs.CALC_PROGRAM))
                .traitDefs(traitDefs)
                .operatorTable(sqlStdOperatorTable)
                .build();


于 2019-05-01T14:20:01.703 回答