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