Merge branch 'cassandra-2.0' into cassandra-2.1
Conflicts:
CHANGES.txt
src/java/org/apache/cassandra/cql3/Cql.g
src/java/org/apache/cassandra/cql3/Lists.java
src/java/org/apache/cassandra/cql3/QueryProcessor.java
src/java/org/apache/cassandra/cql3/Relation.java
src/java/org/apache/cassandra/cql3/ResultSet.java
src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
src/java/org/apache/cassandra/cql3/statements/Restriction.java
src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/bf521900
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/bf521900
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/bf521900
Branch: refs/heads/trunk
Commit: bf5219000be9c03daa1dc4fb420b031f6ffec01d
Parents: 9bd3887 4349638
Author: Tyler Hobbs <[email protected]>
Authored: Thu May 22 14:19:42 2014 -0500
Committer: Tyler Hobbs <[email protected]>
Committed: Thu May 22 14:19:42 2014 -0500
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../apache/cassandra/cql3/AbstractMarker.java | 10 +-
.../org/apache/cassandra/cql3/Constants.java | 6 +
src/java/org/apache/cassandra/cql3/Cql.g | 109 +-
src/java/org/apache/cassandra/cql3/Lists.java | 13 +-
.../cassandra/cql3/MultiColumnRelation.java | 144 +++
.../org/apache/cassandra/cql3/Relation.java | 104 +-
.../cassandra/cql3/SingleColumnRelation.java | 95 ++
src/java/org/apache/cassandra/cql3/Term.java | 10 +
src/java/org/apache/cassandra/cql3/Tuples.java | 349 ++++++
.../cql3/statements/ModificationStatement.java | 20 +-
.../cql3/statements/MultiColumnRestriction.java | 137 +++
.../cassandra/cql3/statements/Restriction.java | 395 +------
.../cql3/statements/SelectStatement.java | 805 ++++++++-----
.../statements/SingleColumnRestriction.java | 413 +++++++
.../cassandra/db/composites/CBuilder.java | 2 +
.../cassandra/db/composites/Composites.java | 2 +
.../cassandra/db/composites/CompoundCType.java | 13 +
.../cassandra/db/composites/SimpleCType.java | 10 +
.../apache/cassandra/db/marshal/TupleType.java | 279 +++++
.../cassandra/cql3/MultiColumnRelationTest.java | 1114 ++++++++++++++++++
21 files changed, 3263 insertions(+), 768 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 55fc400,c6c51c3..7ab411b
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -64,7 -35,24 +64,8 @@@ Merged from 2.0
* Fix 2ndary index queries with DESC clustering order (CASSANDRA-6950)
* Invalid key cache entries on DROP (CASSANDRA-6525)
* Fix flapping RecoveryManagerTest (CASSANDRA-7084)
+ * Add missing iso8601 patterns for date strings (6973)
++ * Support selecting multiple rows in a partition using IN (CASSANDRA-6875)
Merged from 1.2:
* Add Cloudstack snitch (CASSANDRA-7147)
* Update system.peers correctly when relocating tokens (CASSANDRA-7126)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/src/java/org/apache/cassandra/cql3/AbstractMarker.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/AbstractMarker.java
index 2b9c6c9,4329ed9..0b59ed4
--- a/src/java/org/apache/cassandra/cql3/AbstractMarker.java
+++ b/src/java/org/apache/cassandra/cql3/AbstractMarker.java
@@@ -99,10 -103,10 +103,10 @@@ public abstract class AbstractMarker ex
}
@Override
- public AbstractMarker prepare(ColumnSpecification receiver) throws
InvalidRequestException
+ public AbstractMarker prepare(String keyspace, ColumnSpecification
receiver) throws InvalidRequestException
{
if (receiver.type instanceof CollectionType)
- throw new InvalidRequestException("Invalid IN relation on
collection column");
+ throw new InvalidRequestException("Collection columns do not
support IN relations");
return new Lists.Marker(bindIndex, makeInReceiver(receiver));
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/src/java/org/apache/cassandra/cql3/Constants.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/src/java/org/apache/cassandra/cql3/Cql.g
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Cql.g
index 4c1f2dc,ceb2bde..57b61a5
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@@ -962,44 -894,82 +976,85 @@@ relationType returns [Relation.Type op
;
relation[List<Relation> clauses]
- : name=cident type=relationType t=term { $clauses.add(new Relation(name,
type, t)); }
- | K_TOKEN
- { List<ColumnIdentifier> l = new ArrayList<ColumnIdentifier>(); }
- '(' name1=cident { l.add(name1); } ( ',' namen=cident {
l.add(namen); })* ')'
- type=relationType t=term
+ : name=cident type=relationType t=term { $clauses.add(new
SingleColumnRelation(name, type, t)); }
+ | K_TOKEN l=tupleOfIdentifiers type=relationType t=term
{
for (ColumnIdentifier id : l)
- $clauses.add(new Relation(id, type, t, true));
+ $clauses.add(new SingleColumnRelation(id, type, t, true));
}
- | name=cident K_IN { Term.Raw marker = null; } (QMARK { marker =
newINBindVariables(null); } | ':' mid=cident { marker =
newINBindVariables(mid); })
- { $clauses.add(new Relation(name, Relation.Type.IN, marker)); }
- | name=cident K_IN { Relation rel = Relation.createInRelation($name.id); }
- '(' ( f1=term { rel.addInValue(f1); } (',' fN=term {
rel.addInValue(fN); } )* )? ')' { $clauses.add(rel); }
+ | name=cident K_IN marker=inMarker
+ { $clauses.add(new SingleColumnRelation(name, Relation.Type.IN,
marker)); }
+ | name=cident K_IN inValues=singleColumnInValues
+ { $clauses.add(SingleColumnRelation.createInRelation($name.id,
inValues)); }
+ | name=cident K_CONTAINS { Relation.Type rt = Relation.Type.CONTAINS; }
(K_KEY { rt = Relation.Type.CONTAINS_KEY; })?
- t=term { $clauses.add(new Relation(name, rt, t)); }
- | {
- List<ColumnIdentifier> ids = new ArrayList<ColumnIdentifier>();
- List<Term.Raw> terms = new ArrayList<Term.Raw>();
- }
- '(' n1=cident { ids.add(n1); } (',' ni=cident { ids.add(ni); })* ')'
- type=relationType
- '(' t1=term { terms.add(t1); } (',' ti=term { terms.add(ti); })* ')'
- {
- if (type == Relation.Type.IN)
- addRecognitionError("Cannot use IN relation with tuple
notation");
- if (ids.size() != terms.size())
- addRecognitionError(String.format("Number of values (" +
terms.size() + ") in tuple notation doesn't match the number of column names ("
+ ids.size() + ")"));
- else
- for (int i = 0; i < ids.size(); i++)
- $clauses.add(new Relation(ids.get(i), type, terms.get(i), i
== 0 ? null : ids.get(i-1)));
- }
++ t=term { $clauses.add(new SingleColumnRelation(name, rt, t)); }
+ | ids=tupleOfIdentifiers
+ ( K_IN
+ ( '(' ')'
+ { $clauses.add(MultiColumnRelation.createInRelation(ids, new
ArrayList<Tuples.Literal>())); }
+ | tupleInMarker=inMarkerForTuple /* (a, b, c) IN ? */
+ {
$clauses.add(MultiColumnRelation.createSingleMarkerInRelation(ids,
tupleInMarker)); }
+ | literals=tupleOfTupleLiterals /* (a, b, c) IN ((1, 2, 3), (4, 5,
6), ...) */
+ {
+ $clauses.add(MultiColumnRelation.createInRelation(ids,
literals));
+ }
+ | markers=tupleOfMarkersForTuples /* (a, b, c) IN (?, ?, ...) */
+ { $clauses.add(MultiColumnRelation.createInRelation(ids,
markers)); }
+ )
+ | type=relationType literal=tupleLiteral /* (a, b, c) > (1, 2, 3) or
(a, b, c) > (?, ?, ?) */
+ {
+ $clauses.add(MultiColumnRelation.createNonInRelation(ids, type,
literal));
+ }
+ | type=relationType tupleMarker=markerForTuple /* (a, b, c) >= ? */
+ { $clauses.add(MultiColumnRelation.createNonInRelation(ids, type,
tupleMarker)); }
+ )
| '(' relation[$clauses] ')'
;
+ inMarker returns [AbstractMarker.INRaw marker]
+ : QMARK { $marker = newINBindVariables(null); }
+ | ':' name=cident { $marker = newINBindVariables(name); }
+ ;
+
+ tupleOfIdentifiers returns [List<ColumnIdentifier> ids]
+ @init { $ids = new ArrayList<ColumnIdentifier>(); }
+ : '(' n1=cident { $ids.add(n1); } (',' ni=cident { $ids.add(ni); })* ')'
+ ;
+
+ singleColumnInValues returns [List<Term.Raw> terms]
+ @init { $terms = new ArrayList<Term.Raw>(); }
+ : '(' ( t1 = term { $terms.add(t1); } (',' ti=term { $terms.add(ti); })*
)? ')'
+ ;
+
+ tupleLiteral returns [Tuples.Literal literal]
+ @init { List<Term.Raw> terms = new ArrayList<>(); }
+ : '(' t1=term { terms.add(t1); } (',' ti=term { terms.add(ti); })* ')' {
$literal = new Tuples.Literal(terms); }
+ ;
+
+ tupleOfTupleLiterals returns [List<Tuples.Literal> literals]
+ @init { $literals = new ArrayList<>(); }
+ : '(' t1=tupleLiteral { $literals.add(t1); } (',' ti=tupleLiteral {
$literals.add(ti); })* ')'
+ ;
+
+ markerForTuple returns [Tuples.Raw marker]
+ : QMARK { $marker = newTupleBindVariables(null); }
+ | ':' name=cident { $marker = newTupleBindVariables(name); }
+ ;
+
+ tupleOfMarkersForTuples returns [List<Tuples.Raw> markers]
+ @init { $markers = new ArrayList<Tuples.Raw>(); }
+ : '(' m1=markerForTuple { $markers.add(m1); } (',' mi=markerForTuple {
$markers.add(mi); })* ')'
+ ;
+
+ inMarkerForTuple returns [Tuples.INRaw marker]
+ : QMARK { $marker = newTupleINBindVariables(null); }
+ | ':' name=cident { $marker = newTupleINBindVariables(name); }
+ ;
+
-comparatorType returns [CQL3Type t]
- : c=native_type { $t = c; }
+comparatorType returns [CQL3Type.Raw t]
+ : n=native_type { $t = CQL3Type.Raw.from(n); }
| c=collection_type { $t = c; }
+ | id=userTypeName { $t = CQL3Type.Raw.userType(id); }
| s=STRING_LITERAL
{
try {
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/src/java/org/apache/cassandra/cql3/Lists.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Lists.java
index f12af88,d483dd5..c214fa8
--- a/src/java/org/apache/cassandra/cql3/Lists.java
+++ b/src/java/org/apache/cassandra/cql3/Lists.java
@@@ -147,25 -144,18 +147,30 @@@ public abstract class List
}
}
- public ByteBuffer get()
+ public ByteBuffer get(QueryOptions options)
{
- return CollectionType.pack(elements, elements.size());
+ return CollectionSerializer.pack(elements, elements.size(),
options.getProtocolVersion());
+ }
+
+ public boolean equals(ListType lt, Value v)
+ {
+ if (elements.size() != v.elements.size())
+ return false;
+
+ for (int i = 0; i < elements.size(); i++)
+ if (lt.elements.compare(elements.get(i), v.elements.get(i))
!= 0)
+ return false;
+
+ return true;
}
+
+ public List<ByteBuffer> getElements()
+ {
+ return elements;
+ }
}
- /*
+ /**
* Basically similar to a Value, but with some non-pure function (that
need
* to be evaluated at execution time) in it.
*
@@@ -223,11 -216,10 +231,10 @@@
assert receiver.type instanceof ListType;
}
- public Value bind(List<ByteBuffer> values) throws
InvalidRequestException
+ public Value bind(QueryOptions options) throws InvalidRequestException
{
- ByteBuffer value = values.get(bindIndex);
- return value == null ? null : Value.fromSerialized(value,
(ListType)receiver.type);
+ ByteBuffer value = options.getValues().get(bindIndex);
+ return value == null ? null : Value.fromSerialized(value,
(ListType)receiver.type, options.getProtocolVersion());
-
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/src/java/org/apache/cassandra/cql3/Relation.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Relation.java
index 2eeef1d,0f1366d..5318907
--- a/src/java/org/apache/cassandra/cql3/Relation.java
+++ b/src/java/org/apache/cassandra/cql3/Relation.java
@@@ -17,78 -17,35 +17,47 @@@
*/
package org.apache.cassandra.cql3;
- import java.util.ArrayList;
- import java.util.List;
+
- /**
- * Relations encapsulate the relationship between an entity of some kind, and
- * a value (term). For example, <key> > "start" or "colname1" = "somevalue".
- *
- */
- public class Relation
- {
- private final ColumnIdentifier entity;
- private final Type relationType;
- private final Term.Raw value;
- private final List<Term.Raw> inValues;
- public final boolean onToken;
+ public abstract class Relation {
- // Will be null unless for tuple notations (#4851)
- public final ColumnIdentifier previousInTuple;
+ protected Type relationType;
public static enum Type
{
- EQ, LT, LTE, GTE, GT, IN;
+ EQ, LT, LTE, GTE, GT, IN, CONTAINS, CONTAINS_KEY;
+
+ public boolean allowsIndexQuery()
+ {
+ switch (this)
+ {
+ case EQ:
+ case CONTAINS:
+ case CONTAINS_KEY:
+ return true;
+ default:
+ return false;
+ }
+ }
- }
-
- private Relation(ColumnIdentifier entity, Type type, Term.Raw value,
List<Term.Raw> inValues, boolean onToken, ColumnIdentifier previousInTuple)
- {
- this.entity = entity;
- this.relationType = type;
- this.value = value;
- this.inValues = inValues;
- this.onToken = onToken;
- this.previousInTuple = previousInTuple;
- }
- /**
- * Creates a new relation.
- *
- * @param entity the kind of relation this is; what the term is being
compared to.
- * @param type the type that describes how this entity relates to the
value.
- * @param value the value being compared.
- */
- public Relation(ColumnIdentifier entity, Type type, Term.Raw value)
- {
- this(entity, type, value, null, false, null);
- }
-
- public Relation(ColumnIdentifier entity, Type type, Term.Raw value,
boolean onToken)
- {
- this(entity, type, value, null, onToken, null);
- }
-
- public Relation(ColumnIdentifier entity, Type type, Term.Raw value,
ColumnIdentifier previousInTuple)
- {
- this(entity, type, value, null, false, previousInTuple);
- }
-
- public static Relation createInRelation(ColumnIdentifier entity)
- {
- return new Relation(entity, Type.IN, null, new ArrayList<Term.Raw>(),
false, null);
+ @Override
+ public String toString()
+ {
+ switch (this)
+ {
+ case EQ:
+ return "=";
+ case LT:
+ return "<";
+ case LTE:
+ return "<=";
+ case GT:
+ return ">";
+ case GTE:
+ return ">=";
- case IN:
- return "IN";
+ default:
+ return this.name();
+ }
+ }
}
public Type operator()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/src/java/org/apache/cassandra/cql3/Term.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Term.java
index de866e1,96b4b71..e5206c8
--- a/src/java/org/apache/cassandra/cql3/Term.java
+++ b/src/java/org/apache/cassandra/cql3/Term.java
@@@ -88,9 -88,14 +88,14 @@@ public interface Ter
* case this RawTerm describe a list index or a map key, etc...
* @return the prepared term.
*/
- public Term prepare(ColumnSpecification receiver) throws
InvalidRequestException;
+ public Term prepare(String keyspace, ColumnSpecification receiver)
throws InvalidRequestException;
}
+ public interface MultiColumnRaw extends Raw
+ {
- public Term prepare(List<? extends ColumnSpecification> receiver)
throws InvalidRequestException;
++ public Term prepare(String keyspace, List<? extends
ColumnSpecification> receiver) throws InvalidRequestException;
+ }
+
/**
* A terminal term, one that can be reduced to a byte buffer directly.
*
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/src/java/org/apache/cassandra/cql3/Tuples.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Tuples.java
index 0000000,9e86912..3aabbd3
mode 000000,100644..100644
--- a/src/java/org/apache/cassandra/cql3/Tuples.java
+++ b/src/java/org/apache/cassandra/cql3/Tuples.java
@@@ -1,0 -1,349 +1,349 @@@
+ /*
+ * 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 org.apache.cassandra.db.marshal.AbstractType;
+ import org.apache.cassandra.db.marshal.CollectionType;
+ import org.apache.cassandra.db.marshal.ListType;
+ import org.apache.cassandra.db.marshal.TupleType;
+ import org.apache.cassandra.exceptions.InvalidRequestException;
+ import org.apache.cassandra.serializers.MarshalException;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+ import java.nio.ByteBuffer;
+ import java.util.*;
+
+ /**
+ * Static helper methods and classes for tuples.
+ */
+ public class Tuples
+ {
+ private static final Logger logger =
LoggerFactory.getLogger(Tuples.class);
+
+ /**
+ * A raw, literal tuple. When prepared, this will become a Tuples.Value
or Tuples.DelayedValue, depending
+ * on whether the tuple holds NonTerminals.
+ */
+ public static class Literal implements Term.MultiColumnRaw
+ {
+ private final List<Term.Raw> elements;
+
+ public Literal(List<Term.Raw> elements)
+ {
+ this.elements = elements;
+ }
+
- public Term prepare(List<? extends ColumnSpecification> receivers)
throws InvalidRequestException
++ public Term prepare(String keyspace, List<? extends
ColumnSpecification> receivers) throws InvalidRequestException
+ {
+ if (elements.size() != receivers.size())
+ throw new InvalidRequestException(String.format("Expected %d
elements in value tuple, but got %d: %s", receivers.size(), elements.size(),
this));
+
+ List<Term> values = new ArrayList<>(elements.size());
+ boolean allTerminal = true;
+ for (int i = 0; i < elements.size(); i++)
+ {
- Term t = elements.get(i).prepare(receivers.get(i));
++ Term t = elements.get(i).prepare(keyspace, receivers.get(i));
+ if (t instanceof Term.NonTerminal)
+ allTerminal = false;
+
+ values.add(t);
+ }
+ DelayedValue value = new DelayedValue(values);
- return allTerminal ?
value.bind(Collections.<ByteBuffer>emptyList()) : value;
++ return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
+ }
+
- public Term prepare(ColumnSpecification receiver)
++ public Term prepare(String keyspace, ColumnSpecification receiver)
+ {
+ throw new AssertionError("Tuples.Literal instances require a list
of receivers for prepare()");
+ }
+
- public boolean isAssignableTo(ColumnSpecification receiver)
++ public boolean isAssignableTo(String keyspace, ColumnSpecification
receiver)
+ {
+ // tuples shouldn't be assignable to anything right now
+ return false;
+ }
+
+ @Override
+ public String toString()
+ {
+ return tupleToString(elements);
+ }
+ }
+
+ /**
+ * A tuple of terminal values (e.g (123, 'abc')).
+ */
+ public static class Value extends Term.MultiItemTerminal
+ {
+ public final ByteBuffer[] elements;
+
+ public Value(ByteBuffer[] elements)
+ {
+ this.elements = elements;
+ }
+
+ public static Value fromSerialized(ByteBuffer bytes, TupleType type)
+ {
+ return new Value(type.split(bytes));
+ }
+
- public ByteBuffer get()
++ public ByteBuffer get(QueryOptions options)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public List<ByteBuffer> getElements()
+ {
+ return Arrays.asList(elements);
+ }
+ }
+
+ /**
+ * Similar to Value, but contains at least one NonTerminal, such as a
non-pure functions or bind marker.
+ */
+ public static class DelayedValue extends Term.NonTerminal
+ {
+ public final List<Term> elements;
+
+ public DelayedValue(List<Term> elements)
+ {
+ this.elements = elements;
+ }
+
+ public boolean containsBindMarker()
+ {
+ for (Term term : elements)
+ if (term.containsBindMarker())
+ return true;
+
+ return false;
+ }
+
+ public void collectMarkerSpecification(VariableSpecifications
boundNames)
+ {
+ for (Term term : elements)
+ term.collectMarkerSpecification(boundNames);
+ }
+
- public Value bind(List<ByteBuffer> values) throws
InvalidRequestException
++ public Value bind(QueryOptions options) throws InvalidRequestException
+ {
+ ByteBuffer[] buffers = new ByteBuffer[elements.size()];
+ for (int i=0; i < elements.size(); i++)
+ {
- ByteBuffer bytes = elements.get(i).bindAndGet(values);
++ ByteBuffer bytes = elements.get(i).bindAndGet(options);
+ if (bytes == null)
+ throw new InvalidRequestException("Tuples may not contain
null values");
+
- buffers[i] = elements.get(i).bindAndGet(values);
++ buffers[i] = elements.get(i).bindAndGet(options);
+ }
+ return new Value(buffers);
+ }
+
+ @Override
+ public String toString()
+ {
+ return tupleToString(elements);
+ }
+ }
+
+ /**
+ * A terminal value for a list of IN values that are tuples. For example:
"SELECT ... WHERE (a, b, c) IN ?"
+ * This is similar to Lists.Value, but allows us to keep components of
the tuples in the list separate.
+ */
+ public static class InValue extends Term.Terminal
+ {
+ List<List<ByteBuffer>> elements;
+
+ public InValue(List<List<ByteBuffer>> items)
+ {
+ this.elements = items;
+ }
+
+ public static InValue fromSerialized(ByteBuffer value, ListType type)
throws InvalidRequestException
+ {
+ try
+ {
+ // Collections have this small hack that validate cannot be
called on a serialized object,
+ // but compose does the validation (so we're fine).
+ List<?> l = (List<?>)type.compose(value);
+
+ assert type.elements instanceof TupleType;
+ TupleType tupleType = (TupleType) type.elements;
+
+ // type.split(bytes)
+ List<List<ByteBuffer>> elements = new ArrayList<>(l.size());
+ for (Object element : l)
+
elements.add(Arrays.asList(tupleType.split(type.elements.decompose(element))));
+ return new InValue(elements);
+ }
+ catch (MarshalException e)
+ {
+ throw new InvalidRequestException(e.getMessage());
+ }
+ }
+
- public ByteBuffer get()
++ public ByteBuffer get(QueryOptions options)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public List<List<ByteBuffer>> getSplitValues()
+ {
+ return elements;
+ }
+ }
+
+ /**
+ * A raw placeholder for a tuple of values for different multiple
columns, each of which may have a different type.
+ * For example, "SELECT ... WHERE (col1, col2) > ?".
+ */
+ public static class Raw extends AbstractMarker.Raw implements
Term.MultiColumnRaw
+ {
+ public Raw(int bindIndex)
+ {
+ super(bindIndex);
+ }
+
+ private static ColumnSpecification makeReceiver(List<? extends
ColumnSpecification> receivers) throws InvalidRequestException
+ {
+ List<AbstractType<?>> types = new ArrayList<>(receivers.size());
+ StringBuilder inName = new StringBuilder("(");
+ for (int i = 0; i < receivers.size(); i++)
+ {
+ ColumnSpecification receiver = receivers.get(i);
+ inName.append(receiver.name);
+ if (i < receivers.size() - 1)
+ inName.append(",");
+ types.add(receiver.type);
+ }
+ inName.append(')');
+
+ ColumnIdentifier identifier = new
ColumnIdentifier(inName.toString(), true);
+ TupleType type = new TupleType(types);
+ return new ColumnSpecification(receivers.get(0).ksName,
receivers.get(0).cfName, identifier, type);
+ }
+
- public AbstractMarker prepare(List<? extends ColumnSpecification>
receivers) throws InvalidRequestException
++ public AbstractMarker prepare(String keyspace, List<? extends
ColumnSpecification> receivers) throws InvalidRequestException
+ {
+ return new Tuples.Marker(bindIndex, makeReceiver(receivers));
+ }
+
+ @Override
- public AbstractMarker prepare(ColumnSpecification receiver)
++ public AbstractMarker prepare(String keyspace, ColumnSpecification
receiver)
+ {
+ throw new AssertionError("Tuples.Raw.prepare() requires a list of
receivers");
+ }
+ }
+
+ /**
+ * A raw marker for an IN list of tuples, like "SELECT ... WHERE (a, b,
c) IN ?"
+ */
+ public static class INRaw extends AbstractMarker.Raw
+ {
+ public INRaw(int bindIndex)
+ {
+ super(bindIndex);
+ }
+
+ private static ColumnSpecification makeInReceiver(List<? extends
ColumnSpecification> receivers) throws InvalidRequestException
+ {
+ List<AbstractType<?>> types = new ArrayList<>(receivers.size());
+ StringBuilder inName = new StringBuilder("in(");
+ for (int i = 0; i < receivers.size(); i++)
+ {
+ ColumnSpecification receiver = receivers.get(i);
+ inName.append(receiver.name);
+ if (i < receivers.size() - 1)
+ inName.append(",");
+
+ if (receiver.type instanceof CollectionType)
+ throw new InvalidRequestException("Collection columns do
not support IN relations");
+ types.add(receiver.type);
+ }
+ inName.append(')');
+
+ ColumnIdentifier identifier = new
ColumnIdentifier(inName.toString(), true);
+ TupleType type = new TupleType(types);
+ return new ColumnSpecification(receivers.get(0).ksName,
receivers.get(0).cfName, identifier, ListType.getInstance(type));
+ }
+
- public AbstractMarker prepare(List<? extends ColumnSpecification>
receivers) throws InvalidRequestException
++ public AbstractMarker prepare(String keyspace, List<? extends
ColumnSpecification> receivers) throws InvalidRequestException
+ {
+ return new InMarker(bindIndex, makeInReceiver(receivers));
+ }
+
+ @Override
- public AbstractMarker prepare(ColumnSpecification receiver)
++ public AbstractMarker prepare(String keyspace, ColumnSpecification
receiver)
+ {
+ throw new AssertionError("Tuples.INRaw.prepare() requires a list
of receivers");
+ }
+ }
+
+ /**
+ * Represents a marker for a single tuple, like "SELECT ... WHERE (a, b,
c) > ?"
+ */
+ public static class Marker extends AbstractMarker
+ {
+ public Marker(int bindIndex, ColumnSpecification receiver)
+ {
+ super(bindIndex, receiver);
+ }
+
- public Value bind(List<ByteBuffer> values) throws
InvalidRequestException
++ public Value bind(QueryOptions options) throws InvalidRequestException
+ {
- ByteBuffer value = values.get(bindIndex);
++ ByteBuffer value = options.getValues().get(bindIndex);
+ if (value == null)
+ return null;
+
+ return value == null ? null : Value.fromSerialized(value,
(TupleType)receiver.type);
+ }
+ }
+
+ /**
+ * Represents a marker for a set of IN values that are tuples, like
"SELECT ... WHERE (a, b, c) IN ?"
+ */
+ public static class InMarker extends AbstractMarker
+ {
+ protected InMarker(int bindIndex, ColumnSpecification receiver)
+ {
+ super(bindIndex, receiver);
+ assert receiver.type instanceof ListType;
+ }
+
- public InValue bind(List<ByteBuffer> values) throws
InvalidRequestException
++ public InValue bind(QueryOptions options) throws
InvalidRequestException
+ {
- ByteBuffer value = values.get(bindIndex);
++ ByteBuffer value = options.getValues().get(bindIndex);
+ return value == null ? null : InValue.fromSerialized(value,
(ListType)receiver.type);
+ }
+ }
+
+ public static String tupleToString(List<?> items)
+ {
+
+ StringBuilder sb = new StringBuilder("(");
+ for (int i = 0; i < items.size(); i++)
+ {
+ sb.append(items.get(i));
+ if (i < items.size() - 1)
+ sb.append(", ");
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
diff --cc
src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
index ad88eaf,11aa0b1..621006b
--- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
@@@ -29,10 -31,10 +29,12 @@@ import org.apache.cassandra.config.CFMe
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.*;
import org.apache.cassandra.db.*;
+import org.apache.cassandra.db.composites.CBuilder;
+import org.apache.cassandra.db.composites.Composite;
import org.apache.cassandra.db.filter.ColumnSlice;
import org.apache.cassandra.db.filter.SliceQueryFilter;
+ import org.apache.cassandra.db.marshal.CompositeType;
+ import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.db.marshal.BooleanType;
import org.apache.cassandra.exceptions.*;
import org.apache.cassandra.service.ClientState;
@@@ -218,46 -237,54 +220,53 @@@ public abstract class ModificationState
return ifExists;
}
- private void addKeyValues(CFDefinition.Name name, Restriction values)
throws InvalidRequestException
+ private void addKeyValues(ColumnDefinition def, Restriction values)
throws InvalidRequestException
{
- if (name.kind == CFDefinition.Name.Kind.COLUMN_ALIAS)
+ if (def.kind == ColumnDefinition.Kind.CLUSTERING_COLUMN)
hasNoClusteringColumns = false;
- if (processedKeys.put(name.name, values) != null)
- throw new InvalidRequestException(String.format("Multiple
definitions found for PRIMARY KEY part %s", name.name));
+ if (processedKeys.put(def.name, values) != null)
+ throw new InvalidRequestException(String.format("Multiple
definitions found for PRIMARY KEY part %s", def.name));
}
- public void addKeyValue(CFDefinition.Name name, Term value) throws
InvalidRequestException
+ public void addKeyValue(ColumnDefinition def, Term value) throws
InvalidRequestException
{
- addKeyValues(def, new Restriction.EQ(value, false));
- addKeyValues(name, new SingleColumnRestriction.EQ(value, false));
++ addKeyValues(def, new SingleColumnRestriction.EQ(value, false));
}
public void processWhereClause(List<Relation> whereClause,
VariableSpecifications names) throws InvalidRequestException
{
- for (Relation rel : whereClause)
- CFDefinition cfDef = cfm.getCfDef();
+ for (Relation relation : whereClause)
{
- if (!(relation instanceof SingleColumnRelation))
++ if (relation.isMultiColumn())
+ {
+ throw new InvalidRequestException(
+ String.format("Multi-column relations cannot be used
in WHERE clauses for modification statements: %s", relation));
+ }
+ SingleColumnRelation rel = (SingleColumnRelation) relation;
+
- CFDefinition.Name name = cfDef.get(rel.getEntity());
- if (name == null)
+ ColumnDefinition def = cfm.getColumnDefinition(rel.getEntity());
+ if (def == null)
throw new InvalidRequestException(String.format("Unknown key
identifier %s", rel.getEntity()));
- switch (name.kind)
+ switch (def.kind)
{
- case KEY_ALIAS:
- case COLUMN_ALIAS:
+ case PARTITION_KEY:
+ case CLUSTERING_COLUMN:
Restriction restriction;
if (rel.operator() == Relation.Type.EQ)
{
- Term t = rel.getValue().prepare(name);
+ Term t = rel.getValue().prepare(keyspace(), def);
t.collectMarkerSpecification(names);
- restriction = new Restriction.EQ(t, false);
+ restriction = new SingleColumnRestriction.EQ(t,
false);
}
- else if (name.kind == CFDefinition.Name.Kind.KEY_ALIAS &&
rel.operator() == Relation.Type.IN)
+ else if (def.kind == ColumnDefinition.Kind.PARTITION_KEY
&& rel.operator() == Relation.Type.IN)
{
if (rel.getValue() != null)
{
- Term t = rel.getValue().prepare(name);
+ Term t = rel.getValue().prepare(keyspace(), def);
t.collectMarkerSpecification(names);
- restriction = Restriction.IN.create(t);
+ restriction = new
SingleColumnRestriction.InWithMarker((Lists.Marker)t);
}
else
{
@@@ -638,9 -689,9 +647,8 @@@
/**
* Convert statement into a list of mutations to apply on the server
*
- * @param variables value for prepared statement markers
+ * @param options value for prepared statement markers
* @param local if true, any requests (for collections) performed by
getMutation should be done locally only.
-- * @param cl the consistency to use for the potential reads involved in
generating the mutations (for lists set/delete operations)
* @param now the current timestamp in microseconds to use if no
timestamp is user provided.
*
* @return list of the mutations
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/src/java/org/apache/cassandra/cql3/statements/MultiColumnRestriction.java
----------------------------------------------------------------------
diff --cc
src/java/org/apache/cassandra/cql3/statements/MultiColumnRestriction.java
index 0000000,f643684..96cb905
mode 000000,100644..100644
--- a/src/java/org/apache/cassandra/cql3/statements/MultiColumnRestriction.java
+++ b/src/java/org/apache/cassandra/cql3/statements/MultiColumnRestriction.java
@@@ -1,0 -1,135 +1,137 @@@
+ /*
+ * 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.statements;
+
+ import org.apache.cassandra.cql3.AbstractMarker;
++import org.apache.cassandra.cql3.QueryOptions;
+ import org.apache.cassandra.cql3.Term;
+ import org.apache.cassandra.cql3.Tuples;
+ import org.apache.cassandra.exceptions.InvalidRequestException;
+
+ import java.nio.ByteBuffer;
+ import java.util.ArrayList;
+ import java.util.List;
+
+ public interface MultiColumnRestriction extends Restriction
+ {
+ public static class EQ extends SingleColumnRestriction.EQ implements
MultiColumnRestriction
+ {
+ public EQ(Term value, boolean onToken)
+ {
+ super(value, onToken);
+ }
+
+ public boolean isMultiColumn()
+ {
+ return true;
+ }
+
- public List<ByteBuffer> values(List<ByteBuffer> variables) throws
InvalidRequestException
++ public List<ByteBuffer> values(QueryOptions options) throws
InvalidRequestException
+ {
- Tuples.Value t = (Tuples.Value)value.bind(variables);
++ Tuples.Value t = (Tuples.Value)value.bind(options);
+ return t.getElements();
+ }
+ }
+
+ public interface IN extends MultiColumnRestriction
+ {
- public List<List<ByteBuffer>> splitValues(List<ByteBuffer> variables)
throws InvalidRequestException;
++ public List<List<ByteBuffer>> splitValues(QueryOptions options)
throws InvalidRequestException;
+ }
+
+ /**
+ * An IN restriction that has a set of terms for in values.
+ * For example: "SELECT ... WHERE (a, b, c) IN ((1, 2, 3), (4, 5, 6))" or
"WHERE (a, b, c) IN (?, ?)"
+ */
+ public static class InWithValues extends
SingleColumnRestriction.InWithValues implements MultiColumnRestriction.IN
+ {
+ public InWithValues(List<Term> values)
+ {
+ super(values);
+ }
+
+ public boolean isMultiColumn()
+ {
+ return true;
+ }
+
- public List<List<ByteBuffer>> splitValues(List<ByteBuffer> variables)
throws InvalidRequestException
++ public List<List<ByteBuffer>> splitValues(QueryOptions options)
throws InvalidRequestException
+ {
+ List<List<ByteBuffer>> buffers = new ArrayList<>(values.size());
+ for (Term value : values)
+ {
- Term.MultiItemTerminal term =
(Term.MultiItemTerminal)value.bind(variables);
++ Term.MultiItemTerminal term =
(Term.MultiItemTerminal)value.bind(options);
+ buffers.add(term.getElements());
+ }
+ return buffers;
+ }
+ }
+
+ /**
+ * An IN restriction that uses a single marker for a set of IN values
that are tuples.
+ * For example: "SELECT ... WHERE (a, b, c) IN ?"
+ */
+ public static class InWithMarker extends
SingleColumnRestriction.InWithMarker implements MultiColumnRestriction.IN
+ {
+ public InWithMarker(AbstractMarker marker)
+ {
+ super(marker);
+ }
+
+ public boolean isMultiColumn()
+ {
+ return true;
+ }
+
- public List<List<ByteBuffer>> splitValues(List<ByteBuffer> variables)
throws InvalidRequestException
++ public List<List<ByteBuffer>> splitValues(QueryOptions options)
throws InvalidRequestException
+ {
- Tuples.InValue inValue = ((Tuples.InMarker)
marker).bind(variables);
++ Tuples.InMarker inMarker = (Tuples.InMarker)marker;
++ Tuples.InValue inValue = inMarker.bind(options);
+ if (inValue == null)
+ throw new InvalidRequestException("Invalid null value for IN
restriction");
+ return inValue.getSplitValues();
+ }
+ }
+
+ public static class Slice extends SingleColumnRestriction.Slice
implements MultiColumnRestriction
+ {
+ public Slice(boolean onToken)
+ {
+ super(onToken);
+ }
+
+ public boolean isMultiColumn()
+ {
+ return true;
+ }
+
- public ByteBuffer bound(Bound b, List<ByteBuffer> variables) throws
InvalidRequestException
++ public ByteBuffer bound(Bound b, QueryOptions options) throws
InvalidRequestException
+ {
+ throw new UnsupportedOperationException("Multicolumn slice
restrictions do not support bound()");
+ }
+
+ /**
+ * Similar to bounds(), but returns one ByteBuffer per-component in
the bound instead of a single
+ * ByteBuffer to represent the entire bound.
+ */
- public List<ByteBuffer> componentBounds(Bound b, List<ByteBuffer>
variables) throws InvalidRequestException
++ public List<ByteBuffer> componentBounds(Bound b, QueryOptions
options) throws InvalidRequestException
+ {
- Tuples.Value value = (Tuples.Value)bounds[b.idx].bind(variables);
++ Tuples.Value value = (Tuples.Value)bounds[b.idx].bind(options);
+ return value.getElements();
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf521900/src/java/org/apache/cassandra/cql3/statements/Restriction.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/Restriction.java
index 4fd02c1,3d33bde..c529a38
--- a/src/java/org/apache/cassandra/cql3/statements/Restriction.java
+++ b/src/java/org/apache/cassandra/cql3/statements/Restriction.java
@@@ -18,14 -18,10 +18,10 @@@
package org.apache.cassandra.cql3.statements;
import java.nio.ByteBuffer;
- import java.util.ArrayList;
- import java.util.Collections;
import java.util.List;
- import com.google.common.base.Objects;
-
import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.thrift.IndexOperator;
+import org.apache.cassandra.db.IndexExpression;
import org.apache.cassandra.cql3.*;
/**
@@@ -39,398 -35,34 +35,35 @@@ public interface Restrictio
public boolean isSlice();
public boolean isEQ();
public boolean isIN();
+ public boolean isContains();
+ public boolean isMultiColumn();
- // Only supported for EQ and IN, but it's convenient to have here
- public List<ByteBuffer> values(List<ByteBuffer> variables) throws
InvalidRequestException;
+ // Not supported by Slice, but it's convenient to have here
+ public List<ByteBuffer> values(QueryOptions options) throws
InvalidRequestException;
- public static class EQ implements Restriction
- {
- private final Term value;
- private final boolean onToken;
-
- public EQ(Term value, boolean onToken)
- {
- this.value = value;
- this.onToken = onToken;
- }
-
- public List<ByteBuffer> values(QueryOptions options) throws
InvalidRequestException
- {
- return Collections.singletonList(value.bindAndGet(options));
- }
-
- public boolean isSlice()
- {
- return false;
- }
-
- public boolean isEQ()
- {
- return true;
- }
-
- public boolean isIN()
- {
- return false;
- }
-
- public boolean isContains()
- {
- return false;
- }
+ public static interface EQ extends Restriction {}
- public boolean isOnToken()
- {
- return onToken;
- }
-
- @Override
- public String toString()
- {
- return String.format("EQ(%s)%s", value, onToken ? "*" : "");
- }
- }
-
- public static abstract class IN implements Restriction
+ public static interface IN extends Restriction
{
- public static IN create(List<Term> values)
- {
- return new WithValues(values);
- }
-
- public static IN create(Term value)
- {
- assert value instanceof Lists.Marker; // we shouldn't have got
there otherwise
- return new WithMarker((Lists.Marker)value);
- }
-
- public boolean isSlice()
- {
- return false;
- }
-
- public boolean isEQ()
- {
- return false;
- }
-
- public boolean isContains()
- {
- return false;
- }
-
- public boolean isIN()
- {
- return true;
- }
-
- // Used when we need to know if it's a IN with just one value before
we have
- // the bind variables. This is ugly and only there for backward
compatiblity
- // because we used to treate IN with 1 value like an EQ and need to
preserve
- // this behavior.
- public abstract boolean canHaveOnlyOneValue();
-
- public boolean isOnToken()
- {
- return false;
- }
-
- private static class WithValues extends IN
- {
- private final List<Term> values;
-
- private WithValues(List<Term> values)
- {
- this.values = values;
- }
-
- public List<ByteBuffer> values(QueryOptions options) throws
InvalidRequestException
- {
- List<ByteBuffer> buffers = new
ArrayList<ByteBuffer>(values.size());
- for (Term value : values)
- buffers.add(value.bindAndGet(options));
- return buffers;
- }
-
- public boolean canHaveOnlyOneValue()
- {
- return values.size() == 1;
- }
-
- @Override
- public String toString()
- {
- return String.format("IN(%s)", values);
- }
- }
-
- private static class WithMarker extends IN
- {
- private final Lists.Marker marker;
-
- private WithMarker(Lists.Marker marker)
- {
- this.marker = marker;
- }
-
- public List<ByteBuffer> values(QueryOptions options) throws
InvalidRequestException
- {
- Lists.Value lval = marker.bind(options);
- if (lval == null)
- throw new InvalidRequestException("Invalid null value for
IN restriction");
- return lval.elements;
- }
-
- public boolean canHaveOnlyOneValue()
- {
- return false;
- }
-
- @Override
- public String toString()
- {
- return "IN ?";
- }
- }
+ public boolean canHaveOnlyOneValue();
}
- public static class Slice implements Restriction
+ public static interface Slice extends Restriction
{
- private final Term[] bounds;
- private final boolean[] boundInclusive;
- private final boolean onToken;
-
- // The name of the column that was preceding this one if the tuple
notation of #4851 was used
- // (note: if it is set for both bound, we'll validate both have the
same previous value, but we
- // still need to distinguish if it's set or not for both bound)
- private final ColumnIdentifier[] previous;
-
- public Slice(boolean onToken)
- {
- this.bounds = new Term[2];
- this.boundInclusive = new boolean[2];
- this.previous = new ColumnIdentifier[2];
- this.onToken = onToken;
- }
-
- public boolean isSlice()
- {
- return true;
- }
-
- public boolean isEQ()
- {
- return false;
- }
-
- public boolean isIN()
- {
- return false;
- }
-
- public boolean isContains()
- {
- return false;
- }
-
- public List<ByteBuffer> values(QueryOptions options) throws
InvalidRequestException
- {
- throw new UnsupportedOperationException();
- }
-
- public boolean isOnToken()
- {
- return onToken;
- }
-
- public boolean hasBound(Bound b)
- {
- return bounds[b.idx] != null;
- }
-
- public ByteBuffer bound(Bound b, QueryOptions options) throws
InvalidRequestException
- {
- return bounds[b.idx].bindAndGet(options);
- }
-
- public boolean isInclusive(Bound b)
- {
- return bounds[b.idx] == null || boundInclusive[b.idx];
- }
-
- public Relation.Type getRelation(Bound eocBound, Bound inclusiveBound)
- {
- switch (eocBound)
- {
- case START:
- return boundInclusive[inclusiveBound.idx] ?
Relation.Type.GTE : Relation.Type.GT;
- case END:
- return boundInclusive[inclusiveBound.idx] ?
Relation.Type.LTE : Relation.Type.LT;
- }
- throw new AssertionError();
- }
-
- public IndexExpression.Operator getIndexOperator(Bound b)
- {
- switch (b)
- {
- case START:
- return boundInclusive[b.idx] ?
IndexExpression.Operator.GTE : IndexExpression.Operator.GT;
- case END:
- return boundInclusive[b.idx] ?
IndexExpression.Operator.LTE : IndexExpression.Operator.LT;
- }
- throw new AssertionError();
- }
-
- public void setBound(ColumnIdentifier name, Relation.Type type, Term
t, ColumnIdentifier previousName) throws InvalidRequestException
- {
- Bound b;
- boolean inclusive;
- switch (type)
- {
- case GT:
- b = Bound.START;
- inclusive = false;
- break;
- case GTE:
- b = Bound.START;
- inclusive = true;
- break;
- case LT:
- b = Bound.END;
- inclusive = false;
- break;
- case LTE:
- b = Bound.END;
- inclusive = true;
- break;
- default:
- throw new AssertionError();
- }
-
- if (bounds[b.idx] != null)
- throw new InvalidRequestException(String.format("Invalid
restrictions found on %s", name));
-
- bounds[b.idx] = t;
- boundInclusive[b.idx] = inclusive;
-
- // If a bound is part of a tuple notation (#4851), the other
bound must either also be or must not be set at all,
- // and this even if there is a 2ndary index (it's not supported
by the 2ndary code). And it's easier to validate
- // this here so we do.
- Bound reverse = Bound.reverse(b);
- if (hasBound(reverse) && !(Objects.equal(previousName,
previous[reverse.idx])))
- throw new InvalidRequestException(String.format("Clustering
column %s cannot be restricted both inside a tuple notation and outside it",
name));
-
- previous[b.idx] = previousName;
- }
-
- public boolean isPartOfTuple()
- {
- return previous[Bound.START.idx] != null ||
previous[Bound.END.idx] != null;
- }
-
- @Override
- public String toString()
- {
- return String.format("SLICE(%s %s, %s %s)%s", boundInclusive[0] ?
">=" : ">",
- bounds[0],
- boundInclusive[1] ?
"<=" : "<",
- bounds[1],
- onToken ? "*" : "");
- }
- }
-
- // This holds both CONTAINS and CONTAINS_KEY restriction because we might
want to have both of them.
- public static class Contains implements Restriction
- {
- private List<Term> values; // for CONTAINS
- private List<Term> keys; // for CONTAINS_KEY
-
- public boolean hasContains()
- {
- return values != null;
- }
-
- public boolean hasContainsKey()
- {
- return keys != null;
- }
-
- public void add(Term t, boolean isKey)
- {
- if (isKey)
- addKey(t);
- else
- addValue(t);
- }
-
- public void addValue(Term t)
- {
- if (values == null)
- values = new ArrayList<>();
- values.add(t);
- }
-
- public void addKey(Term t)
- {
- if (keys == null)
- keys = new ArrayList<>();
- keys.add(t);
- }
-
- public List<ByteBuffer> values(QueryOptions options) throws
InvalidRequestException
- {
- if (values == null)
- return Collections.emptyList();
-
- List<ByteBuffer> buffers = new
ArrayList<ByteBuffer>(values.size());
- for (Term value : values)
- buffers.add(value.bindAndGet(options));
- return buffers;
- }
-
- public List<ByteBuffer> keys(QueryOptions options) throws
InvalidRequestException
- {
- if (keys == null)
- return Collections.emptyList();
-
- List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(keys.size());
- for (Term value : keys)
- buffers.add(value.bindAndGet(options));
- return buffers;
- }
-
- public boolean isSlice()
- {
- return false;
- }
- public List<ByteBuffer> values(List<ByteBuffer> variables) throws
InvalidRequestException;
++ public List<ByteBuffer> values(QueryOptions options) throws
InvalidRequestException;
- public boolean isEQ()
- {
- return false;
- }
+ /** Returns true if the start or end bound (depending on the
argument) is set, false otherwise */
+ public boolean hasBound(Bound b);
- public boolean isIN()
- {
- return false;
- }
- public ByteBuffer bound(Bound b, List<ByteBuffer> variables) throws
InvalidRequestException;
++ public ByteBuffer bound(Bound b, QueryOptions options) throws
InvalidRequestException;
- public boolean isContains()
- {
- return true;
- }
+ /** Returns true if the start or end bound (depending on the
argument) is inclusive, false otherwise */
+ public boolean isInclusive(Bound b);
- public boolean isOnToken()
- {
- return false;
- }
+ public Relation.Type getRelation(Bound eocBound, Bound
inclusiveBound);
- public IndexOperator getIndexOperator(Bound b);
++ public IndexExpression.Operator getIndexOperator(Bound b);
- @Override
- public String toString()
- {
- return String.format("CONTAINS(values=%s, keys=%s)", values,
keys);
- }
- public void setBound(Relation.Type type, Term t) throws
InvalidRequestException;
++ public void setBound(ColumnIdentifier name, Relation.Type type, Term
t) throws InvalidRequestException;
}
}