You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by bl...@apache.org on 2017/01/27 14:51:43 UTC
[6/7] cassandra git commit: Refactor ColumnCondition
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e71a49e8/src/java/org/apache/cassandra/cql3/conditions/ColumnCondition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/conditions/ColumnCondition.java b/src/java/org/apache/cassandra/cql3/conditions/ColumnCondition.java
new file mode 100644
index 0000000..cfd62f5
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/conditions/ColumnCondition.java
@@ -0,0 +1,825 @@
+/*
+ * 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.conditions;
+
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import com.google.common.collect.Iterators;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.Term.Terminal;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.db.rows.*;
+import org.apache.cassandra.db.marshal.*;
+import org.apache.cassandra.transport.ProtocolVersion;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+import static org.apache.cassandra.cql3.statements.RequestValidations.*;
+
+/**
+ * A CQL3 condition on the value of a column or collection element. For example, "UPDATE .. IF a = 0".
+ */
+public abstract class ColumnCondition
+{
+ public final ColumnDefinition column;
+ public final Operator operator;
+ private final Terms terms;
+
+ private ColumnCondition(ColumnDefinition column, Operator op, Terms terms)
+ {
+ this.column = column;
+ this.operator = op;
+ this.terms = terms;
+ }
+
+ /**
+ * Adds functions for the bind variables of this operation.
+ *
+ * @param functions the list of functions to get add
+ */
+ public void addFunctionsTo(List<Function> functions)
+ {
+ terms.addFunctionsTo(functions);
+ }
+
+ /**
+ * Collects the column specification for the bind variables of this operation.
+ *
+ * @param boundNames the list of column specification where to collect the
+ * bind variables of this term in.
+ */
+ public void collectMarkerSpecification(VariableSpecifications boundNames)
+ {
+ terms.collectMarkerSpecification(boundNames);
+ }
+
+ public abstract ColumnCondition.Bound bind(QueryOptions options);
+
+ protected final List<ByteBuffer> bindAndGetTerms(QueryOptions options)
+ {
+ return filterUnsetValuesIfNeeded(checkValues(terms.bindAndGet(options)));
+ }
+
+ protected final List<Terminal> bindTerms(QueryOptions options)
+ {
+ return filterUnsetValuesIfNeeded(checkValues(terms.bind(options)));
+ }
+
+ /**
+ * Checks that the output of a bind operations on {@code Terms} is a valid one.
+ * @param values the list to check
+ * @return the input list
+ */
+ private <T> List<T> checkValues(List<T> values)
+ {
+ checkFalse(values == null && operator.isIN(), "Invalid null list in IN condition");
+ checkFalse(values == Terms.UNSET_LIST, "Invalid 'unset' value in condition");
+ return values;
+ }
+
+ private <T> List<T> filterUnsetValuesIfNeeded(List<T> values)
+ {
+ if (!operator.isIN())
+ return values;
+
+ List<T> filtered = new ArrayList<>(values.size());
+ for (int i = 0, m = values.size(); i < m; i++)
+ {
+ T value = values.get(i);
+ // The value can be ByteBuffer or Constants.Value so we need to check the 2 type of UNSET
+ if (value != ByteBufferUtil.UNSET_BYTE_BUFFER && value != Constants.UNSET_VALUE)
+ filtered.add(value);
+ }
+ return filtered;
+ }
+
+ /**
+ * Simple condition (e.g. <pre>IF v = 1</pre>).
+ */
+ private static final class SimpleColumnCondition extends ColumnCondition
+ {
+ public SimpleColumnCondition(ColumnDefinition column, Operator op, Terms values)
+ {
+ super(column, op, values);
+ }
+
+ public Bound bind(QueryOptions options)
+ {
+ if (column.type.isCollection() && column.type.isMultiCell())
+ return new MultiCellCollectionBound(column, operator, bindTerms(options));
+
+ if (column.type.isUDT() && column.type.isMultiCell())
+ return new MultiCellUdtBound(column, operator, bindAndGetTerms(options), options.getProtocolVersion());
+
+ return new SimpleBound(column, operator, bindAndGetTerms(options));
+ }
+ }
+
+ /**
+ * A condition on a collection element (e.g. <pre>IF l[1] = 1</pre>).
+ */
+ private static class CollectionElementCondition extends ColumnCondition
+ {
+ private final Term collectionElement;
+
+ public CollectionElementCondition(ColumnDefinition column, Term collectionElement, Operator op, Terms values)
+ {
+ super(column, op, values);
+ this.collectionElement = collectionElement;
+ }
+
+ public void addFunctionsTo(List<Function> functions)
+ {
+ collectionElement.addFunctionsTo(functions);
+ super.addFunctionsTo(functions);
+ }
+
+ public void collectMarkerSpecification(VariableSpecifications boundNames)
+ {
+ collectionElement.collectMarkerSpecification(boundNames);
+ super.collectMarkerSpecification(boundNames);
+ }
+
+ public Bound bind(QueryOptions options)
+ {
+ return new ElementAccessBound(column, collectionElement.bindAndGet(options), operator, bindAndGetTerms(options));
+ }
+ }
+
+ /**
+ * A condition on a UDT field (e.g. <pre>IF v.a = 1</pre>).
+ */
+ private final static class UDTFieldCondition extends ColumnCondition
+ {
+ private final FieldIdentifier udtField;
+
+ public UDTFieldCondition(ColumnDefinition column, FieldIdentifier udtField, Operator op, Terms values)
+ {
+ super(column, op, values);
+ assert udtField != null;
+ this.udtField = udtField;
+ }
+
+ public Bound bind(QueryOptions options)
+ {
+ return new UDTFieldAccessBound(column, udtField, operator, bindAndGetTerms(options));
+ }
+ }
+
+ /**
+ * A regular column, simple condition.
+ */
+ public static ColumnCondition condition(ColumnDefinition column, Operator op, Terms terms)
+ {
+ return new SimpleColumnCondition(column, op, terms);
+ }
+
+ /**
+ * A collection column, simple condition.
+ */
+ public static ColumnCondition condition(ColumnDefinition column, Term collectionElement, Operator op, Terms terms)
+ {
+ return new CollectionElementCondition(column, collectionElement, op, terms);
+ }
+
+ /**
+ * A UDT column, simple condition.
+ */
+ public static ColumnCondition condition(ColumnDefinition column, FieldIdentifier udtField, Operator op, Terms terms)
+ {
+ return new UDTFieldCondition(column, udtField, op, terms);
+ }
+
+ public static abstract class Bound
+ {
+ public final ColumnDefinition column;
+ public final Operator comparisonOperator;
+
+ protected Bound(ColumnDefinition column, Operator operator)
+ {
+ this.column = column;
+ // If the operator is an IN we want to compare the value using an EQ.
+ this.comparisonOperator = operator.isIN() ? Operator.EQ : operator;
+ }
+
+ /**
+ * Validates whether this condition applies to {@code current}.
+ */
+ public abstract boolean appliesTo(Row row);
+
+ public ByteBuffer getCollectionElementValue()
+ {
+ return null;
+ }
+
+ /** Returns true if the operator is satisfied (i.e. "otherValue operator value == true"), false otherwise. */
+ protected static boolean compareWithOperator(Operator operator, AbstractType<?> type, ByteBuffer value, ByteBuffer otherValue)
+ {
+ if (value == ByteBufferUtil.UNSET_BYTE_BUFFER)
+ throw invalidRequest("Invalid 'unset' value in condition");
+
+ if (value == null)
+ {
+ switch (operator)
+ {
+ case EQ:
+ return otherValue == null;
+ case NEQ:
+ return otherValue != null;
+ default:
+ throw invalidRequest("Invalid comparison with null for operator \"%s\"", operator);
+ }
+ }
+ else if (otherValue == null)
+ {
+ // the condition value is not null, so only NEQ can return true
+ return operator == Operator.NEQ;
+ }
+ return operator.isSatisfiedBy(type, otherValue, value);
+ }
+ }
+
+ protected static final Cell getCell(Row row, ColumnDefinition column)
+ {
+ // If we're asking for a given cell, and we didn't got any row from our read, it's
+ // the same as not having said cell.
+ return row == null ? null : row.getCell(column);
+ }
+
+ protected static final Cell getCell(Row row, ColumnDefinition column, CellPath path)
+ {
+ // If we're asking for a given cell, and we didn't got any row from our read, it's
+ // the same as not having said cell.
+ return row == null ? null : row.getCell(column, path);
+ }
+
+ protected static final Iterator<Cell> getCells(Row row, ColumnDefinition column)
+ {
+ // If we're asking for a complex cells, and we didn't got any row from our read, it's
+ // the same as not having any cells for that column.
+ if (row == null)
+ return Collections.<Cell>emptyIterator();
+
+ ComplexColumnData complexData = row.getComplexColumnData(column);
+ return complexData == null ? Collections.<Cell>emptyIterator() : complexData.iterator();
+ }
+
+ protected static final boolean evaluateComparisonWithOperator(int comparison, Operator operator)
+ {
+ // called when comparison != 0
+ switch (operator)
+ {
+ case EQ:
+ return false;
+ case LT:
+ case LTE:
+ return comparison < 0;
+ case GT:
+ case GTE:
+ return comparison > 0;
+ case NEQ:
+ return true;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * A condition on a single non-collection column.
+ */
+ private static final class SimpleBound extends Bound
+ {
+ /**
+ * The condition values
+ */
+ private final List<ByteBuffer> values;
+
+ private SimpleBound(ColumnDefinition column, Operator operator, List<ByteBuffer> values)
+ {
+ super(column, operator);
+ this.values = values;
+ }
+
+ @Override
+ public boolean appliesTo(Row row)
+ {
+ return isSatisfiedBy(rowValue(row));
+ }
+
+ private ByteBuffer rowValue(Row row)
+ {
+ Cell c = getCell(row, column);
+ return c == null ? null : c.value();
+ }
+
+ private boolean isSatisfiedBy(ByteBuffer rowValue)
+ {
+ for (ByteBuffer value : values)
+ {
+ if (compareWithOperator(comparisonOperator, column.type, value, rowValue))
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * A condition on an element of a collection column.
+ */
+ private static final class ElementAccessBound extends Bound
+ {
+ /**
+ * The collection element
+ */
+ private final ByteBuffer collectionElement;
+
+ /**
+ * The conditions values.
+ */
+ private final List<ByteBuffer> values;
+
+ private ElementAccessBound(ColumnDefinition column,
+ ByteBuffer collectionElement,
+ Operator operator,
+ List<ByteBuffer> values)
+ {
+ super(column, operator);
+
+ this.collectionElement = collectionElement;
+ this.values = values;
+ }
+
+ @Override
+ public boolean appliesTo(Row row)
+ {
+ boolean isMap = column.type instanceof MapType;
+
+ if (collectionElement == null)
+ throw invalidRequest("Invalid null value for %s element access", isMap ? "map" : "list");
+
+ if (isMap)
+ {
+ MapType<?, ?> mapType = (MapType<?, ?>) column.type;
+ ByteBuffer rowValue = rowMapValue(mapType, row);
+ return isSatisfiedBy(mapType.getKeysType(), rowValue);
+ }
+
+ ListType<?> listType = (ListType<?>) column.type;
+ ByteBuffer rowValue = rowListValue(listType, row);
+ return isSatisfiedBy(listType.getElementsType(), rowValue);
+ }
+
+ private ByteBuffer rowMapValue(MapType<?, ?> type, Row row)
+ {
+ if (column.type.isMultiCell())
+ {
+ Cell cell = getCell(row, column, CellPath.create(collectionElement));
+ return cell == null ? null : cell.value();
+ }
+
+ Cell cell = getCell(row, column);
+ return cell == null
+ ? null
+ : type.getSerializer().getSerializedValue(cell.value(), collectionElement, type.getKeysType());
+ }
+
+ private ByteBuffer rowListValue(ListType<?> type, Row row)
+ {
+ if (column.type.isMultiCell())
+ return cellValueAtIndex(getCells(row, column), getListIndex(collectionElement));
+
+ Cell cell = getCell(row, column);
+ return cell == null
+ ? null
+ : type.getSerializer().getElement(cell.value(), getListIndex(collectionElement));
+ }
+
+ private static ByteBuffer cellValueAtIndex(Iterator<Cell> iter, int index)
+ {
+ int adv = Iterators.advance(iter, index);
+ if (adv == index && iter.hasNext())
+ return iter.next().value();
+
+ return null;
+ }
+
+ private boolean isSatisfiedBy(AbstractType<?> valueType, ByteBuffer rowValue)
+ {
+ for (ByteBuffer value : values)
+ {
+ if (compareWithOperator(comparisonOperator, valueType, value, rowValue))
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public ByteBuffer getCollectionElementValue()
+ {
+ return collectionElement;
+ }
+
+ private static int getListIndex(ByteBuffer collectionElement)
+ {
+ int idx = ByteBufferUtil.toInt(collectionElement);
+ checkFalse(idx < 0, "Invalid negative list index %d", idx);
+ return idx;
+ }
+ }
+
+ /**
+ * A condition on an entire collection column.
+ */
+ private static final class MultiCellCollectionBound extends Bound
+ {
+ private final List<Term.Terminal> values;
+
+ public MultiCellCollectionBound(ColumnDefinition column, Operator operator, List<Term.Terminal> values)
+ {
+ super(column, operator);
+ assert column.type.isMultiCell();
+ this.values = values;
+ }
+
+ public boolean appliesTo(Row row)
+ {
+ CollectionType<?> type = (CollectionType<?>)column.type;
+
+ // copy iterator contents so that we can properly reuse them for each comparison with an IN value
+ for (Term.Terminal value : values)
+ {
+ Iterator<Cell> iter = getCells(row, column);
+ if (value == null)
+ {
+ if (comparisonOperator == Operator.EQ)
+ {
+ if (!iter.hasNext())
+ return true;
+ continue;
+ }
+
+ if (comparisonOperator == Operator.NEQ)
+ return iter.hasNext();
+
+ throw invalidRequest("Invalid comparison with null for operator \"%s\"", comparisonOperator);
+ }
+
+ if (valueAppliesTo(type, iter, value, comparisonOperator))
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean valueAppliesTo(CollectionType<?> type, Iterator<Cell> iter, Term.Terminal value, Operator operator)
+ {
+ if (value == null)
+ return !iter.hasNext();
+
+ switch (type.kind)
+ {
+ case LIST:
+ List<ByteBuffer> valueList = ((Lists.Value) value).elements;
+ return listAppliesTo((ListType<?>)type, iter, valueList, operator);
+ case SET:
+ Set<ByteBuffer> valueSet = ((Sets.Value) value).elements;
+ return setAppliesTo((SetType<?>)type, iter, valueSet, operator);
+ case MAP:
+ Map<ByteBuffer, ByteBuffer> valueMap = ((Maps.Value) value).map;
+ return mapAppliesTo((MapType<?, ?>)type, iter, valueMap, operator);
+ }
+ throw new AssertionError();
+ }
+
+ private static boolean setOrListAppliesTo(AbstractType<?> type, Iterator<Cell> iter, Iterator<ByteBuffer> conditionIter, Operator operator, boolean isSet)
+ {
+ while(iter.hasNext())
+ {
+ if (!conditionIter.hasNext())
+ return (operator == Operator.GT) || (operator == Operator.GTE) || (operator == Operator.NEQ);
+
+ // for lists we use the cell value; for sets we use the cell name
+ ByteBuffer cellValue = isSet ? iter.next().path().get(0) : iter.next().value();
+ int comparison = type.compare(cellValue, conditionIter.next());
+ if (comparison != 0)
+ return evaluateComparisonWithOperator(comparison, operator);
+ }
+
+ if (conditionIter.hasNext())
+ return (operator == Operator.LT) || (operator == Operator.LTE) || (operator == Operator.NEQ);
+
+ // they're equal
+ return operator == Operator.EQ || operator == Operator.LTE || operator == Operator.GTE;
+ }
+
+ private static boolean listAppliesTo(ListType<?> type, Iterator<Cell> iter, List<ByteBuffer> elements, Operator operator)
+ {
+ return setOrListAppliesTo(type.getElementsType(), iter, elements.iterator(), operator, false);
+ }
+
+ private static boolean setAppliesTo(SetType<?> type, Iterator<Cell> iter, Set<ByteBuffer> elements, Operator operator)
+ {
+ ArrayList<ByteBuffer> sortedElements = new ArrayList<>(elements);
+ Collections.sort(sortedElements, type.getElementsType());
+ return setOrListAppliesTo(type.getElementsType(), iter, sortedElements.iterator(), operator, true);
+ }
+
+ private static boolean mapAppliesTo(MapType<?, ?> type, Iterator<Cell> iter, Map<ByteBuffer, ByteBuffer> elements, Operator operator)
+ {
+ Iterator<Map.Entry<ByteBuffer, ByteBuffer>> conditionIter = elements.entrySet().iterator();
+ while(iter.hasNext())
+ {
+ if (!conditionIter.hasNext())
+ return (operator == Operator.GT) || (operator == Operator.GTE) || (operator == Operator.NEQ);
+
+ Map.Entry<ByteBuffer, ByteBuffer> conditionEntry = conditionIter.next();
+ Cell c = iter.next();
+
+ // compare the keys
+ int comparison = type.getKeysType().compare(c.path().get(0), conditionEntry.getKey());
+ if (comparison != 0)
+ return evaluateComparisonWithOperator(comparison, operator);
+
+ // compare the values
+ comparison = type.getValuesType().compare(c.value(), conditionEntry.getValue());
+ if (comparison != 0)
+ return evaluateComparisonWithOperator(comparison, operator);
+ }
+
+ if (conditionIter.hasNext())
+ return (operator == Operator.LT) || (operator == Operator.LTE) || (operator == Operator.NEQ);
+
+ // they're equal
+ return operator == Operator.EQ || operator == Operator.LTE || operator == Operator.GTE;
+ }
+ }
+
+ /**
+ * A condition on a UDT field
+ */
+ private static final class UDTFieldAccessBound extends Bound
+ {
+ /**
+ * The UDT field.
+ */
+ private final FieldIdentifier field;
+
+ /**
+ * The conditions values.
+ */
+ private final List<ByteBuffer> values;
+
+ private UDTFieldAccessBound(ColumnDefinition column, FieldIdentifier field, Operator operator, List<ByteBuffer> values)
+ {
+ super(column, operator);
+ assert column.type.isUDT() && field != null;
+ this.field = field;
+ this.values = values;
+ }
+
+ @Override
+ public boolean appliesTo(Row row)
+ {
+ return isSatisfiedBy(rowValue(row));
+ }
+
+ private ByteBuffer rowValue(Row row)
+ {
+ UserType userType = (UserType) column.type;
+
+ if (column.type.isMultiCell())
+ {
+ Cell cell = getCell(row, column, userType.cellPathForField(field));
+ return cell == null ? null : cell.value();
+ }
+
+ Cell cell = getCell(row, column);
+ return cell == null
+ ? null
+ : userType.split(cell.value())[userType.fieldPosition(field)];
+ }
+
+ private boolean isSatisfiedBy(ByteBuffer rowValue)
+ {
+ UserType userType = (UserType) column.type;
+ int fieldPosition = userType.fieldPosition(field);
+ AbstractType<?> valueType = userType.fieldType(fieldPosition);
+ for (ByteBuffer value : values)
+ {
+ if (compareWithOperator(comparisonOperator, valueType, value, rowValue))
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * A condition on an entire UDT.
+ */
+ private static final class MultiCellUdtBound extends Bound
+ {
+ /**
+ * The conditions values.
+ */
+ private final List<ByteBuffer> values;
+
+ /**
+ * The protocol version
+ */
+ private final ProtocolVersion protocolVersion;
+
+ private MultiCellUdtBound(ColumnDefinition column, Operator op, List<ByteBuffer> values, ProtocolVersion protocolVersion)
+ {
+ super(column, op);
+ assert column.type.isMultiCell();
+ this.values = values;
+ this.protocolVersion = protocolVersion;
+ }
+
+ @Override
+ public boolean appliesTo(Row row)
+ {
+ return isSatisfiedBy(rowValue(row));
+ }
+
+ private final ByteBuffer rowValue(Row row)
+ {
+ UserType userType = (UserType) column.type;
+ Iterator<Cell> iter = getCells(row, column);
+ return iter.hasNext() ? userType.serializeForNativeProtocol(iter, protocolVersion) : null;
+ }
+
+ private boolean isSatisfiedBy(ByteBuffer rowValue)
+ {
+ for (ByteBuffer value : values)
+ {
+ if (compareWithOperator(comparisonOperator, column.type, value, rowValue))
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public static class Raw
+ {
+ private final Term.Raw value;
+ private final List<Term.Raw> inValues;
+ private final AbstractMarker.INRaw inMarker;
+
+ // Can be null, only used with the syntax "IF m[e] = ..." (in which case it's 'e')
+ private final Term.Raw collectionElement;
+
+ // Can be null, only used with the syntax "IF udt.field = ..." (in which case it's 'field')
+ private final FieldIdentifier udtField;
+
+ private final Operator operator;
+
+ private Raw(Term.Raw value, List<Term.Raw> inValues, AbstractMarker.INRaw inMarker, Term.Raw collectionElement,
+ FieldIdentifier udtField, Operator op)
+ {
+ this.value = value;
+ this.inValues = inValues;
+ this.inMarker = inMarker;
+ this.collectionElement = collectionElement;
+ this.udtField = udtField;
+ this.operator = op;
+ }
+
+ /** A condition on a column. For example: "IF col = 'foo'" */
+ public static Raw simpleCondition(Term.Raw value, Operator op)
+ {
+ return new Raw(value, null, null, null, null, op);
+ }
+
+ /** An IN condition on a column. For example: "IF col IN ('foo', 'bar', ...)" */
+ public static Raw simpleInCondition(List<Term.Raw> inValues)
+ {
+ return new Raw(null, inValues, null, null, null, Operator.IN);
+ }
+
+ /** An IN condition on a column with a single marker. For example: "IF col IN ?" */
+ public static Raw simpleInCondition(AbstractMarker.INRaw inMarker)
+ {
+ return new Raw(null, null, inMarker, null, null, Operator.IN);
+ }
+
+ /** A condition on a collection element. For example: "IF col['key'] = 'foo'" */
+ public static Raw collectionCondition(Term.Raw value, Term.Raw collectionElement, Operator op)
+ {
+ return new Raw(value, null, null, collectionElement, null, op);
+ }
+
+ /** An IN condition on a collection element. For example: "IF col['key'] IN ('foo', 'bar', ...)" */
+ public static Raw collectionInCondition(Term.Raw collectionElement, List<Term.Raw> inValues)
+ {
+ return new Raw(null, inValues, null, collectionElement, null, Operator.IN);
+ }
+
+ /** An IN condition on a collection element with a single marker. For example: "IF col['key'] IN ?" */
+ public static Raw collectionInCondition(Term.Raw collectionElement, AbstractMarker.INRaw inMarker)
+ {
+ return new Raw(null, null, inMarker, collectionElement, null, Operator.IN);
+ }
+
+ /** A condition on a UDT field. For example: "IF col.field = 'foo'" */
+ public static Raw udtFieldCondition(Term.Raw value, FieldIdentifier udtField, Operator op)
+ {
+ return new Raw(value, null, null, null, udtField, op);
+ }
+
+ /** An IN condition on a collection element. For example: "IF col.field IN ('foo', 'bar', ...)" */
+ public static Raw udtFieldInCondition(FieldIdentifier udtField, List<Term.Raw> inValues)
+ {
+ return new Raw(null, inValues, null, null, udtField, Operator.IN);
+ }
+
+ /** An IN condition on a collection element with a single marker. For example: "IF col.field IN ?" */
+ public static Raw udtFieldInCondition(FieldIdentifier udtField, AbstractMarker.INRaw inMarker)
+ {
+ return new Raw(null, null, inMarker, null, udtField, Operator.IN);
+ }
+
+ public ColumnCondition prepare(String keyspace, ColumnDefinition receiver, CFMetaData cfm)
+ {
+ if (receiver.type instanceof CounterColumnType)
+ throw invalidRequest("Conditions on counters are not supported");
+
+ if (collectionElement != null)
+ {
+ if (!(receiver.type.isCollection()))
+ throw invalidRequest("Invalid element access syntax for non-collection column %s", receiver.name);
+
+ ColumnSpecification elementSpec, valueSpec;
+ switch ((((CollectionType<?>) receiver.type).kind))
+ {
+ case LIST:
+ elementSpec = Lists.indexSpecOf(receiver);
+ valueSpec = Lists.valueSpecOf(receiver);
+ break;
+ case MAP:
+ elementSpec = Maps.keySpecOf(receiver);
+ valueSpec = Maps.valueSpecOf(receiver);
+ break;
+ case SET:
+ throw invalidRequest("Invalid element access syntax for set column %s", receiver.name);
+ default:
+ throw new AssertionError();
+ }
+
+ return condition(receiver, collectionElement.prepare(keyspace, elementSpec), operator, prepareTerms(keyspace, valueSpec));
+ }
+
+ if (udtField != null)
+ {
+ UserType userType = (UserType) receiver.type;
+ int fieldPosition = userType.fieldPosition(udtField);
+ if (fieldPosition == -1)
+ throw invalidRequest("Unknown field %s for column %s", udtField, receiver.name);
+
+ ColumnSpecification fieldReceiver = UserTypes.fieldSpecOf(receiver, fieldPosition);
+ return condition(receiver, udtField, operator, prepareTerms(keyspace, fieldReceiver));
+ }
+
+ return condition(receiver, operator, prepareTerms(keyspace, receiver));
+ }
+
+ private Terms prepareTerms(String keyspace, ColumnSpecification receiver)
+ {
+ if (operator.isIN())
+ {
+ return inValues == null ? Terms.ofListMarker(inMarker.prepare(keyspace, receiver), receiver.type)
+ : Terms.of(prepareTerms(keyspace, receiver, inValues));
+ }
+
+ return Terms.of(value.prepare(keyspace, receiver));
+ }
+
+ private static List<Term> prepareTerms(String keyspace, ColumnSpecification receiver, List<Term.Raw> raws)
+ {
+ List<Term> terms = new ArrayList<>(raws.size());
+ for (int i = 0, m = raws.size(); i < m; i++)
+ {
+ Term.Raw raw = raws.get(i);
+ terms.add(raw.prepare(keyspace, receiver));
+ }
+ return terms;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e71a49e8/src/java/org/apache/cassandra/cql3/conditions/ColumnConditions.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/conditions/ColumnConditions.java b/src/java/org/apache/cassandra/cql3/conditions/ColumnConditions.java
new file mode 100644
index 0000000..b0378b7
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/conditions/ColumnConditions.java
@@ -0,0 +1,165 @@
+/*
+ * 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.conditions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+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.CQL3CasRequest;
+import org.apache.cassandra.db.Clustering;
+
+/**
+ * A set of <code>ColumnCondition</code>s.
+ *
+ */
+public final class ColumnConditions extends AbstractConditions
+{
+ /**
+ * The conditions on regular columns.
+ */
+ private final List<ColumnCondition> columnConditions;
+
+ /**
+ * The conditions on static columns
+ */
+ private final List<ColumnCondition> staticConditions;
+
+ /**
+ * Creates a new <code>ColumnConditions</code> instance for the specified builder.
+ */
+ private ColumnConditions(Builder builder)
+ {
+ this.columnConditions = builder.columnConditions;
+ this.staticConditions = builder.staticConditions;
+ }
+
+ @Override
+ public boolean appliesToStaticColumns()
+ {
+ return !staticConditions.isEmpty();
+ }
+
+ @Override
+ public boolean appliesToRegularColumns()
+ {
+ return !columnConditions.isEmpty();
+ }
+
+ @Override
+ public Collection<ColumnDefinition> getColumns()
+ {
+ return Stream.concat(columnConditions.stream(), staticConditions.stream())
+ .map(e -> e.column)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return columnConditions.isEmpty() && staticConditions.isEmpty();
+ }
+
+ /**
+ * Adds the conditions to the specified CAS request.
+ *
+ * @param request the request
+ * @param clustering the clustering prefix
+ * @param options the query options
+ */
+ public void addConditionsTo(CQL3CasRequest request,
+ Clustering clustering,
+ QueryOptions options)
+ {
+ if (!columnConditions.isEmpty())
+ request.addConditions(clustering, columnConditions, options);
+ if (!staticConditions.isEmpty())
+ request.addConditions(Clustering.STATIC_CLUSTERING, staticConditions, options);
+ }
+
+ @Override
+ public void addFunctionsTo(List<Function> functions)
+ {
+ columnConditions.forEach(p -> p.addFunctionsTo(functions));
+ staticConditions.forEach(p -> p.addFunctionsTo(functions));
+ }
+
+ /**
+ * Creates a new <code>Builder</code> for <code>ColumnConditions</code>.
+ * @return a new <code>Builder</code> for <code>ColumnConditions</code>
+ */
+ public static Builder newBuilder()
+ {
+ return new Builder();
+ }
+
+ /**
+ * A <code>Builder</code> for <code>ColumnConditions</code>.
+ *
+ */
+ public static final class Builder
+ {
+ /**
+ * The conditions on regular columns.
+ */
+ private List<ColumnCondition> columnConditions = Collections.emptyList();
+
+ /**
+ * The conditions on static columns
+ */
+ private List<ColumnCondition> staticConditions = Collections.emptyList();
+
+ /**
+ * Adds the specified <code>ColumnCondition</code> to this set of conditions.
+ * @param condition the condition to add
+ */
+ public Builder add(ColumnCondition condition)
+ {
+ List<ColumnCondition> conds = null;
+ if (condition.column.isStatic())
+ {
+ if (staticConditions.isEmpty())
+ staticConditions = new ArrayList<>();
+ conds = staticConditions;
+ }
+ else
+ {
+ if (columnConditions.isEmpty())
+ columnConditions = new ArrayList<>();
+ conds = columnConditions;
+ }
+ conds.add(condition);
+ return this;
+ }
+
+ public ColumnConditions build()
+ {
+ return new ColumnConditions(this);
+ }
+
+ private Builder()
+ {
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e71a49e8/src/java/org/apache/cassandra/cql3/conditions/Conditions.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/conditions/Conditions.java b/src/java/org/apache/cassandra/cql3/conditions/Conditions.java
new file mode 100644
index 0000000..0214fcf
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/conditions/Conditions.java
@@ -0,0 +1,103 @@
+/*
+ * 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.conditions;
+
+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.CQL3CasRequest;
+import org.apache.cassandra.db.Clustering;
+
+/**
+ * Conditions that can be applied to a mutation statement.
+ *
+ */
+public interface Conditions
+{
+ /**
+ * An EMPTY condition
+ */
+ static final Conditions EMPTY_CONDITION = ColumnConditions.newBuilder().build();
+
+ /**
+ * IF EXISTS condition
+ */
+ static final Conditions IF_EXISTS_CONDITION = new IfExistsCondition();
+
+ /**
+ * IF NOT EXISTS condition
+ */
+ static final Conditions IF_NOT_EXISTS_CONDITION = new IfNotExistsCondition();
+
+ /**
+ * Adds the functions used by the conditions to the specified list.
+ * @param functions the list to add to
+ */
+ void addFunctionsTo(List<Function> functions);
+
+ /**
+ * Returns the column definitions to which apply the conditions.
+ * @return the column definitions to which apply the conditions.
+ */
+ Iterable<ColumnDefinition> getColumns();
+
+ /**
+ * Checks if this <code>Conditions</code> is empty.
+ * @return <code>true</code> if this <code>Conditions</code> is empty, <code>false</code> otherwise.
+ */
+ boolean isEmpty();
+
+ /**
+ * Checks if this is a IF EXIST condition.
+ * @return <code>true</code> if this is a IF EXIST condition, <code>false</code> otherwise.
+ */
+ boolean isIfExists();
+
+ /**
+ * Checks if this is a IF NOT EXIST condition.
+ * @return <code>true</code> if this is a IF NOT EXIST condition, <code>false</code> otherwise.
+ */
+ boolean isIfNotExists();
+
+ /**
+ * Checks if some of the conditions apply to static columns.
+ *
+ * @return <code>true</code> if some of the conditions apply to static columns, <code>false</code> otherwise.
+ */
+ boolean appliesToStaticColumns();
+
+ /**
+ * Checks if some of the conditions apply to regular columns.
+ *
+ * @return <code>true</code> if some of the conditions apply to regular columns, <code>false</code> otherwise.
+ */
+ boolean appliesToRegularColumns();
+
+ /**
+ * Adds the conditions to the specified CAS request.
+ *
+ * @param request the request
+ * @param clustering the clustering prefix
+ * @param options the query options
+ */
+ public void addConditionsTo(CQL3CasRequest request,
+ Clustering clustering,
+ QueryOptions options);
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e71a49e8/src/java/org/apache/cassandra/cql3/conditions/IfExistsCondition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/conditions/IfExistsCondition.java b/src/java/org/apache/cassandra/cql3/conditions/IfExistsCondition.java
new file mode 100644
index 0000000..fa8822d
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/conditions/IfExistsCondition.java
@@ -0,0 +1,37 @@
+/*
+ * 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.conditions;
+
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.statements.CQL3CasRequest;
+import org.apache.cassandra.db.Clustering;
+
+final class IfExistsCondition extends AbstractConditions
+{
+ @Override
+ public void addConditionsTo(CQL3CasRequest request, Clustering clustering, QueryOptions options)
+ {
+ request.addExist(clustering);
+ }
+
+ @Override
+ public boolean isIfExists()
+ {
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e71a49e8/src/java/org/apache/cassandra/cql3/conditions/IfNotExistsCondition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/conditions/IfNotExistsCondition.java b/src/java/org/apache/cassandra/cql3/conditions/IfNotExistsCondition.java
new file mode 100644
index 0000000..ede9119
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/conditions/IfNotExistsCondition.java
@@ -0,0 +1,37 @@
+/*
+ * 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.conditions;
+
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.statements.CQL3CasRequest;
+import org.apache.cassandra.db.Clustering;
+
+final class IfNotExistsCondition extends AbstractConditions
+{
+ @Override
+ public void addConditionsTo(CQL3CasRequest request, Clustering clustering, QueryOptions options)
+ {
+ request.addNotExist(clustering);
+ }
+
+ @Override
+ public boolean isIfNotExists()
+ {
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e71a49e8/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java b/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java
index c203ace..4cf2baf 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java
@@ -24,6 +24,7 @@ import com.google.common.collect.*;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.conditions.ColumnCondition;
import org.apache.cassandra.db.*;
import org.apache.cassandra.db.filter.*;
import org.apache.cassandra.db.rows.Row;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e71a49e8/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
index 26b25de..10f3d6f 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
@@ -22,6 +22,8 @@ import java.util.List;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.conditions.ColumnCondition;
+import org.apache.cassandra.cql3.conditions.Conditions;
import org.apache.cassandra.cql3.restrictions.StatementRestrictions;
import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.Slice;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e71a49e8/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
index 6f2ab44..601ddf7 100644
--- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
@@ -30,6 +30,9 @@ import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.config.ColumnDefinition.Raw;
import org.apache.cassandra.config.ViewDefinition;
import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.conditions.ColumnCondition;
+import org.apache.cassandra.cql3.conditions.ColumnConditions;
+import org.apache.cassandra.cql3.conditions.Conditions;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.restrictions.StatementRestrictions;
import org.apache.cassandra.cql3.selection.Selection;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e71a49e8/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
index 86d7171..01d47bd 100644
--- a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
@@ -24,6 +24,8 @@ import java.util.List;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.conditions.ColumnCondition;
+import org.apache.cassandra.cql3.conditions.Conditions;
import org.apache.cassandra.cql3.restrictions.StatementRestrictions;
import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.CompactTables;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e71a49e8/test/unit/org/apache/cassandra/cql3/ColumnConditionTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/ColumnConditionTest.java b/test/unit/org/apache/cassandra/cql3/ColumnConditionTest.java
deleted file mode 100644
index ca0c182..0000000
--- a/test/unit/org/apache/cassandra/cql3/ColumnConditionTest.java
+++ /dev/null
@@ -1,589 +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;
-
-import java.nio.ByteBuffer;
-import java.util.*;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import org.apache.cassandra.config.CFMetaData;
-import org.apache.cassandra.config.ColumnDefinition;
-import org.apache.cassandra.config.DatabaseDescriptor;
-import org.apache.cassandra.db.rows.BufferCell;
-import org.apache.cassandra.db.rows.Cell;
-import org.apache.cassandra.db.rows.CellPath;
-import org.apache.cassandra.db.marshal.*;
-import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.serializers.Int32Serializer;
-import org.apache.cassandra.utils.ByteBufferUtil;
-import org.apache.cassandra.utils.UUIDGen;
-
-import static org.junit.Assert.*;
-
-public class ColumnConditionTest
-{
- private static final CellPath LIST_PATH = CellPath.create(ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes()));
-
- public static final ByteBuffer ZERO = Int32Type.instance.fromString("0");
- public static final ByteBuffer ONE = Int32Type.instance.fromString("1");
- public static final ByteBuffer TWO = Int32Type.instance.fromString("2");
-
- public static final ByteBuffer A = AsciiType.instance.fromString("a");
- public static final ByteBuffer B = AsciiType.instance.fromString("b");
-
- @BeforeClass
- public static void setupDD()
- {
- DatabaseDescriptor.daemonInitialization();
- }
-
- private static boolean isSatisfiedBy(ColumnCondition.Bound bound, ByteBuffer conditionValue, ByteBuffer columnValue) throws InvalidRequestException
- {
- Cell cell = null;
- if (columnValue != null)
- {
- ColumnDefinition definition = ColumnDefinition.regularDef("ks", "cf", "c", ListType.getInstance(Int32Type.instance, true));
- cell = testCell(definition, columnValue, LIST_PATH);
- }
- return bound.isSatisfiedByValue(conditionValue, cell, Int32Type.instance, bound.operator);
- }
-
- private static Cell testCell(ColumnDefinition column, ByteBuffer value, CellPath path)
- {
- return new BufferCell(column, 0L, Cell.NO_TTL, Cell.NO_DELETION_TIME, value, path);
- }
-
- private static void assertThrowsIRE(ColumnCondition.Bound bound, ByteBuffer conditionValue, ByteBuffer columnValue)
- {
- try
- {
- isSatisfiedBy(bound, conditionValue, columnValue);
- fail("Expected InvalidRequestException was not thrown");
- } catch (InvalidRequestException e) { }
- }
-
- @Test
- public void testSimpleBoundIsSatisfiedByValue() throws InvalidRequestException
- {
- ColumnDefinition definition = ColumnDefinition.regularDef("ks", "cf", "c", ListType.getInstance(Int32Type.instance, true));
-
- // EQ
- ColumnCondition condition = ColumnCondition.condition(definition, new Constants.Value(ONE), Operator.EQ);
- ColumnCondition.Bound bound = condition.bind(QueryOptions.DEFAULT);
- assertTrue(isSatisfiedBy(bound, ONE, ONE));
- assertFalse(isSatisfiedBy(bound, ZERO, ONE));
- assertFalse(isSatisfiedBy(bound, TWO, ONE));
- assertFalse(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE));
- assertFalse(isSatisfiedBy(bound, ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertTrue(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertTrue(isSatisfiedBy(bound, null, null));
- assertFalse(isSatisfiedBy(bound, ONE, null));
- assertFalse(isSatisfiedBy(bound, null, ONE));
-
- // NEQ
- condition = ColumnCondition.condition(definition, new Constants.Value(ONE), Operator.NEQ);
- bound = condition.bind(QueryOptions.DEFAULT);
- assertFalse(isSatisfiedBy(bound, ONE, ONE));
- assertTrue(isSatisfiedBy(bound, ZERO, ONE));
- assertTrue(isSatisfiedBy(bound, TWO, ONE));
- assertTrue(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE));
- assertTrue(isSatisfiedBy(bound, ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertFalse(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertFalse(isSatisfiedBy(bound, null, null));
- assertTrue(isSatisfiedBy(bound, ONE, null));
- assertTrue(isSatisfiedBy(bound, null, ONE));
-
- // LT
- condition = ColumnCondition.condition(definition, new Constants.Value(ONE), Operator.LT);
- bound = condition.bind(QueryOptions.DEFAULT);
- assertFalse(isSatisfiedBy(bound, ONE, ONE));
- assertFalse(isSatisfiedBy(bound, ZERO, ONE));
- assertTrue(isSatisfiedBy(bound, TWO, ONE));
- assertFalse(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE));
- assertTrue(isSatisfiedBy(bound, ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertFalse(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertThrowsIRE(bound, null, ONE);
- assertFalse(isSatisfiedBy(bound, ONE, null));
-
- // LTE
- condition = ColumnCondition.condition(definition, new Constants.Value(ONE), Operator.LTE);
- bound = condition.bind(QueryOptions.DEFAULT);
- assertTrue(isSatisfiedBy(bound, ONE, ONE));
- assertFalse(isSatisfiedBy(bound, ZERO, ONE));
- assertTrue(isSatisfiedBy(bound, TWO, ONE));
- assertFalse(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE));
- assertTrue(isSatisfiedBy(bound, ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertTrue(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertThrowsIRE(bound, null, ONE);
- assertFalse(isSatisfiedBy(bound, ONE, null));
-
- // GT
- condition = ColumnCondition.condition(definition, new Constants.Value(ONE), Operator.GT);
- bound = condition.bind(QueryOptions.DEFAULT);
- assertFalse(isSatisfiedBy(bound, ONE, ONE));
- assertTrue(isSatisfiedBy(bound, ZERO, ONE));
- assertFalse(isSatisfiedBy(bound, TWO, ONE));
- assertTrue(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE));
- assertFalse(isSatisfiedBy(bound, ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertFalse(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertThrowsIRE(bound, null, ONE);
- assertFalse(isSatisfiedBy(bound, ONE, null));
-
- // GT
- condition = ColumnCondition.condition(definition, new Constants.Value(ONE), Operator.GTE);
- bound = condition.bind(QueryOptions.DEFAULT);
- assertTrue(isSatisfiedBy(bound, ONE, ONE));
- assertTrue(isSatisfiedBy(bound, ZERO, ONE));
- assertFalse(isSatisfiedBy(bound, TWO, ONE));
- assertTrue(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE));
- assertFalse(isSatisfiedBy(bound, ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertTrue(isSatisfiedBy(bound, ByteBufferUtil.EMPTY_BYTE_BUFFER, ByteBufferUtil.EMPTY_BYTE_BUFFER));
- assertThrowsIRE(bound, null, ONE);
- assertFalse(isSatisfiedBy(bound, ONE, null));
- }
-
- private static List<ByteBuffer> list(ByteBuffer... values)
- {
- return Arrays.asList(values);
- }
-
- private static boolean listAppliesTo(ColumnCondition.CollectionBound bound, List<ByteBuffer> conditionValues, List<ByteBuffer> columnValues)
- {
- CFMetaData cfm = CFMetaData.compile("create table foo(a int PRIMARY KEY, b int, c list<int>)", "ks");
- Map<ByteBuffer, CollectionType> typeMap = new HashMap<>();
- typeMap.put(ByteBufferUtil.bytes("c"), ListType.getInstance(Int32Type.instance, true));
-
- ColumnDefinition definition = ColumnDefinition.regularDef(cfm, ByteBufferUtil.bytes("c"), ListType.getInstance(Int32Type.instance, true));
-
- List<Cell> cells = new ArrayList<>(columnValues.size());
- if (columnValues != null)
- {
- for (int i = 0; i < columnValues.size(); i++)
- {
- ByteBuffer key = Int32Serializer.instance.serialize(i);
- ByteBuffer value = columnValues.get(i);
- cells.add(testCell(definition, value, CellPath.create(key)));
- };
- }
-
- return bound.listAppliesTo(ListType.getInstance(Int32Type.instance, true), cells == null ? null : cells.iterator(), conditionValues, bound.operator);
- }
-
- @Test
- // sets use the same check as lists
- public void testListCollectionBoundAppliesTo() throws InvalidRequestException
- {
- ColumnDefinition definition = ColumnDefinition.regularDef("ks", "cf", "c", ListType.getInstance(Int32Type.instance, true));
-
- // EQ
- ColumnCondition condition = ColumnCondition.condition(definition, new Lists.Value(Arrays.asList(ONE)), Operator.EQ);
- ColumnCondition.CollectionBound bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertTrue(listAppliesTo(bound, list(ONE), list(ONE)));
- assertTrue(listAppliesTo(bound, list(), list()));
- assertFalse(listAppliesTo(bound, list(ZERO), list(ONE)));
- assertFalse(listAppliesTo(bound, list(ONE), list(ZERO)));
- assertFalse(listAppliesTo(bound, list(ONE), list(ONE, ONE)));
- assertFalse(listAppliesTo(bound, list(ONE, ONE), list(ONE)));
- assertFalse(listAppliesTo(bound, list(), list(ONE)));
- assertFalse(listAppliesTo(bound, list(ONE), list()));
-
- assertFalse(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertFalse(listAppliesTo(bound, list(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertTrue(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // NEQ
- condition = ColumnCondition.condition(definition, new Lists.Value(Arrays.asList(ONE)), Operator.NEQ);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertFalse(listAppliesTo(bound, list(ONE), list(ONE)));
- assertFalse(listAppliesTo(bound, list(), list()));
- assertTrue(listAppliesTo(bound, list(ZERO), list(ONE)));
- assertTrue(listAppliesTo(bound, list(ONE), list(ZERO)));
- assertTrue(listAppliesTo(bound, list(ONE), list(ONE, ONE)));
- assertTrue(listAppliesTo(bound, list(ONE, ONE), list(ONE)));
- assertTrue(listAppliesTo(bound, list(), list(ONE)));
- assertTrue(listAppliesTo(bound, list(ONE), list()));
-
- assertTrue(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertTrue(listAppliesTo(bound, list(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertFalse(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // LT
- condition = ColumnCondition.condition(definition, new Lists.Value(Arrays.asList(ONE)), Operator.LT);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertFalse(listAppliesTo(bound, list(ONE), list(ONE)));
- assertFalse(listAppliesTo(bound, list(), list()));
- assertFalse(listAppliesTo(bound, list(ZERO), list(ONE)));
- assertTrue(listAppliesTo(bound, list(ONE), list(ZERO)));
- assertFalse(listAppliesTo(bound, list(ONE), list(ONE, ONE)));
- assertTrue(listAppliesTo(bound, list(ONE, ONE), list(ONE)));
- assertFalse(listAppliesTo(bound, list(), list(ONE)));
- assertTrue(listAppliesTo(bound, list(ONE), list()));
-
- assertFalse(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertTrue(listAppliesTo(bound, list(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertFalse(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // LTE
- condition = ColumnCondition.condition(definition, new Lists.Value(Arrays.asList(ONE)), Operator.LTE);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertTrue(listAppliesTo(bound, list(ONE), list(ONE)));
- assertTrue(listAppliesTo(bound, list(), list()));
- assertFalse(listAppliesTo(bound, list(ZERO), list(ONE)));
- assertTrue(listAppliesTo(bound, list(ONE), list(ZERO)));
- assertFalse(listAppliesTo(bound, list(ONE), list(ONE, ONE)));
- assertTrue(listAppliesTo(bound, list(ONE, ONE), list(ONE)));
- assertFalse(listAppliesTo(bound, list(), list(ONE)));
- assertTrue(listAppliesTo(bound, list(ONE), list()));
-
- assertFalse(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertTrue(listAppliesTo(bound, list(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertTrue(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // GT
- condition = ColumnCondition.condition(definition, new Lists.Value(Arrays.asList(ONE)), Operator.GT);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertFalse(listAppliesTo(bound, list(ONE), list(ONE)));
- assertFalse(listAppliesTo(bound, list(), list()));
- assertTrue(listAppliesTo(bound, list(ZERO), list(ONE)));
- assertFalse(listAppliesTo(bound, list(ONE), list(ZERO)));
- assertTrue(listAppliesTo(bound, list(ONE), list(ONE, ONE)));
- assertFalse(listAppliesTo(bound, list(ONE, ONE), list(ONE)));
- assertTrue(listAppliesTo(bound, list(), list(ONE)));
- assertFalse(listAppliesTo(bound, list(ONE), list()));
-
- assertTrue(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertFalse(listAppliesTo(bound, list(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertFalse(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // GTE
- condition = ColumnCondition.condition(definition, new Lists.Value(Arrays.asList(ONE)), Operator.GTE);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertTrue(listAppliesTo(bound, list(ONE), list(ONE)));
- assertTrue(listAppliesTo(bound, list(), list()));
- assertTrue(listAppliesTo(bound, list(ZERO), list(ONE)));
- assertFalse(listAppliesTo(bound, list(ONE), list(ZERO)));
- assertTrue(listAppliesTo(bound, list(ONE), list(ONE, ONE)));
- assertFalse(listAppliesTo(bound, list(ONE, ONE), list(ONE)));
- assertTrue(listAppliesTo(bound, list(), list(ONE)));
- assertFalse(listAppliesTo(bound, list(ONE), list()));
-
- assertTrue(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertFalse(listAppliesTo(bound, list(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertTrue(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- }
-
- private static SortedSet<ByteBuffer> set(ByteBuffer... values)
- {
- SortedSet<ByteBuffer> results = new TreeSet<>(Int32Type.instance);
- results.addAll(Arrays.asList(values));
- return results;
- }
-
- private static boolean setAppliesTo(ColumnCondition.CollectionBound bound, Set<ByteBuffer> conditionValues, List<ByteBuffer> columnValues)
- {
- CFMetaData cfm = CFMetaData.compile("create table foo(a int PRIMARY KEY, b int, c set<int>)", "ks");
- Map<ByteBuffer, CollectionType> typeMap = new HashMap<>();
- typeMap.put(ByteBufferUtil.bytes("c"), SetType.getInstance(Int32Type.instance, true));
- ColumnDefinition definition = ColumnDefinition.regularDef(cfm, ByteBufferUtil.bytes("c"), SetType.getInstance(Int32Type.instance, true));
-
- List<Cell> cells = new ArrayList<>(columnValues.size());
- if (columnValues != null)
- {
- for (int i = 0; i < columnValues.size(); i++)
- {
- ByteBuffer key = columnValues.get(i);
- cells.add(testCell(definition, ByteBufferUtil.EMPTY_BYTE_BUFFER, CellPath.create(key)));
- };
- }
-
- return bound.setAppliesTo(SetType.getInstance(Int32Type.instance, true), cells == null ? null : cells.iterator(), conditionValues, bound.operator);
- }
-
- @Test
- public void testSetCollectionBoundAppliesTo() throws InvalidRequestException
- {
- ColumnDefinition definition = ColumnDefinition.regularDef("ks", "cf", "c", ListType.getInstance(Int32Type.instance, true));
-
- // EQ
- ColumnCondition condition = ColumnCondition.condition(definition, new Sets.Value(set(ONE)), Operator.EQ);
- ColumnCondition.CollectionBound bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertTrue(setAppliesTo(bound, set(ONE), list(ONE)));
- assertTrue(setAppliesTo(bound, set(), list()));
- assertFalse(setAppliesTo(bound, set(ZERO), list(ONE)));
- assertFalse(setAppliesTo(bound, set(ONE), list(ZERO)));
- assertFalse(setAppliesTo(bound, set(ONE), list(ONE, TWO)));
- assertFalse(setAppliesTo(bound, set(ONE, TWO), list(ONE)));
- assertFalse(setAppliesTo(bound, set(), list(ONE)));
- assertFalse(setAppliesTo(bound, set(ONE), list()));
-
- assertFalse(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertFalse(setAppliesTo(bound, set(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertTrue(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // NEQ
- condition = ColumnCondition.condition(definition, new Sets.Value(set(ONE)), Operator.NEQ);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertFalse(setAppliesTo(bound, set(ONE), list(ONE)));
- assertFalse(setAppliesTo(bound, set(), list()));
- assertTrue(setAppliesTo(bound, set(ZERO), list(ONE)));
- assertTrue(setAppliesTo(bound, set(ONE), list(ZERO)));
- assertTrue(setAppliesTo(bound, set(ONE), list(ONE, TWO)));
- assertTrue(setAppliesTo(bound, set(ONE, TWO), list(ONE)));
- assertTrue(setAppliesTo(bound, set(), list(ONE)));
- assertTrue(setAppliesTo(bound, set(ONE), list()));
-
- assertTrue(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertTrue(setAppliesTo(bound, set(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertFalse(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // LT
- condition = ColumnCondition.condition(definition, new Lists.Value(Arrays.asList(ONE)), Operator.LT);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertFalse(setAppliesTo(bound, set(ONE), list(ONE)));
- assertFalse(setAppliesTo(bound, set(), list()));
- assertFalse(setAppliesTo(bound, set(ZERO), list(ONE)));
- assertTrue(setAppliesTo(bound, set(ONE), list(ZERO)));
- assertFalse(setAppliesTo(bound, set(ONE), list(ONE, TWO)));
- assertTrue(setAppliesTo(bound, set(ONE, TWO), list(ONE)));
- assertFalse(setAppliesTo(bound, set(), list(ONE)));
- assertTrue(setAppliesTo(bound, set(ONE), list()));
-
- assertFalse(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertTrue(setAppliesTo(bound, set(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertFalse(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // LTE
- condition = ColumnCondition.condition(definition, new Lists.Value(Arrays.asList(ONE)), Operator.LTE);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertTrue(setAppliesTo(bound, set(ONE), list(ONE)));
- assertTrue(setAppliesTo(bound, set(), list()));
- assertFalse(setAppliesTo(bound, set(ZERO), list(ONE)));
- assertTrue(setAppliesTo(bound, set(ONE), list(ZERO)));
- assertFalse(setAppliesTo(bound, set(ONE), list(ONE, TWO)));
- assertTrue(setAppliesTo(bound, set(ONE, TWO), list(ONE)));
- assertFalse(setAppliesTo(bound, set(), list(ONE)));
- assertTrue(setAppliesTo(bound, set(ONE), list()));
-
- assertFalse(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertTrue(setAppliesTo(bound, set(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertTrue(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // GT
- condition = ColumnCondition.condition(definition, new Lists.Value(Arrays.asList(ONE)), Operator.GT);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertFalse(setAppliesTo(bound, set(ONE), list(ONE)));
- assertFalse(setAppliesTo(bound, set(), list()));
- assertTrue(setAppliesTo(bound, set(ZERO), list(ONE)));
- assertFalse(setAppliesTo(bound, set(ONE), list(ZERO)));
- assertTrue(setAppliesTo(bound, set(ONE), list(ONE, TWO)));
- assertFalse(setAppliesTo(bound, set(ONE, TWO), list(ONE)));
- assertTrue(setAppliesTo(bound, set(), list(ONE)));
- assertFalse(setAppliesTo(bound, set(ONE), list()));
-
- assertTrue(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertFalse(setAppliesTo(bound, set(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertFalse(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // GTE
- condition = ColumnCondition.condition(definition, new Lists.Value(Arrays.asList(ONE)), Operator.GTE);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
- assertTrue(setAppliesTo(bound, set(ONE), list(ONE)));
- assertTrue(setAppliesTo(bound, set(), list()));
- assertTrue(setAppliesTo(bound, set(ZERO), list(ONE)));
- assertFalse(setAppliesTo(bound, set(ONE), list(ZERO)));
- assertTrue(setAppliesTo(bound, set(ONE), list(ONE, TWO)));
- assertFalse(setAppliesTo(bound, set(ONE, TWO), list(ONE)));
- assertTrue(setAppliesTo(bound, set(), list(ONE)));
- assertFalse(setAppliesTo(bound, set(ONE), list()));
-
- assertTrue(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ONE)));
- assertFalse(setAppliesTo(bound, set(ONE), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertTrue(setAppliesTo(bound, set(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- }
-
- // values should be a list of key, value, key, value, ...
- private static Map<ByteBuffer, ByteBuffer> map(ByteBuffer... values)
- {
- Map<ByteBuffer, ByteBuffer> map = new TreeMap<>();
- for (int i = 0; i < values.length; i += 2)
- map.put(values[i], values[i + 1]);
-
- return map;
- }
-
- private static boolean mapAppliesTo(ColumnCondition.CollectionBound bound, Map<ByteBuffer, ByteBuffer> conditionValues, Map<ByteBuffer, ByteBuffer> columnValues)
- {
- CFMetaData cfm = CFMetaData.compile("create table foo(a int PRIMARY KEY, b map<int, int>)", "ks");
- Map<ByteBuffer, CollectionType> typeMap = new HashMap<>();
- typeMap.put(ByteBufferUtil.bytes("b"), MapType.getInstance(Int32Type.instance, Int32Type.instance, true));
- ColumnDefinition definition = ColumnDefinition.regularDef(cfm, ByteBufferUtil.bytes("b"), MapType.getInstance(Int32Type.instance, Int32Type.instance, true));
-
- List<Cell> cells = new ArrayList<>(columnValues.size());
- if (columnValues != null)
- {
- for (Map.Entry<ByteBuffer, ByteBuffer> entry : columnValues.entrySet())
- cells.add(testCell(definition, entry.getValue(), CellPath.create(entry.getKey())));
- }
-
- return bound.mapAppliesTo(MapType.getInstance(Int32Type.instance, Int32Type.instance, true), cells.iterator(), conditionValues, bound.operator);
- }
-
- @Test
- public void testMapCollectionBoundIsSatisfiedByValue() throws InvalidRequestException
- {
- ColumnDefinition definition = ColumnDefinition.regularDef("ks", "cf", "c", ListType.getInstance(Int32Type.instance, true));
-
- Map<ByteBuffer, ByteBuffer> placeholderMap = new TreeMap<>();
- placeholderMap.put(ONE, ONE);
- Maps.Value placeholder = new Maps.Value(placeholderMap);
-
- // EQ
- ColumnCondition condition = ColumnCondition.condition(definition, placeholder, Operator.EQ);
- ColumnCondition.CollectionBound bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
-
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(), map()));
- assertFalse(mapAppliesTo(bound, map(ZERO, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ZERO, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ZERO), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ZERO)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE, TWO, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE, TWO, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map()));
-
- assertFalse(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertTrue(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // NEQ
- condition = ColumnCondition.condition(definition, placeholder, Operator.NEQ);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
-
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(), map()));
- assertTrue(mapAppliesTo(bound, map(ZERO, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ZERO, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ZERO), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ZERO)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE, TWO, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE, TWO, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map()));
-
- assertTrue(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertFalse(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // LT
- condition = ColumnCondition.condition(definition, placeholder, Operator.LT);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
-
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(), map()));
- assertFalse(mapAppliesTo(bound, map(ZERO, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ZERO, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ZERO), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ZERO)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE, TWO, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE, TWO, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map()));
-
- assertFalse(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertFalse(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // LTE
- condition = ColumnCondition.condition(definition, placeholder, Operator.LTE);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
-
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(), map()));
- assertFalse(mapAppliesTo(bound, map(ZERO, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ZERO, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ZERO), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ZERO)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE, TWO, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE, TWO, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map()));
-
- assertFalse(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertTrue(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // GT
- condition = ColumnCondition.condition(definition, placeholder, Operator.GT);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
-
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(), map()));
- assertTrue(mapAppliesTo(bound, map(ZERO, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ZERO, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ZERO), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ZERO)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE, TWO, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE, TWO, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map()));
-
- assertTrue(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertFalse(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
-
- // GTE
- condition = ColumnCondition.condition(definition, placeholder, Operator.GTE);
- bound = (ColumnCondition.CollectionBound) condition.bind(QueryOptions.DEFAULT);
-
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(), map()));
- assertTrue(mapAppliesTo(bound, map(ZERO, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ZERO, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ZERO), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ZERO)));
- assertTrue(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ONE, TWO, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE, TWO, ONE), map(ONE, ONE)));
- assertTrue(mapAppliesTo(bound, map(), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map()));
-
- assertTrue(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ONE)));
- assertFalse(mapAppliesTo(bound, map(ONE, ONE), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- assertTrue(mapAppliesTo(bound, map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE), map(ByteBufferUtil.EMPTY_BYTE_BUFFER, ONE)));
- assertTrue(mapAppliesTo(bound, map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER), map(ONE, ByteBufferUtil.EMPTY_BYTE_BUFFER)));
- }
-}