blerer commented on code in PR #3095: URL: https://github.com/apache/cassandra/pull/3095#discussion_r1571101355
########## src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java: ########## @@ -1,829 +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.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.cassandra.cql3.Operator; -import org.apache.cassandra.cql3.QueryOptions; -import org.apache.cassandra.cql3.terms.Term; -import org.apache.cassandra.cql3.terms.Terms; -import org.apache.cassandra.db.marshal.ListType; -import org.apache.cassandra.schema.ColumnMetadata; -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.index.Index; -import org.apache.cassandra.index.IndexRegistry; -import org.apache.cassandra.utils.ByteBufferUtil; -import org.apache.cassandra.utils.Pair; - -import static org.apache.cassandra.cql3.statements.RequestValidations.checkBindValueSet; -import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse; -import static org.apache.cassandra.cql3.statements.RequestValidations.checkNotNull; -import static org.apache.cassandra.cql3.statements.RequestValidations.checkTrue; -import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest; - -public abstract class SingleColumnRestriction implements SingleRestriction -{ - /** - * The definition of the column to which apply the restriction. - */ - protected final ColumnMetadata columnDef; - - public SingleColumnRestriction(ColumnMetadata columnDef) - { - this.columnDef = columnDef; - } - - @Override - public List<ColumnMetadata> getColumnDefs() - { - return Collections.singletonList(columnDef); - } - - @Override - public ColumnMetadata getFirstColumn() - { - return columnDef; - } - - @Override - public ColumnMetadata getLastColumn() - { - return columnDef; - } - - @Override - public boolean hasSupportingIndex(IndexRegistry indexRegistry) - { - for (Index index : indexRegistry.listIndexes()) - if (isSupportedBy(index)) - return true; - - return false; - } - - @Override - public Index findSupportingIndex(IndexRegistry indexRegistry) - { - for (Index index : indexRegistry.listIndexes()) - if (isSupportedBy(index)) - return index; - - return null; - } - - @Override - public Index findSupportingIndexFromQueryPlan(Index.QueryPlan indexQueryPlan) - { - for (Index index : indexQueryPlan.getIndexes()) - if (isSupportedBy(index)) - return index; - - return null; - } - - @Override - public boolean needsFiltering(Index.Group indexGroup) - { - for (Index index : indexGroup.getIndexes()) - if (isSupportedBy(index)) - return false; - - return true; - } - - @Override - public final SingleRestriction mergeWith(SingleRestriction otherRestriction) - { - // We want to allow query like: b > ? AND (b,c) < (?, ?) - if (otherRestriction.isMultiColumn() && canBeConvertedToMultiColumnRestriction()) - { - return toMultiColumnRestriction().mergeWith(otherRestriction); - } - - return doMergeWith(otherRestriction); - } - - protected abstract SingleRestriction doMergeWith(SingleRestriction otherRestriction); - - /** - * Converts this <code>SingleColumnRestriction</code> into a {@link MultiColumnRestriction} - * - * @return the <code>MultiColumnRestriction</code> corresponding to this - */ - abstract MultiColumnRestriction toMultiColumnRestriction(); - - /** - * Checks if this <code>Restriction</code> can be converted into a {@link MultiColumnRestriction} - * - * @return <code>true</code> if this <code>Restriction</code> can be converted into a - * {@link MultiColumnRestriction}, <code>false</code> otherwise. - */ - boolean canBeConvertedToMultiColumnRestriction() - { - return true; - } - - /** - * Check if this type of restriction is supported by the specified index. - * - * @param index the secondary index - * @return <code>true</code> this type of restriction is supported by the specified index, - * <code>false</code> otherwise. - */ - protected abstract boolean isSupportedBy(Index index); - - public static final class EQRestriction extends SingleColumnRestriction - { - private final Term value; - - public EQRestriction(ColumnMetadata columnDef, Term value) - { - super(columnDef); - this.value = value; - } - - @Override - public void addFunctionsTo(List<Function> functions) - { - value.addFunctionsTo(functions); - } - - @Override - public boolean isEQ() - { - return true; - } - - @Override - MultiColumnRestriction toMultiColumnRestriction() - { - return new MultiColumnRestriction.EQRestriction(Collections.singletonList(columnDef), value); - } - - @Override - public void addToRowFilter(RowFilter filter, - IndexRegistry indexRegistry, - QueryOptions options) - { - filter.add(columnDef, Operator.EQ, value.bindAndGet(options)); - } - - @Override - public MultiCBuilder appendTo(MultiCBuilder builder, QueryOptions options) - { - builder.addElementToAll(value.bindAndGet(options)); - checkFalse(builder.containsNull(), "Invalid null value in condition for column %s", columnDef.name); - checkFalse(builder.containsUnset(), "Invalid unset value for column %s", columnDef.name); - return builder; - } - - @Override - public String toString() - { - return String.format("EQ(%s)", value); - } - - @Override - public SingleRestriction doMergeWith(SingleRestriction otherRestriction) - { - throw invalidRequest("%s cannot be restricted by more than one relation if it includes an Equal", columnDef.name); - } - - @Override - protected boolean isSupportedBy(Index index) - { - return index.supportsExpression(columnDef, Operator.EQ); - } - } - - public static class INRestriction extends SingleColumnRestriction - { - private final Terms values; - - public INRestriction(ColumnMetadata columnDef, Terms values) - { - super(columnDef); - this.values = values; - } - - @Override - MultiColumnRestriction toMultiColumnRestriction() - { - return new MultiColumnRestriction.INRestriction(Collections.singletonList(columnDef), values); - } - - @Override - public void addFunctionsTo(List<Function> functions) - { - values.addFunctionsTo(functions); - } - - @Override - public final boolean isIN() - { - return true; - } - - @Override - public final SingleRestriction doMergeWith(SingleRestriction otherRestriction) - { - throw invalidRequest("%s cannot be restricted by more than one relation if it includes a IN", columnDef.name); - } - - @Override - public MultiCBuilder appendTo(MultiCBuilder builder, QueryOptions options) - { - List<ByteBuffer> buffers = values.bindAndGet(options); - checkNotNull(buffers, "Invalid null value for column %s", columnDef.name); - checkFalse(buffers == Terms.UNSET_LIST, "Invalid unset value for column %s", columnDef.name); - builder.addEachElementToAll(buffers); - checkFalse(builder.containsNull(), "Invalid null value in condition for column %s", columnDef.name); - checkFalse(builder.containsUnset(), "Invalid unset value for column %s", columnDef.name); - return builder; - } - - @Override - public void addToRowFilter(RowFilter filter, - IndexRegistry indexRegistry, - QueryOptions options) - { - List<ByteBuffer> elements = values.bindAndGet(options); - ListType<?> type = ListType.getInstance(columnDef.type, false); - ByteBuffer buffer = type.pack(elements); - filter.add(columnDef, Operator.IN, buffer); - } - - @Override - protected final boolean isSupportedBy(Index index) - { - return index.supportsExpression(columnDef, Operator.IN); - } - } - - public static class SliceRestriction extends SingleColumnRestriction - { - private final TermSlice slice; - - public SliceRestriction(ColumnMetadata columnDef, Bound bound, boolean inclusive, Term term) - { - super(columnDef); - slice = TermSlice.newInstance(bound, inclusive, term); - } - - @Override - public void addFunctionsTo(List<Function> functions) - { - slice.addFunctionsTo(functions); - } - - @Override - MultiColumnRestriction toMultiColumnRestriction() - { - return new MultiColumnRestriction.SliceRestriction(Collections.singletonList(columnDef), slice); - } - - @Override - public boolean isSlice() - { - return true; - } - - @Override - public MultiCBuilder appendTo(MultiCBuilder builder, QueryOptions options) - { - throw new UnsupportedOperationException(); - } - - @Override - public boolean hasBound(Bound b) - { - return slice.hasBound(b); - } - - @Override - public MultiCBuilder appendBoundTo(MultiCBuilder builder, Bound bound, QueryOptions options) - { - Bound b = bound.reverseIfNeeded(getFirstColumn()); - - if (!hasBound(b)) - return builder; - - ByteBuffer value = slice.bound(b).bindAndGet(options); - checkBindValueSet(value, "Invalid unset value for column %s", columnDef.name); - return builder.addElementToAll(value); - - } - - @Override - public boolean isInclusive(Bound b) - { - return slice.isInclusive(b); - } - - @Override - public SingleRestriction doMergeWith(SingleRestriction otherRestriction) - { - checkTrue(otherRestriction.isSlice(), - "Column \"%s\" cannot be restricted by both an equality and an inequality relation", - columnDef.name); - - SingleColumnRestriction.SliceRestriction otherSlice = (SingleColumnRestriction.SliceRestriction) otherRestriction; - - checkFalse(hasBound(Bound.START) && otherSlice.hasBound(Bound.START), - "More than one restriction was found for the start bound on %s", columnDef.name); - - checkFalse(hasBound(Bound.END) && otherSlice.hasBound(Bound.END), - "More than one restriction was found for the end bound on %s", columnDef.name); - - return new SliceRestriction(columnDef, slice.merge(otherSlice.slice)); - } - - @Override - public void addToRowFilter(RowFilter filter, IndexRegistry indexRegistry, QueryOptions options) - { - for (Bound b : Bound.values()) - if (hasBound(b)) - filter.add(columnDef, slice.getIndexOperator(b), slice.bound(b).bindAndGet(options)); - } - - @Override - protected boolean isSupportedBy(Index index) - { - return slice.isSupportedBy(columnDef, index); - } - - @Override - public String toString() - { - return String.format("SLICE%s", slice); - } - - private SliceRestriction(ColumnMetadata columnDef, TermSlice slice) - { - super(columnDef); - this.slice = slice; - } - } - - // This holds CONTAINS, CONTAINS_KEY, and map[key] = value restrictions because we might want to have any combination of them. - public static final class ContainsRestriction extends SingleColumnRestriction - { - private final List<Term> values = new ArrayList<>(); // for CONTAINS - private final List<Term> keys = new ArrayList<>(); // for CONTAINS_KEY - private final List<Term> entryKeys = new ArrayList<>(); // for map[key] = value - private final List<Term> entryValues = new ArrayList<>(); // for map[key] = value - - public ContainsRestriction(ColumnMetadata columnDef, Term t, boolean isKey) - { - super(columnDef); - if (isKey) - keys.add(t); - else - values.add(t); - } - - public ContainsRestriction(ColumnMetadata columnDef, Term mapKey, Term mapValue) - { - super(columnDef); - entryKeys.add(mapKey); - entryValues.add(mapValue); - } - - @Override - MultiColumnRestriction toMultiColumnRestriction() - { - throw new UnsupportedOperationException(); - } - - @Override - boolean canBeConvertedToMultiColumnRestriction() - { - return false; - } - - @Override - public MultiCBuilder appendTo(MultiCBuilder builder, QueryOptions options) - { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isContains() - { - return true; - } - - @Override - public SingleRestriction doMergeWith(SingleRestriction otherRestriction) - { - checkTrue(otherRestriction.isContains(), - "Collection column %s can only be restricted by CONTAINS, CONTAINS KEY, or map-entry equality", - columnDef.name); - - SingleColumnRestriction.ContainsRestriction newContains = new ContainsRestriction(columnDef); - - copyKeysAndValues(this, newContains); - copyKeysAndValues((ContainsRestriction) otherRestriction, newContains); - - return newContains; - } - - @Override - public void addToRowFilter(RowFilter filter, IndexRegistry indexRegistry, QueryOptions options) - { - for (ByteBuffer value : bindAndGet(values, options)) - filter.add(columnDef, Operator.CONTAINS, value); - for (ByteBuffer key : bindAndGet(keys, options)) - filter.add(columnDef, Operator.CONTAINS_KEY, key); - - List<ByteBuffer> eks = bindAndGet(entryKeys, options); - List<ByteBuffer> evs = bindAndGet(entryValues, options); - assert eks.size() == evs.size(); - for (int i = 0; i < eks.size(); i++) - filter.addMapEquality(columnDef, eks.get(i), Operator.EQ, evs.get(i)); - } - - @Override - protected boolean isSupportedBy(Index index) - { - boolean supported = false; - - if (numberOfValues() > 0) - supported |= index.supportsExpression(columnDef, Operator.CONTAINS); - - if (numberOfKeys() > 0) - supported |= index.supportsExpression(columnDef, Operator.CONTAINS_KEY); - - if (numberOfEntries() > 0) - supported |= index.supportsExpression(columnDef, Operator.EQ); - - return supported; - } - - @Override - public boolean needsFiltering(Index.Group indexGroup) - { - // multiple contains might require filtering on some indexes, since that is equivalent to a disjunction (or) - boolean hasMultipleContains = (numberOfValues() + numberOfKeys() + numberOfEntries()) > 1; - - for (Index index : indexGroup.getIndexes()) - { - if (isSupportedBy(index) && !(hasMultipleContains && index.filtersMultipleContains())) - return false; - } - - return true; - } - - public int numberOfValues() - { - return values.size(); - } - - public int numberOfKeys() - { - return keys.size(); - } - - public int numberOfEntries() - { - return entryKeys.size(); - } - - @Override - public void addFunctionsTo(List<Function> functions) - { - Terms.addFunctions(values, functions); - Terms.addFunctions(keys, functions); - Terms.addFunctions(entryKeys, functions); - Terms.addFunctions(entryValues, functions); - } - - @Override - public String toString() - { - return String.format("CONTAINS(values=%s, keys=%s, entryKeys=%s, entryValues=%s)", values, keys, entryKeys, entryValues); - } - - @Override - public boolean hasBound(Bound b) - { - throw new UnsupportedOperationException(); - } - - @Override - public MultiCBuilder appendBoundTo(MultiCBuilder builder, Bound bound, QueryOptions options) - { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isInclusive(Bound b) - { - throw new UnsupportedOperationException(); - } - - /** - * Binds the query options to the specified terms and returns the resulting values. - * - * @param terms the terms - * @param options the query options - * @return the value resulting from binding the query options to the specified terms - */ - private static List<ByteBuffer> bindAndGet(List<Term> terms, QueryOptions options) - { - List<ByteBuffer> buffers = new ArrayList<>(terms.size()); - for (Term value : terms) - buffers.add(value.bindAndGet(options)); - return buffers; - } - - /** - * Copies the keys and value from the first <code>Contains</code> to the second one. - * - * @param from the <code>Contains</code> to copy from - * @param to the <code>Contains</code> to copy to - */ - private static void copyKeysAndValues(ContainsRestriction from, ContainsRestriction to) - { - to.values.addAll(from.values); - to.keys.addAll(from.keys); - to.entryKeys.addAll(from.entryKeys); - to.entryValues.addAll(from.entryValues); - } - - private ContainsRestriction(ColumnMetadata columnDef) - { - super(columnDef); - } - } - - public static final class IsNotNullRestriction extends SingleColumnRestriction - { - public IsNotNullRestriction(ColumnMetadata columnDef) - { - super(columnDef); - } - - @Override - public void addFunctionsTo(List<Function> functions) - { - } - - @Override - public boolean isNotNull() - { - return true; - } - - @Override - MultiColumnRestriction toMultiColumnRestriction() - { - return new MultiColumnRestriction.NotNullRestriction(Collections.singletonList(columnDef)); - } - - @Override - public void addToRowFilter(RowFilter filter, - IndexRegistry indexRegistry, - QueryOptions options) - { - throw new UnsupportedOperationException("Secondary indexes do not support IS NOT NULL restrictions"); - } - - @Override - public MultiCBuilder appendTo(MultiCBuilder builder, QueryOptions options) - { - throw new UnsupportedOperationException("Cannot use IS NOT NULL restriction for slicing"); - } - - @Override - public String toString() - { - return "IS NOT NULL"; - } - - @Override - public SingleRestriction doMergeWith(SingleRestriction otherRestriction) - { - throw invalidRequest("%s cannot be restricted by a relation if it includes an IS NOT NULL", columnDef.name); Review Comment: It is a IS NOT NULL so we can ignore that one. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]

