You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2005/01/28 10:52:40 UTC

svn commit: r148868 - in incubator/jackrabbit/trunk: . src/java/org/apache/jackrabbit/core/search/lucene src/java/org/apache/jackrabbit/core/search/xpath src/test/org/apache/jackrabbit/test/search

Author: mreutegg
Date: Fri Jan 28 01:52:38 2005
New Revision: 148868

URL: http://svn.apache.org/viewcvs?view=rev&rev=148868
Log:
Upgraded to Lucene 1.4.3 and implemented order by in queries
Added:
   incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/ISO9075Test.java   (contents, props changed)
   incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/OrderByTest.java   (contents, props changed)
Modified:
   incubator/jackrabbit/trunk/project.xml
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/ChildAxisQuery.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DescendantSelfAxisQuery.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/MatchAllScorer.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/WildcardTermEnum.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java
   incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/TestAll.java

Modified: incubator/jackrabbit/trunk/project.xml
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/project.xml?view=diff&rev=148868&p1=incubator/jackrabbit/trunk/project.xml&r1=148867&p2=incubator/jackrabbit/trunk/project.xml&r2=148868
==============================================================================
--- incubator/jackrabbit/trunk/project.xml	(original)
+++ incubator/jackrabbit/trunk/project.xml	Fri Jan 28 01:52:38 2005
@@ -264,7 +264,7 @@
     <dependency>
       <groupId>lucene</groupId>
       <artifactId>lucene</artifactId>
-      <version>1.3</version>
+      <version>1.4.3</version>
     </dependency>
     <dependency>
       <groupId>xerces</groupId>

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&rev=148868&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/ChildAxisQuery.java&r1=148867&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/ChildAxisQuery.java&r2=148868
==============================================================================
--- 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	Fri Jan 28 01:52:38 2005
@@ -158,7 +158,7 @@
         private List uuids = null;
 
         /** The next document id to return */
-        private int nextDoc = 0;
+        private int nextDoc = -1;
 
         /**
          * Creates a new <code>ChildAxisScorer</code>.
@@ -172,9 +172,48 @@
         }
 
         /**
-         * @see Scorer#score(org.apache.lucene.search.HitCollector, int)
+         * @see Scorer#score(org.apache.lucene.search.HitCollector)
          */
-        public void score(HitCollector hc, int maxDoc) throws IOException {
+        public void score(HitCollector hc) throws IOException {
+            calculateChildren();
+
+            int next = hits.nextSetBit(0);
+            while (next > -1) {
+                hc.collect(next, 1.0f);
+                // move to next doc
+                next = hits.nextSetBit(next + 1);
+            }
+        }
+
+        public boolean next() throws IOException {
+            calculateChildren();
+            nextDoc = hits.nextSetBit(nextDoc + 1);
+            return nextDoc > -1;
+        }
+
+        public int doc() {
+            return nextDoc;
+        }
+
+        public float score() throws IOException {
+            // todo implement
+            return 1.0f;
+        }
+
+        public boolean skipTo(int target) throws IOException {
+            nextDoc = hits.nextSetBit(target);
+            return nextDoc > -1;
+        }
+
+        /**
+         * @exception UnsupportedOperationException this implementation always
+         * throws an <code>UnsupportedOperationException</code>.
+         */
+        public Explanation explain(int doc) throws IOException {
+            throw new UnsupportedOperationException();
+        }
+
+        private void calculateChildren() throws IOException {
             if (uuids == null) {
                 uuids = new ArrayList();
                 contextScorer.score(new HitCollector() {
@@ -182,7 +221,7 @@
                         // @todo maintain cache of doc id hierarchy
                         hits.set(doc);
                     }
-                }, reader.maxDoc()); // find all
+                }); // find all
                 for (int i = hits.nextSetBit(0); i >= 0; i = hits.nextSetBit(i + 1)) {
                     String uuid = reader.document(i).get(FieldNames.UUID);
                     uuids.add(uuid);
@@ -195,22 +234,7 @@
                         hits.set(children.doc());
                     }
                 }
-                nextDoc = hits.nextSetBit(0);
-            }
-
-            while (nextDoc > -1 && nextDoc < maxDoc) {
-                hc.collect(nextDoc, 1.0f);
-                // move to next doc
-                nextDoc = hits.nextSetBit(nextDoc + 1);
             }
-        }
-
-        /**
-         * @exception UnsupportedOperationException this implementation always
-         * throws an <code>UnsupportedOperationException</code>.
-         */
-        public Explanation explain(int doc) throws IOException {
-            throw new UnsupportedOperationException();
         }
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DescendantSelfAxisQuery.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DescendantSelfAxisQuery.java?view=diff&rev=148868&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DescendantSelfAxisQuery.java&r1=148867&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DescendantSelfAxisQuery.java&r2=148868
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DescendantSelfAxisQuery.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DescendantSelfAxisQuery.java	Fri Jan 28 01:52:38 2005
@@ -172,7 +172,7 @@
         private Set contextUUIDs = null;
 
         /** The next document id to return */
-        private int nextDoc = 0;
+        private int nextDoc = -1;
 
         /**
          * Creates a new <code>DescendantSelfAxisScorer</code>.
@@ -187,34 +187,18 @@
         }
 
         /**
-         * @see Scorer#score(org.apache.lucene.search.HitCollector, int)
+         * @see Scorer#score(org.apache.lucene.search.HitCollector)
          */
-        public void score(HitCollector hc, int maxDoc) throws IOException {
-            if (contextUUIDs == null) {
-                contextUUIDs = new HashSet();
-                contextScorer.score(new HitCollector() {
-                    public void collect(int doc, float score) {
-                        // @todo maintain cache of doc id hierarchy
-                        hits.set(doc);
-                    }
-                }, reader.maxDoc()); // find all
-                for (int i = hits.nextSetBit(0); i >= 0; i = hits.nextSetBit(i + 1)) {
-                    contextUUIDs.add(reader.document(i).get(FieldNames.UUID));
-                }
-
-                // reuse for final hits
-                hits.clear();
-
-                subScorer.score(new HitCollector() {
-                    public void collect(int doc, float score) {
-                        subHits.set(doc);
-                    }
-                }, reader.maxDoc());
-
-                nextDoc = subHits.nextSetBit(0);
+        public void score(HitCollector hc) throws IOException {
+            while (next()) {
+                hc.collect(doc(), score());
             }
+        }
 
-            while (nextDoc > -1 && nextDoc < maxDoc) {
+        public boolean next() throws IOException {
+            calculateSubHits();
+            nextDoc = subHits.nextSetBit(nextDoc + 1);
+            while (nextDoc > -1) {
                 // check if nextDoc is really valid
                 String parentUUID = reader.document(nextDoc).get(FieldNames.PARENT);
                 while (parentUUID != null && !contextUUIDs.contains(parentUUID)) {
@@ -230,12 +214,48 @@
                     }
                 }
                 if (parentUUID != null) {
-                    // match
-                    hc.collect(nextDoc, 1.0f);
+                    return true;
                 }
-                // move to next doc
+                // try next
                 nextDoc = subHits.nextSetBit(nextDoc + 1);
+            }
+            return false;
+        }
+
+        public int doc() {
+            return nextDoc;
+        }
+
+        public float score() throws IOException {
+            return 1.0f;
+        }
 
+        public boolean skipTo(int target) throws IOException {
+            nextDoc = target - 1;
+            return next();
+        }
+
+        private void calculateSubHits() throws IOException {
+            if (contextUUIDs == null) {
+                contextUUIDs = new HashSet();
+                contextScorer.score(new HitCollector() {
+                    public void collect(int doc, float score) {
+                        // @todo maintain cache of doc id hierarchy
+                        hits.set(doc);
+                    }
+                }); // find all
+                for (int i = hits.nextSetBit(0); i >= 0; i = hits.nextSetBit(i + 1)) {
+                    contextUUIDs.add(reader.document(i).get(FieldNames.UUID));
+                }
+
+                // reuse for final hits
+                hits.clear();
+
+                subScorer.score(new HitCollector() {
+                    public void collect(int doc, float score) {
+                        subHits.set(doc);
+                    }
+                });
             }
         }
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/MatchAllScorer.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/MatchAllScorer.java?view=diff&rev=148868&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/MatchAllScorer.java&r1=148867&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/MatchAllScorer.java&r2=148868
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/MatchAllScorer.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/MatchAllScorer.java	Fri Jan 28 01:52:38 2005
@@ -34,9 +34,9 @@
 class MatchAllScorer extends Scorer {
 
     /**
-     * current doc number
+     * next doc number
      */
-    private int docNo = 0;
+    private int nextDoc = 0;
 
     /**
      * IndexReader giving access to index
@@ -86,23 +86,43 @@
     }
 
     /**
-     * Scores documents until <code>maxDoc</code> has reached.
-     *
-     * @param hc     the <code>HitCollector</code> from the underlying
-     *               lucene query.
-     * @param maxDoc collect hits until <code>maxDoc</code> has reached.
-     */
-    public void score(HitCollector hc, int maxDoc) {
-        float score = getSimilarity().tf(1) * weight.getValue();
-        while (docNo < maxDoc) {
-            if (!reader.isDeleted(docNo)) {
-                // check docFilter
-                if (docFilter.get(docNo)) {
-                    hc.collect(docNo, score);
-                }
-            }
-            docNo++;
+     * @see Scorer#score(org.apache.lucene.search.HitCollector)
+     */
+    public void score(HitCollector hc) throws IOException {
+        while (next()) {
+            hc.collect(doc(), score());
         }
+    }
+
+
+    /**
+     * @see org.apache.lucene.search.Scorer#next()
+     */
+    public boolean next() throws IOException {
+        nextDoc = docFilter.nextSetBit(nextDoc + 1);
+        return nextDoc > -1;
+    }
+
+    /**
+     * @see org.apache.lucene.search.Scorer#doc()
+     */
+    public int doc() {
+        return nextDoc;
+    }
+
+    /**
+     * @see org.apache.lucene.search.Scorer#score()
+     */
+    public float score() throws IOException {
+        return 1.0f;
+    }
+
+    /**
+     * @see org.apache.lucene.search.Scorer#skipTo(int)
+     */
+    public boolean skipTo(int target) throws IOException {
+        nextDoc = target - 1;
+        return next();
     }
 
     /**

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java?view=diff&rev=148868&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java&r1=148867&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java&r2=148868
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java	Fri Jan 28 01:52:38 2005
@@ -24,6 +24,7 @@
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.ItemManager;
 import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.NoPrefixDeclaredException;
 import org.apache.log4j.Logger;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.standard.StandardAnalyzer;
@@ -31,6 +32,8 @@
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.Hits;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.Sort;
 
 import javax.jcr.query.InvalidQueryException;
 import javax.jcr.RepositoryException;
@@ -215,16 +218,25 @@
             return null;
         }
 
-        /*
         SortField[] sortFields = new SortField[orderProps.length];
         for (int i = 0; i < orderProps.length; i++) {
-            sortFields[i] = new SortField(orderProps[i], SortField.STRING, !ascending);
+            String prop = null;
+            try {
+                prop = orderProps[i].toJCRName(nsMappings);
+            } catch (NoPrefixDeclaredException e) {
+                // will never happen
+            }
+            sortFields[i] = new SortField(prop, SortField.STRING, !orderSpecs[i]);
         }
-*/
+
         Hits hits = null;
         try {
-            hits = persistentIndex.getIndexSearcher().search(query
-                    /*, new Sort(sortFields) */);
+            if (sortFields.length > 0) {
+                hits = persistentIndex.getIndexSearcher().search(query,
+                        new Sort(sortFields));
+            } else {
+                hits = persistentIndex.getIndexSearcher().search(query);
+            }
         } finally {
             readWriteLock.readLock().release();
         }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/WildcardTermEnum.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/WildcardTermEnum.java?view=diff&rev=148868&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/WildcardTermEnum.java&r1=148867&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/WildcardTermEnum.java&r2=148868
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/WildcardTermEnum.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/WildcardTermEnum.java	Fri Jan 28 01:52:38 2005
@@ -34,12 +34,20 @@
     private boolean endEnum = false;
 
     public WildcardTermEnum(IndexReader reader, Term term) throws IOException {
-        super(reader, term);
         pattern = createRegexp(term.text());
         field = term.field();
 
-        // FIXME optimize term enum. find start term text
-        setEnum(reader.terms(new Term(term.field(), "")));
+        int idx = 0;
+        while (idx < term.text().length()
+                && Character.isLetterOrDigit(term.text().charAt(idx))) {
+            idx++;
+        }
+        // because IndexReader.terms() starts with the term after the given
+        // one start with idx - 1
+        if (idx > 0) {
+            idx--;
+        }
+        setEnum(reader.terms(new Term(term.field(), term.text().substring(0, idx))));
     }
 
     protected boolean termCompare(Term term) {

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&rev=148868&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java&r1=148867&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java&r2=148868
==============================================================================
--- 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	Fri Jan 28 01:52:38 2005
@@ -350,7 +350,6 @@
                         root.addSelectProperty(name);
                     } else if (queryNode instanceof OrderQueryNode) {
                         QName name = ISO9075.decode(QName.fromJCRName(child.getValue(), resolver));
-                        // todo implement properly
                         root.getOrderNode().addOrderSpec(name, true);
                     }
                 } catch (IllegalNameException e) {

Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/ISO9075Test.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/ISO9075Test.java?view=auto&rev=148868
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/ISO9075Test.java	Fri Jan 28 01:52:38 2005
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.test.search;
+
+import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.search.xpath.ISO9075;
+import org.apache.xerces.util.XMLChar;
+import junit.framework.TestCase;
+
+/**
+ * Test cases for ISO9075 encode / decode.
+ */
+public class ISO9075Test extends TestCase {
+
+    public void testSpecExamples() {
+        assertEquals("My_x0020_Documents", ISO9075.encode("My Documents"));
+        assertEquals("_x0031_234id", ISO9075.encode("1234id"));
+        assertEquals("merry_x005f_xmas", ISO9075.encode("merry_xmas"));
+        assertEquals("merry_christmas", ISO9075.encode("merry_christmas"));
+    }
+
+    /**
+     * This is a disabled brute force test. It tests permutations of characters:
+     * <code>' ', '_', 'x', '0', '2', 'a', 'b', '{'</code>, encodes and decodes
+     * the sequences and test whether the initial sequence equals the resulting
+     * sequence that went through the encoding / decoding process.
+     * </p>
+     * The test takes about 30 seconds on my 1.2G P3.
+     * </p>
+     * To enable the test remove the 'disabled_' refix from the method name.
+     */
+    public void disabled_testBrute() {
+        char[] chars = new char[] {' ', '_', 'x', '0', '2', 'a', 'b', '{'};
+        long start = Long.parseLong("1000000", 8);
+        long end = Long.parseLong("7777777", 8);
+        for (long i = start; i < end; i++) {
+            String s = Long.toString(i, chars.length);
+            StringBuffer b = new StringBuffer(s.length());
+            for (int j = 0; j < s.length(); j++) {
+                b.append(chars[s.charAt(j) - '0']);
+            }
+            // encode and decode
+            QName initial = new QName("", b.toString());
+            if ((i % 100000) == 0) {
+                System.out.println(initial);
+            }
+            QName encoded = ISO9075.encode(initial);
+            assertTrue(XMLChar.isValidName(encoded.getLocalName()));
+            QName decoded = ISO9075.decode(encoded);
+            assertEquals(initial, decoded);
+        }
+    }
+
+}

Added: 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=auto&rev=148868
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/OrderByTest.java	Fri Jan 28 01:52:38 2005
@@ -0,0 +1,238 @@
+/*
+ * $Id: $
+ *
+ * Copyright 1997-2004 Day Management AG
+ * Barfuesserplatz 6, 4001 Basel, Switzerland
+ * All Rights Reserved.
+ *
+ * This software is the confidential and proprietary information of
+ * Day Management AG, ("Confidential Information"). You shall not
+ * disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into
+ * with Day.
+ */
+
+package org.apache.jackrabbit.test.search;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.TimeZone;
+
+/**
+ * Tests queries with order by.
+ */
+public class OrderByTest extends AbstractQueryTest {
+
+    public void testStringOrder() throws Exception {
+        populate(new String[]{"aaaa", "cccc", "bbbb", "dddd"});
+        checkOrder(new int[]{1, 3, 2, 4});
+    }
+
+    public void testIntegerOrder() throws Exception {
+        populate(new int[]{0, -1, 1, 5});
+        checkOrder(new int[]{2, 1, 3, 4});
+    }
+
+    public void testDateOrder() throws Exception {
+        Calendar c1 = Calendar.getInstance();
+        c1.set(2000, 4, 20, 14, 35, 14);
+        Calendar c2 = Calendar.getInstance();
+        c2.set(2000, 5, 20, 14, 35, 14);
+        Calendar c3 = Calendar.getInstance();
+        c3.set(2000, 4, 20, 14, 35, 13);
+        populate(new Calendar[]{c1, c2, c3});
+        checkOrder(new int[]{3, 1, 2});
+    }
+
+    public void testDateOrderMillis() throws Exception {
+        Calendar c1 = Calendar.getInstance();
+        c1.set(2000, 6, 12, 14, 35, 19);
+        c1.set(Calendar.MILLISECOND, 10);
+        Calendar c2 = Calendar.getInstance();
+        c2.set(2000, 6, 12, 14, 35, 19);
+        c2.set(Calendar.MILLISECOND, 9);
+        Calendar c3 = Calendar.getInstance();
+        c3.set(2000, 6, 12, 14, 35, 19);
+        c3.set(Calendar.MILLISECOND, 11);
+        populate(new Calendar[]{c1, c2, c3});
+        checkOrder(new int[]{2, 1, 3});
+    }
+
+    public void testDateOrderPositiveTimeZone() throws Exception {
+        Calendar c1 = Calendar.getInstance(TimeZone.getTimeZone("GMT+1:00"));
+        c1.set(2000, 6, 12, 15, 35, 19);
+        c1.set(Calendar.MILLISECOND, 10);
+        Calendar c2 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+        c2.set(2000, 6, 12, 14, 35, 19);
+        c2.set(Calendar.MILLISECOND, 9);
+        Calendar c3 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+        c3.set(2000, 6, 12, 14, 35, 19);
+        c3.set(Calendar.MILLISECOND, 11);
+        populate(new Calendar[]{c1, c2, c3});
+        checkOrder(new int[]{2, 1, 3});
+    }
+
+    public void testDateOrderNegativeTimeZone() throws Exception {
+        Calendar c1 = Calendar.getInstance(TimeZone.getTimeZone("GMT-1:00"));
+        c1.set(2000, 6, 12, 13, 35, 19);
+        c1.set(Calendar.MILLISECOND, 10);
+        Calendar c2 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+        c2.set(2000, 6, 12, 14, 35, 19);
+        c2.set(Calendar.MILLISECOND, 9);
+        Calendar c3 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+        c3.set(2000, 6, 12, 14, 35, 19);
+        c3.set(Calendar.MILLISECOND, 11);
+        populate(new Calendar[]{c1, c2, c3});
+        checkOrder(new int[]{2, 1, 3});
+    }
+
+    public void testDoubleOrder1() throws Exception {
+        populate(new double[]{-2.4, 4.3, 0.0});
+        checkOrder(new int[]{1, 3, 2});
+    }
+
+    public void testDoubleOrder2() throws Exception {
+        populate(new double[]{-1.5, -1.4, -1.39});
+        checkOrder(new int[]{1, 2, 3});
+    }
+
+    public void testMultipleOrder() throws Exception {
+        Node n1 = testRootNode.addNode("node1");
+        Node n2 = testRootNode.addNode("node2");
+        Node n3 = testRootNode.addNode("node3");
+
+        n1.setProperty("text", "aaa");
+        n1.setProperty("value", 3);
+        n2.setProperty("text", "bbb");
+        n2.setProperty("value", 2);
+        n3.setProperty("text", "ccc");
+        n3.setProperty("value", 2);
+
+        testRootNode.save();
+
+        // both ascending
+        String sql = "SELECT value FROM nt:unstructured WHERE " +
+                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY value, text";
+        Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, "sql");
+        QueryResult result = q.execute();
+        checkResultOrder(result, new String[]{"node2", "node3", "node1"});
+
+        String xpath = "/" + testRoot + "/*[@jcr:primaryType='nt:unstructured'] order by @value, @text";
+        q = superuser.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH_DOCUMENT_VIEW);
+        result = q.execute();
+        checkResultOrder(result, new String[]{"node2", "node3", "node1"});
+
+        // both descending
+        sql = "SELECT value FROM nt:unstructured WHERE " +
+                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY value DESC, text DESC";
+        q = superuser.getWorkspace().getQueryManager().createQuery(sql, "sql");
+        result = q.execute();
+        checkResultOrder(result, new String[]{"node1", "node3", "node2"});
+
+        xpath = "/" + testRoot + "/*[@jcr:primaryType='nt:unstructured'] order by @value descending, @text descending";
+        q = superuser.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH_DOCUMENT_VIEW);
+        result = q.execute();
+        checkResultOrder(result, new String[]{"node1", "node3", "node2"});
+
+        // mixed ascending and descending
+        sql = "SELECT value FROM nt:unstructured WHERE " +
+                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY value DESC, text";
+        q = superuser.getWorkspace().getQueryManager().createQuery(sql, "sql");
+        result = q.execute();
+        checkResultOrder(result, new String[]{"node1", "node2", "node3"});
+
+        xpath = "/" + testRoot + "/*[@jcr:primaryType='nt:unstructured'] order by @value descending, @text";
+        q = superuser.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH_DOCUMENT_VIEW);
+        result = q.execute();
+        checkResultOrder(result, new String[]{"node1", "node2", "node3"});
+    }
+
+    //------------------< internal >--------------------------------------------
+
+    private void populate(String[] values) throws RepositoryException {
+        for (int i = 0; i < values.length; i++) {
+            Node node = testRootNode.addNode("node" + (i + 1));
+            node.setProperty("value", values[i]);
+        }
+        testRootNode.save();
+    }
+
+    private void populate(Calendar[] values) throws RepositoryException {
+        for (int i = 0; i < values.length; i++) {
+            Node node = testRootNode.addNode("node" + (i + 1));
+            node.setProperty("value", values[i]);
+        }
+        testRootNode.save();
+    }
+
+    private void populate(int[] values) throws RepositoryException {
+        for (int i = 0; i < values.length; i++) {
+            Node node = testRootNode.addNode("node" + (i + 1));
+            node.setProperty("value", values[i]);
+        }
+        testRootNode.save();
+    }
+
+    private void populate(double[] values) throws RepositoryException {
+        for (int i = 0; i < values.length; i++) {
+            Node node = testRootNode.addNode("node" + (i + 1));
+            node.setProperty("value", values[i]);
+        }
+        testRootNode.save();
+    }
+
+    private void checkOrder(int[] order) throws RepositoryException {
+        String nodeNames[] = new String[order.length];
+        for (int i = 0; i < order.length; i++) {
+            nodeNames[i] = "node" + order[i];
+        }
+        // first check ascending
+        String sql = "SELECT value FROM nt:unstructured WHERE " +
+                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY value";
+        Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, "sql");
+        QueryResult result = q.execute();
+        checkResultOrder(result, nodeNames);
+
+        String xpath = "/" + testRoot + "/*[@jcr:primaryType='nt:unstructured'] order by @value";
+        q = superuser.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH_DOCUMENT_VIEW);
+        result = q.execute();
+        checkResultOrder(result, nodeNames);
+
+        // then check descending
+        Collections.reverse(Arrays.asList(nodeNames));
+
+        sql = "SELECT value FROM nt:unstructured WHERE " +
+                "jcr:path LIKE '/" + testRoot + "/%' ORDER BY value DESC";
+        q = superuser.getWorkspace().getQueryManager().createQuery(sql, "sql");
+        result = q.execute();
+        checkResultOrder(result, nodeNames);
+
+        xpath = "/" + testRoot + "/*[@jcr:primaryType='nt:unstructured'] order by @value descending";
+        q = superuser.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH_DOCUMENT_VIEW);
+        result = q.execute();
+        checkResultOrder(result, nodeNames);
+    }
+
+    private void checkResultOrder(QueryResult result, String[] nodeNames)
+            throws RepositoryException {
+        List nodes = new ArrayList();
+        for (NodeIterator it = result.getNodes(); it.hasNext();) {
+            nodes.add(it.nextNode());
+        }
+        assertEquals("Wrong hit count:", nodeNames.length, nodes.size());
+
+        for (int i = 0; i < nodeNames.length; i++) {
+            String name = ((Node) nodes.get(i)).getName();
+            assertEquals("Wrong order of nodes:", nodeNames[i], name);
+        }
+    }
+
+}

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/TestAll.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/TestAll.java?view=diff&rev=148868&p1=incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/TestAll.java&r1=148867&p2=incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/TestAll.java&r2=148868
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/TestAll.java	(original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/TestAll.java	Fri Jan 28 01:52:38 2005
@@ -35,10 +35,12 @@
     public static Test suite() {
         TestSuite suite = new TestSuite("Search tests");
 
+        suite.addTestSuite(ISO9075Test.class);
         suite.addTestSuite(SimpleQueryTest.class);
         suite.addTestSuite(FulltextQueryTest.class);
         suite.addTestSuite(SelectClauseTest.class);
         suite.addTestSuite(SQLTest.class);
+        suite.addTestSuite(OrderByTest.class);
 
         return suite;
     }