/** * Analyzes a rex predicate. * * @param rexPredicate predicate to be analyzed * @return a list of SargBindings contained in the input rex predicate */ public List<SargBinding> analyzeAll(RexNode rexPredicate) { sargBindingList = new ArrayList<SargBinding>(); sarg2RexMap = new HashMap<SargExpr, RexNode>(); nonSargFilterList = new ArrayList<RexNode>(); // Flatten out the RexNode tree into a list of terms that // are AND'ed together final List<RexNode> rexCFList = RelOptUtil.conjunctions(rexPredicate); // In simple mode, each input ref can only be referenced once, so // keep a list of them. We also only allow one non-point expression. List<Integer> boundRefList = new ArrayList<Integer>(); boolean rangeFound = false; for (RexNode rexPred : rexCFList) { final SargBinding sargBinding = analyze(rexPred); if (sargBinding != null) { if (simpleMode) { RexInputRef inputRef = sargBinding.getInputRef(); if (boundRefList.contains(inputRef.getIndex())) { nonSargFilterList.add(rexPred); continue; } else { boundRefList.add(inputRef.getIndex()); } SargIntervalSequence sargSeq = sargBinding.getExpr().evaluate(); if (sargSeq.isRange()) { if (rangeFound) { nonSargFilterList.add(rexPred); continue; } else { rangeFound = true; } } } sargBindingList.add(sargBinding); sarg2RexMap.put(sargBinding.getExpr(), rexPred); } else { nonSargFilterList.add(rexPred); } } // Reset the state variables used during analyze, just for sanity sake. failed = false; boundInputRef = null; clearLeaf(); // Combine the AND terms back together. recomposeConjunction(); return sargBindingList; }
public Void visitInputRef(RexInputRef inputRef) { super.visitInputRef(inputRef); if (inputRef.getIndex() >= inputRowType.getFieldCount()) { throw new IllegalForwardRefException(); } return null; }
/** * 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; } }
private boolean isRealRexInputRef(RexInputRef inputRef) { if ((lowerRexInputIdx < 0) && (upperRexInputIdx < 0)) { return true; } int idx = inputRef.getIndex(); if ((idx >= lowerRexInputIdx) && (idx < upperRexInputIdx)) { return false; } else { return true; } }
/** * Returns whether the leading edge of a given array of expressions is wholly {@link RexInputRef} * objects with types corresponding to the underlying datatype. */ public static boolean containIdentity(RexNode[] exprs, RelDataType rowType, boolean fail) { final RelDataTypeField[] fields = rowType.getFields(); if (exprs.length < fields.length) { assert !fail : "exprs/rowType length mismatch"; return false; } for (int i = 0; i < fields.length; i++) { if (!(exprs[i] instanceof RexInputRef)) { assert !fail : "expr[" + i + "] is not a RexInputRef"; return false; } RexInputRef inputRef = (RexInputRef) exprs[i]; if (inputRef.getIndex() != i) { assert !fail : "expr[" + i + "] has ordinal " + inputRef.getIndex(); return false; } if (!RelOptUtil.eq("type1", exprs[i].getType(), "type2", fields[i].getType(), fail)) { return false; } } return true; }
public Void visitInputRef(RexInputRef inputRef) { boolean coordinate = !isRealRexInputRef(inputRef); if (coordinate) { visitCoordinate(inputRef); return null; } variableSeen = true; if (boundInputRef == null) { boundInputRef = inputRef; return null; } if (inputRef.getIndex() != boundInputRef.getIndex()) { // sargs can only be over a single variable failed = true; return null; } return null; }
/** Reconstructs a rex predicate from a list of SargExprs which will be AND'ed together. */ private void recomposeConjunction() { for (int i = 0; i < sargBindingList.size(); i++) { final SargBinding currBinding = sargBindingList.get(i); final RexInputRef currRef = currBinding.getInputRef(); SargExpr currSargExpr = currBinding.getExpr(); RexNode currAndNode = sarg2RexMap.get(currSargExpr); // don't need this anymore // will be have new mapping put back if currSargExpr remain // unchanged. sarg2RexMap.remove(currSargExpr); boolean recomp = false; // search the rest of the list to find SargExpr on the same col. ListIterator<SargBinding> iter = sargBindingList.listIterator(i + 1); while (iter.hasNext()) { final SargBinding nextBinding = iter.next(); final RexInputRef nextRef = nextBinding.getInputRef(); final SargExpr nextSargExpr = nextBinding.getExpr(); if (nextRef.getIndex() == currRef.getIndex()) { // build new SargExpr SargSetExpr expr = factory.newSetExpr(currSargExpr.getDataType(), SargSetOperator.INTERSECTION); expr.addChild(currSargExpr); expr.addChild(nextSargExpr); // build new RexNode currAndNode = factory .getRexBuilder() .makeCall( SqlStdOperatorTable.andOperator, currAndNode, sarg2RexMap.get(nextSargExpr)); currSargExpr = expr; sarg2RexMap.remove(nextSargExpr); iter.remove(); recomp = true; } } if (recomp) { assert !simpleMode; if (!testDynamicParamSupport(currSargExpr)) { // Oops, we can't actually support the conjunction we // recomposed. Toss it. (We could do a better job by at // least using part of it, but the effort might be better // spent on implementing deferred expression evaluation.) nonSargFilterList.add(currAndNode); sargBindingList.remove(i); continue; } } if (recomp) { SargBinding newBinding = new SargBinding(currSargExpr, currRef); sargBindingList.remove(i); sargBindingList.add(i, newBinding); } sarg2RexMap.put(currSargExpr, currAndNode); } }