public SqlNode visit(SqlNodeList list) { SqlNodeList copy = new SqlNodeList(list.getParserPosition()); for (SqlNode node : list) { copy.add(node.accept(this)); } return copy; }
void commaList(SqlWriter writer) { // The precedence of the comma operator if low but not zero. For // instance, this ensures parentheses in // select x, (select * from foo order by z), y from t for (SqlNode node : list) { writer.sep(","); node.unparse(writer, 2, 3); } }
public static SqlNode[] cloneArray(SqlNode[] nodes) { SqlNode[] clones = (SqlNode[]) nodes.clone(); for (int i = 0; i < clones.length; i++) { SqlNode node = clones[i]; if (node != null) { clones[i] = (SqlNode) node.clone(); } } return clones; }
/** Tests that Hive dialect does not generate "AS". */ @Test public void testHiveDialect() throws SqlParseException { Planner planner = getPlanner(); SqlNode parse = planner.parse( "select * from (select * from \"emps\") as t\n" + "where \"name\" like '%e%'"); final SqlDialect hiveDialect = new SqlDialect(SqlDialect.DatabaseProduct.HIVE, "Hive", null); assertThat( parse.toSqlString(hiveDialect).getSql(), equalTo("SELECT *\n" + "FROM (SELECT *\n" + "FROM emps) T\n" + "WHERE name LIKE '%e%'")); }
public SqlNode findAgg(List<SqlNode> nodes) { try { for (SqlNode node : nodes) { node.accept(this); } return null; } catch (Util.FoundOne e) { Util.swallow(e, null); return (SqlNode) e.getNode(); } }
@Test public void testValidateFails() throws SqlParseException { Planner planner = getPlanner(); SqlNode parse = planner.parse("select * from \"emps\" where \"Xname\" like '%e%'"); assertThat( parse.toString(), equalTo("SELECT *\n" + "FROM `emps`\n" + "WHERE `Xname` LIKE '%e%'")); try { SqlNode validate = planner.validate(parse); fail("expected error, got " + validate); } catch (ValidationException e) { assertThat(Util.getStackTrace(e), containsString("Column 'Xname' not found in any table")); // ok } }
@Test public void testParseAndConvert() throws Exception { Planner planner = getPlanner(); SqlNode parse = planner.parse("select * from \"emps\" where \"name\" like '%e%'"); assertThat( parse.toString(), equalTo("SELECT *\n" + "FROM `emps`\n" + "WHERE `name` LIKE '%e%'")); SqlNode validate = planner.validate(parse); RelNode rel = planner.convert(validate); assertThat( toString(rel), equalTo( "ProjectRel(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4])\n" + " FilterRel(condition=[LIKE($2, '%e%')])\n" + " EnumerableTableAccessRel(table=[[hr, emps]])\n")); }
boolean containsAnd(SqlNode node) { try { node.accept(this); return false; } catch (AndFinder.Found e) { return true; } }
public void validateExpr(SqlValidator validator, SqlValidatorScope scope) { // While a SqlNodeList is not always a valid expression, this // implementation makes that assumption. It just validates the members // of the list. // // One example where this is valid is the IN operator. The expression // // empno IN (10, 20) // // results in a call with operands // // { SqlIdentifier({"empno"}), // SqlNodeList(SqlLiteral(10), SqlLiteral(20)) } for (SqlNode node : list) { node.validateExpr(validator, scope); } }
void andOrList(SqlWriter writer, SqlKind sepKind) { SqlBinaryOperator sepOp = sepKind == SqlKind.AND ? SqlStdOperatorTable.AND : SqlStdOperatorTable.OR; for (int i = 0; i < list.size(); i++) { SqlNode node = list.get(i); writer.sep(sepKind.name(), false); // The precedence pulling on the LHS of a node is the // right-precedence of the separator operator, except at the start // of the list; similarly for the RHS of a node. If the operator // has left precedence 4 and right precedence 5, the precedences // in a 3-node list will look as follows: // 0 <- node1 -> 4 5 <- node2 -> 4 5 <- node3 -> 0 int lprec = (i == 0) ? 0 : sepOp.getRightPrec(); int rprec = (i == (list.size() - 1)) ? 0 : sepOp.getLeftPrec(); node.unparse(writer, lprec, rprec); } }
/** * Returns whether two nodes are equal (using {@link #equalsDeep(SqlNode,boolean)}) or are both * null. * * @param node1 First expression * @param node2 Second expression * @param fail Whether to throw {@link AssertionError} if expressions are not equal */ public static boolean equalDeep(SqlNode node1, SqlNode node2, boolean fail) { if (node1 == null) { return node2 == null; } else if (node2 == null) { return false; } else { return node1.equalsDeep(node2, fail); } }
public boolean equalsDeep(SqlNode node, boolean fail) { if (!(node instanceof SqlNodeList)) { assert !fail : this + "!=" + node; return false; } SqlNodeList that = (SqlNodeList) node; if (this.size() != that.size()) { assert !fail : this + "!=" + node; return false; } for (int i = 0; i < list.size(); i++) { SqlNode thisChild = list.get(i); final SqlNode thatChild = that.list.get(i); if (!thisChild.equalsDeep(thatChild, fail)) { return false; } } return true; }
public void unparse(SqlWriter writer, SqlNode[] operands, int leftPrec, int rightPrec) { assert operands.length >= 2; final SqlWriter.Frame frame = writer.startList(SqlWriter.FrameTypeEnum.Simple); operands[0].unparse(writer, leftPrec, getLeftPrec()); final boolean needsSpace = true; writer.setNeedWhitespace(needsSpace); writer.sep("AS"); writer.setNeedWhitespace(needsSpace); operands[1].unparse(writer, getRightPrec(), rightPrec); if (operands.length > 2) { final SqlWriter.Frame frame1 = writer.startList(SqlWriter.FrameTypeEnum.Simple, "(", ")"); for (int i = 2; i < operands.length; i++) { SqlNode operand = operands[i]; writer.sep(",", false); operand.unparse(writer, 0, 0); } writer.endList(frame1); } writer.endList(frame); }
/** * 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 void validate(SqlValidator validator, SqlValidatorScope scope) { for (SqlNode child : list) { child.validate(validator, scope); } }
/** Converts an expression "expr" into "expr AS alias". */ public static SqlNode addAlias(SqlNode expr, String alias) { final SqlParserPos pos = expr.getParserPosition(); final SqlIdentifier id = new SqlIdentifier(alias, pos); return SqlStdOperatorTable.AS.createCall(pos, expr, id); }