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 2012/05/22 16:58:08 UTC

svn commit: r1341505 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/api/ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ oak-core/src/main/java/org/apache/ja...

Author: thomasm
Date: Tue May 22 14:58:07 2012
New Revision: 1341505

URL: http://svn.apache.org/viewvc?rev=1341505&view=rev
Log:
OAK-28 Query implementation - implement missing features

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/QueryEngine.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/CoreValueImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java
    jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt
    jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryXpathTest.txt
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryManagerImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/RowImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/qom/QueryObjectModelImpl.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/QueryEngine.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/QueryEngine.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/QueryEngine.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/QueryEngine.java Tue May 22 14:58:07 2012
@@ -50,12 +50,15 @@ public interface QueryEngine {
      * @param statement the query statement
      * @param language the language
      * @param session the content session to use
+     * @param limit the maximum result set size
+     * @param offset the number of rows to skip
      * @param bindings the bind variable value bindings
      * @return the result
      * @throws ParseException if the statement could not be parsed
      * @throws IllegalArgumentException if there was an error executing the query
      */
-    Result executeQuery(String statement, String language, ContentSession session, Map<String, CoreValue> bindings) throws ParseException;
+    Result executeQuery(String statement, String language, ContentSession session,
+            long limit, long offset, Map<String, CoreValue> bindings) throws ParseException;
 
     // TODO pass namespace mapping
     // TODO pass node type information (select * from [xyz] is supposed to return at least the mandatory columns for xyz)

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/CoreValueImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/CoreValueImpl.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/CoreValueImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/CoreValueImpl.java Tue May 22 14:58:07 2012
@@ -17,12 +17,14 @@
 package org.apache.jackrabbit.oak.kernel;
 
 import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.util.ISO8601;
 
 import javax.jcr.PropertyType;
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.math.BigDecimal;
+import java.util.Calendar;
 
 /**
  * {@code CoreValueImpl} is the default implementation of the {@code CoreValue}
@@ -304,6 +306,10 @@ class CoreValueImpl implements CoreValue
                 return ((BigDecimal) value).compareTo(o.getDecimal());
             case PropertyType.BOOLEAN:
                 return ((Boolean) value).compareTo(o.getBoolean());
+            case PropertyType.DATE:
+                Calendar d1 = ISO8601.parse(getString());
+                Calendar d2 = ISO8601.parse(o.getString());
+                return d1.compareTo(d2);
             default:
                 return value.toString().compareTo(o.toString());
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java Tue May 22 14:58:07 2012
@@ -60,6 +60,7 @@ public class Query {
     final SourceImpl source;
     final ConstraintImpl constraint;
     final HashMap<String, CoreValue> bindVariableMap = new HashMap<String, CoreValue>();
+    final HashMap<String, Integer> selectorIndexes = new HashMap<String, Integer>();
     final ArrayList<SelectorImpl> selectors = new ArrayList<SelectorImpl>();
 
     private MicroKernel mk;
@@ -67,7 +68,7 @@ public class Query {
     private final OrderingImpl[] orderings;
     private ColumnImpl[] columns;
     private boolean explain;
-    private long limit;
+    private long limit = Long.MAX_VALUE;
     private long offset;
     private boolean prepared;
     private final CoreValueFactory valueFactory;
@@ -200,6 +201,10 @@ public class Query {
 
             @Override
             public boolean visit(SelectorImpl node) {
+                String name = node.getSelectorName();
+                if (selectorIndexes.put(name, selectors.size()) != null) {
+                    throw new IllegalArgumentException("Two selectors with the same name: " + name);
+                }
                 selectors.add(node);
                 node.setQuery(query);
                 return true;
@@ -290,7 +295,7 @@ public class Query {
             ResultRowImpl r = new ResultRowImpl(this, new String[0], new CoreValue[] { getValueFactory().createValue(plan) }, null);
             it = Arrays.asList(r).iterator();
         } else {
-            it = new RowIterator(revisionId);
+            it = new RowIterator(revisionId, limit, offset);
             if (orderings != null) {
                 // TODO "order by" is not necessary if the used index returns
                 // rows in the same order
@@ -345,15 +350,22 @@ public class Query {
         private final String revisionId;
         private ResultRowImpl current;
         private boolean started, end;
+        private long limit, offset, rowIndex;
 
-        RowIterator(String revisionId) {
+        RowIterator(String revisionId, long limit, long offset) {
             this.revisionId = revisionId;
+            this.limit = limit;
+            this.offset = offset;
         }
 
         private void fetchNext() {
             if (end) {
                 return;
             }
+            if (rowIndex >= limit) {
+                end = true;
+                return;
+            }
             if (!started) {
                 source.execute(revisionId);
                 started = true;
@@ -361,7 +373,12 @@ public class Query {
             while (true) {
                 if (source.next()) {
                     if (constraint == null || constraint.evaluate()) {
+                        if (offset > 0) {
+                            offset--;
+                            continue;
+                        }
                         current = currentRow();
+                        rowIndex++;
                         break;
                     }
                 } else {
@@ -430,12 +447,11 @@ public class Query {
     }
 
     public int getSelectorIndex(String selectorName) {
-        for (int i = 0, size = selectors.size(); i < size; i++) {
-            if (selectors.get(i).getSelectorName().equals(selectorName)) {
-                return i;
-            }
+        Integer index = selectorIndexes.get(selectorName);
+        if (index == null) {
+            throw new IllegalArgumentException("Unknown selector: " + selectorName);
         }
-        throw new IllegalArgumentException("Unknown selector: " + selectorName);
+        return index;
     }
 
     public int getColumnIndex(String columnName) {
@@ -448,14 +464,6 @@ public class Query {
         throw new IllegalArgumentException("Column not found: " + columnName);
     }
 
-    public long getLimit() {
-        return limit;
-    }
-
-    public long getOffset() {
-        return offset;
-    }
-
     public CoreValue getBindVariableValue(String bindVariableName) {
         CoreValue v = bindVariableMap.get(bindVariableName);
         if (v == null) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java Tue May 22 14:58:07 2012
@@ -83,9 +83,12 @@ public class QueryEngineImpl implements 
     }
 
     @Override
-    public ResultImpl executeQuery(String statement, String language, ContentSession session, Map<String, CoreValue> bindings) throws ParseException {
+    public ResultImpl executeQuery(String statement, String language, ContentSession session,
+            long limit, long offset, Map<String, CoreValue> bindings) throws ParseException {
         Query q = parseQuery(statement, language);
         q.setSession(session);
+        q.setLimit(limit);
+        q.setOffset(offset);
         q.setMicroKernel(mk);
         if (bindings != null) {
             for (Entry<String, CoreValue> e : bindings.entrySet()) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java Tue May 22 14:58:07 2012
@@ -64,14 +64,18 @@ public class XPathToSQL2Converter {
         expected = new ArrayList<String>();
         read();
         String path = "";
+        String nodeName = null;
         Expression condition = null;
         String from = "nt:base";
         ArrayList<Expression> columnList = new ArrayList<Expression>();
-        boolean children = true;
-        boolean descendants = true;
+        boolean children = false;
+        boolean descendants = false;
         while (true) {
             String nodeType;
             if (readIf("/")) {
+                if (nodeName != null) {
+                    throw getSyntaxError("non-path condition");
+                }
                 if (readIf("/")) {
                     descendants = true;
                 } else if (readIf("jcr:root")) {
@@ -81,6 +85,7 @@ public class XPathToSQL2Converter {
                             descendants = true;
                         }
                     } else {
+                        descendants = true;
                         // expected end of statement
                         break;
                     }
@@ -90,11 +95,15 @@ public class XPathToSQL2Converter {
                 if (readIf("*")) {
                     nodeType = "nt:base";
                     from = nodeType;
+                    children = true;
                 } else if (readIf("text")) {
-                    // TODO support text() and jcr:xmltext?
                     read("(");
                     read(")");
-                    path = PathUtils.concat(path, "jcr:xmltext");
+                    if (descendants) {
+                        nodeName = "jcr:xmltext";
+                    } else {
+                        path = PathUtils.concat(path, "jcr:xmltext");
+                    }
                 } else if (readIf("element")) {
                     read("(");
                     if (readIf(")")) {
@@ -119,19 +128,22 @@ public class XPathToSQL2Converter {
                         read(")");
                     }
                 } else if (readIf("@")) {
-                    Property p = new Property(readIdentifier());
+                    Property p = readProperty();
                     columnList.add(p);
                 } else if (readIf("(")) {
                     do {
                         read("@");
-                        Property p = new Property(readIdentifier());
+                        Property p = readProperty();
                         columnList.add(p);
                     } while (readIf("|"));
                     read(")");
                 } else {
-                    String name = readIdentifier();
-                    path = PathUtils.concat(path, name);
-                    continue;
+                    if (descendants) {
+                        nodeName = readIdentifier();
+                    } else {
+                        String name = readIdentifier();
+                        path = PathUtils.concat(path, name);
+                    }
                 }
                 if (readIf("[")) {
                     Expression c = parseConstraint();
@@ -145,6 +157,9 @@ public class XPathToSQL2Converter {
         if (path.isEmpty()) {
             // no condition
         } else {
+            if (!PathUtils.isAbsolute(path)) {
+                path = PathUtils.concat("/", path);
+            }
             if (descendants) {
                 Function c = new Function("isdescendantnode");
                 c.params.add(Literal.newString(path));
@@ -158,6 +173,11 @@ public class XPathToSQL2Converter {
                 Condition c = new Condition(new Property("jcr:path"), "=", Literal.newString(path));
                 condition = add(condition, c);
             }
+            if (nodeName != null) {
+                Function f = new Function("name");
+                Condition c = new Condition(f, "=", Literal.newString(nodeName));
+                condition = add(condition, c);
+            }
         }
         ArrayList<Order> orderList = new ArrayList<Order>();
         if (readIf("order")) {
@@ -177,7 +197,7 @@ public class XPathToSQL2Converter {
             throw getSyntaxError("<end>");
         }
         StringBuilder buff = new StringBuilder("select ");
-        buff.append("[jcr:path], ");
+        buff.append("[jcr:path], [jcr:score], ");
         if (columnList.isEmpty()) {
             buff.append('*');
         } else {
@@ -279,7 +299,7 @@ public class XPathToSQL2Converter {
 
     private Expression parseExpression() throws ParseException {
         if (readIf("@")) {
-            return new Property(readIdentifier());
+            return readProperty();
         } else if (readIf("true")) {
             return Literal.newBoolean(true);
         } else if (readIf("false")) {
@@ -384,6 +404,13 @@ public class XPathToSQL2Converter {
         read();
     }
 
+    private Property readProperty() throws ParseException {
+        if (readIf("*")) {
+            return new Property("*");
+        }
+        return new Property(readIdentifier());
+    }
+
     private String readIdentifier() throws ParseException {
         if (currentTokenType != IDENTIFIER) {
             throw getSyntaxError("identifier");

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java Tue May 22 14:58:07 2012
@@ -18,6 +18,7 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
+import javax.jcr.PropertyType;
 import org.apache.jackrabbit.mk.json.JsopReader;
 import org.apache.jackrabbit.mk.json.JsopTokenizer;
 import org.apache.jackrabbit.oak.api.CoreValue;
@@ -100,5 +101,28 @@ abstract class AstElement {
         return CoreValueMapper.fromJsopReader(r, vf);
     }
 
+    /**
+     * Validate that the givne value can be converted to a JCR name.
+     *
+     * @param v the value
+     * @return true if it can be converted
+     */
+    protected boolean isName(CoreValue v) {
+        // TODO correctly validate JCR names - see JCR 2.0 spec 3.2.4 Naming Restrictions
+        switch (v.getType()) {
+        case PropertyType.DATE:
+        case PropertyType.DECIMAL:
+        case PropertyType.DOUBLE:
+        case PropertyType.LONG:
+        case PropertyType.BOOLEAN:
+            return false;
+        }
+        String n = v.getString();
+        if (n.startsWith("[") && !n.endsWith("]")) {
+            return false;
+        }
+        return true;
+    }
+
 }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java Tue May 22 14:58:07 2012
@@ -105,9 +105,12 @@ public class ComparisonImpl extends Cons
                     // except if UTF-8 isn't supported
                     throw new IllegalArgumentException(v.getString(), e);
                 }
-            case PropertyType.DATE:
-
             }
+            return vf.createValue(v.getString(), targetType);
+        }
+        switch (targetType) {
+        case PropertyType.STRING:
+            return vf.createValue(v.getString());
         case PropertyType.BOOLEAN:
             return vf.createValue(v.getBoolean());
         case PropertyType.DATE:

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java Tue May 22 14:58:07 2012
@@ -18,8 +18,8 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
-import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 
 public class NodeNameImpl extends DynamicOperandImpl {
@@ -60,6 +60,17 @@ public class NodeNameImpl extends Dynami
 
     @Override
     public void apply(FilterImpl f, Operator operator, CoreValue v) {
+        if (!isName(v)) {
+            throw new IllegalArgumentException("Invalid name value: " + v.toString());
+        }
+        String path = v.getString();
+        if (PathUtils.isAbsolute(path)) {
+            throw new IllegalArgumentException("NAME() comparison with absolute path are not allowed: " + path);
+        }
+        // TODO normalize paths (./name > name)
+        if (PathUtils.getDepth(path) > 1) {
+            throw new IllegalArgumentException("NAME() comparison with relative path are not allowed: " + path);
+        }
         // TODO support NAME(..) index conditions
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java Tue May 22 14:58:07 2012
@@ -159,14 +159,20 @@ public class QueryTest extends AbstractQ
         }
     }
 
-    private List<String> executeQuery(String query) throws ParseException {
+    private List<String> executeQuery(String query) {
         List<String> lines = new ArrayList<String>();
-        Result result = executeQuery(query, null);
-        for (ResultRow row : result.getRows()) {
-            lines.add(readRow(row));
-        }
-        if (!query.contains("order by")) {
-            Collections.sort(lines);
+        try {
+            Result result = executeQuery(query, null);
+            for (ResultRow row : result.getRows()) {
+                lines.add(readRow(row));
+            }
+            if (!query.contains("order by")) {
+                Collections.sort(lines);
+            }
+        } catch (ParseException e) {
+            lines.add(e.toString());
+        } catch (IllegalArgumentException e) {
+            lines.add(e.toString());
         }
         return lines;
     }
@@ -185,7 +191,7 @@ public class QueryTest extends AbstractQ
     }
 
     private Result executeQuery(String statement, HashMap<String, CoreValue> sv) throws ParseException {
-        return qe.executeQuery(statement, QueryEngineImpl.SQL2, session, sv);
+        return qe.executeQuery(statement, QueryEngineImpl.SQL2, session, Long.MAX_VALUE, 0, sv);
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt Tue May 22 14:58:07 2012
@@ -23,6 +23,9 @@
 
 # test the property content index
 
+select * from [nt:base] as p inner join [nt:base] as p on ischildnode(p, p) where p.[jcr:path] = '/'
+java.lang.IllegalArgumentException: Two selectors with the same name: p
+
 commit /default + "test": { "a": { "id": "10" }, "b": { "id" : "20" }}
 commit /jcr:system/indexes + "property:id": {}
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryXpathTest.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryXpathTest.txt?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryXpathTest.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryXpathTest.txt Tue May 22 14:58:07 2012
@@ -18,160 +18,175 @@
 # * lines starting with "xpath" are xpath queries, followed by expected sql2 query
 # * use ascii character only
 
-xpath /jcr:root
-select [jcr:path], * from [nt:base] where isdescendantnode('/')
+xpath /jcr:root/testdata/node[@jcr:primaryType]
+select [jcr:path], [jcr:score], * from [nt:base] where ([jcr:primaryType] is not null) and ([jcr:path] = '/testdata/node')
 
-xpath /jcr:root/test/text()
-select [jcr:path], * from [nt:base] where ischildnode('/test/jcr:xmltext')
+xpath //testroot/*[@jcr:primaryType='nt:unstructured'] order by @prop2, @prop1
+invalid: Query: //testroot/*(*)[@jcr:primaryType='nt:unstructured'] order by @prop2, @prop1; expected: non-path condition
+
+xpath /jcr:root/test//jcr:xmltext
+select [jcr:path], [jcr:score], * from [nt:base] where isdescendantnode('/test') and (name() = 'jcr:xmltext')
+
+xpath /jcr:root/test//text()
+select [jcr:path], [jcr:score], * from [nt:base] where isdescendantnode('/test') and (name() = 'jcr:xmltext')
 
 xpath /jcr:root/test/jcr:xmltext
-select [jcr:path], * from [nt:base] where ischildnode('/test/jcr:xmltext')
+select [jcr:path], [jcr:score], * from [nt:base] where [jcr:path] = '/test/jcr:xmltext'
+
+xpath /jcr:root/test/text()
+select [jcr:path], [jcr:score], * from [nt:base] where [jcr:path] = '/test/jcr:xmltext'
+
+xpath //*[@*='x']
+select [jcr:path], [jcr:score], * from [nt:base] where [*] = 'x'
+
+xpath /jcr:root
+select [jcr:path], [jcr:score], * from [nt:base] where isdescendantnode('/')
 
 xpath //*[@name='Hello']
-select [jcr:path], * from [nt:base] where [name] = 'Hello'
+select [jcr:path], [jcr:score], * from [nt:base] where [name] = 'Hello'
 
 xpath /jcr:root//*[@name='Hello']
-select [jcr:path], * from [nt:base] where ([name] = 'Hello') and isdescendantnode('/')
+select [jcr:path], [jcr:score], * from [nt:base] where ([name] = 'Hello') and isdescendantnode('/')
 
 xpath content/*
-select [jcr:path], * from [nt:base] where ischildnode('/content')
+select [jcr:path], [jcr:score], * from [nt:base] where ischildnode('/content')
 
 xpath content//*
-select [jcr:path], * from [nt:base] where isdescendantnode('/content')
+select [jcr:path], [jcr:score], * from [nt:base] where isdescendantnode('/content')
 
 xpath content//*[@name='Hello']
-select [jcr:path], * from [nt:base] where ([name] = 'Hello') and isdescendantnode('/content')
+select [jcr:path], [jcr:score], * from [nt:base] where ([name] = 'Hello') and isdescendantnode('/content')
 
 xpath /jcr:root/content//*[@name='Hello']
-select [jcr:path], * from [nt:base] where ([name] = 'Hello') and isdescendantnode('/content')
+select [jcr:path], [jcr:score], * from [nt:base] where ([name] = 'Hello') and isdescendantnode('/content')
 
 xpath //*[jcr:contains(., 'test')] order by @jcr:score
-select [jcr:path], * from [nt:base] where contains(*, 'test') order by [jcr:score]
+select [jcr:path], [jcr:score], * from [nt:base] where contains(*, 'test') order by [jcr:score]
 
 xpath /jcr:root//*[jcr:contains(., 'test')] order by @jcr:score
-select [jcr:path], * from [nt:base] where contains(*, 'test') and isdescendantnode('/') order by [jcr:score]
+select [jcr:path], [jcr:score], * from [nt:base] where contains(*, 'test') and isdescendantnode('/') order by [jcr:score]
 
 xpath /jcr:root//element(*, test)
-select [jcr:path], * from [test] where isdescendantnode('/')
+select [jcr:path], [jcr:score], * from [test] where isdescendantnode('/')
 
 xpath /jcr:root//element(*, user)[test/@jcr:primaryType]
-select [jcr:path], * from [user] where ([test/jcr:primaryType] is not null) and isdescendantnode('/')
+select [jcr:path], [jcr:score], * from [user] where ([test/jcr:primaryType] is not null) and isdescendantnode('/')
 
 xpath /jcr:root/content//*[(@sling:resourceType = 'start')]
-select [jcr:path], * from [nt:base] where ([sling:resourceType] = 'start') and isdescendantnode('/content')
+select [jcr:path], [jcr:score], * from [nt:base] where ([sling:resourceType] = 'start') and isdescendantnode('/content')
 
 xpath /jcr:root/content//*[(@sling:resourceType = 'page')]
-select [jcr:path], * from [nt:base] where ([sling:resourceType] = 'page') and isdescendantnode('/content')
+select [jcr:path], [jcr:score], * from [nt:base] where ([sling:resourceType] = 'page') and isdescendantnode('/content')
 
 xpath /jcr:root/content//*[@offTime > xs:dateTime('2012-03-28T15:56:18.327+02:00') or @onTime > xs:dateTime('2012-03-28T15:56:18.327+02:00')]
-select [jcr:path], * from [nt:base] where (([offTime] > cast('2012-03-28T15:56:18.327+02:00' as date)) or ([onTime] > cast('2012-03-28T15:56:18.327+02:00' as date))) and isdescendantnode('/content')
+select [jcr:path], [jcr:score], * from [nt:base] where (([offTime] > cast('2012-03-28T15:56:18.327+02:00' as date)) or ([onTime] > cast('2012-03-28T15:56:18.327+02:00' as date))) and isdescendantnode('/content')
 
 xpath /jcr:root/content/campaigns//*[@jcr:primaryType='Page'] order by jcr:content/@lastModified descending
-select [jcr:path], * from [nt:base] where ([jcr:primaryType] = 'Page') and isdescendantnode('/content/campaigns') order by [jcr:content/lastModified] desc
+select [jcr:path], [jcr:score], * from [nt:base] where ([jcr:primaryType] = 'Page') and isdescendantnode('/content/campaigns') order by [jcr:content/lastModified] desc
 
 xpath /jcr:root/content/campaigns//element(*, PageContent)[(@sling:resourceType = 'teaser' or @sling:resourceType = 'newsletter' or @teaserPageType = 'newsletter' or @teaserPageType = 'tweet') and ((@onTime < xs:dateTime('2012-04-01T00:00:00.000+02:00')) or not(@onTime)) and ((@offTime >= xs:dateTime('2012-02-26T00:00:00.000+01:00')) or not(@offTime))] order by @onTime
-select [jcr:path], * from [PageContent] where (((((([sling:resourceType] = 'teaser') or ([sling:resourceType] = 'newsletter')) or ([teaserPageType] = 'newsletter')) or ([teaserPageType] = 'tweet')) and (([onTime] < cast('2012-04-01T00:00:00.000+02:00' as date)) or ([onTime] is null))) and (([offTime] >= cast('2012-02-26T00:00:00.000+01:00' as date)) or ([offTime] is null))) and isdescendantnode('/content/campaigns') order by [onTime]
+select [jcr:path], [jcr:score], * from [PageContent] where (((((([sling:resourceType] = 'teaser') or ([sling:resourceType] = 'newsletter')) or ([teaserPageType] = 'newsletter')) or ([teaserPageType] = 'tweet')) and (([onTime] < cast('2012-04-01T00:00:00.000+02:00' as date)) or ([onTime] is null))) and (([offTime] >= cast('2012-02-26T00:00:00.000+01:00' as date)) or ([offTime] is null))) and isdescendantnode('/content/campaigns') order by [onTime]
 
 xpath /jcr:root/content/dam//element(*, asset)[jcr:content/metadata/@dam:scene]
-select [jcr:path], * from [asset] where ([jcr:content/metadata/dam:scene] is not null) and isdescendantnode('/content/dam')
+select [jcr:path], [jcr:score], * from [asset] where ([jcr:content/metadata/dam:scene] is not null) and isdescendantnode('/content/dam')
 
 xpath /jcr:root/etc/cloud//*[(@sling:resourceType = 'framework')]
-select [jcr:path], * from [nt:base] where ([sling:resourceType] = 'framework') and isdescendantnode('/etc/cloud')
+select [jcr:path], [jcr:score], * from [nt:base] where ([sling:resourceType] = 'framework') and isdescendantnode('/etc/cloud')
 
 xpath /jcr:root/etc/cloud//*[(@sling:resourceType = 'analytics')]
-select [jcr:path], * from [nt:base] where ([sling:resourceType] = 'analytics') and isdescendantnode('/etc/cloud')
+select [jcr:path], [jcr:score], * from [nt:base] where ([sling:resourceType] = 'analytics') and isdescendantnode('/etc/cloud')
 
 xpath /jcr:root/etc/reports//*[@jcr:primaryType='Page'] order by jcr:content/@lastModified descending
-select [jcr:path], * from [nt:base] where ([jcr:primaryType] = 'Page') and isdescendantnode('/etc/reports') order by [jcr:content/lastModified] desc
+select [jcr:path], [jcr:score], * from [nt:base] where ([jcr:primaryType] = 'Page') and isdescendantnode('/etc/reports') order by [jcr:content/lastModified] desc
 
 xpath /jcr:root/etc/segment//*[@jcr:primaryType='Page'] order by jcr:content/@lastModified descending
-select [jcr:path], * from [nt:base] where ([jcr:primaryType] = 'Page') and isdescendantnode('/etc/segment') order by [jcr:content/lastModified] desc
+select [jcr:path], [jcr:score], * from [nt:base] where ([jcr:primaryType] = 'Page') and isdescendantnode('/etc/segment') order by [jcr:content/lastModified] desc
 
 xpath /jcr:root/etc/workflow//element(*,Item)[not(meta/@archived) and not(meta/@archived = true)]
-select [jcr:path], * from [Item] where (([meta/archived] is null) and not([meta/archived] = true)) and isdescendantnode('/etc/workflow')
+select [jcr:path], [jcr:score], * from [Item] where (([meta/archived] is null) and not([meta/archived] = true)) and isdescendantnode('/etc/workflow')
 
 xpath /jcr:root/home//element()
-select [jcr:path], * from [nt:base] where isdescendantnode('/home')
+select [jcr:path], [jcr:score], * from [nt:base] where isdescendantnode('/home')
 
 xpath /jcr:root/home//element(*)
-select [jcr:path], * from [nt:base] where isdescendantnode('/home')
+select [jcr:path], [jcr:score], * from [nt:base] where isdescendantnode('/home')
 
 # other queries
 
 xpath //*
-select [jcr:path], * from [nt:base]
+select [jcr:path], [jcr:score], * from [nt:base]
 
 xpath //element(*, my:type)
-select [jcr:path], * from [my:type]
+select [jcr:path], [jcr:score], * from [my:type]
 
 xpath //element(*, my:type)/@my:title
-select [jcr:path], [my:title] from [my:type]
+select [jcr:path], [jcr:score], [my:title] from [my:type]
 
 xpath //element(*, my:type)/(@my:title | @my:text)
-select [jcr:path], [my:title], [my:text] from [my:type]
+select [jcr:path], [jcr:score], [my:title], [my:text] from [my:type]
 
 xpath /jcr:root/nodes//element(*, my:type)
-select [jcr:path], * from [my:type] where isdescendantnode('/nodes')
+select [jcr:path], [jcr:score], * from [my:type] where isdescendantnode('/nodes')
 
 xpath /jcr:root/some/element(nodes, my:type)
-select [jcr:path], * from [my:type] where [jcr:path] = '/some/nodes'
+select [jcr:path], [jcr:score], * from [my:type] where [jcr:path] = '/some/nodes'
 
 xpath /jcr:root/some/nodes/element(*, my:type)
-select [jcr:path], * from [my:type] where ischildnode('/some/nodes')
+select [jcr:path], [jcr:score], * from [my:type] where ischildnode('/some/nodes')
 
 xpath /jcr:root/some/nodes//element(*, my:type)
-select [jcr:path], * from [my:type] where isdescendantnode('/some/nodes')
+select [jcr:path], [jcr:score], * from [my:type] where isdescendantnode('/some/nodes')
 
 xpath //element(*, my:type)[@my:title = 'JSR 170']
-select [jcr:path], * from [my:type] where [my:title] = 'JSR 170'
+select [jcr:path], [jcr:score], * from [my:type] where [my:title] = 'JSR 170'
 
 xpath //element(*, my:type)[jcr:like(@title,'%Java%')]
-select [jcr:path], * from [my:type] where [title] like '%Java%'
+select [jcr:path], [jcr:score], * from [my:type] where [title] like '%Java%'
 
 xpath //element(*, my:type)[jcr:contains(., 'JSR 170')]
-select [jcr:path], * from [my:type] where contains(*, 'JSR 170')
+select [jcr:path], [jcr:score], * from [my:type] where contains(*, 'JSR 170')
 
 xpath //element(*, my:type)[@my:title]
-select [jcr:path], * from [my:type] where [my:title] is not null
+select [jcr:path], [jcr:score], * from [my:type] where [my:title] is not null
 
 xpath //element(*, my:type)[not(@my:title)]
-select [jcr:path], * from [my:type] where [my:title] is null
+select [jcr:path], [jcr:score], * from [my:type] where [my:title] is null
 
 xpath //element(*, my:type)[@my:value < -1.0]
-select [jcr:path], * from [my:type] where [my:value] < -1.0
+select [jcr:path], [jcr:score], * from [my:type] where [my:value] < -1.0
 
 xpath //element(*, my:type)[@my:value > +10123123123]
-select [jcr:path], * from [my:type] where [my:value] > 10123123123
+select [jcr:path], [jcr:score], * from [my:type] where [my:value] > 10123123123
 
 xpath //element(*, my:type)[@my:value <= 10.3e-3]
-select [jcr:path], * from [my:type] where [my:value] <= 10.3e-3
+select [jcr:path], [jcr:score], * from [my:type] where [my:value] <= 10.3e-3
 
 xpath //element(*, my:type)[@my:value >= 0e3]
-select [jcr:path], * from [my:type] where [my:value] >= 0e3
+select [jcr:path], [jcr:score], * from [my:type] where [my:value] >= 0e3
 
 xpath //element(*, my:type)[@my:value <> 'Joe''s Caffee']
-select [jcr:path], * from [my:type] where [my:value] <> 'Joe''s Caffee'
+select [jcr:path], [jcr:score], * from [my:type] where [my:value] <> 'Joe''s Caffee'
 
 xpath //element(*, my:type)[(not(@my:title) and @my:subject)]
-select [jcr:path], * from [my:type] where ([my:title] is null) and ([my:subject] is not null)
+select [jcr:path], [jcr:score], * from [my:type] where ([my:title] is null) and ([my:subject] is not null)
 
 xpath //element(*, my:type)[not(@my:title) or @my:subject]
-select [jcr:path], * from [my:type] where ([my:title] is null) or ([my:subject] is not null)
+select [jcr:path], [jcr:score], * from [my:type] where ([my:title] is null) or ([my:subject] is not null)
 
 xpath //element(*, my:type)[not(@my:value > 0 and @my:value < 100)]
-select [jcr:path], * from [my:type] where not(([my:value] > 0) and ([my:value] < 100))
+select [jcr:path], [jcr:score], * from [my:type] where not(([my:value] > 0) and ([my:value] < 100))
 
 xpath //element(*, my:type) order by @jcr:lastModified
-select [jcr:path], * from [my:type] order by [jcr:lastModified]
+select [jcr:path], [jcr:score], * from [my:type] order by [jcr:lastModified]
 
 xpath //element(*, my:type) order by @my:date descending, @my:title ascending
-select [jcr:path], * from [my:type] order by [my:date] desc, [my:title]
+select [jcr:path], [jcr:score], * from [my:type] order by [my:date] desc, [my:title]
 
 xpath //element(*, my:type)[jcr:contains(., 'jcr')] order by jcr:score() descending
-select [jcr:path], * from [my:type] where contains(*, 'jcr') order by score() desc
+select [jcr:path], [jcr:score], * from [my:type] where contains(*, 'jcr') order by score() desc
 
 xpath //element(*, my:type)[jcr:contains(@my:title, 'jcr')] order by jcr:score() descending
-select [jcr:path], * from [my:type] where contains([my:title], 'jcr') order by score() desc
+select [jcr:path], [jcr:score], * from [my:type] where contains([my:title], 'jcr') order by score() desc
 
 xpath [invalid/query
 invalid: Query: /jcr:root/[(*)invalid/query; expected: identifier

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryImpl.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryImpl.java Tue May 22 14:58:07 2012
@@ -20,14 +20,21 @@ package org.apache.jackrabbit.oak.jcr.qu
 
 import java.util.HashMap;
 import java.util.List;
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
 import javax.jcr.Node;
 import javax.jcr.PathNotFoundException;
 import javax.jcr.RepositoryException;
-import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
 import javax.jcr.query.InvalidQueryException;
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryResult;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.jcr.NodeDelegate;
+import org.apache.jackrabbit.oak.jcr.NodeImpl;
+import org.apache.jackrabbit.oak.jcr.SessionDelegate;
+import org.apache.jackrabbit.oak.jcr.value.ValueFactoryImpl;
 
 /**
  * The implementation of the corresponding JCR interface.
@@ -38,8 +45,10 @@ public class QueryImpl implements Query 
     private final HashMap<String, Value> bindVariableMap = new HashMap<String, Value>();
     private final String language;
     private final String statement;
-    private long limit, offset;
+    private long limit = Long.MAX_VALUE;
+    private long offset;
     private boolean parsed;
+    private String storedQueryPath;
 
     QueryImpl(QueryManagerImpl manager, String statement, String language) {
         this.manager = manager;
@@ -47,6 +56,10 @@ public class QueryImpl implements Query 
         this.language = language;
     }
 
+    void setStoredQueryPath(String storedQueryPath) {
+        this.storedQueryPath = storedQueryPath;
+    }
+
     @Override
     public void bindValue(String varName, Value value) throws RepositoryException {
         parse();
@@ -64,11 +77,12 @@ public class QueryImpl implements Query 
         for (String n : names) {
             bindVariableMap.put(n, null);
         }
+        parsed = true;
     }
 
     @Override
     public QueryResult execute() throws RepositoryException {
-        return manager.executeQuery(statement, language, bindVariableMap, limit, offset);
+        return manager.executeQuery(statement, language, limit, offset, bindVariableMap);
     }
 
     @Override
@@ -91,8 +105,10 @@ public class QueryImpl implements Query 
 
     @Override
     public String getStoredQueryPath() throws RepositoryException {
-        // TODO not implemented yet
-        return null;
+        if (storedQueryPath == null) {
+            throw new ItemNotFoundException("Not a stored query");
+        }
+        return storedQueryPath;
     }
 
     @Override
@@ -108,11 +124,26 @@ public class QueryImpl implements Query 
     @Override
     public Node storeAsNode(String absPath) throws RepositoryException {
         manager.ensureIsAlive();
-        if (manager.getSessionDelegate().getNode(absPath) == null) {
-            throw new PathNotFoundException("The specified path does not exist: " + absPath);
+        SessionDelegate sessionDelegate = manager.getSessionDelegate();
+        String oakPath = sessionDelegate.getOakPathOrThrow(absPath);
+        // TODO query nodes should be of type nt:query
+        String parent = PathUtils.getParentPath(oakPath);
+        String nodeName = PathUtils.getName(oakPath);
+        NodeDelegate parentNode = sessionDelegate.getNode(parent);
+        ValueFactoryImpl vf = sessionDelegate.getValueFactory();
+        if (parentNode == null) {
+            throw new PathNotFoundException("The specified path does not exist: " + parent);
+        }
+        NodeDelegate node = parentNode.addChild(nodeName);
+        if (node == null) {
+            throw new ItemExistsException("Node already exists: " + absPath);
         }
-        // TODO not implemented yet
-        throw new UnsupportedRepositoryOperationException("This feature is not supported");
+        node.setProperty("statement", vf.getCoreValue(vf.createValue(statement)));
+        node.setProperty("language", vf.getCoreValue(vf.createValue(language)));
+        NodeImpl n = new NodeImpl(node);
+        n.setPrimaryType(NodeType.NT_QUERY);
+        storedQueryPath = oakPath;
+        return n;
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryManagerImpl.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryManagerImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryManagerImpl.java Tue May 22 14:58:07 2012
@@ -27,6 +27,7 @@ import java.util.Map.Entry;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
 import javax.jcr.query.InvalidQueryException;
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryManager;
@@ -71,8 +72,14 @@ public class QueryManagerImpl implements
 
     @Override
     public Query getQuery(Node node) throws RepositoryException {
-        // TODO getQuery(Node node): is it needed?
-        throw new RepositoryException("Feature not implemented");
+        if (!node.isNodeType(NodeType.NT_QUERY)) {
+            throw new InvalidQueryException("Not an nt:query node: " + node.getPath());
+        }
+        String statement = node.getProperty("statement").getString();
+        String language = node.getProperty("language").getString();
+        QueryImpl query = createQuery(statement, language);
+        query.setStoredQueryPath(node.getPath());
+        return query;
     }
 
     @Override
@@ -94,11 +101,11 @@ public class QueryManagerImpl implements
     }
 
     public QueryResult executeQuery(String statement, String language,
-            HashMap<String, Value> bindVariableMap, long limit, long offset) throws RepositoryException {
+            long limit, long offset, HashMap<String, Value> bindVariableMap) throws RepositoryException {
         try {
             HashMap<String, CoreValue> bindMap = convertMap(bindVariableMap);
             ContentSession s = sessionDelegate.getContentSession();
-            Result r = queryEngine.executeQuery(statement, language, s, bindMap);
+            Result r = queryEngine.executeQuery(statement, language, s, limit, offset, bindMap);
             return new QueryResultImpl(sessionDelegate, r);
         } catch (IllegalArgumentException e) {
             throw new InvalidQueryException(e);

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java Tue May 22 14:58:07 2012
@@ -18,23 +18,23 @@
  */
 package org.apache.jackrabbit.oak.jcr.query;
 
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.RowIterator;
 import org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter;
 import org.apache.jackrabbit.commons.iterator.RowIteratorAdapter;
+import org.apache.jackrabbit.oak.api.CoreValue;
 import org.apache.jackrabbit.oak.api.Result;
 import org.apache.jackrabbit.oak.api.ResultRow;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.jcr.NodeDelegate;
 import org.apache.jackrabbit.oak.jcr.NodeImpl;
 import org.apache.jackrabbit.oak.jcr.SessionDelegate;
-import org.apache.jackrabbit.oak.jcr.value.ValueFactoryImpl;
-
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.RowIterator;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
 
 /**
  * The implementation of the corresponding JCR interface.
@@ -42,14 +42,12 @@ import java.util.NoSuchElementException;
 public class QueryResultImpl implements QueryResult {
 
     final SessionDelegate sessionDelegate;
-    final ValueFactoryImpl valueFactory;
     final Result result;
     final String pathFilter;
 
     public QueryResultImpl(SessionDelegate sessionDelegate, Result result) {
         this.sessionDelegate = sessionDelegate;
         this.result = result;
-        this.valueFactory = sessionDelegate.getValueFactory();
 
         // TODO the path currently contains the workspace name
         // TODO filter in oak-core once we support workspaces there
@@ -84,8 +82,8 @@ public class QueryResultImpl implements 
                     for (String s : getSelectorNames()) {
                         String path = r.getPath(s);
                         if (PathUtils.isAncestor(pathFilter, path)) {
-                            current = new RowImpl(sessionDelegate, r, valueFactory);
-                            break;
+                            current = new RowImpl(QueryResultImpl.this, r);
+                            return;
                         }
                     }
                 }
@@ -115,10 +113,20 @@ public class QueryResultImpl implements 
         return new RowIteratorAdapter(it);
     }
 
+    NodeImpl getNode(String path) {
+        NodeDelegate d = sessionDelegate.getNode(path);
+        return new NodeImpl(d);
+    }
+
+    String getLocalPath(String path) {
+        return PathUtils.concat("/", PathUtils.relativize(pathFilter, path));
+    }
+
     @Override
     public NodeIterator getNodes() throws RepositoryException {
         if (getSelectorNames().length > 1) {
-            throw new RepositoryException("Query contains more than one selector: " + Arrays.toString(getSelectorNames()));
+            throw new RepositoryException("Query contains more than one selector: " +
+                    Arrays.toString(getSelectorNames()));
         }
         Iterator<NodeImpl> it = new Iterator<NodeImpl>() {
 
@@ -135,9 +143,7 @@ public class QueryResultImpl implements 
                     ResultRow r = it.next();
                     String path = r.getPath();
                     if (PathUtils.isAncestor(pathFilter, path)) {
-                        path = PathUtils.relativize(pathFilter, path);
-                        NodeDelegate d = sessionDelegate.getNode(path);
-                        current = new NodeImpl(d);
+                        current = getNode(getLocalPath(path));
                         break;
                     }
                 }
@@ -167,4 +173,8 @@ public class QueryResultImpl implements 
         return new NodeIteratorAdapter(it);
     }
 
+    Value createValue(CoreValue value) {
+        return sessionDelegate.getValueFactory().createValue(value);
+    }
+
 }

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/RowImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/RowImpl.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/RowImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/RowImpl.java Tue May 22 14:58:07 2012
@@ -18,52 +18,40 @@
  */
 package org.apache.jackrabbit.oak.jcr.query;
 
-import org.apache.jackrabbit.oak.api.CoreValue;
-import org.apache.jackrabbit.oak.api.ResultRow;
-import org.apache.jackrabbit.oak.jcr.NodeDelegate;
-import org.apache.jackrabbit.oak.jcr.NodeImpl;
-import org.apache.jackrabbit.oak.jcr.SessionDelegate;
-import org.apache.jackrabbit.oak.jcr.value.ValueFactoryImpl;
-
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.query.Row;
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.api.ResultRow;
 
 /**
  * The implementation of the corresponding JCR interface.
  */
 public class RowImpl implements Row {
 
-    private final SessionDelegate sessionDelegate;
+    private final QueryResultImpl result;
     private final ResultRow row;
-    private final ValueFactoryImpl valueFactory;
 
-    public RowImpl(SessionDelegate sessionDelegate, ResultRow row, ValueFactoryImpl valueFactory) {
-        this.sessionDelegate = sessionDelegate;
+    public RowImpl(QueryResultImpl result, ResultRow row) {
+        this.result = result;
         this.row = row;
-        this.valueFactory = valueFactory;
     }
 
     @Override
     public Node getNode() throws RepositoryException {
-        return getNodeForPath(getPath());
+        return result.getNode(getPath());
     }
 
     @Override
     public Node getNode(String selectorName) throws RepositoryException {
-        return getNodeForPath(getPath(selectorName));
-    }
-
-    private Node getNodeForPath(String path) {
-        NodeDelegate d = sessionDelegate.getNode(path);
-        return new NodeImpl(d);
+        return result.getNode(getPath(selectorName));
     }
 
     @Override
     public String getPath() throws RepositoryException {
         try {
-            return row.getPath();
+            return result.getLocalPath(row.getPath());
         } catch (IllegalArgumentException e) {
             throw new RepositoryException(e);
         }
@@ -72,7 +60,7 @@ public class RowImpl implements Row {
     @Override
     public String getPath(String selectorName) throws RepositoryException {
         try {
-            return row.getPath(selectorName);
+            return result.getLocalPath(row.getPath(selectorName));
         } catch (IllegalArgumentException e) {
             throw new RepositoryException(e);
         }
@@ -93,7 +81,7 @@ public class RowImpl implements Row {
     @Override
     public Value getValue(String columnName) throws RepositoryException {
         try {
-            return valueFactory.createValue(row.getValue(columnName));
+            return result.createValue(row.getValue(columnName));
         } catch (IllegalArgumentException e) {
             throw new RepositoryException(e);
         }
@@ -105,7 +93,7 @@ public class RowImpl implements Row {
         int len = values.length;
         Value[] v2 = new Value[values.length];
         for (int i = 0; i < len; i++) {
-            v2[i] = valueFactory.createValue(values[i]);
+            v2[i] = result.createValue(values[i]);
         }
         return v2;
     }

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/qom/QueryObjectModelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/qom/QueryObjectModelImpl.java?rev=1341505&r1=1341504&r2=1341505&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/qom/QueryObjectModelImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/qom/QueryObjectModelImpl.java Tue May 22 14:58:07 2012
@@ -15,6 +15,7 @@ package org.apache.jackrabbit.oak.jcr.qu
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import javax.jcr.ItemNotFoundException;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
@@ -42,12 +43,14 @@ public class QueryObjectModelImpl implem
     final ArrayList<Selector> selectors = new ArrayList<Selector>();
     private final Ordering[] orderings;
     private final Column[] columns;
-    private long limit;
+    private long limit = Long.MAX_VALUE;
     private long offset;
     private boolean parsed;
+    private String storedQueryPath;
 
-    public QueryObjectModelImpl(QueryManagerImpl queryManager, ValueFactory valueFactory, Source source, Constraint constraint, Ordering[] orderings,
-            Column[] columns) {
+    public QueryObjectModelImpl(QueryManagerImpl queryManager,
+            ValueFactory valueFactory, Source source, Constraint constraint,
+            Ordering[] orderings, Column[] columns) {
         this.queryManager = queryManager;
         this.valueFactory = valueFactory;
         this.source = source;
@@ -108,7 +111,8 @@ public class QueryObjectModelImpl implem
     public void bindValue(String varName, Value value) throws RepositoryException {
         parse();
         if (!bindVariableMap.containsKey(varName)) {
-            throw new IllegalArgumentException("Variable name " + varName + " is not a valid variable in this query");
+            throw new IllegalArgumentException("Variable name " + varName +
+                    " is not a valid variable in this query");
         }
         bindVariableMap.put(varName, value);
     }
@@ -117,15 +121,18 @@ public class QueryObjectModelImpl implem
         if (parsed) {
             return;
         }
-        String[] names = queryManager.createQuery(getStatement(), Query.JCR_SQL2).getBindVariableNames();
+        String[] names = queryManager.createQuery(getStatement(), Query.JCR_SQL2).
+                getBindVariableNames();
         for (String n : names) {
             bindVariableMap.put(n, null);
         }
+        parsed = true;
     }
 
     @Override
     public QueryResult execute() throws RepositoryException {
-        return queryManager.executeQuery(getStatement(), Query.JCR_SQL2, bindVariableMap, limit, offset);
+        return queryManager.executeQuery(getStatement(), Query.JCR_SQL2,
+                limit, offset, bindVariableMap);
     }
 
     @Override
@@ -138,7 +145,7 @@ public class QueryObjectModelImpl implem
         StringBuilder buff = new StringBuilder();
         buff.append("select ");
         int i;
-        if (columns != null) {
+        if (columns != null && columns.length > 0) {
             i = 0;
             for (Column c : columns) {
                 if (i++ > 0) {
@@ -170,13 +177,18 @@ public class QueryObjectModelImpl implem
 
     @Override
     public String getStoredQueryPath() throws RepositoryException {
-        // TODO not implemented yet
-        return null;
+        if (storedQueryPath == null) {
+            throw new ItemNotFoundException("Not a stored query");
+        }
+        return storedQueryPath;
     }
 
     @Override
     public Node storeAsNode(String absPath) throws RepositoryException {
-        return queryManager.createQuery(getStatement(), Query.JCR_SQL2).storeAsNode(absPath);
+        Node n = queryManager.createQuery(getStatement(), Query.JCR_SQL2).
+                storeAsNode(absPath);
+        storedQueryPath = n.getPath();
+        return n;
     }
 
     public void addBindVariable(BindVariableValueImpl var) {