SqlValidator.java

/*
 * 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.config.NullCollation;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rel.type.TimeFrame;
import org.apache.calcite.rel.type.TimeFrameSet;
import org.apache.calcite.runtime.CalciteContextException;
import org.apache.calcite.runtime.CalciteException;
import org.apache.calcite.runtime.Resources;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlDataTypeSpec;
import org.apache.calcite.sql.SqlDelete;
import org.apache.calcite.sql.SqlDynamicParam;
import org.apache.calcite.sql.SqlFunction;
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlInsert;
import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.SqlLambda;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlMatchRecognize;
import org.apache.calcite.sql.SqlMerge;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlOperatorTable;
import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.sql.SqlUpdate;
import org.apache.calcite.sql.SqlWindow;
import org.apache.calcite.sql.SqlWith;
import org.apache.calcite.sql.SqlWithItem;
import org.apache.calcite.sql.type.SqlTypeCoercionRule;
import org.apache.calcite.sql.type.SqlTypeMappingRule;
import org.apache.calcite.sql.validate.implicit.TypeCoercion;
import org.apache.calcite.sql.validate.implicit.TypeCoercionFactory;
import org.apache.calcite.sql.validate.implicit.TypeCoercions;

import org.apiguardian.api.API;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.qual.Pure;
import org.immutables.value.Value;

import java.util.List;
import java.util.Map;
import java.util.function.UnaryOperator;

/**
 * Validates the parse tree of a SQL statement, and provides semantic
 * information about the parse tree.
 *
 * <p>To create an instance of the default validator implementation, call
 * {@link SqlValidatorUtil#newValidator}.
 *
 * <h2>Visitor pattern</h2>
 *
 * <p>The validator interface is an instance of the
 * {@link org.apache.calcite.util.Glossary#VISITOR_PATTERN visitor pattern}.
 * Implementations
 * of the {@link SqlNode#validate} method call the <code>validateXxx</code>
 * method appropriate to the kind of node:
 * <ul>
 * <li>{@link SqlLiteral#validate(SqlValidator, SqlValidatorScope)}
 *     calls
 *     {@link #validateLiteral(org.apache.calcite.sql.SqlLiteral)};
 * <li>{@link SqlCall#validate(SqlValidator, SqlValidatorScope)}
 *     calls
 *     {@link #validateCall(SqlCall, SqlValidatorScope)};
 * <li>and so forth.</ul>
 *
 * <p>The {@link SqlNode#validateExpr(SqlValidator, SqlValidatorScope)} method
 * is as {@link SqlNode#validate(SqlValidator, SqlValidatorScope)} but is called
 * when the node is known to be a scalar expression.
 *
 * <h2>Scopes and namespaces</h2>
 *
 * <p>In order to resolve names to objects, the validator builds a map of the
 * structure of the query. This map consists of two types of objects. A
 * {@link SqlValidatorScope} describes the tables and columns accessible at a
 * particular point in the query; and a {@link SqlValidatorNamespace} is a
 * description of a data source used in a query.
 *
 * <p>There are different kinds of namespace for different parts of the query.
 * for example {@link IdentifierNamespace} for table names,
 * {@link SelectNamespace} for SELECT queries,
 * {@link SetopNamespace} for UNION, EXCEPT
 * and INTERSECT. A validator is allowed to wrap namespaces in other objects
 * which implement {@link SqlValidatorNamespace}, so don't try to cast your
 * namespace or use <code>instanceof</code>; use
 * {@link SqlValidatorNamespace#unwrap(Class)} and
 * {@link SqlValidatorNamespace#isWrapperFor(Class)} instead.
 *
 * <p>The validator builds the map by making a quick scan over the query when
 * the root {@link SqlNode} is first provided. Thereafter, it supplies the
 * correct scope or namespace object when it calls validation methods.
 *
 * <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.
 */
@Value.Enclosing
public interface SqlValidator {
  //~ Methods ----------------------------------------------------------------

  /**
   * Returns the catalog reader used by this validator.
   *
   * @return catalog reader
   */
  @Pure
  SqlValidatorCatalogReader getCatalogReader();

  /**
   * Returns the operator table used by this validator.
   *
   * @return operator table
   */
  @Pure
  SqlOperatorTable getOperatorTable();

  /**
   * Validates an expression tree. You can call this method multiple times,
   * but not reentrantly.
   *
   * @param topNode top of expression tree to be validated
   * @return validated tree (possibly rewritten)
   */
  SqlNode validate(SqlNode topNode);

  /**
   * Validates an expression tree. You can call this method multiple times,
   * but not reentrantly.
   *
   * @param topNode       top of expression tree to be validated
   * @param nameToTypeMap map of simple name to {@link RelDataType}; used to
   *                      resolve {@link SqlIdentifier} references
   * @return validated tree (possibly rewritten)
   */
  SqlNode validateParameterizedExpression(
      SqlNode topNode,
      Map<String, RelDataType> nameToTypeMap);

  /**
   * Checks that a query is valid.
   *
   * <p>Valid queries include:
   *
   * <ul>
   * <li><code>SELECT</code> statement,
   * <li>set operation (<code>UNION</code>, <code>INTERSECT</code>, <code>
   * EXCEPT</code>)
   * <li>identifier (e.g. representing use of a table in a FROM clause)
   * <li>query aliased with the <code>AS</code> operator
   * </ul>
   *
   * @param node  Query node
   * @param scope Scope in which the query occurs
   * @param targetRowType Desired row type, must not be null, may be the data
   *                      type 'unknown'.
   * @throws RuntimeException if the query is not valid
   */
  void validateQuery(SqlNode node, SqlValidatorScope scope,
      RelDataType targetRowType);

  /**
   * Returns the type assigned to a node by validation.
   *
   * @param node the node of interest
   * @return validated type, never null
   */
  RelDataType getValidatedNodeType(SqlNode node);

  /**
   * Returns the type assigned to a node by validation, or null if unknown.
   * This allows for queries against nodes such as aliases, which have no type
   * of their own. If you want to assert that the node of interest must have a
   * type, use {@link #getValidatedNodeType} instead.
   *
   * @param node the node of interest
   * @return validated type, or null if unknown or not applicable
   */
  @Nullable RelDataType getValidatedNodeTypeIfKnown(SqlNode node);

  /**
   * Returns the types of a call's operands.
   *
   * <p>Returns null if the call has not been validated, or if the operands'
   * types do not differ from their types as expressions.
   *
   * <p>This method is most useful when some of the operands are of type ANY,
   * or if they need to be coerced to be consistent with other operands, or
   * with the needs of the function.
   *
   * @param call Call
   * @return List of operands' types, or null if not known or 'obvious'
   */
  @Nullable List<RelDataType> getValidatedOperandTypes(SqlCall call);

  /**
   * Resolves an identifier to a fully-qualified name.
   *
   * @param id    Identifier
   * @param scope Naming scope
   */
  void validateIdentifier(SqlIdentifier id, SqlValidatorScope scope);

  /**
   * Validates a literal.
   *
   * @param literal Literal
   */
  void validateLiteral(SqlLiteral literal);

  /**
   * Validates a {@link SqlIntervalQualifier}.
   *
   * @param qualifier Interval qualifier
   */
  void validateIntervalQualifier(SqlIntervalQualifier qualifier);

  /**
   * Validates an INSERT statement.
   *
   * @param insert INSERT statement
   */
  void validateInsert(SqlInsert insert);

  /**
   * Validates an UPDATE statement.
   *
   * @param update UPDATE statement
   */
  void validateUpdate(SqlUpdate update);

  /**
   * Validates a DELETE statement.
   *
   * @param delete DELETE statement
   */
  void validateDelete(SqlDelete delete);

  /**
   * Validates a MERGE statement.
   *
   * @param merge MERGE statement
   */
  void validateMerge(SqlMerge merge);

  /**
   * Validates a data type expression.
   *
   * @param dataType Data type
   */
  void validateDataType(SqlDataTypeSpec dataType);

  /**
   * Validates a dynamic parameter.
   *
   * @param dynamicParam Dynamic parameter
   */
  void validateDynamicParam(SqlDynamicParam dynamicParam);

  /**
   * Validates the right-hand side of an OVER expression. It might be either
   * an {@link SqlIdentifier identifier} referencing a window, or an
   * {@link SqlWindow inline window specification}.
   *
   * @param windowOrId SqlNode that can be either SqlWindow with all the
   *                   components of a window spec or a SqlIdentifier with the
   *                   name of a window spec.
   * @param scope      Naming scope
   * @param call       the SqlNode if a function call if the window is attached
   *                   to one.
   */
  void validateWindow(
      SqlNode windowOrId,
      SqlValidatorScope scope,
      @Nullable SqlCall call);

  /**
   * Validates a MATCH_RECOGNIZE clause.
   *
   * @param pattern MATCH_RECOGNIZE clause
   */
  void validateMatchRecognize(SqlCall pattern);

  /**
   * Validates a lambda expression. lambda expression will be validated twice
   * during the validation process. The first time is validate lambda expression
   * namespace, the second time is when validating higher order function operands
   * type check.
   *
   * @param lambdaExpr Lambda expression
   */
  void validateLambda(SqlLambda lambdaExpr);

  /**
   * Validates a call to an operator.
   *
   * @param call  Operator call
   * @param scope Naming scope
   */
  void validateCall(
      SqlCall call,
      SqlValidatorScope scope);

  /**
   * Validates parameters for aggregate function.
   *
   * @param aggCall      Call to aggregate function
   * @param filter       Filter ({@code FILTER (WHERE)} clause), or null
   * @param distinctList Distinct specification ({@code WITHIN DISTINCT}
   *                     clause), or null
   * @param orderList    Ordering specification ({@code WITHIN GROUP} clause),
   *                     or null
   * @param scope        Syntactic scope
   */
  void validateAggregateParams(SqlCall aggCall, @Nullable SqlNode filter,
      @Nullable SqlNodeList distinctList, @Nullable SqlNodeList orderList,
      SqlValidatorScope scope);

  /**
   * If an identifier is a legitimate call to a function that has no
   * arguments and requires no parentheses (for example "CURRENT_USER"),
   * returns a call to that function, otherwise returns null.
   */
  @Nullable SqlCall makeNullaryCall(SqlIdentifier id);

  /**
   * Derives the type of a node in a given scope. If the type has already been
   * inferred, returns the previous type.
   *
   * @param scope   Syntactic scope
   * @param operand Parse tree node
   * @return Type of the SqlNode. Should never return <code>NULL</code>
   */
  RelDataType deriveType(
      SqlValidatorScope scope,
      SqlNode operand);

  /**
   * Adds "line x, column y" context to a validator exception.
   *
   * <p>Note that the input exception is checked (it derives from
   * {@link Exception}) and the output exception is unchecked (it derives from
   * {@link RuntimeException}). This is intentional -- it should remind code
   * authors to provide context for their validation errors.
   *
   * @param node The place where the exception occurred, not null
   * @param e    The validation error
   * @return Exception containing positional information, never null
   */
  CalciteContextException newValidationError(
      SqlNode node,
      Resources.ExInst<SqlValidatorException> e);

  /**
   * Returns whether a SELECT statement is an aggregation. Criteria are: (1)
   * contains GROUP BY, or (2) contains HAVING, or (3) SELECT or ORDER BY
   * clause contains aggregate functions. (Windowed aggregate functions, such
   * as <code>SUM(x) OVER w</code>, don't count.)
   *
   * @param select SELECT statement
   * @return whether SELECT statement is an aggregation
   */
  boolean isAggregate(SqlSelect select);

  /**
   * Returns whether a select list expression is an aggregate function.
   *
   * @param selectNode Expression in SELECT clause
   * @return whether expression is an aggregate function
   */
  @Deprecated // to be removed before 2.0
  boolean isAggregate(SqlNode selectNode);

  /**
   * Converts a window specification or window name into a fully-resolved
   * window specification. For example, in <code>SELECT sum(x) OVER (PARTITION
   * BY x ORDER BY y), sum(y) OVER w1, sum(z) OVER (w ORDER BY y) FROM t
   * WINDOW w AS (PARTITION BY x)</code> all aggregations have the same
   * resolved window specification <code>(PARTITION BY x ORDER BY y)</code>.
   *
   * @param windowOrRef    Either the name of a window (a {@link SqlIdentifier})
   *                       or a window specification (a {@link SqlWindow}).
   * @param scope          Scope in which to resolve window names
   * @return A window
   * @throws RuntimeException Validation exception if window does not exist
   */
  SqlWindow resolveWindow(
      SqlNode windowOrRef,
      SqlValidatorScope scope);

  /**
   * Converts a window specification or window name into a fully-resolved
   * window specification.
   *
   * @deprecated Use {@link #resolveWindow(SqlNode, SqlValidatorScope)}, which
   * does not have the deprecated {@code populateBounds} parameter.
   *
   * @param populateBounds Whether to populate bounds. Doing so may alter the
   *                       definition of the window. It is recommended that
   *                       populate bounds when translating to physical algebra,
   *                       but not when validating.
   */
  @Deprecated // to be removed before 2.0
  default SqlWindow resolveWindow(
      SqlNode windowOrRef,
      SqlValidatorScope scope,
      boolean populateBounds) {
    return resolveWindow(windowOrRef, scope);
  };

  /**
   * Finds the namespace corresponding to a given node.
   *
   * <p>For example, in the query <code>SELECT * FROM (SELECT * FROM t), t1 AS
   * alias</code>, the both items in the FROM clause have a corresponding
   * namespace.
   *
   * @param node Parse tree node
   * @return namespace of node
   */
  @Nullable SqlValidatorNamespace getNamespace(SqlNode node);

  /**
   * Derives an alias for an expression. If no alias can be derived, returns
   * null if <code>ordinal</code> is less than zero, otherwise generates an
   * alias <code>EXPR$<i>ordinal</i></code>.
   *
   * @param node    Expression
   * @param ordinal Ordinal of expression
   * @return derived alias, or null if no alias can be derived and ordinal is
   * less than zero
   */
  @Nullable String deriveAlias(
      SqlNode node,
      int ordinal);

  /**
   * Returns a list of expressions, with every occurrence of "&#42;" or
   * "TABLE.&#42;" expanded.
   *
   * @param selectList        Select clause to be expanded
   * @param query             Query
   * @param includeSystemVars Whether to include system variables
   * @return expanded select clause
   */
  SqlNodeList expandStar(SqlNodeList selectList, SqlSelect query,
      boolean includeSystemVars);

  /**
   * 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 getMeasureScope(SqlSelect select);

  /**
   * Returns the type factory used by this validator.
   *
   * @return type factory
   */
  @Pure
  RelDataTypeFactory getTypeFactory();

  /**
   * Saves the type of a {@link SqlNode}, now that it has been validated.
   *
   * <p>This method is only for internal use. The validator should drive the
   * type-derivation process, and store nodes' types when they have been derived.
   *
   * @param node A SQL parse tree node, never null
   * @param type Its type; must not be null
   */
  @API(status = API.Status.INTERNAL, since = "1.24")
  void setValidatedNodeType(SqlNode node, RelDataType type);

  /**
   * Removes a node from the set of validated nodes.
   *
   * @param node node to be removed
   */
  void removeValidatedNodeType(SqlNode node);

  /**
   * Returns an object representing the "unknown" type.
   *
   * @return unknown type
   */
  RelDataType getUnknownType();

  /**
   * 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 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);

  /**
   * 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 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 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 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 a scope match recognize clause.
   *
   * @param node Match recognize
   * @return naming scope for Match recognize clause
   */
  SqlValidatorScope getMatchRecognizeScope(SqlMatchRecognize node);

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

  /**
   * Returns a scope that cannot see anything.
   */
  SqlValidatorScope getEmptyScope();

  /**
   * Declares a SELECT expression as a cursor.
   *
   * @param select select expression associated with the cursor
   * @param scope  scope of the parent query associated with the cursor
   */
  void declareCursor(SqlSelect select, SqlValidatorScope scope);

  /**
   * Pushes a new instance of a function call on to a function call stack.
   */
  void pushFunctionCall();

  /**
   * Removes the topmost entry from the function call stack.
   */
  void popFunctionCall();

  /**
   * Retrieves the name of the parent cursor referenced by a column list
   * parameter.
   *
   * @param columnListParamName name of the column list parameter
   * @return name of the parent cursor
   */
  @Nullable String getParentCursor(String columnListParamName);

  /**
   * Derives the type of a constructor.
   *
   * @param scope                 Scope
   * @param call                  Call
   * @param unresolvedConstructor TODO
   * @param resolvedConstructor   TODO
   * @param argTypes              Types of arguments
   * @return Resolved type of constructor
   */
  RelDataType deriveConstructorType(
      SqlValidatorScope scope,
      SqlCall call,
      SqlFunction unresolvedConstructor,
      @Nullable SqlFunction resolvedConstructor,
      List<RelDataType> argTypes);

  /**
   * Handles a call to a function which cannot be resolved. Returns an
   * appropriately descriptive error, which caller must throw.
   *
   * @param call               Call
   * @param unresolvedFunction Overloaded function which is the target of the
   *                           call
   * @param argTypes           Types of arguments
   * @param argNames           Names of arguments, or null if call by position
   */
  CalciteException handleUnresolvedFunction(SqlCall call,
      SqlOperator unresolvedFunction, List<RelDataType> argTypes,
      @Nullable List<String> argNames);

  /**
   * Expands an expression in the ORDER BY clause into an expression with the
   * same semantics as expressions in the SELECT clause.
   *
   * <p>This is made necessary by a couple of dialect 'features':
   *
   * <ul>
   * <li><b>ordinal expressions</b>: In "SELECT x, y FROM t ORDER BY 2", the
   * expression "2" is shorthand for the 2nd item in the select clause, namely
   * "y".
   * <li><b>alias references</b>: In "SELECT x AS a, y FROM t ORDER BY a", the
   * expression "a" is shorthand for the item in the select clause whose alias
   * is "a"
   * </ul>
   *
   * @param select    Select statement which contains ORDER BY
   * @param orderExpr Expression in the ORDER BY clause.
   * @return Expression translated into SELECT clause semantics
   */
  SqlNode expandOrderExpr(SqlSelect select, SqlNode orderExpr);

  /**
   * Expands an expression.
   *
   * @param expr  Expression
   * @param scope Scope
   * @return Expanded expression
   */
  SqlNode expand(SqlNode expr, SqlValidatorScope scope);

  /** Resolves a literal.
   *
   * <p>Usually returns the literal unchanged, but if the literal is of type
   * {@link org.apache.calcite.sql.type.SqlTypeName#UNKNOWN} looks up its type
   * and converts to the appropriate literal subclass. */
  SqlLiteral resolveLiteral(SqlLiteral literal);

  /**
   * Returns whether a field is a system field. Such fields may have
   * particular properties such as sortedness and nullability.
   *
   * <p>In the default implementation, always returns {@code false}.
   *
   * @param field Field
   * @return whether field is a system field
   */
  boolean isSystemField(RelDataTypeField field);

  /**
   * Returns a description of how each field in the row type maps to a
   * catalog, schema, table and column in the schema.
   *
   * <p>The returned list is never null, and has one element for each field
   * in the row type. Each element is a list of four elements (catalog,
   * schema, table, column), or may be null if the column is an expression.
   *
   * @param sqlQuery Query
   * @return Description of how each field in the row type maps to a schema
   * object
   */
  List<@Nullable List<String>> getFieldOrigins(SqlNode sqlQuery);

  /**
   * Returns a record type that contains the name and type of each parameter.
   * Returns a record type with no fields if there are no parameters.
   *
   * @param sqlQuery Query
   * @return Record type
   */
  RelDataType getParameterRowType(SqlNode sqlQuery);

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

  /**
   * Validates that a query is capable of producing a return of given modality
   * (relational or streaming).
   *
   * @param select Query
   * @param modality Modality (streaming or relational)
   * @param fail Whether to throw a user error if does not support required
   *             modality
   * @return whether query supports the given modality
   */
  boolean validateModality(SqlSelect select, SqlModality modality,
      boolean fail);

  void validateWith(SqlWith with, SqlValidatorScope scope);

  void validateWithItem(SqlWithItem withItem);

  void validateSequenceValue(SqlValidatorScope scope, SqlIdentifier id);

  SqlValidatorScope getWithScope(SqlNode withItem);

  /** Get the type coercion instance. */
  TypeCoercion getTypeCoercion();

  /** Returns the type mapping rule. */
  default SqlTypeMappingRule getTypeMappingRule() {
    return config().conformance().allowLenientCoercion()
        ? SqlTypeCoercionRule.lenientInstance()
        : SqlTypeCoercionRule.instance();
  }

  /** Returns the config of the validator. */
  Config config();

  /**
   * Returns this SqlValidator, with the same state, applying
   * a transform to the config.
   *
   * <p>This is mainly used for tests, otherwise constructs a {@link Config} directly
   * through the constructor.
   */
  @API(status = API.Status.INTERNAL, since = "1.23")
  SqlValidator transform(UnaryOperator<SqlValidator.Config> transform);

  /** Returns the set of allowed time frames. */
  TimeFrameSet getTimeFrameSet();

  /** Validates a time frame.
   *
   * <p>A time frame is either a built-in time frame based on a time unit such
   * as {@link org.apache.calcite.avatica.util.TimeUnitRange#HOUR},
   * or is a custom time frame represented by a name in
   * {@link SqlIntervalQualifier#timeFrameName}. A custom time frame is
   * validated against {@link #getTimeFrameSet()}.
   *
   * <p>Returns a time frame, or throws.
   */
  TimeFrame validateTimeFrame(SqlIntervalQualifier intervalQualifier);

  //~ Inner Class ------------------------------------------------------------

  /**
   * Interface to define the configuration for a SqlValidator.
   * Provides methods to set each configuration option.
   */
  @Value.Immutable(singleton = false)
  interface Config {
    /** Default configuration. */
    SqlValidator.Config DEFAULT = ImmutableSqlValidator.Config.builder()
        .withTypeCoercionFactory(TypeCoercions::createTypeCoercion)
        .build();

    /**
     * Returns whether to enable rewrite of "macro-like" calls such as COALESCE.
     */
    @Value.Default default boolean callRewrite() {
      return true;
    }

    /**
     * Sets whether to enable rewrite of "macro-like" calls such as COALESCE.
     */
    Config withCallRewrite(boolean rewrite);

    /** Returns how NULL values should be collated if an ORDER BY item does not
     * contain NULLS FIRST or NULLS LAST. */
    @Value.Default default NullCollation defaultNullCollation() {
      return NullCollation.HIGH;
    }

    /** Sets how NULL values should be collated if an ORDER BY item does not
     * contain NULLS FIRST or NULLS LAST. */
    Config withDefaultNullCollation(NullCollation nullCollation);

    /** Returns whether column reference expansion is enabled. */
    @Value.Default default boolean columnReferenceExpansion() {
      return true;
    }

    /**
     * Sets whether to enable expansion of column references. (Currently this does
     * not apply to the ORDER BY clause; may be fixed in the future.)
     */
    Config withColumnReferenceExpansion(boolean expand);

    /**
     * Returns whether to expand identifiers other than column
     * references.
     *
     * <p>REVIEW jvs 30-June-2006: subclasses may override shouldExpandIdentifiers
     * in a way that ignores this; we should probably get rid of the protected
     * method and always use this variable (or better, move preferences like
     * this to a separate "parameter" class).
     */
    @Value.Default default boolean identifierExpansion() {
      return false;
    }

    /**
     * Sets whether to enable expansion of identifiers other than column
     * references.
     */
    Config withIdentifierExpansion(boolean expand);

    /**
     * Returns whether to treat the query being validated as embedded
     * (as opposed to top-level).
     *
     * <p>The default, false, treats the query as top-level;
     * a value of true treats it as a query inside another, as would be the case
     * for a view or common table expression.
     *
     * <p>Possible behavior differences include ignoring the {@code ORDER BY}
     * clause of an embedded query, or converting measure expressions of a
     * non-embedded query into values. */
    @Value.Default default boolean embeddedQuery() {
      return false;
    }

    /**
     * Sets whether to treat the query being validated as embedded
     * (as opposed to top-level).
     */
    Config withEmbeddedQuery(boolean embedded);

    /**
     * Returns whether this validator should be lenient upon encountering an
     * unknown function, default false.
     *
     * <p>If true, if a statement contains a call to a function that is not
     * present in the operator table, or if the call does not have the required
     * number or types of operands, the validator nevertheless regards the
     * statement as valid. The type of the function call will be
     * {@link #getUnknownType() UNKNOWN}.
     *
     * <p>If false (the default behavior), an unknown function call causes a
     * validation error to be thrown.
     */
    @Value.Default default boolean lenientOperatorLookup() {
      return false;
    }

    /**
     * Sets whether this validator should be lenient upon encountering an unknown
     * function.
     *
     * @param lenient Whether to be lenient when encountering an unknown function
     */
    Config withLenientOperatorLookup(boolean lenient);

    /** Returns whether the validator allows measures to be used without
     * AGGREGATE function in a non-aggregate query. Default is true.
     */
    @Value.Default default boolean nakedMeasuresInNonAggregateQuery() {
      return true;
    }

    /** Sets whether the validator allows measures to be used without AGGREGATE
     * function in a non-aggregate query.
     */
    Config withNakedMeasuresInNonAggregateQuery(boolean value);

    /** Returns whether the validator allows measures to be used without
     * AGGREGATE function in an aggregate query. Default is true.
     */
    @Value.Default default boolean nakedMeasuresInAggregateQuery() {
      return true;
    }

    /** Sets whether the validator allows measures to be used without AGGREGATE
     * function in an aggregate query.
     */
    Config withNakedMeasuresInAggregateQuery(boolean value);

    /** Sets whether the validator allows measures to be used without the
     * AGGREGATE function inside or outside aggregate queries.
     * Deprecated: use the inside / outside variants instead.
     */
    @Deprecated // to be removed before 1.38
    default Config withNakedMeasures(boolean nakedMeasures) {
      return withNakedMeasuresInAggregateQuery(nakedMeasures)
              .withNakedMeasuresInNonAggregateQuery(nakedMeasures);
    }

    /** Returns whether the validator supports implicit type coercion. */
    @Value.Default default boolean typeCoercionEnabled() {
      return true;
    }

    /**
     * Sets whether to enable implicit type coercion for validation, default true.
     *
     * @see org.apache.calcite.sql.validate.implicit.TypeCoercionImpl TypeCoercionImpl
     */
    Config withTypeCoercionEnabled(boolean enabled);

    /** Returns the type coercion factory. */
    TypeCoercionFactory typeCoercionFactory();

    /**
     * Sets a factory to create type coercion instance that overrides the
     * default coercion rules defined in
     * {@link org.apache.calcite.sql.validate.implicit.TypeCoercionImpl}.
     *
     * @param factory Factory to create {@link TypeCoercion} instance
     */
    Config withTypeCoercionFactory(TypeCoercionFactory factory);

    /** Returns the type coercion rules for explicit type coercion. */
    @Nullable SqlTypeCoercionRule typeCoercionRules();

    /**
     * Sets the {@link SqlTypeCoercionRule} instance which defines the type conversion matrix
     * for the explicit type coercion.
     *
     * <p>The {@code rules} setting should be thread safe. In the default implementation,
     * it is set to a ThreadLocal variable.
     *
     * @param rules The {@link SqlTypeCoercionRule} instance,
     *              see its documentation for how to customize the rules
     */
    Config withTypeCoercionRules(@Nullable SqlTypeCoercionRule rules);

    /** Returns the dialect of SQL (SQL:2003, etc.) this validator recognizes.
     * Default is {@link SqlConformanceEnum#DEFAULT}. */
    @Value.Default default SqlConformance conformance() {
      return SqlConformanceEnum.DEFAULT;
    }

    /** Returns the SQL conformance.
     *
     * @deprecated Use {@link #conformance()} */
    @Deprecated // to be removed before 2.0
    default SqlConformance sqlConformance() {
      return conformance();
    }

    /** Sets the SQL conformance of the validator. */
    Config withConformance(SqlConformance conformance);

    /** Sets the SQL conformance of the validator.
     *
     * @deprecated Use {@link #conformance()} */
    @Deprecated // to be removed before 2.0
    default Config withSqlConformance(SqlConformance conformance) {
      return withConformance(conformance);
    }
  }
}