summaryrefslogtreecommitdiff
path: root/src/main/java/com/amazon/carbonado/qe
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/amazon/carbonado/qe')
-rw-r--r--src/main/java/com/amazon/carbonado/qe/FullScanIndexedQueryExecutor.java96
-rw-r--r--src/main/java/com/amazon/carbonado/qe/FullScanQueryExecutor.java4
-rw-r--r--src/main/java/com/amazon/carbonado/qe/IndexedQueryAnalyzer.java26
-rw-r--r--src/main/java/com/amazon/carbonado/qe/IndexedQueryExecutor.java34
-rw-r--r--src/main/java/com/amazon/carbonado/qe/KeyQueryExecutor.java6
-rw-r--r--src/main/java/com/amazon/carbonado/qe/OrderingList.java13
-rw-r--r--src/main/java/com/amazon/carbonado/qe/RepositoryAccess.java4
-rw-r--r--src/main/java/com/amazon/carbonado/qe/SortedQueryExecutor.java8
-rw-r--r--src/main/java/com/amazon/carbonado/qe/StorageAccess.java1
-rw-r--r--src/main/java/com/amazon/carbonado/qe/UnionQueryAnalyzer.java123
-rw-r--r--src/main/java/com/amazon/carbonado/qe/UnionQueryExecutor.java27
11 files changed, 169 insertions, 173 deletions
diff --git a/src/main/java/com/amazon/carbonado/qe/FullScanIndexedQueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/FullScanIndexedQueryExecutor.java
deleted file mode 100644
index cfd012b..0000000
--- a/src/main/java/com/amazon/carbonado/qe/FullScanIndexedQueryExecutor.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
- * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
- * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.amazon.carbonado.qe;
-
-import java.io.IOException;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import com.amazon.carbonado.Cursor;
-import com.amazon.carbonado.FetchException;
-import com.amazon.carbonado.Storable;
-
-import com.amazon.carbonado.filter.Filter;
-import com.amazon.carbonado.filter.FilterValues;
-
-import com.amazon.carbonado.info.OrderedProperty;
-import com.amazon.carbonado.info.StorableIndex;
-
-/**
- * QueryExecutor which fully scans all Storables of a given type, referencing
- * an index.
- *
- * @author Brian S O'Neill
- */
-public class FullScanIndexedQueryExecutor<S extends Storable> extends AbstractQueryExecutor<S> {
- private final Support<S> mSupport;
- private final StorableIndex<S> mIndex;
-
- /**
- * @param support support for full scan
- * @param index index to use, which may be a primary key index
- * @throws IllegalArgumentException if support or index is null
- */
- public FullScanIndexedQueryExecutor(Support<S> support, StorableIndex<S> index) {
- if (support == null || index == null) {
- throw new IllegalArgumentException();
- }
- mSupport = support;
- mIndex = index;
- }
-
- /**
- * Returns an open filter.
- */
- public Filter<S> getFilter() {
- return Filter.getOpenFilter(mIndex.getStorableType());
- }
-
- public Cursor<S> fetch(FilterValues<S> values) throws FetchException {
- return mSupport.fetch(mIndex);
- }
-
- /**
- * Returns the natural order of the index.
- */
- public OrderingList<S> getOrdering() {
- return OrderingList.get(mIndex.getOrderedProperties());
- }
-
- public boolean printPlan(Appendable app, int indentLevel, FilterValues<S> values)
- throws IOException
- {
- indent(app, indentLevel);
- app.append("full index scan: ");
- app.append(mIndex.getStorableType().getName());
- newline(app);
- return true;
- }
-
- public static interface Support<S extends Storable> {
- /**
- * Perform a full scan of all Storables referenced by an index.
- *
- * @param index index to scan, which may be a primary key index
- */
- Cursor<S> fetch(StorableIndex<S> index) throws FetchException;
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/qe/FullScanQueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/FullScanQueryExecutor.java
index 2875542..dbf5690 100644
--- a/src/main/java/com/amazon/carbonado/qe/FullScanQueryExecutor.java
+++ b/src/main/java/com/amazon/carbonado/qe/FullScanQueryExecutor.java
@@ -59,7 +59,7 @@ public class FullScanQueryExecutor<S extends Storable> extends AbstractQueryExec
}
public Cursor<S> fetch(FilterValues<S> values) throws FetchException {
- return mSupport.fetch();
+ return mSupport.fetchAll();
}
/**
@@ -85,6 +85,6 @@ public class FullScanQueryExecutor<S extends Storable> extends AbstractQueryExec
/**
* Perform a full scan of all Storables.
*/
- Cursor<S> fetch() throws FetchException;
+ Cursor<S> fetchAll() throws FetchException;
}
}
diff --git a/src/main/java/com/amazon/carbonado/qe/IndexedQueryAnalyzer.java b/src/main/java/com/amazon/carbonado/qe/IndexedQueryAnalyzer.java
index 9b46227..76f0b52 100644
--- a/src/main/java/com/amazon/carbonado/qe/IndexedQueryAnalyzer.java
+++ b/src/main/java/com/amazon/carbonado/qe/IndexedQueryAnalyzer.java
@@ -83,8 +83,10 @@ public class IndexedQueryAnalyzer<S extends Storable> {
* @param ordering optional properties which define desired ordering
* @throws IllegalArgumentException if filter is not supported
*/
- public Result analyze(Filter<S> filter, OrderingList<S> ordering) {
- if (!filter.isBound()) {
+ public Result analyze(Filter<S> filter, OrderingList<S> ordering)
+ throws SupportException, RepositoryException
+ {
+ if (filter != null && !filter.isBound()) {
throw new IllegalArgumentException("Filter must be bound");
}
@@ -151,7 +153,9 @@ public class IndexedQueryAnalyzer<S extends Storable> {
/**
* @return null if no foreign indexes for property
*/
- private synchronized ForeignIndexes<S> getForeignIndexes(ChainedProperty<S> chainedProp) {
+ private synchronized ForeignIndexes<S> getForeignIndexes(ChainedProperty<S> chainedProp)
+ throws SupportException, RepositoryException
+ {
// Remove the last property as it is expected to be a simple storable
// property instead of a joined Storable.
chainedProp = chainedProp.trim();
@@ -198,7 +202,9 @@ public class IndexedQueryAnalyzer<S extends Storable> {
* Checks if the property is a join and its internal properties are fully
* indexed.
*/
- private boolean isProperJoin(StorableProperty<?> property) {
+ private boolean isProperJoin(StorableProperty<?> property)
+ throws SupportException, RepositoryException
+ {
if (!property.isJoin() || property.isQuery()) {
return false;
}
@@ -227,7 +233,9 @@ public class IndexedQueryAnalyzer<S extends Storable> {
return false;
}
- private <F extends Storable> boolean simpleAnalyze(Filter<F> filter) {
+ private <F extends Storable> boolean simpleAnalyze(Filter<F> filter)
+ throws SupportException, RepositoryException
+ {
Collection<StorableIndex<F>> indexes = indexesFor(filter.getStorableType());
if (indexes != null) {
@@ -242,7 +250,9 @@ public class IndexedQueryAnalyzer<S extends Storable> {
return false;
}
- private <T extends Storable> Collection<StorableIndex<T>> indexesFor(Class<T> type) {
+ private <T extends Storable> Collection<StorableIndex<T>> indexesFor(Class<T> type)
+ throws SupportException, RepositoryException
+ {
return mRepoAccess.storageAccessFor(type).getAllIndexes();
}
@@ -509,10 +519,6 @@ public class IndexedQueryAnalyzer<S extends Storable> {
{
CompositeScore score = getCompositeScore();
FilteringScore fScore = score.getFilteringScore();
-
- if (!fScore.hasAnyMatches()) {
- return new FullScanIndexedQueryExecutor<T>(access, index);
- }
if (fScore.isKeyMatch()) {
return new KeyQueryExecutor<T>(access, index, fScore);
}
diff --git a/src/main/java/com/amazon/carbonado/qe/IndexedQueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/IndexedQueryExecutor.java
index f8d2b23..d87740b 100644
--- a/src/main/java/com/amazon/carbonado/qe/IndexedQueryExecutor.java
+++ b/src/main/java/com/amazon/carbonado/qe/IndexedQueryExecutor.java
@@ -52,6 +52,7 @@ public class IndexedQueryExecutor<S extends Storable> extends AbstractQueryExecu
private final Support<S> mSupport;
private final StorableIndex<S> mIndex;
+ private final int mIdentityCount;
private final Filter<S> mIdentityFilter;
private final List<PropertyFilter<S>> mExclusiveRangeStartFilters;
private final List<PropertyFilter<S>> mInclusiveRangeStartFilters;
@@ -78,6 +79,7 @@ public class IndexedQueryExecutor<S extends Storable> extends AbstractQueryExecu
FilteringScore<S> fScore = score.getFilteringScore();
+ mIdentityCount = fScore.getIdentityCount();
mIdentityFilter = fScore.getIdentityFilter();
mExclusiveRangeStartFilters = fScore.getExclusiveRangeStartFilters();
mInclusiveRangeStartFilters = fScore.getInclusiveRangeStartFilters();
@@ -152,11 +154,11 @@ public class IndexedQueryExecutor<S extends Storable> extends AbstractQueryExecu
}
}
- return mSupport.fetch(mIndex, identityValues,
- rangeStartBoundary, rangeStartValue,
- rangeEndBoundary, rangeEndValue,
- mReverseRange,
- mReverseOrder);
+ return mSupport.fetchSubset(mIndex, identityValues,
+ rangeStartBoundary, rangeStartValue,
+ rangeEndBoundary, rangeEndValue,
+ mReverseRange,
+ mReverseOrder);
}
public Filter<S> getFilter() {
@@ -179,7 +181,11 @@ public class IndexedQueryExecutor<S extends Storable> extends AbstractQueryExecu
}
public OrderingList<S> getOrdering() {
- return OrderingList.get(mIndex.getOrderedProperties());
+ OrderingList<S> list = OrderingList.get(mIndex.getOrderedProperties());
+ if (mIdentityCount > 0) {
+ list = OrderingList.get(list.subList(mIdentityCount, list.size()));
+ }
+ return list;
}
public boolean printPlan(Appendable app, int indentLevel, FilterValues<S> values)
@@ -261,14 +267,14 @@ public class IndexedQueryExecutor<S extends Storable> extends AbstractQueryExecu
* @param reverseOrder when true, iteration should be reversed from its
* natural order
*/
- Cursor<S> fetch(StorableIndex<S> index,
- Object[] identityValues,
- BoundaryType rangeStartBoundary,
- Object rangeStartValue,
- BoundaryType rangeEndBoundary,
- Object rangeEndValue,
- boolean reverseRange,
- boolean reverseOrder)
+ Cursor<S> fetchSubset(StorableIndex<S> index,
+ Object[] identityValues,
+ BoundaryType rangeStartBoundary,
+ Object rangeStartValue,
+ BoundaryType rangeEndBoundary,
+ Object rangeEndValue,
+ boolean reverseRange,
+ boolean reverseOrder)
throws FetchException;
}
}
diff --git a/src/main/java/com/amazon/carbonado/qe/KeyQueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/KeyQueryExecutor.java
index acde1a8..d8436c0 100644
--- a/src/main/java/com/amazon/carbonado/qe/KeyQueryExecutor.java
+++ b/src/main/java/com/amazon/carbonado/qe/KeyQueryExecutor.java
@@ -69,7 +69,7 @@ public class KeyQueryExecutor<S extends Storable> extends AbstractQueryExecutor<
}
public Cursor<S> fetch(FilterValues<S> values) throws FetchException {
- return mSupport.fetch(mIndex, values.getValuesFor(mKeyFilter));
+ return mSupport.fetchOne(mIndex, values.getValuesFor(mKeyFilter));
}
public Filter<S> getFilter() {
@@ -87,7 +87,7 @@ public class KeyQueryExecutor<S extends Storable> extends AbstractQueryExecutor<
throws IOException
{
indent(app, indentLevel);
- app.append("index key: ");
+ app.append("index key match: ");
app.append(mIndex.getStorableType().getName());
newline(app);
indent(app, indentLevel);
@@ -110,7 +110,7 @@ public class KeyQueryExecutor<S extends Storable> extends AbstractQueryExecutor<
* @param index index to open, which may be a primary key index
* @param identityValues of exactly matching values to apply to index
*/
- Cursor<S> fetch(StorableIndex<S> index, Object[] identityValues)
+ Cursor<S> fetchOne(StorableIndex<S> index, Object[] identityValues)
throws FetchException;
}
}
diff --git a/src/main/java/com/amazon/carbonado/qe/OrderingList.java b/src/main/java/com/amazon/carbonado/qe/OrderingList.java
index 08a39f5..f6366e5 100644
--- a/src/main/java/com/amazon/carbonado/qe/OrderingList.java
+++ b/src/main/java/com/amazon/carbonado/qe/OrderingList.java
@@ -97,6 +97,19 @@ public class OrderingList<S extends Storable> extends AbstractList<OrderedProper
return list;
}
+ /**
+ * Returns a canonical instance composed of the given orderings.
+ */
+ public static <S extends Storable> OrderingList<S> get(List<OrderedProperty<S>> orderings) {
+ OrderingList<S> list = emptyList();
+ if (orderings != null && orderings.size() > 0) {
+ for (OrderedProperty<S> property : orderings) {
+ list = list.concat(property);
+ }
+ }
+ return list;
+ }
+
private static <S extends Storable> OrderingList<S> getListHead(Class<S> type) {
OrderingList<S> node;
synchronized (cCache) {
diff --git a/src/main/java/com/amazon/carbonado/qe/RepositoryAccess.java b/src/main/java/com/amazon/carbonado/qe/RepositoryAccess.java
index 6e3c3de..cb25afd 100644
--- a/src/main/java/com/amazon/carbonado/qe/RepositoryAccess.java
+++ b/src/main/java/com/amazon/carbonado/qe/RepositoryAccess.java
@@ -20,6 +20,7 @@ package com.amazon.carbonado.qe;
import com.amazon.carbonado.MalformedTypeException;
import com.amazon.carbonado.Repository;
+import com.amazon.carbonado.RepositoryException;
import com.amazon.carbonado.Storable;
import com.amazon.carbonado.SupportException;
@@ -40,5 +41,6 @@ public interface RepositoryAccess {
* @throws IllegalArgumentException if specified type is null
* @throws MalformedTypeException if specified type is not suitable
*/
- <S extends Storable> StorageAccess<S> storageAccessFor(Class<S> type);
+ <S extends Storable> StorageAccess<S> storageAccessFor(Class<S> type)
+ throws SupportException, RepositoryException;
}
diff --git a/src/main/java/com/amazon/carbonado/qe/SortedQueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/SortedQueryExecutor.java
index 7b12e43..cae03d8 100644
--- a/src/main/java/com/amazon/carbonado/qe/SortedQueryExecutor.java
+++ b/src/main/java/com/amazon/carbonado/qe/SortedQueryExecutor.java
@@ -117,10 +117,10 @@ public class SortedQueryExecutor<S extends Storable> extends AbstractQueryExecut
throws IOException
{
indent(app, indentLevel);
- if (mHandledOrdering.size() == 0) {
- app.append("full sort: ");
- } else {
- app.append("finish sort: ");
+ app.append("sort: ");
+ if (mHandledOrdering.size() > 0) {
+ app.append(mHandledOrdering.toString());
+ app.append(", ");
}
app.append(mRemainderOrdering.toString());
newline(app);
diff --git a/src/main/java/com/amazon/carbonado/qe/StorageAccess.java b/src/main/java/com/amazon/carbonado/qe/StorageAccess.java
index 5f93952..2ab2313 100644
--- a/src/main/java/com/amazon/carbonado/qe/StorageAccess.java
+++ b/src/main/java/com/amazon/carbonado/qe/StorageAccess.java
@@ -37,7 +37,6 @@ import com.amazon.carbonado.info.StorableIndex;
*/
public interface StorageAccess<S extends Storable>
extends FullScanQueryExecutor.Support<S>,
- FullScanIndexedQueryExecutor.Support<S>,
KeyQueryExecutor.Support<S>,
IndexedQueryExecutor.Support<S>,
SortedQueryExecutor.Support<S>
diff --git a/src/main/java/com/amazon/carbonado/qe/UnionQueryAnalyzer.java b/src/main/java/com/amazon/carbonado/qe/UnionQueryAnalyzer.java
index e0d49c2..5933f6c 100644
--- a/src/main/java/com/amazon/carbonado/qe/UnionQueryAnalyzer.java
+++ b/src/main/java/com/amazon/carbonado/qe/UnionQueryAnalyzer.java
@@ -80,8 +80,10 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
* @param filter optional filter which must be {@link Filter#isBound bound}
* @param ordering optional properties which define desired ordering
*/
- public Result analyze(Filter<S> filter, OrderingList<S> ordering) {
- if (!filter.isBound()) {
+ public Result analyze(Filter<S> filter, OrderingList<S> ordering)
+ throws SupportException, RepositoryException
+ {
+ if (filter != null && !filter.isBound()) {
throw new IllegalArgumentException("Filter must be bound");
}
@@ -89,7 +91,7 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
ordering = OrderingList.emptyList();
}
- return new Result(buildSubResults(filter, ordering));
+ return buildResult(filter, ordering);
}
/**
@@ -108,14 +110,19 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
* Splits the filter into sub-results, merges sub-results, and possibly
* imposes a total ordering.
*/
- private List<IndexedQueryAnalyzer<S>.Result>
- buildSubResults(Filter<S> filter, OrderingList<S> ordering)
+ private Result buildResult(Filter<S> filter, OrderingList<S> ordering)
+ throws SupportException, RepositoryException
{
- List<IndexedQueryAnalyzer<S>.Result> subResults = splitIntoSubResults(filter, ordering);
+ List<IndexedQueryAnalyzer<S>.Result> subResults;
+ if (filter == null) {
+ subResults = Collections.singletonList(mIndexAnalyzer.analyze(filter, ordering));
+ } else {
+ subResults = splitIntoSubResults(filter, ordering);
+ }
if (subResults.size() <= 1) {
// Total ordering not required.
- return subResults;
+ return new Result(subResults);
}
// If any orderings have an unspecified direction, switch to ASCENDING
@@ -141,7 +148,7 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
if (subResults.size() <= 1) {
// Total ordering no longer required.
- return subResults;
+ return new Result(subResults);
}
}
@@ -155,7 +162,7 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
ChainedProperty<S> property = op.getChainedProperty();
if (pruneKeys(keys, property)) {
// Found a key which is fully covered, indicating total ordering.
- return subResults;
+ return new Result(subResults, ordering);
}
}
@@ -224,7 +231,7 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
}
}
- return subResults;
+ return new Result(subResults, ordering);
}
/**
@@ -272,7 +279,7 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
private Tally bestTally(Iterable<Tally> tallies) {
Tally best = null;
for (Tally tally : tallies) {
- if (best == null || tally.compareTo(best) < 0) {
+ if (best == null || tally.compareTo(best) > 0) {
best = tally;
}
}
@@ -298,12 +305,16 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
*/
private List<IndexedQueryAnalyzer<S>.Result>
splitIntoSubResults(Filter<S> filter, OrderingList<S> ordering)
+ throws SupportException, RepositoryException
{
// Required for split to work.
Filter<S> dnfFilter = filter.disjunctiveNormalForm();
Splitter splitter = new Splitter(ordering);
- dnfFilter.accept(splitter, null);
+ RepositoryException e = dnfFilter.accept(splitter, null);
+ if (e != null) {
+ throw e;
+ }
List<IndexedQueryAnalyzer<S>.Result> subResults = splitter.mSubResults;
@@ -373,7 +384,9 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
return mergedResults;
}
- Storage storageDelegate(IndexedQueryAnalyzer<S>.Result result) {
+ Storage storageDelegate(IndexedQueryAnalyzer<S>.Result result)
+ throws SupportException, RepositoryException
+ {
StorableIndex<S> localIndex = result.getLocalIndex();
StorageAccess<S> localAccess = mRepoAccess.storageAccessFor(getStorableType());
@@ -389,12 +402,18 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
public class Result {
private final List<IndexedQueryAnalyzer<S>.Result> mSubResults;
+ private final OrderingList<S> mTotalOrdering;
Result(List<IndexedQueryAnalyzer<S>.Result> subResults) {
+ this(subResults, null);
+ }
+
+ Result(List<IndexedQueryAnalyzer<S>.Result> subResults, OrderingList<S> totalOrdering) {
if (subResults.size() < 1) {
throw new IllegalArgumentException();
}
mSubResults = Collections.unmodifiableList(subResults);
+ mTotalOrdering = totalOrdering;
}
/**
@@ -406,6 +425,13 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
}
/**
+ * Returns a total ordering, if one was imposed. Otherwise, null is returned.
+ */
+ public OrderingList<S> getTotalOrdering() {
+ return mTotalOrdering;
+ }
+
+ /**
* Creates a QueryExecutor based on this result.
*/
public QueryExecutor<S> createExecutor()
@@ -423,7 +449,7 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
executors.add(subResults.get(i).createExecutor());
}
- return new UnionQueryExecutor<S>(executors);
+ return new UnionQueryExecutor<S>(executors, mTotalOrdering);
}
}
@@ -484,7 +510,7 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
}
/**
- * Returns -1 if this tally is better.
+ * Returns -1 if this tally is worse.
*/
public int compareTo(Tally other) {
int thisBest = getBestCount();
@@ -497,13 +523,20 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
}
return 0;
}
+
+ public String toString() {
+ return "Tally: {property=" + mProperty +
+ ", asc=" + mAscendingCount +
+ ", desc=" + mDescendingCount +
+ '}';
+ }
}
/**
* Analyzes a disjunctive normal filter into sub-results over filters that
* only contain 'and' operations.
*/
- private class Splitter extends Visitor<S, Object, Object> {
+ private class Splitter extends Visitor<S, RepositoryException, Object> {
private final OrderingList<S> mOrdering;
final List<IndexedQueryAnalyzer<S>.Result> mSubResults;
@@ -514,37 +547,55 @@ public class UnionQueryAnalyzer<S extends Storable> implements QueryExecutorFact
}
@Override
- public Object visit(OrFilter<S> filter, Object param) {
- Filter<S> left = filter.getLeftFilter();
- if (!(left instanceof OrFilter)) {
- subAnalyze(left);
- } else {
- left.accept(this, param);
- }
- Filter<S> right = filter.getRightFilter();
- if (!(right instanceof OrFilter)) {
- subAnalyze(right);
- } else {
- right.accept(this, param);
+ public RepositoryException visit(OrFilter<S> filter, Object param) {
+ try {
+ Filter<S> left = filter.getLeftFilter();
+ if (!(left instanceof OrFilter)) {
+ subAnalyze(left);
+ } else {
+ RepositoryException e = left.accept(this, param);
+ if (e != null) {
+ return e;
+ }
+ }
+ Filter<S> right = filter.getRightFilter();
+ if (!(right instanceof OrFilter)) {
+ subAnalyze(right);
+ } else {
+ RepositoryException e = right.accept(this, param);
+ if (e != null) {
+ return e;
+ }
+ }
+ return null;
+ } catch (RepositoryException e) {
+ return e;
}
- return null;
}
// This method should only be called if root filter has no 'or' operators.
@Override
- public Object visit(AndFilter<S> filter, Object param) {
- subAnalyze(filter);
- return null;
+ public RepositoryException visit(AndFilter<S> filter, Object param) {
+ try {
+ subAnalyze(filter);
+ return null;
+ } catch (RepositoryException e) {
+ return e;
+ }
}
// This method should only be called if root filter has no logical operators.
@Override
- public Object visit(PropertyFilter<S> filter, Object param) {
- subAnalyze(filter);
- return null;
+ public RepositoryException visit(PropertyFilter<S> filter, Object param) {
+ try {
+ subAnalyze(filter);
+ return null;
+ } catch (RepositoryException e) {
+ return e;
+ }
}
- private void subAnalyze(Filter<S> subFilter) {
+ private void subAnalyze(Filter<S> subFilter) throws SupportException, RepositoryException {
IndexedQueryAnalyzer<S>.Result subResult =
mIndexAnalyzer.analyze(subFilter, mOrdering);
diff --git a/src/main/java/com/amazon/carbonado/qe/UnionQueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/UnionQueryExecutor.java
index 5d2a5c6..47672d1 100644
--- a/src/main/java/com/amazon/carbonado/qe/UnionQueryExecutor.java
+++ b/src/main/java/com/amazon/carbonado/qe/UnionQueryExecutor.java
@@ -64,19 +64,34 @@ public class UnionQueryExecutor<S extends Storable> extends AbstractQueryExecuto
/**
* @param executors executors to wrap, each must have the exact same total ordering
- * @throws IllegalArgumentException if any parameter is null or if ordering doesn't match
+ * @throws IllegalArgumentException if any executors is null or if ordering doesn't match
*/
public UnionQueryExecutor(List<QueryExecutor<S>> executors) {
+ this(executors, null);
+ }
+
+ /**
+ * @param executors executors to wrap, each must have the exact same total ordering
+ * @param totalOrdering effective total ordering of executors
+ * @throws IllegalArgumentException if executors is null
+ */
+ public UnionQueryExecutor(List<QueryExecutor<S>> executors, OrderingList<S> totalOrdering) {
if (executors == null || executors.size() == 0) {
throw new IllegalArgumentException();
}
- OrderingList<S> totalOrdering = executors.get(0).getOrdering();
- // Compare for consistency.
- for (int i=1; i<executors.size(); i++) {
- if (!totalOrdering.equals(executors.get(i).getOrdering())) {
- throw new IllegalArgumentException("Ordering doesn't match");
+
+ if (totalOrdering == null) {
+ // Try to infer total ordering, which might not work since
+ // executors are not required to report or support total ordering.
+ totalOrdering = executors.get(0).getOrdering();
+ // Compare for consistency.
+ for (int i=1; i<executors.size(); i++) {
+ if (!totalOrdering.equals(executors.get(i).getOrdering())) {
+ throw new IllegalArgumentException("Ordering doesn't match");
+ }
}
}
+
mExecutors = new QueryExecutor[executors.size()];
executors.toArray(mExecutors);
mTotalOrdering = totalOrdering;