You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ty...@apache.org on 2014/11/11 20:33:47 UTC
[3/4] cassandra git commit: Support for frozen collections
Support for frozen collections
Patch by Tyler Hobbs; reviewed by Sylvain Lebresne for CASSANDRA-7859
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/ee55f361
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/ee55f361
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/ee55f361
Branch: refs/heads/trunk
Commit: ee55f361b76f9ce7dd2a21a0ff4e80da931c77d2
Parents: 0337620
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Tue Nov 11 12:40:48 2014 -0600
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Tue Nov 11 12:40:48 2014 -0600
----------------------------------------------------------------------
CHANGES.txt | 1 +
bin/cqlsh | 18 +
pylib/cqlshlib/cql3handling.py | 19 +-
.../apache/cassandra/cql3/AbstractMarker.java | 2 +-
src/java/org/apache/cassandra/cql3/CQL3Row.java | 2 +-
.../org/apache/cassandra/cql3/CQL3Type.java | 158 ++--
.../apache/cassandra/cql3/ColumnCondition.java | 275 ++++---
.../org/apache/cassandra/cql3/Constants.java | 3 +-
src/java/org/apache/cassandra/cql3/Cql.g | 14 +-
src/java/org/apache/cassandra/cql3/Lists.java | 66 +-
src/java/org/apache/cassandra/cql3/Maps.java | 62 +-
.../org/apache/cassandra/cql3/Operation.java | 16 +-
src/java/org/apache/cassandra/cql3/Sets.java | 80 +-
src/java/org/apache/cassandra/cql3/Term.java | 6 +
src/java/org/apache/cassandra/cql3/Tuples.java | 13 +-
.../apache/cassandra/cql3/UntypedResultSet.java | 6 +-
.../apache/cassandra/cql3/UpdateParameters.java | 2 +-
.../org/apache/cassandra/cql3/UserTypes.java | 3 +-
.../cql3/statements/AlterTableStatement.java | 39 +-
.../cql3/statements/AlterTypeStatement.java | 18 +-
.../cql3/statements/CreateIndexStatement.java | 24 +-
.../cql3/statements/CreateTableStatement.java | 28 +-
.../cql3/statements/DeleteStatement.java | 2 +-
.../cql3/statements/DropTypeStatement.java | 6 +-
.../cassandra/cql3/statements/IndexTarget.java | 23 +-
.../cassandra/cql3/statements/Restriction.java | 6 +
.../cql3/statements/SelectStatement.java | 107 ++-
.../statements/SingleColumnRestriction.java | 24 +
.../org/apache/cassandra/db/CFRowAdder.java | 4 +-
.../db/composites/AbstractCellNameType.java | 4 +-
.../cassandra/db/composites/CellNameType.java | 2 +-
.../composites/CompoundSparseCellNameType.java | 5 +-
.../cassandra/db/filter/ExtendedFilter.java | 47 +-
.../cassandra/db/index/SecondaryIndex.java | 6 +-
.../db/index/SecondaryIndexManager.java | 32 +
.../db/index/SecondaryIndexSearcher.java | 2 +
.../db/index/composites/CompositesIndex.java | 4 +-
.../CompositesIndexOnCollectionValue.java | 2 +-
.../cassandra/db/marshal/AbstractType.java | 18 +
.../cassandra/db/marshal/CollectionType.java | 113 ++-
.../db/marshal/ColumnToCollectionType.java | 2 +-
.../apache/cassandra/db/marshal/FrozenType.java | 62 ++
.../apache/cassandra/db/marshal/ListType.java | 77 +-
.../apache/cassandra/db/marshal/MapType.java | 105 ++-
.../apache/cassandra/db/marshal/SetType.java | 69 +-
.../apache/cassandra/db/marshal/TupleType.java | 9 +-
.../apache/cassandra/db/marshal/TypeParser.java | 34 +-
.../apache/cassandra/db/marshal/UserType.java | 2 +-
.../apache/cassandra/hadoop/pig/CqlStorage.java | 8 +-
.../serializers/CollectionSerializer.java | 24 +-
.../cassandra/serializers/ListSerializer.java | 36 +-
.../cassandra/serializers/MapSerializer.java | 38 +-
.../apache/cassandra/transport/DataType.java | 16 +-
.../org/apache/cassandra/cql3/CQLTester.java | 84 +-
.../cassandra/cql3/ColumnConditionTest.java | 28 +-
.../cassandra/cql3/FrozenCollectionsTest.java | 791 +++++++++++++++++++
.../apache/cassandra/cql3/TupleTypeTest.java | 44 +-
.../db/marshal/CollectionTypeTest.java | 22 +-
.../cassandra/transport/SerDeserTest.java | 13 +-
.../cassandra/stress/generate/values/Lists.java | 2 +-
.../cassandra/stress/generate/values/Sets.java | 2 +-
61 files changed, 2139 insertions(+), 591 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index b1b5df8..5b63f48 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
2.1.3
+ * Support for frozen collections (CASSANDRA-7859)
* Fix overflow on histogram computation (CASSANDRA-8028)
* Have paxos reuse the timestamp generation of normal queries (CASSANDRA-7801)
Merged from 2.0:
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/bin/cqlsh
----------------------------------------------------------------------
diff --git a/bin/cqlsh b/bin/cqlsh
index 6ace914..f105273 100755
--- a/bin/cqlsh
+++ b/bin/cqlsh
@@ -486,6 +486,24 @@ def auto_format_udts():
cassandra.cqltypes.UserType.make_udt_class = classmethod(new_make_udt_class)
+class FrozenType(cassandra.cqltypes._ParameterizedType):
+ """
+ Needed until the bundled python driver adds FrozenType.
+ """
+ typename = "frozen"
+ num_subtypes = 1
+
+ @classmethod
+ def deserialize_safe(cls, byts, protocol_version):
+ subtype, = cls.subtypes
+ return subtype.from_binary(byts)
+
+ @classmethod
+ def serialize_safe(cls, val, protocol_version):
+ subtype, = cls.subtypes
+ return subtype.to_binary(val, protocol_version)
+
+
class Shell(cmd.Cmd):
custom_prompt = os.getenv('CQLSH_PROMPT', '')
if custom_prompt is not '':
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/pylib/cqlshlib/cql3handling.py
----------------------------------------------------------------------
diff --git a/pylib/cqlshlib/cql3handling.py b/pylib/cqlshlib/cql3handling.py
index b1179ca..dbd3709 100644
--- a/pylib/cqlshlib/cql3handling.py
+++ b/pylib/cqlshlib/cql3handling.py
@@ -255,13 +255,20 @@ JUNK ::= /([ \t\r\f\v]+|(--|[/][/])[^\n\r]*([\n\r]|$)|[/][*].*?[*][/])/ ;
<userType> ::= utname=<cfOrKsName> ;
-<storageType> ::= <simpleStorageType> | <collectionType> | <userType> ;
+<storageType> ::= <simpleStorageType> | <collectionType> | <frozenCollectionType> | <userType> ;
+# Note: autocomplete for frozen collection types does not handle nesting past depth 1 properly,
+# but that's a lot of work to fix for little benefit.
<collectionType> ::= "map" "<" <simpleStorageType> "," ( <simpleStorageType> | <userType> ) ">"
| "list" "<" ( <simpleStorageType> | <userType> ) ">"
| "set" "<" ( <simpleStorageType> | <userType> ) ">"
;
+<frozenCollectionType> ::= "frozen" "<" "map" "<" <storageType> "," <storageType> ">" ">"
+ | "frozen" "<" "list" "<" <storageType> ">" ">"
+ | "frozen" "<" "set" "<" <storageType> ">" ">"
+ ;
+
<columnFamilyName> ::= ( ksname=<cfOrKsName> dot="." )? cfname=<cfOrKsName> ;
<userTypeName> ::= ( ksname=<cfOrKsName> dot="." )? utname=<cfOrKsName> ;
@@ -906,11 +913,11 @@ syntax_rules += r'''
<cfamOrdering> ::= [ordercol]=<cident> ( "ASC" | "DESC" )
;
-<singleKeyCfSpec> ::= [newcolname]=<cident> <simpleStorageType> "PRIMARY" "KEY"
+<singleKeyCfSpec> ::= [newcolname]=<cident> <storageType> "PRIMARY" "KEY"
( "," [newcolname]=<cident> <storageType> )*
;
-<compositeKeyCfSpec> ::= [newcolname]=<cident> <simpleStorageType>
+<compositeKeyCfSpec> ::= [newcolname]=<cident> <storageType>
"," [newcolname]=<cident> <storageType> ( "static" )?
( "," [newcolname]=<cident> <storageType> ( "static" )? )*
"," "PRIMARY" k="KEY" p="(" ( partkey=<pkDef> | [pkey]=<cident> )
@@ -986,7 +993,11 @@ def create_cf_composite_primary_key_comma_completer(ctxt, cass):
syntax_rules += r'''
<createIndexStatement> ::= "CREATE" "CUSTOM"? "INDEX" ("IF" "NOT" "EXISTS")? indexname=<identifier>? "ON"
- cf=<columnFamilyName> ( "(" col=<cident> ")" | "(" "KEYS" "(" col=<cident> ")" ")")
+ cf=<columnFamilyName> "(" (
+ col=<cident> |
+ "keys(" col=<cident> ")" |
+ "fullCollection(" col=<cident> ")"
+ ) ")"
( "USING" <stringLiteral> ( "WITH" "OPTIONS" "=" <mapLiteral> )? )?
;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/AbstractMarker.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/AbstractMarker.java b/src/java/org/apache/cassandra/cql3/AbstractMarker.java
index 10a4dff..d18790c 100644
--- a/src/java/org/apache/cassandra/cql3/AbstractMarker.java
+++ b/src/java/org/apache/cassandra/cql3/AbstractMarker.java
@@ -99,7 +99,7 @@ public abstract class AbstractMarker extends Term.NonTerminal
private static ColumnSpecification makeInReceiver(ColumnSpecification receiver)
{
ColumnIdentifier inName = new ColumnIdentifier("in(" + receiver.name + ")", true);
- return new ColumnSpecification(receiver.ksName, receiver.cfName, inName, ListType.getInstance(receiver.type));
+ return new ColumnSpecification(receiver.ksName, receiver.cfName, inName, ListType.getInstance(receiver.type, false));
}
@Override
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/CQL3Row.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/CQL3Row.java b/src/java/org/apache/cassandra/cql3/CQL3Row.java
index 6fa2b64..e3e76d1 100644
--- a/src/java/org/apache/cassandra/cql3/CQL3Row.java
+++ b/src/java/org/apache/cassandra/cql3/CQL3Row.java
@@ -27,7 +27,7 @@ public interface CQL3Row
{
public ByteBuffer getClusteringColumn(int i);
public Cell getColumn(ColumnIdentifier name);
- public List<Cell> getCollection(ColumnIdentifier name);
+ public List<Cell> getMultiCellColumn(ColumnIdentifier name);
public interface Builder
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/CQL3Type.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/CQL3Type.java b/src/java/org/apache/cassandra/cql3/CQL3Type.java
index 6d55285..b656de8 100644
--- a/src/java/org/apache/cassandra/cql3/CQL3Type.java
+++ b/src/java/org/apache/cassandra/cql3/CQL3Type.java
@@ -26,9 +26,13 @@ import org.apache.cassandra.db.marshal.*;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.exceptions.SyntaxException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public interface CQL3Type
{
+ static final Logger logger = LoggerFactory.getLogger(CQL3Type.class);
+
public boolean isCollection();
public AbstractType<?> getType();
@@ -160,17 +164,30 @@ public interface CQL3Type
@Override
public String toString()
{
+ boolean isFrozen = !this.type.isMultiCell();
+ StringBuilder sb = new StringBuilder(isFrozen ? "frozen<" : "");
switch (type.kind)
{
case LIST:
- return "list<" + ((ListType)type).elements.asCQL3Type() + ">";
+ AbstractType<?> listType = ((ListType)type).getElementsType();
+ sb.append("list<").append(listType.asCQL3Type());
+ break;
case SET:
- return "set<" + ((SetType)type).elements.asCQL3Type() + ">";
+ AbstractType<?> setType = ((SetType)type).getElementsType();
+ sb.append("set<").append(setType.asCQL3Type());
+ break;
case MAP:
- MapType mt = (MapType)type;
- return "map<" + mt.keys.asCQL3Type() + ", " + mt.values.asCQL3Type() + ">";
+ AbstractType<?> keysType = ((MapType)type).getKeysType();
+ AbstractType<?> valuesType = ((MapType)type).getValuesType();
+ sb.append("map<").append(keysType.asCQL3Type()).append(", ").append(valuesType.asCQL3Type());
+ break;
+ default:
+ throw new AssertionError();
}
- throw new AssertionError();
+ sb.append(">");
+ if (isFrozen)
+ sb.append(">");
+ return sb.toString();
}
}
@@ -284,7 +301,9 @@ public interface CQL3Type
// actual type used, so Raw is a "not yet prepared" CQL3Type.
public abstract class Raw
{
- protected boolean frozen;
+ protected boolean frozen = false;
+
+ protected abstract boolean supportsFreezing();
public boolean isCollection()
{
@@ -296,10 +315,10 @@ public interface CQL3Type
return false;
}
- public Raw freeze()
+ public void freeze() throws InvalidRequestException
{
- frozen = true;
- return this;
+ String message = String.format("frozen<> is only allowed on collections, tuples, and user-defined types (got %s)", this);
+ throw new InvalidRequestException(message);
}
public abstract CQL3Type prepare(String keyspace) throws InvalidRequestException;
@@ -314,53 +333,30 @@ public interface CQL3Type
return new RawUT(name);
}
- public static Raw map(CQL3Type.Raw t1, CQL3Type.Raw t2) throws InvalidRequestException
+ public static Raw map(CQL3Type.Raw t1, CQL3Type.Raw t2)
{
- if (t1.isCollection() || t2.isCollection())
- throw new InvalidRequestException("map type cannot contain another collection");
- if (t1.isCounter() || t2.isCounter())
- throw new InvalidRequestException("counters are not allowed inside a collection");
-
return new RawCollection(CollectionType.Kind.MAP, t1, t2);
}
- public static Raw list(CQL3Type.Raw t) throws InvalidRequestException
+ public static Raw list(CQL3Type.Raw t)
{
- if (t.isCollection())
- throw new InvalidRequestException("list type cannot contain another collection");
- if (t.isCounter())
- throw new InvalidRequestException("counters are not allowed inside a collection");
-
return new RawCollection(CollectionType.Kind.LIST, null, t);
}
- public static Raw set(CQL3Type.Raw t) throws InvalidRequestException
+ public static Raw set(CQL3Type.Raw t)
{
- if (t.isCollection())
- throw new InvalidRequestException("set type cannot contain another collection");
- if (t.isCounter())
- throw new InvalidRequestException("counters are not allowed inside a collection");
-
return new RawCollection(CollectionType.Kind.SET, null, t);
}
- public static Raw tuple(List<CQL3Type.Raw> ts) throws InvalidRequestException
+ public static Raw tuple(List<CQL3Type.Raw> ts)
{
- for (int i = 0; i < ts.size(); i++)
- if (ts.get(i) != null && ts.get(i).isCounter())
- throw new InvalidRequestException("counters are not allowed inside tuples");
-
return new RawTuple(ts);
}
public static Raw frozen(CQL3Type.Raw t) throws InvalidRequestException
{
- if (t instanceof RawUT)
- return ((RawUT)t).freeze();
- if (t instanceof RawTuple)
- return ((RawTuple)t).freeze();
-
- throw new InvalidRequestException("frozen<> is only currently only allowed on User-Defined and tuple types");
+ t.freeze();
+ return t;
}
private static class RawType extends Raw
@@ -377,6 +373,11 @@ public interface CQL3Type
return type;
}
+ protected boolean supportsFreezing()
+ {
+ return false;
+ }
+
public boolean isCounter()
{
return type == Native.COUNTER;
@@ -402,12 +403,18 @@ public interface CQL3Type
this.values = values;
}
- public Raw freeze()
+ public void freeze() throws InvalidRequestException
{
- if (keys != null)
+ if (keys != null && keys.supportsFreezing())
keys.freeze();
- values.freeze();
- return super.freeze();
+ if (values != null && values.supportsFreezing())
+ values.freeze();
+ frozen = true;
+ }
+
+ protected boolean supportsFreezing()
+ {
+ return true;
}
public boolean isCollection()
@@ -417,11 +424,28 @@ public interface CQL3Type
public CQL3Type prepare(String keyspace) throws InvalidRequestException
{
+ assert values != null : "Got null values type for a collection";
+
+ if (!frozen && values.supportsFreezing() && !values.frozen)
+ throw new InvalidRequestException("Non-frozen collections are not allowed inside collections: " + this);
+ if (values.isCounter())
+ throw new InvalidRequestException("Counters are not allowed inside collections: " + this);
+
+ if (keys != null)
+ {
+ if (!frozen && keys.supportsFreezing() && !keys.frozen)
+ throw new InvalidRequestException("Non-frozen collections are not allowed inside collections: " + this);
+ }
+
switch (kind)
{
- case LIST: return new Collection(ListType.getInstance(values.prepare(keyspace).getType()));
- case SET: return new Collection(SetType.getInstance(values.prepare(keyspace).getType()));
- case MAP: return new Collection(MapType.getInstance(keys.prepare(keyspace).getType(), values.prepare(keyspace).getType()));
+ case LIST:
+ return new Collection(ListType.getInstance(values.prepare(keyspace).getType(), !frozen));
+ case SET:
+ return new Collection(SetType.getInstance(values.prepare(keyspace).getType(), !frozen));
+ case MAP:
+ assert keys != null : "Got null keys type for a collection";
+ return new Collection(MapType.getInstance(keys.prepare(keyspace).getType(), values.prepare(keyspace).getType(), !frozen));
}
throw new AssertionError();
}
@@ -429,11 +453,13 @@ public interface CQL3Type
@Override
public String toString()
{
+ String start = frozen? "frozen<" : "";
+ String end = frozen ? ">" : "";
switch (kind)
{
- case LIST: return "list<" + values + ">";
- case SET: return "set<" + values + ">";
- case MAP: return "map<" + keys + ", " + values + ">";
+ case LIST: return start + "list<" + values + ">" + end;
+ case SET: return start + "set<" + values + ">" + end;
+ case MAP: return start + "map<" + keys + ", " + values + ">" + end;
}
throw new AssertionError();
}
@@ -448,6 +474,11 @@ public interface CQL3Type
this.name = name;
}
+ public void freeze()
+ {
+ frozen = true;
+ }
+
public CQL3Type prepare(String keyspace) throws InvalidRequestException
{
if (name.hasKeyspace())
@@ -477,7 +508,7 @@ public interface CQL3Type
return new UserDefined(name.toString(), type);
}
- public boolean isUDT()
+ protected boolean supportsFreezing()
{
return true;
}
@@ -498,12 +529,9 @@ public interface CQL3Type
this.types = types;
}
- public Raw freeze()
+ protected boolean supportsFreezing()
{
- for (CQL3Type.Raw t : types)
- if (t != null)
- t.freeze();
- return super.freeze();
+ return true;
}
public boolean isCollection()
@@ -511,15 +539,29 @@ public interface CQL3Type
return false;
}
- public CQL3Type prepare(String keyspace) throws InvalidRequestException
+ public void freeze() throws InvalidRequestException
{
- List<AbstractType<?>> ts = new ArrayList<>(types.size());
for (CQL3Type.Raw t : types)
- ts.add(t.prepare(keyspace).getType());
+ {
+ if (t.supportsFreezing())
+ t.freeze();
+ }
+ frozen = true;
+ }
+ public CQL3Type prepare(String keyspace) throws InvalidRequestException
+ {
if (!frozen)
- throw new InvalidRequestException("Non-frozen tuples are not supported, please use frozen<>");
+ freeze();
+ List<AbstractType<?>> ts = new ArrayList<>(types.size());
+ for (CQL3Type.Raw t : types)
+ {
+ if (t.isCounter())
+ throw new InvalidRequestException("Counters are not allowed inside tuples");
+
+ ts.add(t.prepare(keyspace).getType());
+ }
return new Tuple(new TupleType(ts));
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/ColumnCondition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/ColumnCondition.java b/src/java/org/apache/cassandra/cql3/ColumnCondition.java
index 25cb07d..1a8e5a3 100644
--- a/src/java/org/apache/cassandra/cql3/ColumnCondition.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnCondition.java
@@ -20,7 +20,6 @@ package org.apache.cassandra.cql3;
import java.nio.ByteBuffer;
import java.util.*;
-import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterators;
import static com.google.common.collect.Lists.newArrayList;
@@ -33,12 +32,13 @@ import org.apache.cassandra.db.composites.Composite;
import org.apache.cassandra.db.filter.ColumnSlice;
import org.apache.cassandra.db.marshal.*;
import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.transport.Server;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * A CQL3 condition.
+ * A CQL3 condition on the value of a column or collection element. For example, "UPDATE .. IF a = 0".
*/
public class ColumnCondition
{
@@ -235,12 +235,6 @@ public class ColumnCondition
CellName name = current.metadata().comparator.create(rowPrefix, column);
return isSatisfiedByValue(value, current.getColumn(name), column.type, operator, now);
}
-
- @Override
- public int hashCode()
- {
- return Objects.hashCode(column, value, operator);
- }
}
/**
@@ -275,12 +269,6 @@ public class ColumnCondition
}
return false;
}
-
- @Override
- public int hashCode()
- {
- return Objects.hashCode(column, inValues, operator);
- }
}
/** A condition on an element of a collection column. IN operators are not supported here, see ElementAccessInBound. */
@@ -305,16 +293,37 @@ public class ColumnCondition
if (column.type instanceof MapType)
{
- Cell cell = current.getColumn(current.metadata().comparator.create(rowPrefix, column, collectionElement));
- return isSatisfiedByValue(value, cell, ((MapType) column.type).values, operator, now);
+ MapType mapType = (MapType) column.type;
+ if (column.type.isMultiCell())
+ {
+ Cell cell = current.getColumn(current.metadata().comparator.create(rowPrefix, column, collectionElement));
+ return isSatisfiedByValue(value, cell, mapType.getValuesType(), operator, now);
+ }
+ else
+ {
+ Cell cell = current.getColumn(current.metadata().comparator.create(rowPrefix, column));
+ ByteBuffer mapElementValue = cell.isLive(now) ? mapType.getSerializer().getSerializedValue(cell.value(), collectionElement, mapType.getKeysType())
+ : null;
+ return compareWithOperator(operator, mapType.getValuesType(), value, mapElementValue);
+ }
}
// sets don't have element access, so it's a list
- assert column.type instanceof ListType;
- ByteBuffer columnValue = getListItem(
- collectionColumns(current.metadata().comparator.create(rowPrefix, column), current, now),
- getListIndex(collectionElement));
- return compareWithOperator(operator, ((ListType)column.type).elements, value, columnValue);
+ ListType listType = (ListType) column.type;
+ if (column.type.isMultiCell())
+ {
+ ByteBuffer columnValue = getListItem(
+ collectionColumns(current.metadata().comparator.create(rowPrefix, column), current, now),
+ getListIndex(collectionElement));
+ return compareWithOperator(operator, listType.getElementsType(), value, columnValue);
+ }
+ else
+ {
+ Cell cell = current.getColumn(current.metadata().comparator.create(rowPrefix, column));
+ ByteBuffer listElementValue = cell.isLive(now) ? listType.getSerializer().getElement(cell.value(), getListIndex(collectionElement))
+ : null;
+ return compareWithOperator(operator, listType.getElementsType(), value, listElementValue);
+ }
}
static int getListIndex(ByteBuffer collectionElement) throws InvalidRequestException
@@ -338,12 +347,6 @@ public class ColumnCondition
{
return collectionElement;
}
-
- @Override
- public int hashCode()
- {
- return Objects.hashCode(column, collectionElement, value, operator);
- }
}
static class ElementAccessInBound extends Bound
@@ -375,47 +378,86 @@ public class ColumnCondition
CellNameType nameType = current.metadata().comparator;
if (column.type instanceof MapType)
{
- CellName name = nameType.create(rowPrefix, column, collectionElement);
- Cell item = current.getColumn(name);
- AbstractType<?> valueType = ((MapType) column.type).values;
- for (ByteBuffer value : inValues)
+ MapType mapType = (MapType) column.type;
+ AbstractType<?> valueType = mapType.getValuesType();
+ if (column.type.isMultiCell())
{
- if (isSatisfiedByValue(value, item, valueType, Operator.EQ, now))
- return true;
+ CellName name = nameType.create(rowPrefix, column, collectionElement);
+ Cell item = current.getColumn(name);
+ for (ByteBuffer value : inValues)
+ {
+ if (isSatisfiedByValue(value, item, valueType, Operator.EQ, now))
+ return true;
+ }
+ return false;
+ }
+ else
+ {
+ Cell cell = current.getColumn(nameType.create(rowPrefix, column));
+ ByteBuffer mapElementValue = null;
+ if (cell != null && cell.isLive(now))
+ mapElementValue = mapType.getSerializer().getSerializedValue(cell.value(), collectionElement, mapType.getKeysType());
+ for (ByteBuffer value : inValues)
+ {
+ if (value == null)
+ {
+ if (mapElementValue == null)
+ return true;
+ continue;
+ }
+ if (valueType.compare(value, mapElementValue) == 0)
+ return true;
+ }
+ return false;
}
- return false;
}
- assert column.type instanceof ListType;
- ByteBuffer columnValue = ElementAccessBound.getListItem(
- collectionColumns(nameType.create(rowPrefix, column), current, now),
- ElementAccessBound.getListIndex(collectionElement));
+ ListType listType = (ListType) column.type;
+ AbstractType<?> elementsType = listType.getElementsType();
+ if (column.type.isMultiCell())
+ {
+ ByteBuffer columnValue = ElementAccessBound.getListItem(
+ collectionColumns(nameType.create(rowPrefix, column), current, now),
+ ElementAccessBound.getListIndex(collectionElement));
- AbstractType<?> valueType = ((ListType) column.type).elements;
- for (ByteBuffer value : inValues)
+ for (ByteBuffer value : inValues)
+ {
+ if (compareWithOperator(Operator.EQ, elementsType, value, columnValue))
+ return true;
+ }
+ }
+ else
{
- if (compareWithOperator(Operator.EQ, valueType, value, columnValue))
- return true;
+ Cell cell = current.getColumn(nameType.create(rowPrefix, column));
+ ByteBuffer listElementValue = null;
+ if (cell != null && cell.isLive(now))
+ listElementValue = listType.getSerializer().getElement(cell.value(), ElementAccessBound.getListIndex(collectionElement));
+
+ for (ByteBuffer value : inValues)
+ {
+ if (value == null)
+ {
+ if (listElementValue == null)
+ return true;
+ continue;
+ }
+ if (elementsType.compare(value, listElementValue) == 0)
+ return true;
+ }
}
return false;
}
-
- @Override
- public int hashCode()
- {
- return Objects.hashCode(column, collectionElement, inValues, operator);
- }
}
/** A condition on an entire collection column. IN operators are not supported here, see CollectionInBound. */
static class CollectionBound extends Bound
{
- public final Term.Terminal value;
+ private final Term.Terminal value;
private CollectionBound(ColumnCondition condition, QueryOptions options) throws InvalidRequestException
{
super(condition.column, condition.operator);
- assert column.type instanceof CollectionType && condition.collectionElement == null;
+ assert column.type.isCollection() && condition.collectionElement == null;
assert !condition.operator.equals(Operator.IN);
this.value = condition.value.bind(options);
}
@@ -424,18 +466,44 @@ public class ColumnCondition
{
CollectionType type = (CollectionType)column.type;
- Iterator<Cell> iter = collectionColumns(current.metadata().comparator.create(rowPrefix, column), current, now);
+ if (type.isMultiCell())
+ {
+ Iterator<Cell> iter = collectionColumns(current.metadata().comparator.create(rowPrefix, column), current, now);
+ if (value == null)
+ {
+ if (operator.equals(Operator.EQ))
+ return !iter.hasNext();
+ else if (operator.equals(Operator.NEQ))
+ return iter.hasNext();
+ else
+ throw new InvalidRequestException(String.format("Invalid comparison with null for operator \"%s\"", operator));
+ }
+
+ return valueAppliesTo(type, iter, value, operator);
+ }
+
+ // frozen collections
+ Cell cell = current.getColumn(current.metadata().comparator.create(rowPrefix, column));
if (value == null)
{
- if (operator.equals(Operator.EQ))
- return !iter.hasNext();
- else if (operator.equals(Operator.NEQ))
- return iter.hasNext();
+ if (operator == Operator.EQ)
+ return cell == null || !cell.isLive(now);
+ else if (operator == Operator.NEQ)
+ return cell != null && cell.isLive(now);
else
throw new InvalidRequestException(String.format("Invalid comparison with null for operator \"%s\"", operator));
}
- return valueAppliesTo(type, iter, value, operator);
+ // make sure we use v3 serialization format for comparison
+ ByteBuffer conditionValue;
+ if (type.kind == CollectionType.Kind.LIST)
+ conditionValue = ((Lists.Value) value).getWithProtocolVersion(Server.VERSION_3);
+ else if (type.kind == CollectionType.Kind.SET)
+ conditionValue = ((Sets.Value) value).getWithProtocolVersion(Server.VERSION_3);
+ else
+ conditionValue = ((Maps.Value) value).getWithProtocolVersion(Server.VERSION_3);
+
+ return compareWithOperator(operator, type, conditionValue, cell.value());
}
static boolean valueAppliesTo(CollectionType type, Iterator<Cell> iter, Term.Terminal value, Operator operator)
@@ -495,15 +563,15 @@ public class ColumnCondition
static boolean listAppliesTo(ListType type, Iterator<Cell> iter, List<ByteBuffer> elements, Operator operator)
{
- return setOrListAppliesTo(type.elements, iter, elements.iterator(), operator, false);
+ return setOrListAppliesTo(type.getElementsType(), iter, elements.iterator(), operator, false);
}
static boolean setAppliesTo(SetType type, Iterator<Cell> iter, Set<ByteBuffer> elements, Operator operator)
{
ArrayList<ByteBuffer> sortedElements = new ArrayList<>(elements.size());
sortedElements.addAll(elements);
- Collections.sort(sortedElements, type.elements);
- return setOrListAppliesTo(type.elements, iter, sortedElements.iterator(), operator, true);
+ Collections.sort(sortedElements, type.getElementsType());
+ return setOrListAppliesTo(type.getElementsType(), iter, sortedElements.iterator(), operator, true);
}
static boolean mapAppliesTo(MapType type, Iterator<Cell> iter, Map<ByteBuffer, ByteBuffer> elements, Operator operator)
@@ -518,12 +586,12 @@ public class ColumnCondition
Cell c = iter.next();
// compare the keys
- int comparison = type.keys.compare(c.name().collectionElement(), conditionEntry.getKey());
+ int comparison = type.getKeysType().compare(c.name().collectionElement(), conditionEntry.getKey());
if (comparison != 0)
return evaluateComparisonWithOperator(comparison, operator);
// compare the values
- comparison = type.values.compare(c.value(), conditionEntry.getValue());
+ comparison = type.getValuesType().compare(c.value(), conditionEntry.getValue());
if (comparison != 0)
return evaluateComparisonWithOperator(comparison, operator);
}
@@ -534,33 +602,11 @@ public class ColumnCondition
// they're equal
return operator == Operator.EQ || operator == Operator.LTE || operator == Operator.GTE;
}
-
- @Override
- public int hashCode()
- {
- Object val = null;
- if (value != null)
- {
- switch (((CollectionType)column.type).kind)
- {
- case LIST:
- val = ((Lists.Value)value).elements.hashCode();
- break;
- case SET:
- val = ((Sets.Value)value).elements.hashCode();
- break;
- case MAP:
- val = ((Maps.Value)value).map.hashCode();
- break;
- }
- }
- return Objects.hashCode(column, val);
- }
}
public static class CollectionInBound extends Bound
{
- public final List<Term.Terminal> inValues;
+ private final List<Term.Terminal> inValues;
private CollectionInBound(ColumnCondition condition, QueryOptions options) throws InvalidRequestException
{
@@ -575,7 +621,7 @@ public class ColumnCondition
Lists.Marker inValuesMarker = (Lists.Marker) condition.value;
if (column.type instanceof ListType)
{
- ListType deserializer = ListType.getInstance(collectionType.valueComparator());
+ ListType deserializer = ListType.getInstance(collectionType.valueComparator(), false);
for (ByteBuffer buffer : inValuesMarker.bind(options).elements)
{
if (buffer == null)
@@ -586,7 +632,7 @@ public class ColumnCondition
}
else if (column.type instanceof MapType)
{
- MapType deserializer = MapType.getInstance(collectionType.nameComparator(), collectionType.valueComparator());
+ MapType deserializer = MapType.getInstance(collectionType.nameComparator(), collectionType.valueComparator(), false);
for (ByteBuffer buffer : inValuesMarker.bind(options).elements)
{
if (buffer == null)
@@ -597,7 +643,7 @@ public class ColumnCondition
}
else if (column.type instanceof SetType)
{
- SetType deserializer = SetType.getInstance(collectionType.valueComparator());
+ SetType deserializer = SetType.getInstance(collectionType.valueComparator(), false);
for (ByteBuffer buffer : inValuesMarker.bind(options).elements)
{
if (buffer == null)
@@ -618,45 +664,34 @@ public class ColumnCondition
{
CollectionType type = (CollectionType)column.type;
CellName name = current.metadata().comparator.create(rowPrefix, column);
-
- // copy iterator contents so that we can properly reuse them for each comparison with an IN value
- List<Cell> cells = newArrayList(collectionColumns(name, current, now));
- for (Term.Terminal value : inValues)
+ if (type.isMultiCell())
{
- if (CollectionBound.valueAppliesTo(type, cells.iterator(), value, Operator.EQ))
- return true;
+ // copy iterator contents so that we can properly reuse them for each comparison with an IN value
+ List<Cell> cells = newArrayList(collectionColumns(name, current, now));
+ for (Term.Terminal value : inValues)
+ {
+ if (CollectionBound.valueAppliesTo(type, cells.iterator(), value, Operator.EQ))
+ return true;
+ }
+ return false;
}
- return false;
- }
-
- @Override
- public int hashCode()
- {
- List<Collection<ByteBuffer>> inValueBuffers = new ArrayList<>(inValues.size());
- switch (((CollectionType)column.type).kind)
+ else
{
- case LIST:
- for (Term.Terminal term : inValues)
- inValueBuffers.add(term == null ? null : ((Lists.Value)term).elements);
- break;
- case SET:
- for (Term.Terminal term : inValues)
- inValueBuffers.add(term == null ? null : ((Sets.Value)term).elements);
- break;
- case MAP:
- for (Term.Terminal term : inValues)
+ Cell cell = current.getColumn(name);
+ for (Term.Terminal value : inValues)
+ {
+ if (value == null)
{
- if (term != null)
- {
- inValueBuffers.add(((Maps.Value)term).map.keySet());
- inValueBuffers.add(((Maps.Value)term).map.values());
- }
- else
- inValueBuffers.add(null);
+ if (cell == null || !cell.isLive(now))
+ return true;
}
- break;
+ else if (type.compare(((Term.CollectionTerminal)value).getWithProtocolVersion(Server.VERSION_3), cell.value()) == 0)
+ {
+ return true;
+ }
+ }
+ return false;
}
- return Objects.hashCode(column, inValueBuffers, operator);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/Constants.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Constants.java b/src/java/org/apache/cassandra/cql3/Constants.java
index a8f0120..01fbdf0 100644
--- a/src/java/org/apache/cassandra/cql3/Constants.java
+++ b/src/java/org/apache/cassandra/cql3/Constants.java
@@ -18,7 +18,6 @@
package org.apache.cassandra.cql3;
import java.nio.ByteBuffer;
-import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -368,7 +367,7 @@ public abstract class Constants
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
CellName cname = cf.getComparator().create(prefix, column);
- if (column.type.isCollection())
+ if (column.type.isMultiCell())
cf.addAtom(params.makeRangeTombstone(cname.slice()));
else
cf.addColumn(params.makeTombstone(cname));
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/Cql.g
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Cql.g b/src/java/org/apache/cassandra/cql3/Cql.g
index b1c598b..06ba81c 100644
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -575,8 +575,9 @@ createIndexStatement returns [CreateIndexStatement expr]
;
indexIdent returns [IndexTarget.Raw id]
- : c=cident { $id = IndexTarget.Raw.of(c); }
+ : c=cident { $id = IndexTarget.Raw.valuesOf(c); }
| K_KEYS '(' c=cident ')' { $id = IndexTarget.Raw.keysOf(c); }
+ | K_FULL '(' c=cident ')' { $id = IndexTarget.Raw.fullCollection(c); }
;
@@ -1148,21 +1149,21 @@ native_type returns [CQL3Type t]
collection_type returns [CQL3Type.Raw pt]
: K_MAP '<' t1=comparatorType ',' t2=comparatorType '>'
- { try {
+ {
// if we can't parse either t1 or t2, antlr will "recover" and we may have t1 or t2 null.
if (t1 != null && t2 != null)
$pt = CQL3Type.Raw.map(t1, t2);
- } catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); } }
+ }
| K_LIST '<' t=comparatorType '>'
- { try { if (t != null) $pt = CQL3Type.Raw.list(t); } catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); } }
+ { if (t != null) $pt = CQL3Type.Raw.list(t); }
| K_SET '<' t=comparatorType '>'
- { try { if (t != null) $pt = CQL3Type.Raw.set(t); } catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); } }
+ { if (t != null) $pt = CQL3Type.Raw.set(t); }
;
tuple_type returns [CQL3Type.Raw t]
: K_TUPLE '<' { List<CQL3Type.Raw> types = new ArrayList<>(); }
t1=comparatorType { types.add(t1); } (',' tn=comparatorType { types.add(tn); })*
- '>' { try { $t = CQL3Type.Raw.tuple(types); } catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); }}
+ '>' { $t = CQL3Type.Raw.tuple(types); }
;
username
@@ -1227,6 +1228,7 @@ K_WHERE: W H E R E;
K_AND: A N D;
K_KEY: K E Y;
K_KEYS: K E Y S;
+K_FULL: F U L L;
K_INSERT: I N S E R T;
K_UPDATE: U P D A T E;
K_WITH: W I T H;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/Lists.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Lists.java b/src/java/org/apache/cassandra/cql3/Lists.java
index 9d22364..d5174d1 100644
--- a/src/java/org/apache/cassandra/cql3/Lists.java
+++ b/src/java/org/apache/cassandra/cql3/Lists.java
@@ -19,8 +19,6 @@ package org.apache.cassandra.cql3;
import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@@ -34,6 +32,7 @@ import org.apache.cassandra.db.marshal.ListType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.serializers.CollectionSerializer;
import org.apache.cassandra.serializers.MarshalException;
+import org.apache.cassandra.transport.Server;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.UUIDGen;
@@ -56,7 +55,7 @@ public abstract class Lists
public static ColumnSpecification valueSpecOf(ColumnSpecification column)
{
- return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), ((ListType)column.type).elements);
+ return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), ((ListType)column.type).getElementsType());
}
public static class Literal implements Term.Raw
@@ -124,7 +123,7 @@ public abstract class Lists
}
}
- public static class Value extends Term.MultiItemTerminal
+ public static class Value extends Term.MultiItemTerminal implements Term.CollectionTerminal
{
public final List<ByteBuffer> elements;
@@ -143,7 +142,7 @@ public abstract class Lists
List<ByteBuffer> elements = new ArrayList<ByteBuffer>(l.size());
for (Object element : l)
// elements can be null in lists that represent a set of IN values
- elements.add(element == null ? null : type.elements.decompose(element));
+ elements.add(element == null ? null : type.getElementsType().decompose(element));
return new Value(elements);
}
catch (MarshalException e)
@@ -154,7 +153,12 @@ public abstract class Lists
public ByteBuffer get(QueryOptions options)
{
- return CollectionSerializer.pack(elements, elements.size(), options.getProtocolVersion());
+ return getWithProtocolVersion(options.getProtocolVersion());
+ }
+
+ public ByteBuffer getWithProtocolVersion(int protocolVersion)
+ {
+ return CollectionSerializer.pack(elements, elements.size(), protocolVersion);
}
public boolean equals(ListType lt, Value v)
@@ -163,7 +167,7 @@ public abstract class Lists
return false;
for (int i = 0; i < elements.size(); i++)
- if (lt.elements.compare(elements.get(i), v.elements.get(i)) != 0)
+ if (lt.getElementsType().compare(elements.get(i), v.elements.get(i)) != 0)
return false;
return true;
@@ -292,9 +296,12 @@ public abstract class Lists
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
- // delete + append
- CellName name = cf.getComparator().create(prefix, column);
- cf.addAtom(params.makeTombstoneForOverwrite(name.slice()));
+ if (column.type.isMultiCell())
+ {
+ // delete + append
+ CellName name = cf.getComparator().create(prefix, column);
+ cf.addAtom(params.makeTombstoneForOverwrite(name.slice()));
+ }
Appender.doAppend(t, cf, prefix, column, params);
}
}
@@ -324,6 +331,9 @@ public abstract class Lists
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
+ // we should not get here for frozen lists
+ assert column.type.isMultiCell() : "Attempted to set an individual element on a frozen list";
+
ByteBuffer index = idx.bindAndGet(params.options);
ByteBuffer value = t.bindAndGet(params.options);
@@ -362,23 +372,36 @@ public abstract class Lists
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
+ assert column.type.isMultiCell() : "Attempted to append to a frozen list";
doAppend(t, cf, prefix, column, params);
}
static void doAppend(Term t, ColumnFamily cf, Composite prefix, ColumnDefinition column, UpdateParameters params) throws InvalidRequestException
{
Term.Terminal value = t.bind(params.options);
- // If we append null, do nothing. Note that for Setter, we've
- // already removed the previous value so we're good here too
- if (value == null)
- return;
-
- assert value instanceof Lists.Value;
- List<ByteBuffer> toAdd = ((Lists.Value)value).elements;
- for (int i = 0; i < toAdd.size(); i++)
+ Lists.Value listValue = (Lists.Value)value;
+ if (column.type.isMultiCell())
{
- ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes());
- cf.addColumn(params.makeColumn(cf.getComparator().create(prefix, column, uuid), toAdd.get(i)));
+ // If we append null, do nothing. Note that for Setter, we've
+ // already removed the previous value so we're good here too
+ if (value == null)
+ return;
+
+ List<ByteBuffer> toAdd = listValue.elements;
+ for (int i = 0; i < toAdd.size(); i++)
+ {
+ ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes());
+ cf.addColumn(params.makeColumn(cf.getComparator().create(prefix, column, uuid), toAdd.get(i)));
+ }
+ }
+ else
+ {
+ // for frozen lists, we're overwriting the whole cell value
+ CellName name = cf.getComparator().create(prefix, column);
+ if (value == null)
+ cf.addAtom(params.makeTombstone(name));
+ else
+ cf.addColumn(params.makeColumn(name, listValue.getWithProtocolVersion(Server.CURRENT_VERSION)));
}
}
}
@@ -392,6 +415,7 @@ public abstract class Lists
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
+ assert column.type.isMultiCell() : "Attempted to prepend to a frozen list";
Term.Terminal value = t.bind(params.options);
if (value == null)
return;
@@ -424,6 +448,7 @@ public abstract class Lists
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
+ assert column.type.isMultiCell() : "Attempted to delete from a frozen list";
List<Cell> existingList = params.getPrefetchedList(rowKey, column.name);
// We want to call bind before possibly returning to reject queries where the value provided is not a list.
Term.Terminal value = t.bind(params.options);
@@ -464,6 +489,7 @@ public abstract class Lists
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
+ assert column.type.isMultiCell() : "Attempted to delete an item by index from a frozen list";
Term.Terminal index = t.bind(params.options);
if (index == null)
throw new InvalidRequestException("Invalid null value for list index");
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/Maps.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Maps.java b/src/java/org/apache/cassandra/cql3/Maps.java
index ce0ba2a..5b58833 100644
--- a/src/java/org/apache/cassandra/cql3/Maps.java
+++ b/src/java/org/apache/cassandra/cql3/Maps.java
@@ -19,7 +19,6 @@ package org.apache.cassandra.cql3;
import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
@@ -36,6 +35,7 @@ import org.apache.cassandra.db.marshal.MapType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.serializers.CollectionSerializer;
import org.apache.cassandra.serializers.MarshalException;
+import org.apache.cassandra.transport.Server;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.Pair;
@@ -48,12 +48,12 @@ public abstract class Maps
public static ColumnSpecification keySpecOf(ColumnSpecification column)
{
- return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("key(" + column.name + ")", true), ((MapType)column.type).keys);
+ return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("key(" + column.name + ")", true), ((MapType)column.type).getKeysType());
}
public static ColumnSpecification valueSpecOf(ColumnSpecification column)
{
- return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), ((MapType)column.type).values);
+ return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), ((MapType)column.type).getValuesType());
}
public static class Literal implements Term.Raw
@@ -86,7 +86,7 @@ public abstract class Maps
values.put(k, v);
}
- DelayedValue value = new DelayedValue(((MapType)receiver.type).keys, values);
+ DelayedValue value = new DelayedValue(((MapType)receiver.type).getKeysType(), values);
return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
}
@@ -134,7 +134,7 @@ public abstract class Maps
}
}
- public static class Value extends Term.Terminal
+ public static class Value extends Term.Terminal implements Term.CollectionTerminal
{
public final Map<ByteBuffer, ByteBuffer> map;
@@ -152,7 +152,7 @@ public abstract class Maps
Map<?, ?> m = (Map<?, ?>)type.getSerializer().deserializeForNativeProtocol(value, version);
Map<ByteBuffer, ByteBuffer> map = new LinkedHashMap<ByteBuffer, ByteBuffer>(m.size());
for (Map.Entry<?, ?> entry : m.entrySet())
- map.put(type.keys.decompose(entry.getKey()), type.values.decompose(entry.getValue()));
+ map.put(type.getKeysType().decompose(entry.getKey()), type.getValuesType().decompose(entry.getValue()));
return new Value(map);
}
catch (MarshalException e)
@@ -163,13 +163,18 @@ public abstract class Maps
public ByteBuffer get(QueryOptions options)
{
- List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(2 * map.size());
+ return getWithProtocolVersion(options.getProtocolVersion());
+ }
+
+ public ByteBuffer getWithProtocolVersion(int protocolVersion)
+ {
+ List<ByteBuffer> buffers = new ArrayList<>(2 * map.size());
for (Map.Entry<ByteBuffer, ByteBuffer> entry : map.entrySet())
{
buffers.add(entry.getKey());
buffers.add(entry.getValue());
}
- return CollectionSerializer.pack(buffers, map.size(), options.getProtocolVersion());
+ return CollectionSerializer.pack(buffers, map.size(), protocolVersion);
}
public boolean equals(MapType mt, Value v)
@@ -184,7 +189,7 @@ public abstract class Maps
{
Map.Entry<ByteBuffer, ByteBuffer> thisEntry = thisIter.next();
Map.Entry<ByteBuffer, ByteBuffer> thatEntry = thatIter.next();
- if (mt.keys.compare(thisEntry.getKey(), thatEntry.getKey()) != 0 || mt.values.compare(thisEntry.getValue(), thatEntry.getValue()) != 0)
+ if (mt.getKeysType().compare(thisEntry.getKey(), thatEntry.getKey()) != 0 || mt.getValuesType().compare(thisEntry.getValue(), thatEntry.getValue()) != 0)
return false;
}
@@ -266,9 +271,12 @@ public abstract class Maps
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
- // delete + put
- CellName name = cf.getComparator().create(prefix, column);
- cf.addAtom(params.makeTombstoneForOverwrite(name.slice()));
+ if (column.type.isMultiCell())
+ {
+ // delete + put
+ CellName name = cf.getComparator().create(prefix, column);
+ cf.addAtom(params.makeTombstoneForOverwrite(name.slice()));
+ }
Putter.doPut(t, cf, prefix, column, params);
}
}
@@ -292,6 +300,7 @@ public abstract class Maps
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
+ assert column.type.isMultiCell() : "Attempted to set a value for a single key on a frozen map";
ByteBuffer key = k.bindAndGet(params.options);
ByteBuffer value = t.bindAndGet(params.options);
if (key == null)
@@ -325,21 +334,33 @@ public abstract class Maps
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
+ assert column.type.isMultiCell() : "Attempted to add items to a frozen map";
doPut(t, cf, prefix, column, params);
}
static void doPut(Term t, ColumnFamily cf, Composite prefix, ColumnDefinition column, UpdateParameters params) throws InvalidRequestException
{
Term.Terminal value = t.bind(params.options);
- if (value == null)
- return;
- assert value instanceof Maps.Value;
-
- Map<ByteBuffer, ByteBuffer> toAdd = ((Maps.Value)value).map;
- for (Map.Entry<ByteBuffer, ByteBuffer> entry : toAdd.entrySet())
+ Maps.Value mapValue = (Maps.Value) value;
+ if (column.type.isMultiCell())
+ {
+ if (value == null)
+ return;
+
+ for (Map.Entry<ByteBuffer, ByteBuffer> entry : mapValue.map.entrySet())
+ {
+ CellName cellName = cf.getComparator().create(prefix, column, entry.getKey());
+ cf.addColumn(params.makeColumn(cellName, entry.getValue()));
+ }
+ }
+ else
{
- CellName cellName = cf.getComparator().create(prefix, column, entry.getKey());
- cf.addColumn(params.makeColumn(cellName, entry.getValue()));
+ // for frozen maps, we're overwriting the whole cell
+ CellName cellName = cf.getComparator().create(prefix, column);
+ if (value == null)
+ cf.addAtom(params.makeTombstone(cellName));
+ else
+ cf.addColumn(params.makeColumn(cellName, mapValue.getWithProtocolVersion(Server.CURRENT_VERSION)));
}
}
}
@@ -353,6 +374,7 @@ public abstract class Maps
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
+ assert column.type.isMultiCell() : "Attempted to delete a single key in a frozen map";
Term.Terminal key = t.bind(params.options);
if (key == null)
throw new InvalidRequestException("Invalid null map key");
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/Operation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Operation.java b/src/java/org/apache/cassandra/cql3/Operation.java
index 32b6a12..816acb2 100644
--- a/src/java/org/apache/cassandra/cql3/Operation.java
+++ b/src/java/org/apache/cassandra/cql3/Operation.java
@@ -163,7 +163,7 @@ public abstract class Operation
if (receiver.type instanceof CounterColumnType)
throw new InvalidRequestException(String.format("Cannot set the value of counter column %s (counters can only be incremented/decremented, not set)", receiver.name));
- if (!(receiver.type instanceof CollectionType))
+ if (!(receiver.type.isCollection()))
return new Constants.Setter(receiver, v);
switch (((CollectionType)receiver.type).kind)
@@ -206,6 +206,8 @@ public abstract class Operation
{
if (!(receiver.type instanceof CollectionType))
throw new InvalidRequestException(String.format("Invalid operation (%s) for non collection column %s", toString(receiver), receiver.name));
+ else if (!(receiver.type.isMultiCell()))
+ throw new InvalidRequestException(String.format("Invalid operation (%s) for frozen collection column %s", toString(receiver), receiver.name));
switch (((CollectionType)receiver.type).kind)
{
@@ -255,6 +257,8 @@ public abstract class Operation
throw new InvalidRequestException(String.format("Invalid operation (%s) for non counter column %s", toString(receiver), receiver.name));
return new Constants.Adder(receiver, v);
}
+ else if (!(receiver.type.isMultiCell()))
+ throw new InvalidRequestException(String.format("Invalid operation (%s) for frozen collection column %s", toString(receiver), receiver.name));
switch (((CollectionType)receiver.type).kind)
{
@@ -296,6 +300,8 @@ public abstract class Operation
throw new InvalidRequestException(String.format("Invalid operation (%s) for non counter column %s", toString(receiver), receiver.name));
return new Constants.Substracter(receiver, value.prepare(keyspace, receiver));
}
+ else if (!(receiver.type.isMultiCell()))
+ throw new InvalidRequestException(String.format("Invalid operation (%s) for frozen collection column %s", toString(receiver), receiver.name));
switch (((CollectionType)receiver.type).kind)
{
@@ -308,7 +314,7 @@ public abstract class Operation
ColumnSpecification vr = new ColumnSpecification(receiver.ksName,
receiver.cfName,
receiver.name,
- SetType.getInstance(((MapType)receiver.type).keys));
+ SetType.getInstance(((MapType)receiver.type).getKeysType(), false));
return new Sets.Discarder(receiver, value.prepare(keyspace, vr));
}
throw new AssertionError();
@@ -340,6 +346,8 @@ public abstract class Operation
if (!(receiver.type instanceof ListType))
throw new InvalidRequestException(String.format("Invalid operation (%s) for non list column %s", toString(receiver), receiver.name));
+ else if (!(receiver.type.isMultiCell()))
+ throw new InvalidRequestException(String.format("Invalid operation (%s) for frozen list column %s", toString(receiver), receiver.name));
return new Lists.Prepender(receiver, v);
}
@@ -394,8 +402,10 @@ public abstract class Operation
public Operation prepare(String keyspace, ColumnDefinition receiver) throws InvalidRequestException
{
- if (!(receiver.type instanceof CollectionType))
+ if (!(receiver.type.isCollection()))
throw new InvalidRequestException(String.format("Invalid deletion operation for non collection column %s", receiver.name));
+ else if (!(receiver.type.isMultiCell()))
+ throw new InvalidRequestException(String.format("Invalid deletion operation for frozen collection column %s", receiver.name));
switch (((CollectionType)receiver.type).kind)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/Sets.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Sets.java b/src/java/org/apache/cassandra/cql3/Sets.java
index 315d7d3..c5a8e05 100644
--- a/src/java/org/apache/cassandra/cql3/Sets.java
+++ b/src/java/org/apache/cassandra/cql3/Sets.java
@@ -18,15 +18,7 @@
package org.apache.cassandra.cql3;
import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
+import java.util.*;
import com.google.common.base.Joiner;
@@ -34,11 +26,13 @@ import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.db.ColumnFamily;
import org.apache.cassandra.db.composites.CellName;
import org.apache.cassandra.db.composites.Composite;
+import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.MapType;
import org.apache.cassandra.db.marshal.SetType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.serializers.CollectionSerializer;
import org.apache.cassandra.serializers.MarshalException;
+import org.apache.cassandra.transport.Server;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FBUtilities;
@@ -51,7 +45,7 @@ public abstract class Sets
public static ColumnSpecification valueSpecOf(ColumnSpecification column)
{
- return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), ((SetType)column.type).elements);
+ return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), ((SetType)column.type).getElementsType());
}
public static class Literal implements Term.Raw
@@ -87,7 +81,7 @@ public abstract class Sets
values.add(t);
}
- DelayedValue value = new DelayedValue(((SetType)receiver.type).elements, values);
+ DelayedValue value = new DelayedValue(((SetType)receiver.type).getElementsType(), values);
return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
}
@@ -97,7 +91,7 @@ public abstract class Sets
{
// We've parsed empty maps as a set literal to break the ambiguity so
// handle that case now
- if (receiver.type instanceof MapType && elements.isEmpty())
+ if ((receiver.type instanceof MapType) && elements.isEmpty())
return;
throw new InvalidRequestException(String.format("Invalid set literal for %s of type %s", receiver.name, receiver.type.asCQL3Type()));
@@ -131,11 +125,11 @@ public abstract class Sets
}
}
- public static class Value extends Term.Terminal
+ public static class Value extends Term.Terminal implements Term.CollectionTerminal
{
- public final Set<ByteBuffer> elements;
+ public final SortedSet<ByteBuffer> elements;
- public Value(Set<ByteBuffer> elements)
+ public Value(SortedSet<ByteBuffer> elements)
{
this.elements = elements;
}
@@ -147,9 +141,9 @@ public abstract class Sets
// Collections have this small hack that validate cannot be called on a serialized object,
// but compose does the validation (so we're fine).
Set<?> s = (Set<?>)type.getSerializer().deserializeForNativeProtocol(value, version);
- Set<ByteBuffer> elements = new LinkedHashSet<ByteBuffer>(s.size());
+ SortedSet<ByteBuffer> elements = new TreeSet<ByteBuffer>(type.getElementsType());
for (Object element : s)
- elements.add(type.elements.decompose(element));
+ elements.add(type.getElementsType().decompose(element));
return new Value(elements);
}
catch (MarshalException e)
@@ -160,7 +154,12 @@ public abstract class Sets
public ByteBuffer get(QueryOptions options)
{
- return CollectionSerializer.pack(new ArrayList<ByteBuffer>(elements), elements.size(), options.getProtocolVersion());
+ return getWithProtocolVersion(options.getProtocolVersion());
+ }
+
+ public ByteBuffer getWithProtocolVersion(int protocolVersion)
+ {
+ return CollectionSerializer.pack(new ArrayList<>(elements), elements.size(), protocolVersion);
}
public boolean equals(SetType st, Value v)
@@ -170,8 +169,9 @@ public abstract class Sets
Iterator<ByteBuffer> thisIter = elements.iterator();
Iterator<ByteBuffer> thatIter = v.elements.iterator();
+ AbstractType elementsType = st.getElementsType();
while (thisIter.hasNext())
- if (st.elements.compare(thisIter.next(), thatIter.next()) != 0)
+ if (elementsType.compare(thisIter.next(), thatIter.next()) != 0)
return false;
return true;
@@ -202,7 +202,7 @@ public abstract class Sets
public Value bind(QueryOptions options) throws InvalidRequestException
{
- Set<ByteBuffer> buffers = new TreeSet<ByteBuffer>(comparator);
+ SortedSet<ByteBuffer> buffers = new TreeSet<>(comparator);
for (Term t : elements)
{
ByteBuffer bytes = t.bindAndGet(options);
@@ -246,9 +246,12 @@ public abstract class Sets
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
- // delete + add
- CellName name = cf.getComparator().create(prefix, column);
- cf.addAtom(params.makeTombstoneForOverwrite(name.slice()));
+ if (column.type.isMultiCell())
+ {
+ // delete + add
+ CellName name = cf.getComparator().create(prefix, column);
+ cf.addAtom(params.makeTombstoneForOverwrite(name.slice()));
+ }
Adder.doAdd(t, cf, prefix, column, params);
}
}
@@ -262,22 +265,35 @@ public abstract class Sets
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
+ assert column.type.isMultiCell() : "Attempted to add items to a frozen set";
+
doAdd(t, cf, prefix, column, params);
}
static void doAdd(Term t, ColumnFamily cf, Composite prefix, ColumnDefinition column, UpdateParameters params) throws InvalidRequestException
{
Term.Terminal value = t.bind(params.options);
- if (value == null)
- return;
-
- assert value instanceof Sets.Value : value;
+ Sets.Value setValue = (Sets.Value)value;
+ if (column.type.isMultiCell())
+ {
+ if (value == null)
+ return;
- Set<ByteBuffer> toAdd = ((Sets.Value)value).elements;
- for (ByteBuffer bb : toAdd)
+ Set<ByteBuffer> toAdd = setValue.elements;
+ for (ByteBuffer bb : toAdd)
+ {
+ CellName cellName = cf.getComparator().create(prefix, column, bb);
+ cf.addColumn(params.makeColumn(cellName, ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ }
+ }
+ else
{
- CellName cellName = cf.getComparator().create(prefix, column, bb);
- cf.addColumn(params.makeColumn(cellName, ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ // for frozen sets, we're overwriting the whole cell
+ CellName cellName = cf.getComparator().create(prefix, column);
+ if (value == null)
+ cf.addAtom(params.makeTombstone(cellName));
+ else
+ cf.addColumn(params.makeColumn(cellName, ((Value) value).getWithProtocolVersion(Server.CURRENT_VERSION)));
}
}
}
@@ -292,6 +308,8 @@ public abstract class Sets
public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
{
+ assert column.type.isMultiCell() : "Attempted to remove items from a frozen set";
+
Term.Terminal value = t.bind(params.options);
if (value == null)
return;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/Term.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Term.java b/src/java/org/apache/cassandra/cql3/Term.java
index e5206c8..1587df1 100644
--- a/src/java/org/apache/cassandra/cql3/Term.java
+++ b/src/java/org/apache/cassandra/cql3/Term.java
@@ -138,6 +138,12 @@ public interface Term
public abstract List<ByteBuffer> getElements();
}
+ public interface CollectionTerminal
+ {
+ /** Gets the value of the collection when serialized with the given protocol version format */
+ public ByteBuffer getWithProtocolVersion(int protocolVersion);
+ }
+
/**
* A non terminal term, i.e. a term that can only be reduce to a byte buffer
* at execution time.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/Tuples.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Tuples.java b/src/java/org/apache/cassandra/cql3/Tuples.java
index 883cc60..4f1f141 100644
--- a/src/java/org/apache/cassandra/cql3/Tuples.java
+++ b/src/java/org/apache/cassandra/cql3/Tuples.java
@@ -248,13 +248,13 @@ public class Tuples
// but the deserialization does the validation (so we're fine).
List<?> l = (List<?>)type.getSerializer().deserializeForNativeProtocol(value, options.getProtocolVersion());
- assert type.elements instanceof TupleType;
- TupleType tupleType = (TupleType) type.elements;
+ assert type.getElementsType() instanceof TupleType;
+ TupleType tupleType = (TupleType) type.getElementsType();
// 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))));
+ elements.add(Arrays.asList(tupleType.split(type.getElementsType().decompose(element))));
return new InValue(elements);
}
catch (MarshalException e)
@@ -337,15 +337,16 @@ public class Tuples
if (i < receivers.size() - 1)
inName.append(",");
- if (receiver.type instanceof CollectionType)
- throw new InvalidRequestException("Collection columns do not support IN relations");
+ if (receiver.type.isCollection() && receiver.type.isMultiCell())
+ throw new InvalidRequestException("Non-frozen 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));
+ return new ColumnSpecification(receivers.get(0).ksName, receivers.get(0).cfName, identifier, ListType.getInstance(type, false));
}
public AbstractMarker prepare(String keyspace, List<? extends ColumnSpecification> receivers) throws InvalidRequestException
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/UntypedResultSet.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/UntypedResultSet.java b/src/java/org/apache/cassandra/cql3/UntypedResultSet.java
index 42d0cb8..fef70fb 100644
--- a/src/java/org/apache/cassandra/cql3/UntypedResultSet.java
+++ b/src/java/org/apache/cassandra/cql3/UntypedResultSet.java
@@ -267,19 +267,19 @@ public abstract class UntypedResultSet implements Iterable<UntypedResultSet.Row>
public <T> Set<T> getSet(String column, AbstractType<T> type)
{
ByteBuffer raw = data.get(column);
- return raw == null ? null : SetType.getInstance(type).compose(raw);
+ return raw == null ? null : SetType.getInstance(type, true).compose(raw);
}
public <T> List<T> getList(String column, AbstractType<T> type)
{
ByteBuffer raw = data.get(column);
- return raw == null ? null : ListType.getInstance(type).compose(raw);
+ return raw == null ? null : ListType.getInstance(type, true).compose(raw);
}
public <K, V> Map<K, V> getMap(String column, AbstractType<K> keyType, AbstractType<V> valueType)
{
ByteBuffer raw = data.get(column);
- return raw == null ? null : MapType.getInstance(keyType, valueType).compose(raw);
+ return raw == null ? null : MapType.getInstance(keyType, valueType, true).compose(raw);
}
public List<ColumnSpecification> getColumns()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/UpdateParameters.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/UpdateParameters.java b/src/java/org/apache/cassandra/cql3/UpdateParameters.java
index 62ec09c..74c3214 100644
--- a/src/java/org/apache/cassandra/cql3/UpdateParameters.java
+++ b/src/java/org/apache/cassandra/cql3/UpdateParameters.java
@@ -97,6 +97,6 @@ public class UpdateParameters
return Collections.emptyList();
CQL3Row row = prefetchedLists.get(rowKey);
- return row == null ? Collections.<Cell>emptyList() : row.getCollection(cql3ColumnName);
+ return row == null ? Collections.<Cell>emptyList() : row.getMultiCellColumn(cql3ColumnName);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/cql3/UserTypes.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/UserTypes.java b/src/java/org/apache/cassandra/cql3/UserTypes.java
index 9d66c16..c92bc49 100644
--- a/src/java/org/apache/cassandra/cql3/UserTypes.java
+++ b/src/java/org/apache/cassandra/cql3/UserTypes.java
@@ -24,6 +24,7 @@ import org.apache.cassandra.db.marshal.CollectionType;
import org.apache.cassandra.db.marshal.UserType;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.transport.Server;
/**
* Static helper methods and classes for user types.
@@ -171,7 +172,7 @@ public abstract class UserTypes
buffers[i] = values.get(i).bindAndGet(options);
// Inside UDT values, we must force the serialization of collections to v3 whatever protocol
// version is in use since we're going to store directly that serialized value.
- if (version < 3 && type.fieldType(i).isCollection() && buffers[i] != null)
+ if (version < Server.VERSION_3 && type.fieldType(i).isCollection() && buffers[i] != null)
buffers[i] = ((CollectionType)type.fieldType(i)).getSerializer().reserializeToV3(buffers[i]);
}
return buffers;