我需要为Calcite添加一个用户定义的函数,它将一个整数作为参数并返回一个整数。
public class SquareFunction {
public int eval(int a) {
return a*a;
}
}
和创建架构并添加功能的相关代码是
SchemaPlus rootSchema = Frameworks.createRootSchema(false);
rootSchema.add("SQUARE_FUNC",
ScalarFunctionImpl.create(SquareFunction.class,"eval");
但是像
这样的简单SQLselect SQUARE_FUNC(1) from test;
验证期间失败,并显示以下消息:
No match found for function signature SQUARE_FUNC(<NUMERIC>)
堆栈跟踪是:
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
我遵循了Calcite的UdfTest.testUserDefinedFunctionInView
实现,但仍无法使其正常工作。我做错了什么?
答案 0 :(得分:1)
SquareFunction
是内在的一类吗?如果是这样,请尝试将其设置为静态。
如果这不起作用,请尝试使用eval
静态方法。
答案 1 :(得分:1)
Calcite如何验证函数是否存在?
众所周知,SqlOperatorTable
定义了一个用于枚举和查找SQL运算符和函数的目录接口,lookupOperatorOverloads
检索具有给定名称和语法的运算符列表。
对于Frameworks
,SqlOperatorTable
的默认FrameworkConfig
为SqlStdOperatorTable.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());
}
}
答案 2 :(得分: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();