private Result( SqlNode node, Collection<Clause> clauses, String neededAlias, List<Pair<String, RelDataType>> aliases) { this.node = node; this.neededAlias = neededAlias; this.aliases = aliases; this.clauses = Expressions.list(clauses); }
/** Converts a call to an aggregate function to an expression. */ public SqlNode toSql(AggregateCall aggCall) { SqlOperator op = (SqlAggFunction) aggCall.getAggregation(); final List<SqlNode> operands = Expressions.list(); for (int arg : aggCall.getArgList()) { operands.add(field(arg)); } return op.createCall( aggCall.isDistinct() ? SqlSelectKeyword.DISTINCT.symbol(POS) : null, POS, operands.toArray(new SqlNode[operands.size()])); }
public RexNode toRex(Expression expression) { switch (expression.getNodeType()) { case MemberAccess: return rexBuilder.makeFieldAccess( toRex(((MemberExpression) expression).expression), ((MemberExpression) expression).field.getName()); case GreaterThan: return binary(expression, SqlStdOperatorTable.greaterThanOperator); case LessThan: return binary(expression, SqlStdOperatorTable.lessThanOperator); case Parameter: return parameter((ParameterExpression) expression); case Call: MethodCallExpression call = (MethodCallExpression) expression; SqlOperator operator = RexToLixTranslator.JAVA_TO_SQL_METHOD_MAP.get(call.method); if (operator != null) { return rexBuilder.makeCall( operator, toRex( Expressions.<Expression>list() .appendIfNotNull(call.targetExpression) .appendAll(call.expressions))); } throw new RuntimeException("Could translate call to method " + call.method); case Constant: final ConstantExpression constant = (ConstantExpression) expression; Object value = constant.value; if (value instanceof Number) { Number number = (Number) value; if (value instanceof Double || value instanceof Float) { return rexBuilder.makeApproxLiteral(BigDecimal.valueOf(number.doubleValue())); } else if (value instanceof BigDecimal) { return rexBuilder.makeExactLiteral((BigDecimal) value); } else { return rexBuilder.makeExactLiteral(BigDecimal.valueOf(number.longValue())); } } else if (value instanceof Boolean) { return rexBuilder.makeLiteral((Boolean) value); } else { return rexBuilder.makeLiteral(constant.toString()); } default: throw new UnsupportedOperationException( "unknown expression type " + expression.getNodeType() + " " + expression); } }
/** * Once you have a Result of implementing a child relational expression, call this method to * create a Builder to implement the current relational expression by adding additional clauses * to the SQL query. * * <p>You need to declare which clauses you intend to add. If the clauses are "later", you can * add to the same query. For example, "GROUP BY" comes after "WHERE". But if they are the same * or earlier, this method will start a new SELECT that wraps the previous result. * * <p>When you have called {@link Builder#setSelect(org.eigenbase.sql.SqlNodeList)}, {@link * Builder#setWhere(org.eigenbase.sql.SqlNode)} etc. call {@link * Builder#result(org.eigenbase.sql.SqlNode, java.util.Collection, org.eigenbase.rel.RelNode)} * to fix the new query. * * @param rel Relational expression being implemented * @param clauses Clauses that will be generated to implement current relational expression * @return A builder */ public Builder builder(JdbcRel rel, Clause... clauses) { final Clause maxClause = maxClause(); boolean needNew = false; for (Clause clause : clauses) { if (maxClause.ordinal() >= clause.ordinal()) { needNew = true; } } SqlSelect select; Expressions.FluentList<Clause> clauseList = Expressions.list(); if (needNew) { select = subSelect(); } else { select = asSelect(); clauseList.addAll(this.clauses); } clauseList.addAll(Arrays.asList(clauses)); Context newContext; final SqlNodeList selectList = select.getSelectList(); if (selectList != null) { newContext = new Context(selectList.size()) { @Override public SqlNode field(int ordinal) { final SqlNode selectItem = selectList.get(ordinal); switch (selectItem.getKind()) { case AS: return ((SqlCall) selectItem).operand(0); } return selectItem; } }; } else { newContext = new AliasContext(aliases, aliases.size() > 1); } return new Builder(rel, clauseList, select, newContext); }
/** * Creates a result based on a join. (Each join could contain one or more relational expressions.) */ public Result result(SqlNode join, Result leftResult, Result rightResult) { final List<Pair<String, RelDataType>> list = new ArrayList<Pair<String, RelDataType>>(); list.addAll(leftResult.aliases); list.addAll(rightResult.aliases); return new Result(join, Expressions.list(Clause.FROM), null, list); }
/** 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); } }