You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2014/02/12 15:33:38 UTC

svn commit: r1567633 - in /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query: ./ ast/

Author: thomasm
Date: Wed Feb 12 14:33:38 2014
New Revision: 1567633

URL: http://svn.apache.org/r1567633
Log:
OAK-1372 XPath queries with both path and property restrictions are slow (WIP)

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SelectorExecutionPlan.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeJoinConditionImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeJoinConditionImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinConditionImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NotImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyInexistenceImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SameNodeJoinConditionImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java Wed Feb 12 14:33:38 2014
@@ -17,8 +17,10 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.Tree;
@@ -38,6 +40,9 @@ import org.apache.jackrabbit.oak.query.a
 import org.apache.jackrabbit.oak.query.ast.FullTextSearchImpl;
 import org.apache.jackrabbit.oak.query.ast.FullTextSearchScoreImpl;
 import org.apache.jackrabbit.oak.query.ast.InImpl;
+import org.apache.jackrabbit.oak.query.ast.JoinConditionImpl;
+import org.apache.jackrabbit.oak.query.ast.JoinImpl;
+import org.apache.jackrabbit.oak.query.ast.JoinType;
 import org.apache.jackrabbit.oak.query.ast.LengthImpl;
 import org.apache.jackrabbit.oak.query.ast.LiteralImpl;
 import org.apache.jackrabbit.oak.query.ast.LowerCaseImpl;
@@ -87,7 +92,7 @@ public class QueryImpl implements Query 
 
     private static final Logger LOG = LoggerFactory.getLogger(QueryImpl.class);
 
-    final SourceImpl source;
+    SourceImpl source;
     final String statement;
     final HashMap<String, PropertyValue> bindVariableMap = new HashMap<String, PropertyValue>();
     final HashMap<String, Integer> selectorIndexes = new HashMap<String, Integer>();
@@ -438,7 +443,57 @@ public class QueryImpl implements Query 
             return;
         }
         prepared = true;
-        estimatedCost = source.prepare();
+        List<SourceImpl> sources = source.getInnerJoinSelectors();
+        List<JoinConditionImpl> conditions = source.getInnerJoinConditions();
+
+//        if (sources.size() <= 1) {
+            // simple case (no join)
+            estimatedCost = source.prepare();
+//            return;
+//        }
+        
+//        if (sources.size() < 6) {
+//            // TODO iterate over all permutations
+//        }
+//        
+//        // use a greedy algorithm
+//        SourceImpl result = null;
+//        Set<SourceImpl> available = new HashSet<SourceImpl>();
+//        while (sources.size() > 0) {
+//            int bestIndex = 0;
+//            double bestCost = Double.POSITIVE_INFINITY;
+//            for (int i = 0; i < sources.size(); i++) {
+//                SourceImpl source = buildJoin(result, sources.get(i).createClone(), conditions);
+//                double cost = source.prepare();
+//                if (cost <= bestCost) {
+//                    bestCost = cost;
+//                    bestIndex = i;
+//                }
+//            }
+//            SourceImpl s = sources.get(bestIndex).createClone();
+//            available.add(s);
+//            sources.remove(bestIndex);
+//            result = buildJoin(result, s, conditions);
+//        }
+//        source = result;
+                
+    }
+    
+    private static SourceImpl buildJoin(SourceImpl result, SourceImpl last, List<JoinConditionImpl> conditions) {
+        if (result == null) {
+            return last;
+        }
+        Set<SourceImpl> available = new HashSet<SourceImpl>();
+        available.addAll(result.getInnerJoinSelectors());
+        available.add(last);
+        for (JoinConditionImpl j : conditions) {
+            if (j.canEvaluate(available)) {
+                JoinImpl join = new JoinImpl(result, last, JoinType.INNER, j);
+                return join;
+            }
+        }
+        // this is an internal error
+        throw new IllegalArgumentException("No join condition was found");
     }
  
     /**

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SelectorExecutionPlan.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SelectorExecutionPlan.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SelectorExecutionPlan.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SelectorExecutionPlan.java Wed Feb 12 14:33:38 2014
@@ -28,10 +28,10 @@ import org.apache.jackrabbit.oak.spi.que
  */
 public class SelectorExecutionPlan {
     
-    public Filter filter;
-    
     public SelectorImpl selector;
     
+    public Filter filter;
+    
     public double estimatedCost;
     
     public QueryIndex index;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeJoinConditionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeJoinConditionImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeJoinConditionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeJoinConditionImpl.java Wed Feb 12 14:33:38 2014
@@ -18,6 +18,8 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
+import java.util.Set;
+
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.Filter;
@@ -97,5 +99,10 @@ public class ChildNodeJoinConditionImpl 
     public boolean isParent(SourceImpl source) {
         return source == parentSelector;
     }
+ 
+    @Override
+    public boolean canEvaluate(Set<SourceImpl> available) {
+        return available.contains(childSelector) && available.contains(parentSelector);
+    }
 
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeJoinConditionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeJoinConditionImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeJoinConditionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeJoinConditionImpl.java Wed Feb 12 14:33:38 2014
@@ -18,6 +18,8 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
+import java.util.Set;
+
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.Filter;
@@ -97,5 +99,10 @@ public class DescendantNodeJoinCondition
     public boolean isParent(SourceImpl source) {
         return source == ancestorSelector;
     }
+    
+    @Override
+    public boolean canEvaluate(Set<SourceImpl> available) {
+        return available.contains(descendantSelector) && available.contains(ancestorSelector);
+    }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java Wed Feb 12 14:33:38 2014
@@ -18,6 +18,8 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
+import java.util.Set;
+
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
@@ -145,5 +147,10 @@ public class EquiJoinConditionImpl exten
     public boolean isParent(SourceImpl source) {
         return false;
     }
+    
+    @Override
+    public boolean canEvaluate(Set<SourceImpl> available) {
+        return available.contains(selector1) && available.contains(selector2);
+    }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinConditionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinConditionImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinConditionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinConditionImpl.java Wed Feb 12 14:33:38 2014
@@ -13,6 +13,8 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
+import java.util.Set;
+
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 
 /**
@@ -60,5 +62,13 @@ public abstract class JoinConditionImpl 
      * @return true if the source is the parent
      */
     public abstract boolean isParent(SourceImpl source);
+    
+    /**
+     * Whether the join condition can be evaluated if the given selectors are able to retrieve data.
+     * 
+     * @param available the available selectors
+     * @return true if the condition can be evaluated
+     */
+    public abstract boolean canEvaluate(Set<SourceImpl> available);
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java Wed Feb 12 14:33:38 2014
@@ -13,6 +13,9 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.jackrabbit.oak.query.QueryImpl;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -41,6 +44,51 @@ public class JoinImpl extends SourceImpl
         this.joinType = joinType;
         this.joinCondition = joinCondition;
     }
+    
+    private JoinImpl(JoinImpl clone) {
+        this.left = clone.left;
+        this.right = clone.right;
+        this.joinType = clone.joinType;
+        this.joinCondition = clone.joinCondition;
+        this.query = clone.query;
+    }
+    
+    @Override
+    public ArrayList<SourceImpl> getInnerJoinSelectors() {
+        ArrayList<SourceImpl> list = new ArrayList<SourceImpl>();
+        switch (joinType) {
+        case INNER:
+            list.addAll(left.getInnerJoinSelectors());
+            list.addAll(right.getInnerJoinSelectors());
+            break;
+        case LEFT_OUTER:
+            list.addAll(left.getInnerJoinSelectors());
+            list.add(right);
+            break;
+        case RIGHT_OUTER:
+            list.addAll(right.getInnerJoinSelectors());
+            list.add(left);
+        }
+        return list;
+    }
+    
+    @Override
+    public List<JoinConditionImpl> getInnerJoinConditions() {
+        ArrayList<JoinConditionImpl> set = new ArrayList<JoinConditionImpl>();
+        switch (joinType) {
+        case INNER:
+            set.add(joinCondition);
+            set.addAll(left.getInnerJoinConditions());
+            set.addAll(right.getInnerJoinConditions());
+            break;
+        }
+        return set;
+    }
+
+    @Override
+    public JoinImpl createClone() {
+        return new JoinImpl(this);
+    }
 
     public JoinConditionImpl getJoinCondition() {
         return joinCondition;
@@ -105,8 +153,6 @@ public class JoinImpl extends SourceImpl
             right.addJoinCondition(joinCondition, true);
             break;
         }
-        left.setQueryConstraint(queryConstraint);
-        right.setQueryConstraint(queryConstraint);
         setParent(joinCondition);
         right.init(query);
         left.init(query);
@@ -152,6 +198,24 @@ public class JoinImpl extends SourceImpl
     }
 
     @Override
+    public void setQueryConstraint(ConstraintImpl queryConstraint) {
+        left.setQueryConstraint(queryConstraint);
+        right.setQueryConstraint(queryConstraint);
+    }    
+
+    @Override
+    public void setOuterJoin(boolean outerJoinLeftHandSide, boolean outerJoinRightHandSide) {
+        left.setOuterJoin(outerJoinLeftHandSide, outerJoinRightHandSide);
+        right.setOuterJoin(outerJoinLeftHandSide, outerJoinRightHandSide);
+    }
+    
+    @Override
+    public void addJoinCondition(JoinConditionImpl joinCondition, boolean forThisSelector) {
+        left.addJoinCondition(joinCondition, forThisSelector);
+        right.addJoinCondition(joinCondition, forThisSelector);
+    }
+
+    @Override
     public boolean next() {
         if (end) {
             return false;
@@ -185,10 +249,15 @@ public class JoinImpl extends SourceImpl
             }
             // for an outer join, if no matching result was found,
             // one row returned (with all values set to null)
-            if (right.outerJoinRightHandSide && leftNeedNext && !foundJoinedRow) {
+            if (right.isOuterJoinRightHandSide() && leftNeedNext && !foundJoinedRow) {
                 return true;
             }
         }
     }
+    
+    @Override
+    public boolean isOuterJoinRightHandSide() {
+        return left.isOuterJoinRightHandSide() || right.isOuterJoinRightHandSide();
+    }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NotImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NotImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NotImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NotImpl.java Wed Feb 12 14:33:38 2014
@@ -71,7 +71,7 @@ public class NotImpl extends ConstraintI
 
     @Override
     public void restrict(FilterImpl f) {
-        if (f.getSelector().outerJoinRightHandSide) {
+        if (f.getSelector().isOuterJoinRightHandSide()) {
             // we need to be careful with the condition
             // "NOT (property IS NOT NULL)"
             // (which is the same as "property IS NULL")

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyInexistenceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyInexistenceImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyInexistenceImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyInexistenceImpl.java Wed Feb 12 14:33:38 2014
@@ -123,7 +123,7 @@ public class PropertyInexistenceImpl ext
 
     @Override
     public void restrictPushDown(SelectorImpl s) {
-        if (s.outerJoinRightHandSide) {
+        if (s.isOuterJoinRightHandSide()) {
             // we need to be careful with "property IS NULL"
             // because this might cause an index
             // to ignore the join condition "property = x"

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SameNodeJoinConditionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SameNodeJoinConditionImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SameNodeJoinConditionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SameNodeJoinConditionImpl.java Wed Feb 12 14:33:38 2014
@@ -18,6 +18,8 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
+import java.util.Set;
+
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.Filter;
@@ -120,5 +122,10 @@ public class SameNodeJoinConditionImpl e
     public boolean isParent(SourceImpl source) {
         return false;
     }
+    
+    @Override
+    public boolean canEvaluate(Set<SourceImpl> available) {
+        return available.contains(selector1) && available.contains(selector2);
+    }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java Wed Feb 12 14:33:38 2014
@@ -60,12 +60,26 @@ import com.google.common.collect.Iterabl
  * A selector within a query.
  */
 public class SelectorImpl extends SourceImpl {
-
+    
     // TODO possibly support using multiple indexes (using index intersection / index merge)
-    protected SelectorExecutionPlan plan;
+    private SelectorExecutionPlan plan;
+    
+    /**
+     * The WHERE clause of the query.
+     */
+    private ConstraintImpl queryConstraint;
+    
+    /**
+     * The join condition of this selector that can be evaluated at execution
+     * time. For the query "select * from nt:base as a inner join nt:base as b
+     * on a.x = b.x", the join condition "a.x = b.x" is only set for the
+     * selector b, as selector a can't evaluate it if it is executed first
+     * (until b is executed).
+     */
+    private JoinConditionImpl joinCondition;
 
     /**
-     * the node type associated with the {@link #nodeTypeName}
+     * The node type associated with the {@link #nodeTypeName}
      */
     private final NodeState nodeType;
 
@@ -92,13 +106,34 @@ public class SelectorImpl extends Source
      * flag is set
      */
     private final Set<String> mixinTypes;
+    
+    /**
+     * Whether this selector is the parent of a descendent or parent-child join.
+     * Access rights don't need to be checked in such selectors (unless there
+     * are conditions on the selector).
+     */
+    private boolean isParent;  
+    
+    /**
+     * Whether this selector is the left hand side of a left outer join.
+     * Right outer joins are converted to left outer join.
+     */
+    private boolean outerJoinLeftHandSide;
 
-    private Cursor cursor;
-    private IndexRow currentRow;
-    private int scanCount;
+    /**
+     * Whether this selector is the right hand side of a left outer join.
+     * Right outer joins are converted to left outer join.
+     */
+    private boolean outerJoinRightHandSide;
     
-    private Tree lastTree;
-    private String lastPath;
+    /**
+     * The list of all join conditions this selector is involved. For the query
+     * "select * from nt:base as a inner join nt:base as b on a.x =
+     * b.x", the join condition "a.x = b.x" is set for both selectors a and b,
+     * so both can check if the property x is set.
+     */
+    private ArrayList<JoinConditionImpl> allJoinConditions =
+            new ArrayList<JoinConditionImpl>();
 
     /**
      * The selector condition can be evaluated when the given selector is
@@ -106,9 +141,17 @@ public class SelectorImpl extends Source
      * "select * from nt:base a inner join nt:base b where a.x = 1 and b.y = 2",
      * the condition "a.x = 1" can be evaluated when evaluating selector a. The
      * other part of the condition can't be evaluated until b is available.
+     * This field is set during the prepare phase.
      */
     private ConstraintImpl selectorCondition;
 
+    private Cursor cursor;
+    private IndexRow currentRow;
+    private int scanCount;
+    
+    private Tree lastTree;
+    private String lastPath;
+
     public SelectorImpl(NodeState nodeType, String selectorName) {
         this.nodeType = checkNotNull(nodeType);
         this.selectorName = checkNotNull(selectorName);
@@ -134,6 +177,41 @@ public class SelectorImpl extends Source
             this.mixinTypes = ImmutableSet.of();
         }
     }
+    
+    private SelectorImpl(SelectorImpl clone) {
+        this.nodeType = clone.nodeType;
+        this.selectorName = clone.selectorName;
+        this.nodeTypeName = clone.nodeTypeName;
+        this.matchesAllTypes = clone.matchesAllTypes;
+        this.supertypes = clone.supertypes;
+        this.primaryTypes = clone.primaryTypes;
+        this.mixinTypes = clone.mixinTypes;
+        this.query = clone.query;
+        this.isParent = clone.isParent;
+        this.outerJoinLeftHandSide = clone.outerJoinLeftHandSide;
+        this.outerJoinRightHandSide = clone.outerJoinRightHandSide;
+        this.allJoinConditions = clone.allJoinConditions;
+    }
+    
+
+//   queryConstraint;
+//   protected JoinConditionImpl joinCondition;
+//   protected ArrayList<JoinConditionImpl> allJoinConditions =
+//           new ArrayList<JoinConditionImpl>();
+//   protected boolean join;
+//   protected boolean outerJoinLeftHandSide;
+//   protected boolean outerJoinRightHandSide;
+//   protected boolean isParent;    
+    
+    /**
+     * Create a shallow clone of this instance.
+     * 
+     * @return the clone
+     */
+    @Override
+    public SelectorImpl createClone() {
+        return new SelectorImpl(this);
+    }
 
     public String getSelectorName() {
         return selectorName;
@@ -201,6 +279,25 @@ public class SelectorImpl extends Source
         plan = query.getBestSelectorExecutionPlan(createFilter(true));
         return plan.estimatedCost;
     }
+    
+    @Override
+    public void setQueryConstraint(ConstraintImpl queryConstraint) {
+        this.queryConstraint = queryConstraint;
+    }    
+    
+    @Override
+    public void setOuterJoin(boolean outerJoinLeftHandSide, boolean outerJoinRightHandSide) {
+        this.outerJoinLeftHandSide = outerJoinLeftHandSide;
+        this.outerJoinRightHandSide = outerJoinRightHandSide;
+    }    
+    
+    @Override
+    public void addJoinCondition(JoinConditionImpl joinCondition, boolean forThisSelector) {
+        if (forThisSelector) {
+            this.joinCondition = joinCondition;
+        }
+        allJoinConditions.add(joinCondition);
+    }
 
     @Override
     public void execute(NodeState rootState) {
@@ -568,4 +665,16 @@ public class SelectorImpl extends Source
         return plan == null ? null : plan.index;
     }
 
+    @Override
+    public ArrayList<SourceImpl> getInnerJoinSelectors() {
+        ArrayList<SourceImpl> list = new ArrayList<SourceImpl>();
+        list.add(this);
+        return list;
+    }
+
+    @Override
+    public boolean isOuterJoinRightHandSide() {
+        return this.outerJoinRightHandSide;
+    }
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java?rev=1567633&r1=1567632&r2=1567633&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java Wed Feb 12 14:33:38 2014
@@ -18,7 +18,8 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
-import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 import org.apache.jackrabbit.oak.query.QueryImpl;
 import org.apache.jackrabbit.oak.spi.query.Filter;
@@ -28,62 +29,13 @@ import org.apache.jackrabbit.oak.spi.sta
  * The base class of a selector and a join.
  */
 public abstract class SourceImpl extends AstElement {
-
-    /**
-     * The WHERE clause of the query.
-     */
-    protected ConstraintImpl queryConstraint;
-
-    /**
-     * The join condition of this selector that can be evaluated at execution
-     * time. For the query "select * from nt:base as a inner join nt:base as b
-     * on a.x = b.x", the join condition "a.x = b.x" is only set for the
-     * selector b, as selector a can't evaluate it if it is executed first
-     * (until b is executed).
-     */
-    protected JoinConditionImpl joinCondition;
-
-    /**
-     * The list of all join conditions this selector is involved. For the query
-     * "select * from nt:base as a inner join nt:base as b on a.x =
-     * b.x", the join condition "a.x = b.x" is set for both selectors a and b,
-     * so both can check if the property x is set.
-     */
-    protected ArrayList<JoinConditionImpl> allJoinConditions =
-            new ArrayList<JoinConditionImpl>();
-
-    /**
-     * Whether this selector is the right hand side of a join.
-     */
-    protected boolean join;
-
-    /**
-     * Whether this selector is the left hand side of a left outer join.
-     * Right outer joins are converted to left outer join.
-     */
-    protected boolean outerJoinLeftHandSide;
-
-    /**
-     * Whether this selector is the right hand side of a left outer join.
-     * Right outer joins are converted to left outer join.
-     */
-    protected boolean outerJoinRightHandSide;
-    
-    /**
-     * Whether this selector is the parent of a descendent or parent-child join.
-     * Access rights don't need to be checked in such selectors (unless there
-     * are conditions on the selector).
-     */
-    protected boolean isParent;
     
     /**
      * Set the complete constraint of the query (the WHERE ... condition).
      *
      * @param queryConstraint the constraint
      */
-    public void setQueryConstraint(ConstraintImpl queryConstraint) {
-        this.queryConstraint = queryConstraint;
-    }
+    public abstract void setQueryConstraint(ConstraintImpl queryConstraint);
 
     /**
      * Add the join condition (the ON ... condition).
@@ -92,12 +44,7 @@ public abstract class SourceImpl extends
      * @param forThisSelector if set, the join condition can only be evaluated
      *        when all previous selectors are executed.
      */
-    public void addJoinCondition(JoinConditionImpl joinCondition, boolean forThisSelector) {
-        if (forThisSelector) {
-            this.joinCondition = joinCondition;
-        }
-        allJoinConditions.add(joinCondition);
-    }
+    public abstract void addJoinCondition(JoinConditionImpl joinCondition, boolean forThisSelector);
 
     /**
      * Set whether this source is the left hand side or right hand side of a left outer join.
@@ -105,10 +52,7 @@ public abstract class SourceImpl extends
      * @param outerJoinLeftHandSide true if yes
      * @param outerJoinRightHandSide true if yes
      */
-    public void setOuterJoin(boolean outerJoinLeftHandSide, boolean outerJoinRightHandSide) {
-        this.outerJoinLeftHandSide = outerJoinLeftHandSide;
-        this.outerJoinRightHandSide = outerJoinRightHandSide;
-    }
+    public abstract void setOuterJoin(boolean outerJoinLeftHandSide, boolean outerJoinRightHandSide);
 
     /**
      * Initialize the query. This will 'wire' the selectors with the
@@ -170,6 +114,13 @@ public abstract class SourceImpl extends
      * @return true if there is a next row
      */
     public abstract boolean next();
+    
+    /**
+     * Create a shallow clone of this instance.
+     * 
+     * @return the clone
+     */
+    public abstract SourceImpl createClone();
 
     abstract void setParent(JoinConditionImpl joinCondition);
 
@@ -183,4 +134,27 @@ public abstract class SourceImpl extends
      */
     public abstract Filter createFilter(boolean preparing);
 
+    /**
+     * Get all sources that are joined via inner join. (These can be swapped.)
+     * 
+     * @return the list of selectors (sorted from left to right)
+     */
+    public abstract List<SourceImpl> getInnerJoinSelectors();
+    
+    /**
+     * Get the list of inner join conditions. (These match the inner join selectors.)
+     * 
+     * @return the list of join conditions
+     */
+    public List<JoinConditionImpl> getInnerJoinConditions() {
+        return Collections.emptyList();
+    }
+    
+    /**
+     * Whether any selector is the outer-join right hand side.
+     * 
+     * @return true if there is any
+     */
+    public abstract boolean isOuterJoinRightHandSide();
+    
 }