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/02/08 10:36:59 UTC

svn commit: r152654 - in incubator/jackrabbit/trunk/src: java/org/apache/jackrabbit/core/ java/org/apache/jackrabbit/core/search/ java/org/apache/jackrabbit/core/search/lucene/ java/org/apache/jackrabbit/core/search/sql/ test/org/apache/jackrabbit/test/search/

Author: mreutegg
Date: Tue Feb  8 01:36:54 2005
New Revision: 152654

URL: http://svn.apache.org/viewcvs?view=rev&rev=152654
Log:
Simplify QueryHandler. Added support for jcr:score and jcr:path.

Modified:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SearchManager.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryHandler.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryManagerImpl.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/NodeIteratorImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryResultImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/RowIteratorImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.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/test/org/apache/jackrabbit/test/search/OrderByTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SelectClauseTest.java

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SearchManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SearchManager.java?view=diff&r1=152653&r2=152654
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SearchManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SearchManager.java Tue Feb  8 01:36:54 2005
@@ -23,14 +23,15 @@
 import org.apache.jackrabbit.core.observation.EventImpl;
 import org.apache.jackrabbit.core.observation.SynchronousEventListener;
 import org.apache.jackrabbit.core.search.QueryHandler;
+import org.apache.jackrabbit.core.search.QueryImpl;
 import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.log4j.Logger;
 
-import javax.jcr.ItemNotFoundException;
 import javax.jcr.NamespaceException;
 import javax.jcr.NamespaceRegistry;
 import javax.jcr.RepositoryException;
+import javax.jcr.Node;
 import javax.jcr.observation.Event;
 import javax.jcr.observation.EventIterator;
 import javax.jcr.query.InvalidQueryException;
@@ -43,7 +44,7 @@
 /**
  * Acts as a global entry point to execute queries and index nodes.
  *
- * @todo The SearchManager currently uses the system session to obtain an
+ * todo The SearchManager currently uses the system session to obtain an
  * ItemStateManager from where it reads persistent ItemStates. This is kind
  * of nasty, because the system session it is possible to change content through
  * the system session as well.
@@ -203,7 +204,7 @@
                              String statement,
                              String language)
             throws InvalidQueryException, RepositoryException {
-        return handler.createQuery(session, itemMgr, statement, language);
+        return new QueryImpl(session, itemMgr, handler, statement, language);
     }
 
     /**
@@ -212,18 +213,17 @@
      * @param session the session of the user executing the query.
      * @param itemMgr the item manager of the user executing the query. Needed
      *                to return <code>Node</code> instances in the result set.
-     * @param absPath absolute path to a node of type nt:query.
+     * @param node a node of type nt:query.
      * @return a <code>Query</code> instance to execute.
      * @throws InvalidQueryException if <code>absPath</code> is not a valid
      *                               persisted query (that is, a node of type nt:query)
-     * @throws ItemNotFoundException if there is no node at <code>absPath</code>.
      * @throws RepositoryException   if any other error occurs.
      */
     public Query createQuery(SessionImpl session,
                              ItemManager itemMgr,
-                             String absPath)
-            throws InvalidQueryException, ItemNotFoundException, RepositoryException {
-        return handler.createQuery(session, itemMgr, absPath);
+                             Node node)
+            throws InvalidQueryException, RepositoryException {
+        return new QueryImpl(session, itemMgr, handler, node);
     }
 
     //---------------< EventListener interface >--------------------------------

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java?view=diff&r1=152653&r2=152654
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/Constants.java Tue Feb  8 01:36:54 2005
@@ -16,11 +16,34 @@
  */
 package org.apache.jackrabbit.core.search;
 
+import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.NamespaceRegistryImpl;
+
 /**
  * This interface defines constants for data types and operation types
  * used in queries.
  */
 public interface Constants {
+
+    /**
+     * QName for jcr:score
+     */
+    public static final QName JCR_SCORE = new QName(NamespaceRegistryImpl.NS_JCR_URI, "score");
+
+    /**
+     * QName for jcr:path
+     */
+    public static final QName JCR_PATH = new QName(NamespaceRegistryImpl.NS_JCR_URI, "path");
+
+    /**
+     * QName for jcr:statement
+     */
+    public static final QName JCR_STATEMENT = new QName(NamespaceRegistryImpl.NS_JCR_URI, "statement");
+
+    /**
+     * QName for jcr:language
+     */
+    public static final QName JCR_LANGUAGE = new QName(NamespaceRegistryImpl.NS_JCR_URI, "language");
 
     /**
      * long data type

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryHandler.java?view=diff&r1=152653&r2=152654
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryHandler.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryHandler.java Tue Feb  8 01:36:54 2005
@@ -25,7 +25,7 @@
 import javax.jcr.query.Query;
 import javax.jcr.query.InvalidQueryException;
 import javax.jcr.RepositoryException;
-import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
 import java.io.IOException;
 
 /**
@@ -83,25 +83,8 @@
      * @throws InvalidQueryException if statement is invalid or language is unsupported.
      * @return A <code>Query</code> object.
      */
-    public Query createQuery(SessionImpl session,
+    public ExecutableQuery createExecutableQuery(SessionImpl session,
                              ItemManager itemMgr,
                              String statement,
                              String language) throws InvalidQueryException;
-    
-    /**
-     * Retrieves an existing persistent query. If <code>node</code>
-     * is not a valid persisted query (that is, a node of type
-     * <code>nt:query</code>), an <code>InvalidQueryException</code>
-     * is thrown.
-     *
-     * @param absPath path to a persisted query (that is, a node of type
-     *   <code>nt:query</code>).
-     * @throws InvalidQueryException If <code>absPath</code> is not a valid persisted query
-     *   (that is, a node of type <code>nt:query</code>).
-     * @throws RepositoryException if another error occurs
-     * @return a <code>Query</code> object.
-     */
-    public Query createQuery(SessionImpl session,
-                             ItemManager itemMgr,
-                             String absPath) throws ItemNotFoundException, RepositoryException;
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryManagerImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryManagerImpl.java?view=diff&r1=152653&r2=152654
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryManagerImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryManagerImpl.java Tue Feb  8 01:36:54 2005
@@ -93,7 +93,7 @@
     public Query getQuery(Node node)
             throws InvalidQueryException, RepositoryException {
 
-        return searchMgr.createQuery(session, itemMgr, node.getPath());
+        return searchMgr.createQuery(session, itemMgr, node);
     }
 
     /**

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=152653&r2=152654
==============================================================================
--- 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 Tue Feb  8 01:36:54 2005
@@ -134,18 +134,6 @@
     public Object visit(QueryRootNode node, Object data) {
         BooleanQuery root = new BooleanQuery();
 
-        QName[] props = node.getSelectProperties();
-        for (int i = 0; i < props.length; i++) {
-            try {
-                String prop = props[i].toJCRName(nsMappings);
-                // @todo really search nodes that have non null values?
-                root.add(new MatchAllQuery(prop), true, false);
-            } catch (NoPrefixDeclaredException e) {
-                // should never happen actually. prefixes are dynamically created
-                exceptions.add(e);
-            }
-        }
-
         Query wrapped = root;
         if (node.getLocationNode() != null) {
             wrapped = (Query) node.getLocationNode().accept(this, root);

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIteratorImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIteratorImpl.java?view=diff&r1=152653&r2=152654
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIteratorImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIteratorImpl.java Tue Feb  8 01:36:54 2005
@@ -38,6 +38,9 @@
     /** The UUIDs of the nodes in the result set */
     private final String[] uuids;
 
+    /** The score values for the nodes in the result set */
+    private final Float[] scores;
+
     /** ItemManager to turn UUIDs into Node instances */
     private final ItemManager itemMgr;
 
@@ -49,11 +52,14 @@
      * @param itemMgr the <code>ItemManager</code> to turn UUIDs into
      *   <code>Node</code> instances.
      * @param uuids the UUIDs of the result nodes.
+     * @param scores the corresponding score values for each result node.
      */
     NodeIteratorImpl(ItemManager itemMgr,
-                     String[] uuids) {
+                     String[] uuids,
+                     Float[] scores) {
         this.itemMgr = itemMgr;
         this.uuids = uuids;
+        this.scores = scores;
     }
 
     /**
@@ -128,9 +134,22 @@
     }
 
     /**
+     * Returns the score of the node returned by {@link #nextNode()}. In other
+     * words, this method returns the score value of the next <code>Node</code>.
+     * @return the score of the node returned by {@link #nextNode()}.
+     * @throws NoSuchElementException if there is no next node.
+     */
+    float getScore() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        return scores[pos].floatValue();
+    }
+
+    /**
      * Returns the next <code>Node</code> in the result set.
      * @return the next <code>Node</code> in the result set.
-     * @throws java.util.NoSuchElementException if iteration has no more
+     * @throws NoSuchElementException if iteration has no more
      *   <code>Node</code>s.
      */
     NodeImpl nextNodeImpl() {

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=152653&r2=152654
==============================================================================
--- 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 Tue Feb  8 01:36:54 2005
@@ -25,64 +25,56 @@
 import org.apache.jackrabbit.core.search.LocationStepQueryNode;
 import org.apache.jackrabbit.core.search.NodeTypeQueryNode;
 import org.apache.jackrabbit.core.search.DefaultQueryNodeVisitor;
+import org.apache.jackrabbit.core.search.ExecutableQuery;
 import org.apache.jackrabbit.core.QName;
-import org.apache.jackrabbit.core.NamespaceRegistryImpl;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.ItemManager;
-import org.apache.jackrabbit.core.Path;
-import org.apache.jackrabbit.core.MalformedPathException;
-import org.apache.jackrabbit.core.NoPrefixDeclaredException;
 import org.apache.jackrabbit.core.AccessManagerImpl;
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.AccessManager;
-import org.apache.jackrabbit.core.NamespaceResolver;
 import org.apache.lucene.search.Hits;
 import org.apache.lucene.search.Query;
+import org.apache.log4j.Logger;
 
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeManager;
 import javax.jcr.nodetype.PropertyDef;
 import javax.jcr.query.InvalidQueryException;
 import javax.jcr.query.QueryResult;
-import javax.jcr.*;
-import javax.jcr.lock.LockException;
-import javax.jcr.version.VersionException;
+import javax.jcr.RepositoryException;
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.io.IOException;
 
 /**
+ * Implements the {@link ExecutableQuery} interface.
  */
-class QueryImpl implements javax.jcr.query.Query {
+class QueryImpl implements ExecutableQuery {
 
-    /**
-     * jcr:statement
-     */
-    private static final QName PROP_STATEMENT =
-            new QName(NamespaceRegistryImpl.NS_JCR_URI, "statement");
-
-    /**
-     * jcr:language
-     */
-    private static final QName PROP_LANGUAGE =
-            new QName(NamespaceRegistryImpl.NS_JCR_URI, "language");
+    /** The logger instance for this class */
+    private static final Logger log = Logger.getLogger(QueryImpl.class);
 
+    /** The root node of the query tree */
     private final QueryRootNode root;
 
+    /** The session of the user executing this query */
     private final SessionImpl session;
 
+    /** The item manager of the user executing this query */
     private final ItemManager itemMgr;
 
+    /** The actual search index */
     private final SearchIndex index;
 
-    private final String statement;
-
-    private final String language;
-
-    private Path path;
-
+    /**
+     * Creates a new query instance from a query string.
+     * @param session the session of the user executing this query.
+     * @param itemMgr the item manager of the session executing this query.
+     * @param index the search index.
+     * @param statement the query statement.
+     * @param language the syntax of the query statement.
+     * @throws InvalidQueryException if the query statement is invalid according
+     * to the specified <code>language</code>.
+     */
     public QueryImpl(SessionImpl session,
                      ItemManager itemMgr,
                      SearchIndex index,
@@ -91,56 +83,17 @@
         this.session = session;
         this.itemMgr = itemMgr;
         this.index = index;
-        this.statement = statement;
-        this.language = language;
-
         // parse query according to language
         // build query tree
         this.root = QueryParser.parse(statement, language, session.getNamespaceResolver());
     }
 
-    public QueryImpl(SessionImpl session,
-                     ItemManager itemMgr,
-                     SearchIndex index,
-                     String absPath)
-            throws ItemNotFoundException, InvalidQueryException, RepositoryException {
-
-        this.session = session;
-        this.itemMgr = itemMgr;
-        this.index = index;
-
-        try {
-            Node query = null;
-            String relPath = absPath.substring(1);
-            if (session.getRootNode().hasNode(relPath)) {
-                query = session.getRootNode().getNode(relPath);
-                // assert query has mix:referenceable
-                query.getUUID();
-                NodeTypeManager ntMgr = session.getWorkspace().getNodeTypeManager();
-                NodeType ntQuery = ntMgr.getNodeType(NodeTypeRegistry.NT_QUERY.toJCRName(session.getNamespaceResolver()));
-                if (!query.getPrimaryNodeType().equals(ntQuery)) {
-                    throw new InvalidQueryException("node is not of type nt:query");
-                }
-            } else {
-                throw new ItemNotFoundException(absPath);
-            }
-
-            path = Path.create(absPath, session.getNamespaceResolver(), true);
-
-            statement = query.getProperty(PROP_STATEMENT.toJCRName(session.getNamespaceResolver())).getString();
-            language = query.getProperty(PROP_LANGUAGE.toJCRName(session.getNamespaceResolver())).getString();
-
-            // parse query according to language
-            // build query tree and pass to QueryImpl
-            QueryRootNode root = QueryParser.parse(statement, language, session.getNamespaceResolver());
-            this.root = root;
-        } catch (NoPrefixDeclaredException e) {
-            throw new InvalidQueryException(e.getMessage(), e);
-        } catch (MalformedPathException e) {
-            throw new ItemNotFoundException(absPath, e);
-        }
-    }
-
+    /**
+     * Executes this query and returns a <code>{@link QueryResult}</code>.
+     *
+     * @return a <code>QueryResult</code>
+     * @throws RepositoryException if an error occurs
+     */
     public QueryResult execute() throws RepositoryException {
         // build lucene query
         Query query = LuceneQueryBuilder.createQuery(root,
@@ -163,21 +116,27 @@
 
 
         List uuids;
+        List scores;
         AccessManagerImpl accessMgr = session.getAccessManager();
 
         // execute it
         try {
             Hits result = index.executeQuery(query, orderProperties, ascSpecs);
             uuids = new ArrayList(result.length());
+            scores = new ArrayList(result.length());
+
             for (int i = 0; i < result.length(); i++) {
                 String uuid = result.doc(i).get(FieldNames.UUID);
                 // check access
                 if (accessMgr.isGranted(new NodeId(uuid), AccessManager.READ)) {
                     uuids.add(uuid);
+                    scores.add(new Float(result.score(i)));
                 }
             }
         } catch (IOException e) {
+            log.error("Exception while executing query: ", e);
             uuids = Collections.EMPTY_LIST;
+            scores = Collections.EMPTY_LIST;
         }
 
         // get select properties
@@ -209,65 +168,8 @@
         // return QueryResult
         return new QueryResultImpl(itemMgr,
                 (String[]) uuids.toArray(new String[uuids.size()]),
+                (Float[]) scores.toArray(new Float[scores.size()]),
                 selectProps,
                 session.getNamespaceResolver());
     }
-
-    public String getStatement() {
-        return statement;
-    }
-
-    public String getLanguage() {
-        return language;
-    }
-
-    public String getPersistentQueryPath() throws ItemNotFoundException {
-        if (path == null) {
-            throw new ItemNotFoundException("not a persistent query");
-        }
-        try {
-            return path.toJCRPath(session.getNamespaceResolver());
-        } catch (NoPrefixDeclaredException e) {
-            // should not happen actually
-            throw new ItemNotFoundException(path.toString());
-        }
-    }
-
-    public void save(String absPath)
-            throws ItemExistsException,
-            PathNotFoundException,
-            VersionException,
-            ConstraintViolationException,
-            LockException,
-            UnsupportedRepositoryOperationException,
-            RepositoryException {
-        try {
-            NamespaceResolver resolver = session.getNamespaceResolver();
-            Path p = Path.create(absPath, resolver, true);
-            if (!p.isAbsolute()) {
-                throw new RepositoryException(absPath + " is not absolut");
-            }
-            if (!session.getRootNode().hasNode(p.getAncestor(1).toJCRPath(resolver).substring(1))) {
-                throw new PathNotFoundException(p.getAncestor(1).toJCRPath(resolver));
-            }
-            String relPath = p.toJCRPath(resolver).substring(1);
-            if (session.getRootNode().hasNode(relPath)) {
-                throw new ItemExistsException(p.toJCRPath(resolver));
-            }
-            Node queryNode = session.getRootNode().addNode(relPath,
-                    NodeTypeRegistry.NT_QUERY.toJCRName(resolver));
-            // set properties
-            queryNode.setProperty(PROP_LANGUAGE.toJCRName(resolver), language);
-            queryNode.setProperty(PROP_STATEMENT.toJCRName(resolver), statement);
-            // add mixin referenceable
-            queryNode.addMixin(NodeTypeRegistry.MIX_REFERENCEABLE.toJCRName(resolver));
-            // FIXME do anything else?
-            queryNode.getParent().save();
-        } catch (MalformedPathException e) {
-            throw new RepositoryException(e.getMessage(), e);
-        } catch (NoPrefixDeclaredException e) {
-            throw new RepositoryException(e.getMessage(), e);
-        }
-    }
-
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryResultImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryResultImpl.java?view=diff&r1=152653&r2=152654
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryResultImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryResultImpl.java Tue Feb  8 01:36:54 2005
@@ -32,21 +32,39 @@
  */
 class QueryResultImpl implements QueryResult {
 
+    /** The logger instance for this class */
     private static final Logger log = Logger.getLogger(QueryResultImpl.class);
 
+    /** The item manager of the session executing the query */
     private final ItemManager itemMgr;
 
+    /** The UUIDs of the result nodes */
     private final String[] uuids;
 
+    /** The scores of the result nodes */
+    private final Float[] scores;
+
+    /** The select properties */
     private final QName[] selectProps;
 
+    /** The namespace resolver of the session executing the query */
     private final NamespaceResolver resolver;
 
+    /**
+     * Creates a new query result.
+     * @param itemMgr the item manager of the session executing the query.
+     * @param uuids the UUIDs of the result nodes.
+     * @param scores the score values of the result nodes.
+     * @param selectProps the select properties of the query.
+     * @param resolver the namespace resolver of the session executing the query.
+     */
     public QueryResultImpl(ItemManager itemMgr,
                            String[] uuids,
+                           Float[] scores,
                            QName[] selectProps,
                            NamespaceResolver resolver) {
         this.uuids = uuids;
+        this.scores = scores;
         this.itemMgr = itemMgr;
         this.selectProps = selectProps;
         this.resolver = resolver;
@@ -75,13 +93,13 @@
      * @see QueryResult#getNodes()
      */
     public NodeIterator getNodes() throws RepositoryException {
-        return new NodeIteratorImpl(itemMgr, uuids);
+        return new NodeIteratorImpl(itemMgr, uuids, scores);
     }
 
     /**
      * @see QueryResult#getRows()
      */
     public RowIterator getRows() throws RepositoryException {
-        return new RowIteratorImpl(new NodeIteratorImpl(itemMgr, uuids), selectProps, resolver);
+        return new RowIteratorImpl(new NodeIteratorImpl(itemMgr, uuids, scores), selectProps, resolver);
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/RowIteratorImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/RowIteratorImpl.java?view=diff&r1=152653&r2=152654
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/RowIteratorImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/RowIteratorImpl.java Tue Feb  8 01:36:54 2005
@@ -22,12 +22,15 @@
 import org.apache.jackrabbit.core.PropertyImpl;
 import org.apache.jackrabbit.core.IllegalNameException;
 import org.apache.jackrabbit.core.UnknownPrefixException;
+import org.apache.jackrabbit.core.search.Constants;
 
 import javax.jcr.query.RowIterator;
 import javax.jcr.query.Row;
 import javax.jcr.Value;
 import javax.jcr.RepositoryException;
 import javax.jcr.ItemNotFoundException;
+import javax.jcr.PathValue;
+import javax.jcr.LongValue;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.HashSet;
@@ -70,7 +73,7 @@
      *   <code>Row</code>s.
     */
     public Row nextRow() {
-        return new RowImpl(nodes.nextNodeImpl());
+        return new RowImpl(nodes.getScore(), nodes.nextNodeImpl());
     }
 
     /**
@@ -143,6 +146,9 @@
      */
     class RowImpl implements Row {
 
+        /** The score for this result row */
+        private final float score;
+
         /** The underlying <code>Node</code> of this result row. */
         private final NodeImpl node;
 
@@ -154,9 +160,11 @@
 
         /**
          * Creates a new <code>RowImpl</code> instance based on <code>node</code>.
+         * @param score the score value for this result row
          * @param node the underlying <code>Node</code> for this <code>Row</code>.
          */
-        RowImpl(NodeImpl node) {
+        RowImpl(float score, NodeImpl node) {
+            this.score = score;
             this.node = node;
         }
 
@@ -182,8 +190,14 @@
                             tmp[i] = null;
                         }
                     } else {
-                        // property not set
-                        tmp[i] = null;
+                        // property not set or jcr:path / jcr:score
+                        if (Constants.JCR_PATH.equals(properties[i])) {
+                            tmp[i] = PathValue.valueOf(node.getPath());
+                        } else if (Constants.JCR_SCORE.equals(properties[i])) {
+                            tmp[i] = new LongValue((int) (score * 1000f));
+                        } else {
+                            tmp[i] = null;
+                        }
                     }
                 }
                 values = tmp;
@@ -218,7 +232,14 @@
                 if (node.hasProperty(prop)) {
                     return node.getProperty(prop).getValue();
                 } else {
-                    return null;
+                    // either jcr:score / jcr:path or not set
+                    if (Constants.JCR_PATH.equals(prop)) {
+                        return PathValue.valueOf(node.getPath());
+                    } else if (Constants.JCR_SCORE.equals(prop)) {
+                        return new LongValue((int) (score * 1000f));
+                    } else {
+                        return null;
+                    }
                 }
             } catch (IllegalNameException e) {
                 throw new RepositoryException(e.getMessage(), e);

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&r1=152653&r2=152654
==============================================================================
--- 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 Tue Feb  8 01:36:54 2005
@@ -20,6 +20,8 @@
 import org.apache.jackrabbit.core.fs.FileSystemException;
 import org.apache.jackrabbit.core.fs.FileSystemResource;
 import org.apache.jackrabbit.core.search.AbstractQueryHandler;
+import org.apache.jackrabbit.core.search.Constants;
+import org.apache.jackrabbit.core.search.ExecutableQuery;
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.ItemManager;
@@ -37,7 +39,6 @@
 
 import javax.jcr.query.InvalidQueryException;
 import javax.jcr.RepositoryException;
-import javax.jcr.ItemNotFoundException;
 import java.io.IOException;
 
 /**
@@ -163,7 +164,7 @@
      * @throws InvalidQueryException if statement is invalid or language is unsupported.
      * @return A <code>Query</code> object.
      */
-    public javax.jcr.query.Query createQuery(SessionImpl session,
+    public ExecutableQuery createExecutableQuery(SessionImpl session,
                                              ItemManager itemMgr,
                                              String statement,
                                              String language)
@@ -172,26 +173,6 @@
     }
 
     /**
-     * Retrieves an existing persistent query. If <code>node</code>
-     * is not a valid persisted query (that is, a node of type
-     * <code>nt:query</code>), an <code>InvalidQueryException</code>
-     * is thrown.
-     *
-     * @param absPath path to a persisted query (that is, a node of type
-     *   <code>nt:query</code>).
-     * @throws InvalidQueryException If <code>absPath</code> is not a valid persisted query
-     *   (that is, a node of type <code>nt:query</code>).
-     * @throws RepositoryException if another error occurs
-     * @return a <code>Query</code> object.
-     */
-    public javax.jcr.query.Query createQuery(SessionImpl session,
-                                             ItemManager itemMgr,
-                                             String absPath)
-            throws ItemNotFoundException, RepositoryException {
-        return new QueryImpl(session, itemMgr, this, absPath);
-    }
-
-    /**
      * Closes this <code>QueryHandler</code> and frees resources attached
      * to this handler.
      */
@@ -214,19 +195,22 @@
         try {
             readWriteLock.readLock().acquire();
         } catch (InterruptedException e) {
-            // FIXME: ??? do logging, simply return?
-            return null;
+            throw new IOException("Unable to obtain read lock on search index.");
         }
 
         SortField[] sortFields = new SortField[orderProps.length];
         for (int i = 0; i < orderProps.length; i++) {
             String prop = null;
-            try {
-                prop = orderProps[i].toJCRName(nsMappings);
-            } catch (NoPrefixDeclaredException e) {
-                // will never happen
+            if (Constants.JCR_SCORE.equals(orderProps[i])) {
+                sortFields[i] = new SortField(null, SortField.SCORE, !orderSpecs[i]);
+            } else {
+                try {
+                    prop = orderProps[i].toJCRName(nsMappings);
+                } catch (NoPrefixDeclaredException e) {
+                    // will never happen
+                }
+                sortFields[i] = new SortField(prop, SortField.STRING, !orderSpecs[i]);
             }
-            sortFields[i] = new SortField(prop, SortField.STRING, !orderSpecs[i]);
         }
 
         Hits hits = null;

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=152653&r2=152654
==============================================================================
--- 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 Tue Feb  8 01:36:54 2005
@@ -31,7 +31,6 @@
 import org.apache.jackrabbit.core.search.LocationStepQueryNode;
 import org.apache.jackrabbit.core.NamespaceResolver;
 import org.apache.jackrabbit.core.QName;
-import org.apache.jackrabbit.core.NamespaceRegistryImpl;
 import org.apache.jackrabbit.core.IllegalNameException;
 import org.apache.jackrabbit.core.UnknownPrefixException;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
@@ -57,11 +56,6 @@
      */
     private static final String DATE_PATTERN = "yyyy-MM-dd";
 
-    /**
-     * QName for jcr:path
-     */
-    static final QName JCR_PATH = new QName(NamespaceRegistryImpl.NS_JCR_URI, "path");
-
     /** The root node of the sql query syntax tree */
     private final ASTQuery stmt;
 
@@ -74,10 +68,6 @@
     /** Query node to gather the constraints defined in the WHERE clause */
     private final AndQueryNode constraintNode = new AndQueryNode(null);
 
-    public JCRSQLQueryBuilder() {
-        stmt = null;
-    }
-
     /**
      * Creates a new <code>JCRSQLQueryBuilder</code>.
      * @param statement the root node of the SQL syntax tree.
@@ -212,7 +202,7 @@
             }, data);
             QName identifier = tmp[0];
 
-            if (identifier.equals(JCR_PATH)) {
+            if (identifier.equals(Constants.JCR_PATH)) {
                 if (node.children[1] instanceof ASTIdentifier) {
                     // simply ignore, this is a join of a mixin node type
                 } else {

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=152653&r2=152654
==============================================================================
--- 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 Tue Feb  8 01:36:54 2005
@@ -265,7 +265,7 @@
     public Object visit(PathQueryNode node, Object data) {
         StringBuffer sb = (StringBuffer) data;
         try {
-            sb.append(JCRSQLQueryBuilder.JCR_PATH.toJCRName(resolver));
+            sb.append(Constants.JCR_PATH.toJCRName(resolver));
             sb.append(" LIKE '");
             LocationStepQueryNode[] steps = node.getPathSteps();
             for (int i = 0; i < steps.length; i++) {

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=152653&r2=152654
==============================================================================
--- 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 Tue Feb  8 01:36:54 2005
@@ -157,6 +157,32 @@
         checkResultOrder(result, new String[]{"node1", "node2", "node3"});
     }
 
+    public void testOrderByScore() throws RepositoryException {
+        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();
+
+        String sql = "SELECT value, jcr:score FROM nt:unstructured WHERE " +
+                "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);
+
+        String xpath = "/" + testRoot + "/*[@jcr:primaryType='nt:unstructured'] order by @jcr:score, @value";
+        q = superuser.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH);
+        result = q.execute();
+        checkResult(result, 3);
+    }
+
     //------------------< internal >--------------------------------------------
 
     private void populate(String[] values) throws RepositoryException {

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SelectClauseTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SelectClauseTest.java?view=diff&r1=152653&r2=152654
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SelectClauseTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/search/SelectClauseTest.java Tue Feb  8 01:36:54 2005
@@ -36,20 +36,20 @@
 
         testRootNode.save();
 
-        String sql = "SELECT myvalue FROM \"" + ntBase
-                + "\" WHERE \"jcr:path\" LIKE '" + testRoot + "/%'";
+        String sql = "SELECT myvalue FROM " + ntBase + " WHERE " +
+                "jcr:path LIKE '" + testRoot + "/%' AND myvalue IS NOT NULL";
         Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         QueryResult result = q.execute();
         checkResult(result, 2);
 
-        sql = "SELECT myvalue FROM \"" + ntBase
-                + "\" WHERE \"jcr:path\" LIKE '" + testRoot + "/%'"
-                + " AND yourvalue = 'foo'";
+        sql = "SELECT myvalue FROM " + ntBase
+                + " WHERE jcr:path LIKE '" + testRoot + "/%'"
+                + " AND yourvalue = 'foo' AND myvalue IS NOT NULL";
         q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         result = q.execute();
         checkResult(result, 0);
 
-        sql = "SELECT myvalue FROM \"" + ntBase + "\"";
+        sql = "SELECT myvalue FROM " + ntBase + " WHERE myvalue IS NOT NULL";
         q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         result = q.execute();
         checkResult(result, 2);
@@ -65,26 +65,26 @@
 
         testRootNode.save();
 
-        String sql = "SELECT myvalue FROM \"" + ntBase
-                + "\" WHERE \"jcr:path\" LIKE '" + testRoot + "/%'";
+        String sql = "SELECT myvalue FROM " + ntBase + " WHERE " +
+                "jcr:path LIKE '" + testRoot + "/%' AND myvalue IS NOT NULL";
         Query q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         QueryResult result = q.execute();
         checkResult(result, 2, 2);
 
-        sql = "SELECT myvalue FROM \"" + ntBase
-                + "\" WHERE \"jcr:path\" LIKE '" + testRoot + "/%'"
-                + " AND yourvalue = 'foo'";
+        sql = "SELECT myvalue FROM " + ntBase
+                + " WHERE jcr:path LIKE '" + testRoot + "/%'"
+                + " AND yourvalue = 'foo' AND myvalue IS NOT NULL";
         q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         result = q.execute();
         checkResult(result, 0, 0);
 
-        sql = "SELECT myvalue FROM \"" + ntBase + "\"";
+        sql = "SELECT myvalue FROM " + ntBase + " WHERE myvalue IS NOT NULL";
         q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         result = q.execute();
         checkResult(result, 2, 2);
 
-        sql = "SELECT * FROM \"" + ntBase
-                + "\" WHERE \"jcr:path\" LIKE '" + testRoot + "/%'"
+        sql = "SELECT * FROM " + ntBase
+                + " WHERE jcr:path LIKE '" + testRoot + "/%'"
                 + " AND myvalue LIKE '%'";
         q = superuser.getWorkspace().getQueryManager().createQuery(sql, Query.SQL);
         result = q.execute();
@@ -101,8 +101,8 @@
 
         testRootNode.save();
 
-        String sql = "SELECT myvalue FROM \"" + ntBase
-                + "\" WHERE \"jcr:path\" LIKE '" + testRoot + "/node'";
+        String sql = "SELECT myvalue FROM " + ntBase + " WHERE " +
+                "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);