diff --git a/core/src/main/java/org/apache/calcite/sql/validate/NamespaceBuilder.java b/core/src/main/java/org/apache/calcite/sql/validate/NamespaceBuilder.java
new file mode 100644
index 000000000000..d42a669fe278
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/validate/NamespaceBuilder.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.sql.validate;
+
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlDelete;
+import org.apache.calcite.sql.SqlInsert;
+import org.apache.calcite.sql.SqlMatchRecognize;
+import org.apache.calcite.sql.SqlMerge;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlPivot;
+import org.apache.calcite.sql.SqlSelect;
+import org.apache.calcite.sql.SqlUnpivot;
+import org.apache.calcite.sql.SqlUpdate;
+
+import org.checkerframework.checker.initialization.qual.UnknownInitialization;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A builder to allow for customization of namespaces down stream.
+ */
+public class NamespaceBuilder {
+
+ private final SqlValidatorImpl sqlValidatorImpl;
+
+ public NamespaceBuilder(@UnknownInitialization SqlValidatorImpl sqlValidatorImpl) {
+ @SuppressWarnings("argument.type.incompatible")
+ SqlValidatorImpl sqlValidatorCast = sqlValidatorImpl;
+ this.sqlValidatorImpl = sqlValidatorCast;
+ }
+
+ /**
+ * Creates a namespace for a SELECT
node. Derived class may
+ * override this factory method.
+ *
+ * @param select Select node
+ * @param enclosingNode Enclosing node
+ * @return Select namespace
+ */
+ public SelectNamespace createSelectNamespace(
+ SqlSelect select,
+ SqlNode enclosingNode) {
+ return new SelectNamespace(sqlValidatorImpl, select, enclosingNode);
+ }
+
+ /**
+ * Creates a namespace for a set operation (UNION
,
+ * INTERSECT
, or EXCEPT
). Derived class may override
+ * this factory method.
+ *
+ * @param call Call to set operation
+ * @param enclosingNode Enclosing node
+ * @return Set operation namespace
+ */
+ public SetopNamespace createSetopNamespace(
+ SqlCall call,
+ SqlNode enclosingNode) {
+ return new SetopNamespace(sqlValidatorImpl, call, enclosingNode);
+ }
+
+
+ public MatchRecognizeNamespace createMatchRecognizeNameSpace(
+ SqlMatchRecognize call,
+ SqlNode enclosingNode) {
+ return new MatchRecognizeNamespace(sqlValidatorImpl, call, enclosingNode);
+ }
+
+ public UnpivotNamespace createUnpivotNameSpace(
+ SqlUnpivot call,
+ SqlNode enclosingNode) {
+ return new UnpivotNamespace(sqlValidatorImpl, call, enclosingNode);
+ }
+
+
+ public PivotNamespace createPivotNameSpace(
+ SqlPivot call,
+ SqlNode enclosingNode) {
+ return new PivotNamespace(sqlValidatorImpl, call, enclosingNode);
+ }
+
+ public DmlNamespace createDeleteNamespace(SqlDelete delete,
+ SqlNode enclosingNode, SqlValidatorScope parentScope) {
+ return new DeleteNamespace(sqlValidatorImpl, delete, enclosingNode, parentScope);
+ }
+
+ public DmlNamespace createInsertNamespace(SqlInsert insert,
+ SqlNode enclosingNode, SqlValidatorScope parentScope) {
+ return new InsertNamespace(sqlValidatorImpl, insert, enclosingNode, parentScope);
+ }
+
+ public DmlNamespace createMergeNamespace(SqlMerge merge, SqlNode enclosing,
+ SqlValidatorScope parentScope) {
+ return new MergeNamespace(sqlValidatorImpl, merge, enclosing, parentScope);
+ }
+
+ public DmlNamespace createUpdate(SqlUpdate sqlUpdate, SqlNode enclosing,
+ SqlValidatorScope parentScope) {
+ return new UpdateNamespace(sqlValidatorImpl, sqlUpdate, enclosing, parentScope);
+ }
+
+
+ /**
+ * Common base class for DML statement namespaces.
+ */
+ public abstract static class DmlNamespace extends IdentifierNamespace {
+ protected DmlNamespace(SqlValidatorImpl validator, SqlNode id,
+ SqlNode enclosingNode, SqlValidatorScope parentScope) {
+ super(validator, id, enclosingNode, parentScope);
+ }
+ }
+
+ /**
+ * Namespace for an INSERT statement.
+ */
+ private static class InsertNamespace extends DmlNamespace {
+ private final SqlInsert node;
+
+ InsertNamespace(SqlValidatorImpl validator, SqlInsert node,
+ SqlNode enclosingNode, SqlValidatorScope parentScope) {
+ super(validator, node.getTargetTable(), enclosingNode, parentScope);
+ this.node = requireNonNull(node, "node");
+ }
+
+ @Override public @Nullable SqlNode getNode() {
+ return node;
+ }
+ }
+
+ /**
+ * Namespace for an UPDATE statement.
+ */
+ private static class UpdateNamespace extends DmlNamespace {
+ private final SqlUpdate node;
+
+ UpdateNamespace(SqlValidatorImpl validator, SqlUpdate node,
+ SqlNode enclosingNode, SqlValidatorScope parentScope) {
+ super(validator, node.getTargetTable(), enclosingNode, parentScope);
+ this.node = requireNonNull(node, "node");
+ }
+
+ @Override public @Nullable SqlNode getNode() {
+ return node;
+ }
+ }
+
+ /**
+ * Namespace for a DELETE statement.
+ */
+ private static class DeleteNamespace extends DmlNamespace {
+ private final SqlDelete node;
+
+ DeleteNamespace(SqlValidatorImpl validator, SqlDelete node,
+ SqlNode enclosingNode, SqlValidatorScope parentScope) {
+ super(validator, node.getTargetTable(), enclosingNode, parentScope);
+ this.node = requireNonNull(node, "node");
+ }
+
+ @Override public @Nullable SqlNode getNode() {
+ return node;
+ }
+ }
+
+ /**
+ * Namespace for a MERGE statement.
+ */
+ private static class MergeNamespace extends DmlNamespace {
+ private final SqlMerge node;
+
+ MergeNamespace(SqlValidatorImpl validator, SqlMerge node,
+ SqlNode enclosingNode, SqlValidatorScope parentScope) {
+ super(validator, node.getTargetTable(), enclosingNode, parentScope);
+ this.node = requireNonNull(node, "node");
+ }
+
+ @Override public @Nullable SqlNode getNode() {
+ return node;
+ }
+ }
+}
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
index 2fe033bedc88..e37b8e54b648 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
@@ -52,6 +52,7 @@
import org.apache.calcite.sql.validate.implicit.TypeCoercions;
import org.apiguardian.api.API;
+import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.qual.Pure;
import org.immutables.value.Value;
@@ -883,6 +884,15 @@ Config withSqlQueryScopeFactory(
return SqlQueryScopesImpl::new;
}
+ /** Set a factory for name space builder to allow for custom behavior downstream. */
+ Config withNamespaceBuilderFactory(
+ Function<@UnknownInitialization SqlValidatorImpl, NamespaceBuilder> factory);
+
+ /** Returns a NamespaceBuilder factory. */
+ @Value.Default default Function<@UnknownInitialization SqlValidatorImpl, NamespaceBuilder>
+ namespaceBuilderFactory() {
+ return NamespaceBuilder::new;
+ }
/** Returns the SQL conformance.
*
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index e13c15179c45..4e25b0f13a6e 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -107,6 +107,7 @@
import org.apache.calcite.sql.util.SqlBasicVisitor;
import org.apache.calcite.sql.util.SqlShuttle;
import org.apache.calcite.sql.util.SqlVisitor;
+import org.apache.calcite.sql.validate.NamespaceBuilder.DmlNamespace;
import org.apache.calcite.sql.validate.SqlQueryScopes.Clause;
import org.apache.calcite.sql.validate.implicit.TypeCoercion;
import org.apache.calcite.util.BitString;
@@ -271,6 +272,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
// TypeCoercion instance used for implicit type coercion.
private final TypeCoercion typeCoercion;
private final SqlQueryScopesImpl sqlQueryScopes;
+ private final NamespaceBuilder namespaceBuilder;
//~ Constructors -----------------------------------------------------------
@@ -313,6 +315,7 @@ protected SqlValidatorImpl(
TypeCoercion typeCoercion = config.typeCoercionFactory().create(typeFactory, this);
this.typeCoercion = typeCoercion;
this.sqlQueryScopes = config.sqlQueryScopeFactory().apply(catalogReader);
+ this.namespaceBuilder = config.namespaceBuilderFactory().apply(this);
if (config.conformance().allowLenientCoercion()) {
final SqlTypeCoercionRule rules =
@@ -402,7 +405,7 @@ public SqlConformance getConformance() {
SelectScope cursorScope =
new SelectScope(parentScope, createEmptyScope(), select);
sqlQueryScopes.putCursorScope(select, cursorScope);
- final SelectNamespace selectNs = createSelectNamespace(select, select);
+ final SelectNamespace selectNs = namespaceBuilder.createSelectNamespace(select, select);
final String alias = SqlValidatorUtil.alias(select, nextGeneratedId++);
sqlQueryScopes.registerNamespace(cursorScope, alias, selectNs, false);
}
@@ -2038,7 +2041,7 @@ private void registerMatchRecognize(
boolean forceNullable) {
final MatchRecognizeNamespace matchRecognizeNamespace =
- createMatchRecognizeNameSpace(call, enclosingNode);
+ namespaceBuilder.createMatchRecognizeNameSpace(call, enclosingNode);
sqlQueryScopes.registerNamespace(usingScope, alias, matchRecognizeNamespace, forceNullable);
final MatchRecognizeScope matchRecognizeScope =
@@ -2055,12 +2058,6 @@ private void registerMatchRecognize(
}
}
- protected MatchRecognizeNamespace createMatchRecognizeNameSpace(
- SqlMatchRecognize call,
- SqlNode enclosingNode) {
- return new MatchRecognizeNamespace(this, call, enclosingNode);
- }
-
private void registerPivot(
SqlValidatorScope parentScope,
SqlValidatorScope usingScope,
@@ -2068,8 +2065,7 @@ private void registerPivot(
SqlNode enclosingNode,
@Nullable String alias,
boolean forceNullable) {
- final PivotNamespace namespace =
- createPivotNameSpace(pivot, enclosingNode);
+ final PivotNamespace namespace = namespaceBuilder.createPivotNameSpace(pivot, enclosingNode);
sqlQueryScopes.registerNamespace(usingScope, alias, namespace, forceNullable);
final SqlValidatorScope scope =
@@ -2086,11 +2082,6 @@ private void registerPivot(
}
}
- protected PivotNamespace createPivotNameSpace(SqlPivot call,
- SqlNode enclosingNode) {
- return new PivotNamespace(this, call, enclosingNode);
- }
-
private void registerUnpivot(
SqlValidatorScope parentScope,
SqlValidatorScope usingScope,
@@ -2099,7 +2090,7 @@ private void registerUnpivot(
@Nullable String alias,
boolean forceNullable) {
final UnpivotNamespace namespace =
- createUnpivotNameSpace(call, enclosingNode);
+ namespaceBuilder.createUnpivotNameSpace(call, enclosingNode);
sqlQueryScopes.registerNamespace(usingScope, alias, namespace, forceNullable);
final SqlValidatorScope scope =
@@ -2116,12 +2107,6 @@ private void registerUnpivot(
}
}
- protected UnpivotNamespace createUnpivotNameSpace(SqlUnpivot call,
- SqlNode enclosingNode) {
- return new UnpivotNamespace(this, call, enclosingNode);
- }
-
-
/**
* Registers scopes and namespaces implied a relational expression in the
* FROM clause.
@@ -2543,35 +2528,6 @@ protected boolean shouldAllowOverRelation() {
return false;
}
- /**
- * Creates a namespace for a SELECT
node. Derived class may
- * override this factory method.
- *
- * @param select Select node
- * @param enclosingNode Enclosing node
- * @return Select namespace
- */
- protected SelectNamespace createSelectNamespace(
- SqlSelect select,
- SqlNode enclosingNode) {
- return new SelectNamespace(this, select, enclosingNode);
- }
-
- /**
- * Creates a namespace for a set operation (UNION
,
- * INTERSECT
, or EXCEPT
). Derived class may override
- * this factory method.
- *
- * @param call Call to set operation
- * @param enclosingNode Enclosing node
- * @return Set operation namespace
- */
- protected SetopNamespace createSetopNamespace(
- SqlCall call,
- SqlNode enclosingNode) {
- return new SetopNamespace(this, call, enclosingNode);
- }
-
/**
* Registers a query in a parent scope.
*
@@ -2630,7 +2586,7 @@ private void registerQuery(
case SELECT:
final SqlSelect select = (SqlSelect) node;
final SelectNamespace selectNs =
- createSelectNamespace(select, enclosingNode);
+ namespaceBuilder.createSelectNamespace(select, enclosingNode);
sqlQueryScopes.registerNamespace(usingScope, alias, selectNs, forceNullable);
final SqlValidatorScope windowParentScope =
first(usingScope, parentScope);
@@ -2799,9 +2755,8 @@ private void registerQuery(
case INSERT:
SqlInsert insertCall = (SqlInsert) node;
- InsertNamespace insertNs =
- new InsertNamespace(
- this,
+ DmlNamespace insertNs =
+ namespaceBuilder.createInsertNamespace(
insertCall,
enclosingNode,
parentScope);
@@ -2817,9 +2772,8 @@ private void registerQuery(
case DELETE:
SqlDelete deleteCall = (SqlDelete) node;
- DeleteNamespace deleteNs =
- new DeleteNamespace(
- this,
+ DmlNamespace deleteNs =
+ namespaceBuilder.createDeleteNamespace(
deleteCall,
enclosingNode,
parentScope);
@@ -2839,9 +2793,8 @@ private void registerQuery(
node.getParserPosition());
}
SqlUpdate updateCall = (SqlUpdate) node;
- UpdateNamespace updateNs =
- new UpdateNamespace(
- this,
+ DmlNamespace updateNs =
+ namespaceBuilder.createUpdate(
updateCall,
enclosingNode,
parentScope);
@@ -2858,9 +2811,8 @@ private void registerQuery(
case MERGE:
validateFeature(RESOURCE.sQLFeature_F312(), node.getParserPosition());
SqlMerge mergeCall = (SqlMerge) node;
- MergeNamespace mergeNs =
- new MergeNamespace(
- this,
+ DmlNamespace mergeNs =
+ namespaceBuilder.createMergeNamespace(
mergeCall,
enclosingNode,
parentScope);
@@ -2961,7 +2913,7 @@ private void registerSetop(
boolean forceNullable) {
SqlCall call = (SqlCall) node;
final SetopNamespace setopNamespace =
- createSetopNamespace(call, enclosingNode);
+ namespaceBuilder.createSetopNamespace(call, enclosingNode);
sqlQueryScopes.registerNamespace(usingScope, alias, setopNamespace, forceNullable);
// A setop is in the same scope as its parent.
@@ -6566,84 +6518,6 @@ private static boolean isSingleVarRequired(SqlKind kind) {
//~ Inner Classes ----------------------------------------------------------
- /**
- * Common base class for DML statement namespaces.
- */
- public static class DmlNamespace extends IdentifierNamespace {
- protected DmlNamespace(SqlValidatorImpl validator, SqlNode id,
- SqlNode enclosingNode, SqlValidatorScope parentScope) {
- super(validator, id, enclosingNode, parentScope);
- }
- }
-
- /**
- * Namespace for an INSERT statement.
- */
- private static class InsertNamespace extends DmlNamespace {
- private final SqlInsert node;
-
- InsertNamespace(SqlValidatorImpl validator, SqlInsert node,
- SqlNode enclosingNode, SqlValidatorScope parentScope) {
- super(validator, node.getTargetTable(), enclosingNode, parentScope);
- this.node = requireNonNull(node, "node");
- }
-
- @Override public @Nullable SqlNode getNode() {
- return node;
- }
- }
-
- /**
- * Namespace for an UPDATE statement.
- */
- private static class UpdateNamespace extends DmlNamespace {
- private final SqlUpdate node;
-
- UpdateNamespace(SqlValidatorImpl validator, SqlUpdate node,
- SqlNode enclosingNode, SqlValidatorScope parentScope) {
- super(validator, node.getTargetTable(), enclosingNode, parentScope);
- this.node = requireNonNull(node, "node");
- }
-
- @Override public @Nullable SqlNode getNode() {
- return node;
- }
- }
-
- /**
- * Namespace for a DELETE statement.
- */
- private static class DeleteNamespace extends DmlNamespace {
- private final SqlDelete node;
-
- DeleteNamespace(SqlValidatorImpl validator, SqlDelete node,
- SqlNode enclosingNode, SqlValidatorScope parentScope) {
- super(validator, node.getTargetTable(), enclosingNode, parentScope);
- this.node = requireNonNull(node, "node");
- }
-
- @Override public @Nullable SqlNode getNode() {
- return node;
- }
- }
-
- /**
- * Namespace for a MERGE statement.
- */
- private static class MergeNamespace extends DmlNamespace {
- private final SqlMerge node;
-
- MergeNamespace(SqlValidatorImpl validator, SqlMerge node,
- SqlNode enclosingNode, SqlValidatorScope parentScope) {
- super(validator, node.getTargetTable(), enclosingNode, parentScope);
- this.node = requireNonNull(node, "node");
- }
-
- @Override public @Nullable SqlNode getNode() {
- return node;
- }
- }
-
/** Visitor that retrieves pattern variables defined. */
private static class PatternVarVisitor implements SqlVisitor {
private final MatchRecognizeScope scope;
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
index ac038e3dae69..bab29921d536 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
@@ -58,6 +58,7 @@
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlTypeUtil;
+import org.apache.calcite.sql.validate.NamespaceBuilder.DmlNamespace;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.Litmus;
import org.apache.calcite.util.Pair;
@@ -124,9 +125,9 @@ private SqlValidatorUtil() {}
return getRelOptTable(tableNamespace,
requireNonNull(catalogReader, "catalogReader"), datasetName, usedDataset,
tableNamespace.extendedFields);
- } else if (namespace.isWrapperFor(SqlValidatorImpl.DmlNamespace.class)) {
- final SqlValidatorImpl.DmlNamespace dmlNamespace =
- namespace.unwrap(SqlValidatorImpl.DmlNamespace.class);
+ } else if (namespace.isWrapperFor(DmlNamespace.class)) {
+ final DmlNamespace dmlNamespace =
+ namespace.unwrap(DmlNamespace.class);
final SqlValidatorNamespace resolvedNamespace = dmlNamespace.resolve();
if (resolvedNamespace.isWrapperFor(TableNamespace.class)) {
final TableNamespace tableNamespace = resolvedNamespace.unwrap(TableNamespace.class);
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 23a8af7e81c2..50771d0a9d5a 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -163,6 +163,7 @@
import org.apache.calcite.sql.validate.ListScope;
import org.apache.calcite.sql.validate.MatchRecognizeScope;
import org.apache.calcite.sql.validate.MeasureScope;
+import org.apache.calcite.sql.validate.NamespaceBuilder.DmlNamespace;
import org.apache.calcite.sql.validate.ParameterScope;
import org.apache.calcite.sql.validate.SelectScope;
import org.apache.calcite.sql.validate.SqlLambdaScope;
@@ -4112,8 +4113,8 @@ public RelNode toRel(final RelOptTable table, final List hints) {
protected RelOptTable getTargetTable(SqlNode call) {
final SqlValidatorNamespace targetNs = getNamespace(call);
SqlValidatorNamespace namespace;
- if (targetNs.isWrapperFor(SqlValidatorImpl.DmlNamespace.class)) {
- namespace = targetNs.unwrap(SqlValidatorImpl.DmlNamespace.class);
+ if (targetNs.isWrapperFor(DmlNamespace.class)) {
+ namespace = targetNs.unwrap(DmlNamespace.class);
} else {
namespace = targetNs.resolve();
}