Skip to content

Commit

Permalink
[CALCITE-6574] SqlValidatorImpl Refactor: SqlQueryScopes
Browse files Browse the repository at this point in the history
Adding SqlQueryScopes to encapsulate the data for resolving
SqlNode to SqlValidatorScope.  Shift the api for resolving
scopes from SqlValidator to SqlQueryScopes.
  • Loading branch information
jamesstarr committed Sep 10, 2024
1 parent 67405c3 commit ae1c576
Show file tree
Hide file tree
Showing 17 changed files with 574 additions and 397 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,11 @@ private void registerId(SqlIdentifier id, SqlValidatorScope scope) {

@Override protected void validateOver(SqlCall call, SqlValidatorScope scope) {
try {
final OverScope overScope = (OverScope) getOverScope(call);
final OverScope overScope = (OverScope) getSqlQueryScopes().getOverScope(call);
final SqlNode relation = call.operand(0);
validateFrom(relation, unknownType, scope);
final SqlNode window = call.operand(1);
SqlValidatorScope opScope = scopes.get(relation);
SqlValidatorScope opScope = getSqlQueryScopes().getScope(relation);
if (opScope == null) {
opScope = overScope;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1732,7 +1732,7 @@ private static class LambdaFamilyOperandTypeChecker
&& !argFamilies.stream().allMatch(f -> f == SqlTypeFamily.ANY)) {
// Replace the parameter types in the lambda expression.
final SqlLambdaScope scope =
(SqlLambdaScope) validator.getLambdaScope(lambdaExpr);
(SqlLambdaScope) validator.getSqlQueryScopes().getLambdaScope(lambdaExpr);
for (int i = 0; i < argFamilies.size(); i++) {
final SqlNode param = lambdaExpr.getParameters().get(i);
final RelDataType type =
Expand Down Expand Up @@ -1794,7 +1794,7 @@ private static class LambdaRelOperandTypeChecker
// Replace the parameter types in the lambda expression.
final SqlValidator validator = callBinding.getValidator();
final SqlLambdaScope scope =
(SqlLambdaScope) validator.getLambdaScope(lambdaExpr);
(SqlLambdaScope) validator.getSqlQueryScopes().getLambdaScope(lambdaExpr);
for (int i = 0; i < argTypes.size(); i++) {
final SqlNode param = lambdaExpr.getParameters().get(i);
final RelDataType type = argTypes.get(i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ && isMeasureExp(id)) {
if (scope instanceof AggregatingSelectScope) {
final SqlSelect select = (SqlSelect) scope.getNode();
SelectScope selectScope =
requireNonNull(validator.getRawSelectScope(select),
requireNonNull(validator.getSqlQueryScopes().getRawSelectScope(select),
() -> "rawSelectScope for " + scope.getNode());
List<SqlNode> selectList =
requireNonNull(selectScope.getExpandedSelectList(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,9 @@ protected void addColumnNames(

@Override public SqlValidatorScope getOperandScope(SqlCall call) {
if (call instanceof SqlSelect) {
return validator.getSelectScope((SqlSelect) call);
return validator.getSqlQueryScopes().getSelectScope((SqlSelect) call);
} else if (call instanceof SqlLambda) {
return validator.getLambdaScope((SqlLambda) call);
return validator.getSqlQueryScopes().getLambdaScope((SqlLambda) call);
}
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public class OrderByScope extends DelegatingScope {
if (field != null) {
return field.getType();
}
final SqlValidatorScope selectScope = validator.getSelectScope(select);
final SqlValidatorScope selectScope = validator.getSqlQueryScopes().getSelectScope(select);
return selectScope.resolveColumn(name, ctx);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ public SelectNamespace(
final RelDataType rowType = this.getRowTypeSansSystemColumns();
final int field = SqlTypeUtil.findField(rowType, columnName);
SelectScope selectScope =
requireNonNull(validator.getRawSelectScope(select),
requireNonNull(validator.getSqlQueryScopes().getRawSelectScope(select),
() -> "rawSelectScope for " + select);
final SqlNode selectItem =
requireNonNull(selectScope.getExpandedSelectList(),
() -> "expandedSelectList for selectScope of " + select).get(field);
return validator.getSelectScope(select).getMonotonicity(selectItem);
return validator.getSqlQueryScopes().getSelectScope(select).getMonotonicity(selectItem);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ private static SqlMonotonicity combine(@Nullable SqlMonotonicity m0,
case INTERSECT:
case EXCEPT:
final SqlValidatorScope scope =
requireNonNull(validator.scopes.get(call),
requireNonNull(validator.getSqlQueryScopes().getScope(call),
() -> "scope for " + call);
for (SqlNode operand : call.getOperandList()) {
if (!operand.isA(SqlKind.QUERY)) {
Expand Down
227 changes: 227 additions & 0 deletions core/src/main/java/org/apache/calcite/sql/validate/SqlQueryScopes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/*
* 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.SqlLambda;
import org.apache.calcite.sql.SqlMatchRecognize;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.util.Util;

import org.checkerframework.checker.nullness.qual.Nullable;

/**
* Contains mapping of SqlNodes to SqlValidatorScope.
*
* <p>The methods {@link #getSelectScope}, {@link #getFromScope},
* {@link #getWhereScope}, {@link #getGroupScope}, {@link #getHavingScope},
* {@link #getOrderScope} and {@link #getJoinScope} get the correct scope
* to resolve names in a particular clause of a SQL statement.
*/
public interface SqlQueryScopes {
SqlValidatorScope getCursorScope(SqlSelect select);

/**
* Returns a scope containing the objects visible from the FROM clause of a
* query.
*
* @param select SELECT statement
* @return naming scope for FROM clause
*/
SqlValidatorScope getFromScope(SqlSelect select);

/**
* Returns a scope containing the objects visible from the GROUP BY clause
* of a query.
*
* @param select SELECT statement
* @return naming scope for GROUP BY clause
*/
SqlValidatorScope getGroupScope(SqlSelect select);

/**
* Returns a scope containing the objects visible from the HAVING clause of
* a query.
*
* @param select SELECT statement
* @return naming scope for HAVING clause
*/
SqlValidatorScope getHavingScope(SqlSelect select);

/**
* Returns a scope containing the objects visible from the ON and USING
* sections of a JOIN clause.
*
* @param node The item in the FROM clause which contains the ON or USING
* expression
* @return naming scope for JOIN clause
* @see #getFromScope
*/
SqlValidatorScope getJoinScope(SqlNode node);

/**
* Returns the lambda expression scope.
*
* @param node Lambda expression
* @return naming scope for lambda expression
*/
SqlValidatorScope getLambdaScope(SqlLambda node);

/**
* Returns a scope match recognize clause.
*
* @param node Match recognize
* @return naming scope for Match recognize clause
*/
SqlValidatorScope getMatchRecognizeScope(SqlMatchRecognize node);

SqlValidatorScope getMeasureScope(SqlSelect select);

/**
* Returns the scope that expressions in the SELECT and HAVING clause of
* this query should use. This scope consists of the FROM clause and the
* enclosing scope. If the query is aggregating, only columns in the GROUP
* BY clause may be used.
*
* @param select SELECT statement
* @return naming scope for ORDER BY clause
*/
SqlValidatorScope getOrderScope(SqlSelect select);

/**
* Returns the scope of an OVER or VALUES node.
*
* @param node Node
* @return Scope
*/
SqlValidatorScope getOverScope(SqlNode node);

/**
* Returns the appropriate scope for validating a particular clause of a
* SELECT statement.
*
* <p>Consider
*
* <blockquote><pre><code>SELECT *
* FROM foo
* WHERE EXISTS (
* SELECT deptno AS x
* FROM emp
* JOIN dept ON emp.deptno = dept.deptno
* WHERE emp.deptno = 5
* GROUP BY deptno
* ORDER BY x)</code></pre></blockquote>
*
* <p>What objects can be seen in each part of the sub-query?
*
* <ul>
* <li>In FROM ({@link #getFromScope} , you can only see 'foo'.
*
* <li>In WHERE ({@link #getWhereScope}), GROUP BY ({@link #getGroupScope}),
* SELECT ({@code getSelectScope}), and the ON clause of the JOIN
* ({@link #getJoinScope}) you can see 'emp', 'dept', and 'foo'.
*
* <li>In ORDER BY ({@link #getOrderScope}), you can see the column alias 'x';
* and tables 'emp', 'dept', and 'foo'.
*
* </ul>
*
* @param select SELECT statement
* @return naming scope for SELECT statement
*/
SqlValidatorScope getSelectScope(SqlSelect select);
/**
* Returns the scope that expressions in the WHERE and GROUP BY clause of
* this query should use. This scope consists of the tables in the FROM
* clause, and the enclosing scope.
*
* @param select Query
* @return naming scope of WHERE clause
*/
SqlValidatorScope getWhereScope(SqlSelect select);
SqlValidatorScope getWithScope(SqlNode withItem);

SqlValidatorScope getScopeOrThrow(SqlNode node);

SqlValidatorScope getScope(SqlNode sqlNode);

SelectScope getRawSelectScopeNonNull(SqlSelect select);

@Nullable
TableScope getTableScope();


/**
* Returns the scope for resolving the SELECT, GROUP BY and HAVING clauses.
* Always a {@link SelectScope}; if this is an aggregation query, the
* {@link AggregatingScope} is stripped away.
*
* @param select SELECT statement
* @return naming scope for SELECT statement, sans any aggregating scope
*/
@Nullable SelectScope getRawSelectScope(SqlSelect select);


/** Allows {@link SqlQueryScopesImpl#clauseScopes} to have multiple values per SELECT. */
enum Clause {
WHERE,
GROUP_BY,
SELECT,
MEASURE,
ORDER,
CURSOR,
HAVING,
QUALIFY;

/**
* Determines if the extender should replace aliases with expanded values.
* For example:
*
* <blockquote><pre>{@code
* SELECT a + a as twoA
* GROUP BY twoA
* }</pre></blockquote>
*
* <p>turns into
*
* <blockquote><pre>{@code
* SELECT a + a as twoA
* GROUP BY a + a
* }</pre></blockquote>
*
* <p>This is determined both by the clause and the config.
*
* @param config The configuration
* @return Whether we should replace the alias with its expanded value
*/
public boolean shouldReplaceAliases(SqlValidator.Config config) {
switch (this) {
case GROUP_BY:
return config.conformance().isGroupByAlias();

case HAVING:
return config.conformance().isHavingAlias();

case QUALIFY:
return true;

default:
throw Util.unexpected(this);
}
}
}
}
Loading

0 comments on commit ae1c576

Please sign in to comment.