PlanNode plan,
LinkedList<OptimizerRule> ruleStack ) {
for (final PlanNode source : plan.findAllAtOrBelow(Type.SOURCE)) {
// There were some constraints, so prepare to collect indexes ...
assert source.getSelectors().size() == 1;
final SelectorName selectorName = source.getSelectors().iterator().next();
// Look for any SELECT nodes above this but below an ACCESS node, because all of the SELECT define
// criteria that are all ANDed together ...
final List<Constraint> constraints = new LinkedList<>();
final List<JoinCondition> joinConditions = new LinkedList<>();
final Set<String> nodeTypeNames = new HashSet<>();
source.applyToAncestors(new Operation() {
@Override
public void apply( PlanNode node ) {
if (node.getType() == Type.SELECT) {
Constraint constraint = node.getProperty(Property.SELECT_CRITERIA, Constraint.class);
if (constraint != null) {
constraints.add(constraint);
// While we're at it, look for the constraint on the primary type. This tells us which node type
// we're working with ...
if (nodeTypeNames.isEmpty()) {
if (constraint instanceof Comparison) {
Comparison comparison = (Comparison)constraint;
if (isPrimaryTypeConstraint(comparison.getOperand1())) {
addLiteral(comparison.getOperand2(), nodeTypeNames);
}
} else if (constraint instanceof SetCriteria) {
SetCriteria criteria = (SetCriteria)constraint;
if (isPrimaryTypeConstraint(criteria.getOperand())) {
// Look for literal values and collect them as the node type names ...
for (StaticOperand operand : criteria.getValues()) {
addLiteral(operand, nodeTypeNames);
}
}
}
}
}
} else if (node.getType() == Type.JOIN) {
// Also look at the join conditions ...
JoinCondition joinCondition = node.getProperty(Property.JOIN_CONDITION, JoinCondition.class);
if (joinCondition != null) {
joinConditions.add(joinCondition);
}
// Look for additional constraints pushed down to the join ...
List<Constraint> joinConstraints = node.getPropertyAsList(Property.JOIN_CONSTRAINTS, Constraint.class);
if (joinConstraints != null) {
for (Constraint joinConstraint : joinConstraints) {
constraints.add(joinConstraint);
}
}
}
}
private boolean isPrimaryTypeConstraint( DynamicOperand operand ) {
if (operand instanceof PropertyValue) {
PropertyValue propValue = (PropertyValue)operand;
if (propValue.getSelectorName().equals(selectorName.getString())) {
// The property value matches our selector name, so this might be a constraint on the
// primary type or mixin types. If so, then the selector name is an alias ...
String propName = propValue.getPropertyName();
return "jcr:primaryType".equals(propName) || "jcr:mixinTypes".equals(propName);
}
}
return false;
}
private void addLiteral( StaticOperand operand,
Set<String> collector ) {
if (operand instanceof Literal) {
// Get the literal value, which should be a node type ...
Literal literal = (Literal)operand;
StringFactory strings = context.getExecutionContext().getValueFactories().getStringFactory();
nodeTypeNames.add(strings.create(literal.value()));
}
}
});
if (!constraints.isEmpty() || !joinConditions.isEmpty()) {
// Get the selector name. The plan's selectors will contain an alias if one is used, so we have to find
// the 'selector.[jcr:primaryType] = '<nodeType>' constraint
// Add the alias ...
nodeTypeNames.add(selectorName.getString());
final List<IndexPlan> indexPlans = new LinkedList<>();
IndexCostCalculator calculator = new IndexCostCalculator() {
@Override
public Set<String> selectedNodeTypes() {
return nodeTypeNames;