jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mreut...@apache.org
Subject svn commit: r156923 - 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/core/search/ test/org/apache/jackrabbit/test/api/query/
Date Thu, 10 Mar 2005 09:57:13 GMT
Author: mreutegg
Date: Thu Mar 10 01:57:09 2005
New Revision: 156923

URL: http://svn.apache.org/viewcvs?view=rev&rev=156923
Log:
Implement location step with context position index.

Modified:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AbstractQueryHandler.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/LocationStepQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryConstants.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/RelationQueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/ChildAxisQuery.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.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/core/search/SelectClauseTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/XPathAxisTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/XPathDocOrderTest.java

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AbstractQueryHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AbstractQueryHandler.java?view=diff&r1=156922&r2=156923
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AbstractQueryHandler.java
(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AbstractQueryHandler.java
Thu Mar 10 01:57:09 2005
@@ -81,7 +81,7 @@
      * @return the persistent <code>ItemStateProvider</code> of the current
      *         workspace.
      */
-    protected ItemStateManager getItemStateProvider() {
+    public ItemStateManager getItemStateProvider() {
         return stateProvider;
     }
 

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=156922&r2=156923
==============================================================================
--- 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
Thu Mar 10 01:57:09 2005
@@ -30,6 +30,12 @@
  */
 public class LocationStepQueryNode extends NAryQueryNode {
 
+    /** Constant value for position index = last() */
+    public static final int LAST = Integer.MIN_VALUE;
+
+    /** Constant value to indicate no position index */
+    public static final int NONE = Integer.MIN_VALUE + 1;
+
     /** Empty <code>QueryNode</code> array for us as return value */
     private static final QueryNode[] EMPTY = new QueryNode[0];
 
@@ -46,10 +52,9 @@
     private boolean includeDescendants;
 
     /**
-     * If <code>index</code> is larger than 0 this location step contains
-     * a position index.
+     * The context position <code>index</code>. Initially {@link #NONE}.
      */
-    private int index = 0;
+    private int index = NONE;
 
     /**
      * Creates a new <code>LocationStepQueryNode</code> with a reference to
@@ -111,9 +116,8 @@
     }
 
     /**
-     * Returns the predicate nodes for this location step. This method will
-     * not return a position predicate. Use {@link #getIndex} to retrieve
-     * this information.
+     * Returns the predicate nodes for this location step. This method may
+     * also return a position predicate.
      * @return the predicate nodes or an empty array if there are no predicates
      *   for this location step.
      */
@@ -126,21 +130,17 @@
     }
 
     /**
-     * Sets the position index for this step. A value of 0 (zero) indicates
+     * Sets the position index for this step. A value of {@link #NONE} indicates
      * that this location step has no position index assigned. That is, the
      * step selects all same name siblings.
      * @param index the position index.
-     * @exception IllegalArgumentException if index < 0.
      */
     public void setIndex(int index) {
-        if (index < 0) {
-            throw new IllegalArgumentException("index < 0");
-        }
         this.index = index;
     }
 
     /**
-     * Returns the position index for this step. A value of 0 (zero) indicates
+     * Returns the position index for this step. A value of {@link #NONE} indicates
      * that this location step has no position index assigned. That is, the
      * step selects all same name siblings.
      * @return the position index for this step.

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryConstants.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryConstants.java?view=diff&r1=156922&r2=156923
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryConstants.java
(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryConstants.java
Thu Mar 10 01:57:09 2005
@@ -70,6 +70,11 @@
      */
     public static int TYPE_TIMESTAMP = 5;
 
+    /**
+     * position index type
+     */
+    public static int TYPE_POSITION = 6;
+
     public static int OPERATIONS = 10;
 
     /**

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=156922&r2=156923
==============================================================================
--- 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
Thu Mar 10 01:57:09 2005
@@ -37,6 +37,11 @@
     private long valueLong;
 
     /**
+     * The <code>int</code> value of the position index.
+     */
+    private int valuePosition;
+
+    /**
      * The <code>double</code> value of the relation if this is a query is of
      * type <code>double</code>
      */
@@ -62,7 +67,7 @@
 
     /**
      * The value type of this relation. One of {@link #TYPE_DATE}, {@link
-     * #TYPE_DOUBLE}, {@link #TYPE_LONG}, {@link #TYPE_STRING}.
+     * #TYPE_DOUBLE}, {@link #TYPE_LONG}, {@link #TYPE_STRING}, {@link #TYPE_POSITION}.
      */
     private int type;
 
@@ -206,6 +211,25 @@
     public void setLongValue(long value) {
         valueLong = value;
         type = TYPE_LONG;
+    }
+
+    /**
+     * Returns the <code>int</code> position index value if this relation is
+     * of type {@link #TYPE_POSITION}.
+     * @return the position index value.
+     */
+    public int getPositionValue() {
+        return valuePosition;
+    }
+
+    /**
+     * Sets a new value for the position index.
+     *
+     * @param value the new value.
+     */
+    public void setPositionValue(int value) {
+        valuePosition = value;
+        type = TYPE_POSITION;
     }
 
     /**

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/ChildAxisQuery.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/ChildAxisQuery.java?view=diff&r1=156922&r2=156923
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/ChildAxisQuery.java
(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/ChildAxisQuery.java
Thu Mar 10 01:57:09 2005
@@ -26,6 +26,14 @@
 import org.apache.lucene.search.Searcher;
 import org.apache.lucene.search.Similarity;
 import org.apache.lucene.search.Weight;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.document.Document;
+import org.apache.jackrabbit.core.state.ItemStateManager;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.search.LocationStepQueryNode;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -40,23 +48,67 @@
 class ChildAxisQuery extends Query {
 
     /**
+     * The item state manager containing persistent item states.
+     */
+    private final ItemStateManager itemMgr;
+
+    /**
      * The context query
      */
     private final Query contextQuery;
 
     /**
+     * The nameTest to apply on the child axis, or <code>null</code> if all
+     * child nodes should be selected.
+     */
+    private final String nameTest;
+
+    /**
+     * The context position for the selected child node, or
+     * {@link LocationStepQueryNode#NONE} if no position is specified.
+     */
+    private final int position;
+
+    /**
      * The scorer of the context query
      */
     private Scorer contextScorer;
 
     /**
+     * The scorer of the name test query
+     */
+    private Scorer nameTestScorer;
+
+    /**
+     * Creates a new <code>ChildAxisQuery</code> based on a <code>context</code>
+     * query.
+     *
+     * @param itemMgr the item state manager.
+     * @param context the context for this query.
+     * @param nameTest a name test or <code>null</code> if any child node is
+     * selected.
+     */
+    ChildAxisQuery(ItemStateManager itemMgr, Query context, String nameTest) {
+        this(itemMgr, context, nameTest, LocationStepQueryNode.NONE);
+    }
+
+    /**
      * Creates a new <code>ChildAxisQuery</code> based on a <code>context</code>
      * query.
      *
+     * @param itemMgr the item state manager.
      * @param context the context for this query.
+     * @param nameTest a name test or <code>null</code> if any child node is
+     * selected.
+     * @param position the context position of the child node to select. If
+     * <code>position</code> is {@link LocationStepQueryNode#NONE}, the context
+     * position of the child node is not checked.
      */
-    ChildAxisQuery(Query context) {
+    ChildAxisQuery(ItemStateManager itemMgr, Query context, String nameTest, int position)
{
+        this.itemMgr = itemMgr;
         this.contextQuery = context;
+        this.nameTest = nameTest;
+        this.position = position;
     }
 
     /**
@@ -142,6 +194,9 @@
          */
         public Scorer scorer(IndexReader reader) throws IOException {
             contextScorer = contextQuery.weight(searcher).scorer(reader);
+            if (nameTest != null) {
+                nameTestScorer = new TermQuery(new Term(FieldNames.LABEL, nameTest)).weight(searcher).scorer(reader);
+            }
             return new ChildAxisScorer(searcher.getSimilarity(), reader);
         }
 
@@ -256,17 +311,102 @@
                         // @todo maintain cache of doc id hierarchy
                         hits.set(doc);
                     }
-                }); // find all
+                });
+
+                // collect nameTest hits
+                final BitSet nameTestHits = new BitSet();
+                if (nameTestScorer != null) {
+                    nameTestScorer.score(new HitCollector() {
+                        public void collect(int doc, float score) {
+                            nameTestHits.set(doc);
+                        }
+                    });
+                }
+
+                // read the uuids of the context nodes
                 for (int i = hits.nextSetBit(0); i >= 0; i = hits.nextSetBit(i + 1)) {
                     String uuid = reader.document(i).get(FieldNames.UUID);
                     uuids.add(uuid);
                 }
 
+                // collect the doc ids of all child nodes. we reuse the existing
+                // bitset.
                 hits.clear();
                 for (Iterator it = uuids.iterator(); it.hasNext();) {
                     TermDocs children = reader.termDocs(new Term(FieldNames.PARENT, (String)
it.next()));
                     while (children.next()) {
                         hits.set(children.doc());
+                    }
+                }
+                // filter out the child nodes that do not match the name test
+                // if there is any name test at all.
+                if (nameTestScorer != null) {
+                    hits.and(nameTestHits);
+                }
+
+                // filter by index
+                if (position != LocationStepQueryNode.NONE) {
+                    for (int i = hits.nextSetBit(0); i >= 0; i = hits.nextSetBit(i + 1))
{
+                        Document node = reader.document(i);
+                        String parentUUID = node.get(FieldNames.PARENT);
+                        String uuid = node.get(FieldNames.UUID);
+                        try {
+                            NodeState state = (NodeState) itemMgr.getItemState(new NodeId(parentUUID));
+                            if (nameTest == null) {
+                                // only select this node if it is the child at
+                                // specified position
+                                if (position == LocationStepQueryNode.LAST) {
+                                    // only select last
+                                    List childNodes = state.getChildNodeEntries();
+                                    if (childNodes.size() == 0
+                                            || !((NodeState.ChildNodeEntry) childNodes.get(childNodes.size()
- 1)).getUUID().equals(uuid)) {
+                                        hits.flip(i);
+                                    }
+                                } else {
+                                    List childNodes = state.getChildNodeEntries();
+                                    if (position < 1
+                                            || childNodes.size() < position
+                                            || !((NodeState.ChildNodeEntry) childNodes.get(position
- 1)).getUUID().equals(uuid)) {
+                                        hits.flip(i);
+                                    }
+                                }
+                            } else {
+                                // select the node when its index is equal to
+                                // specified position
+                                if (position == LocationStepQueryNode.LAST) {
+                                    // only select last
+                                    List childNodes = state.getChildNodeEntries(uuid);
+                                    if (childNodes.size() == 0) {
+                                        // no such child node, probably deleted meanwhile
+                                        hits.flip(i);
+                                    } else {
+                                        // only use the last one
+                                        QName name = ((NodeState.ChildNodeEntry) childNodes.get(0)).getName();
+                                        childNodes = state.getChildNodeEntries(name);
+                                        if (childNodes.size() == 0
+                                                || !((NodeState.ChildNodeEntry) childNodes.get(childNodes.size()
- 1)).getUUID().equals(uuid)) {
+                                            hits.flip(i);
+                                        }
+                                    }
+                                } else {
+                                    List childNodes = state.getChildNodeEntries(uuid);
+                                    if (childNodes.size() == 0) {
+                                        // no such child node, probably has been deleted
meanwhile
+                                        hits.flip(i);
+                                    } else {
+                                        for (int j = 0; j < childNodes.size(); j++) {
+                                            NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry)
childNodes.get(j);
+                                            if (entry.getIndex() != position) {
+                                                hits.flip(i);
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        } catch (ItemStateException e) {
+                            // ignore this node, probably has been deleted meanwhile
+                            hits.flip(i);
+                        }
                     }
                 }
             }

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=156922&r2=156923
==============================================================================
--- 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
Thu Mar 10 01:57:09 2005
@@ -24,6 +24,7 @@
 import org.apache.jackrabbit.core.QName;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.UnknownPrefixException;
+import org.apache.jackrabbit.core.state.ItemStateManager;
 import org.apache.jackrabbit.core.search.AndQueryNode;
 import org.apache.jackrabbit.core.search.ExactQueryNode;
 import org.apache.jackrabbit.core.search.LocationStepQueryNode;
@@ -38,6 +39,7 @@
 import org.apache.jackrabbit.core.search.QueryRootNode;
 import org.apache.jackrabbit.core.search.RelationQueryNode;
 import org.apache.jackrabbit.core.search.TextsearchQueryNode;
+import org.apache.jackrabbit.core.search.QueryNode;
 import org.apache.log4j.Logger;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.index.Term;
@@ -90,6 +92,11 @@
     private SessionImpl session;
 
     /**
+     * The shared item state manager of the workspace.
+     */
+    private ItemStateManager sharedItemMgr;
+
+    /**
      * Namespace mappings to internal prefixes
      */
     private NamespaceMappings nsMappings;
@@ -114,17 +121,20 @@
      *
      * @param root       the root node of the abstract query tree.
      * @param session    of the user executing this query.
+     * @param sharedItemMgr the shared item state manager of the workspace.
      * @param nsMappings namespace resolver for internal prefixes.
      * @param analyzer   for parsing the query statement of the contains function.
      * @param propReg    the property type registry.
      */
     private LuceneQueryBuilder(QueryRootNode root,
                                SessionImpl session,
+                               ItemStateManager sharedItemMgr,
                                NamespaceMappings nsMappings,
                                Analyzer analyzer,
                                PropertyTypeRegistry propReg) {
         this.root = root;
         this.session = session;
+        this.sharedItemMgr = sharedItemMgr;
         this.nsMappings = nsMappings;
         this.analyzer = analyzer;
         this.propRegistry = propReg;
@@ -136,6 +146,7 @@
      *
      * @param root       the root node of the abstract query tree.
      * @param session    of the user executing the query.
+     * @param sharedItemMgr the shared item state manager of the workspace.
      * @param nsMappings namespace resolver for internal prefixes.
      * @param analyzer   for parsing the query statement of the contains function.
      * @param propReg    the property type registry to lookup type information.
@@ -144,13 +155,14 @@
      */
     public static Query createQuery(QueryRootNode root,
                                     SessionImpl session,
+                                    ItemStateManager sharedItemMgr,
                                     NamespaceMappings nsMappings,
                                     Analyzer analyzer,
                                     PropertyTypeRegistry propReg)
             throws RepositoryException {
 
-        LuceneQueryBuilder builder = new LuceneQueryBuilder(root,
-                session, nsMappings, analyzer, propReg);
+        LuceneQueryBuilder builder = new LuceneQueryBuilder(root, session,
+                sharedItemMgr, nsMappings, analyzer, propReg);
 
         Query q = builder.createLuceneQuery();
         if (builder.exceptions.size() > 0) {
@@ -385,6 +397,17 @@
             andQuery.add((Query) predicates[i], true, false);
         }
 
+        // check for position predicate
+        QueryNode[] pred = node.getPredicates();
+        for (int i = 0; i < pred.length; i++) {
+            if (pred[i].getType() == QueryNode.TYPE_RELATION) {
+                RelationQueryNode pos = (RelationQueryNode) pred[i];
+                if (pos.getValueType() == QueryConstants.TYPE_POSITION) {
+                    node.setIndex(pos.getPositionValue());
+                }
+            }
+        }
+
         TermQuery nameTest = null;
         if (node.getNameTest() != null) {
             try {
@@ -408,19 +431,19 @@
                     andQuery = new BooleanQuery();
                     andQuery.add(subQuery, true, false);
                 } else {
-                    // @todo this will traverse the whole index, optimize!
+                    // todo this will traverse the whole index, optimize!
                     Query subQuery = new MatchAllQuery(FieldNames.UUID);
                     context = new DescendantSelfAxisQuery(context, subQuery);
-                    andQuery.add(new ChildAxisQuery(context), true, false);
+                    andQuery.add(new ChildAxisQuery(sharedItemMgr, context, null, node.getIndex()),
true, false);
                 }
             }
         } else {
-            // select child nodes
-            andQuery.add(new ChildAxisQuery(context), true, false);
-
             // name test
             if (nameTest != null) {
-                andQuery.add(nameTest, true, false);
+                andQuery.add(new ChildAxisQuery(sharedItemMgr, context, nameTest.getTerm().text(),
node.getIndex()), true, false);
+            } else {
+                // select child nodes
+                andQuery.add(new ChildAxisQuery(sharedItemMgr, context, null, node.getIndex()),
true, false);
             }
         }
 
@@ -452,6 +475,9 @@
                     stringValues = getStringValues(node.getProperty(), node.getStringValue());
                 }
                 break;
+            case QueryConstants.TYPE_POSITION:
+                // ignore position. is handled in the location step
+                return null;
             default:
                 throw new IllegalArgumentException("Unknown relation type: "
                         + node.getValueType());

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.java?view=diff&r1=156922&r2=156923
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.java
(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.java
Thu Mar 10 01:57:09 2005
@@ -115,8 +115,9 @@
      */
     public QueryResult execute() throws RepositoryException {
         // build lucene query
-        Query query = LuceneQueryBuilder.createQuery(root,
-                session, index.getNamespaceMappings(), index.getAnalyzer(), propReg);
+        Query query = LuceneQueryBuilder.createQuery(root, session,
+                index.getItemStateProvider(), index.getNamespaceMappings(), 
+                index.getAnalyzer(), propReg);
 
         OrderQueryNode orderNode = root.getOrderNode();
 

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=156922&r2=156923
==============================================================================
--- 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
Thu Mar 10 01:57:09 2005
@@ -501,7 +501,7 @@
             } else {
                 int idx = names[i].indexOf('[');
                 String name = null;
-                int index = 0;
+                int index = LocationStepQueryNode.NONE;
                 if (idx > -1) {
                     // contains index
                     name = names[i].substring(0, idx);
@@ -509,7 +509,7 @@
                     String indexStr = suffix.substring(1, suffix.length() - 1);
                     if (indexStr.equals("%")) {
                         // select all same name siblings
-                        index = 0;
+                        index = LocationStepQueryNode.NONE;
                     } else {
                         try {
                             index = Integer.parseInt(indexStr);
@@ -517,14 +517,19 @@
                             log.warn("Unable to parse index for path element: " + names[i]);
                         }
                     }
+                    if (name.equals("%")) {
+                        name = null;
+                    }
                 } else {
-                    // no index
+                    // no index specified
+                    // - index defaults to 1 if there is an explicit name test
+                    // - index defaults to NONE if name test is %
                     name = names[i];
-                    // in SQL this means index 1
-                    index = 1;
-                }
-                if (name.equals("%")) {
-                    name = null;
+                    if (name.equals("%")) {
+                        name = null;
+                    } else {
+                        index = 1;
+                    }
                 }
                 QName qName = null;
                 if (name != null) {

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=156922&r2=156923
==============================================================================
--- 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
Thu Mar 10 01:57:09 2005
@@ -338,7 +338,7 @@
                 } catch (NoPrefixDeclaredException e) {
                     exceptions.add(e);
                 }
-                if (node.getIndex() == 0) {
+                if (node.getIndex() == LocationStepQueryNode.NONE) {
                     sb.append("[%]");
                 } else if (node.getIndex() == 1) {
                     // do nothing

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=156922&r2=156923
==============================================================================
--- 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
Thu Mar 10 01:57:09 2005
@@ -252,7 +252,7 @@
                 exceptions.add(e);
             }
         }
-        if (node.getIndex() > 0) {
+        if (node.getIndex() != LocationStepQueryNode.NONE) {
             sb.append('[').append(node.getIndex()).append(']');
         }
         QueryNode[] predicates = node.getPredicates();
@@ -268,7 +268,13 @@
         StringBuffer sb = (StringBuffer) data;
         try {
 
-            String propName = "@" + ISO9075.encode(node.getProperty()).toJCRName(resolver);
+            String propName = "@";
+            // only encode if not position function
+            if (node.getProperty().equals(XPathQueryBuilder.FN_POSITION_FULL)) {
+                propName += node.getProperty().toJCRName(resolver);
+            } else {
+                propName += ISO9075.encode(node.getProperty()).toJCRName(resolver);
+            }
 
             if (node.getOperation() == OPERATION_EQ_VALUE) {
                 sb.append(propName).append(" eq ");
@@ -358,6 +364,12 @@
             cal.setTime(node.getDateValue());
             b.append(XPathQueryBuilder.XS_DATETIME.toJCRName(resolver));
             b.append("('").append(ISO8601.format(cal)).append("')");
+        } else if (node.getValueType() == TYPE_POSITION) {
+            if (node.getPositionValue() == LocationStepQueryNode.LAST) {
+                b.append("last()");
+            } else {
+                b.append(node.getPositionValue());
+            }
         } else {
             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=156922&r2=156923
==============================================================================
--- 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
Thu Mar 10 01:57:09 2005
@@ -36,6 +36,7 @@
 import org.apache.jackrabbit.core.search.QueryRootNode;
 import org.apache.jackrabbit.core.search.RelationQueryNode;
 import org.apache.jackrabbit.core.search.TextsearchQueryNode;
+import org.apache.jackrabbit.core.search.QueryConstants;
 import org.apache.jackrabbit.core.util.ISO9075;
 
 import javax.jcr.query.InvalidQueryException;
@@ -61,6 +62,36 @@
     static final QName FN_NOT_10 = new QName("", "not");
 
     /**
+     * QName for true function.
+     */
+    static final QName FN_TRUE = new QName("", "true");
+
+    /**
+     * QName for false function.
+     */
+    static final QName FN_FALSE = new QName("", "false");
+
+    /**
+     * QName for position function.
+     */
+    static final QName FN_POSITION = new QName("", "position");
+
+    /**
+     * QName for the full position function including bracket
+     */
+    static final QName FN_POSITION_FULL = new QName("", "position()");
+
+    /**
+     * QName for last function.
+     */
+    static final QName FN_LAST = new QName("", "last");
+
+    /**
+     * QName for first function.
+     */
+    static final QName FN_FIRST = new QName("", "first");
+
+    /**
      * QName for xs:dateTime
      */
     static final QName XS_DATETIME = new QName(SearchManager.NS_XS_URI, "dateTime");
@@ -71,6 +102,11 @@
     static final QName JCRFN_LIKE = new QName(SearchManager.NS_JCRFN_URI, "like");
 
     /**
+     * QName for jcrfn:deref
+     */
+    static final QName JCRFN_DEREF = new QName(SearchManager.NS_JCRFN_URI, "deref");
+
+    /**
      * QName for jcrfn:contains
      */
     static final QName JCRFN_CONTAINS = new QName(SearchManager.NS_JCRFN_URI, "contains");
@@ -518,7 +554,13 @@
         } else if (node.getId() == JJTDOUBLELITERAL) {
             queryNode.setDoubleValue(Double.parseDouble(node.getValue()));
         } else if (node.getId() == JJTINTEGERLITERAL) {
-            queryNode.setLongValue(Long.parseLong(node.getValue()));
+            // if this is an expression that contains position() do not change
+            // the type.
+            if (queryNode.getValueType() == QueryConstants.TYPE_POSITION) {
+                queryNode.setPositionValue(Integer.parseInt(node.getValue()));
+            } else {
+                queryNode.setLongValue(Long.parseLong(node.getValue()));
+            }
         } else {
             exceptions.add(new InvalidQueryException("Unsupported literal type:" + node.toString()));
         }
@@ -634,6 +676,52 @@
                     // wrong number of arguments
                     exceptions.add(new InvalidQueryException("Wrong number of arguments for
jcrfn:like"));
                 }
+            } else if (FN_TRUE.toJCRName(resolver).equals(fName)) {
+                if (queryNode.getType() == QueryNode.TYPE_RELATION) {
+                    RelationQueryNode rel = (RelationQueryNode) queryNode;
+                    rel.setStringValue("true");
+                } else {
+                    exceptions.add(new InvalidQueryException("Unsupported location for true()"));
+                }
+            } else if (FN_FALSE.toJCRName(resolver).equals(fName)) {
+                if (queryNode.getType() == QueryNode.TYPE_RELATION) {
+                    RelationQueryNode rel = (RelationQueryNode) queryNode;
+                    rel.setStringValue("false");
+                } else {
+                    exceptions.add(new InvalidQueryException("Unsupported location for false()"));
+                }
+            } else if (FN_POSITION.toJCRName(resolver).equals(fName)) {
+                if (queryNode.getType() == QueryNode.TYPE_RELATION) {
+                    RelationQueryNode rel = (RelationQueryNode) queryNode;
+                    if (rel.getOperation() == RelationQueryNode.OPERATION_EQ_GENERAL) {
+                        // set dummy value to set type of relation query node
+                        // will be overwritten when the tree is furhter parsed.
+                        rel.setPositionValue(1);
+                        rel.setProperty(FN_POSITION_FULL);
+                    } else {
+                        exceptions.add(new InvalidQueryException("Unsupported expression
with position(). Only = is supported."));
+                    }
+                } else {
+                    exceptions.add(new InvalidQueryException("Unsupported location for position()"));
+                }
+            } else if (FN_FIRST.toJCRName(resolver).equals(fName)) {
+                if (queryNode.getType() == QueryNode.TYPE_RELATION) {
+                    ((RelationQueryNode) queryNode).setPositionValue(1);
+                } else if (queryNode.getType() == QueryNode.TYPE_LOCATION) {
+                    ((LocationStepQueryNode) queryNode).setIndex(1);
+                } else {
+                    exceptions.add(new InvalidQueryException("Unsupported location for first()"));
+                }
+            } else if (FN_LAST.toJCRName(resolver).equals(fName)) {
+                if (queryNode.getType() == QueryNode.TYPE_RELATION) {
+                    ((RelationQueryNode) queryNode).setPositionValue(LocationStepQueryNode.LAST);
+                } else if (queryNode.getType() == QueryNode.TYPE_LOCATION) {
+                    ((LocationStepQueryNode) queryNode).setIndex(LocationStepQueryNode.LAST);
+                } else {
+                    exceptions.add(new InvalidQueryException("Unsupported location for last()"));
+                }
+            } else if (JCRFN_DEREF.toJCRName(resolver).equals(fName)) {
+                exceptions.add(new InvalidQueryException("Unsupported function: " + fName));
             } else {
                 exceptions.add(new InvalidQueryException("Unsupported function: " + fName));
             }

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/SelectClauseTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/SelectClauseTest.java?view=diff&r1=156922&r2=156923
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/SelectClauseTest.java
(original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/SelectClauseTest.java
Thu Mar 10 01:57:09 2005
@@ -102,7 +102,7 @@
         testRootNode.save();
 
         String sql = "SELECT myvalue FROM " + ntBase + " WHERE " +
-                "jcr:path LIKE '" + testRoot + "/node' AND myvalue IS NOT NULL";
+                "jcr:path LIKE '" + testRoot + "/node[%]' AND myvalue IS NOT NULL";
         Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         QueryResult result = q.execute();
         checkResult(result, 2, 2);

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/XPathAxisTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/XPathAxisTest.java?view=diff&r1=156922&r2=156923
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/XPathAxisTest.java
(original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/XPathAxisTest.java
Thu Mar 10 01:57:09 2005
@@ -167,4 +167,25 @@
         String xpath = testPath + "/node1";
         executeXPathQuery(xpath, new Node[]{n1});
     }
+
+    public void testIndex0Descendant() throws RepositoryException {
+        String xpath = "/jcr:root" + testRoot + "//*[0]";
+        executeXPathQuery(xpath, new Node[0]);
+    }
+
+    public void testIndex1Descendant() throws RepositoryException {
+        String xpath = "/jcr:root" + testRoot + "//*[1]";
+        executeXPathQuery(xpath, new Node[]{n1, n11, n21});
+    }
+
+    public void testIndex2Descendant() throws RepositoryException {
+        String xpath = "/jcr:root" + testRoot + "//*[2]";
+        executeXPathQuery(xpath, new Node[]{n2, n12, n22});
+    }
+
+    public void testIndex3Descendant() throws RepositoryException {
+        String xpath = "/jcr:root" + testRoot + "//*[3]";
+        executeXPathQuery(xpath, new Node[0]);
+    }
+
 }

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/XPathDocOrderTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/XPathDocOrderTest.java?view=diff&r1=156922&r2=156923
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/XPathDocOrderTest.java
(original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/XPathDocOrderTest.java
Thu Mar 10 01:57:09 2005
@@ -64,6 +64,23 @@
     }
 
     /**
+     * Tests if position index and document order on child axis returns the
+     * correct node.
+     * <p/>
+     * For configuration description see {@link XPathDocOrderTest}.
+     */
+    public void testDocOrderPositionIndex() throws Exception {
+        StringBuffer tmp = new StringBuffer("/");
+        tmp.append(jcrRoot).append(testRoot).append("/*");
+        tmp.append("[2]");
+        String resultPath = "";
+        for (NodeIterator nodes = testRootNode.getNodes(); nodes.hasNext() && nodes.getPos()
< 2;) {
+            resultPath = nodes.nextNode().getPath();
+        }
+        docOrderTest(new Statement(tmp.toString(), Query.XPATH), resultPath);
+    }
+
+    /**
      * Tests the <code>last()</code> function.
      * <p/>
      * For configuration description see {@link XPathDocOrderTest}.



Mime
View raw message