You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2010/11/28 16:03:57 UTC
svn commit: r1039888 - in
/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query:
./ lucene/ lucene/join/
Author: jukka
Date: Sun Nov 28 15:03:57 2010
New Revision: 1039888
URL: http://svn.apache.org/viewvc?rev=1039888&view=rev
Log:
JCR-2715: Improved join query performance
Fix all remaining TCK test failures with the new QOM/SQL2 implementation
and enable it for all QOM/SQL2 queries
Removed:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/ExecutableQuery.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryHandler.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/JoinMerger.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/OperandEvaluator.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ValueComparator.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/ExecutableQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/ExecutableQuery.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/ExecutableQuery.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/ExecutableQuery.java Sun Nov 28 15:03:57 2010
@@ -16,10 +16,7 @@
*/
package org.apache.jackrabbit.core.query;
-import java.util.Map;
-
import javax.jcr.RepositoryException;
-import javax.jcr.Value;
import javax.jcr.query.QueryResult;
/**
@@ -39,22 +36,4 @@ public interface ExecutableQuery {
*/
QueryResult execute(long offset, long limit) throws RepositoryException;
- /**
- * Binds the given <code>value</code> to the variable named
- * <code>varName</code>.
- *
- * @param varName name of variable in query
- * @param value value to bind
- * @throws RepositoryException if <code>varName</code> is not a
- * valid variable in this query.
- */
- void bindValue(String varName, Value value) throws RepositoryException;
-
- /**
- * Returns the bind variables of this query.
- *
- * @return bind variables
- */
- Map<String, Value> getBindVariables();
-
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryHandler.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryHandler.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryHandler.java Sun Nov 28 15:03:57 2010
@@ -26,7 +26,6 @@ import org.apache.jackrabbit.core.fs.Fil
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.session.SessionContext;
import org.apache.jackrabbit.core.state.NodeState;
-import org.apache.jackrabbit.spi.commons.query.qom.QueryObjectModelTree;
/**
* Defines an interface for the actual node indexing and query execution.
@@ -112,20 +111,6 @@ public interface QueryHandler {
throws InvalidQueryException;
/**
- * Creates a new query by specifying the query object model. If the query
- * object model is considered invalid for the implementing class, an
- * InvalidQueryException is thrown.
- *
- * @param sessionContext component context of the current session
- * @param qomTree query query object model tree.
- * @return A <code>Query</code> object.
- * @throws InvalidQueryException if the query object model tree is invalid.
- */
- ExecutableQuery createExecutableQuery(
- SessionContext sessionContext, QueryObjectModelTree qomTree)
- throws InvalidQueryException;
-
- /**
* @return the name of the query class to use.
*/
String getQueryClass();
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java Sun Nov 28 15:03:57 2010
@@ -21,7 +21,6 @@ import static org.apache.jackrabbit.spi.
import static org.apache.jackrabbit.spi.commons.name.NameConstants.NT_QUERY;
import java.text.NumberFormat;
-import java.util.Set;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
@@ -97,7 +96,7 @@ public class QueryImpl extends AbstractQ
/**
* The offset in the total result set
*/
- protected long offset;
+ protected long offset = 0;
/**
* @inheritDoc
@@ -210,29 +209,19 @@ public class QueryImpl extends AbstractQ
/**
* {@inheritDoc}
*/
- public String[] getBindVariableNames() throws RepositoryException {
- Set<String> names = query.getBindVariables().keySet();
- return names.toArray(new String[names.size()]);
+ public String[] getBindVariableNames() {
+ return new String[0];
}
/**
- * Binds the given <code>value</code> to the variable named
- * <code>varName</code>.
+ * Throws an {@link IllegalArgumentException} as XPath and SQL1 queries
+ * have no bind variables.
*
- * @param varName name of variable in query
- * @param value value to bind
- * @throws IllegalArgumentException if <code>varName</code> is not a
- * valid variable in this query.
- * @throws javax.jcr.RepositoryException if an error occurs.
+ * @throws IllegalArgumentException always thrown
*/
public void bindValue(String varName, Value value)
- throws IllegalArgumentException, RepositoryException {
- checkInitialized();
- try {
- query.bindValue(varName, value);
- } catch (NameException e) {
- throw new RepositoryException(e.getMessage());
- }
+ throws IllegalArgumentException {
+ throw new IllegalArgumentException("No such bind variable: " + varName);
}
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java Sun Nov 28 15:03:57 2010
@@ -16,8 +16,6 @@
*/
package org.apache.jackrabbit.core.query;
-import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_INNER;
-
import java.util.HashMap;
import java.util.Map;
@@ -28,17 +26,17 @@ import javax.jcr.query.InvalidQueryExcep
import javax.jcr.query.QueryResult;
import javax.jcr.query.qom.Column;
import javax.jcr.query.qom.Constraint;
-import javax.jcr.query.qom.EquiJoinCondition;
-import javax.jcr.query.qom.Join;
import javax.jcr.query.qom.Ordering;
import javax.jcr.query.qom.QueryObjectModel;
-import javax.jcr.query.qom.QueryObjectModelConstants;
import javax.jcr.query.qom.Source;
import org.apache.jackrabbit.commons.query.QueryObjectModelBuilderRegistry;
+import org.apache.jackrabbit.core.query.lucene.LuceneQueryFactory;
+import org.apache.jackrabbit.core.query.lucene.SearchIndex;
import org.apache.jackrabbit.core.query.lucene.join.QueryEngine;
import org.apache.jackrabbit.core.session.SessionContext;
-import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.query.qom.BindVariableValueImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.DefaultTraversingQOMTreeVisitor;
import org.apache.jackrabbit.spi.commons.query.qom.QueryObjectModelTree;
/**
@@ -51,6 +49,11 @@ public class QueryObjectModelImpl extend
*/
protected QueryObjectModelTree qomTree;
+ /** Bind variables */
+ private final Map<String, Value> variables = new HashMap<String, Value>();
+
+ private LuceneQueryFactory lqf;
+
/**
* {@inheritDoc}
* @throws UnsupportedOperationException always.
@@ -88,24 +91,46 @@ public class QueryObjectModelImpl extend
this.qomTree = qomTree;
this.node = node;
this.statement = QueryObjectModelBuilderRegistry.getQueryObjectModelBuilder(language).toString(this);
- this.query = handler.createExecutableQuery(sessionContext, qomTree);
+
+ try {
+ qomTree.accept(new DefaultTraversingQOMTreeVisitor() {
+ @Override
+ public Object visit(BindVariableValueImpl node, Object data) {
+ variables.put(node.getBindVariableName(), null);
+ return data;
+ }
+ }, null);
+ } catch (Exception ignore) {
+ }
+ this.lqf = new LuceneQueryFactory(
+ sessionContext.getSessionImpl(), (SearchIndex) handler,
+ variables);
setInitialized();
}
public QueryResult execute() throws RepositoryException {
- Source source = getSource();
- if (source instanceof Join) {
- Join join = (Join) source;
- if (JCR_JOIN_TYPE_INNER.equals(join.getJoinType())
- && join.getJoinCondition() instanceof EquiJoinCondition) {
- QueryEngine engine =
- new QueryEngine(sessionContext.getSessionImpl(), query.getBindVariables());
- return engine.execute(
- getColumns(), getSource(), getConstraint(),
- getOrderings(), offset, limit);
- }
+ QueryEngine engine = new QueryEngine(
+ sessionContext.getSessionImpl(), lqf, variables);
+ return engine.execute(
+ getColumns(), getSource(), getConstraint(),
+ getOrderings(), offset, limit);
+ }
+
+
+ @Override
+ public String[] getBindVariableNames() {
+ return variables.keySet().toArray(new String[variables.size()]);
+ }
+
+ @Override
+ public void bindValue(String varName, Value value)
+ throws IllegalArgumentException {
+ if (variables.containsKey(varName)) {
+ variables.put(varName, value);
+ } else {
+ throw new IllegalArgumentException(
+ "No such bind variable: " + varName);
}
- return super.execute();
}
//-------------------------< QueryObjectModel >-----------------------------
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java Sun Nov 28 15:03:57 2010
@@ -16,10 +16,7 @@
*/
package org.apache.jackrabbit.core.query.lucene;
-import java.util.Map;
-
import javax.jcr.RepositoryException;
-import javax.jcr.Value;
import javax.jcr.Workspace;
import javax.jcr.query.qom.QueryObjectModelFactory;
@@ -54,10 +51,6 @@ public abstract class AbstractQueryImpl
*/
private boolean documentOrder = true;
- /** Bind variables of this query */
- private final Map<String, Value> variables;
-
-
/**
* Creates a new query instance from a query string.
*
@@ -67,11 +60,10 @@ public abstract class AbstractQueryImpl
*/
public AbstractQueryImpl(
SessionContext sessionContext, SearchIndex index,
- PropertyTypeRegistry propReg, Map<String, Value> variables) {
+ PropertyTypeRegistry propReg) {
this.sessionContext = sessionContext;
this.index = index;
this.propReg = propReg;
- this.variables = variables;
}
/**
@@ -102,33 +94,6 @@ public abstract class AbstractQueryImpl
}
/**
- * Binds the given <code>value</code> to the variable named
- * <code>varName</code>.
- *
- * @param varName name of variable in query
- * @param value value to bind
- * @throws IllegalArgumentException if <code>varName</code> is not a valid
- * variable in this query.
- * @throws RepositoryException if an error occurs.
- */
- public void bindValue(String varName, Value value)
- throws IllegalArgumentException, RepositoryException {
- if (variables.containsKey(varName)) {
- variables.put(varName, value);
- } else {
- throw new IllegalArgumentException(
- varName + " is not a valid variable in this query");
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public Map<String, Value> getBindVariables() {
- return variables;
- }
-
- /**
* @return the query object model factory.
* @throws RepositoryException if an error occurs.
*/
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java Sun Nov 28 15:03:57 2010
@@ -17,9 +17,11 @@
package org.apache.jackrabbit.core.query.lucene;
import static javax.jcr.PropertyType.DATE;
+import static javax.jcr.PropertyType.DECIMAL;
import static javax.jcr.PropertyType.DOUBLE;
import static javax.jcr.PropertyType.LONG;
import static javax.jcr.PropertyType.NAME;
+import static javax.jcr.PropertyType.PATH;
import static javax.jcr.PropertyType.STRING;
import static javax.jcr.PropertyType.UNDEFINED;
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO;
@@ -29,24 +31,41 @@ import static javax.jcr.query.qom.QueryO
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO;
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LIKE;
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_NOT_EQUAL_TO;
+import static org.apache.jackrabbit.core.query.lucene.FieldNames.LOCAL_NAME;
+import static org.apache.jackrabbit.core.query.lucene.FieldNames.MVP;
+import static org.apache.jackrabbit.core.query.lucene.FieldNames.NAMESPACE_URI;
+import static org.apache.jackrabbit.core.query.lucene.FieldNames.PARENT;
import static org.apache.jackrabbit.core.query.lucene.FieldNames.PROPERTIES;
+import static org.apache.jackrabbit.core.query.lucene.FieldNames.UUID;
+import static org.apache.jackrabbit.core.query.lucene.TransformConstants.TRANSFORM_LOWER_CASE;
+import static org.apache.jackrabbit.core.query.lucene.TransformConstants.TRANSFORM_NONE;
+import static org.apache.jackrabbit.core.query.lucene.TransformConstants.TRANSFORM_UPPER_CASE;
import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_MIXINTYPES;
import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_PRIMARYTYPE;
import static org.apache.lucene.search.BooleanClause.Occur.MUST;
+import static org.apache.lucene.search.BooleanClause.Occur.MUST_NOT;
import static org.apache.lucene.search.BooleanClause.Occur.SHOULD;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeIterator;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.query.InvalidQueryException;
+import javax.jcr.query.Row;
import javax.jcr.query.qom.And;
import javax.jcr.query.qom.ChildNode;
import javax.jcr.query.qom.Comparison;
@@ -54,26 +73,35 @@ import javax.jcr.query.qom.Constraint;
import javax.jcr.query.qom.DescendantNode;
import javax.jcr.query.qom.DynamicOperand;
import javax.jcr.query.qom.FullTextSearch;
+import javax.jcr.query.qom.FullTextSearchScore;
+import javax.jcr.query.qom.Length;
+import javax.jcr.query.qom.LowerCase;
+import javax.jcr.query.qom.NodeLocalName;
+import javax.jcr.query.qom.NodeName;
import javax.jcr.query.qom.Not;
import javax.jcr.query.qom.Or;
import javax.jcr.query.qom.PropertyExistence;
import javax.jcr.query.qom.PropertyValue;
import javax.jcr.query.qom.SameNode;
+import javax.jcr.query.qom.Selector;
import javax.jcr.query.qom.StaticOperand;
+import javax.jcr.query.qom.UpperCase;
-import org.apache.jackrabbit.core.HierarchyManager;
+import org.apache.jackrabbit.commons.predicate.Predicate;
+import org.apache.jackrabbit.commons.predicate.Predicates;
+import org.apache.jackrabbit.commons.predicate.RowPredicate;
+import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.query.lucene.join.OperandEvaluator;
+import org.apache.jackrabbit.core.query.lucene.join.SelectorRow;
+import org.apache.jackrabbit.core.query.lucene.join.ValueComparator;
import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
-import org.apache.jackrabbit.spi.commons.query.qom.DefaultQOMTreeVisitor;
import org.apache.jackrabbit.spi.commons.query.qom.FullTextSearchImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.JoinConditionImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.JoinImpl;
import org.apache.jackrabbit.spi.commons.query.qom.PropertyExistenceImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.SelectorImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.SourceImpl;
-import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
@@ -96,10 +124,8 @@ public class LuceneQueryFactory {
*/
private final NodeTypeManager ntManager;
- /**
- * The hierarchy manager.
- */
- private final HierarchyManager hmgr;
+ /** Lucene search index */
+ private final SearchIndex index;
/**
* Namespace mappings to internal prefixes
@@ -111,21 +137,6 @@ public class LuceneQueryFactory {
*/
private final NamePathResolver npResolver;
- /**
- * The analyzer instance to use for contains function query parsing
- */
- private final Analyzer analyzer;
-
- /**
- * The synonym provider or <code>null</code> if none is configured.
- */
- private final SynonymProvider synonymProvider;
-
- /**
- * The index format version.
- */
- private final IndexFormatVersion version;
-
/** Operand evaluator */
private final OperandEvaluator evaluator;
@@ -137,26 +148,16 @@ public class LuceneQueryFactory {
* Creates a new lucene query factory.
*
* @param session the session that executes the query.
- * @param scs the sort comparator source of the index.
- * @param hmgr the hierarchy manager of the workspace.
- * @param nsMappings the index internal namespace mappings.
- * @param analyzer the analyzer of the index.
- * @param synonymProvider the synonym provider of the index.
- * @param version the version of the index format.
+ * @param index the search index
* @param bindVariables the bind variable values of the query
*/
public LuceneQueryFactory(
- SessionImpl session, HierarchyManager hmgr,
- NamespaceMappings nsMappings, Analyzer analyzer,
- SynonymProvider synonymProvider, IndexFormatVersion version,
+ SessionImpl session, SearchIndex index,
Map<String, Value> bindVariables) throws RepositoryException {
this.session = session;
this.ntManager = session.getWorkspace().getNodeTypeManager();
- this.hmgr = hmgr;
- this.nsMappings = nsMappings;
- this.analyzer = analyzer;
- this.synonymProvider = synonymProvider;
- this.version = version;
+ this.index = index;
+ this.nsMappings = index.getNamespaceMappings();
this.npResolver = NamePathResolverImpl.create(nsMappings);
this.evaluator =
new OperandEvaluator(session.getValueFactory(), bindVariables);
@@ -164,6 +165,51 @@ public class LuceneQueryFactory {
this.primaryTypeField = nsMappings.translateName(JCR_PRIMARYTYPE);
}
+ public List<Row> execute(
+ Map<String, PropertyValue> columns, Selector selector,
+ Constraint constraint) throws RepositoryException, IOException {
+ final IndexReader reader = index.getIndexReader(true);
+ try {
+ JackrabbitIndexSearcher searcher = new JackrabbitIndexSearcher(
+ session, reader, index.getContext().getItemStateManager());
+ searcher.setSimilarity(index.getSimilarity());
+
+ Predicate filter = Predicate.TRUE;
+ BooleanQuery query = new BooleanQuery();
+ query.add(create(selector), MUST);
+ if (constraint != null) {
+ String name = selector.getSelectorName();
+ NodeType type =
+ ntManager.getNodeType(selector.getNodeTypeName());
+ filter = mapConstraintToQueryAndFilter(
+ query, constraint, Collections.singletonMap(name, type),
+ searcher, reader);
+ }
+
+ List<Row> rows = new ArrayList<Row>();
+ QueryHits hits = searcher.evaluate(query);
+ ScoreNode node = hits.nextScoreNode();
+ while (node != null) {
+ try {
+ Row row = new SelectorRow(
+ columns, evaluator, selector.getSelectorName(),
+ session.getNodeById(node.getNodeId()),
+ node.getScore());
+ if (filter.evaluate(row)) {
+ rows.add(row);
+ }
+ } catch (ItemNotFoundException e) {
+ // skip the node
+ }
+ node = hits.nextScoreNode();
+ }
+ return rows;
+ } finally {
+ PerQueryCache.getInstance().dispose();
+ Util.closeOrRelease(reader);
+ }
+ }
+
/**
* Creates a lucene query for the given QOM selector.
*
@@ -171,7 +217,7 @@ public class LuceneQueryFactory {
* @return a lucene query for the given selector.
* @throws RepositoryException if an error occurs while creating the query.
*/
- public Query create(SelectorImpl selector) throws RepositoryException {
+ public Query create(Selector selector) throws RepositoryException {
List<Term> terms = new ArrayList<Term>();
String name = selector.getNodeTypeName();
@@ -229,7 +275,7 @@ public class LuceneQueryFactory {
fieldname = tmp.toString();
}
QueryParser parser = new JackrabbitQueryParser(
- fieldname, analyzer, synonymProvider);
+ fieldname, index.getTextAnalyzer(), index.getSynonymProvider());
try {
StaticOperand expr = fts.getFullTextSearchExpression();
return parser.parse(evaluator.getValue(expr).getString());
@@ -247,168 +293,377 @@ public class LuceneQueryFactory {
*/
public Query create(PropertyExistenceImpl prop) throws RepositoryException {
String propName = npResolver.getJCRName(prop.getPropertyQName());
- return Util.createMatchAllQuery(propName, version);
+ return Util.createMatchAllQuery(propName, index.getIndexFormatVersion());
}
- /**
- * Creates a multi column query for the given QOM source.
- *
- * @param source the QOM source.
- * @return a multi column query for the given source.
- * @throws RepositoryException if an error occurs while creating the query.
- */
- public MultiColumnQuery create(SourceImpl source) throws RepositoryException {
- // source is either selector or join
- try {
- return (MultiColumnQuery) source.accept(new DefaultQOMTreeVisitor() {
- public Object visit(JoinImpl node, Object data) throws Exception {
- return create(node);
- }
-
- public Object visit(SelectorImpl node, Object data) throws Exception {
- return MultiColumnQueryAdapter.adapt(
- create(node), node.getSelectorQName());
+ private Predicate mapConstraintToQueryAndFilter(
+ BooleanQuery query, Constraint constraint,
+ Map<String, NodeType> selectorMap,
+ JackrabbitIndexSearcher searcher, IndexReader reader)
+ throws RepositoryException, IOException {
+ Predicate filter = Predicate.TRUE;
+ if (constraint instanceof And) {
+ And and = (And) constraint;
+ filter = mapConstraintToQueryAndFilter(
+ query, and.getConstraint1(), selectorMap, searcher, reader);
+ Predicate other = mapConstraintToQueryAndFilter(
+ query, and.getConstraint2(), selectorMap, searcher, reader);
+ if (filter == Predicate.TRUE) {
+ filter = other;
+ } else if (other != Predicate.TRUE) {
+ filter = Predicates.and(filter, other);
+ }
+ } else if (constraint instanceof Comparison) {
+ Comparison c = (Comparison) constraint;
+ Transform transform = new Transform(c.getOperand1());
+ DynamicOperand left = transform.operand;
+ final String operator = c.getOperator();
+ StaticOperand right = c.getOperand2();
+ if (left instanceof Length
+ || left instanceof FullTextSearchScore
+ || ((!JCR_OPERATOR_EQUAL_TO.equals(operator)
+ || transform.transform != TRANSFORM_NONE)
+ && (left instanceof NodeName
+ || left instanceof NodeLocalName))) {
+ try {
+ int type = PropertyType.UNDEFINED;
+ if (left instanceof Length) {
+ type = PropertyType.LONG;
+ } else if (left instanceof FullTextSearchScore) {
+ type = PropertyType.DOUBLE;
+ }
+ final DynamicOperand operand = c.getOperand1();
+ final Value value = evaluator.getValue(right, type);
+ filter = new RowPredicate() {
+ @Override
+ protected boolean evaluate(Row row)
+ throws RepositoryException {
+ return new ValueComparator().evaluate(
+ operator,
+ evaluator.getValue(operand, row), value);
+ }
+ };
+ } catch (ValueFormatException e) {
+ throw new InvalidQueryException(e);
}
- }, null);
- } catch (RepositoryException e) {
- throw e;
- } catch (Exception e) {
- throw new RepositoryException(e);
+ } else {
+ Query cq = getComparisonQuery(
+ left, transform.transform, operator, right, selectorMap);
+ query.add(cq, MUST);
+ }
+ } else {
+ query.add(create(constraint, selectorMap, searcher), MUST);
}
+ return filter;
}
- /**
- * Creates a multi column query for the given QOM join.
- *
- * @param join the QOM join.
- * @return the multi column query for the given join.
- * @throws RepositoryException if an error occurs while creating the query.
- */
- public MultiColumnQuery create(JoinImpl join) throws RepositoryException {
- MultiColumnQuery left = create((SourceImpl) join.getLeft());
- MultiColumnQuery right = create((SourceImpl) join.getRight());
- return new JoinQuery(left, right, join.getJoinTypeInstance(),
- (JoinConditionImpl) join.getJoinCondition(), nsMappings, hmgr);
- }
-
- public Query create(
- Constraint constraint, Map<String, NodeType> selectorMap)
- throws RepositoryException {
+ private Query create(
+ Constraint constraint, Map<String, NodeType> selectorMap,
+ JackrabbitIndexSearcher searcher)
+ throws RepositoryException, IOException {
if (constraint instanceof And) {
- return getAndQuery((And) constraint, selectorMap);
+ return getAndQuery((And) constraint, selectorMap, searcher);
} else if (constraint instanceof Or) {
- return getOrQuery((Or) constraint, selectorMap);
+ return getOrQuery((Or) constraint, selectorMap, searcher);
} else if (constraint instanceof Not) {
- return getNotQuery((Not) constraint, selectorMap);
+ return getNotQuery((Not) constraint, selectorMap, searcher);
} else if (constraint instanceof PropertyExistence) {
return getPropertyExistenceQuery((PropertyExistence) constraint);
} else if (constraint instanceof Comparison) {
- return getComparisonQuery((Comparison) constraint, selectorMap);
+ Comparison c = (Comparison) constraint;
+ Transform left = new Transform(c.getOperand1());
+ return getComparisonQuery(
+ left.operand, left.transform, c.getOperator(),
+ c.getOperand2(), selectorMap);
} else if (constraint instanceof FullTextSearch) {
- return null; // FIXME
+ return getFullTextSearchQuery((FullTextSearch) constraint);
} else if (constraint instanceof SameNode) {
- return null; // FIXME
+ SameNode sn = (SameNode) constraint;
+ return getNodeIdQuery(UUID, sn.getPath());
} else if (constraint instanceof ChildNode) {
- return null; // FIXME
+ ChildNode cn = (ChildNode) constraint;
+ return getNodeIdQuery(PARENT, cn.getParentPath());
} else if (constraint instanceof DescendantNode) {
- return null; // FIXME
+ DescendantNode dn = (DescendantNode) constraint;
+ return getDescendantNodeQuery(dn, searcher);
} else {
throw new UnsupportedRepositoryOperationException(
"Unknown constraint type: " + constraint);
}
}
- private BooleanQuery getAndQuery(
- And and, Map<String, NodeType> selectorMap)
- throws RepositoryException {
+ private Query getDescendantNodeQuery(
+ DescendantNode dn, JackrabbitIndexSearcher searcher)
+ throws RepositoryException, IOException {
BooleanQuery query = new BooleanQuery();
- addBooleanConstraint(query, and.getConstraint1(), MUST, selectorMap);
- addBooleanConstraint(query, and.getConstraint2(), MUST, selectorMap);
+
+ try {
+ LinkedList<NodeId> ids = new LinkedList<NodeId>();
+ NodeImpl ancestor = (NodeImpl) session.getNode(dn.getAncestorPath());
+ ids.add(ancestor.getNodeId());
+ while (!ids.isEmpty()) {
+ String id = ids.removeFirst().toString();
+ Query q = new JackrabbitTermQuery(new Term(FieldNames.PARENT, id));
+ QueryHits hits = searcher.evaluate(q);
+ ScoreNode sn = hits.nextScoreNode();
+ if (sn != null) {
+ query.add(q, SHOULD);
+ do {
+ ids.add(sn.getNodeId());
+ sn = hits.nextScoreNode();
+ } while (sn != null);
+ }
+ }
+ } catch (PathNotFoundException e) {
+ query.add(new JackrabbitTermQuery(new Term(
+ FieldNames.UUID, "invalid-node-id")), // never matches
+ SHOULD);
+ }
+
return query;
}
- private BooleanQuery getOrQuery(Or or, Map<String, NodeType> selectorMap)
+ private Query getFullTextSearchQuery(FullTextSearch fts)
throws RepositoryException {
+ String field = FieldNames.FULLTEXT;
+ String property = fts.getPropertyName();
+ if (property != null) {
+ Name name = session.getQName(property);
+ field = nsMappings.getPrefix(name.getNamespaceURI()) + ":"
+ + FieldNames.FULLTEXT_PREFIX + name.getLocalName();
+ }
+
+ StaticOperand expression = fts.getFullTextSearchExpression();
+ String query = evaluator.getValue(expression).getString();
+ try {
+ QueryParser parser = new JackrabbitQueryParser(
+ field, index.getTextAnalyzer(), index.getSynonymProvider());
+ return parser.parse(query);
+ } catch (ParseException e) {
+ throw new RepositoryException(
+ "Invalid full text search expression: " + query, e);
+ }
+ }
+
+ private BooleanQuery getAndQuery(
+ And and, Map<String, NodeType> selectorMap,
+ JackrabbitIndexSearcher searcher)
+ throws RepositoryException, IOException {
+ BooleanQuery query = new BooleanQuery();
+ addBooleanConstraint(
+ query, and.getConstraint1(), MUST, selectorMap, searcher);
+ addBooleanConstraint(
+ query, and.getConstraint2(), MUST, selectorMap, searcher);
+ return query;
+ }
+
+ private BooleanQuery getOrQuery(
+ Or or, Map<String, NodeType> selectorMap,
+ JackrabbitIndexSearcher searcher)
+ throws RepositoryException, IOException {
BooleanQuery query = new BooleanQuery();
- addBooleanConstraint(query, or.getConstraint1(), SHOULD, selectorMap);
- addBooleanConstraint(query, or.getConstraint2(), SHOULD, selectorMap);
+ addBooleanConstraint(
+ query, or.getConstraint1(), SHOULD, selectorMap, searcher);
+ addBooleanConstraint(
+ query, or.getConstraint2(), SHOULD, selectorMap, searcher);
return query;
}
private void addBooleanConstraint(
BooleanQuery query, Constraint constraint, Occur occur,
- Map<String, NodeType> selectorMap) throws RepositoryException {
+ Map<String, NodeType> selectorMap, JackrabbitIndexSearcher searcher)
+ throws RepositoryException, IOException {
if (occur == MUST && constraint instanceof And) {
And and = (And) constraint;
- addBooleanConstraint(query, and.getConstraint1(), occur, selectorMap);
- addBooleanConstraint(query, and.getConstraint2(), occur, selectorMap);
+ addBooleanConstraint(
+ query, and.getConstraint1(), occur, selectorMap, searcher);
+ addBooleanConstraint(
+ query, and.getConstraint2(), occur, selectorMap, searcher);
} else if (occur == SHOULD && constraint instanceof Or) {
Or or = (Or) constraint;
- addBooleanConstraint(query, or.getConstraint1(), occur, selectorMap);
- addBooleanConstraint(query, or.getConstraint2(), occur, selectorMap);
+ addBooleanConstraint(
+ query, or.getConstraint1(), occur, selectorMap, searcher);
+ addBooleanConstraint(
+ query, or.getConstraint2(), occur, selectorMap, searcher);
} else {
- query.add(create(constraint, selectorMap), occur);
+ query.add(create(constraint, selectorMap, searcher), occur);
}
}
- private NotQuery getNotQuery(Not not, Map<String, NodeType> selectorMap)
- throws RepositoryException {
- return new NotQuery(create(not.getConstraint(), selectorMap));
+ private NotQuery getNotQuery(
+ Not not, Map<String, NodeType> selectorMap,
+ JackrabbitIndexSearcher searcher)
+ throws RepositoryException, IOException {
+ return new NotQuery(create(not.getConstraint(), selectorMap, searcher));
}
private Query getPropertyExistenceQuery(PropertyExistence property)
throws RepositoryException {
String name = npResolver.getJCRName(session.getQName(
property.getPropertyName()));
- return Util.createMatchAllQuery(name, version);
+ return Util.createMatchAllQuery(name, index.getIndexFormatVersion());
+ }
+
+ private static class Transform {
+
+ private final DynamicOperand operand;
+
+ private final int transform;
+
+ public Transform(DynamicOperand operand) {
+ // Check the transformation type
+ if (operand instanceof UpperCase) {
+ this.transform = TRANSFORM_UPPER_CASE;
+ } else if (operand instanceof LowerCase) {
+ this.transform = TRANSFORM_LOWER_CASE;
+ } else {
+ this.transform = TRANSFORM_NONE;
+ }
+
+ // Unwrap any nested transformations
+ while (true) {
+ if (operand instanceof UpperCase) {
+ operand = ((UpperCase) operand).getOperand();
+ } else if (operand instanceof LowerCase) {
+ operand = ((LowerCase) operand).getOperand();
+ } else {
+ break;
+ }
+ }
+ this.operand = operand;
+ }
}
private Query getComparisonQuery(
- Comparison comparison, Map<String, NodeType> selectorMap)
+ DynamicOperand left, int transform, String operator,
+ StaticOperand rigth, Map<String, NodeType> selectorMap)
throws RepositoryException {
- DynamicOperand operand = comparison.getOperand1();
- if (operand instanceof PropertyValue) {
- PropertyValue property = (PropertyValue) operand;
+ if (left instanceof PropertyValue) {
+ PropertyValue pv = (PropertyValue) left;
String field = npResolver.getJCRName(session.getQName(
- property.getPropertyName()));
+ pv.getPropertyName()));
int type = PropertyType.UNDEFINED;
- NodeType nt = selectorMap.get(property.getSelectorName());
+ NodeType nt = selectorMap.get(pv.getSelectorName());
if (nt != null) {
for (PropertyDefinition pd : nt.getPropertyDefinitions()) {
- if (pd.getName().equals(property.getPropertyName())) {
+ if (pd.getName().equals(pv.getPropertyName())) {
type = pd.getRequiredType();
}
}
}
return getPropertyValueQuery(
- field, comparison.getOperator(),
- evaluator.getValue(comparison.getOperand2()), type);
+ field, operator, evaluator.getValue(rigth), type, transform);
+ } else if (left instanceof NodeName) {
+ return getNodeNameQuery(transform, operator, rigth);
+ } else if (left instanceof NodeLocalName) {
+ return getNodeLocalNameQuery(transform, operator, rigth);
} else {
- throw new UnsupportedRepositoryOperationException(); // FIXME
+ throw new UnsupportedRepositoryOperationException(
+ "Unknown operand type: " + left); // FIXME
}
}
- private Query getPropertyValueQuery(
- String field, String operator, Value value, int type)
+ private Query getNodeNameQuery(
+ int transform, String operator, StaticOperand right)
throws RepositoryException {
- Term term = getTerm(field, getValueString(value, type));
+ if (transform != TRANSFORM_NONE
+ || !JCR_OPERATOR_EQUAL_TO.equals(operator)) {
+ throw new UnsupportedRepositoryOperationException();
+ }
+
+ Value value = evaluator.getValue(right);
+ int type = value.getType();
+ String string = value.getString();
+ if (type == PropertyType.URI && string.startsWith("./")) {
+ string = string.substring("./".length());
+ } else if (type == PropertyType.DOUBLE
+ || type == PropertyType.DECIMAL
+ || type == PropertyType.LONG
+ || type == PropertyType.BOOLEAN
+ || type == PropertyType.REFERENCE
+ || type == PropertyType.WEAKREFERENCE) {
+ throw new InvalidQueryException("Invalid name value: " + string);
+ }
+
+ try {
+ Name name = session.getQName(string);
+ Term uri = new Term(NAMESPACE_URI, name.getNamespaceURI());
+ Term local = new Term(LOCAL_NAME, name.getLocalName());
+
+ BooleanQuery query = new BooleanQuery();
+ query.add(new JackrabbitTermQuery(uri), MUST);
+ query.add(new JackrabbitTermQuery(local), MUST);
+ return query;
+ } catch (IllegalNameException e) {
+ throw new InvalidQueryException("Illegal name: " + string, e);
+ }
+ }
+
+ private Query getNodeLocalNameQuery(
+ int transform, String operator, StaticOperand right)
+ throws RepositoryException {
+ if (transform != TRANSFORM_NONE
+ || !JCR_OPERATOR_EQUAL_TO.equals(operator)) {
+ throw new UnsupportedRepositoryOperationException();
+ }
+
+ String name = evaluator.getValue(right).getString();
+ return new JackrabbitTermQuery(new Term(LOCAL_NAME, name));
+ }
+
+ private Query getNodeIdQuery(String field, String path)
+ throws RepositoryException {
+ String value;
+ try {
+ NodeImpl node = (NodeImpl) session.getNode(path);
+ value = node.getNodeId().toString();
+ } catch (PathNotFoundException e) {
+ value = "invalid-node-id"; // can never match a node
+ }
+ return new JackrabbitTermQuery(new Term(field, value));
+ }
+
+ private Query getPropertyValueQuery(
+ String field, String operator, Value value,
+ int type, int transform) throws RepositoryException {
+ String string = getValueString(value, type);
+ if (JCR_OPERATOR_LIKE.equals(operator)) {
+ return new WildcardQuery(PROPERTIES, field, string, transform);
+ }
+
+ Term term = getTerm(field, string);
if (JCR_OPERATOR_EQUAL_TO.equals(operator)) {
- return new JackrabbitTermQuery(term);
+ switch (transform) {
+ case TRANSFORM_UPPER_CASE:
+ return new CaseTermQuery.Upper(term);
+ case TRANSFORM_LOWER_CASE:
+ return new CaseTermQuery.Lower(term);
+ default:
+ return new JackrabbitTermQuery(term);
+ }
} else if (JCR_OPERATOR_GREATER_THAN.equals(operator)) {
- return new RangeQuery(term, getTerm(field, "\uFFFF"), false);
+ return new RangeQuery(term, getTerm(field, "\uFFFF"), false, transform);
} else if (JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO.equals(operator)) {
- return new RangeQuery(term, getTerm(field, "\uFFFF"), true);
+ return new RangeQuery(term, getTerm(field, "\uFFFF"), true, transform);
} else if (JCR_OPERATOR_LESS_THAN.equals(operator)) {
- return new RangeQuery(getTerm(field, ""), term, false);
+ return new RangeQuery(getTerm(field, ""), term, false, transform);
} else if (JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO.equals(operator)) {
- return new RangeQuery(getTerm(field, ""), term, true);
+ return new RangeQuery(getTerm(field, ""), term, true, transform);
} else if (JCR_OPERATOR_NOT_EQUAL_TO.equals(operator)) {
- BooleanQuery or = new BooleanQuery();
- or.add(new RangeQuery(getTerm(field, ""), term, false), SHOULD);
- or.add(new RangeQuery(term, getTerm(field, "\uFFFF"), false), SHOULD);
- return or;
- } else if (JCR_OPERATOR_LIKE.equals(operator)) {
- throw new UnsupportedRepositoryOperationException(); // FIXME
+ BooleanQuery query = new BooleanQuery();
+ query.add(Util.createMatchAllQuery(
+ field, index.getIndexFormatVersion()), SHOULD);
+ switch (transform) {
+ case TRANSFORM_UPPER_CASE:
+ query.add(new CaseTermQuery.Upper(term), MUST_NOT);
+ case TRANSFORM_LOWER_CASE:
+ query.add(new CaseTermQuery.Lower(term), MUST_NOT);
+ default:
+ query.add(new JackrabbitTermQuery(term), MUST_NOT);
+ }
+ // and exclude all nodes where 'field' is multi valued
+ query.add(new JackrabbitTermQuery(new Term(MVP, field)), MUST_NOT);
+ return query;
} else {
throw new UnsupportedRepositoryOperationException(); // FIXME
}
@@ -427,8 +682,12 @@ public class LuceneQueryFactory {
return DoubleField.doubleToString(value.getDouble());
case LONG:
return LongField.longToString(value.getLong());
+ case DECIMAL:
+ return DecimalField.decimalToString(value.getDecimal());
case NAME:
return npResolver.getJCRName(session.getQName(value.getString()));
+ case PATH:
+ return npResolver.getJCRPath(session.getQPath(value.getString()));
default:
String string = value.getString();
if (type != UNDEFINED && type != STRING) {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java Sun Nov 28 15:03:57 2010
@@ -88,8 +88,7 @@ public class QueryImpl extends AbstractQ
SessionContext sessionContext, SearchIndex index,
PropertyTypeRegistry propReg, String statement, String language,
QueryNodeFactory factory) throws InvalidQueryException {
- super(sessionContext, index, propReg,
- Collections.<String, Value>emptyMap());
+ super(sessionContext, index, propReg);
// parse query according to language
// build query tree using the passed factory
this.root = QueryParser.parse(
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java Sun Nov 28 15:03:57 2010
@@ -16,10 +16,9 @@
*/
package org.apache.jackrabbit.core.query.lucene;
-import java.io.InputStream;
-
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -39,7 +38,6 @@ import javax.xml.parsers.DocumentBuilder
import javax.xml.parsers.ParserConfigurationException;
import org.apache.jackrabbit.core.HierarchyManager;
-import org.apache.jackrabbit.core.ItemManager;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.fs.FileSystem;
import org.apache.jackrabbit.core.fs.FileSystemException;
@@ -60,12 +58,10 @@ import org.apache.jackrabbit.core.state.
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.PathFactory;
-import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
import org.apache.jackrabbit.spi.commons.name.NameConstants;
import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
import org.apache.jackrabbit.spi.commons.query.DefaultQueryNodeFactory;
import org.apache.jackrabbit.spi.commons.query.qom.OrderingImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.QueryObjectModelTree;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.document.Document;
@@ -683,28 +679,6 @@ public class SearchIndex extends Abstrac
}
/**
- * Creates a new query by specifying the query object model. If the query
- * object model is considered invalid for the implementing class, an
- * InvalidQueryException is thrown.
- *
- * @param sessionContext component context of the current session
- * @param qomTree query query object model tree.
- * @return A <code>Query</code> object.
- * @throws javax.jcr.query.InvalidQueryException
- * if the query object model tree is invalid.
- * @see QueryHandler#createExecutableQuery(SessionImpl, ItemManager, QueryObjectModelTree)
- */
- public ExecutableQuery createExecutableQuery(
- SessionContext sessionContext, QueryObjectModelTree qomTree)
- throws InvalidQueryException {
- QueryObjectModelImpl query = new QueryObjectModelImpl(
- sessionContext, this, getContext().getPropertyTypeRegistry(),
- qomTree);
- query.setRespectDocumentOrder(documentOrder);
- return query;
- }
-
- /**
* {@inheritDoc}
*/
public Iterable<NodeId> getWeaklyReferringNodes(NodeId id)
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/JoinMerger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/JoinMerger.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/JoinMerger.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/JoinMerger.java Sun Nov 28 15:03:57 2010
@@ -17,7 +17,6 @@
package org.apache.jackrabbit.core.query.lucene.join;
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_LEFT_OUTER;
-import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_RIGHT_OUTER;
import java.util.ArrayList;
import java.util.Collections;
@@ -163,93 +162,47 @@ abstract class JoinMerger {
public QueryResult merge(RowIterator leftRows, RowIterator rightRows)
throws RepositoryException {
RowIterator joinRows;
- if (JCR_JOIN_TYPE_RIGHT_OUTER.equals(type)) {
- Map<String, List<Row>> map = new HashMap<String, List<Row>>();
- for (Row row : new RowIterable(leftRows)) {
- for (String value : getLeftValues(row)) {
- List<Row> rows = map.get(value);
- if (rows == null) {
- rows = new ArrayList<Row>();
- map.put(value, rows);
- }
- rows.add(row);
- }
- }
- joinRows = mergeRight(map, rightRows);
- } else {
- Map<String, List<Row>> map = new HashMap<String, List<Row>>();
- for (Row row : new RowIterable(rightRows)) {
- for (String value : getRightValues(row)) {
- List<Row> rows = map.get(value);
- if (rows == null) {
- rows = new ArrayList<Row>();
- map.put(value, rows);
- }
- rows.add(row);
+
+ Map<String, List<Row>> map = new HashMap<String, List<Row>>();
+ for (Row row : new RowIterable(rightRows)) {
+ for (String value : getRightValues(row)) {
+ List<Row> rows = map.get(value);
+ if (rows == null) {
+ rows = new ArrayList<Row>();
+ map.put(value, rows);
}
+ rows.add(row);
}
- boolean outer = JCR_JOIN_TYPE_LEFT_OUTER.equals(type);
- joinRows = mergeLeft(leftRows, map, outer);
}
- return new SimpleQueryResult(columnNames, selectorNames, joinRows);
- }
- private RowIterator mergeLeft(
- RowIterator leftRows, Map<String, List<Row>> rightRowMap,
- boolean outer) throws RepositoryException {
- if (!rightRowMap.isEmpty()) {
+ if (!map.isEmpty()) {
List<Row> rows = new ArrayList<Row>();
for (Row leftRow : new RowIterable(leftRows)) {
for (String value : getLeftValues(leftRow)) {
- List<Row> rightRows = rightRowMap.get(value);
- if (rightRows != null) {
- for (Row rightRow : rightRows) {
+ List<Row> matchingRows = map.get(value);
+ if (matchingRows != null) {
+ for (Row rightRow : matchingRows) {
rows.add(mergeRow(leftRow, rightRow));
}
- } else if (outer) {
+ } else if (JCR_JOIN_TYPE_LEFT_OUTER.equals(type)) {
+ // No matches in an outer join -> add a null row
rows.add(mergeRow(leftRow, null));
}
}
}
- return new RowIteratorAdapter(rows);
- } else if (outer) {
- return new RowIteratorAdapter(leftRows) {
+ joinRows = new RowIteratorAdapter(rows);
+ } else if (JCR_JOIN_TYPE_LEFT_OUTER.equals(type)) {
+ joinRows = new RowIteratorAdapter(leftRows) {
@Override
public Object next() {
return mergeRow((Row) super.next(), null);
}
};
} else {
- return new RowIteratorAdapter(Collections.emptySet());
+ joinRows = new RowIteratorAdapter(Collections.emptySet());
}
- }
- private RowIterator mergeRight(
- Map<String, List<Row>> leftRowMap, RowIterator rightRows)
- throws RepositoryException {
- if (leftRowMap.isEmpty()) {
- List<Row> rows = new ArrayList<Row>();
- for (Row rightRow : new RowIterable(rightRows)) {
- for (String value : getRightValues(rightRow)) {
- List<Row> leftRows = leftRowMap.get(value);
- if (leftRows != null) {
- for (Row leftRow : leftRows) {
- rows.add(mergeRow(leftRow, rightRow));
- }
- } else {
- rows.add(mergeRow(null, rightRow));
- }
- }
- }
- return new RowIteratorAdapter(rows);
- } else {
- return new RowIteratorAdapter(rightRows) {
- @Override
- public Object next() {
- return mergeRow(null, (Row) super.next());
- }
- };
- }
+ return new SimpleQueryResult(columnNames, selectorNames, joinRows);
}
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/OperandEvaluator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/OperandEvaluator.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/OperandEvaluator.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/OperandEvaluator.java Sun Nov 28 15:03:57 2010
@@ -24,6 +24,7 @@ import java.util.Map;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
+import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
@@ -67,6 +68,21 @@ public class OperandEvaluator {
this.variables = variables;
}
+ public Value getValue(StaticOperand operand, int type) throws RepositoryException {
+ Value value = getValue(operand);
+ if (type == PropertyType.UNDEFINED || type == value.getType()) {
+ return value;
+ } if (type == PropertyType.LONG) {
+ return factory.createValue(value.getLong());
+ } if (type == PropertyType.DOUBLE) {
+ return factory.createValue(value.getDouble());
+ } if (type == PropertyType.DATE) {
+ return factory.createValue(value.getDate());
+ } else {
+ return factory.createValue(value.getString(), type);
+ }
+ }
+
/**
* Returns the value of the given static operand
* ({@link Literal literal} or {@link BindVariableValue bind variable}).
@@ -280,11 +296,14 @@ public class OperandEvaluator {
*/
private Property getProperty(PropertyValue operand, Row row)
throws RepositoryException {
- try {
- String selector = operand.getSelectorName();
- String property = operand.getPropertyName();
- return row.getNode(selector).getProperty(property);
- } catch (PathNotFoundException e) {
+ Node node = row.getNode(operand.getSelectorName());
+ if (node != null) {
+ try {
+ return node.getProperty(operand.getPropertyName());
+ } catch (PathNotFoundException e) {
+ return null;
+ }
+ } else {
return null;
}
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/QueryEngine.java Sun Nov 28 15:03:57 2010
@@ -16,68 +16,45 @@
*/
package org.apache.jackrabbit.core.query.lucene.join;
-import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO;
-import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN;
-import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO;
-import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN;
-import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO;
-import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LIKE;
-import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_NOT_EQUAL_TO;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_LEFT_OUTER;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_RIGHT_OUTER;
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_ORDER_DESCENDING;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.PropertyType;
-import javax.jcr.RangeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.Workspace;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.nodetype.PropertyDefinition;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
+import javax.jcr.query.InvalidQueryException;
import javax.jcr.query.QueryResult;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
-import javax.jcr.query.qom.And;
-import javax.jcr.query.qom.BindVariableValue;
-import javax.jcr.query.qom.ChildNode;
import javax.jcr.query.qom.Column;
-import javax.jcr.query.qom.Comparison;
import javax.jcr.query.qom.Constraint;
-import javax.jcr.query.qom.DescendantNode;
-import javax.jcr.query.qom.FullTextSearch;
import javax.jcr.query.qom.Join;
-import javax.jcr.query.qom.Literal;
-import javax.jcr.query.qom.LowerCase;
-import javax.jcr.query.qom.Not;
import javax.jcr.query.qom.Operand;
-import javax.jcr.query.qom.Or;
import javax.jcr.query.qom.Ordering;
-import javax.jcr.query.qom.PropertyExistence;
import javax.jcr.query.qom.PropertyValue;
import javax.jcr.query.qom.QueryObjectModelFactory;
-import javax.jcr.query.qom.SameNode;
import javax.jcr.query.qom.Selector;
import javax.jcr.query.qom.Source;
-import javax.jcr.query.qom.UpperCase;
import org.apache.jackrabbit.commons.JcrUtils;
-import org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter;
-import org.apache.jackrabbit.commons.iterator.RangeIteratorAdapter;
import org.apache.jackrabbit.commons.iterator.RowIteratorAdapter;
+import org.apache.jackrabbit.core.query.lucene.LuceneQueryFactory;
public class QueryEngine {
@@ -128,7 +105,7 @@ public class QueryEngine {
}
- private final Session session;
+ private final LuceneQueryFactory lqf;
private final NodeTypeManager ntManager;
@@ -138,9 +115,10 @@ public class QueryEngine {
private final OperandEvaluator evaluator;
- public QueryEngine(Session session, Map<String, Value> variables)
- throws RepositoryException {
- this.session = session;
+ public QueryEngine(
+ Session session, LuceneQueryFactory lqf,
+ Map<String, Value> variables) throws RepositoryException {
+ this.lqf = lqf;
Workspace workspace = session.getWorkspace();
this.ntManager = workspace.getNodeTypeManager();
@@ -160,6 +138,12 @@ public class QueryEngine {
columns, selector, constraint, orderings, offset, limit);
} else if (source instanceof Join) {
Join join = (Join) source;
+ if (join.getJoinType() == JCR_JOIN_TYPE_RIGHT_OUTER) {
+ // Swap the join sources to normalize all outer joins to left
+ join = qomFactory.join(
+ join.getRight(), join.getLeft(),
+ JCR_JOIN_TYPE_LEFT_OUTER, join.getJoinCondition());
+ }
return execute(
columns, join, constraint, orderings, offset, limit);
} else {
@@ -221,155 +205,29 @@ public class QueryEngine {
return sort(result, orderings, offset, limit);
}
- private String toSqlConstraint(Constraint constraint)
- throws RepositoryException {
- if (constraint instanceof And) {
- And and = (And) constraint;
- String c1 = toSqlConstraint(and.getConstraint1());
- String c2 = toSqlConstraint(and.getConstraint2());
- return "(" + c1 + ") AND (" + c2 + ")";
- } else if (constraint instanceof Or) {
- Or or = (Or) constraint;
- String c1 = toSqlConstraint(or.getConstraint1());
- String c2 = toSqlConstraint(or.getConstraint2());
- return "(" + c1 + ") OR (" + c2 + ")";
- } else if (constraint instanceof Not) {
- Not or = (Not) constraint;
- return "NOT (" + toSqlConstraint(or.getConstraint()) + ")";
- } else if (constraint instanceof Comparison) {
- Comparison c = (Comparison) constraint;
- String left = toSqlOperand(c.getOperand1());
- String right = toSqlOperand(c.getOperand2());
- if (c.getOperator().equals(JCR_OPERATOR_EQUAL_TO)) {
- return left + " = " + right;
- } else if (c.getOperator().equals(JCR_OPERATOR_GREATER_THAN)) {
- return left + " > " + right;
- } else if (c.getOperator().equals(JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO)) {
- return left + " >= " + right;
- } else if (c.getOperator().equals(JCR_OPERATOR_LESS_THAN)) {
- return left + " < " + right;
- } else if (c.getOperator().equals(JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO)) {
- return left + " <= " + right;
- } else if (c.getOperator().equals(JCR_OPERATOR_LIKE)) {
- return left + " LIKE " + right;
- } else if (c.getOperator().equals(JCR_OPERATOR_NOT_EQUAL_TO)) {
- return left + " <> " + right;
- } else {
- throw new RepositoryException("Unsupported comparison: " + c);
- }
- } else if (constraint instanceof SameNode) {
- SameNode sn = (SameNode) constraint;
- return "jcr:path = '" + sn.getPath() + "'";
- } else if (constraint instanceof ChildNode) {
- ChildNode cn = (ChildNode) constraint;
- return "jcr:path LIKE '" + cn.getParentPath() + "/%'";
- } else if (constraint instanceof DescendantNode) {
- DescendantNode dn = (DescendantNode) constraint;
- return "jcr:path LIKE '" + dn.getAncestorPath() + "/%'";
- } else if (constraint instanceof PropertyExistence) {
- PropertyExistence pe = (PropertyExistence) constraint;
- return pe.getPropertyName() + " IS NOT NULL";
- } else if (constraint instanceof FullTextSearch) {
- FullTextSearch fts = (FullTextSearch) constraint;
- String expr = toSqlOperand(fts.getFullTextSearchExpression());
- return "CONTAINS(" + fts.getPropertyName() + ", " + expr + ")";
- } else {
- throw new RepositoryException("Unsupported constraint: " + constraint);
- }
- }
-
- private static enum Transform {
- NONE,
- UPPER,
- LOWER
- }
-
- private String toSqlOperand(Operand operand) throws RepositoryException {
- return toSqlOperand(operand, Transform.NONE);
- }
-
- private String toSqlOperand(Operand operand, Transform transform)
- throws RepositoryException {
- if (operand instanceof PropertyValue) {
- PropertyValue pv = (PropertyValue) operand;
- switch (transform) {
- case UPPER:
- return "UPPER(" + pv.getPropertyName() + ")";
- case LOWER:
- return "LOWER(" + pv.getPropertyName() + ")";
- default:
- return pv.getPropertyName();
- }
- } else if (operand instanceof LowerCase) {
- LowerCase lc = (LowerCase) operand;
- if (transform == Transform.NONE) {
- transform = Transform.LOWER;
- }
- return toSqlOperand(lc.getOperand(), transform);
- } else if (operand instanceof UpperCase) {
- UpperCase uc = (UpperCase) operand;
- if (transform == Transform.NONE) {
- transform = Transform.UPPER;
- }
- return toSqlOperand(uc.getOperand(), transform);
- } else if ((operand instanceof Literal)
- || (operand instanceof BindVariableValue)) {
- Value value = evaluator.getValue(operand, null);
- int type = value.getType();
- if (type == PropertyType.LONG || type == PropertyType.DOUBLE) {
- return value.getString();
- } else if (type == PropertyType.DATE && transform == Transform.NONE) {
- return "TIMESTAMP '" + value.getString() + "'";
- } else if (transform == Transform.UPPER) {
- return "'" + value.getString().toUpperCase(Locale.ENGLISH) + "'";
- } else if (transform == Transform.LOWER) {
- return "'" + value.getString().toLowerCase(Locale.ENGLISH) + "'";
- } else {
- return "'" + value.getString() + "'";
- }
- } else {
- throw new RepositoryException("Uknown operand type: " + operand);
- }
- }
-
protected QueryResult execute(
Column[] columns, Selector selector, Constraint constraint,
Ordering[] orderings, long offset, long limit)
throws RepositoryException {
- StringBuilder builder = new StringBuilder();
- builder.append("SELECT * FROM ");
- builder.append(selector.getNodeTypeName());
- if (constraint != null) {
- builder.append(" WHERE ");
- builder.append(toSqlConstraint(constraint));
- }
-
- QueryManager manager = session.getWorkspace().getQueryManager();
- Query query = manager.createQuery(builder.toString(), Query.SQL);
-
Map<String, NodeType> selectorMap = getSelectorNames(selector);
- final String[] selectorNames =
+ String[] selectorNames =
selectorMap.keySet().toArray(new String[selectorMap.size()]);
- final Map<String, PropertyValue> columnMap =
+ Map<String, PropertyValue> columnMap =
getColumnMap(columns, selectorMap);
- final String[] columnNames =
+ String[] columnNames =
columnMap.keySet().toArray(new String[columnMap.size()]);
- NodeIterator nodes = query.execute().getNodes();
- final String selectorName = selector.getSelectorName();
- RowIterator rows = new RowIteratorAdapter(nodes) {
- @Override
- public Object next() {
- Node node = (Node) super.next();
- return new SelectorRow(
- columnMap, evaluator, selectorName, node, 1.0);
- }
- };
-
- QueryResult result =
- new SimpleQueryResult(columnNames, selectorNames, rows);
- return sort(result, orderings, offset, limit);
+ try {
+ RowIterator rows = new RowIteratorAdapter(lqf.execute(
+ columnMap, selector, constraint));
+ QueryResult result =
+ new SimpleQueryResult(columnNames, selectorNames, rows);
+ return sort(result, orderings, offset, limit);
+ } catch (IOException e) {
+ throw new RepositoryException(
+ "Failed to access the query index", e);
+ }
}
private Map<String, PropertyValue> getColumnMap(
@@ -418,8 +276,7 @@ public class QueryEngine {
if (source instanceof Selector) {
Selector selector = (Selector) source;
return Collections.singletonMap(
- selector.getSelectorName(),
- ntManager.getNodeType(selector.getNodeTypeName()));
+ selector.getSelectorName(), getNodeType(selector));
} else if (source instanceof Join) {
Join join = (Join) source;
Map<String, NodeType> map = new LinkedHashMap<String, NodeType>();
@@ -432,6 +289,15 @@ public class QueryEngine {
}
}
+ private NodeType getNodeType(Selector selector) throws RepositoryException {
+ try {
+ return ntManager.getNodeType(selector.getNodeTypeName());
+ } catch (NoSuchNodeTypeException e) {
+ throw new InvalidQueryException(
+ "Selected node type does not exist: " + selector, e);
+ }
+ }
+
/**
* Sorts the given query results according to the given QOM orderings.
* If one or more orderings have been specified, this method will iterate
@@ -461,13 +327,13 @@ public class QueryEngine {
Collections.sort(rows, new RowComparator(orderings));
}
- if (offset != 0 || limit >= 0) {
- int from = (int) offset;
- int to = rows.size();
- if (limit >= 0 && offset + limit < to) {
- to = (int) (offset + limit);
- }
- rows = rows.subList(from, to);
+ if (offset > 0) {
+ int size = rows.size();
+ rows = rows.subList((int) Math.min(offset, size), size);
+ }
+ if (limit >= 0) {
+ int size = rows.size();
+ rows = rows.subList(0, (int) Math.min(limit, size));
}
return new SimpleQueryResult(
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoinMerger.java Sun Nov 28 15:03:57 2010
@@ -33,6 +33,8 @@ import javax.jcr.query.qom.PropertyValue
import javax.jcr.query.qom.QueryObjectModelFactory;
import javax.jcr.query.qom.SameNodeJoinCondition;
+import org.apache.jackrabbit.spi.commons.conversion.PathResolver;
+
class SameNodeJoinMerger extends JoinMerger {
private final String selector1;
@@ -91,10 +93,14 @@ class SameNodeJoinMerger extends JoinMer
Node node = row.getNode(selector2);
if (node != null) {
try {
- if (path != null) {
- node = node.getNode(path);
+ String p = node.getPath();
+ if (path != null && !".".equals(path)) {
+ if (!"/".equals(p)) {
+ p += "/";
+ }
+ p += path;
}
- return Collections.singleton(node.getPath());
+ return Collections.singleton(p);
} catch (PathNotFoundException e) {
// fall through
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ValueComparator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ValueComparator.java?rev=1039888&r1=1039887&r2=1039888&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ValueComparator.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ValueComparator.java Sun Nov 28 15:03:57 2010
@@ -26,12 +26,16 @@ import static javax.jcr.query.qom.QueryO
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN;
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO;
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LIKE;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_NOT_EQUAL_TO;
import java.util.Comparator;
+import java.util.regex.Pattern;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
+import org.apache.jackrabbit.core.query.lucene.Util;
+
/**
* Comparator for {@link Value} instances.
*/
@@ -78,10 +82,16 @@ public class ValueComparator implements
return compare(a, b) < 0;
} else if (JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO.equals(operator)) {
return compare(a, b) <= 0;
+ } else if (JCR_OPERATOR_NOT_EQUAL_TO.equals(operator)) {
+ return compare(a, b) != 0;
} else if (JCR_OPERATOR_LIKE.equals(operator)) {
- // TODO: Implement LIKE support
- throw new RuntimeException(
- "LIKE comparisions are not currently supported");
+ try {
+ Pattern pattern = Util.createRegexp(b.getString());
+ return pattern.matcher(a.getString()).matches();
+ } catch (RepositoryException e) {
+ throw new RuntimeException(
+ "Unable to compare values " + a + " and " + b, e);
+ }
} else {
throw new IllegalArgumentException(
"Unknown comparison operator: " + operator);