Beispiel #1
0
  /**
   * Derives an alias for a node, and invents a mangled identifier if it cannot.
   *
   * <p>Examples:
   *
   * <ul>
   *   <li>Alias: "1 + 2 as foo" yields "foo"
   *   <li>Identifier: "foo.bar.baz" yields "baz"
   *   <li>Anything else yields "expr$<i>ordinal</i>"
   * </ul>
   *
   * @return An alias, if one can be derived; or a synthetic alias "expr$<i>ordinal</i>" if ordinal
   *     >= 0; otherwise null
   */
  public static String getAlias(SqlNode node, int ordinal) {
    switch (node.getKind()) {
      case AS:
        // E.g. "1 + 2 as foo" --> "foo"
        return ((SqlCall) node).getOperands()[1].toString();

      case OVER:
        // E.g. "bids over w" --> "bids"
        return getAlias(((SqlCall) node).getOperands()[0], ordinal);

      case IDENTIFIER:
        // E.g. "foo.bar" --> "bar"
        return Util.last(((SqlIdentifier) node).names);

      default:
        if (ordinal < 0) {
          return null;
        } else {
          return SqlUtil.deriveAliasFromOrdinal(ordinal);
        }
    }
  }
  private RelDataType deriveType(
      SqlValidator validator,
      SqlValidatorScope scope,
      SqlCall call,
      boolean convertRowArgToColumnList) {
    final SqlNode[] operands = call.operands;
    RelDataType[] argTypes = new RelDataType[operands.length];

    // Scope for operands. Usually the same as 'scope'.
    final SqlValidatorScope operandScope = scope.getOperandScope(call);

    // Indicate to the validator that we're validating a new function call
    validator.pushFunctionCall();

    try {
      boolean containsRowArg = false;
      for (int i = 0; i < operands.length; ++i) {
        RelDataType nodeType;

        // for row arguments that should be converted to ColumnList
        // types, set the nodeType to a ColumnList type but defer
        // validating the arguments of the row constructor until we know
        // for sure that the row argument maps to a ColumnList type
        if (operands[i].getKind() == SqlKind.ROW && convertRowArgToColumnList) {
          containsRowArg = true;
          RelDataTypeFactory typeFactory = validator.getTypeFactory();
          nodeType = typeFactory.createSqlType(SqlTypeName.COLUMN_LIST);
        } else {
          nodeType = validator.deriveType(operandScope, operands[i]);
        }
        validator.setValidatedNodeType(operands[i], nodeType);
        argTypes[i] = nodeType;
      }

      SqlFunction function =
          SqlUtil.lookupRoutine(
              validator.getOperatorTable(), getNameAsId(), argTypes, getFunctionType());

      // if we have a match on function name and parameter count, but
      // couldn't find a function with  a COLUMN_LIST type, retry, but
      // this time, don't convert the row argument to a COLUMN_LIST type;
      // if we did find a match, go back and revalidate the row operands
      // (corresponding to column references), now that we can set the
      // scope to that of the source cursor referenced by that ColumnList
      // type
      if (containsRowArg) {
        if ((function == null)
            && SqlUtil.matchRoutinesByParameterCount(
                validator.getOperatorTable(), getNameAsId(), argTypes, getFunctionType())) {
          // remove the already validated node types corresponding to
          // row arguments before revalidating
          for (SqlNode operand : operands) {
            if (operand.getKind() == SqlKind.ROW) {
              validator.removeValidatedNodeType(operand);
            }
          }
          return deriveType(validator, scope, call, false);
        } else if (function != null) {
          validator.validateColumnListParams(function, argTypes, operands);
        }
      }

      if (getFunctionType() == SqlFunctionCategory.UserDefinedConstructor) {
        return validator.deriveConstructorType(scope, call, this, function, argTypes);
      }
      if (function == null) {
        validator.handleUnresolvedFunction(call, this, argTypes);
      }

      // REVIEW jvs 25-Mar-2005:  This is, in a sense, expanding
      // identifiers, but we ignore shouldExpandIdentifiers()
      // because otherwise later validation code will
      // choke on the unresolved function.
      call.setOperator(function);
      return function.validateOperands(validator, operandScope, call);
    } finally {
      validator.popFunctionCall();
    }
  }
  public int reduceExpr(int opOrdinal, List<Object> list) {
    final SqlParserUtil.ToTreeListItem betweenNode =
        (SqlParserUtil.ToTreeListItem) list.get(opOrdinal);
    SqlOperator op = betweenNode.getOperator();
    assert op == this;

    // Break the expression up into expressions. For example, a simple
    // expression breaks down as follows:
    //
    //            opOrdinal   endExp1
    //            |           |
    //     a + b BETWEEN c + d AND e + f
    //    |_____|       |_____|   |_____|
    //     exp0          exp1      exp2
    // Create the expression between 'BETWEEN' and 'AND'.
    final SqlParserPos pos = ((SqlNode) list.get(opOrdinal + 1)).getParserPosition();
    SqlNode exp1 = SqlParserUtil.toTreeEx(list, opOrdinal + 1, 0, SqlKind.AND);
    if ((opOrdinal + 2) >= list.size()) {
      SqlParserPos lastPos = ((SqlNode) list.get(list.size() - 1)).getParserPosition();
      final int line = lastPos.getEndLineNum();
      final int col = lastPos.getEndColumnNum() + 1;
      SqlParserPos errPos = new SqlParserPos(line, col, line, col);
      throw SqlUtil.newContextException(
          errPos, EigenbaseResource.instance().BetweenWithoutAnd.ex());
    }
    final Object o = list.get(opOrdinal + 2);
    if (!(o instanceof SqlParserUtil.ToTreeListItem)) {
      SqlParserPos errPos = ((SqlNode) o).getParserPosition();
      throw SqlUtil.newContextException(
          errPos, EigenbaseResource.instance().BetweenWithoutAnd.ex());
    }
    if (((SqlParserUtil.ToTreeListItem) o).getOperator().getKind() != SqlKind.AND) {
      SqlParserPos errPos = ((SqlParserUtil.ToTreeListItem) o).getPos();
      throw SqlUtil.newContextException(
          errPos, EigenbaseResource.instance().BetweenWithoutAnd.ex());
    }

    // Create the expression after 'AND', but stopping if we encounter an
    // operator of lower precedence.
    //
    // For example,
    //   a BETWEEN b AND c + d OR e
    // becomes
    //   (a BETWEEN b AND c + d) OR e
    // because OR has lower precedence than BETWEEN.
    SqlNode exp2 = SqlParserUtil.toTreeEx(list, opOrdinal + 3, getRightPrec(), SqlKind.OTHER);

    // Create the call.
    SqlNode exp0 = (SqlNode) list.get(opOrdinal - 1);
    SqlCall newExp =
        createCall(
            betweenNode.getPos(),
            exp0,
            exp1,
            exp2,
            SqlLiteral.createSymbol(flag, SqlParserPos.ZERO));

    // Replace all of the matched nodes with the single reduced node.
    SqlParserUtil.replaceSublist(list, opOrdinal - 1, opOrdinal + 4, newExp);

    // Return the ordinal of the new current node.
    return opOrdinal - 1;
  }