You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2012/03/09 17:52:04 UTC

svn commit: r1298914 - in /jackrabbit/sandbox/jackrabbit-microkernel/src: main/java/org/apache/jackrabbit/query/ main/java/org/apache/jackrabbit/query/qom/ main/java/org/apache/jackrabbit/query/qom/tree/ main/java/org/apache/jackrabbit/query/reader/ te...

Author: thomasm
Date: Fri Mar  9 16:52:03 2012
New Revision: 1298914

URL: http://svn.apache.org/viewvc?rev=1298914&view=rev
Log:
Query implementation (WIP) - outer joins, explain plan feature

Removed:
    jackrabbit/sandbox/jackrabbit-microkernel/src/test/java/org/apache/jackrabbit/query/SQL2Test.java
Modified:
    jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserSQL2.java
    jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/QueryObjectModelImpl.java
    jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/JoinImpl.java
    jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SelectorImpl.java
    jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SourceImpl.java
    jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/reader/NodeReader.java
    jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/reader/TraversingReader.java
    jackrabbit/sandbox/jackrabbit-microkernel/src/test/java/org/apache/jackrabbit/query/QueryTest.java
    jackrabbit/sandbox/jackrabbit-microkernel/src/test/resources/queryTest.txt

Modified: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserSQL2.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserSQL2.java?rev=1298914&r1=1298913&r2=1298914&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserSQL2.java (original)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/ParserSQL2.java Fri Mar  9 16:52:03 2012
@@ -104,6 +104,7 @@ public class ParserSQL2 {
         expected = new ArrayList<String>();
         bindVariables = new HashMap<String, BindVariableValue>();
         read();
+        boolean explain = readIf("EXPLAIN");
         read("SELECT");
         ArrayList<ColumnOrWildcard> list = parseColumns();
         read("FROM");
@@ -121,7 +122,9 @@ public class ParserSQL2 {
         if (currentToken.length() > 0) {
             throw getSyntaxError("<end>");
         }
-        return factory.createQuery(source, constraint, orderings, columnArray);
+        QueryObjectModelImpl q = factory.createQuery(source, constraint, orderings, columnArray);
+        q.setExplain(explain);
+        return q;
     }
 
     private Selector parseSelector() throws RepositoryException {

Modified: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/QueryObjectModelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/QueryObjectModelImpl.java?rev=1298914&r1=1298913&r2=1298914&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/QueryObjectModelImpl.java (original)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/QueryObjectModelImpl.java Fri Mar  9 16:52:03 2012
@@ -13,6 +13,7 @@
  */
 package org.apache.jackrabbit.query.qom;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 import javax.jcr.Node;
@@ -60,6 +61,7 @@ public class QueryObjectModelImpl implem
     private final OrderingImpl[] orderings;
     private final ColumnImpl[] columns;
     final HashMap<String, Value> bindVariableMap = new HashMap<String, Value>();
+    private boolean explain;
     private long limit;
     private long offset;
     private boolean prepared;
@@ -273,10 +275,17 @@ public class QueryObjectModelImpl implem
         return valueFactory;
     }
 
+    public void setExplain(boolean explain) {
+        this.explain = explain;
+    };
+
     public Iterator<String> executeQuery(String revisionId) {
         prepare();
-        ResultIterator result = new ResultIterator(revisionId);
-        return result;
+        if (explain) {
+            return Arrays.asList(source.getPlan()).iterator();
+        } else {
+            return new ResultIterator(revisionId);
+        }
     }
 
     private void prepare() {
@@ -347,6 +356,6 @@ public class QueryObjectModelImpl implem
             throw new UnsupportedOperationException();
         }
 
-    };
+    }
 
 }

Modified: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/JoinImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/JoinImpl.java?rev=1298914&r1=1298913&r2=1298914&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/JoinImpl.java (original)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/JoinImpl.java Fri Mar  9 16:52:03 2012
@@ -23,12 +23,13 @@ import org.apache.jackrabbit.query.qom.Q
  */
 public class JoinImpl extends SourceImpl implements Join {
 
-    private final SourceImpl left;
-    private final SourceImpl right;
-    private final JoinType joinType;
-    private final JoinConditionImpl joinCondition;
+    private JoinType joinType;
+    private SourceImpl left;
+    private SourceImpl right;
+    private JoinConditionImpl joinCondition;
     private boolean leftNeedExecute, rightNeedExecute;
     private boolean leftNeedNext;
+    private boolean foundJoinedRow;
     private boolean end;
     private String revisionId;
 
@@ -61,6 +62,10 @@ public class JoinImpl extends SourceImpl
         return v.visit(this);
     }
 
+    public String getPlan() {
+        return left.getPlan() + " " + joinType.name() + " JOIN " + right.getPlan();
+    }
+
     public String toString() {
         return joinType.formatSql(left, right, joinCondition);
     }
@@ -90,6 +95,13 @@ public class JoinImpl extends SourceImpl
             left.setJoinCondition(joinCondition);
             right.init(qom);
             left.init(qom);
+            // TODO right outer join: verify whether converting
+            // to left outer join is always correct (given the current restrictions)
+            joinType = JoinType.LEFT;
+            // swap left and right
+            SourceImpl temp = left;
+            left = right;
+            right = temp;
             break;
         }
     }
@@ -137,15 +149,22 @@ public class JoinImpl extends SourceImpl
             }
             if (rightNeedExecute) {
                 right.execute(revisionId);
+                foundJoinedRow = false;
                 rightNeedExecute = false;
             }
             if (!right.next()) {
                 leftNeedNext = true;
             } else {
                 if (joinCondition.evaluate()) {
+                    foundJoinedRow = true;
                     return true;
                 }
             }
+            // for an outer join, if no matching result was found,
+            // one row returned (with all values set to null)
+            if (right.outerJoin && leftNeedNext && !foundJoinedRow) {
+                return true;
+            }
         }
     }
 

Modified: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SelectorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SelectorImpl.java?rev=1298914&r1=1298913&r2=1298914&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SelectorImpl.java (original)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SelectorImpl.java Fri Mar  9 16:52:03 2012
@@ -19,7 +19,13 @@
 package org.apache.jackrabbit.query.qom.tree;
 
 import javax.jcr.query.qom.Selector;
+import org.apache.jackrabbit.mk.api.MicroKernel;
+import org.apache.jackrabbit.mk.simple.NodeImpl;
 import org.apache.jackrabbit.query.qom.QueryObjectModelImpl;
+import org.apache.jackrabbit.query.reader.Cursor;
+import org.apache.jackrabbit.query.reader.Filter;
+import org.apache.jackrabbit.query.reader.NodeReader;
+import org.apache.jackrabbit.query.reader.TraversingReader;
 
 /**
  * The implementation of the corresponding JCR interface.
@@ -27,6 +33,8 @@ import org.apache.jackrabbit.query.qom.Q
 public class SelectorImpl extends SourceImpl implements Selector {
 
     private final String nodeTypeName, selectorName;
+    protected NodeReader reader;
+    private Cursor cursor;
 
     public SelectorImpl(String nodeTypeName, String selectorName) {
         this.nodeTypeName = nodeTypeName;
@@ -51,6 +59,36 @@ public class SelectorImpl extends Source
         return nodeTypeName + " AS " + getSelectorName();
     }
 
+
+    public void prepare(MicroKernel mk) {
+        reader = new TraversingReader(mk);
+    }
+
+    @Override
+    public void execute(String revisionId) {
+        cursor = reader.query(getFilter(), revisionId);
+    }
+
+    public String getPlan() {
+        return  nodeTypeName + " AS " + getSelectorName() + " /* " + reader.getPlan(getFilter()) + " */";
+    }
+
+    private Filter getFilter() {
+        return new Filter();
+    }
+
+    public boolean next() {
+        return cursor.next();
+    }
+
+    public String currentPath() {
+        return cursor.currentPath();
+    }
+
+    public NodeImpl currentNode() {
+        return cursor.currentNode();
+    }
+
     @Override
     public void init(QueryObjectModelImpl qom) {
         // TODO Auto-generated method stub

Modified: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SourceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SourceImpl.java?rev=1298914&r1=1298913&r2=1298914&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SourceImpl.java (original)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/qom/tree/SourceImpl.java Fri Mar  9 16:52:03 2012
@@ -22,10 +22,6 @@ import javax.jcr.query.qom.Source;
 import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.mk.simple.NodeImpl;
 import org.apache.jackrabbit.query.qom.QueryObjectModelImpl;
-import org.apache.jackrabbit.query.reader.Cursor;
-import org.apache.jackrabbit.query.reader.Filter;
-import org.apache.jackrabbit.query.reader.NodeReader;
-import org.apache.jackrabbit.query.reader.TraversingReader;
 
 public abstract class SourceImpl extends QOMNode implements Source {
 
@@ -33,8 +29,6 @@ public abstract class SourceImpl extends
     protected JoinConditionImpl joinCondition;
     protected boolean join;
     protected boolean outerJoin;
-    private NodeReader reader;
-    private Cursor cursor;
 
     public void setQueryConstraint(ConstraintImpl queryConstraint) {
         this.queryConstraint = queryConstraint;
@@ -52,24 +46,16 @@ public abstract class SourceImpl extends
 
     public abstract SelectorImpl getSelector(String selectorName);
 
-    public void prepare(MicroKernel mk) {
-        reader = new TraversingReader(mk);
-    }
+    public abstract String getPlan();
 
-    public void execute(String revisionId) {
-        cursor = reader.query(new Filter(), revisionId);
-    }
+    public abstract void prepare(MicroKernel mk);
 
-    public boolean next() {
-        return cursor.next();
-    }
+    public abstract void execute(String revisionId);
 
-    public String currentPath() {
-        return cursor.currentPath();
-    }
+    public abstract boolean next();
 
-    public NodeImpl currentNode() {
-        return cursor.currentNode();
-    }
+    public abstract String currentPath();
+
+    public abstract NodeImpl currentNode();
 
 }

Modified: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/reader/NodeReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/reader/NodeReader.java?rev=1298914&r1=1298913&r2=1298914&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/reader/NodeReader.java (original)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/reader/NodeReader.java Fri Mar  9 16:52:03 2012
@@ -42,4 +42,12 @@ public interface NodeReader {
      */
     Cursor query(Filter filter, String revisionId);
 
+    /**
+     * Get the query plan for the given reader.
+     *
+     * @param filter the filter
+     * @return the query plan
+     */
+    String getPlan(Filter filter);
+
 }

Modified: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/reader/TraversingReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/reader/TraversingReader.java?rev=1298914&r1=1298913&r2=1298914&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/reader/TraversingReader.java (original)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/query/reader/TraversingReader.java Fri Mar  9 16:52:03 2012
@@ -53,4 +53,8 @@ public class TraversingReader implements
         return nodeCount;
     }
 
+    public String getPlan(Filter filter) {
+        return "traverse \"" + filter.getPath() + "\"";
+    }
+
 }

Modified: jackrabbit/sandbox/jackrabbit-microkernel/src/test/java/org/apache/jackrabbit/query/QueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/test/java/org/apache/jackrabbit/query/QueryTest.java?rev=1298914&r1=1298913&r2=1298914&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/test/java/org/apache/jackrabbit/query/QueryTest.java (original)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/test/java/org/apache/jackrabbit/query/QueryTest.java Fri Mar  9 16:52:03 2012
@@ -84,7 +84,7 @@ public class QueryTest {
                     if (!line.equals(got)) {
                         errors = true;
                     }
-                } else if (line.startsWith("select")) {
+                } else if (line.startsWith("select") || line.startsWith("explain")) {
                     w.println(line);
                     Iterator<String> result = qe.executeQuery(line, null);
                     boolean readEnd = true;

Modified: jackrabbit/sandbox/jackrabbit-microkernel/src/test/resources/queryTest.txt
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/test/resources/queryTest.txt?rev=1298914&r1=1298913&r2=1298914&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/test/resources/queryTest.txt (original)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/test/resources/queryTest.txt Fri Mar  9 16:52:03 2012
@@ -1,6 +1,7 @@
 # Syntax:
 # * lines starting with "#" are remarks.
 # * lines starting with "select" are queries, followed by expected results and an empty line
+# * lines starting with "explain" are followed by expected query plan and an empty line
 # * all other lines are are committed into the microkernel (line by line)
 # * new tests are typically be added on top, after the syntax docs
 # * use ascii character only
@@ -8,11 +9,34 @@
 + "parents": { "p0": {"id": "0"}, "p1": {"id": "1"}, "p2": {"id": "2"}}
 + "children": { "c1": {"p": "1"}, "c2": {"p": "1"}, "c3": {"p": "2"}, "c4": {"p": "3"}}
 
+select * from [nt:base] as c right outer join [nt:base] as p on p.id = c.p where p.id is not null
+/parents/p0
+/parents/p1
+/parents/p1
+/parents/p2
+
+select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null
+/parents/p0
+/parents/p1
+/parents/p1
+/parents/p2
+
+select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is null
+/parents/p0
+
+select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is not null
+/parents/p1
+/parents/p1
+/parents/p2
+
 select * from [nt:base] as p inner join [nt:base] as c on p.id = c.p
 /parents/p1
 /parents/p1
 /parents/p2
 
+explain select * from [nt:base] as p inner join [nt:base] as c on p.id = c.p
+nt:base AS p /* traverse "/" */ INNER JOIN nt:base AS c /* traverse "/" */
+
 - "parents"
 - "children"