1 回答
TA贡献1842条经验 获得超12个赞
这是因为 SqlStdOperatorTable.instance() 为注册的函数做了一些初始化工作。因此,在 #register 之后调用它不会按预期工作。正确的方法是使用 ListSqlOperatorTable 并将其与带有 ChainedSqlOperatorTable 的 StdSqlOperatorTable 链接起来,预置代码可能如下所示:
ListSqlOperatorTable listOpTable = new ListSqlOperatorTable();
listOpTable.add(my_udf);
ChainedSqlOperatorTable chainedOpTable = ChainedSqlOperatorTable.of(listOpTable, SqlStdOperatorTable.instance());
// then use this chainedOpTable
// If you want to use a special dialect operators, you can code like this
SqlOperatorTable optable = SqlLibraryOperatorTableFactory.INSTANCE
.getOperatorTable(SqlLibrary.STANDARD, SqlLibrary.POSTGRESQL);
我用以下方法解决了我的问题 -
// methods containing the udf logic
public static class MyUdf1 {
public Integer eval(String a) {
return a.length();
}
}
@Test
public void test1() throws SQLException, ClassNotFoundException {
CalciteConnection connection = MyTests.getCalciteConnection();
final String functionName = "STR_LEN";
final ScalarFunction udfLengthFunction = ScalarFunctionImpl.create(Types.lookupMethod(MyUdf1.class, "eval", String.class));
connection.getRootSchema().getSubSchema("SYSTEM").add(functionName, udfLengthFunction);
FrameworkConfig frameworkConfig = Frameworks.newConfigBuilder()
.parserConfig(SqlParser.Config.DEFAULT)
.defaultSchema(connection.getRootSchema().getSubSchema("SYSTEM"))
.programs(Programs.sequence(Programs.ofRules(Programs.RULE_SET), Programs.CALC_PROGRAM))
.build();
SqlIdentifier udfLengthIdentifier = new SqlIdentifier(Collections.singletonList(functionName), null, SqlParserPos.ZERO, null);
final SqlOperator strLenOperator = new SqlUserDefinedFunction(udfLengthIdentifier, ReturnTypes.INTEGER, null, OperandTypes.STRING, null, udfLengthFunction);
final RelBuilder builder = RelBuilder.create(frameworkConfig);
RelNode udfRelNode = builder
.scan("EMP")
.project(builder.call(strLenOperator, builder.literal("SampleString")))
.build();
ResultSet set = RelRunners.run(udfRelNode).executeQuery();
set.next();
System.out.println(set.getString(1));
}
添加回答
举报