private SargIntervalSequence evaluateIntersection(List<SargIntervalSequence> list) { SargIntervalSequence seq = null; if (list.isEmpty()) { // Counterintuitive but true: intersection of no sets is the // universal set (kinda like 2^0=1). One way to prove this to // yourself is to apply DeMorgan's law. The union of no sets is // certainly the empty set. So the complement of that union is the // universal set. That's equivalent to the intersection of the // complements of no sets, which is the intersection of no sets. // QED. seq = new SargIntervalSequence(); seq.addInterval(new SargInterval(factory, getDataType())); return seq; } // The way we evaluate the intersection is to start with the first // entry as a baseline, and then keep deleting stuff from it by // intersecting the other entrie in turn. Whatever makes it through // this filtering remains as the final result. for (SargIntervalSequence newSeq : list) { if (seq == null) { // first child seq = newSeq; continue; } intersectSequences(seq, newSeq); } return seq; }
/** * 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; }
private SargIntervalSequence evaluateUnion(List<SargIntervalSequence> list) { SargIntervalSequence seq = new SargIntervalSequence(); // Toss all entries from each sequence in the list into one big sorted // set. SortedSet<SargInterval> intervals = new TreeSet<SargInterval>(new IntervalComparator()); for (SargIntervalSequence childSeq : list) { intervals.addAll(childSeq.getList()); } // Now, overlapping ranges are consecutive in the set. Merge them by // increasing the upper bound of the first; discard the others. In the // example, [4, 6] and [5, 7) are combined to form [4, 7). (7, 8] is // not merged with the new range because neither range contains the // value 7. // // Input: // 1 2 3 4 5 6 7 8 9 // 1 [1, 3] [-----] // 2 [4, 6] [-----] // 3 [5, 7) [-----) // 4 (7, 8] (--] // // Output: // 1 [1, 3] [-----] // 2 [4, 7) [--------) // 3 (7, 8] (--] SargInterval accumulator = null; for (SargInterval interval : intervals) { // Empty intervals should have been previously filtered out. assert (!interval.isEmpty()); if (accumulator == null) { // The very first interval: start accumulating. accumulator = new SargInterval(factory, getDataType()); accumulator.copyFrom(interval); seq.addInterval(accumulator); continue; } if (accumulator.contains(interval)) { // Just drop new interval because it's already covered // by accumulator. continue; } // Test for overlap. int c = interval.getLowerBound().compareTo(accumulator.getUpperBound()); // If no overlap, test for touching instead. if (c > 0) { if (interval.getLowerBound().isTouching(accumulator.getUpperBound())) { // Force test below to pass. c = -1; } } if (c <= 0) { // Either touching or overlap: grow the accumulator. accumulator.upperBound.copyFrom(interval.getUpperBound()); } else { // Disjoint: start accumulating a new interval accumulator = new SargInterval(factory, getDataType()); accumulator.copyFrom(interval); seq.addInterval(accumulator); } } return seq; }