Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java (revision 744293) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java (working copy) @@ -16,14 +16,14 @@ */ package org.apache.jackrabbit.core.query.lucene; +import java.io.IOException; + +import org.apache.jackrabbit.core.SessionImpl; +import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.Sort; -import org.apache.lucene.index.IndexReader; -import org.apache.jackrabbit.core.SessionImpl; -import java.io.IOException; - /** * JackrabbitIndexSearcher implements an index searcher with * jackrabbit specific optimizations. @@ -75,6 +75,7 @@ */ public QueryHits evaluate(Query query, Sort sort) throws IOException { query = query.rewrite(reader); + QueryHits hits = null; if (query instanceof JackrabbitQuery) { hits = ((JackrabbitQuery) query).execute(this, session, sort); Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ParentAxisQuery.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ParentAxisQuery.java (revision 744293) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ParentAxisQuery.java (working copy) @@ -124,9 +124,16 @@ * @return 'ParentAxisQuery'. */ public String toString(String field) { - return "ParentAxisQuery"; + StringBuffer sb = new StringBuffer(); + sb.append("ParentAxisQuery("); + sb.append(contextQuery); + sb.append(", "); + sb.append(nameTest); + sb.append(")"); + return sb.toString(); } + //-----------------------< ParentAxisWeight >------------------------------- /** Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (revision 744293) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (working copy) @@ -494,12 +494,18 @@ NameQuery nameTest = null; if (node.getNameTest() != null) { + if (node.getNameTest().equals(LocationStepQueryNode.PARENT_NAME)) { + andQuery.add(new ParentAxisQuery(context, null, indexFormatVersion, nsMappings), Occur.MUST); + return andQuery; + } nameTest = new NameQuery(node.getNameTest(), indexFormatVersion, nsMappings); } if (node.getIncludeDescendants()) { if (nameTest != null) { - andQuery.add(new DescendantSelfAxisQuery(context, nameTest, false), Occur.MUST); + andQuery.add(nameTest, Occur.MUST); + return new DescendantSelfAxisQuery(context, andQuery, false); +// andQuery.add(new DescendantSelfAxisQuery(context, nameTest, false), Occur.MUST); } else { // descendant-or-self with nametest=* if (predicates.length > 0) { @@ -863,12 +869,13 @@ + node.getOperation()); } } - + if (relPath.getLength() > 1) { // child axis in relation Path.Element[] elements = relPath.getElements(); // elements.length - 1 = property name // elements.length - 2 = last child axis name test + boolean selectParent = true; for (int i = elements.length - 2; i >= 0; i--) { Name name = null; if (!elements[i].getName().equals(RelationQueryNode.STAR_NAME_TEST)) { @@ -877,25 +884,55 @@ if (i == elements.length - 2) { // join name test with property query if there is one if (name != null) { - Query nameTest = new NameQuery(name, - indexFormatVersion, nsMappings); - BooleanQuery and = new BooleanQuery(); - and.add(query, Occur.MUST); - and.add(nameTest, Occur.MUST); - query = and; + if (!name.equals(LocationStepQueryNode.PARENT_NAME)) { + Query nameTest = new NameQuery(name, + indexFormatVersion, nsMappings); + BooleanQuery and = new BooleanQuery(); + and.add(query, Occur.MUST); + and.add(nameTest, Occur.MUST); + + query = and; + } else { + // If we're searching the parent, we want to return the child axis, + // not the parent because this is part of the predicate. For instance, + // if the query is //child[../base], this part of the code is operating + // on the "../base" portion. So we want to return all the child nodes + // of "base", which will then be matched against the non predicate part. + query = new ChildAxisQuery(sharedItemMgr, + query, + null, + indexFormatVersion, + nsMappings); + selectParent = false; + } } else { // otherwise the query can be used as is } + } else if (name.equals(LocationStepQueryNode.PARENT_NAME)) { + // We need to select the of the properties if we haven't already. + if (selectParent) { + query = new ParentAxisQuery(query, null, + indexFormatVersion, nsMappings); + + selectParent = false; + } + + // See the note above on searching parents + query = new ChildAxisQuery(sharedItemMgr, + query, + null, + indexFormatVersion, + nsMappings); } else { query = new ParentAxisQuery(query, name, - indexFormatVersion, nsMappings); + indexFormatVersion, nsMappings); } } - // finally select the parent of the selected nodes - query = new ParentAxisQuery(query, null, - indexFormatVersion, nsMappings); + + if (selectParent) { + query = new ParentAxisQuery(query, null, indexFormatVersion, nsMappings); + } } - return query; } Index: jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/LocationStepQueryNode.java =================================================================== --- jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/LocationStepQueryNode.java (revision 744293) +++ jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/LocationStepQueryNode.java (working copy) @@ -47,6 +47,8 @@ */ public static final Name EMPTY_NAME = NameFactoryImpl.getInstance().create("", ""); + public static final Name PARENT_NAME = NameFactoryImpl.getInstance().create("internal", "__PARENT__"); + /** Empty QueryNode array for us as return value */ private static final QueryNode[] EMPTY = new QueryNode[0]; Index: jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/XPathQueryBuilder.java =================================================================== --- jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/XPathQueryBuilder.java (revision 744293) +++ jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/XPathQueryBuilder.java (working copy) @@ -545,7 +545,11 @@ } break; case JJTDOTDOT: - exceptions.add(new InvalidQueryException("Parent axis is not supported")); + if (queryNode instanceof LocationStepQueryNode) { + ((LocationStepQueryNode) queryNode).setNameTest(LocationStepQueryNode.PARENT_NAME); + } else { + ((RelationQueryNode) queryNode).addPathElement(PATH_FACTORY.createElement(LocationStepQueryNode.PARENT_NAME)); + } break; default: // per default traverse