/** Converts an expression from {@link RexNode} to {@link SqlNode} format. */ SqlNode toSql(RexProgram program, RexNode rex) { if (rex instanceof RexLocalRef) { final int index = ((RexLocalRef) rex).getIndex(); return toSql(program, program.getExprList().get(index)); } else if (rex instanceof RexInputRef) { return field(((RexInputRef) rex).getIndex()); } else if (rex instanceof RexLiteral) { final RexLiteral literal = (RexLiteral) rex; switch (literal.getTypeName().getFamily()) { case CHARACTER: return SqlLiteral.createCharString((String) literal.getValue2(), POS); case NUMERIC: case EXACT_NUMERIC: return SqlLiteral.createExactNumeric(literal.getValue().toString(), POS); case APPROXIMATE_NUMERIC: return SqlLiteral.createApproxNumeric(literal.getValue().toString(), POS); case BOOLEAN: return SqlLiteral.createBoolean((Boolean) literal.getValue(), POS); case DATE: return SqlLiteral.createDate((Calendar) literal.getValue(), POS); case TIME: return SqlLiteral.createTime( (Calendar) literal.getValue(), literal.getType().getPrecision(), POS); case TIMESTAMP: return SqlLiteral.createTimestamp( (Calendar) literal.getValue(), literal.getType().getPrecision(), POS); case ANY: switch (literal.getTypeName()) { case NULL: return SqlLiteral.createNull(POS); // fall through } default: throw new AssertionError(literal + ": " + literal.getTypeName()); } } else if (rex instanceof RexCall) { final RexCall call = (RexCall) rex; final SqlOperator op = call.getOperator(); final List<SqlNode> nodeList = toSql(program, call.getOperands()); if (op == SqlStdOperatorTable.CAST) { RelDataType type = call.getType(); if (type.getSqlTypeName() == SqlTypeName.VARCHAR && dialect.getDatabaseProduct() == SqlDialect.DatabaseProduct.MYSQL) { // MySQL doesn't have a VARCHAR type, only CHAR. nodeList.add( new SqlDataTypeSpec( new SqlIdentifier("CHAR", POS), type.getPrecision(), -1, null, null, POS)); } else { nodeList.add(toSql(type)); } } if (op == SqlStdOperatorTable.CASE) { final SqlNode valueNode; final List<SqlNode> whenList = Expressions.list(); final List<SqlNode> thenList = Expressions.list(); final SqlNode elseNode; if (nodeList.size() % 2 == 0) { // switched: // "case x when v1 then t1 when v2 then t2 ... else e end" valueNode = nodeList.get(0); for (int i = 1; i < nodeList.size() - 1; i += 2) { whenList.add(nodeList.get(i)); thenList.add(nodeList.get(i + 1)); } } else { // other: "case when w1 then t1 when w2 then t2 ... else e end" valueNode = null; for (int i = 0; i < nodeList.size() - 1; i += 2) { whenList.add(nodeList.get(i)); thenList.add(nodeList.get(i + 1)); } } elseNode = nodeList.get(nodeList.size() - 1); return op.createCall( POS, valueNode, new SqlNodeList(whenList, POS), new SqlNodeList(thenList, POS), elseNode); } if (op instanceof SqlBinaryOperator && nodeList.size() > 2) { // In RexNode trees, OR and AND have any number of children; // SqlCall requires exactly 2. So, convert to a left-deep binary tree. return createLeftCall(op, nodeList); } return op.createCall(new SqlNodeList(nodeList, POS)); } else { throw new AssertionError(rex); } }
public SqlNode visit(SqlLiteral literal) { return (SqlNode) literal.clone(); }
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; }