You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by yu...@apache.org on 2012/07/27 17:19:39 UTC

[27/50] [abbrv] git commit: Refactor set/list/map CQL3 code

Refactor set/list/map CQL3 code

patch by xedin; reviewed by slebresne for CASSANDRA-3647


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/2b62df24
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/2b62df24
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/2b62df24

Branch: refs/heads/cassandra-1.1
Commit: 2b62df244cb9e047d13c9c6dadcf44a26505b036
Parents: 1dadaa7
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Fri Jul 20 11:58:45 2012 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Fri Jul 20 11:58:45 2012 +0200

----------------------------------------------------------------------
 src/java/org/apache/cassandra/cql3/Cql.g           |   60 ++--
 src/java/org/apache/cassandra/cql3/Operation.java  |  108 ------
 src/java/org/apache/cassandra/cql3/Term.java       |    2 +-
 src/java/org/apache/cassandra/cql3/Value.java      |  121 -------
 .../cassandra/cql3/operations/ColumnOperation.java |  136 ++++++++
 .../cassandra/cql3/operations/ListOperation.java   |  258 +++++++++++++++
 .../cassandra/cql3/operations/MapOperation.java    |  145 ++++++++
 .../cassandra/cql3/operations/Operation.java       |   53 +++
 .../cassandra/cql3/operations/SetOperation.java    |  127 +++++++
 .../statements/CreateColumnFamilyStatement.java    |    8 +-
 .../cassandra/cql3/statements/DeleteStatement.java |   31 ++-
 .../cassandra/cql3/statements/SelectStatement.java |   19 +-
 .../cassandra/cql3/statements/UpdateStatement.java |  133 +++------
 .../apache/cassandra/db/marshal/AbstractType.java  |    5 +
 .../cassandra/db/marshal/CollectionType.java       |   40 +--
 .../apache/cassandra/db/marshal/CompositeType.java |   15 +-
 .../org/apache/cassandra/db/marshal/ListType.java  |  155 +---------
 .../org/apache/cassandra/db/marshal/MapType.java   |   43 +---
 .../org/apache/cassandra/db/marshal/SetType.java   |   44 +---
 19 files changed, 861 insertions(+), 642 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/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 04c2391..e6aa09e 100644
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -34,6 +34,7 @@ options {
     import java.util.List;
     import java.util.Map;
 
+    import org.apache.cassandra.cql3.operations.*;
     import org.apache.cassandra.cql3.statements.*;
     import org.apache.cassandra.config.ConfigurationException;
     import org.apache.cassandra.db.marshal.CollectionType;
@@ -221,15 +222,15 @@ insertStatement returns [UpdateStatement expr]
     @init {
         Attributes attrs = new Attributes();
         List<ColumnIdentifier> columnNames  = new ArrayList<ColumnIdentifier>();
-        List<Value> columnValues = new ArrayList<Value>();
+        List<Operation> columnOperations = new ArrayList<Operation>();
     }
     : K_INSERT K_INTO cf=columnFamilyName
           '(' c1=cident { columnNames.add(c1); }  ( ',' cn=cident { columnNames.add(cn); } )+ ')'
         K_VALUES
-          '(' v1=value { columnValues.add(v1); } ( ',' vn=value { columnValues.add(vn); } )+ ')'
+          '(' v1=set_operation { columnOperations.add(v1); } ( ',' vn=set_operation { columnOperations.add(vn); } )+ ')'
         ( usingClause[attrs] )?
       {
-          $expr = new UpdateStatement(cf, attrs, columnNames, columnValues);
+          $expr = new UpdateStatement(cf, attrs, columnNames, columnOperations);
       }
     ;
 
@@ -471,29 +472,25 @@ cfOrKsName[CFName name, boolean isKs]
     | k=unreserved_keyword { if (isKs) $name.setKeyspace(k, false); else $name.setColumnFamily(k, false); }
     ;
 
-// Values (includes prepared statement markers)
-value returns [Value value]
-    : t=term               { $value = t; }
-    | c=collection_literal { $value = c; }
+set_operation returns [Operation op]
+    : t=term         { $op = ColumnOperation.Set(t); }
+    | m=map_literal  { $op = MapOperation.Set(m);  }
+    | l=list_literal { $op = ListOperation.Set(l); }
+    | s=set_literal  { $op = SetOperation.Set(s);  }
     ;
 
-collection_literal returns [Value value]
-    : ll=list_literal { $value = ll; }
-    | sl=set_literal  { $value = sl; }
-    | ml=map_literal  { $value = ml; }
+list_literal returns [List<Term> value]
+    : '[' { List<Term> l = new ArrayList<Term>(); } ( t1=term { l.add(t1); } ( ',' tn=term { l.add(tn); } )* )? ']' { $value = l; }
     ;
 
-list_literal returns [Value.ListLiteral value]
-    : '[' { Value.ListLiteral l = new Value.ListLiteral(); } ( t1=term { l.add(t1); } ( ',' tn=term { l.add(tn); } )* )? ']' { $value = l; }
+set_literal returns [List<Term> value]
+    : '{' { List<Term> s = new ArrayList<Term>(); } ( t1=term { s.add(t1); } ( ',' tn=term { s.add(tn); } )* )? '}'  { $value = s; }
     ;
 
-set_literal returns [Value.SetLiteral value]
-    : '{' { Value.SetLiteral s = new Value.SetLiteral(); } ( t1=term { s.add(t1); } ( ',' tn=term { s.add(tn); } )* )? '}'  { $value = s; }
-    ;
-
-map_literal returns [Value.MapLiteral value]
+map_literal returns [Map<Term, Term> value]
     // Note that we have an ambiguity between maps and set for "{}". So we force it to a set, and deal with it later based on the type of the column
-    : '{' { Value.MapLiteral m = new Value.MapLiteral(); } k1=term ':' v1=term { m.put(k1, v1); } ( ',' kn=term ':' vn=term { m.put(kn, vn); } )* '}'
+    : '{' { Map<Term, Term> m = new HashMap<Term, Term>(); }
+          k1=term ':' v1=term { m.put(k1, v1); } ( ',' kn=term ':' vn=term { m.put(kn, vn); } )* '}'
        { $value = m; }
     ;
 
@@ -514,7 +511,7 @@ intTerm returns [Term integer]
 
 termPairWithOperation[List<Pair<ColumnIdentifier, Operation>> columns]
     : key=cident '='
-        ( v=value { columns.add(Pair.<ColumnIdentifier, Operation>create(key, new Operation.Set(v))); }
+        (set_op = set_operation { columns.add(Pair.<ColumnIdentifier, Operation>create(key, set_op)); }
         | c=cident op=operation
           {
               if (!key.equals(c))
@@ -525,32 +522,35 @@ termPairWithOperation[List<Pair<ColumnIdentifier, Operation>> columns]
           {
               if (!key.equals(c))
                   addRecognitionError("Only expressions like X = <value> + X are supported.");
-              columns.add(Pair.<ColumnIdentifier, Operation>create(key, new Operation.Function(CollectionType.Function.PREPEND, ll)));
+              columns.add(Pair.<ColumnIdentifier, Operation>create(key, ListOperation.Prepend(ll)));
           }
         )
     | key=cident '[' t=term ']' '=' vv=term
       {
-          List<Term> args = Arrays.asList(t, vv);
-          columns.add(Pair.<ColumnIdentifier, Operation>create(key, new Operation.Function(CollectionType.Function.SET, args)));
+          Operation setOp = (t.getType() == Term.Type.INTEGER)
+                             ? ListOperation.SetIndex(Arrays.asList(t, vv))
+                             : MapOperation.Put(t, vv);
+
+          columns.add(Pair.<ColumnIdentifier, Operation>create(key, setOp));
       }
     ;
 
 operation returns [Operation op]
-    : '+' v=intTerm { $op = new Operation.Counter(v, false); }
+    : '+' v=intTerm { $op = ColumnOperation.CounterInc(v); }
     | sign='-'? v=intTerm
       {
           validateMinusSupplied(sign, v, input);
           if (sign == null)
               v = new Term(-(Long.valueOf(v.getText())), v.getType());
-          $op = new Operation.Counter(v, true);
+          $op = ColumnOperation.CounterDec(v);
       }
-    | '+' ll=list_literal { $op = new Operation.Function(CollectionType.Function.APPEND, ll); }
-    | '-' ll=list_literal { $op = new Operation.Function(CollectionType.Function.DISCARD_LIST, ll); }
+    | '+' ll=list_literal { $op = ListOperation.Append(ll); }
+    | '-' ll=list_literal { $op = ListOperation.Discard(ll); }
 
-    | '+' sl=set_literal { $op = new Operation.Function(CollectionType.Function.ADD, sl.asList()); }
-    | '-' sl=set_literal { $op = new Operation.Function(CollectionType.Function.DISCARD_SET, sl.asList()); }
+    | '+' sl=set_literal { $op = SetOperation.Add(sl); }
+    | '-' sl=set_literal { $op = SetOperation.Discard(sl); }
 
-    | '+' ml=map_literal { $op = new Operation.Function(CollectionType.Function.SET, ml.asList()); }
+    | '+' ml=map_literal { $op = MapOperation.Put(ml); }
     ;
 
 property returns [String str]

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/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
deleted file mode 100644
index e7291c3..0000000
--- a/src/java/org/apache/cassandra/cql3/Operation.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.cql3;
-
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.cassandra.db.marshal.CollectionType;
-import org.apache.cassandra.thrift.InvalidRequestException;
-
-public abstract class Operation
-{
-    public static enum Type { SET, COUNTER, FUNCTION }
-
-    public final Type type;
-
-    protected Operation(Type type)
-    {
-        this.type = type;
-    }
-
-    public abstract Iterable<Term> allTerms();
-
-    public static class Set extends Operation
-    {
-        public final Value value;
-
-        public Set(Value value)
-        {
-            super(Type.SET);
-            this.value = value;
-        }
-
-        @Override
-        public String toString()
-        {
-            return " = " + value;
-        }
-
-        public List<Term> allTerms()
-        {
-            return value.asList();
-        }
-    }
-
-    public static class Counter extends Operation
-    {
-        public final Term value;
-        public final boolean isSubstraction;
-
-        public Counter(Term value, boolean isSubstraction)
-        {
-            super(Type.COUNTER);
-            this.value = value;
-            this.isSubstraction = isSubstraction;
-        }
-
-        @Override
-        public String toString()
-        {
-            return (isSubstraction ? "-" : "+") + "= " + value;
-        }
-
-        public Iterable<Term> allTerms()
-        {
-            return Collections.singletonList(value);
-        }
-    }
-
-    public static class Function extends Operation
-    {
-        public final CollectionType.Function fct;
-        public final List<Term> arguments;
-
-        public Function(CollectionType.Function fct, List<Term> arguments)
-        {
-            super(Type.FUNCTION);
-            this.fct = fct;
-            this.arguments = arguments;
-        }
-
-        @Override
-        public String toString()
-        {
-            return "." + fct + arguments;
-        }
-
-        public Iterable<Term> allTerms()
-        {
-            return arguments;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/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 81be6de..a38260d 100644
--- a/src/java/org/apache/cassandra/cql3/Term.java
+++ b/src/java/org/apache/cassandra/cql3/Term.java
@@ -34,7 +34,7 @@ import org.apache.cassandra.db.marshal.MarshalException;
 import org.apache.cassandra.thrift.InvalidRequestException;
 
 /** A term parsed from a CQL statement. */
-public class Term implements Value
+public class Term
 {
     public enum Type
     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/Value.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Value.java b/src/java/org/apache/cassandra/cql3/Value.java
deleted file mode 100644
index 64f588b..0000000
--- a/src/java/org/apache/cassandra/cql3/Value.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.cql3;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cassandra.db.marshal.CollectionType;
-import org.apache.cassandra.db.marshal.ListType;
-import org.apache.cassandra.db.marshal.MapType;
-import org.apache.cassandra.db.marshal.SetType;
-import org.apache.cassandra.thrift.InvalidRequestException;
-
-public interface Value
-{
-    public List<Term> asList();
-
-    public interface CollectionLiteral extends Value
-    {
-        /**
-         * Validate that this literal is compatible with the provided column and
-         * throws an InvalidRequestException if not.
-         */
-        public void validateType(CFDefinition.Name value) throws InvalidRequestException;
-
-        /**
-         * Returns whether this litteral is empty or not.
-         */
-        public boolean isEmpty();
-
-        /**
-         * Returns the internal function to use to construct this literal.
-         */
-        public CollectionType.Function constructionFunction();
-    }
-
-    public static class MapLiteral extends HashMap<Term, Term> implements CollectionLiteral
-    {
-        public List<Term> asList()
-        {
-            List<Term> l = new ArrayList<Term>(2 * size());
-            for (Map.Entry<Term, Term> entry : entrySet())
-            {
-                l.add(entry.getKey());
-                l.add(entry.getValue());
-            }
-            return l;
-        }
-
-        public void validateType(CFDefinition.Name value) throws InvalidRequestException
-        {
-            if (!(value.type instanceof MapType))
-                throw new InvalidRequestException(String.format("Invalid value: %s is not a map", value.name));
-        }
-
-        public CollectionType.Function constructionFunction()
-        {
-            return CollectionType.Function.SET;
-        }
-    }
-
-    public static class ListLiteral extends ArrayList<Term> implements CollectionLiteral
-    {
-        public List<Term> asList()
-        {
-            return this;
-        }
-
-        public void validateType(CFDefinition.Name value) throws InvalidRequestException
-        {
-            if (!(value.type instanceof ListType))
-                throw new InvalidRequestException(String.format("Invalid value: %s is not a list", value.name));
-        }
-
-        public CollectionType.Function constructionFunction()
-        {
-            return CollectionType.Function.APPEND;
-        }
-    }
-
-    public static class SetLiteral extends HashSet<Term> implements CollectionLiteral
-    {
-        public List<Term> asList()
-        {
-            return new ArrayList<Term>(this);
-        }
-
-        public void validateType(CFDefinition.Name value) throws InvalidRequestException
-        {
-            // The parser don't distinguish between empty set and empty map and always return an empty set
-            if ((value.type instanceof MapType) && !isEmpty())
-                throw new InvalidRequestException(String.format("Invalid value: %s is not a map", value.name));
-            else if (!(value.type instanceof SetType))
-                throw new InvalidRequestException(String.format("Invalid value: %s is not a set", value.name));
-        }
-
-        public CollectionType.Function constructionFunction()
-        {
-            return CollectionType.Function.ADD;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/operations/ColumnOperation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/operations/ColumnOperation.java b/src/java/org/apache/cassandra/cql3/operations/ColumnOperation.java
new file mode 100644
index 0000000..5e4f6b3
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/operations/ColumnOperation.java
@@ -0,0 +1,136 @@
+/**
+ * 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.operations;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.db.ColumnFamily;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.filter.QueryPath;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.db.marshal.LongType;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.Pair;
+
+public class ColumnOperation implements Operation
+{
+    enum Kind { SET, COUNTER_INC, COUNTER_DEC }
+
+    private final Term value;
+    private final Kind kind;
+
+    private ColumnOperation(Term value, Kind kind)
+    {
+        this.value = value;
+        this.kind = kind;
+    }
+
+    public void execute(ColumnFamily cf,
+                        ColumnNameBuilder builder,
+                        AbstractType<?> validator,
+                        UpdateParameters params) throws InvalidRequestException
+    {
+        switch (kind)
+        {
+            case SET:
+                doSet(cf, builder, validator, params);
+                break;
+            case COUNTER_INC:
+            case COUNTER_DEC:
+                doCounter(cf, builder, params);
+                break;
+            default:
+                throw new AssertionError("Unsupported operation: " + kind);
+        }
+    }
+
+    public void execute(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+    {
+        throw new InvalidRequestException("Column operations are only supported on simple types, but " + validator + " given.");
+    }
+
+    private void doSet(ColumnFamily cf, ColumnNameBuilder builder, AbstractType<?> validator, UpdateParameters params) throws InvalidRequestException
+    {
+        ByteBuffer colName = builder.build();
+        QueryProcessor.validateColumnName(colName);
+
+        ByteBuffer valueBytes = value.getByteBuffer(validator, params.variables);
+        cf.addColumn(params.makeColumn(colName, valueBytes));
+    }
+
+    private void doCounter(ColumnFamily cf, ColumnNameBuilder builder, UpdateParameters params) throws InvalidRequestException
+    {
+        long val;
+
+        try
+        {
+            val = ByteBufferUtil.toLong(value.getByteBuffer(LongType.instance, params.variables));
+        }
+        catch (NumberFormatException e)
+        {
+            throw new InvalidRequestException(String.format("'%s' is an invalid value, should be a long.", value.getText()));
+        }
+
+        if (kind == Kind.COUNTER_DEC)
+        {
+            if (val == Long.MIN_VALUE)
+                throw new InvalidRequestException("The negation of " + val + " overflows supported integer precision (signed 8 bytes integer)");
+            else
+                val = -val;
+        }
+
+        cf.addCounter(new QueryPath(cf.metadata().cfName, null, builder.build()), val);
+    }
+
+    public List<Term> getValues()
+    {
+        return Collections.singletonList(value);
+    }
+
+    public boolean requiresRead()
+    {
+        return false;
+    }
+
+    public Type getType()
+    {
+        return kind == Kind.COUNTER_DEC || kind == Kind.COUNTER_INC ? Type.COUNTER : Type.COLUMN;
+    }
+
+    /* Utility methods */
+
+    public static Operation Set(Term value)
+    {
+        return new ColumnOperation(value, Kind.SET);
+    }
+
+    public static Operation CounterInc(Term value)
+    {
+        return new ColumnOperation(value, Kind.COUNTER_INC);
+    }
+
+    public static Operation CounterDec(Term value)
+    {
+        return new ColumnOperation(value, Kind.COUNTER_DEC);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/operations/ListOperation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/operations/ListOperation.java b/src/java/org/apache/cassandra/cql3/operations/ListOperation.java
new file mode 100644
index 0000000..b4ba021
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/operations/ListOperation.java
@@ -0,0 +1,258 @@
+/**
+ * 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.operations;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.cassandra.cql3.ColumnNameBuilder;
+import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.UpdateParameters;
+import org.apache.cassandra.db.ColumnFamily;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.Pair;
+import org.apache.cassandra.utils.UUIDGen;
+
+public class ListOperation implements Operation
+{
+    // Our reference time (1 jan 2010, 00:00:00) in milliseconds.
+    private static final long REFERENCE_TIME = 1262304000000L;
+
+    /*
+     * For prepend, we need to be able to generate unique but decreasing time
+     * UUID, which is a bit challenging. To do that, given a time in milliseconds,
+     * we adds a number representing the 100-nanoseconds precision and make sure
+     * that within the same millisecond, that number is always increasing. We
+     * do rely on the fact that the user will only provide decreasing
+     * milliseconds timestamp for that purpose.
+     */
+    private static class PrecisionTime
+    {
+        public final long millis;
+        public final int nanos;
+
+        public PrecisionTime(long millis, int nanos)
+        {
+            this.millis = millis;
+            this.nanos = nanos;
+        }
+    }
+
+    private static final AtomicReference<PrecisionTime> last = new AtomicReference<PrecisionTime>(new PrecisionTime(Long.MAX_VALUE, 0));
+
+    private static PrecisionTime getNextTime(long millis)
+    {
+        while (true)
+        {
+            PrecisionTime current = last.get();
+
+            assert millis <= current.millis;
+            PrecisionTime next = millis < current.millis
+                    ? new PrecisionTime(millis, 0)
+                    : new PrecisionTime(millis, current.nanos + 1);
+
+            if (last.compareAndSet(current, next))
+                return next;
+        }
+    }
+
+    enum Kind { SET, SET_IDX, APPEND, PREPEND, DISCARD, DISCARD_IDX }
+
+    private final List<Term> values;
+    private final Kind kind;
+
+    private ListOperation(List<Term> values, Kind kind)
+    {
+        this.values = Collections.unmodifiableList(values);
+        this.kind = kind;
+    }
+
+    public void execute(ColumnFamily cf,
+                        ColumnNameBuilder builder,
+                        CollectionType validator,
+                        UpdateParameters params,
+                        List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+    {
+        if (validator.kind != CollectionType.Kind.LIST)
+            throw new InvalidRequestException("List operations are only supported on List typed columns, but " + validator + " given.");
+
+        switch (kind)
+        {
+            case SET:
+                cf.addAtom(params.makeTombstoneForOverwrite(builder.copy().build(), builder.copy().buildAsEndOfRange()));
+                doAppend(cf, builder, validator, params);
+                break;
+            case SET_IDX:
+                doSet(cf, builder, params, validator, list);
+                break;
+            case APPEND:
+                doAppend(cf, builder, validator, params);
+                break;
+            case PREPEND:
+                doPrepend(cf, builder, validator, params);
+                break;
+            case DISCARD:
+                doDiscard(cf, validator, params, list);
+                break;
+            case DISCARD_IDX:
+                doDiscardIdx(cf, params, list);
+                break;
+            default:
+                throw new AssertionError("Unsupported List operation: " + kind);
+        }
+    }
+
+    public void execute(ColumnFamily cf, ColumnNameBuilder builder, AbstractType<?> validator, UpdateParameters params) throws InvalidRequestException
+    {
+        throw new InvalidRequestException("List operations are only supported on List typed columns, but " + validator + " given.");
+    }
+
+    private void doSet(ColumnFamily cf, ColumnNameBuilder builder, UpdateParameters params, CollectionType validator, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+    {
+        int idx = validateListIdx(values.get(0), list);
+        Term value = values.get(1);
+
+        ByteBuffer name = list.get(idx).right.name();
+        cf.addColumn(params.makeColumn(name, value.getByteBuffer(validator.valueComparator(), params.variables)));
+    }
+
+    private void doAppend(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+    {
+        for (int i = 0; i < values.size(); i++)
+        {
+            ColumnNameBuilder b = i == values.size() - 1 ? builder : builder.copy();
+            ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes());
+            ByteBuffer name = b.add(uuid).build();
+            cf.addColumn(params.makeColumn(name, values.get(i).getByteBuffer(validator.valueComparator(), params.variables)));
+        }
+    }
+
+    private void doPrepend(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+    {
+        long time = REFERENCE_TIME - (System.currentTimeMillis() - REFERENCE_TIME);
+
+        // We do the loop in reverse order because getNext() will create increasing time but we want the last
+        // value in the prepended list to have the lower time
+        for (int i = values.size() - 1; i >= 0; i--)
+        {
+            ColumnNameBuilder b = i == 0 ? builder : builder.copy();
+            PrecisionTime pt = getNextTime(time);
+            ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(pt.millis, pt.nanos));
+            ByteBuffer name = b.add(uuid).build();
+            cf.addColumn(params.makeColumn(name, values.get(i).getByteBuffer(validator.valueComparator(), params.variables)));
+        }
+    }
+
+    private void doDiscard(ColumnFamily cf, CollectionType validator, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+    {
+        if (list == null)
+            return;
+
+        Set<ByteBuffer> toDiscard = new HashSet<ByteBuffer>();
+
+        for (Term value : values)
+            toDiscard.add(value.getByteBuffer(validator.valueComparator(), params.variables));
+
+        for (Pair<ByteBuffer, IColumn> p : list)
+        {
+            IColumn c = p.right;
+            if (toDiscard.contains(c.value()))
+                cf.addColumn(params.makeTombstone(c.name()));
+        }
+    }
+
+    private void doDiscardIdx(ColumnFamily cf, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+    {
+        int idx = validateListIdx(values.get(0), list);
+        cf.addColumn(params.makeTombstone(list.get(idx).right.name()));
+    }
+
+    public List<Term> getValues()
+    {
+        return values;
+    }
+
+    public boolean requiresRead()
+    {
+        return kind == Kind.DISCARD || kind == Kind.DISCARD_IDX || kind == Kind.SET || kind == Kind.SET_IDX;
+    }
+
+    public Type getType()
+    {
+        return Type.LIST;
+    }
+
+    /* Utility methods */
+
+    public static Operation Set(List<Term> values)
+    {
+        return new ListOperation(values, Kind.SET);
+    }
+
+    public static Operation SetIndex(List<Term> values)
+    {
+        return new ListOperation(values, Kind.SET_IDX);
+    }
+
+    public static Operation Append(List<Term> values)
+    {
+        return new ListOperation(values, Kind.APPEND);
+    }
+
+    public static Operation Prepend(List<Term> values)
+    {
+        return new ListOperation(values, Kind.PREPEND);
+    }
+
+    public static Operation Discard(List<Term> values)
+    {
+        return new ListOperation(values, Kind.DISCARD);
+    }
+
+    public static Operation DiscardKey(List<Term> values)
+    {
+        return new ListOperation(values, Kind.DISCARD_IDX);
+    }
+
+    private int validateListIdx(Term value, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+    {
+        try
+        {
+            if (value.getType() != Term.Type.INTEGER)
+                throw new InvalidRequestException(String.format("Invalid argument %s for %s, must be an integer.", value.getText(), getType()));
+
+            int idx = Integer.parseInt(value.getText());
+            if (list == null || list.size() <= idx)
+                throw new InvalidRequestException(String.format("Invalid index %d, list has size %d", idx, list == null ? 0 : list.size()));
+
+            return idx;
+        }
+        catch (NumberFormatException e)
+        {
+            // This should not happen, unless we screwed up the parser
+            throw new RuntimeException();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/operations/MapOperation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/operations/MapOperation.java b/src/java/org/apache/cassandra/cql3/operations/MapOperation.java
new file mode 100644
index 0000000..d843fc7
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/operations/MapOperation.java
@@ -0,0 +1,145 @@
+/**
+ * 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.operations;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cassandra.cql3.ColumnNameBuilder;
+import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.UpdateParameters;
+import org.apache.cassandra.db.ColumnFamily;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.Pair;
+
+public class MapOperation implements Operation
+{
+    enum Kind { SET, PUT, DISCARD }
+
+    private final Map<Term, Term> values;
+    private final Term discardKey;
+    private final Kind kind;
+
+    private MapOperation(Map<Term, Term> values, Kind kind)
+    {
+        this.values = values;
+        this.discardKey = null;
+        this.kind = kind;
+    }
+
+    private MapOperation(Term discardKey)
+    {
+        this.values = null;
+        this.discardKey = discardKey;
+        this.kind = Kind.DISCARD;
+    }
+
+    public void execute(ColumnFamily cf, ColumnNameBuilder builder, AbstractType<?> validator, UpdateParameters params) throws InvalidRequestException
+    {
+        throw new InvalidRequestException("Map operations are only supported on Map typed columns, but " + validator + " given.");
+    }
+
+    public void execute(ColumnFamily cf,
+                        ColumnNameBuilder builder,
+                        CollectionType validator,
+                        UpdateParameters params,
+                        List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+    {
+        if (validator.kind != CollectionType.Kind.MAP)
+            throw new InvalidRequestException("Map operations are only supported on Map typed columns, but " + validator + " given.");
+
+        switch (kind)
+        {
+            case SET: // fallthrough on purpose; remove previous Map before setting (PUT) the new one
+                cf.addAtom(params.makeTombstoneForOverwrite(builder.copy().build(), builder.copy().buildAsEndOfRange()));
+            case PUT:
+                doPut(cf, builder, validator, params);
+                break;
+            case DISCARD:
+                doDiscard(cf, builder, validator, params);
+                break;
+            default:
+                throw new AssertionError("Unsupported Map operation: " + kind);
+        }
+    }
+
+    private void doPut(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+    {
+        for (Map.Entry<Term, Term> entry : values.entrySet())
+        {
+            ByteBuffer name = builder.copy().add(entry.getKey().getByteBuffer(validator.nameComparator(), params.variables)).build();
+            ByteBuffer value = entry.getValue().getByteBuffer(validator.valueComparator(), params.variables);
+            cf.addColumn(params.makeColumn(name, value));
+        }
+    }
+
+    private void doDiscard(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+    {
+        ByteBuffer name = builder.add(discardKey.getByteBuffer(validator.nameComparator(), params.variables)).build();
+        cf.addColumn(params.makeTombstone(name));
+    }
+
+    public List<Term> getValues()
+    {
+        List<Term> l = new ArrayList<Term>(2 * values.size());
+        for (Map.Entry<Term, Term> entry : values.entrySet())
+        {
+            l.add(entry.getKey());
+            l.add(entry.getValue());
+        }
+        return l;
+    }
+
+    public boolean requiresRead()
+    {
+        return kind == Kind.SET || kind == Kind.DISCARD;
+    }
+
+    public Type getType()
+    {
+        return Type.MAP;
+    }
+
+    /* Utility methods */
+
+    public static Operation Set(Map<Term, Term> values)
+    {
+        return new MapOperation(values, Kind.SET);
+    }
+
+    public static Operation Put(Map<Term, Term> values)
+    {
+        return new MapOperation(values, Kind.PUT);
+    }
+
+    public static Operation Put(final Term key, final Term value)
+    {
+        return Put(new HashMap<Term, Term>(1) {{ put(key, value); }});
+    }
+
+    public static Operation DiscardKey(Term discardKey)
+    {
+        return new MapOperation(discardKey);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/operations/Operation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/operations/Operation.java b/src/java/org/apache/cassandra/cql3/operations/Operation.java
new file mode 100644
index 0000000..13c341c
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/operations/Operation.java
@@ -0,0 +1,53 @@
+/**
+ * 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.operations;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.cql3.ColumnNameBuilder;
+import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.UpdateParameters;
+import org.apache.cassandra.db.ColumnFamily;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.Pair;
+
+public interface Operation
+{
+    public static enum Type { COLUMN, COUNTER, LIST, SET, MAP }
+
+    public void execute(ColumnFamily cf,
+                        ColumnNameBuilder builder,
+                        AbstractType<?> validator,
+                        UpdateParameters params) throws InvalidRequestException;
+
+    public void execute(ColumnFamily cf,
+                        ColumnNameBuilder builder,
+                        CollectionType validator,
+                        UpdateParameters params,
+                        List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException;
+
+    public List<Term> getValues();
+
+    public boolean requiresRead();
+
+    public Type getType();
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/operations/SetOperation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/operations/SetOperation.java b/src/java/org/apache/cassandra/cql3/operations/SetOperation.java
new file mode 100644
index 0000000..22b4517
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/operations/SetOperation.java
@@ -0,0 +1,127 @@
+/**
+ * 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.operations;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.cql3.ColumnNameBuilder;
+import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.UpdateParameters;
+import org.apache.cassandra.db.ColumnFamily;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.Pair;
+
+public class SetOperation implements Operation
+{
+    enum Kind { SET, ADD, DISCARD }
+
+    private final List<Term> values;
+    private final Kind kind;
+
+    private SetOperation(List<Term> values, Kind kind)
+    {
+        this.values = values;
+        this.kind = kind;
+    }
+
+    public void execute(ColumnFamily cf,
+                        ColumnNameBuilder builder,
+                        CollectionType validator,
+                        UpdateParameters params,
+                        List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+    {
+        if (validator.kind != CollectionType.Kind.SET)
+            throw new InvalidRequestException("Set operations are only supported on Set typed columns, but " + validator + " given.");
+
+        switch (kind)
+        {
+            case SET: // fallthrough on purpose; remove previous Set before setting (ADD) the new one
+                cf.addAtom(params.makeTombstoneForOverwrite(builder.copy().build(), builder.copy().buildAsEndOfRange()));
+            case ADD:
+                doAdd(cf, builder, validator, params);
+                break;
+            case DISCARD:
+                doDiscard(cf, builder, validator, params);
+                break;
+            default:
+                throw new AssertionError("Unsupported Set operation: " + kind);
+        }
+    }
+
+    public void execute(ColumnFamily cf, ColumnNameBuilder builder, AbstractType<?> validator, UpdateParameters params) throws InvalidRequestException
+    {
+        throw new InvalidRequestException("Set operations are only supported on Set typed columns, but " + validator + " given.");
+    }
+
+    private void doAdd(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+    {
+        for (int i = 0; i < values.size(); ++i)
+        {
+            ColumnNameBuilder b = i == values.size() - 1 ? builder : builder.copy();
+            ByteBuffer name = b.add(values.get(i).getByteBuffer(validator.nameComparator(), params.variables)).build();
+            cf.addColumn(params.makeColumn(name, ByteBufferUtil.EMPTY_BYTE_BUFFER));
+        }
+    }
+
+    private void doDiscard(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+    {
+        for (int i = 0; i < values.size(); ++i)
+        {
+            ColumnNameBuilder b = i == values.size() - 1 ? builder : builder.copy();
+            ByteBuffer name = b.add(values.get(i).getByteBuffer(validator.nameComparator(), params.variables)).build();
+            cf.addColumn(params.makeTombstone(name));
+        }
+    }
+
+    public List<Term> getValues()
+    {
+        return values;
+    }
+
+    public boolean requiresRead()
+    {
+        return false;
+    }
+
+    public Type getType()
+    {
+        return Type.SET;
+    }
+
+    /* Utility methods */
+
+    public static Operation Set(List<Term> values)
+    {
+        return new SetOperation(values, Kind.SET);
+    }
+
+    public static Operation Add(List<Term> values)
+    {
+        return new SetOperation(values, Kind.ADD);
+    }
+
+    public static Operation Discard(List<Term> values)
+    {
+        return new SetOperation(values, Kind.DISCARD);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
index 45a55da..bf7a82a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
@@ -245,12 +245,16 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement
                     if (useCompactStorage)
                     {
                         if (definedCollections != null)
-                            throw new InvalidRequestException("Collection types are not supported with non composite PRIMARY KEY");
+                            throw new InvalidRequestException("Collection types are not supported with COMPACT STORAGE");
                         stmt.comparator = CFDefinition.definitionType;
                     }
                     else
                     {
-                        stmt.comparator = CompositeType.getInstance(Collections.<AbstractType<?>>singletonList(CFDefinition.definitionType));
+                        List<AbstractType<?>> types = new ArrayList<AbstractType<?>>(definedCollections == null ? 1 : 2);
+                        types.add(CFDefinition.definitionType);
+                        if (definedCollections != null)
+                            types.add(ColumnToCollectionType.getInstance(definedCollections));
+                        stmt.comparator = CompositeType.getInstance(types);
                     }
                 }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
index eb96417..346fcf8 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
@@ -23,6 +23,10 @@ import java.util.concurrent.TimeoutException;
 
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.operations.ListOperation;
+import org.apache.cassandra.cql3.operations.MapOperation;
+import org.apache.cassandra.cql3.operations.Operation;
+import org.apache.cassandra.cql3.operations.SetOperation;
 import org.apache.cassandra.db.ColumnFamily;
 import org.apache.cassandra.db.DeletionInfo;
 import org.apache.cassandra.db.IMutation;
@@ -160,9 +164,12 @@ public class DeleteStatement extends ModificationStatement
                     {
                         Pair<CFDefinition.Name, Term> p = iter.next();
                         CFDefinition.Name column = p.left;
-                        if (column.type instanceof CollectionType)
+
+                        if (column.type.isCollection())
                         {
+                            CollectionType validator = (CollectionType) column.type;
                             Term keySelected = p.right;
+
                             if (keySelected == null)
                             {
                                 // Delete the whole collection
@@ -175,13 +182,25 @@ public class DeleteStatement extends ModificationStatement
                             else
                             {
                                 builder.add(column.name.key);
-                                CollectionType.Function fct = CollectionType.Function.DISCARD_KEY;
                                 List<Term> args = Collections.singletonList(keySelected);
 
-                                if (column.type instanceof ListType)
-                                    ((ListType)column.type).execute(cf, builder, fct, args, params, group == null ? null : group.getCollection(column.name.key));
-                                else
-                                    ((CollectionType)column.type).executeFunction(cf, builder, fct, args, params);
+                                Operation op;
+                                switch (validator.kind)
+                                {
+                                    case LIST:
+                                        op = ListOperation.DiscardKey(args);
+                                        break;
+                                    case SET:
+                                        op = SetOperation.Discard(args);
+                                        break;
+                                    case MAP:
+                                        op = MapOperation.DiscardKey(keySelected);
+                                        break;
+                                    default:
+                                        throw new InvalidRequestException("Unknown collection type: " + validator.kind);
+                                }
+
+                                op.execute(cf, builder, validator, params, group == null ? null : group.getCollection(column.name.key));
                             }
                         }
                         else

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index dd729fb..97ff931 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -272,7 +272,7 @@ public class SelectStatement implements CQLStatement
         {
             // For sparse, we used to ask for 'defined columns' * 'asked limit' to account for the grouping of columns.
             // Since that doesn't work for maps/sets/lists, we use the compositesToGroup option of SliceQueryFilter.
-            // But we must preserver backward compatibility too.
+            // But we must preserve backward compatibility too.
             int multiplier = cfDef.isCompact ? 1 : cfDef.metadata.size();
             int toGroup = cfDef.isCompact ? -1 : cfDef.columns.size();
             ColumnSlice slice = new ColumnSlice(getRequestedBound(isReversed ? Bound.END : Bound.START, variables),
@@ -419,6 +419,10 @@ public class SelectStatement implements CQLStatement
         }
         else
         {
+            // Collections require doing a slice query because a given collection is a
+            // non-know set of columns, so we shouldn't get there
+            assert !cfDef.hasCollections;
+
             // Adds all columns (even if the user selected a few columns, we
             // need to query all columns to know if the row exists or not).
             // Note that when we allow IS NOT NULL in queries and if all
@@ -702,7 +706,12 @@ public class SelectStatement implements CQLStatement
                 ColumnGroupMap.Builder builder = new ColumnGroupMap.Builder(composite, cfDef.hasCollections);
 
                 for (IColumn c : row.cf)
+                {
+                    if (c.isMarkedForDelete())
+                        continue;
+
                     builder.add(c);
+                }
 
                 for (ColumnGroupMap group : builder.groups())
                     handleGroup(selection, row.key.key, group, cqlRows);
@@ -801,9 +810,13 @@ public class SelectStatement implements CQLStatement
                     // This should not happen for SPARSE
                     throw new AssertionError();
                 case COLUMN_METADATA:
-                    if (name.type instanceof CollectionType)
+                    if (name.type.isCollection())
                     {
-                         cqlRows.addColumnValue(((CollectionType)name.type).serializeForThrift(columns.getCollection(name.name.key)));
+                        List<Pair<ByteBuffer, IColumn>> collection = columns.getCollection(name.name.key);
+                        if (collection == null)
+                            cqlRows.addColumnValue(null);
+                        else
+                            cqlRows.addColumnValue(((CollectionType)name.type).serializeForThrift(collection));
                         break;
                     }
                     IColumn c = columns.getSimple(name.name.key);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
index dc670dc..f84875a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
@@ -17,8 +17,6 @@
  */
 package org.apache.cassandra.cql3.statements;
 
-import java.io.IOError;
-import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.*;
 import java.util.concurrent.TimeoutException;
@@ -27,17 +25,14 @@ import com.google.common.collect.ArrayListMultimap;
 
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.operations.Operation;
 import org.apache.cassandra.db.*;
-import org.apache.cassandra.db.filter.QueryPath;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.service.ClientState;
-import org.apache.cassandra.service.StorageProxy;
 import org.apache.cassandra.thrift.InvalidRequestException;
 import org.apache.cassandra.thrift.UnavailableException;
-import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.Pair;
 
-import static org.apache.cassandra.cql.QueryProcessor.validateColumnName;
 import static org.apache.cassandra.cql.QueryProcessor.validateKey;
 
 import static org.apache.cassandra.thrift.ThriftValidation.validateColumnFamily;
@@ -52,7 +47,7 @@ public class UpdateStatement extends ModificationStatement
     private CFDefinition cfDef;
     private final List<Pair<ColumnIdentifier, Operation>> columns;
     private final List<ColumnIdentifier> columnNames;
-    private final List<Value> columnValues;
+    private final List<Operation> columnOperations;
     private final List<Relation> whereClause;
 
     private final ArrayListMultimap<CFDefinition.Name, Operation> processedColumns = ArrayListMultimap.create();
@@ -77,7 +72,7 @@ public class UpdateStatement extends ModificationStatement
         this.columns = columns;
         this.whereClause = whereClause;
         this.columnNames = null;
-        this.columnValues = null;
+        this.columnOperations = null;
     }
 
     /**
@@ -87,18 +82,18 @@ public class UpdateStatement extends ModificationStatement
      *
      * @param name column family being operated on
      * @param columnNames list of column names
-     * @param columnValues list of column values (corresponds to names)
+     * @param columnOperations list of column 'set' operations (corresponds to names)
      * @param attrs additional attributes for statement (CL, timestamp, timeToLive)
      */
     public UpdateStatement(CFName name,
                            Attributes attrs,
                            List<ColumnIdentifier> columnNames,
-                           List<Value> columnValues)
+                           List<Operation> columnOperations)
     {
         super(name, attrs);
 
         this.columnNames = columnNames;
-        this.columnValues = columnValues;
+        this.columnOperations = columnOperations;
         this.whereClause = null;
         this.columns = null;
     }
@@ -151,11 +146,7 @@ public class UpdateStatement extends ModificationStatement
             if (!(name.type instanceof ListType))
                 continue;
 
-            if (value == null || value.type != Operation.Type.FUNCTION)
-                continue;
-
-            Operation.Function fOp = (Operation.Function)value;
-            if (fOp.fct.needsReading)
+            if (value.requiresRead())
             {
                 needsReading = true;
                 break;
@@ -176,12 +167,6 @@ public class UpdateStatement extends ModificationStatement
     /**
      * Compute a row mutation for a single key
      *
-     * @param cfDef column family being operated on
-     * @param clientState user/session state
-     * @param key key to change
-     * @param builder ongoing column name accumulator for the current statement
-     * @param variables positional values
-     *
      * @return row mutation
      *
      * @throws InvalidRequestException on the wrong request
@@ -202,20 +187,18 @@ public class UpdateStatement extends ModificationStatement
             if (builder.componentCount() == 0)
                 throw new InvalidRequestException(String.format("Missing PRIMARY KEY part %s", cfDef.columns.values().iterator().next()));
 
-            List<Operation> value = processedColumns.get(cfDef.value);
-            if (value.isEmpty())
+            List<Operation> operation = processedColumns.get(cfDef.value);
+            if (operation.isEmpty())
                 throw new InvalidRequestException(String.format("Missing mandatory column %s", cfDef.value));
-            assert value.size() == 1;
-            hasCounterColumn = addToMutation(cf, builder, cfDef.value, value.get(0), params, null);
+            assert operation.size() == 1;
+            hasCounterColumn = addToMutation(cf, builder, cfDef.value, operation.get(0), params, null);
         }
         else
         {
             for (Map.Entry<CFDefinition.Name, Operation> entry : processedColumns.entries())
             {
                 CFDefinition.Name name = entry.getKey();
-                Operation value = entry.getValue();
-
-                hasCounterColumn |= addToMutation(cf, builder.copy().add(name.name.key), name, value, params, group == null ? null : group.getCollection(name.name.key));
+                hasCounterColumn |= addToMutation(cf, builder.copy().add(name.name.key), name, entry.getValue(), params, group == null ? null : group.getCollection(name.name.key));
             }
         }
 
@@ -225,69 +208,29 @@ public class UpdateStatement extends ModificationStatement
     private boolean addToMutation(ColumnFamily cf,
                                   ColumnNameBuilder builder,
                                   CFDefinition.Name valueDef,
-                                  Operation value,
+                                  Operation valueOperation,
                                   UpdateParameters params,
                                   List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
     {
-        switch (value.type)
-        {
-            case SET:
-                Value v = ((Operation.Set)value).value;
-                if (v instanceof Term)
-                {
-                    ByteBuffer colName = builder.build();
-                    validateColumnName(colName);
-                    ByteBuffer valueBytes = ((Term)v).getByteBuffer(valueDef.type, params.variables);
-                    cf.addColumn(params.makeColumn(colName, valueBytes));
-                }
-                else
-                {
-                    assert v instanceof Value.CollectionLiteral;
-                    Value.CollectionLiteral l = (Value.CollectionLiteral)v;
-                    l.validateType(valueDef);
 
-                    // Remove previous
-                    cf.addAtom(params.makeTombstoneForOverwrite(builder.copy().build(), builder.copy().buildAsEndOfRange()));
+        Operation.Type type = valueOperation.getType();
 
-                    if (!l.isEmpty())
-                        addToMutation(cf, builder, valueDef, new Operation.Function(l.constructionFunction(), l.asList()), params, null);
-                }
-                return false;
-            case COUNTER:
-                Operation.Counter cOp = (Operation.Counter)value;
-                long val;
-                try
-                {
-                    val = ByteBufferUtil.toLong(cOp.value.getByteBuffer(LongType.instance, params.variables));
-                }
-                catch (NumberFormatException e)
-                {
-                    throw new InvalidRequestException(String.format("'%s' is an invalid value, should be a long.",
-                                cOp.value.getText()));
-                }
+        if (type == Operation.Type.COLUMN || type == Operation.Type.COUNTER)
+        {
+            if (valueDef.type.isCollection())
+                throw new InvalidRequestException("Can't apply operation on column with " + valueDef.type + " type.");
 
-                if (cOp.isSubstraction)
-                {
-                    if (val == Long.MIN_VALUE)
-                        throw new InvalidRequestException("The negation of " + val + " overflows supported integer precision (signed 8 bytes integer)");
-                    else
-                        val = -val;
-                }
-                cf.addCounter(new QueryPath(columnFamily(), null, builder.build()), val);
-                return true;
-            case FUNCTION:
-                Operation.Function fOp = (Operation.Function)value;
-                if (!(valueDef.type instanceof CollectionType))
-                    throw new InvalidRequestException(String.format("Invalid operation %s, %s is not a collection", fOp.fct, valueDef.name));
-
-                if ((valueDef.type instanceof ListType) && fOp.fct.needsReading)
-                    ((ListType)valueDef.type).execute(cf, builder, fOp.fct, fOp.arguments, params, list);
-                else
-                    ((CollectionType)valueDef.type).execute(cf, builder, fOp.fct, fOp.arguments, params);
-
-                return false;
+            valueOperation.execute(cf, builder.copy(), valueDef.type, params);
         }
-        throw new AssertionError();
+        else
+        {
+            if (!valueDef.type.isCollection())
+                throw new InvalidRequestException("Can't apply collection operation on column with " + valueDef.type + " type.");
+
+            valueOperation.execute(cf, builder.copy(), (CollectionType) valueDef.type, params, list);
+        }
+
+        return valueOperation.getType() == Operation.Type.COUNTER;
     }
 
     public ParsedStatement.Prepared prepare(CFDefinition.Name[] boundNames) throws InvalidRequestException
@@ -298,10 +241,10 @@ public class UpdateStatement extends ModificationStatement
         {
             for (Pair<ColumnIdentifier, Operation> column : columns)
             {
-                if (column.right.type == Operation.Type.COUNTER)
+                if (column.right.getType() == Operation.Type.COUNTER)
                     hasCommutativeOperation = true;
 
-                if (hasCommutativeOperation && column.right.type != Operation.Type.COUNTER)
+                if (hasCommutativeOperation && column.right.getType() != Operation.Type.COUNTER)
                     throw new InvalidRequestException("Mix of counter and non-counter operations is not allowed.");
             }
         }
@@ -317,7 +260,7 @@ public class UpdateStatement extends ModificationStatement
         {
             // Created from an INSERT
             // Don't hate, validate.
-            if (columnNames.size() != columnValues.size())
+            if (columnNames.size() != columnOperations.size())
                 throw new InvalidRequestException("unmatched column names/values");
             if (columnNames.size() < 1)
                 throw new InvalidRequestException("no columns specified for INSERT");
@@ -328,8 +271,8 @@ public class UpdateStatement extends ModificationStatement
                 if (name == null)
                     throw new InvalidRequestException(String.format("Unknown identifier %s", columnNames.get(i)));
 
-                Value value = columnValues.get(i);
-                for (Term t : value.asList())
+                Operation operation = columnOperations.get(i);
+                for (Term t : operation.getValues())
                     if (t.isBindMarker())
                         boundNames[t.bindIndex] = name;
 
@@ -339,15 +282,15 @@ public class UpdateStatement extends ModificationStatement
                     case COLUMN_ALIAS:
                         if (processedKeys.containsKey(name.name))
                             throw new InvalidRequestException(String.format("Multiple definitions found for PRIMARY KEY part %s", name));
-                        if (!(value instanceof Term))
+                        if (operation.getType() != Operation.Type.COLUMN)
                             throw new InvalidRequestException(String.format("Invalid definition for %s, not a collection type", name));
-                        processedKeys.put(name.name, Collections.singletonList((Term)value));
+                        processedKeys.put(name.name, operation.getValues());
                         break;
                     case VALUE_ALIAS:
                     case COLUMN_METADATA:
                         if (processedColumns.containsKey(name))
                             throw new InvalidRequestException(String.format("Multiple definitions found for column %s", name));
-                        processedColumns.put(name, new Operation.Set(value));
+                        processedColumns.put(name, operation);
                         break;
                 }
             }
@@ -369,11 +312,11 @@ public class UpdateStatement extends ModificationStatement
                     case VALUE_ALIAS:
                     case COLUMN_METADATA:
                         for (Operation op : processedColumns.get(name))
-                            if (op.type != Operation.Type.FUNCTION)
+                            if (op.getType() == Operation.Type.COLUMN)
                                 throw new InvalidRequestException(String.format("Multiple definitions found for column %s", name));
 
                         Operation op = entry.right;
-                        for (Term t : op.allTerms())
+                        for (Term t : op.getValues())
                             if (t.isBindMarker())
                                 boundNames[t.bindIndex] = name;
                         processedColumns.put(name, op);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/db/marshal/AbstractType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractType.java b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
index 148138a..2aa9578 100644
--- a/src/java/org/apache/cassandra/db/marshal/AbstractType.java
+++ b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
@@ -226,6 +226,11 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>
         validate(bytes);
     }
 
+    public boolean isCollection()
+    {
+        return false;
+    }
+
     /**
      * This must be overriden by subclasses if necessary so that for any
      * AbstractType, this == TypeParser.parse(toString()).

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/db/marshal/CollectionType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/CollectionType.java b/src/java/org/apache/cassandra/db/marshal/CollectionType.java
index ab8f15b..d50fc7d 100644
--- a/src/java/org/apache/cassandra/db/marshal/CollectionType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CollectionType.java
@@ -45,26 +45,6 @@ public abstract class CollectionType extends AbstractType<ByteBuffer>
         MAP, SET, LIST
     }
 
-    public enum Function
-    {
-        APPEND       (false, Kind.LIST),
-        PREPEND      (false, Kind.LIST),
-        SET          ( true, Kind.LIST, Kind.MAP),
-        ADD          (false, Kind.SET),
-        DISCARD_LIST ( true, Kind.LIST),
-        DISCARD_SET  (false, Kind.SET),
-        DISCARD_KEY  ( true, Kind.LIST, Kind.MAP);
-
-        public final boolean needsReading;
-        public final EnumSet<Kind> validReceivers;
-
-        private Function(boolean needsReading, Kind ... validReceivers)
-        {
-            this.needsReading = needsReading;
-            this.validReceivers = EnumSet.copyOf(Arrays.asList(validReceivers));
-        }
-    }
-
     public final Kind kind;
 
     protected CollectionType(Kind kind)
@@ -72,19 +52,10 @@ public abstract class CollectionType extends AbstractType<ByteBuffer>
         this.kind = kind;
     }
 
-    protected abstract AbstractType<?> nameComparator();
-    protected abstract AbstractType<?> valueComparator();
-    protected abstract void appendToStringBuilder(StringBuilder sb);
-
-    public void execute(ColumnFamily cf, ColumnNameBuilder fullPath, Function fct, List<Term> args, UpdateParameters params) throws InvalidRequestException
-    {
-        if (!fct.validReceivers.contains(kind))
-            throw new InvalidRequestException(String.format("Invalid operation %s for %s collection", fct, kind));
-
-        executeFunction(cf, fullPath, fct, args, params);
-    }
+    public abstract AbstractType<?> nameComparator();
+    public abstract AbstractType<?> valueComparator();
 
-    public abstract void executeFunction(ColumnFamily cf, ColumnNameBuilder fullPath, Function fct, List<Term> args, UpdateParameters params) throws InvalidRequestException;
+    protected abstract void appendToStringBuilder(StringBuilder sb);
 
     public abstract ByteBuffer serializeForThrift(List<Pair<ByteBuffer, IColumn>> columns);
 
@@ -132,4 +103,9 @@ public abstract class CollectionType extends AbstractType<ByteBuffer>
     {
         valueComparator().validate(bytes);
     }
+
+    public boolean isCollection()
+    {
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/db/marshal/CompositeType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/CompositeType.java b/src/java/org/apache/cassandra/db/marshal/CompositeType.java
index 516c44b..dfe79e2 100644
--- a/src/java/org/apache/cassandra/db/marshal/CompositeType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CompositeType.java
@@ -196,7 +196,6 @@ public class CompositeType extends AbstractCompositeType
     public static class Builder implements ColumnNameBuilder
     {
         private final CompositeType composite;
-        private int current;
 
         private final List<ByteBuffer> components;
         private final byte[] endOfComponents;
@@ -219,15 +218,15 @@ public class CompositeType extends AbstractCompositeType
         private Builder(Builder b)
         {
             this(b.composite, new ArrayList<ByteBuffer>(b.components), Arrays.copyOf(b.endOfComponents, b.endOfComponents.length));
-            this.current = b.current;
             this.serializedSize = b.serializedSize;
         }
 
         public Builder add(Term t, Relation.Type op, List<ByteBuffer> variables) throws InvalidRequestException
         {
-            if (current >= composite.types.size())
+            if (components.size() >= composite.types.size())
                 throw new IllegalStateException("Composite column is already fully constructed");
 
+            int current = components.size();
             AbstractType currentType = composite.types.get(current);
             ByteBuffer buffer = t.getByteBuffer(currentType, variables);
             components.add(buffer);
@@ -254,23 +253,23 @@ public class CompositeType extends AbstractCompositeType
                     endOfComponents[current] = (byte) 0;
                     break;
             }
-            ++current;
             return this;
         }
 
         public Builder add(ByteBuffer bb)
         {
+            int current = components.size();
             if (current >= composite.types.size())
                 throw new IllegalStateException("Composite column is already fully constructed");
 
             components.add(bb);
-            endOfComponents[current++] = (byte) 0;
+            endOfComponents[current] = (byte) 0;
             return this;
         }
 
         public int componentCount()
         {
-            return current;
+            return components.size();
         }
 
         public ByteBuffer build()
@@ -286,10 +285,10 @@ public class CompositeType extends AbstractCompositeType
 
         public ByteBuffer buildAsEndOfRange()
         {
-            if (current >= composite.types.size())
+            if (components.size() >= composite.types.size())
                 throw new IllegalStateException("Composite column is already fully constructed");
 
-            if (current == 0)
+            if (components.isEmpty())
                 return ByteBufferUtil.EMPTY_BYTE_BUFFER;
 
             ByteBuffer bb = build();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/db/marshal/ListType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/ListType.java b/src/java/org/apache/cassandra/db/marshal/ListType.java
index 8ad4590..ad1211d 100644
--- a/src/java/org/apache/cassandra/db/marshal/ListType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ListType.java
@@ -19,64 +19,18 @@ package org.apache.cassandra.db.marshal;
 
 import java.nio.ByteBuffer;
 import java.util.*;
-import java.util.concurrent.atomic.AtomicReference;
 
-import org.apache.cassandra.cql3.ColumnNameBuilder;
-import org.apache.cassandra.cql3.Term;
-import org.apache.cassandra.cql3.UpdateParameters;
-import org.apache.cassandra.db.ColumnFamily;
 import org.apache.cassandra.db.IColumn;
 import org.apache.cassandra.config.ConfigurationException;
-import org.apache.cassandra.thrift.InvalidRequestException;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.Pair;
-import org.apache.cassandra.utils.UUIDGen;
 
 public class ListType extends CollectionType
 {
     // interning instances
     private static final Map<AbstractType<?>, ListType> instances = new HashMap<AbstractType<?>, ListType>();
 
-    // Our reference time (1 jan 2010, 00:00:00) in milliseconds.
-    private static final long REFERENCE_TIME = 1262304000000L;
-
-    /*
-     * For prepend, we need to be able to generate unique but decreasing time
-     * UUID, which is a bit challenging. To do that, given a time in milliseconds,
-     * we adds a number represening the 100-nanoseconds precision and make sure
-     * that within the same millisecond, that number is always increasing. We
-     * do rely on the fact that the user will only provide decreasing
-     * milliseconds timestamp for that purpose.
-     */
-    private static class PrecisionTime
-    {
-        public final long millis;
-        public final int nanos;
-
-        public PrecisionTime(long millis, int nanos)
-        {
-            this.millis = millis;
-            this.nanos = nanos;
-        }
-    }
-
-    private static final AtomicReference<PrecisionTime> last = new AtomicReference<PrecisionTime>(new PrecisionTime(Long.MAX_VALUE, 0));
-
-    private static PrecisionTime getNextTime(long millis)
-    {
-        while (true)
-        {
-            PrecisionTime current = last.get();
-            assert millis <= current.millis;
-            PrecisionTime next = millis < current.millis
-                               ? new PrecisionTime(millis, 0)
-                               : new PrecisionTime(millis, current.nanos + 1);
-            if (last.compareAndSet(current, next))
-                return next;
-        }
-    }
-
     public final AbstractType<?> elements;
 
     public static ListType getInstance(TypeParser parser) throws ConfigurationException
@@ -105,12 +59,12 @@ public class ListType extends CollectionType
         this.elements = elements;
     }
 
-    protected AbstractType<?> nameComparator()
+    public AbstractType<?> nameComparator()
     {
         return TimeUUIDType.instance;
     }
 
-    protected AbstractType<?> valueComparator()
+    public AbstractType<?> valueComparator()
     {
         return elements;
     }
@@ -120,111 +74,6 @@ public class ListType extends CollectionType
         sb.append(getClass().getName()).append(TypeParser.stringifyTypeParameters(Collections.<AbstractType<?>>singletonList(elements)));
     }
 
-    public void executeFunction(ColumnFamily cf, ColumnNameBuilder fullPath, Function fct, List<Term> args, UpdateParameters params) throws InvalidRequestException
-    {
-        switch (fct)
-        {
-            case APPEND:
-                doAppend(cf, fullPath, args, params);
-                break;
-            case PREPEND:
-                doPrepend(cf, fullPath, args, params);
-                break;
-            default:
-                throw new AssertionError("Unsupported function " + fct);
-        }
-    }
-
-    public void execute(ColumnFamily cf, ColumnNameBuilder fullPath, Function fct, List<Term> args, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
-    {
-        switch (fct)
-        {
-            case SET:
-                doSet(cf, fullPath, validateIdx(fct, args.get(0), list), args.get(1), params, list);
-                break;
-            case DISCARD_LIST:
-                // If list is empty, do nothing
-                if (list != null)
-                    doDiscard(cf, fullPath, args, params, list);
-                break;
-            case DISCARD_KEY:
-                doDiscardIdx(cf, fullPath, validateIdx(fct, args.get(0), list), params, list);
-                break;
-            default:
-                throw new AssertionError();
-        }
-    }
-
-    private int validateIdx(Function fct, Term value, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
-    {
-        try
-        {
-            if (value.getType() != Term.Type.INTEGER)
-                throw new InvalidRequestException(String.format("Invalid argument %s for %s, must be an integer", value.getText(), fct));
-            int idx = Integer.parseInt(value.getText());
-            if (list == null || list.size() <= idx)
-                throw new InvalidRequestException(String.format("Invalid index %d, list has size %d", idx, list == null ? 0 : list.size()));
-            return idx;
-        }
-        catch (NumberFormatException e)
-        {
-            // This should not happen, unless we screwed up the parser
-            throw new RuntimeException();
-        }
-    }
-
-    private void doPrepend(ColumnFamily cf, ColumnNameBuilder builder, List<Term> values, UpdateParameters params) throws InvalidRequestException
-    {
-        long time = REFERENCE_TIME - (System.currentTimeMillis() - REFERENCE_TIME);
-        // We do the loop in reverse order because getNext() will create increasing time but we want the last
-        // value in the prepended list to have the lower time
-        for (int i = values.size() - 1; i >= 0; i--)
-        {
-            ColumnNameBuilder b = i == 0 ? builder : builder.copy();
-            PrecisionTime pt = getNextTime(time);
-            ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(pt.millis, pt.nanos));
-            ByteBuffer name = b.add(uuid).build();
-            cf.addColumn(params.makeColumn(name, values.get(i).getByteBuffer(elements, params.variables)));
-        }
-    }
-
-    private void doAppend(ColumnFamily cf, ColumnNameBuilder builder, List<Term> values, UpdateParameters params) throws InvalidRequestException
-    {
-        for (int i = 0; i < values.size(); i++)
-        {
-            ColumnNameBuilder b = i == values.size() - 1 ? builder : builder.copy();
-            ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes());
-            ByteBuffer name = b.add(uuid).build();
-            cf.addColumn(params.makeColumn(name, values.get(i).getByteBuffer(elements, params.variables)));
-        }
-    }
-
-    public void doSet(ColumnFamily cf, ColumnNameBuilder builder, int idx, Term value, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
-    {
-        ByteBuffer name = list.get(idx).right.name();
-        cf.addColumn(params.makeColumn(name, value.getByteBuffer(elements, params.variables)));
-    }
-
-    public void doDiscard(ColumnFamily cf, ColumnNameBuilder builder, List<Term> values, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
-    {
-        Set<ByteBuffer> toDiscard = new HashSet<ByteBuffer>();
-        for (Term value : values)
-            toDiscard.add(value.getByteBuffer(elements, params.variables));
-
-        for (Pair<ByteBuffer, IColumn> p : list)
-        {
-            IColumn c = p.right;
-            if (toDiscard.contains(c.value()))
-                cf.addColumn(params.makeTombstone(c.name()));
-        }
-    }
-
-    public void doDiscardIdx(ColumnFamily cf, ColumnNameBuilder builder, int idx, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
-    {
-        ByteBuffer name = list.get(idx).right.name();
-        cf.addColumn(params.makeTombstone(name));
-    }
-
     public ByteBuffer serializeForThrift(List<Pair<ByteBuffer, IColumn>> columns)
     {
         List<Object> l = new ArrayList<Object>(columns.size());

http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/db/marshal/MapType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/MapType.java b/src/java/org/apache/cassandra/db/marshal/MapType.java
index 8e29520..a5a6caa 100644
--- a/src/java/org/apache/cassandra/db/marshal/MapType.java
+++ b/src/java/org/apache/cassandra/db/marshal/MapType.java
@@ -19,19 +19,13 @@ package org.apache.cassandra.db.marshal;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
-import java.util.Iterator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import org.apache.cassandra.cql3.ColumnNameBuilder;
-import org.apache.cassandra.cql3.Term;
-import org.apache.cassandra.cql3.UpdateParameters;
-import org.apache.cassandra.db.ColumnFamily;
 import org.apache.cassandra.db.IColumn;
 import org.apache.cassandra.config.ConfigurationException;
-import org.apache.cassandra.thrift.InvalidRequestException;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.Pair;
@@ -72,12 +66,12 @@ public class MapType extends CollectionType
         this.values = values;
     }
 
-    protected AbstractType<?> nameComparator()
+    public AbstractType<?> nameComparator()
     {
         return keys;
     }
 
-    protected AbstractType<?> valueComparator()
+    public AbstractType<?> valueComparator()
     {
         return values;
     }
@@ -87,39 +81,6 @@ public class MapType extends CollectionType
         sb.append(getClass().getName()).append(TypeParser.stringifyTypeParameters(Arrays.asList(keys, values)));
     }
 
-    public void executeFunction(ColumnFamily cf, ColumnNameBuilder fullPath, Function fct, List<Term> args, UpdateParameters params) throws InvalidRequestException
-    {
-        switch (fct)
-        {
-            case SET:
-                doPut(cf, fullPath, args, params);
-                break;
-            case DISCARD_KEY:
-                doDiscard(cf, fullPath, args.get(0), params);
-                break;
-            default:
-                throw new AssertionError("Unsupported function " + fct);
-        }
-    }
-
-    private void doPut(ColumnFamily cf, ColumnNameBuilder builder, List<Term> args, UpdateParameters params) throws InvalidRequestException
-    {
-        assert args.size() % 2 == 0;
-        Iterator<Term> iter = args.iterator();
-        while (iter.hasNext())
-        {
-            ByteBuffer name = builder.copy().add(iter.next().getByteBuffer(keys, params.variables)).build();
-            ByteBuffer value = iter.next().getByteBuffer(values, params.variables);
-            cf.addColumn(params.makeColumn(name, value));
-        }
-    }
-
-    private void doDiscard(ColumnFamily cf, ColumnNameBuilder builder, Term value, UpdateParameters params) throws InvalidRequestException
-    {
-        ByteBuffer name = builder.add(value.getByteBuffer(keys, params.variables)).build();
-        cf.addColumn(params.makeTombstone(name));
-    }
-
     public ByteBuffer serializeForThrift(List<Pair<ByteBuffer, IColumn>> columns)
     {
         Map<String, Object> m = new LinkedHashMap<String, Object>();