jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mreut...@apache.org
Subject svn commit: r154682 - in incubator/jackrabbit/trunk/src: java/org/apache/jackrabbit/core/search/ java/org/apache/jackrabbit/core/search/lucene/ java/org/apache/jackrabbit/core/search/sql/ java/org/apache/jackrabbit/core/search/xpath/ test/org/apache/jackrabbit/test/search/
Date Mon, 21 Feb 2005 15:41:26 GMT
Author: mreutegg
Date: Mon Feb 21 07:41:17 2005
New Revision: 154682

URL: http://svn.apache.org/viewcvs?view=rev&rev=154682
Log:
Implement 'child axis' and 'descendant-or-self axis' for SQL queries.

Removed:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/RangeQueryNode.java
Modified:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AndQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DefaultQueryNodeVisitor.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/ExactQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/LocationStepQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NodeTypeQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NotQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/OrQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/OrderQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PathQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNodeVisitor.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryRootNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/RelationQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/TextsearchQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/OrderByTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SQLPathTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AndQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AndQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AndQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AndQueryNode.java Mon Feb 21 07:41:17 2005
@@ -55,4 +55,11 @@
         return visitor.visit(this, data);
     }
 
+    /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_AND;
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DefaultQueryNodeVisitor.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DefaultQueryNodeVisitor.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DefaultQueryNodeVisitor.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DefaultQueryNodeVisitor.java Mon Feb 21 07:41:17 2005
@@ -46,10 +46,6 @@
         return data;
     }
 
-    public Object visit(RangeQueryNode node, Object data) {
-        return data;
-    }
-
     public Object visit(TextsearchQueryNode node, Object data) {
         return data;
     }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/ExactQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/ExactQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/ExactQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/ExactQueryNode.java Mon Feb 21 07:41:17 2005
@@ -58,6 +58,14 @@
     }
 
     /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_EXACT;
+    }
+
+    /**
      * Returns the name of the property to match.
      *
      * @return the name of the property to match.

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/LocationStepQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/LocationStepQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/LocationStepQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/LocationStepQueryNode.java Mon Feb 21 07:41:17 2005
@@ -156,4 +156,11 @@
         return visitor.visit(this, data);
     }
 
+    /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_LOCATION;
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NAryQueryNode.java Mon Feb 21 07:41:17 2005
@@ -102,6 +102,18 @@
     }
 
     /**
+     * Returns the number of operands.
+     * @return the number of operands.
+     */
+    public int getNumOperands() {
+        if (operands == null) {
+            return 0;
+        } else {
+            return operands.size();
+        }
+    }
+
+    /**
      * Helper class to accept a <code>visitor</code> for all operands
      * of this <code>NAryQueryNode</code>.
      *

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NodeTypeQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NodeTypeQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NodeTypeQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NodeTypeQueryNode.java Mon Feb 21 07:41:17 2005
@@ -43,4 +43,12 @@
     public Object accept(QueryNodeVisitor visitor, Object data) {
         return visitor.visit(this, data);
     }
+
+    /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_NODETYPE;
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NotQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NotQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NotQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/NotQueryNode.java Mon Feb 21 07:41:17 2005
@@ -49,4 +49,11 @@
         return visitor.visit(this, data);
     }
 
+    /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_NOT;
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/OrQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/OrQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/OrQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/OrQueryNode.java Mon Feb 21 07:41:17 2005
@@ -51,4 +51,11 @@
         return visitor.visit(this, data);
     }
 
+    /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_OR;
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/OrderQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/OrderQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/OrderQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/OrderQueryNode.java Mon Feb 21 07:41:17 2005
@@ -43,6 +43,14 @@
     }
 
     /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_ORDER;
+    }
+
+    /**
      * Adds an order specification to this query node.
      * @param property the name of the property.
      * @param ascending if <code>true</code> values of this properties are

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PathQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PathQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PathQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PathQueryNode.java Mon Feb 21 07:41:17 2005
@@ -45,6 +45,14 @@
     }
 
     /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_PATH;
+    }
+
+    /**
      * Adds a path step to this <code>PathQueryNode</code>.
      * @param step the step to add.
      */

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNode.java Mon Feb 21 07:41:17 2005
@@ -23,6 +23,39 @@
  */
 public abstract class QueryNode {
 
+    /** Type value for {@link QueryRootNode} */
+    public static final int TYPE_ROOT = 1;
+
+    /** Type value for {@link RelationQueryNode} */
+    public static final int TYPE_RELATION = 2;
+
+    /** Type value for {@link OrderQueryNode} */
+    public static final int TYPE_ORDER = 3;
+
+    /** Type value for {@link TextsearchQueryNode} */
+    public static final int TYPE_TEXTSEARCH = 4;
+
+    /** Type value for {@link ExactQueryNode} */
+    public static final int TYPE_EXACT = 5;
+
+    /** Type value for {@link NodeTypeQueryNode} */
+    public static final int TYPE_NODETYPE = 6;
+
+    /** Type value for {@link AndQueryNode} */
+    public static final int TYPE_AND = 7;
+
+    /** Type value for {@link OrQueryNode} */
+    public static final int TYPE_OR = 8;
+
+    /** Type value for {@link NotQueryNode} */
+    public static final int TYPE_NOT = 9;
+
+    /** Type value for {@link LocationStepQueryNode} */
+    public static final int TYPE_LOCATION = 10;
+
+    /** Type value for {@link PathQueryNode} */
+    public static final int TYPE_PATH = 11;
+
     /**
      * References the parent of this <code>QueryNode</code>. If this is the root
      * of a query tree, then <code>parent</code> is <code>null</code>.
@@ -60,5 +93,11 @@
      * @return the return value of the <code>visitor.visit()</code> call.
      */
     public abstract Object accept(QueryNodeVisitor visitor, Object data);
+
+    /**
+     * Returns the type of this query node.
+     * @return the type of this query node.
+     */
+    public abstract int getType();
 
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNodeVisitor.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNodeVisitor.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNodeVisitor.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNodeVisitor.java Mon Feb 21 07:41:17 2005
@@ -33,8 +33,6 @@
 
     public Object visit(NodeTypeQueryNode node, Object data);
 
-    public Object visit(RangeQueryNode node, Object data);
-
     public Object visit(TextsearchQueryNode node, Object data);
 
     public Object visit(PathQueryNode node, Object data);

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryRootNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryRootNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryRootNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryRootNode.java Mon Feb 21 07:41:17 2005
@@ -112,4 +112,11 @@
         return visitor.visit(this, data);
     }
 
+    /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_ROOT;
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/RelationQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/RelationQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/RelationQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/RelationQueryNode.java Mon Feb 21 07:41:17 2005
@@ -152,11 +152,19 @@
     }
 
     /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_RELATION;
+    }
+
+    /**
      * Returns the type of the value.
      *
      * @return the type of the value.
      */
-    public int getType() {
+    public int getValueType() {
         return type;
     }
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/TextsearchQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/TextsearchQueryNode.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/TextsearchQueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/TextsearchQueryNode.java Mon Feb 21 07:41:17 2005
@@ -46,6 +46,14 @@
     }
 
     /**
+     * Returns the type of this node.
+     * @return the type of this node.
+     */
+    public int getType() {
+        return QueryNode.TYPE_TEXTSEARCH;
+    }
+
+    /**
      * Returns the textsearch statement.
      *
      * @return the textsearch statement.

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java Mon Feb 21 07:41:17 2005
@@ -247,10 +247,6 @@
         }
     }
 
-    public Object visit(RangeQueryNode node, Object data) {
-        return null;
-    }
-
     public Object visit(TextsearchQueryNode node, Object data) {
         try {
             org.apache.lucene.queryParser.QueryParser parser
@@ -401,7 +397,7 @@
     public Object visit(RelationQueryNode node, Object data) {
         Query query;
         String stringValue = null;
-        switch (node.getType()) {
+        switch (node.getValueType()) {
             case 0:
                 // not set: either IS NULL or IS NOT NULL
                 break;
@@ -419,7 +415,7 @@
                 break;
             default:
                 throw new IllegalArgumentException("Unknown relation type: "
-                        + node.getType());
+                        + node.getValueType());
         }
 
         String field = "";

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/JCRSQLQueryBuilder.java Mon Feb 21 07:41:17 2005
@@ -40,6 +40,11 @@
 import javax.jcr.util.ISO8601;
 import java.util.Date;
 import java.util.Calendar;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Arrays;
 import java.text.SimpleDateFormat;
 
 /**
@@ -68,6 +73,9 @@
     /** Query node to gather the constraints defined in the WHERE clause */
     private final AndQueryNode constraintNode = new AndQueryNode(null);
 
+    /** List of PathQueryNode constraints that need to be merged */
+    private final List pathConstraints = new ArrayList();
+
     /**
      * Creates a new <code>JCRSQLQueryBuilder</code>.
      * @param statement the root node of the SQL syntax tree.
@@ -139,15 +147,50 @@
 
         // use //* if no path has been set
         PathQueryNode pathNode = root.getLocationNode();
-        if (pathNode.getPathSteps().length == 0) {
-            pathNode.setAbsolute(true);
+        pathNode.setAbsolute(true);
+        if (pathConstraints.size() == 0) {
             pathNode.addPathStep(new LocationStepQueryNode(pathNode, new QName("", ""), false));
             pathNode.addPathStep(new LocationStepQueryNode(pathNode, null, true));
+        } else {
+            try {
+                while (pathConstraints.size() > 1) {
+                    // merge path nodes
+                    MergingPathQueryNode path = null;
+                    for (Iterator it = pathConstraints.iterator(); it.hasNext();) {
+                        path = (MergingPathQueryNode) it.next();
+                        if (path.needsMerge()) {
+                            break;
+                        } else {
+                            path = null;
+                        }
+                    }
+                    if (path == null) {
+                        throw new IllegalArgumentException("Invalid combination of jcr:path clauses");
+                    } else {
+                        pathConstraints.remove(path);
+                        MergingPathQueryNode[] paths = (MergingPathQueryNode[]) pathConstraints.toArray(new MergingPathQueryNode[pathConstraints.size()]);
+                        paths = path.doMerge(paths);
+                        pathConstraints.clear();
+                        pathConstraints.addAll(Arrays.asList(paths));
+                    }
+                }
+            } catch (NoSuchElementException e) {
+                throw new IllegalArgumentException("Invalid combination of jcr:path clauses");
+            }
+            MergingPathQueryNode path = (MergingPathQueryNode) pathConstraints.get(0);
+            LocationStepQueryNode[] steps = path.getPathSteps();
+            for (int i = 0; i < steps.length; i++) {
+                LocationStepQueryNode step = new LocationStepQueryNode(pathNode, steps[i].getNameTest(), steps[i].getIncludeDescendants());
+                step.setIndex(steps[i].getIndex());
+                pathNode.addPathStep(step);
+            }
         }
 
-        // attach constraint to last path step
-        LocationStepQueryNode[] steps = pathNode.getPathSteps();
-        steps[steps.length - 1].addPredicate(constraintNode);
+        if (constraintNode.getNumOperands() > 0) {
+            // attach constraint to last path step
+            LocationStepQueryNode[] steps = pathNode.getPathSteps();
+            steps[steps.length - 1].addPredicate(constraintNode);
+        }
 
         return root;
     }
@@ -206,7 +249,7 @@
                 if (node.children[1] instanceof ASTIdentifier) {
                     // simply ignore, this is a join of a mixin node type
                 } else {
-                    createPathQuery(((ASTLiteral) node.children[1]).getValue());
+                    createPathQuery(((ASTLiteral) node.children[1]).getValue(), parent.getType());
                 }
                 // done
                 return data;
@@ -292,7 +335,9 @@
         // pass to operands
         node.childrenAccept(this, orQuery);
 
-        parent.addOperand(orQuery);
+        if (orQuery.getNumOperands() > 0) {
+            parent.addOperand(orQuery);
+        }
         return parent;
     }
 
@@ -432,9 +477,11 @@
 
     /**
      * Creates <code>LocationStepQueryNode</code>s from a <code>path</code>.
+     * @param path the path pattern
+     * @param operation the type of the parent node
      */
-    private void createPathQuery(String path) {
-        PathQueryNode pathNode = root.getLocationNode();
+    private void createPathQuery(String path, int operation) {
+        MergingPathQueryNode pathNode = new MergingPathQueryNode(operation);
         pathNode.setAbsolute(true);
 
         String[] names = path.split("/");
@@ -445,8 +492,11 @@
                     // root
                     pathNode.addPathStep(new LocationStepQueryNode(pathNode, new QName("", ""), false));
                 } else {
-                    // descendant '//'
-                    // FIXME this is not possible
+                    // descendant '//' -> invalid path
+                    // todo throw or ignore?
+                    // we currently do not throw and add location step for an
+                    // empty name (which is basically the root node)
+                    pathNode.addPathStep(new LocationStepQueryNode(pathNode, new QName("", ""), false));
                 }
             } else {
                 int idx = names[i].indexOf('[');
@@ -486,7 +536,6 @@
                         throw new IllegalArgumentException("Unknown prefix: " + name);
                     }
                 }
-                // @todo how to specify descendant-or-self?
                 // if name test is % this means also search descendants
                 boolean descendant = name == null;
                 LocationStepQueryNode step = new LocationStepQueryNode(pathNode, qName, descendant);
@@ -496,6 +545,7 @@
                 pathNode.addPathStep(step);
             }
         }
+        pathConstraints.add(pathNode);
     }
 
     /**
@@ -540,4 +590,205 @@
         return translated.toString();
     }
 
+    /**
+     * Extends the <code>PathQueryNode</code> with merging capability. A
+     * <code>PathQueryNode</code> <code>n1</code> can be merged with another
+     * node <code>n2</code> in the following case:
+     * <p/>
+     * <code>n1</code> contains a location step at position <code>X</code> with
+     * a name test that matches any node and has the descending flag set. Where
+     * <code>X</code> &lt; number of location steps.
+     * <code>n2</code> contains no location step to match any node name and
+     * the sequence of name tests is the same as the sequence of name tests
+     * of <code>n1</code>.
+     * The merged node then contains a location step at position <code>X</code>
+     * with the name test of the location step at position <code>X+1</code> and
+     * the descending flag set.
+     * <p/>
+     * The following path patterns:<br/>
+     * <code>/foo/%/bar</code> OR <code>/foo/bar</code><br/>
+     * are merged into:<br/>
+     * <code>/foo//bar</code>.
+     * <p/>
+     * The path patterns:<br/>
+     * <code>/foo/%</code> AND NOT <code>/foo/%/%</code><br/>
+     * are merged into:<br/>
+     * <code>/foo/*</code>
+     */
+    private static class MergingPathQueryNode extends PathQueryNode {
+
+        /** The operation type of the parent node */
+        private int operation;
+
+        /**
+         * Creates a new <code>MergingPathQueryNode</code> with the operation
+         * tpye of a parent node. <code>operation</code> must be one of:
+         * {@link org.apache.jackrabbit.core.search.QueryNode#TYPE_OR},
+         * {@link org.apache.jackrabbit.core.search.QueryNode#TYPE_AND} or
+         * {@link org.apache.jackrabbit.core.search.QueryNode#TYPE_NOT}.
+         * @param operation the operation type of the parent node.
+         */
+        MergingPathQueryNode(int operation) {
+            super(null);
+            if (operation != QueryNode.TYPE_OR && operation != QueryNode.TYPE_AND && operation != QueryNode.TYPE_NOT) {
+                throw new IllegalArgumentException("operation");
+            }
+            this.operation = operation;
+        }
+
+        /**
+         * Merges this node with a node from <code>nodes</code>. If a merge
+         * is not possible an NoSuchElementException is thrown.
+         * @param nodes the nodes to try to merge with.
+         * @return the merged array containing a merged version of this node.
+         */
+        MergingPathQueryNode[] doMerge(MergingPathQueryNode[] nodes) {
+            if (operation == QueryNode.TYPE_OR) {
+                return doOrMerge(nodes);
+            } else {
+                return doAndMerge(nodes);
+            }
+        }
+
+        /**
+         * Merges two nodes into a node which selects any child nodes of a
+         * given node.
+         * <p/>
+         * Example:<br/>
+         * The path patterns:<br/>
+         * <code>/foo/%</code> AND NOT <code>/foo/%/%</code><br/>
+         * are merged into:<br/>
+         * <code>/foo/*</code>
+         *
+         * @param nodes the nodes to merge with.
+         * @return the merged nodes.
+         */
+        private MergingPathQueryNode[] doAndMerge(MergingPathQueryNode[] nodes) {
+            if (operation == QueryNode.TYPE_AND) {
+                // check if there is an node with operation OP_AND_NOT
+                MergingPathQueryNode n = null;
+                for (int i = 0; i < nodes.length; i++) {
+                    if (nodes[i].operation == QueryNode.TYPE_NOT) {
+                        n = nodes[i];
+                        nodes[i] = this;
+                    }
+                }
+                if (n == null) {
+                    throw new NoSuchElementException("Merging not possible with any node");
+                } else {
+                    return n.doAndMerge(nodes);
+                }
+            }
+            // check if this node is valid as an operand
+            if (operands.size() < 3) {
+                throw new NoSuchElementException("Merging not possible");
+            }
+            int size = operands.size();
+            LocationStepQueryNode n1 = (LocationStepQueryNode) operands.get(size - 1);
+            LocationStepQueryNode n2 = (LocationStepQueryNode) operands.get(size - 2);
+            if (n1.getNameTest() != null || n2.getNameTest() != null
+                    || !n1.getIncludeDescendants() || !n2.getIncludeDescendants()) {
+                throw new NoSuchElementException("Merging not possible");
+            }
+            // find a node to merge with
+            MergingPathQueryNode matchedNode = null;
+            for (int i = 0; i < nodes.length; i++) {
+                if (nodes[i].operands.size() == operands.size() - 1) {
+                    boolean match = true;
+                    for (int j = 0; j < operands.size() - 1 && match; j++) {
+                        LocationStepQueryNode step = (LocationStepQueryNode) operands.get(j);
+                        LocationStepQueryNode other = (LocationStepQueryNode) nodes[i].operands.get(j);
+                        match &= (step.getNameTest() == null) ? other.getNameTest() == null : step.getNameTest().equals(other.getNameTest());
+                    }
+                    if (match) {
+                        matchedNode = nodes[i];
+                        break;
+                    }
+                }
+            }
+            if (matchedNode == null) {
+                throw new NoSuchElementException("Merging not possible with any node");
+            }
+            // change descendants flag to only match child nodes
+            // that's the result of the merge.
+            ((LocationStepQueryNode) matchedNode.operands.get(matchedNode.operands.size() - 1)).setIncludeDescendants(false);
+            return nodes;
+        }
+
+        /**
+         * Merges two nodes into one node selecting a node on the
+         * descendant-or-self axis.
+         * <p/>
+         * Example:<br/>
+         * The following path patterns:<br/>
+         * <code>/foo/%/bar</code> OR <code>/foo/bar</code><br/>
+         * are merged into:<br/>
+         * <code>/foo//bar</code>.
+         *
+         * @param nodes the node to merge.
+         * @return the merged nodes.
+         */
+        private MergingPathQueryNode[] doOrMerge(MergingPathQueryNode[] nodes) {
+            // compact this
+            MergingPathQueryNode compacted = new MergingPathQueryNode(QueryNode.TYPE_OR);
+            for (Iterator it = operands.iterator(); it.hasNext();) {
+                LocationStepQueryNode step = (LocationStepQueryNode) it.next();
+                if (step.getIncludeDescendants() && step.getNameTest() == null) {
+                    // check if has next
+                    if (it.hasNext()) {
+                        LocationStepQueryNode next = (LocationStepQueryNode) it.next();
+                        next.setIncludeDescendants(true);
+                        compacted.addPathStep(next);
+                    } else {
+                        compacted.addPathStep(step);
+                    }
+                } else {
+                    compacted.addPathStep(step);
+                }
+            }
+
+            MergingPathQueryNode matchedNode = null;
+            for (int i = 0; i < nodes.length; i++) {
+                // loop over the steps and compare the names
+                if (nodes[i].operands.size() == compacted.operands.size()) {
+                    boolean match = true;
+                    Iterator compactedSteps = compacted.operands.iterator();
+                    Iterator otherSteps = nodes[i].operands.iterator();
+                    while (match && compactedSteps.hasNext()) {
+                        LocationStepQueryNode n1 = (LocationStepQueryNode) compactedSteps.next();
+                        LocationStepQueryNode n2 = (LocationStepQueryNode) otherSteps.next();
+                        match &= (n1.getNameTest() == null) ? n2.getNameTest() == null : n1.getNameTest().equals(n2.getNameTest());
+                    }
+                    if (match) {
+                        matchedNode = nodes[i];
+                        break;
+                    }
+                }
+            }
+            if (matchedNode == null) {
+                throw new NoSuchElementException("Merging not possible with any node.");
+            }
+            // construct new list
+            List mergedList = new ArrayList(Arrays.asList(nodes));
+            mergedList.remove(matchedNode);
+            mergedList.add(compacted);
+            return (MergingPathQueryNode[]) mergedList.toArray(new MergingPathQueryNode[mergedList.size()]);
+        }
+
+        /**
+         * Returns <code>true</code> if this node needs merging; <code>false</code>
+         * otherwise.
+         * @return <code>true</code> if this node needs merging; <code>false</code>
+         * otherwise.
+         */
+        boolean needsMerge() {
+            for (Iterator it = operands.iterator(); it.hasNext();) {
+                LocationStepQueryNode step = (LocationStepQueryNode) it.next();
+                if (step.getIncludeDescendants() && step.getNameTest() == null) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java Mon Feb 21 07:41:17 2005
@@ -23,7 +23,6 @@
 import org.apache.jackrabbit.core.search.NotQueryNode;
 import org.apache.jackrabbit.core.search.ExactQueryNode;
 import org.apache.jackrabbit.core.search.NodeTypeQueryNode;
-import org.apache.jackrabbit.core.search.RangeQueryNode;
 import org.apache.jackrabbit.core.search.TextsearchQueryNode;
 import org.apache.jackrabbit.core.search.PathQueryNode;
 import org.apache.jackrabbit.core.search.LocationStepQueryNode;
@@ -250,10 +249,6 @@
         return data;
     }
 
-    public Object visit(RangeQueryNode node, Object data) {
-        return data;
-    }
-
     public Object visit(TextsearchQueryNode node, Object data) {
         StringBuffer sb = (StringBuffer) data;
         // escape quote
@@ -265,17 +260,67 @@
     public Object visit(PathQueryNode node, Object data) {
         StringBuffer sb = (StringBuffer) data;
         try {
-            sb.append(QueryConstants.JCR_PATH.toJCRName(resolver));
-            sb.append(" LIKE '");
-            LocationStepQueryNode[] steps = node.getPathSteps();
-            for (int i = 0; i < steps.length; i++) {
-                if (steps[i].getNameTest() == null
-                        || steps[i].getNameTest().getLocalName().length() > 0) {
-                    sb.append('/');
+            if (containsDescendantOrSelf(node)) {
+                sb.append("(");
+                sb.append(QueryConstants.JCR_PATH.toJCRName(resolver));
+                sb.append(" LIKE '");
+                LocationStepQueryNode[] steps = node.getPathSteps();
+                for (int i = 0; i < steps.length; i++) {
+                    if (steps[i].getNameTest() == null
+                            || steps[i].getNameTest().getLocalName().length() > 0) {
+                        sb.append('/');
+                    }
+                    if (steps[i].getIncludeDescendants()) {
+                        sb.append("%/");
+                    }
+                    steps[i].accept(this, sb);
+                }
+                sb.append('\'');
+                sb.append(" OR ");
+                sb.append(QueryConstants.JCR_PATH.toJCRName(resolver));
+                sb.append(" LIKE '");
+                for (int i = 0; i < steps.length; i++) {
+                    if (steps[i].getNameTest() == null
+                            || steps[i].getNameTest().getLocalName().length() > 0) {
+                        sb.append('/');
+                    }
+                    if (steps[i].getNameTest() != null) {
+                        steps[i].accept(this, sb);
+                    }
+                }
+                sb.append("')");
+            } else if (containsAllChildrenMatch(node)) {
+                sb.append(QueryConstants.JCR_PATH.toJCRName(resolver));
+                sb.append(" LIKE '");
+                StringBuffer path = new StringBuffer();
+                LocationStepQueryNode[] steps = node.getPathSteps();
+                for (int i = 0; i < steps.length; i++) {
+                    if (steps[i].getNameTest() == null
+                            || steps[i].getNameTest().getLocalName().length() > 0) {
+                        path.append('/');
+                    }
+                    steps[i].accept(this, path);
+                }
+                sb.append(path);
+                sb.append('\'');
+                sb.append(" AND NOT ");
+                sb.append(QueryConstants.JCR_PATH.toJCRName(resolver));
+                sb.append(" LIKE '");
+                sb.append(path).append("/%").append('\'');
+            } else {
+                // just do a best effort
+                sb.append(QueryConstants.JCR_PATH.toJCRName(resolver));
+                sb.append(" LIKE '");
+                LocationStepQueryNode[] steps = node.getPathSteps();
+                for (int i = 0; i < steps.length; i++) {
+                    if (steps[i].getNameTest() == null
+                            || steps[i].getNameTest().getLocalName().length() > 0) {
+                        sb.append('/');
+                    }
+                    steps[i].accept(this, sb);
                 }
-                steps[i].accept(this, sb);
+                sb.append('\'');
             }
-            sb.append('\'');
         } catch (NoPrefixDeclaredException e) {
             exceptions.add(e);
         }
@@ -417,19 +462,60 @@
     }
 
     private void appendValue(RelationQueryNode node, StringBuffer b) {
-        if (node.getType() == TYPE_LONG) {
+        if (node.getValueType() == TYPE_LONG) {
             b.append(node.getLongValue());
-        } else if (node.getType() == TYPE_DOUBLE) {
+        } else if (node.getValueType() == TYPE_DOUBLE) {
             b.append(node.getDoubleValue());
-        } else if (node.getType() == TYPE_STRING) {
+        } else if (node.getValueType() == TYPE_STRING) {
             b.append("'").append(node.getStringValue().replaceAll("'", "''")).append("'");
-        } else if (node.getType() == TYPE_DATE || node.getType() == TYPE_TIMESTAMP) {
+        } else if (node.getValueType() == TYPE_DATE || node.getValueType() == TYPE_TIMESTAMP) {
             Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
             cal.setTime(node.getDateValue());
             b.append("TIMESTAMP '").append(ISO8601.format(cal)).append("'");
         } else {
-            exceptions.add(new InvalidQueryException("Invalid type: " + node.getType()));
+            exceptions.add(new InvalidQueryException("Invalid type: " + node.getValueType()));
         }
 
+    }
+
+    /**
+     * Returns <code>true</code> if <code>path</code> contains exactly one
+     * step with a descendant-or-self axis and an explicit name test; returns
+     * <code>false</code> otherwise.
+     * @param path the path node.
+     * @return <code>true</code> if <code>path</code> contains exactly one
+     * step with a descendant-or-self axis.
+     */
+    private static boolean containsDescendantOrSelf(PathQueryNode path) {
+        LocationStepQueryNode[] steps = path.getPathSteps();
+        int count = 0;
+        for (int i = 0; i < steps.length; i++) {
+            if (steps[i].getNameTest() != null && steps[i].getIncludeDescendants()) {
+                count++;
+            }
+        }
+        return count == 1;
+    }
+
+    /**
+     * Returns <code>true</code> if <code>path</code> contains exactly one
+     * location step which matches all node names. That is, matches any children
+     * of a given node. That location step must be the last one in the sequence
+     * of location steps.
+     * @param path the path node.
+     * @return <code>true</code> if the last step matches any node name.
+     */
+    private static boolean containsAllChildrenMatch(PathQueryNode path) {
+        LocationStepQueryNode[] steps = path.getPathSteps();
+        int count = 0;
+        for (int i = 0; i < steps.length; i++) {
+            if (steps[i].getNameTest() == null && !steps[i].getIncludeDescendants()) {
+                if (i == steps.length - 1 && count == 0) {
+                    return true;
+                }
+                count++;
+            }
+        }
+        return false;
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java Mon Feb 21 07:41:17 2005
@@ -193,10 +193,6 @@
         return sb;
     }
 
-    public Object visit(RangeQueryNode node, Object data) {
-        return data;
-    }
-
     public Object visit(TextsearchQueryNode node, Object data) {
         StringBuffer sb = (StringBuffer) data;
         try {
@@ -338,19 +334,19 @@
      */
     private void appendValue(RelationQueryNode node, StringBuffer b)
             throws NoPrefixDeclaredException {
-        if (node.getType() == TYPE_LONG) {
+        if (node.getValueType() == TYPE_LONG) {
             b.append(node.getLongValue());
-        } else if (node.getType() == TYPE_DOUBLE) {
+        } else if (node.getValueType() == TYPE_DOUBLE) {
             b.append(node.getDoubleValue());
-        } else if (node.getType() == TYPE_STRING) {
+        } else if (node.getValueType() == TYPE_STRING) {
             b.append("'").append(node.getStringValue().replaceAll("'", "''")).append("'");
-        } else if (node.getType() == TYPE_DATE || node.getType() == TYPE_TIMESTAMP) {
+        } else if (node.getValueType() == TYPE_DATE || node.getValueType() == TYPE_TIMESTAMP) {
             Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
             cal.setTime(node.getDateValue());
             b.append(XPathQueryBuilder.XS_DATETIME.toJCRName(resolver));
             b.append("('").append(ISO8601.format(cal)).append("')");
         } else {
-            exceptions.add(new InvalidQueryException("Invalid type: " + node.getType()));
+            exceptions.add(new InvalidQueryException("Invalid type: " + node.getValueType()));
         }
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java Mon Feb 21 07:41:17 2005
@@ -447,7 +447,7 @@
 
         // if property name is jcr:primaryType treat special
         if (Constants.JCR_PRIMARYTYPE.equals(rqn.getProperty())) {
-            if (rqn.getType() == RelationQueryNode.TYPE_STRING) {
+            if (rqn.getValueType() == RelationQueryNode.TYPE_STRING) {
                 try {
                     QName ntName = QName.fromJCRName(rqn.getStringValue(), resolver);
                     NodeTypeQueryNode ntNode = new NodeTypeQueryNode(queryNode, ntName);

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/OrderByTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/OrderByTest.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/OrderByTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/OrderByTest.java Mon Feb 21 07:41:17 2005
@@ -122,7 +122,7 @@
 
         // both ascending
         String sql = "SELECT value FROM nt:unstructured WHERE " +
-                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY value, text";
+                "jcr:path LIKE '" + testRoot + "/%' ORDER BY value, text";
         Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         QueryResult result = q.execute();
         checkResultOrder(result, new String[]{"node2", "node3", "node1"});
@@ -134,7 +134,7 @@
 
         // both descending
         sql = "SELECT value FROM nt:unstructured WHERE " +
-                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY value DESC, text DESC";
+                "jcr:path LIKE '" + testRoot + "/%' ORDER BY value DESC, text DESC";
         q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         result = q.execute();
         checkResultOrder(result, new String[]{"node1", "node3", "node2"});
@@ -146,7 +146,7 @@
 
         // mixed ascending and descending
         sql = "SELECT value FROM nt:unstructured WHERE " +
-                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY value DESC, text";
+                "jcr:path LIKE '" + testRoot + "/%' ORDER BY value DESC, text";
         q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         result = q.execute();
         checkResultOrder(result, new String[]{"node1", "node2", "node3"});
@@ -172,7 +172,7 @@
         testRootNode.save();
 
         String sql = "SELECT value, jcr:score FROM nt:unstructured WHERE " +
-                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY jcr:score, value";
+                "jcr:path LIKE '" + testRoot + "/%' ORDER BY jcr:score, value";
         Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         QueryResult result = q.execute();
         checkResult(result, 3);
@@ -224,7 +224,7 @@
         }
         // first check ascending
         String sql = "SELECT value FROM nt:unstructured WHERE " +
-                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY value";
+                "jcr:path LIKE '" + testRoot + "/%' ORDER BY value";
         Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         QueryResult result = q.execute();
         checkResultOrder(result, nodeNames);
@@ -238,7 +238,7 @@
         Collections.reverse(Arrays.asList(nodeNames));
 
         sql = "SELECT value FROM nt:unstructured WHERE " +
-                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY value DESC";
+                "jcr:path LIKE '" + testRoot + "/%' ORDER BY value DESC";
         q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         result = q.execute();
         checkResultOrder(result, nodeNames);

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SQLPathTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SQLPathTest.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SQLPathTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SQLPathTest.java Mon Feb 21 07:41:17 2005
@@ -58,9 +58,28 @@
     }
 
     public void testDescendantSelfTestRoot() throws RepositoryException {
+        String sql = getStatement(testRoot + "/%/node1");
+        sql += " OR jcr:path = '" + testRoot + "/node1'";
+        executeSQLQuery(sql, new Node[]{n1});
+    }
+
+    public void testChildAxisRoot() throws RepositoryException {
+        String sql = getStatement("/%");
+        sql += " AND NOT jcr:path = '/%/%'";
+        Node[] nodes = toArray(superuser.getRootNode().getNodes());
+        executeSQLQuery(sql, nodes);
+    }
+
+    public void testChildAxisTestRoot() throws RepositoryException {
         String sql = getStatement(testRoot + "/%");
-        sql += " OR jcr:path = '" + testRoot + "'";
-        executeSQLQuery(sql, new Node[]{testRootNode, n1, n11, n12, n2, n21, n22});
+        sql += " AND NOT jcr:path = '" + testRoot + "/%/%'";
+        executeSQLQuery(sql, new Node[]{n1, n2});
+    }
+
+    public void testChildAxisLeaf() throws RepositoryException {
+        String sql = getStatement(testRoot + "/node1/node11/%");
+        sql += " AND NOT jcr:path = '" + testRoot + "/node1/node11/%/%'";
+        executeSQLQuery(sql, new Node[0]);
     }
 
     //-----------------------------< internal >---------------------------------

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java?view=diff&r1=154681&r2=154682
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SimpleQueryTest.java Mon Feb 21 07:41:17 2005
@@ -304,7 +304,7 @@
 
         testRootNode.save();
 
-        String sql = "SELECT * FROM nt:unstructured WHERE mytext is null and jcr:path LIKE '/"
+        String sql = "SELECT * FROM nt:unstructured WHERE mytext is null and jcr:path LIKE '"
                 + testRoot + "/%'";
         Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         QueryResult result = q.execute();
@@ -353,7 +353,7 @@
         testRootNode.save();
 
         String sql = "SELECT * FROM nt:unstructured WHERE 'foo' IN text " +
-                "and jcr:path LIKE '/" + testRoot + "/%'";
+                "and jcr:path LIKE '" + testRoot + "/%'";
         Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         QueryResult result = q.execute();
         checkResult(result, 3); // foo, bar, bla
@@ -369,7 +369,7 @@
         checkResult(result, 3); // foo, bar, bla
 
         sql = "SELECT * FROM nt:unstructured WHERE text = 'foo' " +
-                "and jcr:path LIKE '/" + testRoot + "/%'";
+                "and jcr:path LIKE '" + testRoot + "/%'";
         q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         result = q.execute();
         checkResult(result, 2); // bar, bla
@@ -385,7 +385,7 @@
         checkResult(result, 2); // bar, bla
 
         sql = "SELECT * FROM nt:unstructured WHERE 'bar' NOT IN text " +
-                "and jcr:path LIKE '/" + testRoot + "/%'";
+                "and jcr:path LIKE '" + testRoot + "/%'";
         q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         result = q.execute();
         checkResult(result, 2); // bar, bla



Mime
View raw message