Пример #1
0
/**
 * 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.
 */
public interface SqlValidator {
  /** Whether to follow the SQL standard strictly. */
  boolean STRICT = Util.getBooleanProperty("calcite.strict.sql");

  // ~ Methods ----------------------------------------------------------------

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

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

  /**
   * Returns the operator table used by this validator.
   *
   * @return operator table
   */
  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
   */
  RelDataType getValidatedNodeTypeIfKnown(SqlNode node);

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

  /**
   * 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 Function containing COLUMN_LIST parameter
   * @param filter Filter, or null
   * @param scope Syntactic scope
   */
  void validateAggregateParams(SqlCall aggCall, SqlNode filter, SqlValidatorScope scope);

  /**
   * Validates a COLUMN_LIST parameter
   *
   * @param function function containing COLUMN_LIST parameter
   * @param argTypes function arguments
   * @param operands operands passed into the function call
   */
  void validateColumnListParams(
      SqlFunction function, List<RelDataType> argTypes, List<SqlNode> operands);

  /**
   * 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
   * @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.
   * @return A window
   * @throws RuntimeException Validation exception if window does not exist
   */
  SqlWindow resolveWindow(SqlNode windowOrRef, SqlValidatorScope scope, boolean populateBounds);

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

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

  /**
   * Saves the type of a {@link SqlNode}, now that it has been validated.
   *
   * @param node A SQL parse tree node, never null
   * @param type Its type; must not be null
   * @deprecated This method should not be in the {@link SqlValidator} interface. The validator
   *     should drive the type-derivation process, and store nodes' types when they have been
   *     derived.
   */
  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
   */
  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);

  /**
   * 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
   */
  String getParentCursor(String columnListParamName);

  /**
   * Enables or disables expansion of identifiers other than column references.
   *
   * @param expandIdentifiers new setting
   */
  void setIdentifierExpansion(boolean expandIdentifiers);

  /**
   * Enables or disables expansion of column references. (Currently this does not apply to the ORDER
   * BY clause; may be fixed in the future.)
   *
   * @param expandColumnReferences new setting
   */
  void setColumnReferenceExpansion(boolean expandColumnReferences);

  /** @return whether column reference expansion is enabled */
  boolean getColumnReferenceExpansion();

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

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

  /**
   * Returns expansion of identifiers.
   *
   * @return whether this validator should expand identifiers
   */
  boolean shouldExpandIdentifiers();

  /**
   * Enables or disables rewrite of "macro-like" calls such as COALESCE.
   *
   * @param rewriteCalls new setting
   */
  void setCallRewrite(boolean rewriteCalls);

  /**
   * 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,
      SqlFunction resolvedConstructor,
      List<RelDataType> argTypes);

  /**
   * Handles a call to a function which cannot be resolved. Returns a 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,
      SqlFunction unresolvedFunction,
      List<RelDataType> argTypes,
      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);

  /**
   * 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<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);
}
Пример #2
0
/**
 * Created by amognm on 11/18/15.
 *
 * <p>Utility function for Planners RuleSet
 */
public class RuleSets {
  private RuleSets() {}

  public static final boolean COMMUTE = Util.getBooleanProperty("calcite.enable.join.commute");

  private static final ImmutableList<RelOptRule> DEFAULT_RULES =
      ImmutableList.of(
          AggStarRule.INSTANCE,
          AggStarRule.INSTANCE2,
          TableScanRule.INSTANCE,
          COMMUTE ? JoinAssociateRule.INSTANCE : ProjectMergeRule.INSTANCE,
          FilterTableScanRule.INSTANCE,
          ProjectFilterTransposeRule.INSTANCE,
          FilterProjectTransposeRule.INSTANCE,
          FilterJoinRule.FILTER_ON_JOIN,
          AggregateExpandDistinctAggregatesRule.INSTANCE,
          AggregateReduceFunctionsRule.INSTANCE,
          FilterAggregateTransposeRule.INSTANCE,
          JoinCommuteRule.INSTANCE,
          JoinPushThroughJoinRule.RIGHT,
          JoinPushThroughJoinRule.LEFT,
          SortProjectTransposeRule.INSTANCE);

  private static final List<RelOptRule> ENUMERABLE_RULES =
      ImmutableList.of(
          EnumerableRules.ENUMERABLE_JOIN_RULE,
          EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE,
          EnumerableRules.ENUMERABLE_SEMI_JOIN_RULE,
          EnumerableRules.ENUMERABLE_CORRELATE_RULE,
          EnumerableRules.ENUMERABLE_PROJECT_RULE,
          EnumerableRules.ENUMERABLE_FILTER_RULE,
          EnumerableRules.ENUMERABLE_AGGREGATE_RULE,
          EnumerableRules.ENUMERABLE_SORT_RULE,
          EnumerableRules.ENUMERABLE_LIMIT_RULE,
          EnumerableRules.ENUMERABLE_COLLECT_RULE,
          EnumerableRules.ENUMERABLE_UNCOLLECT_RULE,
          EnumerableRules.ENUMERABLE_UNION_RULE,
          EnumerableRules.ENUMERABLE_INTERSECT_RULE,
          EnumerableRules.ENUMERABLE_MINUS_RULE,
          EnumerableRules.ENUMERABLE_TABLE_MODIFICATION_RULE,
          EnumerableRules.ENUMERABLE_VALUES_RULE,
          EnumerableRules.ENUMERABLE_WINDOW_RULE,
          EnumerableRules.ENUMERABLE_TABLE_SCAN_RULE,
          EnumerableRules.ENUMERABLE_TABLE_FUNCTION_SCAN_RULE);

  /** Gets the default set of rules for planning process */
  public static RuleSet getDefaultRuleSet() {
    ImmutableList.Builder<RelOptRule> builder = ImmutableList.builder();
    builder.addAll(DEFAULT_RULES).addAll(ENUMERABLE_RULES);
    return new QuarkRuleSet(builder.build());
  }

  /** Quark's Rule Set which will be used for planning process */
  private static class QuarkRuleSet implements RuleSet {
    final ImmutableList<RelOptRule> rules;

    QuarkRuleSet(ImmutableList<RelOptRule> rules) {
      this.rules = rules;
    }

    @Override
    public Iterator<RelOptRule> iterator() {
      return rules.iterator();
    }
  }
}