You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2011/03/10 12:20:36 UTC

svn commit: r1080186 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/query/lucene/join/ test/java/org/apache/jackrabbit/core/query/

Author: jukka
Date: Thu Mar 10 11:20:36 2011
New Revision: 1080186

URL: http://svn.apache.org/viewvc?rev=1080186&view=rev
Log:
JCR-2852: Support multi-selector OR constraints in join queries

Patch by Alex Parvulescu

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ConstraintSplitInfo.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoinMerger.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ConstraintSplitter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoinMerger.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoinMerger.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/JoinMerger.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/JoinTest.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoinMerger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoinMerger.java?rev=1080186&r1=1080185&r2=1080186&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoinMerger.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoinMerger.java Thu Mar 10 11:20:36 2011
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.core.query.lucene.join;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -59,7 +60,7 @@ class ChildNodeJoinMerger extends JoinMe
     }
 
     @Override
-    public List<Constraint> getRightJoinConstraints(List<Row> leftRows)
+    public List<Constraint> getRightJoinConstraints(Collection<Row> leftRows)
             throws RepositoryException {
         Set<String> paths = new HashSet<String>();
         for (Row row : leftRows) {

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ConstraintSplitInfo.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ConstraintSplitInfo.java?rev=1080186&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ConstraintSplitInfo.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ConstraintSplitInfo.java Thu Mar 10 11:20:36 2011
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.query.lucene.join;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.query.qom.Constraint;
+import javax.jcr.query.qom.Or;
+import javax.jcr.query.qom.QueryObjectModelFactory;
+
+class ConstraintSplitInfo {
+
+    private final QueryObjectModelFactory factory;
+
+    private final List<Constraint> leftConstraints = new ArrayList<Constraint>();
+
+    private final List<Constraint> rightConstraints = new ArrayList<Constraint>();
+
+    private boolean isMultiple;
+
+    private final List<ConstraintSplitInfo> innerConstraints = new ArrayList<ConstraintSplitInfo>();
+
+    public ConstraintSplitInfo(QueryObjectModelFactory factory) {
+        this.factory = factory;
+        this.isMultiple = false;
+    }
+
+    private ConstraintSplitInfo(QueryObjectModelFactory factory,
+            List<Constraint> leftConstraints, List<Constraint> rightConstraints) {
+        this.factory = factory;
+        this.isMultiple = false;
+        this.leftConstraints.addAll(leftConstraints);
+        this.rightConstraints.addAll(rightConstraints);
+    }
+
+    public void addLeftConstraint(Constraint c) {
+        if (isMultiple) {
+            for (ConstraintSplitInfo csi : innerConstraints) {
+                csi.addLeftConstraint(c);
+            }
+            return;
+        }
+        leftConstraints.add(c);
+    }
+
+    public void addRightConstraint(Constraint c) {
+        if (isMultiple) {
+            for (ConstraintSplitInfo csi : innerConstraints) {
+                csi.addRightConstraint(c);
+            }
+            return;
+        }
+        rightConstraints.add(c);
+    }
+
+    public void split(Or or) {
+        if (isMultiple) {
+            for (ConstraintSplitInfo csi : innerConstraints) {
+                csi.split(or);
+            }
+            return;
+        }
+
+        this.isMultiple = true;
+
+        ConstraintSplitInfo csi1 = new ConstraintSplitInfo(factory,
+                leftConstraints, rightConstraints);
+        csi1.addLeftConstraint(or.getConstraint1());
+        this.innerConstraints.add(csi1);
+
+        ConstraintSplitInfo csi2 = new ConstraintSplitInfo(factory,
+                leftConstraints, rightConstraints);
+        csi2.addLeftConstraint(or.getConstraint2());
+        this.innerConstraints.add(csi2);
+
+        // would null be better?
+        this.leftConstraints.clear();
+        this.rightConstraints.clear();
+    }
+
+    public boolean isMultiple() {
+        return isMultiple;
+    }
+
+    public List<ConstraintSplitInfo> getInnerConstraints() {
+        return innerConstraints;
+    }
+
+    /**
+     * @return the left constraint
+     */
+    public Constraint getLeftConstraint() throws RepositoryException {
+        return Constraints.and(factory, leftConstraints);
+    }
+
+    /**
+     * @return the right constraint
+     */
+    public Constraint getRightConstraint() throws RepositoryException {
+        return Constraints.and(factory, rightConstraints);
+    }
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ConstraintSplitter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ConstraintSplitter.java?rev=1080186&r1=1080185&r2=1080186&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ConstraintSplitter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ConstraintSplitter.java Thu Mar 10 11:20:36 2011
@@ -16,10 +16,8 @@
  */
 package org.apache.jackrabbit.core.query.lucene.join;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
 import javax.jcr.RepositoryException;
@@ -45,15 +43,17 @@ import javax.jcr.query.qom.SameNode;
 import javax.jcr.query.qom.UpperCase;
 
 /**
- * Returns a mapped constraint that only refers to the given set of
- * selectors. The returned constraint is guaranteed to match an as small
- * as possible superset of the node tuples matched by the given original
- * constraints.
+ * Returns a mapped constraint that only refers to the given set of selectors.
+ * The returned constraint is guaranteed to match an as small as possible
+ * superset of the node tuples matched by the given original constraints.
  *
- * @param constraint original constraint
- * @param selectors target selectors
+ * @param constraint
+ *            original constraint
+ * @param selectors
+ *            target selectors
  * @return mapped constraint
- * @throws RepositoryException if the constraint mapping fails
+ * @throws RepositoryException
+ *             if the constraint mapping fails
  */
 class ConstraintSplitter {
 
@@ -63,39 +63,21 @@ class ConstraintSplitter {
 
     private final Set<String> rightSelectors;
 
-    private final List<Constraint> leftConstraints =
-        new ArrayList<Constraint>();
+    private final ConstraintSplitInfo constraintSplitInfo;
 
-    private final List<Constraint> rightConstraints =
-        new ArrayList<Constraint>();
-
-    public ConstraintSplitter(
-            Constraint constraint, QueryObjectModelFactory factory,
-            Set<String> leftSelectors, Set<String> rightSelectors)
-            throws RepositoryException {
+    public ConstraintSplitter(Constraint constraint,
+            QueryObjectModelFactory factory, Set<String> leftSelectors,
+            Set<String> rightSelectors) throws RepositoryException {
         this.factory = factory;
         this.leftSelectors = leftSelectors;
         this.rightSelectors = rightSelectors;
+        constraintSplitInfo = new ConstraintSplitInfo(this.factory);
 
         if (constraint != null) {
             split(constraint);
         }
     }
 
-    /**
-     * @return the left constraint
-     */
-    public Constraint getLeftConstraint() throws RepositoryException {
-        return Constraints.and(factory, leftConstraints);
-    }
-
-    /**
-     * @return the right constraint
-     */
-    public Constraint getRightConstraint() throws RepositoryException {
-        return Constraints.and(factory, rightConstraints);
-    }
-
     private void split(Constraint constraint) throws RepositoryException {
         if (constraint instanceof Not) {
             splitNot((Not) constraint);
@@ -103,24 +85,33 @@ class ConstraintSplitter {
             And and = (And) constraint;
             split(and.getConstraint1());
             split(and.getConstraint2());
+        } else if (constraint instanceof Or) {
+            if (isReferencingBothSides(getSelectorNames(constraint))) {
+                constraintSplitInfo.split((Or) constraint);
+            } else {
+                splitBySelectors(constraint, getSelectorNames(constraint));
+            }
         } else {
             splitBySelectors(constraint, getSelectorNames(constraint));
         }
     }
 
+    private boolean isReferencingBothSides(Set<String> selectors) {
+        return !leftSelectors.containsAll(selectors)
+                && !rightSelectors.containsAll(selectors);
+    }
+
     private void splitNot(Not not) throws RepositoryException {
         Constraint constraint = not.getConstraint();
         if (constraint instanceof Not) {
             split(((Not) constraint).getConstraint());
         } else if (constraint instanceof And) {
             And and = (And) constraint;
-            split(factory.or(
-                    factory.not(and.getConstraint1()),
+            split(factory.or(factory.not(and.getConstraint1()),
                     factory.not(and.getConstraint2())));
         } else if (constraint instanceof Or) {
             Or or = (Or) constraint;
-            split(factory.and(
-                    factory.not(or.getConstraint1()),
+            split(factory.and(factory.not(or.getConstraint1()),
                     factory.not(or.getConstraint2())));
         } else {
             splitBySelectors(not, getSelectorNames(constraint));
@@ -130,23 +121,24 @@ class ConstraintSplitter {
     private void splitBySelectors(Constraint constraint, Set<String> selectors)
             throws UnsupportedRepositoryOperationException {
         if (leftSelectors.containsAll(selectors)) {
-            leftConstraints.add(constraint);
+            constraintSplitInfo.addLeftConstraint(constraint);
         } else if (rightSelectors.containsAll(selectors)) {
-            rightConstraints.add(constraint);
+            constraintSplitInfo.addRightConstraint(constraint);
         } else {
             throw new UnsupportedRepositoryOperationException(
                     "Unable to split a constraint that references"
-                    + " both sides of a join: " + constraint);
+                            + " both sides of a join: " + constraint);
         }
     }
 
     /**
      * Returns the names of the selectors referenced by the given constraint.
      *
-     * @param constraint constraint
+     * @param constraint
+     *            constraint
      * @return referenced selector names
      * @throws UnsupportedRepositoryOperationException
-     *         if the constraint type is unknown
+     *             if the constraint type is unknown
      */
     private Set<String> getSelectorNames(Constraint constraint)
             throws UnsupportedRepositoryOperationException {
@@ -184,14 +176,16 @@ class ConstraintSplitter {
     }
 
     /**
-     * Returns the combined set of selector names referenced by the given
-     * two constraint.
+     * Returns the combined set of selector names referenced by the given two
+     * constraint.
      *
-     * @param a first constraint
-     * @param b second constraint
+     * @param a
+     *            first constraint
+     * @param b
+     *            second constraint
      * @return selector names
      * @throws UnsupportedRepositoryOperationException
-     *         if the constraint types are unknown
+     *             if the constraint types are unknown
      */
     private Set<String> getSelectorNames(Constraint a, Constraint b)
             throws UnsupportedRepositoryOperationException {
@@ -204,10 +198,11 @@ class ConstraintSplitter {
     /**
      * Returns the selector name referenced by the given dynamic operand.
      *
-     * @param operand dynamic operand
+     * @param operand
+     *            dynamic operand
      * @return selector name
      * @throws UnsupportedRepositoryOperationException
-     *         if the operand type is unknown
+     *             if the operand type is unknown
      */
     private String getSelectorName(DynamicOperand operand)
             throws UnsupportedRepositoryOperationException {
@@ -238,4 +233,8 @@ class ConstraintSplitter {
         }
     }
 
+    public ConstraintSplitInfo getConstraintSplitInfo() {
+        return constraintSplitInfo;
+    }
+
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoinMerger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoinMerger.java?rev=1080186&r1=1080185&r2=1080186&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoinMerger.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoinMerger.java Thu Mar 10 11:20:36 2011
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.core.query.lucene.join;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -59,7 +60,7 @@ class DescendantNodeJoinMerger extends J
     }
 
     @Override
-    public List<Constraint> getRightJoinConstraints(List<Row> leftRows)
+    public List<Constraint> getRightJoinConstraints(Collection<Row> leftRows)
             throws RepositoryException {
         Set<String> paths = new HashSet<String>();
         for (Row row : leftRows) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoinMerger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoinMerger.java?rev=1080186&r1=1080185&r2=1080186&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoinMerger.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoinMerger.java Thu Mar 10 11:20:36 2011
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.core.query
 import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -76,7 +77,7 @@ class EquiJoinMerger extends JoinMerger 
     }
 
     @Override
-    public List<Constraint> getRightJoinConstraints(List<Row> leftRows)
+    public List<Constraint> getRightJoinConstraints(Collection<Row> leftRows)
             throws RepositoryException {
         Map<String, Literal> literals = new HashMap<String, Literal>();
         for (Row leftRow : leftRows) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/JoinMerger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/JoinMerger.java?rev=1080186&r1=1080185&r2=1080186&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/JoinMerger.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/JoinMerger.java Thu Mar 10 11:20:36 2011
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.core.query
 import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_LEFT_OUTER;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
@@ -224,7 +225,7 @@ abstract class JoinMerger {
     public abstract Set<String> getRightValues(Row row)
             throws RepositoryException;
 
-    public abstract List<Constraint> getRightJoinConstraints(List<Row> leftRows)
+    public abstract List<Constraint> getRightJoinConstraints(Collection<Row> leftRows)
             throws RepositoryException;
 
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java?rev=1080186&r1=1080185&r2=1080186&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java Thu Mar 10 11:20:36 2011
@@ -24,9 +24,12 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
@@ -164,45 +167,98 @@ public class QueryEngine {
                 merger.getLeftSelectors(), merger.getRightSelectors());
 
         Source left = join.getLeft();
-        Constraint leftConstraint = splitter.getLeftConstraint();
-        QueryResult leftResult =
-            execute(null, left, leftConstraint, null, 0, -1);
-        List<Row> leftRows = new ArrayList<Row>();
+        Set<Row> leftRows = buildLeftRowsJoin(left, splitter.getConstraintSplitInfo());
+
+        Source right = join.getRight();
+        List<Constraint> rightConstraints = merger.getRightJoinConstraints(leftRows);
+        RowIterator rightRows = new RowIteratorAdapter(buildRightRowsJoin(right, splitter.getConstraintSplitInfo(), rightConstraints));
+
+        QueryResult result = merger.merge(new RowIteratorAdapter(leftRows), rightRows);
+        return sort(result, orderings, offset, limit);
+    }
+
+    private Comparator<Row> buildSimplePathRowComparator() {
+        return new Comparator<Row>() {
+
+            public int compare(Row o1, Row o2) {
+                try {
+                    return o1.getPath().compareTo(o2.getPath());
+                } catch (RepositoryException e) {
+                    throw new RuntimeException("Unable to compare rows " + o1
+                            + " and " + o2, e);
+                }
+            }
+        };
+    }
+
+    private Set<Row> buildLeftRowsJoin(Source left, ConstraintSplitInfo csi)
+            throws RepositoryException {
+
+        if (csi.isMultiple()) {
+            // this *needs* to merge automatically multiple sets of nodes
+            Set<Row> leftRows = new TreeSet<Row>(buildSimplePathRowComparator());
+            for (ConstraintSplitInfo child : csi.getInnerConstraints()) {
+                leftRows.addAll(buildLeftRowsJoin(left, child));
+            }
+            return leftRows;
+        }
+
+        Set<Row> leftRows = new HashSet<Row>();
+        Constraint leftConstraint = csi.getLeftConstraint();
+        QueryResult leftResult = execute(null, left, leftConstraint, null, 0,
+                -1);
         for (Row row : JcrUtils.getRows(leftResult)) {
             leftRows.add(row);
         }
+        return leftRows;
+    }
 
-        RowIterator rightRows;
-        Source right = join.getRight();
-        List<Constraint> rightConstraints =
-            merger.getRightJoinConstraints(leftRows);
+    private Set<Row> buildRightRowsJoin(Source right, ConstraintSplitInfo csi,
+            List<Constraint> rightConstraints) throws RepositoryException {
+
+        if (csi.isMultiple()) {
+            // this *needs* to merge automatically multiple sets of nodes
+            Set<Row> rightRows = new TreeSet<Row>(
+                    buildSimplePathRowComparator());
+            for (ConstraintSplitInfo child : csi.getInnerConstraints()) {
+                rightRows.addAll(buildRightRowsJoin(right, child,
+                        rightConstraints));
+            }
+            return rightRows;
+        }
+
+        // TODO refactor to page automatically at 500 *if needed*
         if (rightConstraints.size() < 500) {
-            Constraint rightConstraint = Constraints.and(
-                    qomFactory,
+            Set<Row> rightRows = new HashSet<Row>();
+            Constraint rightConstraint = Constraints.and(qomFactory,
                     Constraints.or(qomFactory, rightConstraints),
-                    splitter.getRightConstraint());
-            rightRows =
-                execute(null, right, rightConstraint, null, 0, -1).getRows();
-        } else {
-            List<Row> list = new ArrayList<Row>();
-            for (int i = 0; i < rightConstraints.size(); i += 500) {
-                Constraint rightConstraint = Constraints.and(
-                        qomFactory,
-                        Constraints.or(qomFactory, rightConstraints.subList(
-                                i, Math.min(i + 500, rightConstraints.size()))),
-                        splitter.getRightConstraint());
-                QueryResult rightResult =
-                    execute(null, right, rightConstraint, null, 0, -1);
-                for (Row row : JcrUtils.getRows(rightResult)) {
-                    list.add(row);
-                }
+                    csi.getRightConstraint());
+            QueryResult rightResult = execute(null, right, rightConstraint,
+                    null, 0, -1);
+            for (Row row : JcrUtils.getRows(rightResult)) {
+                rightRows.add(row);
+            }
+            return rightRows;
+        }
+
+        Set<Row> rightRows = new HashSet<Row>();
+        for (int i = 0; i < rightConstraints.size(); i += 500) {
+            Constraint rightConstraint = Constraints
+                    .and(qomFactory,
+                            Constraints.or(
+                                    qomFactory,
+                                    rightConstraints.subList(
+                                            i,
+                                            Math.min(i + 500,
+                                                    rightConstraints.size()))),
+                            csi.getRightConstraint());
+            QueryResult rightResult = execute(null, right, rightConstraint,
+                    null, 0, -1);
+            for (Row row : JcrUtils.getRows(rightResult)) {
+                rightRows.add(row);
             }
-            rightRows = new RowIteratorAdapter(list);
         }
-
-        QueryResult result =
-            merger.merge(new RowIteratorAdapter(leftRows), rightRows);
-        return sort(result, orderings, offset, limit);
+        return rightRows;
     }
 
     protected QueryResult execute(

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java?rev=1080186&r1=1080185&r2=1080186&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java Thu Mar 10 11:20:36 2011
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.core.query.lucene.join;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -62,7 +63,7 @@ class SameNodeJoinMerger extends JoinMer
     }
 
     @Override
-    public List<Constraint> getRightJoinConstraints(List<Row> leftRows)
+    public List<Constraint> getRightJoinConstraints(Collection<Row> leftRows)
             throws RepositoryException {
         Set<String> paths = new HashSet<String>();
         for (Row row : leftRows) {

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/JoinTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/JoinTest.java?rev=1080186&r1=1080185&r2=1080186&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/JoinTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/JoinTest.java Thu Mar 10 11:20:36 2011
@@ -23,8 +23,7 @@ import javax.jcr.query.Query;
 import javax.jcr.query.QueryResult;
 
 /**
- * Test case for
- * <a href="https://issues.apache.org/jira/browse/JCR-2718">JCR-2718</a>
+ * Test case for JOIN queries with JCR_SQL2
  */
 public class JoinTest extends AbstractQueryTest {
 
@@ -45,8 +44,7 @@ public class JoinTest extends AbstractQu
 
         Node n3 = node.addNode("node3");
         n3.addMixin(NodeType.MIX_REFERENCEABLE);
-        n3.setProperty(
-                "testref",
+        n3.setProperty("testref",
                 new String[] { n1.getIdentifier(), n2.getIdentifier() },
                 PropertyType.REFERENCE);
         testRootNode.getSession().save();
@@ -59,12 +57,72 @@ public class JoinTest extends AbstractQu
         super.tearDown();
     }
 
+    /**
+     * Test case for <a
+     * href="https://issues.apache.org/jira/browse/JCR-2718">JCR-2718</a>
+     */
     public void testMultiValuedReferenceJoin() throws Exception {
-        String join =
-            "SELECT a.*, b.*"
-            + " FROM [nt:base] AS a"
-            + " INNER JOIN [nt:base] AS b ON a.[jcr:uuid] = b.testref";
-        QueryResult result = qm.createQuery(join, Query.JCR_SQL2).execute();
+        String join = "SELECT a.*, b.*" + " FROM [nt:base] AS a"
+                + " INNER JOIN [nt:base] AS b ON a.[jcr:uuid] = b.testref";
+        checkResult(qm.createQuery(join, Query.JCR_SQL2).execute(), 2);
+    }
+
+    /**
+     * Test case for <a
+     * href="https://issues.apache.org/jira/browse/JCR-2852">JCR-2852</a>
+     */
+    public void testJoinWithOR() throws Exception {
+
+        String join = "SELECT a.*, b.*"
+                + " FROM [nt:base] AS a"
+                + " INNER JOIN [nt:base] AS b ON a.[jcr:uuid] = b.testref WHERE "
+                + "a.[jcr:primaryType] IS NOT NULL OR b.[jcr:primaryType] IS NOT NULL";
+
+        Query q = qm.createQuery(join, Query.JCR_SQL2);
+        QueryResult result = q.execute();
+        checkResult(result, 2);
+    }
+
+    /**
+     * Test case for <a
+     * href="https://issues.apache.org/jira/browse/JCR-2852">JCR-2852</a> <br>
+     * <p>
+     * Test inspired by <a
+     * href="http://markmail.org/message/gee5yyygozestsml">this discussion</a>
+     */
+    public void testMegaJoin() throws Exception {
+
+        // WHERE
+        // ( (ISSAMENODE(projects,
+        // '/repository/projects/U970f5509-54de-46d8-88bd-bc1a94ab85eb')))
+        // AND
+        // ( ( ISDESCENDANTNODE( projects, '/repository/projects') AND
+        // eventclassassociations.active = true )
+        // or
+        // ( ISDESCENDANTNODE( projects, '/repository/template') )
+        // )
+        // AND ((NAME(parentRelationshipStatus) = 'parentRelationshipStatus'))
+
+        StringBuilder join = new StringBuilder(
+                "SELECT a.*, b.* FROM [nt:base] AS a");
+        join.append("  INNER JOIN [nt:base] AS b ON a.[jcr:uuid] = b.testref ");
+        join.append("  WHERE  ");
+        join.append("  ISSAMENODE(b, '/testroot/jointest/node3') ");
+        join.append("  AND ");
+        join.append("  ( ");
+        join.append("    ( ");
+        join.append("    ISDESCENDANTNODE(b, '/testroot/jointest') ");
+        join.append("    AND ");
+        join.append("    b.testref IS NOT NULL ");
+        join.append("    ) ");
+        join.append("    OR ");
+        join.append("    ISDESCENDANTNODE(a, '/testroot/jointest') ");
+        join.append("  ) ");
+        join.append("  AND ");
+        join.append(" (NAME(b) = 'node3') ");
+
+        Query q = qm.createQuery(join.toString(), Query.JCR_SQL2);
+        QueryResult result = q.execute();
         checkResult(result, 2);
     }