Refactor Restriction hierarchy patch by Benjamin Lerer; reviewed by Tyler Hobbs for CASSANDRA-11354
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/831bebdb Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/831bebdb Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/831bebdb Branch: refs/heads/trunk Commit: 831bebdba86ac1956852bd216a4cc62d898c87d7 Parents: dc569c9 Author: Benjamin Lerer <[email protected]> Authored: Fri Apr 15 21:04:25 2016 +0200 Committer: Benjamin Lerer <[email protected]> Committed: Fri Apr 15 21:13:52 2016 +0200 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../AbstractPrimaryKeyRestrictions.java | 61 - .../cql3/restrictions/AbstractRestriction.java | 108 - .../ClusteringColumnRestrictions.java | 179 ++ .../ForwardingPrimaryKeyRestrictions.java | 197 -- .../restrictions/MultiColumnRestriction.java | 34 +- .../restrictions/PartitionKeyRestrictions.java | 51 + .../PartitionKeySingleRestrictionSet.java | 132 ++ .../restrictions/PrimaryKeyRestrictionSet.java | 339 ---- .../restrictions/PrimaryKeyRestrictions.java | 46 - .../cql3/restrictions/Restriction.java | 70 +- .../cql3/restrictions/RestrictionSet.java | 85 +- .../restrictions/RestrictionSetWrapper.java | 95 + .../cql3/restrictions/Restrictions.java | 54 +- .../restrictions/SingleColumnRestriction.java | 43 +- .../cql3/restrictions/SingleRestriction.java | 117 ++ .../restrictions/StatementRestrictions.java | 62 +- .../cql3/restrictions/TokenFilter.java | 85 +- .../cql3/restrictions/TokenRestriction.java | 85 +- .../apache/cassandra/cql3/statements/Bound.java | 13 + .../ClusteringColumnRestrictionsTest.java | 1919 ++++++++++++++++++ .../PrimaryKeyRestrictionSetTest.java | 1919 ------------------ 22 files changed, 2748 insertions(+), 2947 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index c91a4cd..acbbfa5 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.6 + * Refactor Restriction hierarchy (CASSANDRA-11354) * Eliminate allocations in R/W path (CASSANDRA-11421) * Update Netty to 4.0.36 (CASSANDRA-11567) * Fix PER PARTITION LIMIT for queries requiring post-query ordering (CASSANDRA-11556) http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/AbstractPrimaryKeyRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/AbstractPrimaryKeyRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/AbstractPrimaryKeyRestrictions.java deleted file mode 100644 index f1b5a50..0000000 --- a/src/java/org/apache/cassandra/cql3/restrictions/AbstractPrimaryKeyRestrictions.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.cassandra.cql3.restrictions; - -import java.nio.ByteBuffer; -import java.util.*; - -import org.apache.cassandra.cql3.QueryOptions; -import org.apache.cassandra.cql3.statements.Bound; -import org.apache.cassandra.db.ClusteringPrefix; -import org.apache.cassandra.db.ClusteringComparator; -import org.apache.cassandra.exceptions.InvalidRequestException; - -/** - * Base class for <code>PrimaryKeyRestrictions</code>. - */ -abstract class AbstractPrimaryKeyRestrictions extends AbstractRestriction implements PrimaryKeyRestrictions -{ - /** - * The composite type. - */ - protected final ClusteringComparator comparator; - - public AbstractPrimaryKeyRestrictions(ClusteringComparator comparator) - { - this.comparator = comparator; - } - - @Override - public List<ByteBuffer> bounds(Bound b, QueryOptions options) throws InvalidRequestException - { - return values(options); - } - - @Override - public final boolean isEmpty() - { - return getColumnDefs().isEmpty(); - } - - @Override - public final int size() - { - return getColumnDefs().size(); - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/AbstractRestriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/AbstractRestriction.java b/src/java/org/apache/cassandra/cql3/restrictions/AbstractRestriction.java deleted file mode 100644 index 4d6240c..0000000 --- a/src/java/org/apache/cassandra/cql3/restrictions/AbstractRestriction.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.cassandra.cql3.restrictions; - -import org.apache.cassandra.cql3.QueryOptions; -import org.apache.cassandra.cql3.statements.Bound; -import org.apache.cassandra.db.MultiCBuilder; - -import org.apache.cassandra.config.ColumnDefinition; - -/** - * Base class for <code>Restriction</code>s - */ -abstract class AbstractRestriction implements Restriction -{ - @Override - public boolean isOnToken() - { - return false; - } - - @Override - public boolean isMultiColumn() - { - return false; - } - - @Override - public boolean isSlice() - { - return false; - } - - @Override - public boolean isEQ() - { - return false; - } - - @Override - public boolean isLIKE() - { - return false; - } - - @Override - public boolean isIN() - { - return false; - } - - @Override - public boolean isContains() - { - return false; - } - - @Override - public boolean isNotNull() - { - return false; - } - - @Override - public boolean hasBound(Bound b) - { - return true; - } - - @Override - public MultiCBuilder appendBoundTo(MultiCBuilder builder, Bound bound, QueryOptions options) - { - return appendTo(builder, options); - } - - @Override - public boolean isInclusive(Bound b) - { - return true; - } - - /** - * Reverses the specified bound if the column type is a reversed one. - * - * @param columnDefinition the column definition - * @param bound the bound - * @return the bound reversed if the column type was a reversed one or the original bound - */ - protected static Bound reverseBoundIfNeeded(ColumnDefinition columnDefinition, Bound bound) - { - return columnDefinition.isReversedType() ? bound.reverse() : bound; - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java new file mode 100644 index 0000000..47cf76b --- /dev/null +++ b/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java @@ -0,0 +1,179 @@ +/* + * 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.cassandra.cql3.restrictions; + +import java.util.*; + +import org.apache.cassandra.config.CFMetaData; +import org.apache.cassandra.config.ColumnDefinition; +import org.apache.cassandra.cql3.QueryOptions; +import org.apache.cassandra.cql3.statements.Bound; +import org.apache.cassandra.db.*; +import org.apache.cassandra.db.filter.RowFilter; +import org.apache.cassandra.exceptions.InvalidRequestException; +import org.apache.cassandra.index.SecondaryIndexManager; +import org.apache.cassandra.utils.btree.BTreeSet; + +import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse; +import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest; + +/** + * A set of restrictions on the clustering key. + */ +final class ClusteringColumnRestrictions extends RestrictionSetWrapper +{ + /** + * The composite type. + */ + protected final ClusteringComparator comparator; + + public ClusteringColumnRestrictions(CFMetaData cfm) + { + super(new RestrictionSet()); + this.comparator = cfm.comparator; + } + + private ClusteringColumnRestrictions(ClusteringComparator comparator, RestrictionSet restrictionSet) + { + super(restrictionSet); + this.comparator = comparator; + } + + public ClusteringColumnRestrictions mergeWith(Restriction restriction) throws InvalidRequestException + { + SingleRestriction newRestriction = (SingleRestriction) restriction; + RestrictionSet newRestrictionSet = restrictions.addRestriction(newRestriction); + + if (!isEmpty()) + { + SingleRestriction lastRestriction = restrictions.lastRestriction(); + ColumnDefinition lastRestrictionStart = lastRestriction.getFirstColumn(); + ColumnDefinition newRestrictionStart = restriction.getFirstColumn(); + + checkFalse(lastRestriction.isSlice() && newRestrictionStart.position() > lastRestrictionStart.position(), + "Clustering column \"%s\" cannot be restricted (preceding column \"%s\" is restricted by a non-EQ relation)", + newRestrictionStart.name, + lastRestrictionStart.name); + + if (newRestrictionStart.position() < lastRestrictionStart.position() && newRestriction.isSlice()) + throw invalidRequest("PRIMARY KEY column \"%s\" cannot be restricted (preceding column \"%s\" is restricted by a non-EQ relation)", + restrictions.nextColumn(newRestrictionStart).name, + newRestrictionStart.name); + } + + return new ClusteringColumnRestrictions(this.comparator, newRestrictionSet); + } + + private boolean hasMultiColumnSlice() + { + for (SingleRestriction restriction : restrictions) + { + if (restriction.isMultiColumn() && restriction.isSlice()) + return true; + } + return false; + } + + public NavigableSet<Clustering> valuesAsClustering(QueryOptions options) throws InvalidRequestException + { + MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN()); + for (SingleRestriction r : restrictions) + { + r.appendTo(builder, options); + if (builder.hasMissingElements()) + break; + } + return builder.build(); + } + + public NavigableSet<Slice.Bound> boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException + { + MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN() || hasMultiColumnSlice()); + int keyPosition = 0; + for (SingleRestriction r : restrictions) + { + ColumnDefinition def = r.getFirstColumn(); + + if (keyPosition != def.position() || r.isContains() || r.isLIKE()) + break; + + if (r.isSlice()) + { + r.appendBoundTo(builder, bound, options); + return builder.buildBoundForSlice(bound.isStart(), + r.isInclusive(bound), + r.isInclusive(bound.reverse()), + r.getColumnDefs()); + } + + r.appendBoundTo(builder, bound, options); + + if (builder.hasMissingElements()) + return BTreeSet.empty(comparator); + + keyPosition = r.getLastColumn().position() + 1; + } + + // Everything was an equal (or there was nothing) + return builder.buildBound(bound.isStart(), true); + } + + /** + * Checks if any of the underlying restriction is a CONTAINS or CONTAINS KEY. + * + * @return <code>true</code> if any of the underlying restriction is a CONTAINS or CONTAINS KEY, + * <code>false</code> otherwise + */ + public final boolean hasContains() + { + return restrictions.stream().anyMatch(SingleRestriction::isContains); + } + + /** + * Checks if any of the underlying restriction is a slice restrictions. + * + * @return <code>true</code> if any of the underlying restriction is a slice restrictions, + * <code>false</code> otherwise + */ + public final boolean hasSlice() + { + return restrictions.stream().anyMatch(SingleRestriction::isSlice); + } + + @Override + public void addRowFilterTo(RowFilter filter, + SecondaryIndexManager indexManager, + QueryOptions options) throws InvalidRequestException + { + int position = 0; + + for (SingleRestriction restriction : restrictions) + { + ColumnDefinition columnDef = restriction.getFirstColumn(); + + // We ignore all the clustering columns that can be handled by slices. + if (!(restriction.isContains() || restriction.isLIKE()) && position == columnDef.position()) + { + position = restriction.getLastColumn().position() + 1; + if (!restriction.hasSupportingIndex(indexManager)) + continue; + } + restriction.addRowFilterTo(filter, indexManager, options); + } + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java deleted file mode 100644 index c9cd1d2..0000000 --- a/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * 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.cassandra.cql3.restrictions; - -import java.nio.ByteBuffer; -import java.util.List; -import java.util.NavigableSet; - -import org.apache.cassandra.config.ColumnDefinition; -import org.apache.cassandra.cql3.QueryOptions; -import org.apache.cassandra.cql3.functions.Function; -import org.apache.cassandra.cql3.statements.Bound; -import org.apache.cassandra.db.Clustering; -import org.apache.cassandra.db.MultiCBuilder; -import org.apache.cassandra.db.Slice; -import org.apache.cassandra.db.filter.RowFilter; -import org.apache.cassandra.exceptions.InvalidRequestException; -import org.apache.cassandra.index.SecondaryIndexManager; - -/** - * A <code>PrimaryKeyRestrictions</code> which forwards all its method calls to another - * <code>PrimaryKeyRestrictions</code>. Subclasses should override one or more methods to modify the behavior - * of the backing <code>PrimaryKeyRestrictions</code> as desired per the decorator pattern. - */ -abstract class ForwardingPrimaryKeyRestrictions implements PrimaryKeyRestrictions -{ - /** - * Returns the backing delegate instance that methods are forwarded to. - * @return the backing delegate instance that methods are forwarded to. - */ - protected abstract PrimaryKeyRestrictions getDelegate(); - - @Override - public Iterable<Function> getFunctions() - { - return getDelegate().getFunctions(); - } - - @Override - public List<ColumnDefinition> getColumnDefs() - { - return getDelegate().getColumnDefs(); - } - - @Override - public ColumnDefinition getFirstColumn() - { - return getDelegate().getFirstColumn(); - } - - @Override - public ColumnDefinition getLastColumn() - { - return getDelegate().getLastColumn(); - } - - @Override - public PrimaryKeyRestrictions mergeWith(Restriction restriction) throws InvalidRequestException - { - return getDelegate().mergeWith(restriction); - } - - @Override - public boolean hasSupportingIndex(SecondaryIndexManager secondaryIndexManager) - { - return getDelegate().hasSupportingIndex(secondaryIndexManager); - } - - @Override - public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException - { - return getDelegate().values(options); - } - - @Override - public MultiCBuilder appendTo(MultiCBuilder builder, QueryOptions options) - { - return getDelegate().appendTo(builder, options); - } - - @Override - public NavigableSet<Clustering> valuesAsClustering(QueryOptions options) throws InvalidRequestException - { - return getDelegate().valuesAsClustering(options); - } - - @Override - public List<ByteBuffer> bounds(Bound bound, QueryOptions options) throws InvalidRequestException - { - return getDelegate().bounds(bound, options); - } - - @Override - public NavigableSet<Slice.Bound> boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException - { - return getDelegate().boundsAsClustering(bound, options); - } - - @Override - public MultiCBuilder appendBoundTo(MultiCBuilder builder, Bound bound, QueryOptions options) - { - return getDelegate().appendBoundTo(builder, bound, options); - } - - @Override - public boolean isInclusive(Bound bound) - { - return getDelegate().isInclusive(bound.reverse()); - } - - @Override - public boolean isEmpty() - { - return getDelegate().isEmpty(); - } - - @Override - public int size() - { - return getDelegate().size(); - } - - @Override - public boolean isOnToken() - { - return getDelegate().isOnToken(); - } - - @Override - public boolean isSlice() - { - return getDelegate().isSlice(); - } - - @Override - public boolean isEQ() - { - return getDelegate().isEQ(); - } - - @Override - public boolean isLIKE() - { - return getDelegate().isLIKE(); - } - - @Override - public boolean isIN() - { - return getDelegate().isIN(); - } - - @Override - public boolean isContains() - { - return getDelegate().isContains(); - } - - @Override - public boolean isNotNull() - { - return getDelegate().isNotNull(); - } - - @Override - public boolean isMultiColumn() - { - return getDelegate().isMultiColumn(); - } - - @Override - public boolean hasBound(Bound b) - { - return getDelegate().hasBound(b); - } - - @Override - public void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, QueryOptions options) throws InvalidRequestException - { - getDelegate().addRowFilterTo(filter, indexManager, options); - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java b/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java index ec02d06..f2f530d 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java @@ -27,7 +27,6 @@ import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.statements.Bound; import org.apache.cassandra.db.MultiCBuilder; import org.apache.cassandra.db.filter.RowFilter; -import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.index.Index; import org.apache.cassandra.index.SecondaryIndexManager; @@ -36,7 +35,7 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.checkNotNu import static org.apache.cassandra.cql3.statements.RequestValidations.checkTrue; import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest; -public abstract class MultiColumnRestriction extends AbstractRestriction +public abstract class MultiColumnRestriction implements SingleRestriction { /** * The columns to which the restriction apply. @@ -73,7 +72,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public final Restriction mergeWith(Restriction otherRestriction) throws InvalidRequestException + public final SingleRestriction mergeWith(SingleRestriction otherRestriction) { // We want to allow query like: (b,c) > (?, ?) AND b < ? if (!otherRestriction.isMultiColumn() @@ -85,7 +84,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction return doMergeWith(otherRestriction); } - protected abstract Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException; + protected abstract SingleRestriction doMergeWith(SingleRestriction otherRestriction); /** * Returns the names of the columns that are specified within this <code>Restrictions</code> and the other one @@ -150,7 +149,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException + public SingleRestriction doMergeWith(SingleRestriction otherRestriction) { throw invalidRequest("%s cannot be restricted by more than one relation if it includes an Equal", getColumnsInCommons(otherRestriction)); @@ -179,7 +178,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public final void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexMananger, QueryOptions options) throws InvalidRequestException + public final void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexMananger, QueryOptions options) { Tuples.Value t = ((Tuples.Value) value.bind(options)); List<ByteBuffer> values = t.getElements(); @@ -220,7 +219,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException + public SingleRestriction doMergeWith(SingleRestriction otherRestriction) { throw invalidRequest("%s cannot be restricted by more than one relation if it includes a IN", getColumnsInCommons(otherRestriction)); @@ -238,7 +237,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction @Override public final void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, - QueryOptions options) throws InvalidRequestException + QueryOptions options) { List<List<ByteBuffer>> splitInValues = splitValues(options); checkTrue(splitInValues.size() == 1, "IN restrictions are not supported on indexed columns"); @@ -251,7 +250,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } } - protected abstract List<List<ByteBuffer>> splitValues(QueryOptions options) throws InvalidRequestException; + protected abstract List<List<ByteBuffer>> splitValues(QueryOptions options); } /** @@ -281,7 +280,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - protected List<List<ByteBuffer>> splitValues(QueryOptions options) throws InvalidRequestException + protected List<List<ByteBuffer>> splitValues(QueryOptions options) { List<List<ByteBuffer>> buffers = new ArrayList<>(values.size()); for (Term value : values) @@ -320,7 +319,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - protected List<List<ByteBuffer>> splitValues(QueryOptions options) throws InvalidRequestException + protected List<List<ByteBuffer>> splitValues(QueryOptions options) { Tuples.InMarker inMarker = (Tuples.InMarker) marker; Tuples.InValue inValue = inMarker.bind(options); @@ -371,7 +370,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction for (int i = 0, m = columnDefs.size(); i < m; i++) { ColumnDefinition column = columnDefs.get(i); - Bound b = reverseBoundIfNeeded(column, bound); + Bound b = bound.reverseIfNeeded(column); // For mixed order columns, we need to create additional slices when 2 columns are in reverse order if (reversed != column.isReversedType()) @@ -445,7 +444,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException + public SingleRestriction doMergeWith(SingleRestriction otherRestriction) { checkTrue(otherRestriction.isSlice(), "Column \"%s\" cannot be restricted by both an equality and an inequality relation", @@ -476,7 +475,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction @Override public final void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, - QueryOptions options) throws InvalidRequestException + QueryOptions options) { throw invalidRequest("Slice restrictions are not supported on indexed columns"); } @@ -493,9 +492,8 @@ public abstract class MultiColumnRestriction extends AbstractRestriction * @param b the bound type * @param options the query options * @return one ByteBuffer per-component in the bound - * @throws InvalidRequestException if the components cannot be retrieved */ - private List<ByteBuffer> componentBounds(Bound b, QueryOptions options) throws InvalidRequestException + private List<ByteBuffer> componentBounds(Bound b, QueryOptions options) { if (!slice.hasBound(b)) return Collections.emptyList(); @@ -543,7 +541,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException + public SingleRestriction doMergeWith(SingleRestriction otherRestriction) { throw invalidRequest("%s cannot be restricted by a relation if it includes an IS NOT NULL clause", getColumnsInCommons(otherRestriction)); @@ -565,7 +563,7 @@ public abstract class MultiColumnRestriction extends AbstractRestriction } @Override - public final void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexMananger, QueryOptions options) throws InvalidRequestException + public final void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexMananger, QueryOptions options) { throw new UnsupportedOperationException("Secondary indexes do not support IS NOT NULL restrictions"); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeyRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeyRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeyRestrictions.java new file mode 100644 index 0000000..10efa9f --- /dev/null +++ b/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeyRestrictions.java @@ -0,0 +1,51 @@ +/* + * 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.cassandra.cql3.restrictions; + +import java.nio.ByteBuffer; +import java.util.List; + +import org.apache.cassandra.cql3.QueryOptions; +import org.apache.cassandra.cql3.statements.Bound; + +/** + * A set of restrictions on the partition key. + * + */ +interface PartitionKeyRestrictions extends Restrictions +{ + public PartitionKeyRestrictions mergeWith(Restriction restriction); + + public List<ByteBuffer> values(QueryOptions options); + + public List<ByteBuffer> bounds(Bound b, QueryOptions options); + + /** + * Checks if the specified bound is set or not. + * @param b the bound type + * @return <code>true</code> if the specified bound is set, <code>false</code> otherwise + */ + public boolean hasBound(Bound b); + + /** + * Checks if the specified bound is inclusive or not. + * @param b the bound type + * @return <code>true</code> if the specified bound is inclusive, <code>false</code> otherwise + */ + public boolean isInclusive(Bound b); +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeySingleRestrictionSet.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeySingleRestrictionSet.java b/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeySingleRestrictionSet.java new file mode 100644 index 0000000..b96f6da --- /dev/null +++ b/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeySingleRestrictionSet.java @@ -0,0 +1,132 @@ +/* + * 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.cassandra.cql3.restrictions; + +import java.nio.ByteBuffer; +import java.util.*; + +import org.apache.cassandra.config.CFMetaData; +import org.apache.cassandra.cql3.QueryOptions; +import org.apache.cassandra.cql3.statements.Bound; +import org.apache.cassandra.db.ClusteringComparator; +import org.apache.cassandra.db.ClusteringPrefix; +import org.apache.cassandra.db.MultiCBuilder; +import org.apache.cassandra.db.filter.RowFilter; +import org.apache.cassandra.index.SecondaryIndexManager; + +/** + * A set of single restrictions on the partition key. + * <p>This class can only contains <code>SingleRestriction</code> instances. Token restrictions will be handled by + * <code>TokenRestriction</code> class or by the <code>TokenFilter</code> class if the query contains a mix of token + * restrictions and single column restrictions on the partition key. + */ +final class PartitionKeySingleRestrictionSet extends RestrictionSetWrapper implements PartitionKeyRestrictions +{ + /** + * The composite type. + */ + protected final ClusteringComparator comparator; + + public PartitionKeySingleRestrictionSet(ClusteringComparator comparator) + { + super(new RestrictionSet()); + this.comparator = comparator; + } + + private PartitionKeySingleRestrictionSet(PartitionKeySingleRestrictionSet restrictionSet, + SingleRestriction restriction) + { + super(restrictionSet.restrictions.addRestriction(restriction)); + this.comparator = restrictionSet.comparator; + } + + private List<ByteBuffer> toByteBuffers(SortedSet<? extends ClusteringPrefix> clusterings) + { + List<ByteBuffer> l = new ArrayList<>(clusterings.size()); + for (ClusteringPrefix clustering : clusterings) + l.add(CFMetaData.serializePartitionKey(clustering)); + return l; + } + + @Override + public PartitionKeyRestrictions mergeWith(Restriction restriction) + { + if (restriction.isOnToken()) + { + if (isEmpty()) + return (PartitionKeyRestrictions) restriction; + + return new TokenFilter(this, (TokenRestriction) restriction); + } + + return new PartitionKeySingleRestrictionSet(this, (SingleRestriction) restriction); + } + + @Override + public List<ByteBuffer> values(QueryOptions options) + { + MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN()); + for (SingleRestriction r : restrictions) + { + r.appendTo(builder, options); + if (builder.hasMissingElements()) + break; + } + return toByteBuffers(builder.build()); + } + + @Override + public List<ByteBuffer> bounds(Bound bound, QueryOptions options) + { + MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN()); + for (SingleRestriction r : restrictions) + { + r.appendBoundTo(builder, bound, options); + if (builder.hasMissingElements()) + return Collections.emptyList(); + } + return toByteBuffers(builder.buildBound(bound.isStart(), true)); + } + + @Override + public boolean hasBound(Bound b) + { + if (isEmpty()) + return false; + return restrictions.lastRestriction().hasBound(b); + } + + @Override + public boolean isInclusive(Bound b) + { + if (isEmpty()) + return false; + return restrictions.lastRestriction().isInclusive(b); + } + + @Override + public void addRowFilterTo(RowFilter filter, + SecondaryIndexManager indexManager, + QueryOptions options) + { + for (SingleRestriction restriction : restrictions) + { + restriction.addRowFilterTo(filter, indexManager, options); + } + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java b/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java deleted file mode 100644 index 7d0c3df..0000000 --- a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * 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.cassandra.cql3.restrictions; - -import java.nio.ByteBuffer; -import java.util.*; - -import org.apache.cassandra.config.CFMetaData; -import org.apache.cassandra.config.ColumnDefinition; -import org.apache.cassandra.cql3.QueryOptions; -import org.apache.cassandra.cql3.functions.Function; -import org.apache.cassandra.cql3.statements.Bound; -import org.apache.cassandra.db.*; -import org.apache.cassandra.db.filter.RowFilter; -import org.apache.cassandra.exceptions.InvalidRequestException; -import org.apache.cassandra.index.SecondaryIndexManager; -import org.apache.cassandra.utils.btree.BTreeSet; - -import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse; -import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest; - -/** - * A set of single column restrictions on a primary key part (partition key or clustering key). - */ -final class PrimaryKeyRestrictionSet extends AbstractPrimaryKeyRestrictions -{ - /** - * The restrictions. - */ - private final RestrictionSet restrictions; - - /** - * <code>true</code> if the restrictions are corresponding to an EQ, <code>false</code> otherwise. - */ - private boolean eq; - - /** - * <code>true</code> if the restrictions are corresponding to an IN, <code>false</code> otherwise. - */ - private boolean in; - - /** - * <code>true</code> if the restrictions are corresponding to a LIKE, <code>false</code> otherwise. - */ - private boolean like; - - /** - * <code>true</code> if the restrictions are corresponding to a Slice, <code>false</code> otherwise. - */ - private boolean slice; - - /** - * <code>true</code> if the restrictions are corresponding to a Contains, <code>false</code> otherwise. - */ - private boolean contains; - - /** - * <code>true</code> if the restrictions corresponding to a partition key, <code>false</code> if it's clustering columns. - */ - private boolean isPartitionKey; - - public PrimaryKeyRestrictionSet(ClusteringComparator comparator, boolean isPartitionKey) - { - super(comparator); - this.restrictions = new RestrictionSet(); - this.eq = true; - this.isPartitionKey = isPartitionKey; - } - - private PrimaryKeyRestrictionSet(PrimaryKeyRestrictionSet primaryKeyRestrictions, - Restriction restriction) throws InvalidRequestException - { - super(primaryKeyRestrictions.comparator); - this.restrictions = primaryKeyRestrictions.restrictions.addRestriction(restriction); - this.isPartitionKey = primaryKeyRestrictions.isPartitionKey; - - if (!primaryKeyRestrictions.isEmpty()) - { - ColumnDefinition lastRestrictionStart = primaryKeyRestrictions.restrictions.lastRestriction().getFirstColumn(); - ColumnDefinition newRestrictionStart = restriction.getFirstColumn(); - - checkFalse(primaryKeyRestrictions.isSlice() && newRestrictionStart.position() > lastRestrictionStart.position(), - "Clustering column \"%s\" cannot be restricted (preceding column \"%s\" is restricted by a non-EQ relation)", - newRestrictionStart.name, - lastRestrictionStart.name); - - if (newRestrictionStart.position() < lastRestrictionStart.position() && restriction.isSlice()) - throw invalidRequest("PRIMARY KEY column \"%s\" cannot be restricted (preceding column \"%s\" is restricted by a non-EQ relation)", - restrictions.nextColumn(newRestrictionStart).name, - newRestrictionStart.name); - } - - if (restriction.isSlice() || primaryKeyRestrictions.isSlice()) - this.slice = true; - else if (restriction.isContains() || primaryKeyRestrictions.isContains()) - this.contains = true; - else if (restriction.isIN() || primaryKeyRestrictions.isIN()) - this.in = true; - else if (restriction.isLIKE() || primaryKeyRestrictions.isLIKE()) - this.like = true; - else - this.eq = true; - } - - private List<ByteBuffer> toByteBuffers(SortedSet<? extends ClusteringPrefix> clusterings) - { - // It's currently a tad hard to follow that this is only called for partition key so we should fix that - List<ByteBuffer> l = new ArrayList<>(clusterings.size()); - for (ClusteringPrefix clustering : clusterings) - l.add(CFMetaData.serializePartitionKey(clustering)); - return l; - } - - @Override - public boolean isSlice() - { - return slice; - } - - @Override - public boolean isEQ() - { - return eq; - } - - @Override - public boolean isIN() - { - return in; - } - - @Override - public boolean isLIKE() - { - return like; - } - - @Override - public boolean isContains() - { - return contains; - } - - @Override - public Iterable<Function> getFunctions() - { - return restrictions.getFunctions(); - } - - @Override - public PrimaryKeyRestrictions mergeWith(Restriction restriction) throws InvalidRequestException - { - if (restriction.isOnToken()) - { - if (isEmpty()) - return (PrimaryKeyRestrictions) restriction; - - return new TokenFilter(this, (TokenRestriction) restriction); - } - - return new PrimaryKeyRestrictionSet(this, restriction); - } - - // Whether any of the underlying restriction is an IN - private boolean hasIN() - { - if (isIN()) - return true; - - for (Restriction restriction : restrictions) - { - if (restriction.isIN()) - return true; - } - return false; - } - - private boolean hasMultiColumnSlice() - { - for (Restriction restriction : restrictions) - { - if (restriction.isMultiColumn() && restriction.isSlice()) - return true; - } - return false; - } - - @Override - public NavigableSet<Clustering> valuesAsClustering(QueryOptions options) throws InvalidRequestException - { - return appendTo(MultiCBuilder.create(comparator, hasIN()), options).build(); - } - - @Override - public MultiCBuilder appendTo(MultiCBuilder builder, QueryOptions options) - { - for (Restriction r : restrictions) - { - r.appendTo(builder, options); - if (builder.hasMissingElements()) - break; - } - return builder; - } - - @Override - public MultiCBuilder appendBoundTo(MultiCBuilder builder, Bound bound, QueryOptions options) - { - throw new UnsupportedOperationException(); - } - - @Override - public NavigableSet<Slice.Bound> boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException - { - MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN() || hasMultiColumnSlice()); - int keyPosition = 0; - for (Restriction r : restrictions) - { - ColumnDefinition def = r.getFirstColumn(); - - if (keyPosition != def.position() || r.isContains() || r.isLIKE()) - break; - - if (r.isSlice()) - { - r.appendBoundTo(builder, bound, options); - return builder.buildBoundForSlice(bound.isStart(), - r.isInclusive(bound), - r.isInclusive(bound.reverse()), - r.getColumnDefs()); - } - - r.appendBoundTo(builder, bound, options); - - if (builder.hasMissingElements()) - return BTreeSet.empty(comparator); - - keyPosition = r.getLastColumn().position() + 1; - } - - // Everything was an equal (or there was nothing) - return builder.buildBound(bound.isStart(), true); - } - - @Override - public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException - { - if (!isPartitionKey) - throw new UnsupportedOperationException(); - - return toByteBuffers(valuesAsClustering(options)); - } - - @Override - public List<ByteBuffer> bounds(Bound b, QueryOptions options) throws InvalidRequestException - { - if (!isPartitionKey) - throw new UnsupportedOperationException(); - - return toByteBuffers(boundsAsClustering(b, options)); - } - - @Override - public boolean hasBound(Bound b) - { - if (isEmpty()) - return false; - return restrictions.lastRestriction().hasBound(b); - } - - @Override - public boolean isInclusive(Bound b) - { - if (isEmpty()) - return false; - return restrictions.lastRestriction().isInclusive(b); - } - - @Override - public boolean hasSupportingIndex(SecondaryIndexManager indexManager) - { - return restrictions.hasSupportingIndex(indexManager); - } - - @Override - public void addRowFilterTo(RowFilter filter, - SecondaryIndexManager indexManager, - QueryOptions options) throws InvalidRequestException - { - int position = 0; - - for (Restriction restriction : restrictions) - { - ColumnDefinition columnDef = restriction.getFirstColumn(); - - // We ignore all the clustering columns that can be handled by slices. - if (!isPartitionKey && !(restriction.isContains() || restriction.isLIKE()) && position == columnDef.position()) - { - position = restriction.getLastColumn().position() + 1; - if (!restriction.hasSupportingIndex(indexManager)) - continue; - } - restriction.addRowFilterTo(filter, indexManager, options); - } - } - - @Override - public List<ColumnDefinition> getColumnDefs() - { - return restrictions.getColumnDefs(); - } - - @Override - public ColumnDefinition getFirstColumn() - { - return restrictions.firstColumn(); - } - - @Override - public ColumnDefinition getLastColumn() - { - return restrictions.lastColumn(); - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictions.java deleted file mode 100644 index 2f9cd7b..0000000 --- a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictions.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.cassandra.cql3.restrictions; - -import java.nio.ByteBuffer; -import java.util.List; -import java.util.NavigableSet; - -import org.apache.cassandra.cql3.QueryOptions; -import org.apache.cassandra.cql3.statements.Bound; -import org.apache.cassandra.db.Clustering; -import org.apache.cassandra.db.Slice; -import org.apache.cassandra.exceptions.InvalidRequestException; - -/** - * A set of restrictions on a primary key part (partition key or clustering key). - * - */ -interface PrimaryKeyRestrictions extends Restriction, Restrictions -{ - @Override - public PrimaryKeyRestrictions mergeWith(Restriction restriction) throws InvalidRequestException; - - public List<ByteBuffer> values(QueryOptions options) throws InvalidRequestException; - - public NavigableSet<Clustering> valuesAsClustering(QueryOptions options) throws InvalidRequestException; - - public List<ByteBuffer> bounds(Bound b, QueryOptions options) throws InvalidRequestException; - - public NavigableSet<Slice.Bound> boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException; -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java b/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java index d3c525e..8311220 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java @@ -22,28 +22,18 @@ import java.util.List; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.functions.Function; -import org.apache.cassandra.cql3.statements.Bound; -import org.apache.cassandra.db.MultiCBuilder; import org.apache.cassandra.db.filter.RowFilter; -import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.index.SecondaryIndexManager; /** - * A restriction/clause on a column. - * The goal of this class being to group all conditions for a column in a SELECT. - * - * <p>Implementation of this class must be immutable. See {@link #mergeWith(Restriction)} for more explanation.</p> + * <p>Implementation of this class must be immutable.</p> */ public interface Restriction { - public boolean isOnToken(); - public boolean isSlice(); - public boolean isEQ(); - public boolean isLIKE(); - public boolean isIN(); - public boolean isContains(); - public boolean isNotNull(); - public boolean isMultiColumn(); + public default boolean isOnToken() + { + return false; + } /** * Returns the definition of the first column. @@ -71,33 +61,6 @@ public interface Restriction public Iterable<Function> getFunctions(); /** - * Checks if the specified bound is set or not. - * @param b the bound type - * @return <code>true</code> if the specified bound is set, <code>false</code> otherwise - */ - public boolean hasBound(Bound b); - - /** - * Checks if the specified bound is inclusive or not. - * @param b the bound type - * @return <code>true</code> if the specified bound is inclusive, <code>false</code> otherwise - */ - public boolean isInclusive(Bound b); - - /** - * Merges this restriction with the specified one. - * - * <p>Restriction are immutable. Therefore merging two restrictions result in a new one. - * The reason behind this choice is that it allow a great flexibility in the way the merging can done while - * preventing any side effect.</p> - * - * @param otherRestriction the restriction to merge into this one - * @return the restriction resulting of the merge - * @throws InvalidRequestException if the restrictions cannot be merged - */ - public Restriction mergeWith(Restriction otherRestriction) throws InvalidRequestException; - - /** * Check if the restriction is on indexed columns. * * @param indexManager the index manager @@ -111,29 +74,8 @@ public interface Restriction * @param filter the row filter to add expressions to * @param indexManager the secondary index manager * @param options the query options - * @throws InvalidRequestException if this <code>Restriction</code> cannot be converted into a row filter */ public void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, - QueryOptions options) - throws InvalidRequestException; - - /** - * Appends the values of this <code>Restriction</code> to the specified builder. - * - * @param builder the <code>MultiCBuilder</code> to append to. - * @param options the query options - * @return the <code>MultiCBuilder</code> - */ - public MultiCBuilder appendTo(MultiCBuilder builder, QueryOptions options); - - /** - * Appends the values of the <code>Restriction</code> for the specified bound to the specified builder. - * - * @param builder the <code>MultiCBuilder</code> to append to. - * @param bound the bound - * @param options the query options - * @return the <code>MultiCBuilder</code> - */ - public MultiCBuilder appendBoundTo(MultiCBuilder builder, Bound bound, QueryOptions options); + QueryOptions options); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java index c9aec0e..8011e92 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java @@ -18,6 +18,7 @@ package org.apache.cassandra.cql3.restrictions; import java.util.*; +import java.util.stream.Stream; import com.google.common.collect.Iterables; @@ -32,10 +33,9 @@ import org.apache.cassandra.index.SecondaryIndexManager; /** * Sets of column restrictions. * - * <p>This class is immutable in order to be use within {@link PrimaryKeyRestrictionSet} which as - * an implementation of {@link Restriction} need to be immutable. + * <p>This class is immutable.</p> */ -final class RestrictionSet implements Restrictions, Iterable<Restriction> +final class RestrictionSet implements Restrictions, Iterable<SingleRestriction> { /** * The comparator used to sort the <code>Restriction</code>s. @@ -53,14 +53,14 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> /** * The restrictions per column. */ - protected final TreeMap<ColumnDefinition, Restriction> restrictions; + protected final TreeMap<ColumnDefinition, SingleRestriction> restrictions; public RestrictionSet() { - this(new TreeMap<ColumnDefinition, Restriction>(COLUMN_DEFINITION_COMPARATOR)); + this(new TreeMap<ColumnDefinition, SingleRestriction>(COLUMN_DEFINITION_COMPARATOR)); } - private RestrictionSet(TreeMap<ColumnDefinition, Restriction> restrictions) + private RestrictionSet(TreeMap<ColumnDefinition, SingleRestriction> restrictions) { this.restrictions = restrictions; } @@ -78,6 +78,11 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> return new ArrayList<>(restrictions.keySet()); } + public Stream<SingleRestriction> stream() + { + return new LinkedHashSet<>(restrictions.values()).stream(); + } + @Override public Iterable<Function> getFunctions() { @@ -110,21 +115,19 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> * * @param restriction the restriction to add * @return the new set of restrictions - * @throws InvalidRequestException if the new restriction cannot be added */ - public RestrictionSet addRestriction(Restriction restriction) throws InvalidRequestException + public RestrictionSet addRestriction(SingleRestriction restriction) { // RestrictionSet is immutable so we need to clone the restrictions map. - TreeMap<ColumnDefinition, Restriction> newRestrictions = new TreeMap<>(this.restrictions); + TreeMap<ColumnDefinition, SingleRestriction> newRestrictions = new TreeMap<>(this.restrictions); return new RestrictionSet(mergeRestrictions(newRestrictions, restriction)); } - private TreeMap<ColumnDefinition, Restriction> mergeRestrictions(TreeMap<ColumnDefinition, Restriction> restrictions, - Restriction restriction) - throws InvalidRequestException + private TreeMap<ColumnDefinition, SingleRestriction> mergeRestrictions(TreeMap<ColumnDefinition, SingleRestriction> restrictions, + SingleRestriction restriction) { Collection<ColumnDefinition> columnDefs = restriction.getColumnDefs(); - Set<Restriction> existingRestrictions = getRestrictions(columnDefs); + Set<SingleRestriction> existingRestrictions = getRestrictions(columnDefs); if (existingRestrictions.isEmpty()) { @@ -133,9 +136,9 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> } else { - for (Restriction existing : existingRestrictions) + for (SingleRestriction existing : existingRestrictions) { - Restriction newRestriction = mergeRestrictions(existing, restriction); + SingleRestriction newRestriction = mergeRestrictions(existing, restriction); for (ColumnDefinition columnDef : columnDefs) restrictions.put(columnDef, newRestriction); @@ -151,12 +154,12 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> * @param columnDefs the column definitions * @return all the restrictions applied to the specified columns */ - private Set<Restriction> getRestrictions(Collection<ColumnDefinition> columnDefs) + private Set<SingleRestriction> getRestrictions(Collection<ColumnDefinition> columnDefs) { - Set<Restriction> set = new HashSet<>(); + Set<SingleRestriction> set = new HashSet<>(); for (ColumnDefinition columnDef : columnDefs) { - Restriction existing = restrictions.get(columnDef); + SingleRestriction existing = restrictions.get(columnDef); if (existing != null) set.add(existing); } @@ -185,22 +188,14 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> return restrictions.tailMap(columnDef, false).firstKey(); } - /** - * Returns the definition of the first column. - * - * @return the definition of the first column. - */ - ColumnDefinition firstColumn() + @Override + public ColumnDefinition getFirstColumn() { return isEmpty() ? null : this.restrictions.firstKey(); } - /** - * Returns the definition of the last column. - * - * @return the definition of the last column. - */ - ColumnDefinition lastColumn() + @Override + public ColumnDefinition getLastColumn() { return isEmpty() ? null : this.restrictions.lastKey(); } @@ -210,7 +205,7 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> * * @return the last restriction. */ - Restriction lastRestriction() + SingleRestriction lastRestriction() { return isEmpty() ? null : this.restrictions.lastEntry().getValue(); } @@ -223,8 +218,8 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> * @return the merged restriction * @throws InvalidRequestException if the two restrictions cannot be merged */ - private static Restriction mergeRestrictions(Restriction restriction, - Restriction otherRestriction) throws InvalidRequestException + private static SingleRestriction mergeRestrictions(SingleRestriction restriction, + SingleRestriction otherRestriction) { return restriction == null ? otherRestriction : restriction.mergeWith(otherRestriction); @@ -239,7 +234,7 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> public final boolean hasMultipleContains() { int numberOfContains = 0; - for (Restriction restriction : restrictions.values()) + for (SingleRestriction restriction : restrictions.values()) { if (restriction.isContains()) { @@ -251,8 +246,28 @@ final class RestrictionSet implements Restrictions, Iterable<Restriction> } @Override - public Iterator<Restriction> iterator() + public Iterator<SingleRestriction> iterator() { return new LinkedHashSet<>(restrictions.values()).iterator(); } + + /** + * Checks if any of the underlying restriction is an IN. + * @return <code>true</code> if any of the underlying restriction is an IN, <code>false</code> otherwise + */ + public final boolean hasIN() + { + return stream().anyMatch(SingleRestriction::isIN); + } + + /** + * Checks if all of the underlying restrictions are EQ or IN restrictions. + * + * @return <code>true</code> if all of the underlying restrictions are EQ or IN restrictions, + * <code>false</code> otherwise + */ + public final boolean hasOnlyEqualityRestrictions() + { + return stream().allMatch(p -> p.isEQ() || p.isIN()); + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSetWrapper.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSetWrapper.java b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSetWrapper.java new file mode 100644 index 0000000..b8ccb1c --- /dev/null +++ b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSetWrapper.java @@ -0,0 +1,95 @@ +/* + * 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.cassandra.cql3.restrictions; + +import java.util.List; + +import org.apache.cassandra.config.ColumnDefinition; +import org.apache.cassandra.cql3.QueryOptions; +import org.apache.cassandra.cql3.functions.Function; +import org.apache.cassandra.db.filter.RowFilter; +import org.apache.cassandra.index.SecondaryIndexManager; + +/** + * A <code>RestrictionSet</code> wrapper that can be extended to allow to modify the <code>RestrictionSet</code> + * behaviour without breaking its immutability. Sub-classes should be immutables. + */ +class RestrictionSetWrapper implements Restrictions +{ + /** + * The wrapped <code>RestrictionSet</code>. + */ + protected final RestrictionSet restrictions; + + public RestrictionSetWrapper(RestrictionSet restrictions) + { + this.restrictions = restrictions; + } + + public void addRowFilterTo(RowFilter filter, + SecondaryIndexManager indexManager, + QueryOptions options) + { + restrictions.addRowFilterTo(filter, indexManager, options); + } + + public List<ColumnDefinition> getColumnDefs() + { + return restrictions.getColumnDefs(); + } + + public Iterable<Function> getFunctions() + { + return restrictions.getFunctions(); + } + + public boolean isEmpty() + { + return restrictions.isEmpty(); + } + + public int size() + { + return restrictions.size(); + } + + public boolean hasSupportingIndex(SecondaryIndexManager indexManager) + { + return restrictions.hasSupportingIndex(indexManager); + } + + public ColumnDefinition getFirstColumn() + { + return restrictions.getFirstColumn(); + } + + public ColumnDefinition getLastColumn() + { + return restrictions.getLastColumn(); + } + + public boolean hasIN() + { + return restrictions.hasIN(); + } + + public boolean hasOnlyEqualityRestrictions() + { + return restrictions.hasOnlyEqualityRestrictions(); + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java index f46f176..7ca82ab 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java @@ -17,62 +17,36 @@ */ package org.apache.cassandra.cql3.restrictions; -import java.util.Collection; - -import org.apache.cassandra.config.ColumnDefinition; -import org.apache.cassandra.cql3.QueryOptions; -import org.apache.cassandra.cql3.functions.Function; -import org.apache.cassandra.db.filter.RowFilter; -import org.apache.cassandra.exceptions.InvalidRequestException; -import org.apache.cassandra.index.SecondaryIndexManager; - /** * Sets of restrictions */ -public interface Restrictions +public interface Restrictions extends Restriction { /** - * Returns the column definitions in position order. - * @return the column definitions in position order. - */ - public Collection<ColumnDefinition> getColumnDefs(); - - /** - * Return an Iterable over all of the functions (both native and user-defined) used by any component - * of the restrictions - * @return functions all functions found (may contain duplicates) - */ - public Iterable<Function> getFunctions(); - - /** - * Check if the restriction is on indexed columns. + * Checks if this <code>PrimaryKeyRestrictionSet</code> is empty or not. * - * @param indexManager the index manager - * @return <code>true</code> if the restriction is on indexed columns, <code>false</code> + * @return <code>true</code> if this <code>PrimaryKeyRestrictionSet</code> is empty, <code>false</code> otherwise. */ - public boolean hasSupportingIndex(SecondaryIndexManager indexManager); + boolean isEmpty(); /** - * Adds to the specified row filter the expressions corresponding to this <code>Restrictions</code>. + * Returns the number of columns that have a restriction. * - * @param filter the row filter to add expressions to - * @param indexManager the secondary index manager - * @param options the query options - * @throws InvalidRequestException if this <code>Restrictions</code> cannot be converted into a row filter + * @return the number of columns that have a restriction. */ - public void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, QueryOptions options) throws InvalidRequestException; + public int size(); /** - * Checks if this <code>PrimaryKeyRestrictionSet</code> is empty or not. - * - * @return <code>true</code> if this <code>PrimaryKeyRestrictionSet</code> is empty, <code>false</code> otherwise. + * Checks if any of the underlying restriction is an IN. + * @return <code>true</code> if any of the underlying restriction is an IN, <code>false</code> otherwise */ - boolean isEmpty(); + public boolean hasIN(); /** - * Returns the number of columns that have a restriction. + * Checks if all of the underlying restrictions are EQ or IN restrictions. * - * @return the number of columns that have a restriction. + * @return <code>true</code> if all of the underlying restrictions are EQ or IN restrictions, + * <code>false</code> otherwise */ - public int size(); + public boolean hasOnlyEqualityRestrictions(); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java b/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java index a5804be..9c20bef 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java @@ -31,7 +31,6 @@ import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.statements.Bound; import org.apache.cassandra.db.MultiCBuilder; import org.apache.cassandra.db.filter.RowFilter; -import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.index.Index; import org.apache.cassandra.index.SecondaryIndexManager; import org.apache.cassandra.utils.ByteBufferUtil; @@ -43,7 +42,7 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.checkNotNu import static org.apache.cassandra.cql3.statements.RequestValidations.checkTrue; import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest; -public abstract class SingleColumnRestriction extends AbstractRestriction +public abstract class SingleColumnRestriction implements SingleRestriction { /** * The definition of the column to which apply the restriction. @@ -84,7 +83,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public final Restriction mergeWith(Restriction otherRestriction) throws InvalidRequestException + public final SingleRestriction mergeWith(SingleRestriction otherRestriction) { // We want to allow query like: b > ? AND (b,c) < (?, ?) if (otherRestriction.isMultiColumn() && canBeConvertedToMultiColumnRestriction()) @@ -95,7 +94,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction return doMergeWith(otherRestriction); } - protected abstract Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException; + protected abstract SingleRestriction doMergeWith(SingleRestriction otherRestriction); /** * Converts this <code>SingleColumnRestriction</code> into a {@link MultiColumnRestriction} @@ -176,7 +175,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException + public SingleRestriction doMergeWith(SingleRestriction otherRestriction) { throw invalidRequest("%s cannot be restricted by more than one relation if it includes an Equal", columnDef.name); } @@ -202,7 +201,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public final Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException + public final SingleRestriction doMergeWith(SingleRestriction otherRestriction) { throw invalidRequest("%s cannot be restricted by more than one relation if it includes a IN", columnDef.name); } @@ -219,7 +218,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction @Override public void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, - QueryOptions options) throws InvalidRequestException + QueryOptions options) { List<ByteBuffer> values = getValues(options); checkTrue(values.size() == 1, "IN restrictions are not supported on indexed columns"); @@ -233,7 +232,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction return index.supportsExpression(columnDef, Operator.IN); } - protected abstract List<ByteBuffer> getValues(QueryOptions options) throws InvalidRequestException; + protected abstract List<ByteBuffer> getValues(QueryOptions options); } public static class InRestrictionWithValues extends INRestriction @@ -259,7 +258,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - protected List<ByteBuffer> getValues(QueryOptions options) throws InvalidRequestException + protected List<ByteBuffer> getValues(QueryOptions options) { List<ByteBuffer> buffers = new ArrayList<>(values.size()); for (Term value : values) @@ -297,7 +296,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - protected List<ByteBuffer> getValues(QueryOptions options) throws InvalidRequestException + protected List<ByteBuffer> getValues(QueryOptions options) { Terminal term = marker.bind(options); checkNotNull(term, "Invalid null value for column %s", columnDef.name); @@ -356,7 +355,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction @Override public MultiCBuilder appendBoundTo(MultiCBuilder builder, Bound bound, QueryOptions options) { - Bound b = reverseBoundIfNeeded(getFirstColumn(), bound); + Bound b = bound.reverseIfNeeded(getFirstColumn()); if (!hasBound(b)) return builder; @@ -374,7 +373,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException + public SingleRestriction doMergeWith(SingleRestriction otherRestriction) { checkTrue(otherRestriction.isSlice(), "Column \"%s\" cannot be restricted by both an equality and an inequality relation", @@ -392,7 +391,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, QueryOptions options) throws InvalidRequestException + public void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, QueryOptions options) { for (Bound b : Bound.values()) if (hasBound(b)) @@ -467,7 +466,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException + public SingleRestriction doMergeWith(SingleRestriction otherRestriction) { checkTrue(otherRestriction.isContains(), "Collection column %s can only be restricted by CONTAINS, CONTAINS KEY, or map-entry equality", @@ -482,7 +481,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, QueryOptions options) throws InvalidRequestException + public void addRowFilterTo(RowFilter filter, SecondaryIndexManager indexManager, QueryOptions options) { for (ByteBuffer value : bindAndGet(values, options)) filter.add(columnDef, Operator.CONTAINS, value); @@ -567,9 +566,8 @@ public abstract class SingleColumnRestriction extends AbstractRestriction * @param terms the terms * @param options the query options * @return the value resulting from binding the query options to the specified terms - * @throws InvalidRequestException if a problem occurs while binding the query options */ - private static List<ByteBuffer> bindAndGet(List<Term> terms, QueryOptions options) throws InvalidRequestException + private static List<ByteBuffer> bindAndGet(List<Term> terms, QueryOptions options) { List<ByteBuffer> buffers = new ArrayList<>(terms.size()); for (Term value : terms) @@ -643,7 +641,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException + public SingleRestriction doMergeWith(SingleRestriction otherRestriction) { throw invalidRequest("%s cannot be restricted by a relation if it includes an IS NOT NULL", columnDef.name); } @@ -708,9 +706,8 @@ public abstract class SingleColumnRestriction extends AbstractRestriction // there must be a suitable INDEX for LIKE_XXX expressions RowFilter.SimpleExpression expression = filter.add(columnDef, operation.left, operation.right); indexManager.getBestIndexFor(expression) - .orElseThrow(() -> new InvalidRequestException(expression.toString() + - " is only supported on properly" + - " indexed columns")); + .orElseThrow(() -> invalidRequest("%s is only supported on properly indexed columns", + expression)); } @Override @@ -729,7 +726,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } @Override - public Restriction doMergeWith(Restriction otherRestriction) throws InvalidRequestException + public SingleRestriction doMergeWith(SingleRestriction otherRestriction) { throw invalidRequest("%s cannot be restricted by more than one relation if it includes a %s", columnDef.name, operator); } @@ -778,7 +775,7 @@ public abstract class SingleColumnRestriction extends AbstractRestriction } if (endIndex == 0 || beginIndex == endIndex) - throw new InvalidRequestException("LIKE value can't be empty."); + throw invalidRequest("LIKE value can't be empty."); ByteBuffer newValue = value.duplicate(); newValue.position(beginIndex); http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/src/java/org/apache/cassandra/cql3/restrictions/SingleRestriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/SingleRestriction.java b/src/java/org/apache/cassandra/cql3/restrictions/SingleRestriction.java new file mode 100644 index 0000000..42b0b4e --- /dev/null +++ b/src/java/org/apache/cassandra/cql3/restrictions/SingleRestriction.java @@ -0,0 +1,117 @@ +/* + * 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.cassandra.cql3.restrictions; + +import org.apache.cassandra.cql3.QueryOptions; +import org.apache.cassandra.cql3.statements.Bound; +import org.apache.cassandra.db.MultiCBuilder; + +/** + * A single restriction/clause on one or multiple column. + */ +public interface SingleRestriction extends Restriction +{ + public default boolean isSlice() + { + return false; + } + + public default boolean isEQ() + { + return false; + } + + public default boolean isLIKE() + { + return false; + } + + public default boolean isIN() + { + return false; + } + + public default boolean isContains() + { + return false; + } + + public default boolean isNotNull() + { + return false; + } + + public default boolean isMultiColumn() + { + return false; + } + + /** + * Checks if the specified bound is set or not. + * @param b the bound type + * @return <code>true</code> if the specified bound is set, <code>false</code> otherwise + */ + public default boolean hasBound(Bound b) + { + return true; + } + + /** + * Checks if the specified bound is inclusive or not. + * @param b the bound type + * @return <code>true</code> if the specified bound is inclusive, <code>false</code> otherwise + */ + public default boolean isInclusive(Bound b) + { + return true; + } + + /** + * Merges this restriction with the specified one. + * + * <p>Restriction are immutable. Therefore merging two restrictions result in a new one. + * The reason behind this choice is that it allow a great flexibility in the way the merging can done while + * preventing any side effect.</p> + * + * @param otherRestriction the restriction to merge into this one + * @return the restriction resulting of the merge + */ + public SingleRestriction mergeWith(SingleRestriction otherRestriction); + + /** + * Appends the values of this <code>SingleRestriction</code> to the specified builder. + * + * @param builder the <code>MultiCBuilder</code> to append to. + * @param options the query options + * @return the <code>MultiCBuilder</code> + */ + public MultiCBuilder appendTo(MultiCBuilder builder, QueryOptions options); + + /** + * Appends the values of the <code>SingleRestriction</code> for the specified bound to the specified builder. + * + * @param builder the <code>MultiCBuilder</code> to append to. + * @param bound the bound + * @param options the query options + * @return the <code>MultiCBuilder</code> + */ + public default MultiCBuilder appendBoundTo(MultiCBuilder builder, Bound bound, QueryOptions options) + { + return appendTo(builder, options); + } +}
