Multimap<DynamicOperand, PlanNode> selectNodeByOperand = ArrayListMultimap.create();
for (PlanNode select : access.findAllAtOrBelow(Type.SELECT)) {
Constraint constraint = select.getProperty(Property.SELECT_CRITERIA, Constraint.class);
// Look for Comparison constraints that use a range operator
if (constraint instanceof Comparison) {
Comparison comparison = (Comparison)constraint;
if (comparison.operator().isRangeOperator()) {
selectNodeByOperand.put(comparison.getOperand1(), select);
}
}
}
if (!selectNodeByOperand.isEmpty()) {
// Go through the constraints we've found ...
for (DynamicOperand operand : selectNodeByOperand.keySet()) {
Collection<PlanNode> nodes = selectNodeByOperand.get(operand);
if (nodes.size() <= 1) continue;
// Extract the constraints from the nodes ...
List<Comparison> rangeConstraints = new ArrayList<Comparison>(nodes.size());
List<PlanNode> selectNodes = new ArrayList<PlanNode>(nodes.size());
Set<SelectorName> selectors = null;
for (PlanNode select : nodes) {
selectNodes.add(select);
Comparison constraint = select.getProperty(Property.SELECT_CRITERIA, Comparison.class);
rangeConstraints.add(constraint);
// Record the selector names (should all be the same) ...
if (selectors == null) selectors = select.getSelectors();
else assert selectors.equals(select.getSelectors());
}
// Attempt to merge the constraints ...
Constraint merged = rewrite(context, rangeConstraints);
if (merged == CONFLICTING_CONSTRAINT) {
// The ANDed constraints cancel each other out, so this whole access node will return no results ...
access.setProperty(Property.ACCESS_NO_RESULTS, Boolean.TRUE);
foundNoResults = true;
break; // don't do anything else under this access node
}
if (merged != null) {
// Add a SELECT node for the new merged constraint ...
PlanNode newSelect = new PlanNode(Type.SELECT);
newSelect.getSelectors().addAll(selectors);
newSelect.setProperty(Property.SELECT_CRITERIA, merged);
// And insert the SELECT node into the tree (just below the ACCESS, we'll rerun pushdown selects) ...
assert access.getChildCount() == 1;
access.getFirstChild().insertAsParent(newSelect);
rewritten = true;
}
// Remove any of the SELECT nodes that were not needed (this can happen if the constraints are not needed) ...
Iterator<PlanNode> nodeIter = selectNodes.iterator();
Iterator<Comparison> constraintIter = rangeConstraints.iterator();
while (nodeIter.hasNext()) {
assert constraintIter.hasNext();
PlanNode node = nodeIter.next();
Comparison comparison = constraintIter.next();
if (comparison == null) {
// This comparison was rewritten, so remove the PlanNode ...
node.extractFromParent();
nodeIter.remove();
}