/** * Determines if a filter condition is a simple one and returns the parameters corresponding to * the simple filters. * * @param calcRel original CalcRel * @param filterExprs filter expression being analyzed * @param filterList returns the list of filter ordinals in the simple expression * @param literals returns the list of literals to be used in the simple comparisons * @param op returns the operator to be used in the simple comparison * @return true if the filter condition is simple */ private boolean isConditionSimple( CalcRel calcRel, RexNode filterExprs, List<Integer> filterList, List<RexLiteral> literals, List<CompOperatorEnum> op) { SargFactory sargFactory = new SargFactory(calcRel.getCluster().getRexBuilder()); SargRexAnalyzer rexAnalyzer = sargFactory.newRexAnalyzer(true); List<SargBinding> sargBindingList = rexAnalyzer.analyzeAll(filterExprs); // Currently, it's all or nothing. So, if there are filters rejected // by the analyzer, we can't process a subset using the reshape // exec stream if (rexAnalyzer.getNonSargFilterRexNode() != null) { return false; } List<RexInputRef> filterCols = new ArrayList<RexInputRef>(); List<RexNode> filterOperands = new ArrayList<RexNode>(); if (FennelRelUtil.extractSimplePredicates(sargBindingList, filterCols, filterOperands, op)) { for (RexInputRef filterCol : filterCols) { filterList.add(filterCol.getIndex()); } for (RexNode operand : filterOperands) { literals.add((RexLiteral) operand); } return true; } else { return false; } }
/** * Constructs a FarragoReentrantSubquery. * * @param subq the subquery to evaluate * @param parentConverter sqlToRelConverter associated with the parent query * @param isExists whether the subquery is part of an EXISTS expression * @param isExplain whether the subquery is part of an EXPLAIN PLAN statement * @param results the resulting evaluated expressions */ FarragoReentrantSubquery( SqlCall subq, SqlToRelConverter parentConverter, boolean isExists, boolean isExplain, List<RexNode> results) { super( FennelRelUtil.getPreparingStmt(parentConverter.getCluster()).getRootStmtContext(), parentConverter.getRexBuilder(), results); FarragoSessionStmtContext rootContext = getRootStmtContext(); if (rootContext != null) { rootContext.setSaveFirstTxnCsn(); } if (!isExists) { assert subq.getKind() == SqlKind.SCALAR_QUERY; } this.subq = subq; this.parentConverter = parentConverter; this.isExists = isExists; this.isExplain = isExplain; }
protected void executeImpl() throws Exception { SqlCall call = (SqlCall) subq; SqlSelect select = (SqlSelect) call.getOperands()[0]; // Convert the SqlNode tree to a RelNode tree; we need to do this // here so the RelNode tree is associated with the new preparing // stmt. FarragoPreparingStmt preparingStmt = (FarragoPreparingStmt) getPreparingStmt(); SqlValidator validator = preparingStmt.getSqlValidator(); SqlToRelConverter sqlConverter = preparingStmt.getSqlToRelConverter(validator, preparingStmt); preparingStmt.setParentStmt(FennelRelUtil.getPreparingStmt(parentConverter.getCluster())); // Add to the new converter any subqueries that have already been // converted by the parent so we can avoid re-executing them sqlConverter.addConvertedNonCorrSubqs(parentConverter.getMapConvertedNonCorrSubqs()); RelNode plan = sqlConverter.convertQuery(select, true, true); // The subquery cannot have dynamic parameters if (sqlConverter.getDynamicParamCount() > 0) { failed = true; return; } List<RexNode> exprs = new ArrayList<RexNode>(); RelDataType resultType = null; if (!isExists) { // Non-EXISTS subqueries need to be converted to single-value // subqueries plan = sqlConverter.convertToSingleValueSubq(select, plan); // Create a dummy expression to store the type of the result. // When setting the type, derive the type based on what a // scalar subquery should return and create the type from the // type factory of the parent query. resultType = call.getOperator().deriveType(validator, validator.getFromScope(select), call); resultType = rexBuilder.getTypeFactory().copyType(resultType); exprs.add(rexBuilder.makeInputRef(resultType, 0)); } plan = sqlConverter.decorrelate(select, plan); // If the subquery is part of an EXPLAIN PLAN statement, don't // execute the subquery, but instead just return a dynamic parameter // as a placeholder for the subquery result. Otherwise, execute // the query to produce the constant expression. Cast the expression // as needed so the type matches the expected result type. RexNode constExpr; if (isExplain) { if (isExists) { resultType = rexBuilder.getTypeFactory().createSqlType(SqlTypeName.BOOLEAN); } constExpr = rexBuilder.makeDynamicParam( resultType, parentConverter.getDynamicParamCountInExplain(true)); results.add(constExpr); } else { executePlan(plan, exprs, isExists, false); if (!failed && !isExists) { constExpr = results.get(0); if (constExpr.getType() != resultType) { constExpr = rexBuilder.makeCast(resultType, constExpr); results.set(0, constExpr); } } } }