You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by da...@apache.org on 2015/10/21 17:19:16 UTC
svn commit: r1709863 [1/2] - in /jackrabbit/oak/trunk:
oak-core/src/main/java/org/apache/jackrabbit/oak/query/
oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/
oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/
oak-core...
Author: davide
Date: Wed Oct 21 15:19:15 2015
New Revision: 1709863
URL: http://svn.apache.org/viewvc?rev=1709863&view=rev
Log:
OAK-1617 - Automatically convert "or" queries to "union" for SQL-2
- implemented functionality
- to enable -Doak.query.sql2optimisation
- disabled by default
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/MultiPropertyOrTestOptimisation.java
- copied, changed from r1709862, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTestSQL2Optimisations.java
- copied, changed from r1709862, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryCostOverheadTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2OptimiseQueryTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ast/AndImplTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ast/OrImplTest.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexQueryTestSQL2Optimisation.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AndImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeJoinConditionImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ColumnImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ConstraintImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeJoinConditionImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/InImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NativeFunctionImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NotImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/OrImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyExistenceImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyInexistenceImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SameNodeImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SimilarImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SuggestImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexQueryTest.java
jackrabbit/oak/trunk/oak-solr-core/pom.xml
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java Wed Oct 21 15:19:15 2015
@@ -16,7 +16,11 @@ package org.apache.jackrabbit.oak.query;
import java.util.Iterator;
import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
import aQute.bnd.annotation.ProviderType;
+
import org.apache.jackrabbit.oak.api.PropertyValue;
import org.apache.jackrabbit.oak.api.Result;
import org.apache.jackrabbit.oak.api.Tree;
@@ -125,4 +129,69 @@ public interface Query {
* @return if sorted by index
*/
boolean isSortedByIndex();
+
+ /**
+ * Perform optimisation on the object itself. To avoid any potential error due to state
+ * variables perfom the optimisation before the {@link #init()}.
+ *
+ * @return {@code this} if no optimisations are possible or a new instance of a {@link Query}.
+ * Cannot return null.
+ */
+ @Nonnull
+ Query optimise();
+
+ /**
+ * <p>
+ * returns a clone of the current object. Will throw an exception in case it's invoked in a non
+ * appropriate moment. For example the default {@link QueryImpl} cannot be cloned once the
+ * {@link #init()} has been executed.
+ * </p>
+ *
+ * <p>
+ * <strong>May return null if not implemented.</strong>
+ * </p>
+ * @return a clone of self
+ * @throws IllegalStateException
+ */
+ @Nullable
+ Query copyOf() throws IllegalStateException;
+
+ /**
+ * @return {@code true} if the query has been already initialised. {@code false} otherwise.
+ */
+ boolean isInit();
+
+ /**
+ * @return {@code true} if the query is a result of optimisations. {@code false} if it's the
+ * originally computed one.
+ */
+ boolean isOptimised();
+
+ /**
+ * @return the original statement as it was used to construct the object. If not provided the
+ * {@link #toString()} will be used instead.
+ */
+ String getStatement();
+
+ /**
+ *
+ * @return {@code true} if the current query is internal. {@code false} otherwise.
+ */
+ boolean isInternal();
+
+ /**
+ * <p>
+ * Some queries can bring with them a cost overhead that the query engine could consider when
+ * electing the best query between the original SQL2 and the possible available optimisations.
+ * </p>
+ * <p>
+ * For example for the case of <a href="https://issues.apache.org/jira/browse/OAK-2660" /> if
+ * you have a case where {@code (a = 'v' OR CONTAINS(b, 'v1') OR CONTAINS(c, 'v2')) AND (...)}
+ * currently the query engine does not know how to leverage indexes and post conditions and the
+ * query is better suited with a UNION.
+ * </p>
+ *
+ * @return a positive number or 0. <strong>Cannot be negative.</strong>
+ */
+ double getCostOverhead();
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java Wed Oct 21 15:19:15 2015
@@ -16,7 +16,9 @@
*/
package org.apache.jackrabbit.oak.query;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableSet.of;
+import static com.google.common.collect.Sets.newHashSet;
import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
@@ -27,6 +29,8 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import javax.annotation.Nonnull;
+
import org.apache.jackrabbit.oak.api.PropertyValue;
import org.apache.jackrabbit.oak.api.QueryEngine;
import org.apache.jackrabbit.oak.api.Result;
@@ -43,6 +47,27 @@ import org.slf4j.MDC;
* The query engine implementation.
*/
public abstract class QueryEngineImpl implements QueryEngine {
+
+ /**
+ * used to instruct the {@link QueryEngineImpl} on how to act with respect of the SQL2
+ * optimisation.
+ */
+ public static enum ForceOptimised {
+ /**
+ * will force the original SQL2 query to be executed
+ */
+ ORIGINAL,
+
+ /**
+ * will force the computed optimised query to be executed. If available.
+ */
+ OPTIMISED,
+
+ /**
+ * will execute the cheapest.
+ */
+ CHEAPEST
+ }
private static final AtomicInteger ID_COUNTER = new AtomicInteger();
private static final String MDC_QUERY_ID = "oak.query.id";
@@ -68,6 +93,12 @@ public abstract class QueryEngineImpl im
* disabled for testing purposes.
*/
private boolean traversalEnabled = true;
+
+ /**
+ * Whether the query engine should be forced to use the optimised version of the query if
+ * available.
+ */
+ private ForceOptimised forceOptimised = ForceOptimised.CHEAPEST;
/**
* Get the execution context for a single query execution.
@@ -94,11 +125,12 @@ public abstract class QueryEngineImpl im
public List<String> getBindVariableNames(
String statement, String language, Map<String, String> mappings)
throws ParseException {
- Query q = parseQuery(statement, language, getExecutionContext(), mappings);
- return q.getBindVariableNames();
+ Set<Query> qs = parseQuery(statement, language, getExecutionContext(), mappings);
+
+ return qs.iterator().next().getBindVariableNames();
}
- private static Query parseQuery(
+ private static Set<Query> parseQuery(
String statement, String language, ExecutionContext context,
Map<String, String> mappings) throws ParseException {
@@ -123,11 +155,16 @@ public abstract class QueryEngineImpl im
parser.setAllowNumberLiterals(false);
parser.setAllowTextLiterals(false);
}
+
+ Set<Query> queries = newHashSet();
+
+ Query q;
+
if (SQL2.equals(language) || JQOM.equals(language)) {
- return parser.parse(statement);
+ q = parser.parse(statement, false);
} else if (SQL.equals(language)) {
parser.setSupportSQL1(true);
- return parser.parse(statement);
+ q = parser.parse(statement, false);
} else if (XPATH.equals(language)) {
XPathToSQL2Converter converter = new XPathToSQL2Converter();
String sql2 = converter.convert(statement);
@@ -135,7 +172,7 @@ public abstract class QueryEngineImpl im
try {
// OAK-874: No artificial XPath selector name in wildcards
parser.setIncludeSelectorNameInWildcardColumns(false);
- return parser.parse(sql2);
+ q = parser.parse(sql2, false);
} catch (ParseException e) {
ParseException e2 = new ParseException(
statement + " converted to SQL-2 " + e.getMessage(), 0);
@@ -145,6 +182,34 @@ public abstract class QueryEngineImpl im
} else {
throw new ParseException("Unsupported language: " + language, 0);
}
+
+ queries.add(q);
+
+ if (settings.isSql2Optimisation()) {
+ if (q.isInternal()) {
+ LOG.trace("Skipping optimisation as internal query.");
+ } else {
+ LOG.trace("Attempting optimisation");
+ Query q2 = q.optimise();
+ if (q2 != q) {
+ LOG.debug("Optimised query available. {}", q2);
+ queries.add(q2);
+ }
+ }
+ }
+
+ // initialising all the queries.
+ for (Query query : queries) {
+ try {
+ query.init();
+ } catch (Exception e) {
+ ParseException e2 = new ParseException(query.getStatement() + ": " + e.getMessage(), 0);
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+ return queries;
}
@Override
@@ -176,21 +241,25 @@ public abstract class QueryEngineImpl im
}
ExecutionContext context = getExecutionContext();
- Query q = parseQuery(statement, language, context, mappings);
- q.setExecutionContext(context);
- q.setLimit(limit);
- q.setOffset(offset);
- if (bindings != null) {
- for (Entry<String, ? extends PropertyValue> e : bindings.entrySet()) {
- q.bindValue(e.getKey(), e.getValue());
+ Set<Query> queries = parseQuery(statement, language, context, mappings);
+
+ for (Query q : queries) {
+ q.setExecutionContext(context);
+ q.setLimit(limit);
+ q.setOffset(offset);
+ if (bindings != null) {
+ for (Entry<String, ? extends PropertyValue> e : bindings.entrySet()) {
+ q.bindValue(e.getKey(), e.getValue());
+ }
}
+ q.setTraversalEnabled(traversalEnabled);
}
- q.setTraversalEnabled(traversalEnabled);
boolean mdc = false;
try {
- mdc = setupMDC(q);
- q.prepare();
+ MdcAndPrepared map = prepareAndGetCheapest(queries);
+ mdc = map.mdc;
+ Query q = map.query;
return q.executeQuery();
} finally {
if (mdc) {
@@ -199,6 +268,133 @@ public abstract class QueryEngineImpl im
}
}
+ /**
+ * POJO class used to return the cheapest prepared query from the set and related MDC status
+ */
+ private static class MdcAndPrepared {
+ private final boolean mdc;
+ private final Query query;
+
+ public MdcAndPrepared(final boolean mdc, @Nonnull final Query q) {
+ this.mdc = mdc;
+ this.query = checkNotNull(q);
+ }
+ }
+
+ /**
+ * will prepare all the available queries and by based on the {@link ForceOptimised} flag return
+ * the appropriate.
+ *
+ * @param queries the list of queries to be executed. cannot be null
+ * @return
+ */
+ @Nonnull
+ private MdcAndPrepared prepareAndGetCheapest(@Nonnull final Set<Query> queries) {
+ MdcAndPrepared map = null;
+ Query cheapest = null;
+
+
+ if (checkNotNull(queries).size() == 1) {
+ // Optimisation. We only have the original query so we prepare and return it.
+ cheapest = queries.iterator().next();
+ cheapest.prepare();
+ LOG.debug("No optimisations found. Cheapest is the original query: {}", cheapest);
+ map = new MdcAndPrepared(setupMDC(cheapest), cheapest);
+ } else {
+ double bestCost = Double.MAX_VALUE;
+ double originalCost = Double.MAX_VALUE;
+ boolean firstLoop = true;
+ Query original = null;
+
+ // always prepare all of the queries and compute the cheapest as it's the default behaviour.
+ // It should trigger more errors during unit and integration testing. Changing
+ // `forceOptimised` flag should be in case used only during testing.
+ for (Query q : checkNotNull(queries)) {
+ LOG.debug("Preparing: {}", q);
+ q.prepare();
+
+ double actualCost = q.getEstimatedCost();
+ double costOverhead = q.getCostOverhead();
+ double overallCost = Math.min(actualCost + costOverhead, Double.MAX_VALUE);
+
+ LOG.debug("actualCost: {} - costOverhead: {} - overallCost: {}", actualCost,
+ costOverhead, overallCost);
+
+ if (firstLoop) {
+ // first time we're always the best cost. Avoiding situations where the original
+ // query has an overall cost as Double.MAX_VALUE.
+ bestCost = overallCost;
+ cheapest = q;
+ firstLoop = false;
+ } else if (overallCost < bestCost) {
+ bestCost = overallCost;
+ cheapest = q;
+ }
+ if (!q.isOptimised()) {
+ original = q;
+ originalCost = overallCost;
+ }
+ }
+
+ if (original != null && bestCost == originalCost && cheapest != original) {
+ // if the optimised cost is the same as the original SQL2 query we prefer the original. As
+ // we deal with references the `cheapest!=original` should work.
+ LOG.trace("Same cost for original and optimised. Forcing original");
+ cheapest = original;
+ }
+
+ switch (forceOptimised) {
+ case ORIGINAL:
+ LOG.debug("Forcing the original SQL2 query to be executed by flag");
+ for (Query q : checkNotNull(queries)) {
+ if (!q.isOptimised()) {
+ map = new MdcAndPrepared(setupMDC(q), q);
+ }
+ }
+ break;
+
+ case OPTIMISED:
+ LOG.debug("Forcing the optimised SQL2 query to be executed by flag");
+ for (Query q : checkNotNull(queries)) {
+ if (q.isOptimised()) {
+ map = new MdcAndPrepared(setupMDC(q), q);
+ }
+ }
+ break;
+
+ // CHEAPEST is the default behaviour
+ case CHEAPEST:
+ default:
+ if (cheapest == null) {
+ // this should not really happen. Defensive coding.
+ LOG.debug("Cheapest is null. Returning the original SQL2 query.");
+ for (Query q : checkNotNull(queries)) {
+ if (!q.isOptimised()) {
+ map = new MdcAndPrepared(setupMDC(q), q);
+ }
+ }
+ } else {
+ LOG.debug("Cheapest cost: {} - query: {}", bestCost, cheapest);
+ map = new MdcAndPrepared(setupMDC(cheapest), cheapest);
+ }
+ }
+ }
+
+
+ if (map == null) {
+ // we should only get here in case of testing forcing weird conditions
+ LOG.trace("`MdcAndPrepared` is null. Falling back to the original query");
+ for (Query q : checkNotNull(queries)) {
+ if (!q.isOptimised()) {
+ map = new MdcAndPrepared(setupMDC(q), q);
+ break;
+ }
+ }
+ }
+
+ return map;
+ }
+
protected void setTraversalEnabled(boolean traversalEnabled) {
this.traversalEnabled = traversalEnabled;
}
@@ -222,4 +418,13 @@ public abstract class QueryEngineImpl im
MDC.remove(OAK_QUERY_ANALYZE);
}
+ /**
+ * Instruct the query engine on how to behave with regards to the SQL2 optimised query if
+ * available.
+ *
+ * @param forceOptimised cannot be null
+ */
+ protected void setForceOptimised(@Nonnull ForceOptimised forceOptimised) {
+ this.forceOptimised = forceOptimised;
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java Wed Oct 21 15:19:15 2015
@@ -41,6 +41,8 @@ public class QueryEngineSettings impleme
private boolean fullTextComparisonWithoutIndex =
DEFAULT_FULL_TEXT_COMPARISON_WITHOUT_INDEX;
+ private boolean sql2Optimisation = Boolean.getBoolean("oak.query.sql2optimisation");
+
/**
* Get the limit on how many nodes a query may read at most into memory, for
* "order by" and "distinct" queries. If this limit is exceeded, the query
@@ -93,4 +95,7 @@ public class QueryEngineSettings impleme
return fullTextComparisonWithoutIndex;
}
+ public boolean isSql2Optimisation() {
+ return sql2Optimisation;
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java Wed Oct 21 15:19:15 2015
@@ -13,6 +13,10 @@
*/
package org.apache.jackrabbit.oak.query;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Lists.newArrayList;
+import static org.apache.jackrabbit.oak.query.ast.AstElementFactory.copyElementAndCheckReference;
+
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
@@ -24,11 +28,14 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.annotation.Nonnull;
+
+import com.google.common.base.Strings;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-
import com.google.common.collect.Ordering;
+
import org.apache.jackrabbit.oak.api.PropertyValue;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
@@ -79,6 +86,7 @@ import org.apache.jackrabbit.oak.query.p
import org.apache.jackrabbit.oak.query.plan.SelectorExecutionPlan;
import org.apache.jackrabbit.oak.spi.query.Filter;
import org.apache.jackrabbit.oak.spi.query.PropertyValues;
+import org.apache.jackrabbit.oak.spi.query.QueryConstants;
import org.apache.jackrabbit.oak.spi.query.QueryIndex;
import org.apache.jackrabbit.oak.spi.query.QueryIndex.AdvancedQueryIndex;
import org.apache.jackrabbit.oak.spi.query.QueryIndex.IndexPlan;
@@ -131,7 +139,7 @@ public class QueryImpl implements Query
};
SourceImpl source;
- final String statement;
+ private String statement;
final HashMap<String, PropertyValue> bindVariableMap = new HashMap<String, PropertyValue>();
final HashMap<String, Integer> selectorIndexes = new HashMap<String, Integer>();
final ArrayList<SelectorImpl> selectors = new ArrayList<SelectorImpl>();
@@ -160,6 +168,16 @@ public class QueryImpl implements Query
private long size = -1;
private boolean prepared;
private ExecutionContext context;
+
+ /**
+ * whether the object has been initialised or not
+ */
+ private boolean init;
+
+ /**
+ * whether the query is a result of optimisation or original one.
+ */
+ private boolean optimised;
private boolean isSortedByIndex;
@@ -175,12 +193,19 @@ public class QueryImpl implements Query
QueryImpl(String statement, SourceImpl source, ConstraintImpl constraint,
ColumnImpl[] columns, NamePathMapper mapper, QueryEngineSettings settings) {
+ this(statement, source, constraint, columns, mapper, settings, false);
+ }
+
+ QueryImpl(String statement, SourceImpl source, ConstraintImpl constraint,
+ ColumnImpl[] columns, NamePathMapper mapper, QueryEngineSettings settings,
+ final boolean optimised) {
this.statement = statement;
this.source = source;
this.constraint = constraint;
this.columns = columns;
this.namePathMapper = mapper;
this.settings = settings;
+ this.optimised = optimised;
}
@Override
@@ -416,6 +441,8 @@ public class QueryImpl implements Query
}
distinctColumns[i] = distinct;
}
+
+ init = true;
}
@Override
@@ -1138,8 +1165,9 @@ public class QueryImpl implements Query
return Math.min(limit, source.getSize(precision, max));
}
+ @Override
public String getStatement() {
- return statement;
+ return Strings.isNullOrEmpty(statement) ? toString() : statement;
}
public QueryEngineSettings getSettings() {
@@ -1170,4 +1198,171 @@ public class QueryImpl implements Query
return sum.min(max).max(min).longValue();
}
+ @Override
+ public Query optimise() {
+ // optimising for UNION
+ Query optimised = this;
+
+ if (constraint != null) {
+ Set<ConstraintImpl> unionList = constraint.simplifyForUnion();
+ if (unionList.size() > 1) {
+ // there are some cases where multiple ORs simplify into a single one. If we get a
+ // union list of just one we don't really have to UNION anything.
+ QueryImpl left = null;
+ Query right = null;
+ // we have something to do here.
+ for (ConstraintImpl c : unionList) {
+ if (right != null) {
+ right = newOptimisedUnionQuery(left, right);
+ } else {
+ // pulling left to the right
+ if (left != null) {
+ right = left;
+ }
+ }
+
+ // cloning original query
+ left = (QueryImpl) this.copyOf(true);
+
+ // cloning the constraints and assigning to new query
+ left.constraint = (ConstraintImpl) copyElementAndCheckReference(c);
+ // re-composing the statement for better debug messages
+ left.statement = recomposeStatement(left);
+ }
+
+ optimised = newOptimisedUnionQuery(left, right);
+ }
+ }
+
+ return optimised;
+ }
+
+ private static String recomposeStatement(@Nonnull QueryImpl query) {
+ checkNotNull(query);
+ String original = query.getStatement();
+ String origUpper = original.toUpperCase();
+ StringBuilder recomputed = new StringBuilder();
+ final String where = " WHERE ";
+ final String orderBy = " ORDER BY ";
+ int whereOffset = where.length();
+
+ if (query.getConstraint() == null) {
+ recomputed.append(original);
+ } else {
+ recomputed.append(original.substring(0, origUpper.indexOf(where) + whereOffset));
+ recomputed.append(query.getConstraint());
+ if (origUpper.indexOf(orderBy) > -1) {
+ recomputed.append(original.substring(origUpper.indexOf(orderBy)));
+ }
+ }
+ return recomputed.toString();
+ }
+
+ /**
+ * convenience method for creating a UnionQueryImpl with proper settings.
+ *
+ * @param left
+ * @param right
+ * @return
+ */
+ private UnionQueryImpl newOptimisedUnionQuery(@Nonnull Query left, @Nonnull Query right) {
+ UnionQueryImpl u = new UnionQueryImpl(
+ false,
+ checkNotNull(left, "`left` cannot be null"),
+ checkNotNull(right, "`right` cannot be null"),
+ this.settings,
+ true);
+ u.setExplain(explain);
+ return u;
+ }
+
+ @Override
+ public Query copyOf() throws IllegalStateException {
+ return copyOf(false);
+ }
+
+ private Query copyOf(final boolean optimised) {
+ if (isInit()) {
+ throw new IllegalStateException("QueryImpl cannot be cloned once initialised.");
+ }
+
+ List<ColumnImpl> cols = newArrayList();
+ for (ColumnImpl c : columns) {
+ cols.add((ColumnImpl) copyElementAndCheckReference(c));
+ }
+
+ QueryImpl copy = new QueryImpl(
+ this.statement,
+ (SourceImpl) copyElementAndCheckReference(this.source),
+ this.constraint,
+ cols.toArray(new ColumnImpl[0]),
+ this.namePathMapper,
+ this.settings,
+ optimised);
+ copy.explain = this.explain;
+ copy.distinct = this.distinct;
+
+ return copy;
+ }
+
+ @Override
+ public boolean isInit() {
+ return init;
+ }
+
+ @Override
+ public boolean isOptimised() {
+ return optimised;
+ }
+
+ @Override
+ public boolean isInternal() {
+ return isInternal;
+ }
+
+ @Override
+ public double getCostOverhead() {
+ return oak2660CostOverhead(getConstraint());
+ }
+
+ /**
+ * compute a cost overhead for the OAK-2660 use case. The query engine better perform/compute
+ * the use case `(a = 'v' OR CONTAINS(b, 'v1') OR CONTAINS(c, 'v2') AND (...)` as a UNION query
+ * to leverage different indexes. In this case we return an 'Infinity' overhead for make the
+ * query engine choose a union query instead.
+ *
+ * @param constraint the constraint to analyse. Cannot be null.
+ * @return
+ */
+ private double oak2660CostOverhead(@Nonnull ConstraintImpl constraint) {
+ if (checkNotNull(constraint) instanceof OrImpl) {
+ boolean fulltext = false, plain = false;
+ for (ConstraintImpl c : constraint.getConstraints()) {
+ if (c instanceof FullTextSearchImpl) {
+ fulltext = true;
+ } else {
+ plain = true;
+ }
+
+ if (fulltext && plain) {
+ return Double.MAX_VALUE;
+ }
+ }
+ } else {
+ List<ConstraintImpl> cs = constraint.getConstraints();
+ if (cs == null) {
+ return 0;
+ } else {
+ double cost = 0;
+ for (ConstraintImpl c : cs) {
+ cost += oak2660CostOverhead(c);
+ if (cost == Double.MAX_VALUE) {
+ return cost;
+ }
+ }
+ return cost;
+ }
+ }
+ return 0;
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java Wed Oct 21 15:19:15 2015
@@ -125,10 +125,11 @@ public class SQL2Parser {
* Parse the statement and return the query.
*
* @param query the query string
+ * @param initialise if performing the query init ({@code true}) or not ({@code false})
* @return the query
* @throws ParseException if parsing fails
*/
- public Query parse(String query) throws ParseException {
+ public Query parse(final String query, final boolean initialise) throws ParseException {
// TODO possibly support union,... as available at
// http://docs.jboss.org/modeshape/latest/manuals/reference/html/jcr-query-and-search.html
@@ -164,17 +165,32 @@ public class SQL2Parser {
q.setOrderings(orderings);
q.setExplain(explain);
q.setMeasure(measure);
- try {
- q.init();
- } catch (Exception e) {
- ParseException e2 = new ParseException(query + ": " + e.getMessage(), 0);
- e2.initCause(e);
- throw e2;
- }
q.setInternal(isInternal(query));
+
+ if (initialise) {
+ try {
+ q.init();
+ } catch (Exception e) {
+ ParseException e2 = new ParseException(statement + ": " + e.getMessage(), 0);
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
return q;
}
+ /**
+ * as {@link #parse(String, boolean)} by providing {@code true} to the initialisation flag.
+ *
+ * @param query
+ * @return
+ * @throws ParseException
+ */
+ public Query parse(final String query) throws ParseException {
+ return parse(query, true);
+ }
+
private QueryImpl parseSelect() throws ParseException {
read("SELECT");
boolean distinct = readIf("DISTINCT");
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java Wed Oct 21 15:19:15 2015
@@ -56,11 +56,22 @@ public class UnionQueryImpl implements Q
private final QueryEngineSettings settings;
private boolean isInternal;
+ /**
+ * whether the query is a result of optimisation or not
+ */
+ private boolean optimised;
+
UnionQueryImpl(boolean unionAll, Query left, Query right, QueryEngineSettings settings) {
+ this(unionAll, left, right, settings, false);
+ }
+
+ UnionQueryImpl(final boolean unionAll, final Query left, final Query right,
+ final QueryEngineSettings settings, final boolean optimised) {
this.unionAll = unionAll;
this.left = left;
this.right = right;
this.settings = settings;
+ this.optimised = optimised;
}
@Override
@@ -355,4 +366,40 @@ public class UnionQueryImpl implements Q
public boolean isSortedByIndex() {
return left.isSortedByIndex() && right.isSortedByIndex();
}
+
+ @Override
+ public Query optimise() {
+ return this;
+ }
+
+ @Override
+ public Query copyOf() throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public boolean isInit() {
+ return left.isInit() || right.isInit();
+ }
+
+ @Override
+ public boolean isOptimised() {
+ return optimised;
+ }
+
+ @Override
+ public String getStatement() {
+ return toString();
+ }
+
+ @Override
+ public boolean isInternal() {
+ return left.isInternal() || right.isInternal();
+ }
+
+ @Override
+ public double getCostOverhead() {
+ // for now we don't really have any case where a union query should suffer from overheads.
+ return 0;
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AndImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AndImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AndImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AndImpl.java Wed Oct 21 15:19:15 2015
@@ -22,7 +22,9 @@ import static com.google.common.base.Pre
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newHashSet;
import static com.google.common.collect.Sets.newLinkedHashSet;
+import static org.apache.jackrabbit.oak.query.ast.AstElementFactory.copyElementAndCheckReference;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
@@ -32,6 +34,8 @@ import org.apache.jackrabbit.oak.query.f
import org.apache.jackrabbit.oak.query.fulltext.FullTextExpression;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import com.google.common.collect.Sets;
+
/**
* An AND condition.
*/
@@ -48,6 +52,7 @@ public class AndImpl extends ConstraintI
this(Arrays.asList(constraint1, constraint2));
}
+ @Override
public List<ConstraintImpl> getConstraints() {
return constraints;
}
@@ -205,4 +210,43 @@ public class AndImpl extends ConstraintI
return constraints.hashCode();
}
+ @Override
+ public AstElement copyOf() {
+ List<ConstraintImpl> clone = new ArrayList<ConstraintImpl>(constraints.size());
+ for (ConstraintImpl c : constraints) {
+ clone.add((ConstraintImpl) copyElementAndCheckReference(c));
+ }
+ return new AndImpl(clone);
+ }
+
+ @Override
+ public Set<ConstraintImpl> simplifyForUnion() {
+ Set<ConstraintImpl> union = Sets.newHashSet();
+ Set<ConstraintImpl> result = Sets.newHashSet();
+ Set<ConstraintImpl> nonUnion = Sets.newHashSet();
+
+ for (ConstraintImpl c : getConstraints()) {
+ Set<ConstraintImpl> ccc = c.simplifyForUnion();
+ if (ccc.isEmpty()) {
+ nonUnion.add(c);
+ } else {
+ union.addAll(ccc);
+ }
+ }
+ if (!union.isEmpty() && nonUnion.size() == 1) {
+ // this is the simplest case where, for example, out of the two AND operands at least
+ // one is a non-union. For example WHERE (a OR b OR c) AND d
+ ConstraintImpl right = nonUnion.iterator().next();
+ for (ConstraintImpl c : union) {
+ result.add(new AndImpl(c, right));
+ }
+ } else {
+ // in this case prefer to be conservative and don't optimise. This could happen when for
+ // example: WHERE (a OR b) AND (c OR d).
+ // This should be translated into a AND c, a AND d, b AND c, b AND d.
+ }
+
+ return result;
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java Wed Oct 21 15:19:15 2015
@@ -18,6 +18,8 @@
*/
package org.apache.jackrabbit.oak.query.ast;
+import javax.annotation.Nonnull;
+
import org.apache.jackrabbit.oak.api.PropertyValue;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.query.QueryImpl;
@@ -27,7 +29,6 @@ import org.apache.jackrabbit.oak.spi.que
* The base class for all abstract syntax tree nodes.
*/
abstract class AstElement {
-
protected QueryImpl query;
abstract boolean accept(AstVisitor v);
@@ -147,5 +148,13 @@ abstract class AstElement {
return path;
}
+ /**
+ * @return a clone of self. Default implementation in {@link AstElement} returns same reference
+ * to {@code this}.
+ */
+ @Nonnull
+ public AstElement copyOf() {
+ return this;
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java Wed Oct 21 15:19:15 2015
@@ -13,15 +13,22 @@
*/
package org.apache.jackrabbit.oak.query.ast;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.util.ArrayList;
+import javax.annotation.Nonnull;
+
import org.apache.jackrabbit.oak.api.PropertyValue;
import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A factory for syntax tree elements.
*/
public class AstElementFactory {
+ private static final Logger LOG = LoggerFactory.getLogger(AstElementFactory.class);
public AndImpl and(ConstraintImpl constraint1, ConstraintImpl constraint2) {
return new AndImpl(constraint1, constraint2);
@@ -164,4 +171,28 @@ public class AstElementFactory {
public ConstraintImpl suggest(String selectorName, StaticOperandImpl expression) {
return new SuggestImpl(selectorName, expression);
}
+
+ /**
+ * <p>
+ * as the {@link AstElement#copyOf()} can return {@code this} is the cloning is not implemented
+ * by the subclass, this method add some spice around it by checking for this case and tracking
+ * a DEBUG message in the logs.
+ * </p>
+ *
+ * @param e the element to be cloned. Cannot be null.
+ * @return same as {@link AstElement#copyOf()}
+ */
+ @Nonnull
+ public static AstElement copyElementAndCheckReference(@Nonnull final AstElement e) {
+ AstElement clone = checkNotNull(e).copyOf();
+
+ if (clone == e && LOG.isDebugEnabled()) {
+ LOG.debug(
+ "Failed to clone the AstElement. Returning same reference; the client may fail. {} - {}",
+ e.getClass().getName(), e);
+ }
+
+ return clone;
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeImpl.java Wed Oct 21 15:19:15 2015
@@ -95,4 +95,8 @@ public class ChildNodeImpl extends Const
}
}
+ @Override
+ public AstElement copyOf() {
+ return new ChildNodeImpl(selectorName, parentPath);
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeJoinConditionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeJoinConditionImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeJoinConditionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeJoinConditionImpl.java Wed Oct 21 15:19:15 2015
@@ -103,4 +103,8 @@ public class ChildNodeJoinConditionImpl
return available.contains(childSelector) && available.contains(parentSelector);
}
+ @Override
+ public AstElement copyOf() {
+ return new ChildNodeJoinConditionImpl(childSelectorName, parentSelectorName);
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ColumnImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ColumnImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ColumnImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ColumnImpl.java Wed Oct 21 15:19:15 2015
@@ -67,4 +67,8 @@ public class ColumnImpl extends AstEleme
return selector;
}
+ @Override
+ public AstElement copyOf() {
+ return new ColumnImpl(selectorName, propertyName, columnName);
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java Wed Oct 21 15:19:15 2015
@@ -30,12 +30,15 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.query.fulltext.LikePattern;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
import org.apache.jackrabbit.oak.spi.query.PropertyValues;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A comparison operation (including "like").
*/
public class ComparisonImpl extends ConstraintImpl {
-
+ private static final Logger LOG = LoggerFactory.getLogger(ComparisonImpl.class);
+
private final DynamicOperandImpl operand1;
private final Operator operator;
private final StaticOperandImpl operand2;
@@ -195,4 +198,8 @@ public class ComparisonImpl extends Cons
}
}
+ @Override
+ public AstElement copyOf() {
+ return new ComparisonImpl(operand1.createCopy(), operator, operand2);
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ConstraintImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ConstraintImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ConstraintImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ConstraintImpl.java Wed Oct 21 15:19:15 2015
@@ -16,8 +16,13 @@
*/
package org.apache.jackrabbit.oak.query.ast;
+import java.util.Collections;
+import java.util.List;
import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
import org.apache.jackrabbit.oak.query.fulltext.FullTextExpression;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
@@ -135,5 +140,35 @@ public abstract class ConstraintImpl ext
public int hashCode() {
return toString().hashCode();
}
-
+
+ /**
+ *
+ * @return the list of {@link ConstraintImpl} that the current constraint could hold. Default
+ * implementation returns {@code null}.
+ */
+ @Nullable
+ public List<ConstraintImpl> getConstraints() {
+ return null;
+ }
+
+ /**
+ * <p>
+ * Compute a Set of sub-constraints that could be used for composing UNION statements. For
+ * example in case of {@code OR (c1, c2)} it will return to the caller {@code [c1, c2]}. Those
+ * can be later on used for re-composing conditions.
+ * </p>
+ * <p>
+ * If no union optimisations are possible it must return an empty set.
+ * </p>
+ * <p>
+ * Default implementation in {@link ConstraintImpl#simplifyForUnion()} always return an empty
+ * set.
+ * </p>
+ *
+ * @return
+ */
+ @Nonnull
+ public Set<ConstraintImpl> simplifyForUnion() {
+ return Collections.emptySet();
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeImpl.java Wed Oct 21 15:19:15 2015
@@ -92,4 +92,8 @@ public class DescendantNodeImpl extends
}
}
+ @Override
+ public AstElement copyOf() {
+ return new DescendantNodeImpl(selectorName, ancestorPath);
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeJoinConditionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeJoinConditionImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeJoinConditionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DescendantNodeJoinConditionImpl.java Wed Oct 21 15:19:15 2015
@@ -97,4 +97,9 @@ public class DescendantNodeJoinCondition
return available.contains(descendantSelector) && available.contains(ancestorSelector);
}
+ @Override
+ public AstElement copyOf() {
+ return new DescendantNodeJoinConditionImpl(descendantSelectorName, ancestorSelectorName);
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java Wed Oct 21 15:19:15 2015
@@ -172,4 +172,8 @@ public class EquiJoinConditionImpl exten
return available.contains(selector1) && available.contains(selector2);
}
+ @Override
+ public AstElement copyOf() {
+ return new EquiJoinConditionImpl(selector1Name, property1Name, selector2Name, property2Name);
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java Wed Oct 21 15:19:15 2015
@@ -303,4 +303,9 @@ public class FullTextSearchImpl extends
void restrictPropertyOnFilter(String propertyName, FilterImpl f) {
f.restrictProperty(propertyName, Operator.NOT_EQUAL, null);
}
+
+ @Override
+ public AstElement copyOf() {
+ return new FullTextSearchImpl(selectorName, propertyName, fullTextSearchExpression);
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/InImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/InImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/InImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/InImpl.java Wed Oct 21 15:19:15 2015
@@ -179,4 +179,8 @@ public class InImpl extends ConstraintIm
return operand1.hashCode();
}
+ @Override
+ public AstElement copyOf() {
+ return new InImpl(operand1.createCopy(), operand2);
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java Wed Oct 21 15:19:15 2015
@@ -13,6 +13,8 @@
*/
package org.apache.jackrabbit.oak.query.ast;
+import static org.apache.jackrabbit.oak.query.ast.AstElementFactory.copyElementAndCheckReference;
+
import java.util.ArrayList;
import java.util.List;
@@ -27,7 +29,6 @@ import org.apache.jackrabbit.oak.spi.sta
* source, the join type, and the join condition.
*/
public class JoinImpl extends SourceImpl {
-
private final JoinConditionImpl joinCondition;
private JoinType joinType;
private SourceImpl left;
@@ -285,4 +286,13 @@ public class JoinImpl extends SourceImpl
return -1;
}
+ @Override
+ public AstElement copyOf() {
+ return new JoinImpl(
+ (SourceImpl) copyElementAndCheckReference(left),
+ (SourceImpl) copyElementAndCheckReference(right),
+ joinType,
+ (JoinConditionImpl) copyElementAndCheckReference(joinCondition)
+ );
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NativeFunctionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NativeFunctionImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NativeFunctionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NativeFunctionImpl.java Wed Oct 21 15:19:15 2015
@@ -107,4 +107,8 @@ public class NativeFunctionImpl extends
return nativeSearchExpression;
}
+ @Override
+ public AstElement copyOf() {
+ return new NativeFunctionImpl(selectorName, language, nativeSearchExpression);
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NotImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NotImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NotImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NotImpl.java Wed Oct 21 15:19:15 2015
@@ -18,6 +18,9 @@
*/
package org.apache.jackrabbit.oak.query.ast;
+import static com.google.common.collect.Lists.newArrayList;
+import static org.apache.jackrabbit.oak.query.ast.AstElementFactory.copyElementAndCheckReference;
+
import java.util.Collections;
import java.util.Set;
@@ -110,4 +113,8 @@ public class NotImpl extends ConstraintI
// TODO convert NOT conditions
}
+ @Override
+ public AstElement copyOf() {
+ return new NotImpl((ConstraintImpl) copyElementAndCheckReference(constraint));
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/OrImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/OrImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/OrImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/OrImpl.java Wed Oct 21 15:19:15 2015
@@ -23,6 +23,7 @@ import static com.google.common.collect.
import static com.google.common.collect.Maps.newLinkedHashMap;
import static com.google.common.collect.Sets.newHashSet;
import static com.google.common.collect.Sets.newLinkedHashSet;
+import static org.apache.jackrabbit.oak.query.ast.AstElementFactory.copyElementAndCheckReference;
import static org.apache.jackrabbit.oak.query.ast.Operator.EQUAL;
import java.util.Arrays;
@@ -37,6 +38,8 @@ import org.apache.jackrabbit.oak.query.f
import org.apache.jackrabbit.oak.query.fulltext.FullTextOr;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import com.google.common.collect.Sets;
+
/**
* An "or" condition.
*/
@@ -53,6 +56,7 @@ public class OrImpl extends ConstraintIm
this(Arrays.asList(constraint1, constraint2));
}
+ @Override
public List<ConstraintImpl> getConstraints() {
return constraints;
}
@@ -345,4 +349,26 @@ public class OrImpl extends ConstraintIm
return constraints.hashCode();
}
+ @Override
+ public AstElement copyOf() {
+ List<ConstraintImpl> clone = newArrayList();
+ for (ConstraintImpl c : constraints) {
+ clone.add((ConstraintImpl) copyElementAndCheckReference(c));
+ }
+ return new OrImpl(clone);
+ }
+
+ @Override
+ public Set<ConstraintImpl> simplifyForUnion() {
+ Set<ConstraintImpl> cc = Sets.newHashSet();
+ for (ConstraintImpl c : getConstraints()) {
+ Set<ConstraintImpl> ccc = c.simplifyForUnion();
+ if (ccc.isEmpty()) {
+ cc.add(c);
+ } else {
+ cc.addAll(ccc);
+ }
+ }
+ return cc;
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyExistenceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyExistenceImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyExistenceImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyExistenceImpl.java Wed Oct 21 15:19:15 2015
@@ -114,4 +114,8 @@ public class PropertyExistenceImpl exten
return a == null || b == null ? a == b : a.equals(b);
}
+ @Override
+ public AstElement copyOf() {
+ return new PropertyExistenceImpl(selectorName, propertyName);
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyInexistenceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyInexistenceImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyInexistenceImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyInexistenceImpl.java Wed Oct 21 15:19:15 2015
@@ -165,4 +165,8 @@ public class PropertyInexistenceImpl ext
return a == null || b == null ? a == b : a.equals(b);
}
+ @Override
+ public AstElement copyOf() {
+ return new PropertyInexistenceImpl(selectorName, propertyName);
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java Wed Oct 21 15:19:15 2015
@@ -155,5 +155,4 @@ public class PropertyValueImpl extends D
public PropertyValueImpl createCopy() {
return new PropertyValueImpl(selectorName, propertyName);
}
-
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SameNodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SameNodeImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SameNodeImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SameNodeImpl.java Wed Oct 21 15:19:15 2015
@@ -84,4 +84,8 @@ public class SameNodeImpl extends Constr
}
}
+ @Override
+ public AstElement copyOf() {
+ return new SameNodeImpl(selectorName, path);
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java Wed Oct 21 15:19:15 2015
@@ -786,5 +786,9 @@ public class SelectorImpl extends Source
}
return cursor.getSize(precision, max);
}
-
+
+ @Override
+ public SourceImpl copyOf() {
+ return new SelectorImpl(nodeType, selectorName);
+ }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SimilarImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SimilarImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SimilarImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SimilarImpl.java Wed Oct 21 15:19:15 2015
@@ -127,4 +127,9 @@ public class SimilarImpl extends Constra
return pathExpression;
}
+ @Override
+ public AstElement copyOf() {
+ return new SimilarImpl(selectorName, propertyName, pathExpression);
+ }
+
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java Wed Oct 21 15:19:15 2015
@@ -170,5 +170,4 @@ public abstract class SourceImpl extends
* @return the size, or -1 if unknown
*/
public abstract long getSize(SizePrecision precision, long max);
-
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SpellcheckImpl.java Wed Oct 21 15:19:15 2015
@@ -114,4 +114,9 @@ public class SpellcheckImpl extends Cons
return expression;
}
+ @Override
+ public AstElement copyOf() {
+ return new SpellcheckImpl(selectorName, expression);
+ }
+
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SuggestImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SuggestImpl.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SuggestImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SuggestImpl.java Wed Oct 21 15:19:15 2015
@@ -114,4 +114,8 @@ public class SuggestImpl extends Constra
return expression;
}
+ @Override
+ public AstElement copyOf() {
+ return new SuggestImpl(selectorName, expression);
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java Wed Oct 21 15:19:15 2015
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("2.3")
+@Version("2.4")
@Export(optional = "provide:=true")
package org.apache.jackrabbit.oak.query;
Copied: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/MultiPropertyOrTestOptimisation.java (from r1709862, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/MultiPropertyOrTestOptimisation.java?p2=jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/MultiPropertyOrTestOptimisation.java&p1=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java&r1=1709862&r2=1709863&rev=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/MultiPropertyOrTestOptimisation.java Wed Oct 21 15:19:15 2015
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,9 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("2.3")
-@Export(optional = "provide:=true")
-package org.apache.jackrabbit.oak.query;
+package org.apache.jackrabbit.oak.plugins.index.property;
-import aQute.bnd.annotation.Version;
-import aQute.bnd.annotation.Export;
+import static org.apache.jackrabbit.oak.query.QueryEngineImpl.ForceOptimised.OPTIMISED;
+
+import org.junit.Before;
+
+/**
+ * should be executing the {@link MultiPropertyOrTest} by forcing the optimisation in place.
+ */
+public class MultiPropertyOrTestOptimisation extends MultiPropertyOrTest {
+
+ @Override
+ @Before
+ public void before() throws Exception {
+ super.before();
+ setForceOptimised(OPTIMISED);
+ setTraversalEnabled(false);
+ }
+}
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTest.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTest.java Wed Oct 21 15:19:15 2015
@@ -52,13 +52,23 @@ public class PropertyIndexQueryTest exte
@Override
protected ContentRepository createRepository() {
- return new Oak().with(new InitialContent())
- .with(new OpenSecurityProvider())
- .with(new PropertyIndexProvider())
- .with(new PropertyIndexEditorProvider())
- .createContentRepository();
+ return getOakRepositoryInstance().createContentRepository();
}
+ /**
+ * return an instance of {@link Oak} repository ready to be built with
+ * {@link Oak#createContentRepository()}.
+ *
+ * @return
+ */
+ @Nonnull
+ Oak getOakRepositoryInstance() {
+ return new Oak().with(new InitialContent())
+ .with(new OpenSecurityProvider())
+ .with(new PropertyIndexProvider())
+ .with(new PropertyIndexEditorProvider());
+ }
+
@Test
public void nativeQuery() throws Exception {
test("sql2_native.txt");
Copied: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTestSQL2Optimisations.java (from r1709862, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTestSQL2Optimisations.java?p2=jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTestSQL2Optimisations.java&p1=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java&r1=1709862&r2=1709863&rev=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTestSQL2Optimisations.java Wed Oct 21 15:19:15 2015
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,9 +14,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("2.3")
-@Export(optional = "provide:=true")
-package org.apache.jackrabbit.oak.query;
+package org.apache.jackrabbit.oak.plugins.index.property;
-import aQute.bnd.annotation.Version;
-import aQute.bnd.annotation.Export;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+
+/**
+ * checks the same as {@link PropertyIndexQueryTest} enabling the feature for optimising SQL2
+ * statements.
+ */
+public class PropertyIndexQueryTestSQL2Optimisations extends PropertyIndexQueryTest {
+
+ @Override
+ Oak getOakRepositoryInstance() {
+ return super.getOakRepositoryInstance()
+ .with(new QueryEngineSettings() {
+ @Override
+ public boolean isSql2Optimisation() {
+ return true;
+ }
+ });
+ }
+}
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java?rev=1709863&r1=1709862&r2=1709863&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java Wed Oct 21 15:19:15 2015
@@ -32,6 +32,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import javax.annotation.Nonnull;
import javax.jcr.PropertyType;
import com.google.common.collect.Lists;
@@ -55,9 +56,11 @@ import org.apache.jackrabbit.oak.json.Ty
import org.apache.jackrabbit.oak.plugins.memory.BooleanPropertyState;
import org.apache.jackrabbit.oak.plugins.memory.StringPropertyState;
import org.apache.jackrabbit.oak.plugins.value.Conversions;
+import org.apache.jackrabbit.oak.query.QueryEngineImpl.ForceOptimised;
import org.apache.jackrabbit.oak.query.xpath.XPathToSQL2Converter;
import org.junit.Before;
+import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.jackrabbit.oak.api.QueryEngine.NO_BINDINGS;
import static org.apache.jackrabbit.oak.api.QueryEngine.NO_MAPPINGS;
import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
@@ -308,18 +311,27 @@ public abstract class AbstractQueryTest
protected List<String> assertQuery(String sql, String language,
List<String> expected, boolean skipSort) {
List<String> paths = executeQuery(sql, language, true, skipSort);
- for (String p : expected) {
- assertTrue("Expected path " + p + " not found, got " + paths, paths.contains(p));
- }
- assertEquals("Result set size is different", expected.size(),
- paths.size());
+ assertResult(expected, paths);
return paths;
}
+
+ protected static void assertResult(@Nonnull List<String> expected, @Nonnull List<String> actual) {
+ for (String p : checkNotNull(expected)) {
+ assertTrue("Expected path " + p + " not found, got " + actual, checkNotNull(actual)
+ .contains(p));
+ }
+ assertEquals("Result set size is different", expected.size(),
+ actual.size());
+ }
protected void setTraversalEnabled(boolean traversalEnabled) {
((QueryEngineImpl) qe).setTraversalEnabled(traversalEnabled);
}
+
+ protected void setForceOptimised(@Nonnull ForceOptimised forceOptimised) {
+ ((QueryEngineImpl) qe).setForceOptimised(checkNotNull(forceOptimised));
+ }
protected static String readRow(ResultRow row, boolean pathOnly) {
if (pathOnly) {
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryCostOverheadTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryCostOverheadTest.java?rev=1709863&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryCostOverheadTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryCostOverheadTest.java Wed Oct 21 15:19:15 2015
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.query;
+
+import static com.google.common.collect.ImmutableList.of;
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.jackrabbit.oak.query.ast.AndImpl;
+import org.apache.jackrabbit.oak.query.ast.ComparisonImpl;
+import org.apache.jackrabbit.oak.query.ast.ConstraintImpl;
+import org.apache.jackrabbit.oak.query.ast.DescendantNodeImpl;
+import org.apache.jackrabbit.oak.query.ast.FullTextSearchImpl;
+import org.apache.jackrabbit.oak.query.ast.OrImpl;
+import org.junit.Test;
+
+public class QueryCostOverheadTest {
+ @Test
+ public void getCostOverhead() {
+ final double allowedDelta = 10;
+ QueryImpl query;
+ UnionQueryImpl union;
+ ConstraintImpl c, c1, c2, c3, c4, c5;
+
+ union = new UnionQueryImpl(false, null, null, null);
+ assertEquals("we always expect 0 from a `UnionQueryImpl`", 0, union.getCostOverhead(),
+ allowedDelta);
+
+ c = mock(OrImpl.class);
+ c1 = mock(ComparisonImpl.class);
+ c2 = mock(FullTextSearchImpl.class);
+ when(c.getConstraints()).thenReturn(of(c1, c2));
+ query = new QueryImpl(null, null, c, null, null, null);
+ assertEquals(Double.MAX_VALUE, query.getCostOverhead(), allowedDelta);
+
+ c = mock(OrImpl.class);
+ c1 = mock(ComparisonImpl.class);
+ c2 = mock(FullTextSearchImpl.class);
+ c3 = mock(FullTextSearchImpl.class);
+ when(c.getConstraints()).thenReturn(of(c1, c2, c3));
+ query = new QueryImpl(null, null, c, null, null, null);
+ assertEquals(Double.MAX_VALUE, query.getCostOverhead(), allowedDelta);
+
+ c1 = mock(OrImpl.class);
+ c2 = mock(FullTextSearchImpl.class);
+ c3 = mock(FullTextSearchImpl.class);
+ c4 = mock(ComparisonImpl.class);
+ when(c1.getConstraints()).thenReturn(of(c2, c3, c4));
+ c = mock(AndImpl.class);
+ c5 = mock(DescendantNodeImpl.class);
+ when(c.getConstraints()).thenReturn(of(c1, c5));
+ query = new QueryImpl(null, null, c, null, null, null);
+ assertEquals(Double.MAX_VALUE, query.getCostOverhead(), allowedDelta);
+
+ c = mock(FullTextSearchImpl.class);
+ query = new QueryImpl(null, null, c, null, null, null);
+ assertEquals(0, query.getCostOverhead(), allowedDelta);
+
+ c = mock(OrImpl.class);
+ c1 = mock(FullTextSearchImpl.class);
+ c2 = mock(FullTextSearchImpl.class);
+ c3 = mock(FullTextSearchImpl.class);
+ when(c.getConstraints()).thenReturn(of(c1, c2, c3));
+ query = new QueryImpl(null, null, c, null, null, null);
+ assertEquals(0, query.getCostOverhead(), allowedDelta);
+
+ c = mock(AndImpl.class);
+ c1 = mock(ComparisonImpl.class);
+ c2 = mock(FullTextSearchImpl.class);
+ c3 = mock(FullTextSearchImpl.class);
+ when(c.getConstraints()).thenReturn(of(c1, c2, c3));
+ query = new QueryImpl(null, null, c, null, null, null);
+ assertEquals(0, query.getCostOverhead(), allowedDelta);
+
+ c = mock(AndImpl.class);
+ c1 = mock(ComparisonImpl.class);
+ c2 = mock(ComparisonImpl.class);
+ when(c.getConstraints()).thenReturn(of(c1, c2, c3));
+ query = new QueryImpl(null, null, c, null, null, null);
+ assertEquals(0, query.getCostOverhead(), allowedDelta);
+
+ c2 = mock(ComparisonImpl.class);
+ query = new QueryImpl(null, null, c, null, null, null);
+ assertEquals(0, query.getCostOverhead(), allowedDelta);
+ }
+}