cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tylerho...@apache.org
Subject [1/4] cassandra git commit: Support for frozen collections
Date Tue, 11 Nov 2014 19:33:45 GMT
Repository: cassandra
Updated Branches:
  refs/heads/trunk f2e2862f5 -> fb4356a36


http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/db/marshal/TypeParser.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/TypeParser.java b/src/java/org/apache/cassandra/db/marshal/TypeParser.java
index 1b83180..cdb5679 100644
--- a/src/java/org/apache/cassandra/db/marshal/TypeParser.java
+++ b/src/java/org/apache/cassandra/db/marshal/TypeParser.java
@@ -241,7 +241,7 @@ public class TypeParser
 
     public Map<ByteBuffer, CollectionType> getCollectionsParameters() throws SyntaxException, ConfigurationException
     {
-        Map<ByteBuffer, CollectionType> map = new HashMap<ByteBuffer, CollectionType>();
+        Map<ByteBuffer, CollectionType> map = new HashMap<>();
 
         if (isEOS())
             return map;
@@ -539,25 +539,37 @@ public class TypeParser
      */
     public static String stringifyTypeParameters(List<AbstractType<?>> types)
     {
-        StringBuilder sb = new StringBuilder();
-        sb.append('(').append(StringUtils.join(types, ",")).append(')');
-        return sb.toString();
+        return stringifyTypeParameters(types, false);
+    }
+
+    /**
+     * Helper function to ease the writing of AbstractType.toString() methods.
+     */
+    public static String stringifyTypeParameters(List<AbstractType<?>> types, boolean ignoreFreezing)
+    {
+        StringBuilder sb = new StringBuilder("(");
+        for (int i = 0; i < types.size(); i++)
+        {
+            if (i > 0)
+                sb.append(",");
+            sb.append(types.get(i).toString(ignoreFreezing));
+        }
+        return sb.append(')').toString();
     }
 
-    public static String stringifyCollectionsParameters(Map<ByteBuffer, CollectionType> collections)
+    public static String stringifyCollectionsParameters(Map<ByteBuffer, ? extends CollectionType> collections)
     {
         StringBuilder sb = new StringBuilder();
         sb.append('(');
         boolean first = true;
-        for (Map.Entry<ByteBuffer, CollectionType> entry : collections.entrySet())
+        for (Map.Entry<ByteBuffer, ? extends CollectionType> entry : collections.entrySet())
         {
             if (!first)
-            {
                 sb.append(',');
-            }
+
             first = false;
             sb.append(ByteBufferUtil.bytesToHex(entry.getKey())).append(":");
-            entry.getValue().appendToStringBuilder(sb);
+            sb.append(entry.getValue());
         }
         sb.append(')');
         return sb.toString();
@@ -572,7 +584,9 @@ public class TypeParser
         {
             sb.append(',');
             sb.append(ByteBufferUtil.bytesToHex(columnNames.get(i))).append(":");
-            sb.append(columnTypes.get(i).toString());
+
+            // omit FrozenType(...) from fields because it is currently implicit
+            sb.append(columnTypes.get(i).toString(true));
         }
         sb.append(')');
         return sb.toString();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/db/marshal/UserType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/UserType.java b/src/java/org/apache/cassandra/db/marshal/UserType.java
index 44c208f..180d713 100644
--- a/src/java/org/apache/cassandra/db/marshal/UserType.java
+++ b/src/java/org/apache/cassandra/db/marshal/UserType.java
@@ -61,7 +61,7 @@ public class UserType extends TupleType
         for (Pair<ByteBuffer, AbstractType> p : params.right)
         {
             columnNames.add(p.left);
-            columnTypes.add(p.right);
+            columnTypes.add(p.right.freeze());
         }
         return new UserType(keyspace, name, columnNames, columnTypes);
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/hadoop/pig/CqlStorage.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/hadoop/pig/CqlStorage.java b/src/java/org/apache/cassandra/hadoop/pig/CqlStorage.java
index 7a6be71..2ba4dbf 100644
--- a/src/java/org/apache/cassandra/hadoop/pig/CqlStorage.java
+++ b/src/java/org/apache/cassandra/hadoop/pig/CqlStorage.java
@@ -148,9 +148,9 @@ public class CqlStorage extends AbstractCassandraStorage
         }
         AbstractType elementValidator;
         if (validator instanceof SetType)
-            elementValidator = ((SetType<?>) validator).elements;
+            elementValidator = ((SetType<?>) validator).getElementsType();
         else if (validator instanceof ListType)
-            elementValidator = ((ListType<?>) validator).elements;
+            elementValidator = ((ListType<?>) validator).getElementsType();
         else 
             return;
         
@@ -167,8 +167,8 @@ public class CqlStorage extends AbstractCassandraStorage
     /** set the values of set/list at and after the position of the tuple */
     private void setMapTupleValues(Tuple tuple, int position, Object value, AbstractType<?> validator) throws ExecException
     {
-        AbstractType<?> keyValidator = ((MapType<?, ?>) validator).keys;
-        AbstractType<?> valueValidator = ((MapType<?, ?>) validator).values;
+        AbstractType<?> keyValidator = ((MapType<?, ?>) validator).getKeysType();
+        AbstractType<?> valueValidator = ((MapType<?, ?>) validator).getValuesType();
         
         int i = 0;
         Tuple innerTuple = TupleFactory.getInstance().newTuple(((Map<?,?>) value).size());

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/serializers/CollectionSerializer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/serializers/CollectionSerializer.java b/src/java/org/apache/cassandra/serializers/CollectionSerializer.java
index 2a5e809..29ae2fd 100644
--- a/src/java/org/apache/cassandra/serializers/CollectionSerializer.java
+++ b/src/java/org/apache/cassandra/serializers/CollectionSerializer.java
@@ -19,8 +19,10 @@
 package org.apache.cassandra.serializers;
 
 import java.nio.ByteBuffer;
+import java.util.Collection;
 import java.util.List;
 
+import org.apache.cassandra.transport.Server;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
 public abstract class CollectionSerializer<T> implements TypeSerializer<T>
@@ -35,17 +37,17 @@ public abstract class CollectionSerializer<T> implements TypeSerializer<T>
     {
         List<ByteBuffer> values = serializeValues(value);
         // See deserialize() for why using the protocol v3 variant is the right thing to do.
-        return pack(values, getElementCount(value), 3);
+        return pack(values, getElementCount(value), Server.VERSION_3);
     }
 
     public T deserialize(ByteBuffer bytes)
     {
         // The only cases we serialize/deserialize collections internally (i.e. not for the protocol sake),
         // is:
-        //  1) when collections are in UDT values
+        //  1) when collections are frozen
         //  2) for internal calls.
         // In both case, using the protocol 3 version variant is the right thing to do.
-        return deserializeForNativeProtocol(bytes, 3);
+        return deserializeForNativeProtocol(bytes, Server.VERSION_3);
     }
 
     public ByteBuffer reserializeToV3(ByteBuffer bytes)
@@ -55,11 +57,11 @@ public abstract class CollectionSerializer<T> implements TypeSerializer<T>
 
     public void validate(ByteBuffer bytes) throws MarshalException
     {
-        // Same thing than above
-        validateForNativeProtocol(bytes, 3);
+        // Same thing as above
+        validateForNativeProtocol(bytes, Server.VERSION_3);
     }
 
-    public static ByteBuffer pack(List<ByteBuffer> buffers, int elements, int version)
+    public static ByteBuffer pack(Collection<ByteBuffer> buffers, int elements, int version)
     {
         int size = 0;
         for (ByteBuffer bb : buffers)
@@ -74,7 +76,7 @@ public abstract class CollectionSerializer<T> implements TypeSerializer<T>
 
     protected static void writeCollectionSize(ByteBuffer output, int elements, int version)
     {
-        if (version >= 3)
+        if (version >= Server.VERSION_3)
             output.putInt(elements);
         else
             output.putShort((short)elements);
@@ -82,12 +84,12 @@ public abstract class CollectionSerializer<T> implements TypeSerializer<T>
 
     public static int readCollectionSize(ByteBuffer input, int version)
     {
-        return version >= 3 ? input.getInt() : ByteBufferUtil.readShortLength(input);
+        return version >= Server.VERSION_3 ? input.getInt() : ByteBufferUtil.readShortLength(input);
     }
 
     protected static int sizeOfCollectionSize(int elements, int version)
     {
-        return version >= 3 ? 4 : 2;
+        return version >= Server.VERSION_3 ? 4 : 2;
     }
 
     protected static void writeValue(ByteBuffer output, ByteBuffer value, int version)
@@ -113,7 +115,7 @@ public abstract class CollectionSerializer<T> implements TypeSerializer<T>
 
     public static ByteBuffer readValue(ByteBuffer input, int version)
     {
-        if (version >= 3)
+        if (version >= Server.VERSION_3)
         {
             int size = input.getInt();
             if (size < 0)
@@ -129,7 +131,7 @@ public abstract class CollectionSerializer<T> implements TypeSerializer<T>
 
     protected static int sizeOfValue(ByteBuffer value, int version)
     {
-        if (version >= 3)
+        if (version >= Server.VERSION_3)
         {
             return value == null ? 4 : 4 + value.remaining();
         }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/serializers/ListSerializer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/serializers/ListSerializer.java b/src/java/org/apache/cassandra/serializers/ListSerializer.java
index 7387e1b..aeee2b9 100644
--- a/src/java/org/apache/cassandra/serializers/ListSerializer.java
+++ b/src/java/org/apache/cassandra/serializers/ListSerializer.java
@@ -18,12 +18,12 @@
 
 package org.apache.cassandra.serializers;
 
+import org.apache.cassandra.transport.Server;
+
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.util.*;
 
-import org.apache.cassandra.utils.ByteBufferUtil;
-
 public class ListSerializer<T> extends CollectionSerializer<List<T>>
 {
     // interning instances
@@ -111,6 +111,34 @@ public class ListSerializer<T> extends CollectionSerializer<List<T>>
         }
     }
 
+    /**
+     * Returns the element at the given index in a list.
+     * @param serializedList a serialized list
+     * @param index the index to get
+     * @return the serialized element at the given index, or null if the index exceeds the list size
+     */
+    public ByteBuffer getElement(ByteBuffer serializedList, int index)
+    {
+        try
+        {
+            ByteBuffer input = serializedList.duplicate();
+            int n = readCollectionSize(input, Server.VERSION_3);
+            if (n <= index)
+                return null;
+
+            for (int i = 0; i < index; i++)
+            {
+                int length = input.getInt();
+                input.position(input.position() + length);
+            }
+            return readValue(input, Server.VERSION_3);
+        }
+        catch (BufferUnderflowException e)
+        {
+            throw new MarshalException("Not enough bytes to read a list");
+        }
+    }
+
     public String toString(List<T> value)
     {
         StringBuilder sb = new StringBuilder();
@@ -118,13 +146,9 @@ public class ListSerializer<T> extends CollectionSerializer<List<T>>
         for (T element : value)
         {
             if (isFirst)
-            {
                 isFirst = false;
-            }
             else
-            {
                 sb.append("; ");
-            }
             sb.append(elements.toString(element));
         }
         return sb.toString();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/serializers/MapSerializer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/serializers/MapSerializer.java b/src/java/org/apache/cassandra/serializers/MapSerializer.java
index dadadd0..bc8e509 100644
--- a/src/java/org/apache/cassandra/serializers/MapSerializer.java
+++ b/src/java/org/apache/cassandra/serializers/MapSerializer.java
@@ -22,6 +22,8 @@ import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.util.*;
 
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.transport.Server;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.Pair;
 
@@ -114,6 +116,38 @@ public class MapSerializer<K, V> extends CollectionSerializer<Map<K, V>>
         }
     }
 
+    /**
+     * Given a serialized map, gets the value associated with a given key.
+     * @param serializedMap a serialized map
+     * @param serializedKey a serialized key
+     * @param keyType the key type for the map
+     * @return the value associated with the key if one exists, null otherwise
+     */
+    public ByteBuffer getSerializedValue(ByteBuffer serializedMap, ByteBuffer serializedKey, AbstractType keyType)
+    {
+        try
+        {
+            ByteBuffer input = serializedMap.duplicate();
+            int n = readCollectionSize(input, Server.VERSION_3);
+            for (int i = 0; i < n; i++)
+            {
+                ByteBuffer kbb = readValue(input, Server.VERSION_3);
+                ByteBuffer vbb = readValue(input, Server.VERSION_3);
+                int comparison = keyType.compare(kbb, serializedKey);
+                if (comparison == 0)
+                    return vbb;
+                else if (comparison > 0)
+                    // since the map is in sorted order, we know we've gone too far and the element doesn't exist
+                    return null;
+            }
+            return null;
+        }
+        catch (BufferUnderflowException e)
+        {
+            throw new MarshalException("Not enough bytes to read a map");
+        }
+    }
+
     public String toString(Map<K, V> value)
     {
         StringBuilder sb = new StringBuilder();
@@ -121,13 +155,9 @@ public class MapSerializer<K, V> extends CollectionSerializer<Map<K, V>>
         for (Map.Entry<K, V> element : value.entrySet())
         {
             if (isFirst)
-            {
                 isFirst = false;
-            }
             else
-            {
                 sb.append("; ");
-            }
             sb.append('(');
             sb.append(keys.toString(element.getKey()));
             sb.append(", ");

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/src/java/org/apache/cassandra/transport/DataType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/transport/DataType.java b/src/java/org/apache/cassandra/transport/DataType.java
index a45d7ce..0ea353a 100644
--- a/src/java/org/apache/cassandra/transport/DataType.java
+++ b/src/java/org/apache/cassandra/transport/DataType.java
@@ -214,18 +214,18 @@ public enum DataType implements OptionCodec.Codecable<DataType>
             {
                 if (type instanceof ListType)
                 {
-                    return Pair.<DataType, Object>create(LIST, ((ListType)type).elements);
+                    return Pair.<DataType, Object>create(LIST, ((ListType)type).getElementsType());
                 }
                 else if (type instanceof MapType)
                 {
                     MapType mt = (MapType)type;
-                    return Pair.<DataType, Object>create(MAP, Arrays.asList(mt.keys, mt.values));
+                    return Pair.<DataType, Object>create(MAP, Arrays.asList(mt.getKeysType(), mt.getValuesType()));
                 }
-                else
+                else if (type instanceof SetType)
                 {
-                    assert type instanceof SetType;
-                    return Pair.<DataType, Object>create(SET, ((SetType)type).elements);
+                    return Pair.<DataType, Object>create(SET, ((SetType)type).getElementsType());
                 }
+                throw new AssertionError();
             }
 
             if (type instanceof UserType && version >= 3)
@@ -251,12 +251,12 @@ public enum DataType implements OptionCodec.Codecable<DataType>
                 case CUSTOM:
                     return TypeParser.parse((String)entry.right);
                 case LIST:
-                    return ListType.getInstance((AbstractType)entry.right);
+                    return ListType.getInstance((AbstractType)entry.right, true);
                 case SET:
-                    return SetType.getInstance((AbstractType)entry.right);
+                    return SetType.getInstance((AbstractType)entry.right, true);
                 case MAP:
                     List<AbstractType> l = (List<AbstractType>)entry.right;
-                    return MapType.getInstance(l.get(0), l.get(1));
+                    return MapType.getInstance(l.get(0), l.get(1), true);
                 case UDT:
                     return (AbstractType)entry.right;
                 case TUPLE:

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/test/unit/org/apache/cassandra/cql3/CQLTester.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/CQLTester.java b/test/unit/org/apache/cassandra/cql3/CQLTester.java
index 6e4a5a9..aacfb4b 100644
--- a/test/unit/org/apache/cassandra/cql3/CQLTester.java
+++ b/test/unit/org/apache/cassandra/cql3/CQLTester.java
@@ -37,7 +37,6 @@ import org.slf4j.LoggerFactory;
 import org.apache.cassandra.SchemaLoader;
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.Schema;
-import org.apache.cassandra.db.ConsistencyLevel;
 import org.apache.cassandra.db.Directories;
 import org.apache.cassandra.db.Keyspace;
 import org.apache.cassandra.db.marshal.*;
@@ -45,7 +44,6 @@ import org.apache.cassandra.exceptions.*;
 import org.apache.cassandra.io.util.FileUtils;
 import org.apache.cassandra.serializers.TypeSerializer;
 import org.apache.cassandra.service.StorageService;
-import org.apache.cassandra.utils.ByteBufferUtil;
 
 /**
  * Base class for CQL tests.
@@ -96,10 +94,10 @@ public abstract class CQLTester
             {
                 try
                 {
-                    schemaChange(String.format("DROP TABLE %s.%s", KEYSPACE, tableToDrop));
+                    schemaChange(String.format("DROP TABLE IF EXISTS %s.%s", KEYSPACE, tableToDrop));
 
                     for (String typeName : typesToDrop)
-                        schemaChange(String.format("DROP TYPE %s.%s", KEYSPACE, typeName));
+                        schemaChange(String.format("DROP TYPE IF EXISTS %s.%s", KEYSPACE, typeName));
 
                     // Dropping doesn't delete the sstables. It's not a huge deal but it's cleaner to cleanup after us
                     // Thas said, we shouldn't delete blindly before the SSTableDeletingTask for the table we drop
@@ -186,6 +184,21 @@ public abstract class CQLTester
         schemaChange(fullQuery);
     }
 
+    protected void createTableMayThrow(String query) throws Throwable
+    {
+        currentTable = "table_" + seqNumber.getAndIncrement();
+        String fullQuery = String.format(query, KEYSPACE + "." + currentTable);
+        logger.info(fullQuery);
+        try
+        {
+            QueryProcessor.executeOnceInternal(fullQuery);
+        }
+        catch (RuntimeException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
     protected void alterTable(String query)
     {
         String fullQuery = String.format(query, KEYSPACE + "." + currentTable);
@@ -193,6 +206,20 @@ public abstract class CQLTester
         schemaChange(fullQuery);
     }
 
+    protected void alterTableMayThrow(String query) throws Throwable
+    {
+        String fullQuery = String.format(query, KEYSPACE + "." + currentTable);
+        logger.info(fullQuery);
+        try
+        {
+            QueryProcessor.executeOnceInternal(fullQuery);
+        }
+        catch (RuntimeException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
     protected void createIndex(String query)
     {
         String fullQuery = String.format(query, KEYSPACE + "." + currentTable);
@@ -200,6 +227,20 @@ public abstract class CQLTester
         schemaChange(fullQuery);
     }
 
+    protected void createIndexMayThrow(String query) throws Throwable
+    {
+        String fullQuery = String.format(query, KEYSPACE + "." + currentTable);
+        logger.info(fullQuery);
+        try
+        {
+            QueryProcessor.executeOnceInternal(fullQuery);
+        }
+        catch (RuntimeException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
     private static void schemaChange(String query)
     {
         try
@@ -262,7 +303,7 @@ public abstract class CQLTester
         int i = 0;
         while (iter.hasNext() && i < rows.length)
         {
-            Object[] expected = rows[i++];
+            Object[] expected = rows[i];
             UntypedResultSet.Row actual = iter.next();
 
             Assert.assertEquals(String.format("Invalid number of (expected) values provided for row %d", i), meta.size(), expected.length);
@@ -278,6 +319,7 @@ public abstract class CQLTester
                     Assert.fail(String.format("Invalid value for row %d column %d (%s of type %s), expected <%s> but got <%s>",
                                               i, j, column.name, column.type.asCQL3Type(), formatValue(expectedByteValue, column.type), formatValue(actualValue, column.type)));
             }
+            i++;
         }
 
         if (iter.hasNext())
@@ -311,6 +353,11 @@ public abstract class CQLTester
 
     protected void assertInvalid(String query, Object... values) throws Throwable
     {
+        assertInvalidMessage(null, query, values);
+    }
+
+    protected void assertInvalidMessage(String errorMessage, String query, Object... values) throws Throwable
+    {
         try
         {
             execute(query, values);
@@ -321,7 +368,11 @@ public abstract class CQLTester
         }
         catch (InvalidRequestException e)
         {
-            // This is what we expect
+            if (errorMessage != null)
+            {
+                Assert.assertTrue("Expected error message to contain '" + errorMessage + "', but got '" + e.getMessage() + "'",
+                        e.getMessage().contains(errorMessage));
+            }
         }
     }
 
@@ -401,7 +452,15 @@ public abstract class CQLTester
                 continue;
             }
 
-            buffers[i] = typeFor(value).decompose(serializeTuples(value));
+            try
+            {
+                buffers[i] = typeFor(value).decompose(serializeTuples(value));
+            }
+            catch (Exception ex)
+            {
+                logger.info("Error serializing query parameter {}:", value, ex);
+                throw ex;
+            }
         }
         return buffers;
     }
@@ -613,14 +672,14 @@ public abstract class CQLTester
         {
             List l = (List)value;
             AbstractType elt = l.isEmpty() ? BytesType.instance : typeFor(l.get(0));
-            return ListType.getInstance(elt);
+            return ListType.getInstance(elt, true);
         }
 
         if (value instanceof Set)
         {
             Set s = (Set)value;
             AbstractType elt = s.isEmpty() ? BytesType.instance : typeFor(s.iterator().next());
-            return SetType.getInstance(elt);
+            return SetType.getInstance(elt, true);
         }
 
         if (value instanceof Map)
@@ -638,7 +697,7 @@ public abstract class CQLTester
                 keys = typeFor(entry.getKey());
                 values = typeFor(entry.getValue());
             }
-            return MapType.getInstance(keys, values);
+            return MapType.getInstance(keys, values, true);
         }
 
         throw new IllegalArgumentException("Unsupported value type (value is " + value + ")");
@@ -674,5 +733,10 @@ public abstract class CQLTester
             sb.append(")");
             return sb.toString();
         }
+
+        public String toString()
+        {
+            return "TupleValue" + toCQLString();
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/test/unit/org/apache/cassandra/cql3/ColumnConditionTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/ColumnConditionTest.java b/test/unit/org/apache/cassandra/cql3/ColumnConditionTest.java
index 205babc..3b1a826 100644
--- a/test/unit/org/apache/cassandra/cql3/ColumnConditionTest.java
+++ b/test/unit/org/apache/cassandra/cql3/ColumnConditionTest.java
@@ -154,9 +154,9 @@ public class ColumnConditionTest
     {
         CFMetaData cfm = CFMetaData.compile("create table foo(a int PRIMARY KEY, b int, c list<int>)", "ks");
         Map<ByteBuffer, CollectionType> typeMap = new HashMap<>();
-        typeMap.put(ByteBufferUtil.bytes("c"), ListType.getInstance(Int32Type.instance));
+        typeMap.put(ByteBufferUtil.bytes("c"), ListType.getInstance(Int32Type.instance, true));
         CompoundSparseCellNameType.WithCollection nameType = new CompoundSparseCellNameType.WithCollection(Collections.EMPTY_LIST, ColumnToCollectionType.getInstance(typeMap));
-        ColumnDefinition definition = new ColumnDefinition(cfm, ByteBufferUtil.bytes("c"), ListType.getInstance(Int32Type.instance), 0, ColumnDefinition.Kind.REGULAR);
+        ColumnDefinition definition = new ColumnDefinition(cfm, ByteBufferUtil.bytes("c"), ListType.getInstance(Int32Type.instance, true), 0, ColumnDefinition.Kind.REGULAR);
 
         List<Cell> cells = new ArrayList<>(columnValues.size());
         if (columnValues != null)
@@ -169,14 +169,14 @@ public class ColumnConditionTest
             };
         }
 
-        return bound.listAppliesTo(ListType.getInstance(Int32Type.instance), cells == null ? null : cells.iterator(), conditionValues, bound.operator);
+        return bound.listAppliesTo(ListType.getInstance(Int32Type.instance, true), cells == null ? null : cells.iterator(), conditionValues, bound.operator);
     }
 
     @Test
     // sets use the same check as lists
     public void testListCollectionBoundAppliesTo() throws InvalidRequestException
     {
-        ColumnDefinition definition = new ColumnDefinition("ks", "cf", new ColumnIdentifier("c", true), ListType.getInstance(Int32Type.instance), null, null, null, null, null);
+        ColumnDefinition definition = new ColumnDefinition("ks", "cf", new ColumnIdentifier("c", true), ListType.getInstance(Int32Type.instance, true), null, null, null, null, null);
 
         // EQ
         ColumnCondition condition = ColumnCondition.condition(definition, null, new Lists.Value(Arrays.asList(ONE)), Operator.EQ);
@@ -275,9 +275,9 @@ public class ColumnConditionTest
         assertTrue(listAppliesTo(bound, list(ByteBufferUtil.EMPTY_BYTE_BUFFER), list(ByteBufferUtil.EMPTY_BYTE_BUFFER)));
     }
 
-    private static Set<ByteBuffer> set(ByteBuffer... values)
+    private static SortedSet<ByteBuffer> set(ByteBuffer... values)
     {
-        Set results = new HashSet<ByteBuffer>(values.length);
+        SortedSet<ByteBuffer> results = new TreeSet<>(Int32Type.instance);
         results.addAll(Arrays.asList(values));
         return results;
     }
@@ -286,9 +286,9 @@ public class ColumnConditionTest
     {
         CFMetaData cfm = CFMetaData.compile("create table foo(a int PRIMARY KEY, b int, c set<int>)", "ks");
         Map<ByteBuffer, CollectionType> typeMap = new HashMap<>();
-        typeMap.put(ByteBufferUtil.bytes("c"), SetType.getInstance(Int32Type.instance));
+        typeMap.put(ByteBufferUtil.bytes("c"), SetType.getInstance(Int32Type.instance, true));
         CompoundSparseCellNameType.WithCollection nameType = new CompoundSparseCellNameType.WithCollection(Collections.EMPTY_LIST, ColumnToCollectionType.getInstance(typeMap));
-        ColumnDefinition definition = new ColumnDefinition(cfm, ByteBufferUtil.bytes("c"), SetType.getInstance(Int32Type.instance), 0, ColumnDefinition.Kind.REGULAR);
+        ColumnDefinition definition = new ColumnDefinition(cfm, ByteBufferUtil.bytes("c"), SetType.getInstance(Int32Type.instance, true), 0, ColumnDefinition.Kind.REGULAR);
 
         List<Cell> cells = new ArrayList<>(columnValues.size());
         if (columnValues != null)
@@ -300,13 +300,13 @@ public class ColumnConditionTest
             };
         }
 
-        return bound.setAppliesTo(SetType.getInstance(Int32Type.instance), cells == null ? null : cells.iterator(), conditionValues, bound.operator);
+        return bound.setAppliesTo(SetType.getInstance(Int32Type.instance, true), cells == null ? null : cells.iterator(), conditionValues, bound.operator);
     }
 
     @Test
     public void testSetCollectionBoundAppliesTo() throws InvalidRequestException
     {
-        ColumnDefinition definition = new ColumnDefinition("ks", "cf", new ColumnIdentifier("c", true), SetType.getInstance(Int32Type.instance), null, null, null, null, null);
+        ColumnDefinition definition = new ColumnDefinition("ks", "cf", new ColumnIdentifier("c", true), SetType.getInstance(Int32Type.instance, true), null, null, null, null, null);
 
         // EQ
         ColumnCondition condition = ColumnCondition.condition(definition, null, new Sets.Value(set(ONE)), Operator.EQ);
@@ -419,9 +419,9 @@ public class ColumnConditionTest
     {
         CFMetaData cfm = CFMetaData.compile("create table foo(a int PRIMARY KEY, b map<int, int>)", "ks");
         Map<ByteBuffer, CollectionType> typeMap = new HashMap<>();
-        typeMap.put(ByteBufferUtil.bytes("b"), MapType.getInstance(Int32Type.instance, Int32Type.instance));
+        typeMap.put(ByteBufferUtil.bytes("b"), MapType.getInstance(Int32Type.instance, Int32Type.instance, true));
         CompoundSparseCellNameType.WithCollection nameType = new CompoundSparseCellNameType.WithCollection(Collections.EMPTY_LIST, ColumnToCollectionType.getInstance(typeMap));
-        ColumnDefinition definition = new ColumnDefinition(cfm, ByteBufferUtil.bytes("b"), MapType.getInstance(Int32Type.instance, Int32Type.instance), 0, ColumnDefinition.Kind.REGULAR);
+        ColumnDefinition definition = new ColumnDefinition(cfm, ByteBufferUtil.bytes("b"), MapType.getInstance(Int32Type.instance, Int32Type.instance, true), 0, ColumnDefinition.Kind.REGULAR);
 
         List<Cell> cells = new ArrayList<>(columnValues.size());
         if (columnValues != null)
@@ -430,13 +430,13 @@ public class ColumnConditionTest
                 cells.add(new BufferCell(nameType.create(Composites.EMPTY, definition, entry.getKey()), entry.getValue()));
         }
 
-        return bound.mapAppliesTo(MapType.getInstance(Int32Type.instance, Int32Type.instance), cells.iterator(), conditionValues, bound.operator);
+        return bound.mapAppliesTo(MapType.getInstance(Int32Type.instance, Int32Type.instance, true), cells.iterator(), conditionValues, bound.operator);
     }
 
     @Test
     public void testMapCollectionBoundIsSatisfiedByValue() throws InvalidRequestException
     {
-        ColumnDefinition definition = new ColumnDefinition("ks", "cf", new ColumnIdentifier("b", true), MapType.getInstance(Int32Type.instance, Int32Type.instance), null, null, null, null, null);
+        ColumnDefinition definition = new ColumnDefinition("ks", "cf", new ColumnIdentifier("b", true), MapType.getInstance(Int32Type.instance, Int32Type.instance, true), null, null, null, null, null);
 
         Map<ByteBuffer, ByteBuffer> placeholderMap = new TreeMap<>();
         placeholderMap.put(ONE, ONE);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java b/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java
new file mode 100644
index 0000000..203adae
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/FrozenCollectionsTest.java
@@ -0,0 +1,791 @@
+/*
+ * 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.*;
+import org.apache.cassandra.exceptions.ConfigurationException;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.exceptions.SyntaxException;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class FrozenCollectionsTest extends CQLTester
+{
+    @Test
+    public void testPartitionKeyUsage() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k frozen<set<int>> PRIMARY KEY, v int)");
+
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(), 1);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(1, 2, 3), 1);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(4, 5, 6), 0);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(7, 8, 9), 0);
+
+        // overwrite with an update
+        execute("UPDATE %s SET v=? WHERE k=?", 0, set());
+        execute("UPDATE %s SET v=? WHERE k=?", 0, set(1, 2, 3));
+
+        assertRows(execute("SELECT * FROM %s"),
+            row(set(), 0),
+            row(set(1, 2, 3), 0),
+            row(set(4, 5, 6), 0),
+            row(set(7, 8, 9), 0)
+        );
+
+        assertRows(execute("SELECT k FROM %s"),
+            row(set()),
+            row(set(1, 2, 3)),
+            row(set(4, 5, 6)),
+            row(set(7, 8, 9))
+        );
+
+        assertRows(execute("SELECT * FROM %s LIMIT 2"),
+                row(set(), 0),
+                row(set(1, 2, 3), 0)
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE k=?", set(4, 5, 6)),
+            row(set(4, 5, 6), 0)
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE k=?", set()),
+                row(set(), 0)
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE k IN ?", list(set(4, 5, 6), set())),
+                row(set(4, 5, 6), 0),
+                row(set(), 0)
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE token(k) >= token(?)", set(4, 5, 6)),
+                row(set(4, 5, 6), 0),
+                row(set(7, 8, 9), 0)
+        );
+
+        assertInvalid("INSERT INTO %s (k, v) VALUES (null, 0)");
+
+        execute("DELETE FROM %s WHERE k=?", set());
+        execute("DELETE FROM %s WHERE k=?", set(4, 5, 6));
+        assertRows(execute("SELECT * FROM %s"),
+            row(set(1, 2, 3), 0),
+            row(set(7, 8, 9), 0)
+        );
+    }
+
+    @Test
+    public void testNestedPartitionKeyUsage() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k frozen<map<set<int>, list<int>>> PRIMARY KEY, v int)");
+
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", map(), 1);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", map(set(), list(1, 2, 3)), 0);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", map(set(1, 2, 3), list(1, 2, 3)), 1);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", map(set(4, 5, 6), list(1, 2, 3)), 0);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", map(set(7, 8, 9), list(1, 2, 3)), 0);
+
+        // overwrite with an update
+        execute("UPDATE %s SET v=? WHERE k=?", 0, map());
+        execute("UPDATE %s SET v=? WHERE k=?", 0, map(set(1, 2, 3), list(1, 2, 3)));
+
+        assertRows(execute("SELECT * FROM %s"),
+            row(map(), 0),
+            row(map(set(), list(1, 2, 3)), 0),
+            row(map(set(1, 2, 3), list(1, 2, 3)), 0),
+            row(map(set(4, 5, 6), list(1, 2, 3)), 0),
+            row(map(set(7, 8, 9), list(1, 2, 3)), 0)
+        );
+
+        assertRows(execute("SELECT k FROM %s"),
+            row(map()),
+            row(map(set(), list(1, 2, 3))),
+            row(map(set(1, 2, 3), list(1, 2, 3))),
+            row(map(set(4, 5, 6), list(1, 2, 3))),
+            row(map(set(7, 8, 9), list(1, 2, 3)))
+        );
+
+        assertRows(execute("SELECT * FROM %s LIMIT 3"),
+            row(map(), 0),
+            row(map(set(), list(1, 2, 3)), 0),
+            row(map(set(1, 2, 3), list(1, 2, 3)), 0)
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE k=?", map(set(4, 5, 6), list(1, 2, 3))),
+            row(map(set(4, 5, 6), list(1, 2, 3)), 0)
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE k=?", map()),
+                row(map(), 0)
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE k=?", map(set(), list(1, 2, 3))),
+                row(map(set(), list(1, 2, 3)), 0)
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE k IN ?", list(map(set(4, 5, 6), list(1, 2, 3)), map(), map(set(), list(1, 2, 3)))),
+            row(map(set(4, 5, 6), list(1, 2, 3)), 0),
+            row(map(), 0),
+            row(map(set(), list(1, 2, 3)), 0)
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE token(k) >= token(?)", map(set(4, 5, 6), list(1, 2, 3))),
+            row(map(set(4, 5, 6), list(1, 2, 3)), 0),
+            row(map(set(7, 8, 9), list(1, 2, 3)), 0)
+        );
+
+        execute("DELETE FROM %s WHERE k=?", map());
+        execute("DELETE FROM %s WHERE k=?", map(set(), list(1, 2, 3)));
+        execute("DELETE FROM %s WHERE k=?", map(set(4, 5, 6), list(1, 2, 3)));
+        assertRows(execute("SELECT * FROM %s"),
+            row(map(set(1, 2, 3), list(1, 2, 3)), 0),
+            row(map(set(7, 8, 9), list(1, 2, 3)), 0)
+        );
+
+    }
+
+    @Test
+    public void testClusteringKeyUsage() throws Throwable
+    {
+        for (String option : Arrays.asList("", " WITH COMPACT STORAGE"))
+        {
+            createTable("CREATE TABLE %s (a int, b frozen<set<int>>, c int, PRIMARY KEY (a, b))" + option);
+
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(), 1);
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(1, 2, 3), 1);
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(4, 5, 6), 0);
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(7, 8, 9), 0);
+
+            // overwrite with an update
+            execute("UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, set());
+            execute("UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, set(1, 2, 3));
+
+            assertRows(execute("SELECT * FROM %s"),
+                row(0, set(), 0),
+                row(0, set(1, 2, 3), 0),
+                row(0, set(4, 5, 6), 0),
+                row(0, set(7, 8, 9), 0)
+            );
+
+            assertRows(execute("SELECT b FROM %s"),
+                row(set()),
+                row(set(1, 2, 3)),
+                row(set(4, 5, 6)),
+                row(set(7, 8, 9))
+            );
+
+            assertRows(execute("SELECT * FROM %s LIMIT 2"),
+                row(0, set(), 0),
+                row(0, set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, set(4, 5, 6)),
+                row(0, set(4, 5, 6), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, set()),
+                row(0, set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b IN ?", 0, list(set(4, 5, 6), set())),
+                row(0, set(), 0),
+                row(0, set(4, 5, 6), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ?", 0, set(4, 5, 6)),
+                row(0, set(7, 8, 9), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b >= ?", 0, set(4, 5, 6)),
+                row(0, set(4, 5, 6), 0),
+                row(0, set(7, 8, 9), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b < ?", 0, set(4, 5, 6)),
+                row(0, set(), 0),
+                row(0, set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b <= ?", 0, set(4, 5, 6)),
+                row(0, set(), 0),
+                row(0, set(1, 2, 3), 0),
+                row(0, set(4, 5, 6), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, set(1, 2, 3), set(4, 5, 6)),
+                row(0, set(4, 5, 6), 0)
+            );
+
+            execute("DELETE FROM %s WHERE a=? AND b=?", 0, set());
+            execute("DELETE FROM %s WHERE a=? AND b=?", 0, set(4, 5, 6));
+            assertRows(execute("SELECT * FROM %s"),
+                row(0, set(1, 2, 3), 0),
+                row(0, set(7, 8, 9), 0)
+            );
+        }
+    }
+
+    @Test
+    public void testNestedClusteringKeyUsage() throws Throwable
+    {
+        for (String option : Arrays.asList("", " WITH COMPACT STORAGE"))
+        {
+            createTable("CREATE TABLE %s (a int, b frozen<map<set<int>, list<int>>>, c frozen<set<int>>, d int, PRIMARY KEY (a, b, c))" + option);
+
+            execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(), set(), 0);
+            execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(), list(1, 2, 3)), set(), 0);
+            execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0);
+            execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0);
+            execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0);
+
+            assertRows(execute("SELECT * FROM %s"),
+                row(0, map(), set(), 0),
+                row(0, map(set(), list(1, 2, 3)), set(), 0),
+                row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0),
+                row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0),
+                row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT b FROM %s"),
+                row(map()),
+                row(map(set(), list(1, 2, 3))),
+                row(map(set(1, 2, 3), list(1, 2, 3))),
+                row(map(set(4, 5, 6), list(1, 2, 3))),
+                row(map(set(7, 8, 9), list(1, 2, 3)))
+            );
+
+            assertRows(execute("SELECT c FROM %s"),
+                row(set()),
+                row(set()),
+                row(set(1, 2, 3)),
+                row(set(1, 2, 3)),
+                row(set(1, 2, 3))
+            );
+
+            assertRows(execute("SELECT * FROM %s LIMIT 3"),
+                row(0, map(), set(), 0),
+                row(0, map(set(), list(1, 2, 3)), set(), 0),
+                row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=0 ORDER BY b DESC LIMIT 4"),
+                row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0),
+                row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0),
+                row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0),
+                row(0, map(set(), list(1, 2, 3)), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, map()),
+                row(0, map(), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, map(set(), list(1, 2, 3))),
+                row(0, map(set(), list(1, 2, 3)), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, map(set(1, 2, 3), list(1, 2, 3))),
+                row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(), list(1, 2, 3)), set()),
+                    row(0, map(set(), list(1, 2, 3)), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND (b, c) IN ?", 0, list(tuple(map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3)),
+                                                                                     tuple(map(), set()))),
+                row(0, map(), set(), 0),
+                row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ?", 0, map(set(4, 5, 6), list(1, 2, 3))),
+                row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b >= ?", 0, map(set(4, 5, 6), list(1, 2, 3))),
+                row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0),
+                row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b < ?", 0, map(set(4, 5, 6), list(1, 2, 3))),
+                row(0, map(), set(), 0),
+                row(0, map(set(), list(1, 2, 3)), set(), 0),
+                row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b <= ?", 0, map(set(4, 5, 6), list(1, 2, 3))),
+                row(0, map(), set(), 0),
+                row(0, map(set(), list(1, 2, 3)), set(), 0),
+                row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0),
+                row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, map(set(1, 2, 3), list(1, 2, 3)), map(set(4, 5, 6), list(1, 2, 3))),
+                row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, map(), set());
+            assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(), set()));
+
+            execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(), list(1, 2, 3)), set());
+            assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(), list(1, 2, 3)), set()));
+
+            execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3));
+            assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3)));
+
+            assertRows(execute("SELECT * FROM %s"),
+                    row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0),
+                    row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+        }
+    }
+
+    @Test
+    public void testNormalColumnUsage() throws Throwable
+    {
+        for (String option : Arrays.asList("", " WITH COMPACT STORAGE"))
+        {
+            createTable("CREATE TABLE %s (a int PRIMARY KEY, b frozen<map<set<int>, list<int>>>, c frozen<set<int>>)" + option);
+
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, map(), set());
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 1, map(set(), list(99999, 999999, 99999)), set());
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 2, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3));
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 3, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3));
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 4, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3));
+
+            // overwrite with update
+            execute ("UPDATE %s SET b=? WHERE a=?", map(set(), list(1, 2, 3)), 1);
+
+            assertRows(execute("SELECT * FROM %s"),
+                row(0, map(), set()),
+                row(1, map(set(), list(1, 2, 3)), set()),
+                row(2, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3)),
+                row(3, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3)),
+                row(4, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3))
+            );
+
+            assertRows(execute("SELECT b FROM %s"),
+                row(map()),
+                row(map(set(), list(1, 2, 3))),
+                row(map(set(1, 2, 3), list(1, 2, 3))),
+                row(map(set(4, 5, 6), list(1, 2, 3))),
+                row(map(set(7, 8, 9), list(1, 2, 3)))
+            );
+
+            assertRows(execute("SELECT c FROM %s"),
+                row(set()),
+                row(set()),
+                row(set(1, 2, 3)),
+                row(set(1, 2, 3)),
+                row(set(1, 2, 3))
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=?", 3),
+                row(3, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3))
+            );
+
+            execute("UPDATE %s SET b=? WHERE a=?", null, 1);
+            assertRows(execute("SELECT * FROM %s WHERE a=?", 1),
+                row(1, null, set())
+            );
+
+            execute("UPDATE %s SET b=? WHERE a=?", map(), 1);
+            assertRows(execute("SELECT * FROM %s WHERE a=?", 1),
+                row(1, map(), set())
+            );
+
+            execute("UPDATE %s SET c=? WHERE a=?", null, 2);
+            assertRows(execute("SELECT * FROM %s WHERE a=?", 2),
+                row(2, map(set(1, 2, 3), list(1, 2, 3)), null)
+            );
+
+            execute("UPDATE %s SET c=? WHERE a=?", set(), 2);
+            assertRows(execute("SELECT * FROM %s WHERE a=?", 2),
+                    row(2, map(set(1, 2, 3), list(1, 2, 3)), set())
+            );
+
+            execute("DELETE b FROM %s WHERE a=?", 3);
+            assertRows(execute("SELECT * FROM %s WHERE a=?", 3),
+                row(3, null, set(1, 2, 3))
+            );
+
+            execute("DELETE c FROM %s WHERE a=?", 4);
+            assertRows(execute("SELECT * FROM %s WHERE a=?", 4),
+                row(4, map(set(7, 8, 9), list(1, 2, 3)), null)
+            );
+        }
+    }
+
+    @Test
+    public void testStaticColumnUsage() throws Throwable
+    {
+        createTable("CREATE TABLE %s (a int, b int, c frozen<map<set<int>, list<int>>> static, d int, PRIMARY KEY (a, b))");
+        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, map(), 0);
+        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, map(), 0);
+        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 0, map(set(), list(1, 2, 3)), 0);
+        execute("INSERT INTO %s (a, b, d) VALUES (?, ?, ?)", 1, 1, 0);
+        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 0, map(set(1, 2, 3), list(1, 2, 3)), 0);
+
+        assertRows(execute("SELECT * FROM %s"),
+            row(0, 0, map(), 0),
+            row(0, 1, map(), 0),
+            row(1, 0, map(set(), list(1, 2, 3)), 0),
+            row(1, 1, map(set(), list(1, 2, 3)), 0),
+            row(2, 0, map(set(1, 2, 3), list(1, 2, 3)), 0)
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, 1),
+            row(0, 1, map(), 0)
+        );
+
+        execute("DELETE c FROM %s WHERE a=?", 0);
+        assertRows(execute("SELECT * FROM %s"),
+                row(0, 0, null, 0),
+                row(0, 1, null, 0),
+                row(1, 0, map(set(), list(1, 2, 3)), 0),
+                row(1, 1, map(set(), list(1, 2, 3)), 0),
+                row(2, 0, map(set(1, 2, 3), list(1, 2, 3)), 0)
+        );
+
+        execute("DELETE FROM %s WHERE a=?", 0);
+        assertRows(execute("SELECT * FROM %s"),
+                row(1, 0, map(set(), list(1, 2, 3)), 0),
+                row(1, 1, map(set(), list(1, 2, 3)), 0),
+                row(2, 0, map(set(1, 2, 3), list(1, 2, 3)), 0)
+        );
+
+        execute("UPDATE %s SET c=? WHERE a=?", map(set(1, 2, 3), list(1, 2, 3)), 1);
+        assertRows(execute("SELECT * FROM %s"),
+                row(1, 0, map(set(1, 2, 3), list(1, 2, 3)), 0),
+                row(1, 1, map(set(1, 2, 3), list(1, 2, 3)), 0),
+                row(2, 0, map(set(1, 2, 3), list(1, 2, 3)), 0)
+        );
+    }
+
+    private void assertInvalidCreateWithMessage(String createTableStatement, String errorMessage) throws Throwable
+    {
+         try
+        {
+            createTableMayThrow(createTableStatement);
+            Assert.fail("Expected CREATE TABLE statement to error: " + createTableStatement);
+        }
+        catch (InvalidRequestException | ConfigurationException | SyntaxException ex)
+        {
+            Assert.assertTrue("Expected error message to contain '" + errorMessage + "', but got '" + ex.getMessage() + "'",
+                    ex.getMessage().contains(errorMessage));
+        }
+    }
+
+    private void assertInvalidAlterWithMessage(String createTableStatement, String errorMessage) throws Throwable
+    {
+        try
+        {
+            alterTableMayThrow(createTableStatement);
+            Assert.fail("Expected CREATE TABLE statement to error: " + createTableStatement);
+        }
+        catch (InvalidRequestException | ConfigurationException ex)
+        {
+            Assert.assertTrue("Expected error message to contain '" + errorMessage + "', but got '" + ex.getMessage() + "'",
+                    ex.getMessage().contains(errorMessage));
+        }
+    }
+
+    @Test
+    public void testInvalidOperations() throws Throwable
+    {
+        // lists
+        createTable("CREATE TABLE %s (k int PRIMARY KEY, l frozen<list<int>>)");
+        assertInvalid("UPDATE %s SET l[?]=? WHERE k=?", 0, 0, 0);
+        assertInvalid("UPDATE %s SET l = ? + l WHERE k=?", list(0), 0);
+        assertInvalid("UPDATE %s SET l = l + ? WHERE k=?", list(4), 0);
+        assertInvalid("UPDATE %s SET l = l - ? WHERE k=?", list(3), 0);
+        assertInvalid("DELETE l[?] FROM %s WHERE k=?", 0, 0);
+
+        // sets
+        createTable("CREATE TABLE %s (k int PRIMARY KEY, s frozen<set<int>>)");
+        assertInvalid("UPDATE %s SET s = s + ? WHERE k=?", set(0), 0);
+        assertInvalid("UPDATE %s SET s = s - ? WHERE k=?", set(3), 0);
+
+        // maps
+        createTable("CREATE TABLE %s (k int PRIMARY KEY, m frozen<map<int, int>>)");
+        assertInvalid("UPDATE %s SET m[?]=? WHERE k=?", 0, 0, 0);
+        assertInvalid("UPDATE %s SET m = m + ? WHERE k=?", map(4, 4), 0);
+        assertInvalid("DELETE m[?] FROM %s WHERE k=?", 0, 0);
+
+        assertInvalidCreateWithMessage("CREATE TABLE %s (k int PRIMARY KEY, t set<set<int>>)",
+                "Non-frozen collections are not allowed inside collections");
+
+        assertInvalidCreateWithMessage("CREATE TABLE %s (k int PRIMARY KEY, t frozen<set<counter>>)",
+                                       "Counters are not allowed inside collections");
+
+        assertInvalidCreateWithMessage("CREATE TABLE %s (k int PRIMARY KEY, t frozen<text>)",
+                "frozen<> is only allowed on collections, tuples, and user-defined types");
+    }
+
+    @Test
+    public void testAltering() throws Throwable
+    {
+        createTable("CREATE TABLE %s (a int, b frozen<list<int>>, c frozen<list<int>>, PRIMARY KEY (a, b))");
+
+        alterTable("ALTER TABLE %s ALTER c TYPE frozen<list<blob>>");
+
+        assertInvalidAlterWithMessage("ALTER TABLE %s ALTER b TYPE frozen<list<blob>>",
+                                      "types are not order-compatible");
+
+        assertInvalidAlterWithMessage("ALTER TABLE %s ALTER b TYPE list<int>",
+                                      "types are not order-compatible");
+
+        assertInvalidAlterWithMessage("ALTER TABLE %s ALTER c TYPE list<blob>",
+                                      "types are incompatible");
+
+        alterTable("ALTER TABLE %s DROP c");
+        alterTable("ALTER TABLE %s ADD c frozen<set<int>>");
+        assertInvalidAlterWithMessage("ALTER TABLE %s ALTER c TYPE frozen<set<blob>>",
+                                      "types are incompatible");
+
+        alterTable("ALTER TABLE %s DROP c");
+        alterTable("ALTER TABLE %s ADD c frozen<map<int, int>>");
+        assertInvalidAlterWithMessage("ALTER TABLE %s ALTER c TYPE frozen<map<blob, int>>",
+                                      "types are incompatible");
+        alterTable("ALTER TABLE %s ALTER c TYPE frozen<map<int, blob>>");
+    }
+
+    private void assertInvalidIndexCreationWithMessage(String statement, String errorMessage) throws Throwable
+    {
+        try
+        {
+            createIndexMayThrow(statement);
+            Assert.fail("Expected index creation to fail: " + statement);
+        }
+        catch (InvalidRequestException ex)
+        {
+            Assert.assertTrue("Expected error message to contain '" + errorMessage + "', but got '" + ex.getMessage() + "'",
+                              ex.getMessage().contains(errorMessage));
+        }
+    }
+
+    @Test
+    public void testSecondaryIndex() throws Throwable
+    {
+        createTable("CREATE TABLE %s (a frozen<map<int, text>> PRIMARY KEY, b frozen<map<int, text>>)");
+
+        // for now, we don't support indexing values or keys of collections in the primary key
+        assertInvalidIndexCreationWithMessage("CREATE INDEX ON %s (full(a))", "Cannot create secondary index on partition key column");
+        assertInvalidIndexCreationWithMessage("CREATE INDEX ON %s (keys(a))", "Cannot create index on keys of frozen<map> column");
+        assertInvalidIndexCreationWithMessage("CREATE INDEX ON %s (keys(b))", "Cannot create index on keys of frozen<map> column");
+
+        createTable("CREATE TABLE %s (a int, b frozen<list<int>>, c frozen<set<int>>, d frozen<map<int, text>>, PRIMARY KEY (a, b))");
+
+        createIndex("CREATE INDEX ON %s (full(b))");
+        createIndex("CREATE INDEX ON %s (full(c))");
+        createIndex("CREATE INDEX ON %s (full(d))");
+
+        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, list(1, 2, 3), set(1, 2, 3), map(1, "a"));
+        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, list(4, 5, 6), set(1, 2, 3), map(1, "a"));
+        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, list(1, 2, 3), set(4, 5, 6), map(2, "b"));
+        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, list(4, 5, 6), set(4, 5, 6), map(2, "b"));
+
+        // CONTAINS KEY doesn't work on non-maps
+        assertInvalidMessage("Cannot use CONTAINS KEY on non-map column",
+                             "SELECT * FROM %s WHERE b CONTAINS KEY ?", 1);
+
+        assertInvalidMessage("Cannot use CONTAINS KEY on non-map column",
+                             "SELECT * FROM %s WHERE b CONTAINS KEY ? ALLOW FILTERING", 1);
+
+        assertInvalidMessage("Cannot use CONTAINS KEY on non-map column",
+                             "SELECT * FROM %s WHERE c CONTAINS KEY ?", 1);
+
+        // normal indexes on frozen collections don't support CONTAINS or CONTAINS KEY
+        assertInvalidMessage("No secondary indexes on the restricted columns support the provided operator",
+                             "SELECT * FROM %s WHERE b CONTAINS ?", 1);
+
+        assertInvalidMessage("No secondary indexes on the restricted columns support the provided operator",
+                             "SELECT * FROM %s WHERE b CONTAINS ? ALLOW FILTERING", 1);
+
+        assertInvalidMessage("No secondary indexes on the restricted columns support the provided operator",
+                             "SELECT * FROM %s WHERE d CONTAINS KEY ?", 1);
+
+        assertInvalidMessage("No secondary indexes on the restricted columns support the provided operator",
+                             "SELECT * FROM %s WHERE d CONTAINS KEY ? ALLOW FILTERING", 1);
+
+        assertInvalidMessage("No secondary indexes on the restricted columns support the provided operator",
+                             "SELECT * FROM %s WHERE b CONTAINS ? AND d CONTAINS KEY ? ALLOW FILTERING", 1, 1);
+
+        // index lookup on b
+        assertRows(execute("SELECT * FROM %s WHERE b=?", list(1, 2, 3)),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")),
+            row(1, list(1, 2, 3), set(4, 5, 6), map(2, "b"))
+        );
+
+        assertEmpty(execute("SELECT * FROM %s WHERE b=?", list(-1)));
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE b=? AND c=?", list(1, 2, 3), set(4, 5, 6));
+        assertRows(execute("SELECT * FROM %s WHERE b=? AND c=? ALLOW FILTERING", list(1, 2, 3), set(4, 5, 6)),
+            row(1, list(1, 2, 3), set(4, 5, 6), map(2, "b"))
+        );
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE b=? AND c CONTAINS ?", list(1, 2, 3), 5);
+        assertRows(execute("SELECT * FROM %s WHERE b=? AND c CONTAINS ? ALLOW FILTERING", list(1, 2, 3), 5),
+            row(1, list(1, 2, 3), set(4, 5, 6), map(2, "b"))
+        );
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE b=? AND d=?", list(1, 2, 3), map(1, "a"));
+        assertRows(execute("SELECT * FROM %s WHERE b=? AND d=? ALLOW FILTERING", list(1, 2, 3), map(1, "a")),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE b=? AND d CONTAINS ?", list(1, 2, 3), "a");
+        assertRows(execute("SELECT * FROM %s WHERE b=? AND d CONTAINS ? ALLOW FILTERING", list(1, 2, 3), "a"),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE b=? AND d CONTAINS KEY ?", list(1, 2, 3), 1);
+        assertRows(execute("SELECT * FROM %s WHERE b=? AND d CONTAINS KEY ? ALLOW FILTERING", list(1, 2, 3), 1),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a"))
+        );
+
+        // index lookup on c
+        assertRows(execute("SELECT * FROM %s WHERE c=?", set(1, 2, 3)),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")),
+            row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a"))
+        );
+
+        // ordering of c should not matter
+        assertRows(execute("SELECT * FROM %s WHERE c=?", set(2, 1, 3)),
+                row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")),
+                row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertEmpty(execute("SELECT * FROM %s WHERE c=?", set(-1)));
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE c=? AND b=?", set(1, 2, 3), list(1, 2, 3));
+        assertRows(execute("SELECT * FROM %s WHERE c=? AND b=? ALLOW FILTERING", set(1, 2, 3), list(1, 2, 3)),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE c=? AND b CONTAINS ?", set(1, 2, 3), 1);
+        assertRows(execute("SELECT * FROM %s WHERE c=? AND b CONTAINS ? ALLOW FILTERING", set(1, 2, 3), 1),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE c=? AND d = ?", set(1, 2, 3), map(1, "a"));
+        assertRows(execute("SELECT * FROM %s WHERE c=? AND d = ? ALLOW FILTERING", set(1, 2, 3), map(1, "a")),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")),
+            row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE c=? AND d CONTAINS ?", set(1, 2, 3), "a");
+        assertRows(execute("SELECT * FROM %s WHERE c=? AND d CONTAINS ? ALLOW FILTERING", set(1, 2, 3), "a"),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")),
+            row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE c=? AND d CONTAINS KEY ?", set(1, 2, 3), 1);
+        assertRows(execute("SELECT * FROM %s WHERE c=? AND d CONTAINS KEY ? ALLOW FILTERING", set(1, 2, 3), 1),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")),
+            row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a"))
+        );
+
+        // index lookup on d
+        assertRows(execute("SELECT * FROM %s WHERE d=?", map(1, "a")),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a")),
+            row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE d=?", map(2, "b")),
+            row(1, list(1, 2, 3), set(4, 5, 6), map(2, "b")),
+            row(1, list(4, 5, 6), set(4, 5, 6), map(2, "b"))
+        );
+
+        assertEmpty(execute("SELECT * FROM %s WHERE d=?", map(3, "c")));
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE d=? AND c=?", map(1, "a"), set(1, 2, 3));
+        assertRows(execute("SELECT * FROM %s WHERE d=? AND b=? ALLOW FILTERING", map(1, "a"), list(1, 2, 3)),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE d=? AND b CONTAINS ?", map(1, "a"), 3);
+        assertRows(execute("SELECT * FROM %s WHERE d=? AND b CONTAINS ? ALLOW FILTERING", map(1, "a"), 3),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertInvalidMessage("ALLOW FILTERING", "SELECT * FROM %s WHERE d=? AND b=? AND c=?", map(1, "a"), list(1, 2, 3), set(1, 2, 3));
+        assertRows(execute("SELECT * FROM %s WHERE d=? AND b=? AND c=? ALLOW FILTERING", map(1, "a"), list(1, 2, 3), set(1, 2, 3)),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a"))
+        );
+
+        assertRows(execute("SELECT * FROM %s WHERE d=? AND b CONTAINS ? AND c CONTAINS ? ALLOW FILTERING", map(1, "a"), 2, 2),
+            row(0, list(1, 2, 3), set(1, 2, 3), map(1, "a"))
+        );
+
+        execute("DELETE d FROM %s WHERE a=? AND b=?", 0, list(1, 2, 3));
+        assertRows(execute("SELECT * FROM %s WHERE d=?", map(1, "a")),
+            row(0, list(4, 5, 6), set(1, 2, 3), map(1, "a"))
+        );
+    }
+
+    @Test
+    public void testUserDefinedTypes() throws Throwable
+    {
+        String myType = createType("CREATE TYPE %s (a set<int>, b tuple<list<int>>)");
+        createTable("CREATE TABLE %s (k int PRIMARY KEY, v frozen<" + myType + ">)");
+        execute("INSERT INTO %s (k, v) VALUES (?, {a: ?, b: ?})", 0, set(1, 2, 3), tuple(list(1, 2, 3)));
+        assertRows(execute("SELECT v.a, v.b FROM %s WHERE k=?", 0),
+            row(set(1, 2, 3), tuple(list(1, 2, 3)))
+        );
+    }
+
+    private static String clean(String classname)
+    {
+        return StringUtils.remove(classname, "org.apache.cassandra.db.marshal.");
+    }
+
+    @Test
+    public void testToString()
+    {
+        // set<frozen<list<int>>>
+        SetType t = SetType.getInstance(ListType.getInstance(Int32Type.instance, false), true);
+        assertEquals("SetType(FrozenType(ListType(Int32Type)))", clean(t.toString()));
+        assertEquals("SetType(ListType(Int32Type))", clean(t.toString(true)));
+
+        // frozen<set<list<int>>>
+        t = SetType.getInstance(ListType.getInstance(Int32Type.instance, false), false);
+        assertEquals("FrozenType(SetType(ListType(Int32Type)))", clean(t.toString()));
+        assertEquals("SetType(ListType(Int32Type))", clean(t.toString(true)));
+
+        // map<frozen<list<int>>, int>
+        MapType m = MapType.getInstance(ListType.getInstance(Int32Type.instance, false), Int32Type.instance, true);
+        assertEquals("MapType(FrozenType(ListType(Int32Type)),Int32Type)", clean(m.toString()));
+        assertEquals("MapType(ListType(Int32Type),Int32Type)", clean(m.toString(true)));
+
+        // frozen<map<list<int>, int>>
+        m = MapType.getInstance(ListType.getInstance(Int32Type.instance, false), Int32Type.instance, false);
+        assertEquals("FrozenType(MapType(ListType(Int32Type),Int32Type))", clean(m.toString()));
+        assertEquals("MapType(ListType(Int32Type),Int32Type)", clean(m.toString(true)));
+
+        // tuple<set<int>>
+        List<AbstractType<?>> types = new ArrayList<>();
+        types.add(SetType.getInstance(Int32Type.instance, true));
+        TupleType tuple = new TupleType(types);
+        assertEquals("TupleType(SetType(Int32Type))", clean(tuple.toString()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/test/unit/org/apache/cassandra/cql3/TupleTypeTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/TupleTypeTest.java b/test/unit/org/apache/cassandra/cql3/TupleTypeTest.java
index 53e7e71..ce935e3 100644
--- a/test/unit/org/apache/cassandra/cql3/TupleTypeTest.java
+++ b/test/unit/org/apache/cassandra/cql3/TupleTypeTest.java
@@ -24,26 +24,30 @@ public class TupleTypeTest extends CQLTester
     @Test
     public void testTuplePutAndGet() throws Throwable
     {
-        createTable("CREATE TABLE %s (k int PRIMARY KEY, t frozen<tuple<int, text, double>>)");
+        String[] valueTypes = {"frozen<tuple<int, text, double>>", "tuple<int, text, double>"};
+        for (String valueType : valueTypes)
+        {
+            createTable("CREATE TABLE %s (k int PRIMARY KEY, t " + valueType + ")");
 
-        execute("INSERT INTO %s (k, t) VALUES (?, ?)", 0, tuple(3, "foo", 3.4));
-        execute("INSERT INTO %s (k, t) VALUES (?, ?)", 1, tuple(8, "bar", 0.2));
-        assertAllRows(
-            row(0, tuple(3, "foo", 3.4)),
-            row(1, tuple(8, "bar", 0.2))
-        );
+            execute("INSERT INTO %s (k, t) VALUES (?, ?)", 0, tuple(3, "foo", 3.4));
+            execute("INSERT INTO %s (k, t) VALUES (?, ?)", 1, tuple(8, "bar", 0.2));
+            assertAllRows(
+                row(0, tuple(3, "foo", 3.4)),
+                row(1, tuple(8, "bar", 0.2))
+            );
 
-        // nulls
-        execute("INSERT INTO %s (k, t) VALUES (?, ?)", 2, tuple(5, null, 3.4));
-        assertRows(execute("SELECT * FROM %s WHERE k=?", 2),
-            row(2, tuple(5, null, 3.4))
-        );
+            // nulls
+            execute("INSERT INTO %s (k, t) VALUES (?, ?)", 2, tuple(5, null, 3.4));
+            assertRows(execute("SELECT * FROM %s WHERE k=?", 2),
+                row(2, tuple(5, null, 3.4))
+            );
 
-        // incomplete tuple
-        execute("INSERT INTO %s (k, t) VALUES (?, ?)", 3, tuple(5, "bar"));
-        assertRows(execute("SELECT * FROM %s WHERE k=?", 3),
-            row(3, tuple(5, "bar"))
-        );
+            // incomplete tuple
+            execute("INSERT INTO %s (k, t) VALUES (?, ?)", 3, tuple(5, "bar"));
+            assertRows(execute("SELECT * FROM %s WHERE k=?", 3),
+                row(3, tuple(5, "bar"))
+            );
+        }
     }
 
     @Test
@@ -94,10 +98,4 @@ public class TupleTypeTest extends CQLTester
         assertInvalidSyntax("INSERT INTO %s (k, t) VALUES (0, ())");
         assertInvalid("INSERT INTO %s (k, t) VALUES (0, (2, 'foo', 3.1, 'bar'))");
     }
-
-    @Test
-    public void testNonFrozenTuple() throws Throwable
-    {
-        assertInvalid("CREATE TABLE wrong (k int PRIMARY KEY, v tuple<int, text>)");
-    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/test/unit/org/apache/cassandra/db/marshal/CollectionTypeTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/db/marshal/CollectionTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/CollectionTypeTest.java
index 18156c3..92990e9 100644
--- a/test/unit/org/apache/cassandra/db/marshal/CollectionTypeTest.java
+++ b/test/unit/org/apache/cassandra/db/marshal/CollectionTypeTest.java
@@ -36,7 +36,7 @@ public class CollectionTypeTest
     @Test
     public void testListComparison()
     {
-        ListType<String> lt = ListType.getInstance(UTF8Type.instance);
+        ListType<String> lt = ListType.getInstance(UTF8Type.instance, true);
 
         ByteBuffer[] lists = new ByteBuffer[] {
             ByteBufferUtil.EMPTY_BYTE_BUFFER,
@@ -63,7 +63,7 @@ public class CollectionTypeTest
     @Test
     public void testSetComparison()
     {
-        SetType<String> st = SetType.getInstance(UTF8Type.instance);
+        SetType<String> st = SetType.getInstance(UTF8Type.instance, true);
 
         ByteBuffer[] sets = new ByteBuffer[] {
             ByteBufferUtil.EMPTY_BYTE_BUFFER,
@@ -90,7 +90,7 @@ public class CollectionTypeTest
     @Test
     public void testMapComparison()
     {
-        MapType<String, String> mt = MapType.getInstance(UTF8Type.instance, UTF8Type.instance);
+        MapType<String, String> mt = MapType.getInstance(UTF8Type.instance, UTF8Type.instance, true);
 
         ByteBuffer[] maps = new ByteBuffer[] {
             ByteBufferUtil.EMPTY_BYTE_BUFFER,
@@ -119,8 +119,8 @@ public class CollectionTypeTest
     @Test
     public void listSerDerTest()
     {
-        ListSerializer<String> sls = ListType.getInstance(UTF8Type.instance).getSerializer();
-        ListSerializer<Integer> ils = ListType.getInstance(Int32Type.instance).getSerializer();
+        ListSerializer<String> sls = ListType.getInstance(UTF8Type.instance, true).getSerializer();
+        ListSerializer<Integer> ils = ListType.getInstance(Int32Type.instance, true).getSerializer();
 
         List<String> sl = Arrays.asList("Foo", "Bar");
         List<Integer> il = Arrays.asList(3, 1, 5);
@@ -143,8 +143,8 @@ public class CollectionTypeTest
     @Test
     public void setSerDerTest()
     {
-        SetSerializer<String> sss = SetType.getInstance(UTF8Type.instance).getSerializer();
-        SetSerializer<Integer> iss = SetType.getInstance(Int32Type.instance).getSerializer();
+        SetSerializer<String> sss = SetType.getInstance(UTF8Type.instance, true).getSerializer();
+        SetSerializer<Integer> iss = SetType.getInstance(Int32Type.instance, true).getSerializer();
 
         Set<String> ss = new HashSet(){{ add("Foo"); add("Bar"); }};
         Set<Integer> is = new HashSet(){{ add(3); add(1); add(5); }};
@@ -167,8 +167,8 @@ public class CollectionTypeTest
     @Test
     public void setMapDerTest()
     {
-        MapSerializer<String, String> sms = MapType.getInstance(UTF8Type.instance, UTF8Type.instance).getSerializer();
-        MapSerializer<Integer, Integer> ims = MapType.getInstance(Int32Type.instance, Int32Type.instance).getSerializer();
+        MapSerializer<String, String> sms = MapType.getInstance(UTF8Type.instance, UTF8Type.instance, true).getSerializer();
+        MapSerializer<Integer, Integer> ims = MapType.getInstance(Int32Type.instance, Int32Type.instance, true).getSerializer();
 
         Map<String, String> sm = new HashMap(){{ put("Foo", "xxx"); put("Bar", "yyy"); }};
         Map<Integer, Integer> im = new HashMap(){{ put(3, 0); put(1, 8); put(5, 2); }};
@@ -187,8 +187,8 @@ public class CollectionTypeTest
         // non map value
         assertInvalid(sms, UTF8Type.instance.getSerializer().serialize("foo"));
 
-        MapSerializer<Integer, String> sims = MapType.getInstance(Int32Type.instance, UTF8Type.instance).getSerializer();
-        MapSerializer<String, Integer> isms = MapType.getInstance(UTF8Type.instance, Int32Type.instance).getSerializer();
+        MapSerializer<Integer, String> sims = MapType.getInstance(Int32Type.instance, UTF8Type.instance, true).getSerializer();
+        MapSerializer<String, Integer> isms = MapType.getInstance(UTF8Type.instance, Int32Type.instance, true).getSerializer();
 
         // only key are invalid
         assertInvalid(isms, sb);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/test/unit/org/apache/cassandra/transport/SerDeserTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/transport/SerDeserTest.java b/test/unit/org/apache/cassandra/transport/SerDeserTest.java
index 9b66efb..649f7a2 100644
--- a/test/unit/org/apache/cassandra/transport/SerDeserTest.java
+++ b/test/unit/org/apache/cassandra/transport/SerDeserTest.java
@@ -31,7 +31,6 @@ import org.apache.cassandra.serializers.CollectionSerializer;
 import org.apache.cassandra.transport.Event.TopologyChange;
 import org.apache.cassandra.transport.Event.SchemaChange;
 import org.apache.cassandra.transport.Event.StatusChange;
-import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.Pair;
 
@@ -53,7 +52,7 @@ public class SerDeserTest
     public void collectionSerDeserTest(int version) throws Exception
     {
         // Lists
-        ListType<?> lt = ListType.getInstance(Int32Type.instance);
+        ListType<?> lt = ListType.getInstance(Int32Type.instance, true);
         List<Integer> l = Arrays.asList(2, 6, 1, 9);
 
         List<ByteBuffer> lb = new ArrayList<>(l.size());
@@ -63,7 +62,7 @@ public class SerDeserTest
         assertEquals(l, lt.getSerializer().deserializeForNativeProtocol(CollectionSerializer.pack(lb, lb.size(), version), version));
 
         // Sets
-        SetType<?> st = SetType.getInstance(UTF8Type.instance);
+        SetType<?> st = SetType.getInstance(UTF8Type.instance, true);
         Set<String> s = new LinkedHashSet<>();
         s.addAll(Arrays.asList("bar", "foo", "zee"));
 
@@ -74,7 +73,7 @@ public class SerDeserTest
         assertEquals(s, st.getSerializer().deserializeForNativeProtocol(CollectionSerializer.pack(sb, sb.size(), version), version));
 
         // Maps
-        MapType<?, ?> mt = MapType.getInstance(UTF8Type.instance, LongType.instance);
+        MapType<?, ?> mt = MapType.getInstance(UTF8Type.instance, LongType.instance, true);
         Map<String, Long> m = new LinkedHashMap<>();
         m.put("bar", 12L);
         m.put("foo", 42L);
@@ -165,9 +164,9 @@ public class SerDeserTest
 
     public void udtSerDeserTest(int version) throws Exception
     {
-        ListType<?> lt = ListType.getInstance(Int32Type.instance);
-        SetType<?> st = SetType.getInstance(UTF8Type.instance);
-        MapType<?, ?> mt = MapType.getInstance(UTF8Type.instance, LongType.instance);
+        ListType<?> lt = ListType.getInstance(Int32Type.instance, true);
+        SetType<?> st = SetType.getInstance(UTF8Type.instance, true);
+        MapType<?, ?> mt = MapType.getInstance(UTF8Type.instance, LongType.instance, true);
 
         UserType udt = new UserType("ks",
                                     bb("myType"),

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
index 6480d7a..bfa58ea 100644
--- a/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Lists.java
@@ -33,7 +33,7 @@ public class Lists extends Generator<List>
 
     public Lists(String name, Generator valueType, GeneratorConfig config)
     {
-        super(ListType.getInstance(valueType.type), config, name, List.class);
+        super(ListType.getInstance(valueType.type, true), config, name, List.class);
         this.valueType = valueType;
         buffer = new Object[(int) sizeDistribution.maxValue()];
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ee55f361/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
----------------------------------------------------------------------
diff --git a/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java b/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
index 8246286..5c17b4e 100644
--- a/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
+++ b/tools/stress/src/org/apache/cassandra/stress/generate/values/Sets.java
@@ -32,7 +32,7 @@ public class Sets extends Generator<Set>
 
     public Sets(String name, Generator valueType, GeneratorConfig config)
     {
-        super(SetType.getInstance(valueType.type), config, name, Set.class);
+        super(SetType.getInstance(valueType.type, true), config, name, Set.class);
         this.valueType = valueType;
     }
 


Mime
View raw message