[CALCITE-3547] SqlValidatorException because Planner cannot find UDFs added to schema (Chenxiao Mao)
* Fix PlannerImpl#validate and PlannerImpl#expandView
close apache/calcite#1615
diff --git a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
index 9acbc42..4beee6e 100644
--- a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
@@ -47,6 +47,7 @@
import org.apache.calcite.sql.SqlOperatorTable;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.util.ChainedSqlOperatorTable;
import org.apache.calcite.sql.validate.SqlConformance;
import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.sql2rel.RelDecorrelator;
@@ -211,12 +212,7 @@
public SqlNode validate(SqlNode sqlNode) throws ValidationException {
ensure(State.STATE_3_PARSED);
- final SqlConformance conformance = conformance();
- final CalciteCatalogReader catalogReader = createCatalogReader();
- this.validator =
- new CalciteSqlValidator(operatorTable, catalogReader, typeFactory,
- conformance);
- this.validator.setIdentifierExpansion(true);
+ this.validator = createSqlValidator(createCatalogReader());
try {
validatedSqlNode = validator.validate(sqlNode);
} catch (RuntimeException e) {
@@ -294,13 +290,9 @@
throw new RuntimeException("parse failed", e);
}
- final SqlConformance conformance = conformance();
final CalciteCatalogReader catalogReader =
createCatalogReader().withSchemaPath(schemaPath);
- final SqlValidator validator =
- new CalciteSqlValidator(operatorTable, catalogReader, typeFactory,
- conformance);
- validator.setIdentifierExpansion(true);
+ final SqlValidator validator = createSqlValidator(catalogReader);
final RexBuilder rexBuilder = createRexBuilder();
final RelOptCluster cluster = RelOptCluster.create(planner, rexBuilder);
@@ -334,6 +326,16 @@
typeFactory, connectionConfig);
}
+ private SqlValidator createSqlValidator(CalciteCatalogReader catalogReader) {
+ final SqlConformance conformance = conformance();
+ final SqlOperatorTable opTab =
+ ChainedSqlOperatorTable.of(operatorTable, catalogReader);
+ final SqlValidator validator =
+ new CalciteSqlValidator(opTab, catalogReader, typeFactory, conformance);
+ validator.setIdentifierExpansion(true);
+ return validator;
+ }
+
private static SchemaPlus rootSchema(SchemaPlus schema) {
for (;;) {
if (schema.getParentSchema() == null) {
diff --git a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
index 3d73774..dd247dd 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -59,6 +59,7 @@
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.impl.ScalarFunctionImpl;
import org.apache.calcite.sql.SqlAggFunction;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlDialect;
@@ -82,6 +83,7 @@
import org.apache.calcite.test.CalciteAssert;
import org.apache.calcite.test.RelBuilderTest;
import org.apache.calcite.util.Optionality;
+import org.apache.calcite.util.Smalls;
import org.apache.calcite.util.Util;
import com.google.common.base.Throwables;
@@ -246,6 +248,27 @@
}
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-3547">[CALCITE-3547]
+ * SqlValidatorException because Planner cannot find UDFs added to schema</a>. */
+ @Test public void testValidateUserDefinedFunctionInSchema() throws Exception {
+ SchemaPlus rootSchema = Frameworks.createRootSchema(true);
+ rootSchema.add("my_plus",
+ ScalarFunctionImpl.create(Smalls.MyPlusFunction.class, "eval"));
+ final FrameworkConfig config = Frameworks.newConfigBuilder()
+ .defaultSchema(
+ CalciteAssert.addSchema(rootSchema, CalciteAssert.SchemaSpec.HR))
+ .build();
+ final Planner planner = Frameworks.getPlanner(config);
+ final String sql = "select \"my_plus\"(\"deptno\", 100) as \"p\"\n"
+ + "from \"hr\".\"emps\"";
+ SqlNode parse = planner.parse(sql);
+ SqlNode validate = planner.validate(parse);
+ assertThat(Util.toLinux(validate.toString()),
+ equalTo("SELECT `my_plus`(`emps`.`deptno`, 100) AS `p`\n"
+ + "FROM `hr`.`emps` AS `emps`"));
+ }
+
private Planner getPlanner(List<RelTraitDef> traitDefs, Program... programs) {
return getPlanner(traitDefs, SqlParser.Config.DEFAULT, programs);
}