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/04/05 15:27:09 UTC

svn commit: r1309843 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/query/ test/java/org/apache/jackrabbit/oak/query/ test/resources/org/apache/jackrabbit/oak/query/

Author: thomasm
Date: Thu Apr  5 13:27:08 2012
New Revision: 1309843

URL: http://svn.apache.org/viewvc?rev=1309843&view=rev
Log:
OAK-28 Query implementation (XPath to SQL-2 conversion)

Modified:
    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/ResultImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.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

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=1309843&r1=1309842&r2=1309843&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 Thu Apr  5 13:27:08 2012
@@ -261,6 +261,10 @@ public class Query {
     }
 
     public ResultImpl executeQuery(String revisionId) {
+        return new ResultImpl(this, revisionId);
+    }
+
+    Iterator<ResultRowImpl> getRows(String revisionId) {
         prepare();
         Iterator<ResultRowImpl> it;
         if (explain) {
@@ -282,7 +286,7 @@ public class Query {
                 it = list.iterator();
             }
         }
-        return new ResultImpl(this, it);
+        return it;
     }
 
     public int compareRows(CoreValue[] orderValues, CoreValue[] orderValues2) {

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=1309843&r1=1309842&r2=1309843&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 Thu Apr  5 13:27:08 2012
@@ -25,6 +25,9 @@ import org.apache.jackrabbit.oak.api.Que
 
 public class QueryEngineImpl implements QueryEngine {
 
+    static final String SQL2 = "JCR-SQL2";
+    private static final String XPATH = "xpath";
+
     private final MicroKernel mk;
     private final CoreValueFactory vf = new CoreValueFactory();
     private final SQL2Parser parserSQL2;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java?rev=1309843&r1=1309842&r2=1309843&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java Thu Apr  5 13:27:08 2012
@@ -28,12 +28,12 @@ import org.apache.jackrabbit.oak.query.a
  */
 public class ResultImpl implements Result {
 
-    private final Query query;
-    private final Iterator<ResultRowImpl> it;
+    protected final Query query;
+    protected final String revisionId;
 
-    ResultImpl(Query query, Iterator<ResultRowImpl> it) {
+    ResultImpl(Query query, String revisionId) {
         this.query = query;
-        this.it = it;
+        this.revisionId = revisionId;
     }
 
     @Override
@@ -57,8 +57,14 @@ public class ResultImpl implements Resul
     }
 
     @Override
-    public Iterator<? extends ResultRow> getRows() {
-        return it;
+    public Iterable<? extends ResultRow> getRows() {
+        return new Iterable<ResultRowImpl>() {
+
+            @Override
+            public Iterator<ResultRowImpl> iterator() {
+                return query.getRows(revisionId);
+            }
+        };
     }
 
 }

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=1309843&r1=1309842&r2=1309843&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 Thu Apr  5 13:27:08 2012
@@ -63,17 +63,21 @@ public class XPathToSQL2Converter {
         Expression condition = null;
         String from = "nt:base";
         ArrayList<Expression> columnList = new ArrayList<Expression>();
-        boolean includeChildren = true;
+        boolean children = true;
+        boolean descendants = true;
         while (true) {
             String nodeType;
             if (readIf("/")) {
                 if (readIf("/")) {
-                    includeChildren = true;
+                    descendants = true;
                 } else if (readIf("jcr:root")) {
                     path = "/";
                     read("/");
+                    if (readIf("/")) {
+                        descendants = true;
+                    }
                 } else {
-                    includeChildren = false;
+                    descendants = false;
                 }
                 if (readIf("*")) {
                     nodeType = "nt:base";
@@ -82,16 +86,19 @@ public class XPathToSQL2Converter {
                     read("(");
                     if (readIf("*")) {
                         // any
-                        if (!includeChildren) {
-                            path = PathUtils.concat(path, "%");
-                        }
+                        children = true;
                     } else {
+                        children = false;
                         String name = readIdentifier();
                         path = PathUtils.concat(path, name);
                     }
-                    read(",");
-                    nodeType = readIdentifier();
-                    from = nodeType;
+                    if (readIf(",")) {
+                        nodeType = readIdentifier();
+                        from = nodeType;
+                    } else {
+                        nodeType = "nt:base";
+                        from = nodeType;
+                    }
                     read(")");
                 } else if (readIf("@")) {
                     Property p = new Property(readIdentifier());
@@ -122,15 +129,22 @@ public class XPathToSQL2Converter {
         } else if (path.equals("%")) {
             // ignore
         } else {
-            Condition c = new Condition(new Property("jcr:path"), "like", Literal.newString(path));
-            if (!includeChildren && path.endsWith("%")) {
-                Condition c2 = new Condition(new Property("jcr:path"), "like", Literal.newString(path + '/'));
-                c = new Condition(c, "and", new Condition(null, "not", c2));
-            } else if (includeChildren && !path.endsWith("%")) {
-                Condition c2 = new Condition(new Property("jcr:path"), "like", Literal.newString(path + "/%"));
-                c = new Condition(c, "or", c2);
+            if (descendants) {
+                Function f1 = new Function("issamenode");
+                f1.params.add(Literal.newString(path));
+                Function f2 = new Function("isdescendantnode");
+                f2.params.add(Literal.newString(path));
+                Condition c = new Condition(f1, "or", f2);
+                condition = add(condition, c);
+            } else if (children) {
+                Function f = new Function("ischildnode");
+                f.params.add(Literal.newString(path));
+                condition = add(condition, f);
+            } else {
+                // TODO jcr:path is only a pseudo-property
+                Condition c = new Condition(new Property("jcr:path"), "=", Literal.newString(path));
+                condition = add(condition, c);
             }
-            condition = add(condition, c);
         }
         ArrayList<Order> orderList = new ArrayList<Order>();
         if (readIf("order")) {
@@ -163,7 +177,7 @@ public class XPathToSQL2Converter {
         buff.append(" from ");
         buff.append('[' + from + ']');
         if (condition != null) {
-            buff.append(" where ").append(condition);
+            buff.append(" where ").append(removeParens(condition.toString()));
         }
         if (!orderList.isEmpty()) {
             buff.append(" order by ");
@@ -211,14 +225,13 @@ public class XPathToSQL2Converter {
                 c = new Condition(c.left, "is null", null);
                 a = c;
             } else {
-                Function f = new Function();
-                f.name = "not";
+                Function f = new Function("not");
                 f.params.add(a);
                 a = f;
             }
             read(")");
         } else if (readIf("(")) {
-            a = new Parenthesis(parseConstraint());
+            a = parseConstraint();
             read(")");
         } else {
             Expression e = parseExpression();
@@ -253,6 +266,10 @@ public class XPathToSQL2Converter {
     private Expression parseExpression() throws ParseException {
         if (readIf("@")) {
             return new Property(readIdentifier());
+        } else if (readIf("true")) {
+            return Literal.newBoolean(true);
+        } else if (readIf("false")) {
+            return Literal.newBoolean(false);
         } else if (currentTokenType == VALUE_NUMBER) {
             Literal l = Literal.newNumber(currentToken);
             read();
@@ -263,6 +280,17 @@ public class XPathToSQL2Converter {
             return l;
         } else if (currentTokenType == IDENTIFIER) {
             String name = readIdentifier();
+            // relative properties
+            if (readIf("/")) {
+                do {
+                    if (readIf("@")) {
+                        name = name + "/" + readIdentifier();
+                        return new Property(name);
+                    } else {
+                        name = name + "/" + readIdentifier();
+                    }
+                } while (readIf("/"));
+            }
             read("(");
             return parseFunction(name);
         } else if (readIf("-")) {
@@ -290,8 +318,7 @@ public class XPathToSQL2Converter {
             read(")");
             return c;
         } else if ("jcr:contains".equals(functionName)) {
-            Function f = new Function();
-            f.name = "contains";
+            Function f = new Function("contains");
             if (readIf(".")) {
                 // special case: jcr:contains(., expr)
                 f.params.add(new Literal("*"));
@@ -303,11 +330,15 @@ public class XPathToSQL2Converter {
             read(")");
             return f;
         } else if ("jcr:score".equals(functionName)) {
-            Function f = new Function();
-            f.name = "score";
+            Function f = new Function("score");
             // TODO score: support parameters?
             read(")");
             return f;
+        } else if ("xs:dateTime".equals(functionName)) {
+            Expression expr = parseExpression();
+            Cast c = new Cast(expr, "date");
+            read(")");
+            return c;
         // } else if ("jcr:deref".equals(functionName)) {
             // TODO support jcr:deref?
         } else {
@@ -625,19 +656,29 @@ public class XPathToSQL2Converter {
     }
 
     abstract static class Expression {
+
         boolean isCondition() {
             return false;
         }
+
     }
 
     static class Literal extends Expression {
+
         final String value;
+
         Literal(String value) {
             this.value = value;
         }
+
+        public static Expression newBoolean(boolean value) {
+            return new Literal("" + value);
+        }
+
         static Literal newNumber(String s) {
             return new Literal(s);
         }
+
         static Literal newString(String s) {
             return new Literal(SQL2Parser.escapeStringLiteral(s));
         }
@@ -646,10 +687,13 @@ public class XPathToSQL2Converter {
         public String toString() {
             return value;
         }
+
     }
 
     static class Property extends Expression {
+
         final String name;
+
         Property(String name) {
             this.name = name;
         }
@@ -658,24 +702,15 @@ public class XPathToSQL2Converter {
         public String toString() {
             return '[' + name + ']';
         }
-    }
-
-    static class Parenthesis extends Expression {
-        final Expression expr;
-        public Parenthesis(Expression expr) {
-            this.expr = expr;
-        }
 
-        @Override
-        public String toString() {
-            return "(" + expr + ')';
-        }
     }
 
     static class Condition extends Expression {
+
         final Expression left;
         final String operator;
         Expression right;
+
         Condition(Expression left, String operator, Expression right) {
             this.left = left;
             this.operator = operator;
@@ -685,20 +720,29 @@ public class XPathToSQL2Converter {
         @Override
         public String toString() {
             return
+                "(" +
                 (left == null ? "" : left + " ") +
                 operator +
-                (right == null ? "" : " " + right);
+                (right == null ? "" : " " + right) +
+                ")";
         }
+
         @Override
         boolean isCondition() {
             return true;
         }
+
     }
 
     static class Function extends Expression {
-        String name;
+
+        final String name;
         final ArrayList<Expression> params = new ArrayList<Expression>();
 
+        Function(String name) {
+            this.name = name;
+        }
+
         @Override
         public String toString() {
             StringBuilder buff = new StringBuilder(name);
@@ -707,18 +751,46 @@ public class XPathToSQL2Converter {
                 if (i > 0) {
                     buff.append(", ");
                 }
-                buff.append(params.get(i));
+                buff.append(removeParens(params.get(i).toString()));
             }
             buff.append(')');
             return buff.toString();
         }
+
         @Override
         boolean isCondition() {
             return name.equals("contains") || name.equals("not");
         }
+
+    }
+
+    static class Cast extends Expression {
+
+        final Expression expr;
+        final String type;
+
+        Cast(Expression expr, String type) {
+            this.expr = expr;
+            this.type = type;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder buff = new StringBuilder("cast(");
+            buff.append(removeParens(expr.toString()));
+            buff.append(" as ").append(type).append(')');
+            return buff.toString();
+        }
+
+        @Override
+        boolean isCondition() {
+            return false;
+        }
+
     }
 
     static class Order {
+
         boolean descending;
         Expression expr;
 
@@ -726,6 +798,14 @@ public class XPathToSQL2Converter {
         public String toString() {
             return expr + (descending ? " desc" : "");
         }
+
+    }
+
+    static String removeParens(String s) {
+        if (s.startsWith("(") && s.endsWith(")")) {
+            return s.substring(1, s.length() - 1);
+        }
+        return s;
     }
 
 }

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=1309843&r1=1309842&r2=1309843&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 Thu Apr  5 13:27:08 2012
@@ -26,7 +26,6 @@ import java.util.HashMap;
 import java.util.Iterator;
 import org.apache.jackrabbit.mk.MicroKernelFactory;
 import org.apache.jackrabbit.mk.api.MicroKernel;
-import org.apache.jackrabbit.oak.api.QueryEngine;
 import org.apache.jackrabbit.oak.api.ResultRow;
 import org.junit.After;
 import org.junit.Before;
@@ -65,31 +64,37 @@ public class QueryTest {
 
     @Test
     public void bindVariableTest() throws Exception {
-        head = mk.commit("/", "+ \"test\": { \"hello\": {\"id\": \"1\"}, \"world\": {\"id\": \"2\"}}", null, null);
+        head = mk.commit("/", "+ \"test\": { \"hello\": {\"id\": \"1\"}, \"world\": {\"id\": \"2\"}}",
+                null, null);
         HashMap<String, CoreValue> sv = new HashMap<String, CoreValue>();
         CoreValueFactory vf = new CoreValueFactory();
         sv.put("id", vf.createValue("1"));
         Iterator<? extends ResultRow> result;
-        result = qe.executeQuery("select * from [nt:base] where id = $id", QueryEngine.SQL2, sv).getRows();
+        result = qe.executeQuery("select * from [nt:base] where id = $id",
+                QueryEngineImpl.SQL2, sv).getRows().iterator();
         assertTrue(result.hasNext());
         assertEquals("/test/hello", result.next().getPath());
 
         sv.put("id", vf.createValue("2"));
-        result = qe.executeQuery("select * from [nt:base] where id = $id", QueryEngine.SQL2, sv).getRows();
+        result = qe.executeQuery("select * from [nt:base] where id = $id",
+                QueryEngineImpl.SQL2, sv).getRows().iterator();
         assertTrue(result.hasNext());
         assertEquals("/test/world", result.next().getPath());
 
 
-        result = qe.executeQuery("explain select * from [nt:base] where id = 1 order by id", QueryEngine.SQL2, null).getRows();
+        result = qe.executeQuery("explain select * from [nt:base] where id = 1 order by id",
+                QueryEngineImpl.SQL2, null).getRows().iterator();
         assertTrue(result.hasNext());
-        assertEquals("nt:base AS nt:base /* traverse \"//*\" */", result.next().getValue("plan").getString());
+        assertEquals("nt:base AS nt:base /* traverse \"//*\" */",
+                result.next().getValue("plan").getString());
 
     }
 
     private void test(String file) throws Exception {
         InputStream in = getClass().getResourceAsStream(file);
         LineNumberReader r = new LineNumberReader(new InputStreamReader(in));
-        PrintWriter w = new PrintWriter(new OutputStreamWriter(new FileOutputStream("target/" + file)));
+        PrintWriter w = new PrintWriter(new OutputStreamWriter(
+                new FileOutputStream("target/" + file)));
         boolean errors = false;
         try {
             while (true) {
@@ -117,7 +122,8 @@ public class QueryTest {
                     }
                 } else if (line.startsWith("select") || line.startsWith("explain")) {
                     w.println(line);
-                    Iterator<? extends ResultRow> result = qe.executeQuery(line, QueryEngine.SQL2, null).getRows();
+                    Iterator<? extends ResultRow> result = qe.executeQuery(line,
+                            QueryEngineImpl.SQL2, null).getRows().iterator();
                     boolean readEnd = true;
                     while (result.hasNext()) {
                         ResultRow row = result.next();

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=1309843&r1=1309842&r2=1309843&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 Thu Apr  5 13:27:08 2012
@@ -42,6 +42,10 @@ select * from [nt:base] as x where isdes
 + "parents": { "p0": {"id": "0"}, "p1": {"id": "1"}, "p2": {"id": "2"}}
 + "children": { "c1": {"p": "1"}, "c2": {"p": "1"}, "c3": {"p": "2"}, "c4": {"p": "3"}}
 
+# relative property
+select * from [nt:base] where [c1/p] = '1'
+/children
+
 select * from [nt:base] as p where p.[jcr:path] = '/parents'
 /parents
 

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=1309843&r1=1309842&r2=1309843&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 Thu Apr  5 13:27:08 2012
@@ -3,6 +3,56 @@
 # * lines starting with "xpath" are xpath queries, followed by expected sql2 query
 # * use ascii character only
 
+xpath /jcr:root//*[jcr:contains(., 'test')] order by @jcr:score
+select * from [nt:base] where contains(*, 'test') and (issamenode('/') or isdescendantnode('/')) order by [jcr:score]
+
+xpath /jcr:root//element(*, test)
+select * from [test] where issamenode('/') or isdescendantnode('/')
+
+xpath /jcr:root//element(*, test)
+select * from [test] where issamenode('/') or isdescendantnode('/')
+
+xpath /jcr:root//element(*, user)[test/@jcr:primaryType]
+select * from [user] where ([test/jcr:primaryType] is not null) and (issamenode('/') or isdescendantnode('/'))
+
+xpath /jcr:root/content//*[(@sling:resourceType = 'start')]
+select * from [nt:base] where ([sling:resourceType] = 'start') and (issamenode('/content') or isdescendantnode('/content'))
+
+xpath /jcr:root/content//*[(@sling:resourceType = 'page')]
+select * from [nt:base] where ([sling:resourceType] = 'page') and (issamenode('/content') or 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 * 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 (issamenode('/content') or isdescendantnode('/content'))
+
+xpath /jcr:root/content/campaigns//*[@jcr:primaryType='Page'] order by jcr:content/@lastModified descending
+select * from [nt:base] where ([jcr:primaryType] = 'Page') and (issamenode('/content/campaigns') or 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 * 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 (issamenode('/content/campaigns') or isdescendantnode('/content/campaigns')) order by [onTime]
+
+xpath /jcr:root/content/dam//element(*, asset)[jcr:content/metadata/@dam:scene]
+select * from [asset] where ([jcr:content/metadata/dam:scene] is not null) and (issamenode('/content/dam') or isdescendantnode('/content/dam'))
+
+xpath /jcr:root/etc/cloud//*[(@sling:resourceType = 'framework')]
+select * from [nt:base] where ([sling:resourceType] = 'framework') and (issamenode('/etc/cloud') or isdescendantnode('/etc/cloud'))
+
+xpath /jcr:root/etc/cloud//*[(@sling:resourceType = 'analytics')]
+select * from [nt:base] where ([sling:resourceType] = 'analytics') and (issamenode('/etc/cloud') or isdescendantnode('/etc/cloud'))
+
+xpath /jcr:root/etc/reports//*[@jcr:primaryType='Page'] order by jcr:content/@lastModified descending
+select * from [nt:base] where ([jcr:primaryType] = 'Page') and (issamenode('/etc/reports') or isdescendantnode('/etc/reports')) order by [jcr:content/lastModified] desc
+
+xpath /jcr:root/etc/segment//*[@jcr:primaryType='Page'] order by jcr:content/@lastModified descending
+select * from [nt:base] where ([jcr:primaryType] = 'Page') and (issamenode('/etc/segment') or 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 * from [Item] where (([meta/archived] is null) and not([meta/archived] = true)) and (issamenode('/etc/workflow') or isdescendantnode('/etc/workflow'))
+
+xpath /jcr:root/home//element(*)
+select * from [nt:base] where issamenode('/home') or isdescendantnode('/home')
+
+# other queries
+
 xpath //*
 select * from [nt:base]
 
@@ -16,16 +66,16 @@ xpath //element(*, my:type)/(@my:title |
 select [my:title], [my:text] from [my:type]
 
 xpath /jcr:root/nodes//element(*, my:type)
-select * from [my:type] where [jcr:path] like '/nodes' or [jcr:path] like '/nodes/%'
+select * from [my:type] where issamenode('/nodes') or isdescendantnode('/nodes')
 
 xpath /jcr:root/some/element(nodes, my:type)
-select * from [my:type] where [jcr:path] like '/some/nodes'
+select * from [my:type] where [jcr:path] = '/some/nodes'
 
 xpath /jcr:root/some/nodes/element(*, my:type)
-select * from [my:type] where [jcr:path] like '/some/nodes/%' and not [jcr:path] like '/some/nodes/%/'
+select * from [my:type] where ischildnode('/some/nodes')
 
 xpath /jcr:root/some/nodes//element(*, my:type)
-select * from [my:type] where [jcr:path] like '/some/nodes' or [jcr:path] like '/some/nodes/%'
+select * from [my:type] where issamenode('/some/nodes') or isdescendantnode('/some/nodes')
 
 xpath //element(*, my:type)[@my:title = 'JSR 170']
 select * from [my:type] where [my:title] = 'JSR 170'
@@ -58,13 +108,13 @@ xpath //element(*, my:type)[@my:value <>
 select * from [my:type] where [my:value] <> 'Joe''s Caffee'
 
 xpath //element(*, my:type)[(not(@my:title) and @my:subject)]
-select * from [my:type] where ([my:title] is null and [my:subject] is not null)
+select * 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 * from [my:type] where [my:title] is null or [my:subject] is not null
+select * 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 * from [my:type] where not([my:value] > 0 and [my:value] < 100)
+select * from [my:type] where not(([my:value] > 0) and ([my:value] < 100))
 
 xpath //element(*, my:type) order by @jcr:lastModified
 select * from [my:type] order by [jcr:lastModified]
@@ -94,13 +144,13 @@ xpath //element(*, my:type)[@my:value = 
 invalid: Query: //element(*, my:type)[@my:value = +'x'(*)]
 
 xpath //element(*, my:type)[@my:value = ['x']
-invalid: Query: //element(*, my:type)[@my:value = [(*)'x']; expected: @, -, +
+invalid: Query: //element(*, my:type)[@my:value = [(*)'x']; expected: @, true, false, -, +
 
 xpath //element(*, my:type)[jcr:strike(@title,'%Java%')]
 invalid: Query: //element(*, my:type)[jcr:strike(@(*)title,'%Java%')]; expected: jcr:like | jcr:contains | jcr:score | jcr:deref
 
 xpath //element(*, my:type)[
-invalid: Query: //element(*, my:type)(*)[; expected: not, (, @, -, +
+invalid: Query: //element(*, my:type)(*)[; expected: not, (, @, true, false, -, +
 
 xpath //element(*, my:type)[@my:value >= .]
-invalid: Query: //element(*, my:type)[@my:value >= .(*)]; expected: @, -, +
+invalid: Query: //element(*, my:type)[@my:value >= .(*)]; expected: @, true, false, -, +