cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From slebre...@apache.org
Subject [2/5] CQL3 refactor to allow conversion function
Date Fri, 08 Feb 2013 17:45:59 GMT
http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/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 8f74b72..4491394 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -66,7 +66,7 @@ public class SelectStatement implements CQLStatement
     private final int boundTerms;
     public final CFDefinition cfDef;
     public final Parameters parameters;
-    private final List<Pair<CFDefinition.Name, Selector>> selectedNames = new ArrayList<Pair<CFDefinition.Name, Selector>>(); // empty => wildcard
+    private final Selection selection;
 
     private final Restriction[] keyRestrictions;
     private final Restriction[] columnRestrictions;
@@ -95,10 +95,11 @@ public class SelectStatement implements CQLStatement
         }
     };
 
-    public SelectStatement(CFDefinition cfDef, int boundTerms, Parameters parameters)
+    public SelectStatement(CFDefinition cfDef, int boundTerms, Parameters parameters, Selection selection)
     {
         this.cfDef = cfDef;
         this.boundTerms = boundTerms;
+        this.selection = selection;
         this.keyRestrictions = new Restriction[cfDef.keys.size()];
         this.columnRestrictions = new Restriction[cfDef.columns.size()];
         this.parameters = parameters;
@@ -342,13 +343,13 @@ public class SelectStatement implements CQLStatement
             if (builder.remainingCount() == 1)
             {
                 for (Term t : r.eqValues)
-                    keys.add(builder.copy().add(t, Relation.Type.EQ, variables).build());
+                    keys.add(builder.copy().add(t.bindAndGet(variables)).build());
             }
             else
             {
                 if (r.eqValues.size() > 1)
                     throw new InvalidRequestException("IN is only supported on the last column of the partition key");
-                builder.add(r.eqValues.get(0), Relation.Type.EQ, variables);
+                builder.add(r.eqValues.get(0).bindAndGet(variables));
             }
         }
         return keys;
@@ -371,29 +372,8 @@ public class SelectStatement implements CQLStatement
         if (t == null)
             return p.getMinimumToken();
 
-        if (!t.isToken)
-        {
-            try
-            {
-                String text = t.getText();
-                p.getTokenFactory().validate(text);
-                return p.getTokenFactory().fromString(text);
-            }
-            catch (ConfigurationException e)
-            {
-                throw new InvalidRequestException(e.getMessage());
-            }
-        }
-
-        assert t.isToken;
-        ColumnNameBuilder builder = cfDef.getKeyNameBuilder();
-        // We know all keyRestriction must be set
-        for (CFDefinition.Name name : cfDef.keys.values())
-        {
-            Restriction r = keyRestrictions[name.position];
-            builder.add(r.isEquality() ? r.eqValues.get(0) : r.bound(b), Relation.Type.EQ, variables);
-        }
-        return p.getToken(builder.build());
+        ByteBuffer value = t.bindAndGet(variables);
+        return p.getTokenFactory().fromByteArray(value);
     }
 
     private boolean includeKeyBound(Bound b)
@@ -429,11 +409,6 @@ public class SelectStatement implements CQLStatement
         return false;
     }
 
-    private boolean isWildcard()
-    {
-        return selectedNames.isEmpty();
-    }
-
     private SortedSet<ByteBuffer> getRequestedColumns(List<ByteBuffer> variables) throws InvalidRequestException
     {
         assert !isColumnRange();
@@ -452,14 +427,14 @@ public class SelectStatement implements CQLStatement
                 {
                     Term v = iter.next();
                     ColumnNameBuilder b = iter.hasNext() ? builder.copy() : builder;
-                    ByteBuffer cname = b.add(v, Relation.Type.EQ, variables).build();
+                    ByteBuffer cname = b.add(v.bindAndGet(variables)).build();
                     columns.add(cname);
                 }
                 return columns;
             }
             else
             {
-                builder.add(r.eqValues.get(0), Relation.Type.EQ, variables);
+                builder.add(r.eqValues.get(0).bindAndGet(variables));
             }
         }
 
@@ -485,8 +460,8 @@ public class SelectStatement implements CQLStatement
                 columns.add(builder.copy().add(ByteBufferUtil.EMPTY_BYTE_BUFFER).build());
 
                 // selected columns
-                for (Pair<CFDefinition.Name, Selector> p : getExpandedSelection())
-                    columns.add(builder.copy().add(p.right.id().key).build());
+                for (ColumnIdentifier id : selection.regularColumnsToFetch())
+                    columns.add(builder.copy().add(id.key).build());
             }
             else
             {
@@ -536,13 +511,13 @@ public class SelectStatement implements CQLStatement
             if (r.isEquality())
             {
                 assert r.eqValues.size() == 1;
-                builder.add(r.eqValues.get(0), Relation.Type.EQ, variables);
+                builder.add(r.eqValues.get(0).bindAndGet(variables));
             }
             else
             {
                 Term t = r.bound(b);
                 assert t != null;
-                return builder.add(t, r.getRelation(eocBound, b), variables).build();
+                return builder.add(t.bindAndGet(variables), r.getRelation(eocBound, b)).build();
             }
         }
         // Means no relation at all or everything was an equal
@@ -569,7 +544,7 @@ public class SelectStatement implements CQLStatement
             {
                 for (Term t : restriction.eqValues)
                 {
-                    ByteBuffer value = t.getByteBuffer(name.type, variables);
+                    ByteBuffer value = t.bindAndGet(variables);
                     if (value.remaining() > 0xFFFF)
                         throw new InvalidRequestException("Index expression values may not be larger than 64K");
                     expressions.add(new IndexExpression(name.name.key, IndexOperator.EQ, value));
@@ -581,7 +556,7 @@ public class SelectStatement implements CQLStatement
                 {
                     if (restriction.bound(b) != null)
                     {
-                        ByteBuffer value = restriction.bound(b).getByteBuffer(name.type, variables);
+                        ByteBuffer value = restriction.bound(b).bindAndGet(variables);
                         if (value.remaining() > 0xFFFF)
                             throw new InvalidRequestException("Index expression values may not be larger than 64K");
                         expressions.add(new IndexExpression(name.name.key, restriction.getIndexOperator(b), value));
@@ -592,91 +567,6 @@ public class SelectStatement implements CQLStatement
         return expressions;
     }
 
-    private List<Pair<CFDefinition.Name, Selector>> getExpandedSelection()
-    {
-        if (selectedNames.isEmpty())
-        {
-            List<Pair<CFDefinition.Name, Selector>> selection = new ArrayList<Pair<CFDefinition.Name, Selector>>();
-            for (CFDefinition.Name name : cfDef)
-                selection.add(Pair.<CFDefinition.Name, Selector>create(name, name.name));
-            return selection;
-        }
-        else
-        {
-            return selectedNames;
-        }
-    }
-
-    private ByteBuffer value(IColumn c)
-    {
-        return (c instanceof CounterColumn)
-             ? ByteBufferUtil.bytes(CounterContext.instance().total(c.value()))
-             : c.value();
-    }
-
-    private void addReturnValue(ResultSet cqlRows, Selector s, IColumn c)
-    {
-        if (c == null || c.isMarkedForDelete())
-        {
-            cqlRows.addColumnValue(null);
-            return;
-        }
-
-        if (s.hasFunction())
-        {
-            switch (s.function())
-            {
-                case WRITE_TIME:
-                    cqlRows.addColumnValue(ByteBufferUtil.bytes(c.timestamp()));
-                    return;
-                case TTL:
-                    if (c instanceof ExpiringColumn)
-                    {
-                        int ttl = ((ExpiringColumn)c).getLocalDeletionTime() - (int) (System.currentTimeMillis() / 1000);
-                        cqlRows.addColumnValue(ByteBufferUtil.bytes(ttl));
-                    }
-                    else
-                    {
-                        cqlRows.addColumnValue(null);
-                    }
-                    return;
-            }
-        }
-
-        addReturnValue(cqlRows, s, value(c));
-    }
-
-    private void addReturnValue(ResultSet cqlRows, Selector s, ByteBuffer value)
-    {
-        if (value != null && s.hasFunction())
-        {
-            switch (s.function())
-            {
-                case DATE_OF:
-                    value = DateType.instance.decompose(new Date(UUIDGen.unixTimestamp(UUIDGen.getUUID(value))));
-                    break;
-                case UNIXTIMESTAMP_OF:
-                    value = ByteBufferUtil.bytes(UUIDGen.unixTimestamp(UUIDGen.getUUID(value)));
-                    break;
-                case WRITE_TIME:
-                case TTL:
-                    throw new AssertionError("Cannot return the timestamp or ttl of a value");
-            }
-        }
-        cqlRows.addColumnValue(value);
-    }
-
-    private ResultSet createResult(List<Pair<CFDefinition.Name, Selector>> selection)
-    {
-        List<ColumnSpecification> names = new ArrayList<ColumnSpecification>(selection.size());
-        for (Pair<CFDefinition.Name, Selector> p : selection)
-        {
-            names.add(p.right.hasFunction()
-                      ? new ColumnSpecification(p.left.ksName, p.left.cfName, new ColumnIdentifier(p.right.toString(), true), p.right.function().resultType)
-                      : p.left);
-        }
-        return new ResultSet(names);
-    }
 
     private Iterable<IColumn> columnsInOrder(final ColumnFamily cf, final List<ByteBuffer> variables) throws InvalidRequestException
     {
@@ -688,7 +578,7 @@ public class SelectStatement implements CQLStatement
 
         ColumnNameBuilder builder = cfDef.getColumnNameBuilder();
         for (int i = 0; i < columnRestrictions.length - 1; i++)
-            builder.add(columnRestrictions[i].eqValues.get(0), Relation.Type.EQ, variables);
+            builder.add(columnRestrictions[i].eqValues.get(0).bindAndGet(variables));
 
         final List<ByteBuffer> requested = new ArrayList<ByteBuffer>(last.eqValues.size());
         Iterator<Term> iter = last.eqValues.iterator();
@@ -696,7 +586,7 @@ public class SelectStatement implements CQLStatement
         {
             Term t = iter.next();
             ColumnNameBuilder b = iter.hasNext() ? builder.copy() : builder;
-            requested.add(b.add(t, Relation.Type.EQ, variables).build());
+            requested.add(b.add(t.bindAndGet(variables)).build());
         }
 
         return new Iterable<IColumn>()
@@ -720,9 +610,7 @@ public class SelectStatement implements CQLStatement
 
     private ResultSet process(List<Row> rows, List<ByteBuffer> variables) throws InvalidRequestException
     {
-        List<Pair<CFDefinition.Name, Selector>> selection = getExpandedSelection();
-        ResultSet cqlRows = createResult(selection);
-
+        Selection.ResultSetBuilder result = selection.resultSetBuilder();
         for (org.apache.cassandra.db.Row row : rows)
         {
             // Not columns match the query, skip
@@ -755,30 +643,29 @@ public class SelectStatement implements CQLStatement
                     else if (sliceRestriction != null)
                     {
                         // For dynamic CF, the column could be out of the requested bounds, filter here
-                        if (!sliceRestriction.isInclusive(Bound.START) && c.name().equals(sliceRestriction.bound(Bound.START).getByteBuffer(cfDef.cfm.comparator, variables)))
+                        if (!sliceRestriction.isInclusive(Bound.START) && c.name().equals(sliceRestriction.bound(Bound.START).bindAndGet(variables)))
                             continue;
-                        if (!sliceRestriction.isInclusive(Bound.END) && c.name().equals(sliceRestriction.bound(Bound.END).getByteBuffer(cfDef.cfm.comparator, variables)))
+                        if (!sliceRestriction.isInclusive(Bound.END) && c.name().equals(sliceRestriction.bound(Bound.END).bindAndGet(variables)))
                             continue;
                     }
 
+                    result.newRow();
                     // Respect selection order
-                    for (Pair<CFDefinition.Name, Selector> p : selection)
+                    for (CFDefinition.Name name : selection.getColumnsList())
                     {
-                        CFDefinition.Name name = p.left;
-                        Selector selector = p.right;
                         switch (name.kind)
                         {
                             case KEY_ALIAS:
-                                addReturnValue(cqlRows, selector, keyComponents[name.position]);
+                                result.add(keyComponents[name.position]);
                                 break;
                             case COLUMN_ALIAS:
                                 ByteBuffer val = cfDef.isComposite
                                                ? (name.position < components.length ? components[name.position] : null)
                                                : c.name();
-                                addReturnValue(cqlRows, selector, val);
+                                result.add(val);
                                 break;
                             case VALUE_ALIAS:
-                                addReturnValue(cqlRows, selector, c);
+                                result.add(c);
                                 break;
                             case COLUMN_METADATA:
                                 // This should not happen for compact CF
@@ -805,7 +692,7 @@ public class SelectStatement implements CQLStatement
                 }
 
                 for (ColumnGroupMap group : builder.groups())
-                    handleGroup(selection, row.key.key, keyComponents, group, cqlRows);
+                    handleGroup(selection, result, row.key.key, keyComponents, group);
             }
             else
             {
@@ -813,24 +700,20 @@ public class SelectStatement implements CQLStatement
                     continue;
 
                 // Static case: One cqlRow for all columns
-                // Respect selection order
-                for (Pair<CFDefinition.Name, Selector> p : selection)
+                result.newRow();
+                for (CFDefinition.Name name : selection.getColumnsList())
                 {
-                    CFDefinition.Name name = p.left;
-                    Selector selector = p.right;
                     if (name.kind == CFDefinition.Name.Kind.KEY_ALIAS)
-                    {
-                        addReturnValue(cqlRows, selector, keyComponents[name.position]);
-                        continue;
-                    }
-
-                    IColumn c = row.cf.getColumn(name.name.key);
-                    addReturnValue(cqlRows, selector, c);
+                        result.add(keyComponents[name.position]);
+                    else
+                        result.add(row.cf.getColumn(name.name.key));
                 }
             }
         }
 
-        orderResults(selection, cqlRows);
+        ResultSet cqlRows = result.build();
+
+        orderResults(cqlRows);
 
         // Internal calls always return columns in the comparator order, even when reverse was set
         if (isReversed)
@@ -844,7 +727,7 @@ public class SelectStatement implements CQLStatement
     /**
      * Orders results when multiple keys are selected (using IN)
      */
-    private void orderResults(List<Pair<CFDefinition.Name, Selector>> selection, ResultSet cqlRows)
+    private void orderResults(ResultSet cqlRows)
     {
         // There is nothing to do if
         //   a. there are no results,
@@ -859,7 +742,7 @@ public class SelectStatement implements CQLStatement
         if (parameters.orderings.size() == 1)
         {
             CFDefinition.Name ordering = cfDef.get(parameters.orderings.keySet().iterator().next());
-            Collections.sort(cqlRows.rows, new SingleColumnComparator(getColumnPositionInSelect(selection, ordering), ordering.type));
+            Collections.sort(cqlRows.rows, new SingleColumnComparator(getColumnPositionInResultSet(cqlRows, ordering), ordering.type));
             return;
         }
 
@@ -874,18 +757,18 @@ public class SelectStatement implements CQLStatement
         {
             CFDefinition.Name orderingColumn = cfDef.get(identifier);
             types.add(orderingColumn.type);
-            positions[idx++] = getColumnPositionInSelect(selection, orderingColumn);
+            positions[idx++] = getColumnPositionInResultSet(cqlRows, orderingColumn);
         }
 
         Collections.sort(cqlRows.rows, new CompositeComparator(types, positions));
     }
 
     // determine position of column in the select clause
-    private int getColumnPositionInSelect(List<Pair<CFDefinition.Name, Selector>> selection, CFDefinition.Name columnName)
+    private int getColumnPositionInResultSet(ResultSet rs, CFDefinition.Name columnName)
     {
-        for (int i = 0; i < selection.size(); i++)
+        for (int i = 0; i < rs.metadata.names.size(); i++)
         {
-            if (selection.get(i).left.equals(columnName))
+            if (rs.metadata.names.get(i).name.equals(columnName.name))
                 return i;
         }
 
@@ -914,20 +797,19 @@ public class SelectStatement implements CQLStatement
         return true;
     }
 
-    private void handleGroup(List<Pair<CFDefinition.Name, Selector>> selection, ByteBuffer key, ByteBuffer[] keyComponents, ColumnGroupMap columns, ResultSet cqlRows)
+    private void handleGroup(Selection selection, Selection.ResultSetBuilder result, ByteBuffer key, ByteBuffer[] keyComponents, ColumnGroupMap columns) throws InvalidRequestException
     {
         // Respect requested order
-        for (Pair<CFDefinition.Name, Selector> p : selection)
+        result.newRow();
+        for (CFDefinition.Name name : selection.getColumnsList())
         {
-            CFDefinition.Name name = p.left;
-            Selector selector = p.right;
             switch (name.kind)
             {
                 case KEY_ALIAS:
-                    addReturnValue(cqlRows, selector, keyComponents[name.position]);
+                    result.add(keyComponents[name.position]);
                     break;
                 case COLUMN_ALIAS:
-                    addReturnValue(cqlRows, selector, columns.getKeyComponent(name.position));
+                    result.add(columns.getKeyComponent(name.position));
                     break;
                 case VALUE_ALIAS:
                     // This should not happen for SPARSE
@@ -939,16 +821,13 @@ public class SelectStatement implements CQLStatement
                         ByteBuffer value = collection == null
                                          ? null
                                          : ((CollectionType)name.type).serialize(collection);
-                        addReturnValue(cqlRows, selector, value);
+                        result.add(value);
                     }
                     else
                     {
-                        IColumn c = columns.getSimple(name.name.key);
-                        addReturnValue(cqlRows, selector, c);
+                        result.add(columns.getSimple(name.name.key));
                     }
                     break;
-                default:
-                    throw new AssertionError();
             }
         }
     }
@@ -971,10 +850,10 @@ public class SelectStatement implements CQLStatement
     public static class RawStatement extends CFStatement
     {
         private final Parameters parameters;
-        private final List<Selector> selectClause;
+        private final List<RawSelector> selectClause;
         private final List<Relation> whereClause;
 
-        public RawStatement(CFName cfName, Parameters parameters, List<Selector> selectClause, List<Relation> whereClause)
+        public RawStatement(CFName cfName, Parameters parameters, List<RawSelector> selectClause, List<Relation> whereClause)
         {
             super(cfName);
             this.parameters = parameters;
@@ -990,48 +869,19 @@ public class SelectStatement implements CQLStatement
                 throw new InvalidRequestException("LIMIT must be strictly positive");
 
             CFDefinition cfDef = cfm.getCfDef();
-            SelectStatement stmt = new SelectStatement(cfDef, getBoundsTerms(), parameters);
-            CFDefinition.Name[] names = new CFDefinition.Name[getBoundsTerms()];
+
+            ColumnSpecification[] names = new ColumnSpecification[getBoundsTerms()];
             IPartitioner partitioner = StorageService.getPartitioner();
 
             // Select clause
-            if (parameters.isCount)
-            {
-                if (!selectClause.isEmpty())
-                    throw new InvalidRequestException("Only COUNT(*) and COUNT(1) operations are currently supported.");
-            }
-            else
-            {
-                for (Selector t : selectClause)
-                {
-                    CFDefinition.Name name = cfDef.get(t.id());
-                    if (name == null)
-                        throw new InvalidRequestException(String.format("Undefined name %s in selection clause", t.id()));
-                    if (t.hasFunction())
-                    {
-                        if (name.type.isCollection())
-                            throw new InvalidRequestException(String.format("Function %s is not supported on collections", t.function()));
-                        switch (t.function())
-                        {
-                            case WRITE_TIME:
-                            case TTL:
-                                if (name.kind != CFDefinition.Name.Kind.COLUMN_METADATA && name.kind != CFDefinition.Name.Kind.VALUE_ALIAS)
-                                    throw new InvalidRequestException(String.format("Cannot use function %s on PRIMARY KEY part %s", t.function(), name));
-                                break;
-                            case DATE_OF:
-                            case UNIXTIMESTAMP_OF:
-                                if (!(name.type instanceof TimeUUIDType))
-                                    throw new InvalidRequestException(String.format("Function %s is only allowed on timeuuid columns", t.function()));
-                                break;
-                        }
-                    }
+            if (parameters.isCount && !selectClause.isEmpty())
+                throw new InvalidRequestException("Only COUNT(*) and COUNT(1) operations are currently supported.");
 
-                    if (t.hasKey())
-                        throw new InvalidRequestException("Selecting a list/map element by index/key is not yet supported");
+            Selection selection = selectClause.isEmpty()
+                                ? Selection.wildcard(cfDef)
+                                : Selection.fromSelectors(cfDef, selectClause);
 
-                    stmt.selectedNames.add(Pair.create(name, t));
-                }
-            }
+            SelectStatement stmt = new SelectStatement(cfDef, getBoundsTerms(), parameters, selection);
 
             /*
              * WHERE clause. For a given entity, rules are:
@@ -1047,41 +897,18 @@ public class SelectStatement implements CQLStatement
                 if (name == null)
                     throw new InvalidRequestException(String.format("Undefined name %s in where clause ('%s')", rel.getEntity(), rel));
 
-                if (rel.operator() == Relation.Type.IN)
-                {
-                    for (Term value : rel.getInValues())
-                    {
-                        if (!rel.onToken || value.isToken)
-                            value.validateType(name.toString(), name.type);
-                        else
-                            value.validateType("token of " + name.toString(), StorageService.getPartitioner().getTokenValidator());
-                        if (value.isBindMarker())
-                            names[value.bindIndex] = name;
-                    }
-                }
-                else
-                {
-                    Term value = rel.getValue();
-                    if (!rel.onToken || value.isToken)
-                        value.validateType(name.toString(), name.type);
-                    else
-                        value.validateType("token of " + name.toString(), StorageService.getPartitioner().getTokenValidator());
-                    if (value.isBindMarker())
-                        names[value.bindIndex] = name;
-                }
-
                 switch (name.kind)
                 {
                     case KEY_ALIAS:
-                        stmt.keyRestrictions[name.position] = updateRestriction(name, stmt.keyRestrictions[name.position], rel);
+                        stmt.keyRestrictions[name.position] = updateRestriction(name, stmt.keyRestrictions[name.position], rel, names);
                         break;
                     case COLUMN_ALIAS:
-                        stmt.columnRestrictions[name.position] = updateRestriction(name, stmt.columnRestrictions[name.position], rel);
+                        stmt.columnRestrictions[name.position] = updateRestriction(name, stmt.columnRestrictions[name.position], rel, names);
                         break;
                     case VALUE_ALIAS:
                         throw new InvalidRequestException(String.format("Restricting the value of a compact CF (%s) is not supported", name.name));
                     case COLUMN_METADATA:
-                        stmt.metadataRestrictions.put(name, updateRestriction(name, stmt.metadataRestrictions.get(name), rel));
+                        stmt.metadataRestrictions.put(name, updateRestriction(name, stmt.metadataRestrictions.get(name), rel, names));
                         break;
                 }
             }
@@ -1135,6 +962,7 @@ public class SelectStatement implements CQLStatement
             {
                 CFDefinition.Name cname = iter.next();
                 Restriction restriction = stmt.keyRestrictions[i];
+
                 if (restriction == null)
                 {
                     if (stmt.onToken)
@@ -1235,16 +1063,16 @@ public class SelectStatement implements CQLStatement
                 // If we order an IN query, we'll have to do a manual sort post-query. Currently, this sorting requires that we
                 // have queried the column on which we sort (TODO: we should update it to add the column on which we sort to the one
                 // queried automatically, and then removing it from the resultSet afterwards if needed)
-                if (stmt.keyIsInRelation && !stmt.selectedNames.isEmpty()) // empty means wildcard was used
+                if (stmt.keyIsInRelation && !selectClause.isEmpty()) // empty means wildcard was used
                 {
                     for (ColumnIdentifier column : stmt.parameters.orderings.keySet())
                     {
                         CFDefinition.Name name = cfDef.get(column);
 
                         boolean hasColumn = false;
-                        for (Pair<CFDefinition.Name, Selector> selectPair : stmt.selectedNames)
+                        for (RawSelector selector : selectClause)
                         {
-                            if (selectPair.left.equals(name))
+                            if (name.name.equals(selector))
                             {
                                 hasColumn = true;
                                 break;
@@ -1310,30 +1138,54 @@ public class SelectStatement implements CQLStatement
             return new ParsedStatement.Prepared(stmt, Arrays.<ColumnSpecification>asList(names));
         }
 
-        Restriction updateRestriction(CFDefinition.Name name, Restriction restriction, Relation newRel) throws InvalidRequestException
+        Restriction updateRestriction(CFDefinition.Name name, Restriction restriction, Relation newRel, ColumnSpecification[] boundNames) throws InvalidRequestException
         {
-            if (newRel.onToken && name.kind != CFDefinition.Name.Kind.KEY_ALIAS)
-                throw new InvalidRequestException(String.format("The token() function is only supported on the partition key, found on %s", name));
+            ColumnSpecification receiver = name;
+            if (newRel.onToken)
+            {
+                if (name.kind != CFDefinition.Name.Kind.KEY_ALIAS)
+                    throw new InvalidRequestException(String.format("The token() function is only supported on the partition key, found on %s", name));
+
+                receiver = new ColumnSpecification(name.ksName,
+                                                   name.cfName,
+                                                   new ColumnIdentifier("partition key token", true),
+                                                   StorageService.instance.getPartitioner().getTokenValidator());
+            }
 
             switch (newRel.operator())
             {
                 case EQ:
-                    if (restriction != null)
-                        throw new InvalidRequestException(String.format("%s cannot be restricted by more than one relation if it includes an Equal", name));
-                    restriction = new Restriction(newRel.getValue(), newRel.onToken);
+                    {
+                        if (restriction != null)
+                            throw new InvalidRequestException(String.format("%s cannot be restricted by more than one relation if it includes an Equal", name));
+                        Term t = newRel.getValue().prepare(receiver);
+                        t.collectMarkerSpecification(boundNames);
+                        restriction = new Restriction(t, newRel.onToken);
+                    }
                     break;
                 case IN:
                     if (restriction != null)
                         throw new InvalidRequestException(String.format("%s cannot be restricted by more than one reation if it includes a IN", name));
-                    restriction = new Restriction(newRel.getInValues());
+                    List<Term> inValues = new ArrayList<Term>(newRel.getInValues().size());
+                    for (Term.Raw raw : newRel.getInValues())
+                    {
+                        Term t = raw.prepare(receiver);
+                        t.collectMarkerSpecification(boundNames);
+                        inValues.add(t);
+                    }
+                    restriction = new Restriction(inValues);
                     break;
                 case GT:
                 case GTE:
                 case LT:
                 case LTE:
-                    if (restriction == null)
-                        restriction = new Restriction(newRel.onToken);
-                    restriction.setBound(name.name, newRel.operator(), newRel.getValue());
+                    {
+                        if (restriction == null)
+                            restriction = new Restriction(newRel.onToken);
+                        Term t = newRel.getValue().prepare(receiver);
+                        t.collectMarkerSpecification(boundNames);
+                        restriction.setBound(name.name, newRel.operator(), t);
+                    }
                     break;
             }
             return restriction;
@@ -1364,17 +1216,23 @@ public class SelectStatement implements CQLStatement
 
         final boolean onToken;
 
-        Restriction(List<Term> values)
+
+        Restriction(List<Term> values, boolean onToken)
         {
             this.eqValues = values;
             this.bounds = null;
             this.boundInclusive = null;
-            this.onToken = false;
+            this.onToken = onToken;
+        }
+
+        Restriction(List<Term> values)
+        {
+            this(values, false);
         }
 
         Restriction(Term value, boolean onToken)
         {
-            this(Collections.singletonList(value));
+            this(Collections.singletonList(value), onToken);
         }
 
         Restriction(boolean onToken)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/src/java/org/apache/cassandra/cql3/statements/Selection.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/Selection.java b/src/java/org/apache/cassandra/cql3/statements/Selection.java
new file mode 100644
index 0000000..a402453
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/statements/Selection.java
@@ -0,0 +1,401 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.statements;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.cql3.functions.Functions;
+import org.apache.cassandra.db.CounterColumn;
+import org.apache.cassandra.db.ExpiringColumn;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.context.CounterContext;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.Int32Type;
+import org.apache.cassandra.db.marshal.LongType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class Selection
+{
+    private static final Logger logger = LoggerFactory.getLogger(Selection.class);
+
+    private final List<CFDefinition.Name> columnsList;
+    private final List<ColumnSpecification> metadata;
+    private final boolean collectTimestamps;
+    private final boolean collectTTLs;
+
+    protected Selection(List<CFDefinition.Name> columnsList, List<ColumnSpecification> metadata, boolean collectTimestamps, boolean collectTTLs)
+    {
+        this.columnsList = columnsList;
+        this.metadata = metadata;
+        this.collectTimestamps = collectTimestamps;
+        this.collectTTLs = collectTTLs;
+    }
+
+    public static Selection wildcard(CFDefinition cfDef)
+    {
+        List<CFDefinition.Name> all = new ArrayList<CFDefinition.Name>();
+        for (CFDefinition.Name name : cfDef)
+            all.add(name);
+        return new SimpleSelection(all);
+    }
+
+    private static boolean isUsingFunction(List<RawSelector> rawSelectors)
+    {
+        for (RawSelector rawSelector : rawSelectors)
+        {
+            if (!(rawSelector instanceof ColumnIdentifier))
+                return true;
+        }
+        return false;
+    }
+
+    private static int addAndGetIndex(CFDefinition.Name name, List<CFDefinition.Name> l)
+    {
+        int idx = l.indexOf(name);
+        if (idx < 0)
+        {
+            idx = l.size();
+            l.add(name);
+        }
+        return idx;
+    }
+
+    private static Selector makeSelector(CFDefinition cfDef, RawSelector raw, List<CFDefinition.Name> names, List<ColumnSpecification> metadata) throws InvalidRequestException
+    {
+        if (raw instanceof ColumnIdentifier)
+        {
+            CFDefinition.Name name = cfDef.get((ColumnIdentifier)raw);
+            if (name == null)
+                throw new InvalidRequestException(String.format("Undefined name %s in selection clause", raw));
+            if (metadata != null)
+                metadata.add(name);
+            return new SimpleSelector(addAndGetIndex(name, names), name.type);
+        }
+        else if (raw instanceof RawSelector.WritetimeOrTTL)
+        {
+            RawSelector.WritetimeOrTTL tot = (RawSelector.WritetimeOrTTL)raw;
+            CFDefinition.Name name = cfDef.get(tot.id);
+            if (name == null)
+                throw new InvalidRequestException(String.format("Undefined name %s in selection clause", tot.id));
+            if (name.kind != CFDefinition.Name.Kind.COLUMN_METADATA && name.kind != CFDefinition.Name.Kind.VALUE_ALIAS)
+                throw new InvalidRequestException(String.format("Cannot use selection function %s on PRIMARY KEY part %s", tot.isWritetime ? "writeTime" : "ttl", name));
+            if (name.type.isCollection())
+                throw new InvalidRequestException(String.format("Cannot use selection function %s on collections", tot.isWritetime ? "writeTime" : "ttl"));
+
+            if (metadata != null)
+                metadata.add(makeWritetimeOrTTLSpec(cfDef, tot));
+            return new WritetimeOrTTLSelector(addAndGetIndex(name, names), tot.isWritetime);
+        }
+        else
+        {
+            RawSelector.WithFunction withFun = (RawSelector.WithFunction)raw;
+            List<Selector> args = new ArrayList<Selector>(withFun.args.size());
+            for (RawSelector rawArg : withFun.args)
+                args.add(makeSelector(cfDef, rawArg, names, null));
+
+            AbstractType<?> returnType = Functions.getReturnType(withFun.functionName, cfDef.cfm.ksName, cfDef.cfm.cfName);
+            ColumnSpecification spec = makeFunctionSpec(cfDef, withFun, returnType);
+            Function fun = Functions.get(withFun.functionName, args, spec);
+            if (metadata != null)
+                metadata.add(spec);
+            return new FunctionSelector(fun, args);
+        }
+    }
+
+    private static ColumnSpecification makeWritetimeOrTTLSpec(CFDefinition cfDef, RawSelector.WritetimeOrTTL tot)
+    {
+        return new ColumnSpecification(cfDef.cfm.ksName,
+                                       cfDef.cfm.cfName,
+                                       new ColumnIdentifier(tot.toString(), true),
+                                       tot.isWritetime ? LongType.instance : Int32Type.instance);
+    }
+
+    private static ColumnSpecification makeFunctionSpec(CFDefinition cfDef, RawSelector.WithFunction fun, AbstractType<?> returnType) throws InvalidRequestException
+    {
+        if (returnType == null)
+            throw new InvalidRequestException(String.format("Unknown function %s called in selection clause", fun.functionName));
+
+        return new ColumnSpecification(cfDef.cfm.ksName,
+                                       cfDef.cfm.cfName,
+                                       new ColumnIdentifier(fun.toString(), true),
+                                       returnType);
+    }
+
+    public static Selection fromSelectors(CFDefinition cfDef, List<RawSelector> rawSelectors) throws InvalidRequestException
+    {
+        boolean usesFunction = isUsingFunction(rawSelectors);
+
+        if (usesFunction)
+        {
+            List<CFDefinition.Name> names = new ArrayList<CFDefinition.Name>();
+            List<ColumnSpecification> metadata = new ArrayList<ColumnSpecification>(rawSelectors.size());
+            List<Selector> selectors = new ArrayList<Selector>(rawSelectors.size());
+            boolean collectTimestamps = false;
+            boolean collectTTLs = false;
+            for (RawSelector rawSelector : rawSelectors)
+            {
+                Selector selector = makeSelector(cfDef, rawSelector, names, metadata);
+                selectors.add(selector);
+                if (selector instanceof WritetimeOrTTLSelector)
+                {
+                    collectTimestamps |= ((WritetimeOrTTLSelector)selector).isWritetime;
+                    collectTTLs |= !((WritetimeOrTTLSelector)selector).isWritetime;
+                }
+            }
+            return new SelectionWithFunctions(names, metadata, selectors, collectTimestamps, collectTTLs);
+        }
+        else
+        {
+            List<CFDefinition.Name> names = new ArrayList<CFDefinition.Name>(rawSelectors.size());
+            for (RawSelector rawSelector : rawSelectors)
+            {
+                assert rawSelector instanceof ColumnIdentifier;
+                CFDefinition.Name name = cfDef.get((ColumnIdentifier)rawSelector);
+                if (name == null)
+                    throw new InvalidRequestException(String.format("Undefined name %s in selection clause", rawSelector));
+                names.add(name);
+            }
+            return new SimpleSelection(names);
+        }
+    }
+
+    protected abstract List<ByteBuffer> handleRow(ResultSetBuilder rs) throws InvalidRequestException;
+
+    /**
+     * @return the list of CQL3 "regular" (the "COLUMN_METADATA" ones) column names to fetch.
+     */
+    public List<ColumnIdentifier> regularColumnsToFetch()
+    {
+        List<ColumnIdentifier> toFetch = new ArrayList<ColumnIdentifier>();
+        for (CFDefinition.Name name : columnsList)
+        {
+            if (name.kind == CFDefinition.Name.Kind.COLUMN_METADATA)
+                toFetch.add(name.name);
+        }
+        return toFetch;
+    }
+
+    /**
+     * @return the list of CQL3 columns value this SelectionClause needs.
+     */
+    public List<CFDefinition.Name> getColumnsList()
+    {
+        return columnsList;
+    }
+
+    public ResultSetBuilder resultSetBuilder()
+    {
+        return new ResultSetBuilder();
+    }
+
+    private static ByteBuffer value(IColumn c)
+    {
+        return (c instanceof CounterColumn)
+            ? ByteBufferUtil.bytes(CounterContext.instance().total(c.value()))
+            : c.value();
+    }
+
+    public class ResultSetBuilder
+    {
+        private final ResultSet resultSet;
+
+        /*
+         * We'll build CQL3 row one by one.
+         * The currentRow is the values for the (CQL3) columns we've fetched.
+         * We also collect timestamps and ttls for the case where the writetime and
+         * ttl functions are used. Note that we might collect timestamp and/or ttls
+         * we don't care about, but since the array below are allocated just once,
+         * it doesn't matter performance wise.
+         */
+        List<ByteBuffer> current;
+        final long[] timestamps;
+        final int[] ttls;
+
+        private ResultSetBuilder()
+        {
+            this.resultSet = new ResultSet(metadata);
+            this.timestamps = collectTimestamps ? new long[columnsList.size()] : null;
+            this.ttls = collectTTLs ? new int[columnsList.size()] : null;
+        }
+
+        public void add(ByteBuffer v)
+        {
+            current.add(v);
+        }
+
+        public void add(IColumn c)
+        {
+            current.add(c == null || c.isMarkedForDelete() ? null : value(c));
+            if (timestamps != null)
+            {
+                timestamps[current.size() - 1] = c.timestamp();
+            }
+            if (ttls != null)
+            {
+                int ttl = -1;
+                if (c instanceof ExpiringColumn)
+                    ttl = ((ExpiringColumn)c).getLocalDeletionTime() - (int) (System.currentTimeMillis() / 1000);
+                ttls[current.size() - 1] = ttl;
+            }
+        }
+
+        public void newRow() throws InvalidRequestException
+        {
+            if (current != null)
+                resultSet.addRow(handleRow(this));
+            current = new ArrayList<ByteBuffer>(columnsList.size());
+        }
+
+        public ResultSet build() throws InvalidRequestException
+        {
+            if (current != null)
+            {
+                resultSet.addRow(handleRow(this));
+                current = null;
+            }
+            return resultSet;
+        }
+    }
+
+    // Special cased selection for when no function is used (this save some allocations).
+    private static class SimpleSelection extends Selection
+    {
+        public SimpleSelection(List<CFDefinition.Name> columnsList)
+        {
+            /*
+             * In theory, even a simple selection could have multiple time the same column, so we
+             * could filter those duplicate out of columnsList. But since we're very unlikely to
+             * get much duplicate in practice, it's more efficient not to bother.
+             */
+            super(columnsList, new ArrayList<ColumnSpecification>(columnsList), false, false);
+        }
+
+        protected List<ByteBuffer> handleRow(ResultSetBuilder rs)
+        {
+            return rs.current;
+        }
+    }
+
+    private interface Selector extends AssignementTestable
+    {
+        public ByteBuffer compute(ResultSetBuilder rs) throws InvalidRequestException;
+    }
+
+    private static class SimpleSelector implements Selector
+    {
+        private final int idx;
+        private final AbstractType<?> type;
+
+        public SimpleSelector(int idx, AbstractType<?> type)
+        {
+            this.idx = idx;
+            this.type = type;
+        }
+
+        public ByteBuffer compute(ResultSetBuilder rs)
+        {
+            return rs.current.get(idx);
+        }
+
+        public boolean isAssignableTo(ColumnSpecification receiver)
+        {
+            return type.equals(receiver.type);
+        }
+    }
+
+    private static class FunctionSelector implements Selector
+    {
+        private final Function fun;
+        private final List<Selector> argSelectors;
+
+        public FunctionSelector(Function fun, List<Selector> argSelectors)
+        {
+            this.fun = fun;
+            this.argSelectors = argSelectors;
+        }
+
+        public ByteBuffer compute(ResultSetBuilder rs) throws InvalidRequestException
+        {
+            List<ByteBuffer> args = new ArrayList<ByteBuffer>(argSelectors.size());
+            for (Selector s : argSelectors)
+                args.add(s.compute(rs));
+
+            return fun.execute(args);
+        }
+
+        public boolean isAssignableTo(ColumnSpecification receiver)
+        {
+            return fun.returnType().equals(receiver.type);
+        }
+    }
+
+    private static class WritetimeOrTTLSelector implements Selector
+    {
+        private final int idx;
+        private final boolean isWritetime;
+
+        public WritetimeOrTTLSelector(int idx, boolean isWritetime)
+        {
+            this.idx = idx;
+            this.isWritetime = isWritetime;
+        }
+
+        public ByteBuffer compute(ResultSetBuilder rs)
+        {
+            if (isWritetime)
+                return ByteBufferUtil.bytes(rs.timestamps[idx]);
+
+            int ttl = rs.ttls[idx];
+            return ttl > 0 ? ByteBufferUtil.bytes(ttl) : null;
+        }
+
+        public boolean isAssignableTo(ColumnSpecification receiver)
+        {
+            return receiver.type.equals(isWritetime ? LongType.instance : Int32Type.instance);
+        }
+    }
+
+    private static class SelectionWithFunctions extends Selection
+    {
+        private final List<Selector> selectors;
+
+        public SelectionWithFunctions(List<CFDefinition.Name> columnsList, List<ColumnSpecification> metadata, List<Selector> selectors, boolean collectTimestamps, boolean collectTTLs)
+        {
+            super(columnsList, metadata, collectTimestamps, collectTTLs);
+            this.selectors = selectors;
+        }
+
+        protected List<ByteBuffer> handleRow(ResultSetBuilder rs) throws InvalidRequestException
+        {
+            List<ByteBuffer> result = new ArrayList<ByteBuffer>();
+            for (Selector selector : selectors)
+            {
+                result.add(selector.compute(rs));
+            }
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/src/java/org/apache/cassandra/cql3/statements/Selector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/Selector.java b/src/java/org/apache/cassandra/cql3/statements/Selector.java
deleted file mode 100644
index 4f1db00..0000000
--- a/src/java/org/apache/cassandra/cql3/statements/Selector.java
+++ /dev/null
@@ -1,181 +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.statements;
-
-import com.google.common.base.Objects;
-
-import org.apache.cassandra.cql3.ColumnIdentifier;
-import org.apache.cassandra.cql3.Term;
-import org.apache.cassandra.db.marshal.*;
-
-public abstract class Selector
-{
-    public enum Function
-    {
-        WRITE_TIME      (LongType.instance),
-        TTL             (Int32Type.instance),
-        DATE_OF         (DateType.instance),
-        UNIXTIMESTAMP_OF(LongType.instance);
-
-        public final AbstractType<?> resultType;
-
-        private Function(AbstractType<?> resultType)
-        {
-            this.resultType = resultType;
-        }
-
-        @Override
-        public String toString()
-        {
-            switch (this)
-            {
-                case WRITE_TIME:
-                    return "writetime";
-                case TTL:
-                    return "ttl";
-                case DATE_OF:
-                    return "dateof";
-                case UNIXTIMESTAMP_OF:
-                    return "unixtimestampof";
-            }
-            throw new AssertionError();
-        }
-    }
-
-    public abstract ColumnIdentifier id();
-
-    public boolean hasFunction()
-    {
-        return false;
-    }
-
-    public Function function()
-    {
-        return null;
-    }
-
-    public boolean hasKey()
-    {
-        return false;
-    }
-
-    public Term key()
-    {
-        return null;
-    }
-
-    public static class WithFunction extends Selector
-    {
-        private final Function function;
-        private final ColumnIdentifier id;
-
-        public WithFunction(ColumnIdentifier id, Function function)
-        {
-            this.id = id;
-            this.function = function;
-        }
-
-        public ColumnIdentifier id()
-        {
-            return id;
-        }
-
-        @Override
-        public boolean hasFunction()
-        {
-            return true;
-        }
-
-        @Override
-        public Function function()
-        {
-            return function;
-        }
-
-        @Override
-        public final int hashCode()
-        {
-            return Objects.hashCode(function, id);
-        }
-
-        @Override
-        public final boolean equals(Object o)
-        {
-            if(!(o instanceof WithFunction))
-                return false;
-            Selector that = (WithFunction)o;
-            return id().equals(that.id()) && function() == that.function();
-        }
-
-        @Override
-        public String toString()
-        {
-            return function + "(" + id + ")";
-        }
-    }
-
-    public static class WithKey extends Selector
-    {
-        private final ColumnIdentifier id;
-        private final Term key;
-
-        public WithKey(ColumnIdentifier id, Term key)
-        {
-            this.id = id;
-            this.key = key;
-        }
-
-        public ColumnIdentifier id()
-        {
-            return id;
-        }
-
-        @Override
-        public boolean hasKey()
-        {
-            return true;
-        }
-
-        public Term key()
-        {
-            return key;
-        }
-
-        @Override
-        public final int hashCode()
-        {
-            return Objects.hashCode(id, key);
-        }
-
-        @Override
-        public final boolean equals(Object o)
-        {
-            if(!(o instanceof WithKey))
-                return false;
-            WithKey that = (WithKey)o;
-            return id().equals(that.id()) && key.equals(that.key);
-        }
-
-        @Override
-        public String toString()
-        {
-            return id + "[" + key + "]";
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/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 aac4f04..683d24b 100644
--- a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
@@ -20,14 +20,8 @@ package org.apache.cassandra.cql3.statements;
 import java.nio.ByteBuffer;
 import java.util.*;
 
-import com.google.common.collect.ArrayListMultimap;
-
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.config.CFMetaData;
-import org.apache.cassandra.cql3.operations.ColumnOperation;
-import org.apache.cassandra.cql3.operations.Operation;
-import org.apache.cassandra.cql3.operations.SetOperation;
-import org.apache.cassandra.cql3.operations.PreparedOperation;
 import org.apache.cassandra.db.*;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.exceptions.*;
@@ -44,34 +38,39 @@ import static org.apache.cassandra.thrift.ThriftValidation.validateColumnFamily;
 public class UpdateStatement extends ModificationStatement
 {
     private CFDefinition cfDef;
-    private final List<Pair<ColumnIdentifier, Operation>> columns;
-    private final List<ColumnIdentifier> columnNames;
-    private final List<Operation> columnOperations;
+
+    // Provided for an UPDATE
+    private final List<Pair<ColumnIdentifier, Operation.RawUpdate>> operations;
     private final List<Relation> whereClause;
 
-    private final ArrayListMultimap<CFDefinition.Name, Operation> processedColumns = ArrayListMultimap.create();
+    // Provided for an INSERT
+    private final List<ColumnIdentifier> columnNames;
+    private final List<Term.Raw> columnValues;
+
+    private final List<Operation> processedColumns = new ArrayList<Operation>();
     private final Map<ColumnIdentifier, List<Term>> processedKeys = new HashMap<ColumnIdentifier, List<Term>>();
 
+    private static final Operation setToEmptyOperation = new Constants.Setter(null, new Constants.Value(ByteBufferUtil.EMPTY_BYTE_BUFFER));
+
     /**
      * Creates a new UpdateStatement from a column family name, columns map, consistency
      * level, and key term.
      *
      * @param name column family being operated on
-     * @param columns a map of column name/values pairs
+     * @param operations a map of column operations to perform
      * @param whereClause the where clause
      * @param attrs additional attributes for statement (CL, timestamp, timeToLive)
      */
     public UpdateStatement(CFName name,
-                           List<Pair<ColumnIdentifier, Operation>> columns,
+                           List<Pair<ColumnIdentifier, Operation.RawUpdate>> operations,
                            List<Relation> whereClause,
                            Attributes attrs)
     {
         super(name, attrs);
-
-        this.columns = columns;
+        this.operations = operations;
         this.whereClause = whereClause;
         this.columnNames = null;
-        this.columnOperations = null;
+        this.columnValues = null;
     }
 
     /**
@@ -81,20 +80,19 @@ public class UpdateStatement extends ModificationStatement
      *
      * @param name column family being operated on
      * @param columnNames list of column names
-     * @param columnOperations list of column 'set' operations (corresponds to names)
+     * @param columnValues list of column values (corresponds to names)
      * @param attrs additional attributes for statement (CL, timestamp, timeToLive)
      */
     public UpdateStatement(CFName name,
                            Attributes attrs,
                            List<ColumnIdentifier> columnNames,
-                           List<Operation> columnOperations)
+                           List<Term.Raw> columnValues)
     {
         super(name, attrs);
-
         this.columnNames = columnNames;
-        this.columnOperations = columnOperations;
+        this.columnValues = columnValues;
+        this.operations = null;
         this.whereClause = null;
-        this.columns = null;
     }
 
     protected void validateConsistency(ConsistencyLevel cl) throws InvalidRequestException
@@ -116,29 +114,23 @@ public class UpdateStatement extends ModificationStatement
 
         // Lists SET operation incurs a read.
         Set<ByteBuffer> toRead = null;
-        for (Map.Entry<CFDefinition.Name, Operation> entry : processedColumns.entries())
+        for (Operation op : processedColumns)
         {
-            CFDefinition.Name name = entry.getKey();
-            Operation value = entry.getValue();
-
-            if (!(name.type instanceof ListType))
-                continue;
-
-            if (value.requiresRead(name.type))
+            if (op.requiresRead())
             {
                 if (toRead == null)
                     toRead = new TreeSet<ByteBuffer>(UTF8Type.instance);
-                toRead.add(name.name.key);
+                toRead.add(op.columnName.key);
             }
         }
 
         Map<ByteBuffer, ColumnGroupMap> rows = toRead != null ? readRows(keys, builder, toRead, (CompositeType)cfDef.cfm.comparator, local, cl) : null;
 
         Collection<IMutation> mutations = new LinkedList<IMutation>();
-        UpdateParameters params = new UpdateParameters(variables, getTimestamp(now), getTimeToLive());
+        UpdateParameters params = new UpdateParameters(variables, getTimestamp(now), getTimeToLive(), rows);
 
         for (ByteBuffer key: keys)
-            mutations.add(mutationForKey(cfDef, key, builder, params, rows == null ? null : rows.get(key), cl));
+            mutations.add(mutationForKey(cfDef, key, builder, params, cl));
 
         return mutations;
     }
@@ -164,7 +156,7 @@ public class UpdateStatement extends ModificationStatement
             else
             {
                 assert values.size() == 1; // We only allow IN for row keys so far
-                builder.add(values.get(0), Relation.Type.EQ, variables);
+                builder.add(values.get(0).bindAndGet(variables));
             }
         }
         return firstEmpty;
@@ -184,13 +176,15 @@ public class UpdateStatement extends ModificationStatement
             if (keyBuilder.remainingCount() == 1)
             {
                 for (Term t : values)
-                    keys.add(keyBuilder.copy().add(t, Relation.Type.EQ, variables).build());
+                {
+                    keys.add(keyBuilder.copy().add(t.bindAndGet(variables)).build());
+                }
             }
             else
             {
                 if (values.size() > 1)
                     throw new InvalidRequestException("IN is only supported on the last column of the partition key");
-                keyBuilder.add(values.get(0), Relation.Type.EQ, variables);
+                keyBuilder.add(values.get(0).bindAndGet(variables));
             }
         }
         return keys;
@@ -203,7 +197,7 @@ public class UpdateStatement extends ModificationStatement
      *
      * @throws InvalidRequestException on the wrong request
      */
-    private IMutation mutationForKey(CFDefinition cfDef, ByteBuffer key, ColumnNameBuilder builder, UpdateParameters params, ColumnGroupMap group, ConsistencyLevel cl)
+    private IMutation mutationForKey(CFDefinition cfDef, ByteBuffer key, ColumnNameBuilder builder, UpdateParameters params, ConsistencyLevel cl)
     throws InvalidRequestException
     {
         validateKey(key);
@@ -232,30 +226,28 @@ public class UpdateStatement extends ModificationStatement
             if (builder.componentCount() == 0)
                 throw new InvalidRequestException(String.format("Missing PRIMARY KEY part %s", cfDef.columns.values().iterator().next()));
 
-            Operation operation;
             if (cfDef.value == null)
             {
-                // No value was defined, we set to the empty value
-                operation = ColumnOperation.SetToEmpty();
+                // compact + no compact value implies there is no column outside the PK. So no operation could
+                // have passed through validation
+                assert processedColumns.isEmpty();
+                setToEmptyOperation.execute(key, cf, builder.copy(), params);
             }
             else
             {
-                List<Operation> operations = processedColumns.get(cfDef.value);
-                if (operations.isEmpty())
+                // compact means we don't have a row marker, so don't accept to set only the PK (Note: we
+                // could accept it and use an empty value!?)
+                if (processedColumns.isEmpty())
                     throw new InvalidRequestException(String.format("Missing mandatory column %s", cfDef.value));
-                assert operations.size() == 1;
-                operation = operations.get(0);
+
+                for (Operation op : processedColumns)
+                    op.execute(key, cf, builder.copy(), params);
             }
-            operation.execute(cf, builder.copy(), cfDef.value == null ? null : cfDef.value.type, params, null);
         }
         else
         {
-            for (Map.Entry<CFDefinition.Name, Operation> entry : processedColumns.entries())
-            {
-                CFDefinition.Name name = entry.getKey();
-                Operation op = entry.getValue();
-                op.execute(cf, builder.copy().add(name.name.key), name.type, params, group == null || !op.requiresRead(name.type) ? null : group.getCollection(name.name.key));
-            }
+            for (Operation op : processedColumns)
+                op.execute(key, cf, builder.copy(), params);
         }
 
         return type == Type.COUNTER ? new CounterMutation(rm, cl) : rm;
@@ -269,15 +261,15 @@ public class UpdateStatement extends ModificationStatement
 
         type = metadata.getDefaultValidator().isCommutative() ? Type.COUNTER : Type.LOGGED;
 
-        if (columns == null)
+        if (operations == null)
         {
             // Created from an INSERT
             if (type == Type.COUNTER)
                 throw new InvalidRequestException("INSERT statement are not allowed on counter tables, use UPDATE instead");
-            if (columnNames.size() != columnOperations.size())
-                throw new InvalidRequestException("unmatched column names/values");
-            if (columnNames.size() < 1)
-                throw new InvalidRequestException("no columns specified for INSERT");
+            if (columnNames.size() != columnValues.size())
+                throw new InvalidRequestException("Unmatched column names/values");
+            if (columnNames.isEmpty())
+                throw new InvalidRequestException("No columns provided to INSERT");
 
             for (int i = 0; i < columnNames.size(); i++)
             {
@@ -285,24 +277,27 @@ public class UpdateStatement extends ModificationStatement
                 if (name == null)
                     throw new InvalidRequestException(String.format("Unknown identifier %s", columnNames.get(i)));
 
-                Operation operation = columnOperations.get(i).validateAndAddBoundNames(name, boundNames);
+                // For UPDATES, the parser validates we don't set the same value twice but we must check it here for INSERT
+                for (int j = 0; j < i; j++)
+                    if (name.name.equals(columnNames.get(j)))
+                        throw new InvalidRequestException(String.format("Multiple definitions found for column %s", name));
+
+                Term.Raw value = columnValues.get(i);
 
                 switch (name.kind)
                 {
                     case KEY_ALIAS:
                     case COLUMN_ALIAS:
-                        if (processedKeys.containsKey(name.name))
+                        Term t = value.prepare(name);
+                        t.collectMarkerSpecification(boundNames);
+                        if (processedKeys.put(name.name, Collections.singletonList(t)) != null)
                             throw new InvalidRequestException(String.format("Multiple definitions found for PRIMARY KEY part %s", name));
-                        // We know collection are not accepted for key and column aliases
-                        if (operation.getType() != Operation.Type.COLUMN && operation.getType() != Operation.Type.PREPARED)
-                            throw new InvalidRequestException(String.format("Invalid definition for %s, not a collection type", name));
-                        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, operation);
+                        Operation operation = new Operation.SetValue(value).prepare(name);
+                        operation.collectMarkerSpecification(boundNames);
+                        processedColumns.add(operation);
                         break;
                 }
             }
@@ -310,32 +305,14 @@ public class UpdateStatement extends ModificationStatement
         else
         {
             // Created from an UPDATE
-            for (Pair<ColumnIdentifier, Operation> entry : columns)
+            for (Pair<ColumnIdentifier, Operation.RawUpdate> entry : operations)
             {
                 CFDefinition.Name name = cfDef.get(entry.left);
                 if (name == null)
                     throw new InvalidRequestException(String.format("Unknown identifier %s", entry.left));
 
-                Operation operation = entry.right.validateAndAddBoundNames(name, boundNames);
-
-                switch (operation.getType())
-                {
-                    case COUNTER:
-                        if (type != Type.COUNTER)
-                            throw new InvalidRequestException("Invalid counter operation on non-counter table.");
-                        break;
-                    case LIST:
-                    case SET:
-                    case MAP:
-                    case COLUMN:
-                        if (type == Type.COUNTER)
-                            throw new InvalidRequestException("Invalid non-counter operation on counter table.");
-                        break;
-                    case PREPARED:
-                        if (type == Type.COUNTER && !((PreparedOperation)operation).isPotentialCounterOperation())
-                            throw new InvalidRequestException("Invalid non-counter operation on counter table.");
-                        break;
-                }
+                Operation operation = entry.right.prepare(name);
+                operation.collectMarkerSpecification(boundNames);
 
                 switch (name.kind)
                 {
@@ -344,10 +321,7 @@ public class UpdateStatement extends ModificationStatement
                         throw new InvalidRequestException(String.format("PRIMARY KEY part %s found in SET part", entry.left));
                     case VALUE_ALIAS:
                     case COLUMN_METADATA:
-                        for (Operation otherOp : processedColumns.get(name))
-                            if (otherOp.getType() == Operation.Type.COLUMN)
-                                throw new InvalidRequestException(String.format("Multiple definitions found for column %s", name));
-                        processedColumns.put(name, operation);
+                        processedColumns.add(operation);
                         break;
                 }
             }
@@ -376,27 +350,28 @@ public class UpdateStatement extends ModificationStatement
             {
                 case KEY_ALIAS:
                 case COLUMN_ALIAS:
-                    List<Term> values;
+                    List<Term.Raw> rawValues;
                     if (rel.operator() == Relation.Type.EQ)
-                        values = Collections.singletonList(rel.getValue());
+                        rawValues = Collections.singletonList(rel.getValue());
                     else if (name.kind == CFDefinition.Name.Kind.KEY_ALIAS && rel.operator() == Relation.Type.IN)
-                        values = rel.getInValues();
+                        rawValues = rel.getInValues();
                     else
-                        throw new InvalidRequestException(String.format("Invalid operator %s for key %s", rel.operator(), rel.getEntity()));
+                        throw new InvalidRequestException(String.format("Invalid operator %s for PRIMARY KEY part %s", rel.operator(), name));
 
-                    if (processed.containsKey(name.name))
-                        throw new InvalidRequestException(String.format("Multiple definitions found for PRIMARY KEY part %s", name));
-                    for (Term value : values)
+                    List<Term> values = new ArrayList<Term>(rawValues.size());
+                    for (Term.Raw raw : rawValues)
                     {
-                        value.validateType(name.toString(), name.type);
-                        if (value.isBindMarker())
-                            names[value.bindIndex] = name;
+                        Term t = raw.prepare(name);
+                        t.collectMarkerSpecification(names);
+                        values.add(t);
                     }
-                    processed.put(name.name, values);
+
+                    if (processed.put(name.name, values) != null)
+                        throw new InvalidRequestException(String.format("Multiple definitions found for PRIMARY KEY part %s", name));
                     break;
                 case VALUE_ALIAS:
                 case COLUMN_METADATA:
-                    throw new InvalidRequestException(String.format("PRIMARY KEY part %s found in SET part", rel.getEntity()));
+                    throw new InvalidRequestException(String.format("Non PRIMARY KEY %s found in where clause", name));
             }
         }
     }
@@ -406,7 +381,7 @@ public class UpdateStatement extends ModificationStatement
         return String.format("UpdateStatement(name=%s, keys=%s, columns=%s, timestamp=%s, timeToLive=%s)",
                              cfName,
                              whereClause,
-                             columns,
+                             operations,
                              isSetTimestamp() ? getTimestamp(-1) : "<now>",
                              getTimeToLive());
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/src/java/org/apache/cassandra/db/SystemTable.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/SystemTable.java b/src/java/org/apache/cassandra/db/SystemTable.java
index 629defe..6a38757 100644
--- a/src/java/org/apache/cassandra/db/SystemTable.java
+++ b/src/java/org/apache/cassandra/db/SystemTable.java
@@ -29,6 +29,7 @@ import com.google.common.base.Function;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -204,7 +205,7 @@ public class SystemTable
                 return sstable.descriptor.generation;
             }
         });
-        processInternal(String.format(req, COMPACTION_LOG, compactionId, cfs.table.name, cfs.columnFamily, StringUtils.join(generations.iterator(), ',')));
+        processInternal(String.format(req, COMPACTION_LOG, compactionId, cfs.table.name, cfs.columnFamily, StringUtils.join(Sets.newHashSet(generations), ',')));
         forceBlockingFlush(COMPACTION_LOG);
         return compactionId;
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/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 5c4c03e..7b586d5 100644
--- a/src/java/org/apache/cassandra/db/marshal/AbstractType.java
+++ b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
@@ -24,7 +24,6 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.cassandra.cql3.CQL3Type;
-import org.apache.cassandra.cql3.Term;
 import org.apache.cassandra.exceptions.SyntaxException;
 import org.apache.cassandra.db.IColumn;
 import org.apache.cassandra.db.OnDiskAtom;
@@ -150,12 +149,6 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>
     /* validate that the byte array is a valid sequence for the type we are supposed to be comparing */
     public abstract void validate(ByteBuffer bytes) throws MarshalException;
 
-    /* CQL3 types will actually override this, but we use a default for compatibility sake */
-    public Set<Term.Type> supportedCQL3Constants()
-    {
-        return null;
-    }
-
     /* Most of our internal type should override that. */
     public CQL3Type asCQL3Type()
     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/src/java/org/apache/cassandra/db/marshal/AsciiType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/AsciiType.java b/src/java/org/apache/cassandra/db/marshal/AsciiType.java
index c1762cc..990b3d4 100644
--- a/src/java/org/apache/cassandra/db/marshal/AsciiType.java
+++ b/src/java/org/apache/cassandra/db/marshal/AsciiType.java
@@ -18,19 +18,14 @@
 package org.apache.cassandra.db.marshal;
 
 import java.nio.ByteBuffer;
-import java.util.EnumSet;
-import java.util.Set;
 
 import org.apache.cassandra.cql.jdbc.JdbcAscii;
 import org.apache.cassandra.cql3.CQL3Type;
-import org.apache.cassandra.cql3.Term;
 
 public class AsciiType extends AbstractType<String>
 {
     public static final AsciiType instance = new AsciiType();
 
-    private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.STRING);
-
     AsciiType() {} // singleton
 
     public String getString(ByteBuffer bytes)
@@ -76,11 +71,6 @@ public class AsciiType extends AbstractType<String>
         }
     }
 
-    public Set<Term.Type> supportedCQL3Constants()
-    {
-        return supportedCQL3Constants;
-    }
-
     public CQL3Type asCQL3Type()
     {
         return CQL3Type.Native.ASCII;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/src/java/org/apache/cassandra/db/marshal/BooleanType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/BooleanType.java b/src/java/org/apache/cassandra/db/marshal/BooleanType.java
index 87b1183..0bd1a57 100644
--- a/src/java/org/apache/cassandra/db/marshal/BooleanType.java
+++ b/src/java/org/apache/cassandra/db/marshal/BooleanType.java
@@ -18,19 +18,15 @@
 package org.apache.cassandra.db.marshal;
 
 import java.nio.ByteBuffer;
-import java.util.EnumSet;
-import java.util.Set;
 
 import org.apache.cassandra.cql.jdbc.JdbcBoolean;
+import org.apache.cassandra.cql3.Constants;
 import org.apache.cassandra.cql3.CQL3Type;
-import org.apache.cassandra.cql3.Term;
 
 public class BooleanType extends AbstractType<Boolean>
 {
   public static final BooleanType instance = new BooleanType();
 
-  public final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.BOOLEAN);
-
   BooleanType() {} // singleton
 
   public Boolean compose(ByteBuffer bytes)
@@ -84,11 +80,6 @@ public class BooleanType extends AbstractType<Boolean>
           throw new MarshalException(String.format("Expected 1 or 0 byte value (%d)", bytes.remaining()));
   }
 
-  public Set<Term.Type> supportedCQL3Constants()
-  {
-      return supportedCQL3Constants;
-  }
-
   public CQL3Type asCQL3Type()
   {
       return CQL3Type.Native.BOOLEAN;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/src/java/org/apache/cassandra/db/marshal/BytesType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/BytesType.java b/src/java/org/apache/cassandra/db/marshal/BytesType.java
index a2ddbf8..1bb2bd2 100644
--- a/src/java/org/apache/cassandra/db/marshal/BytesType.java
+++ b/src/java/org/apache/cassandra/db/marshal/BytesType.java
@@ -18,12 +18,9 @@
 package org.apache.cassandra.db.marshal;
 
 import java.nio.ByteBuffer;
-import java.util.EnumSet;
-import java.util.Set;
 
 import org.apache.cassandra.cql.jdbc.JdbcBytes;
 import org.apache.cassandra.cql3.CQL3Type;
-import org.apache.cassandra.cql3.Term;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.Hex;
 
@@ -31,8 +28,6 @@ public class BytesType extends AbstractType<ByteBuffer>
 {
     public static final BytesType instance = new BytesType();
 
-    private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.HEX);
-
     BytesType() {} // singleton
 
     public ByteBuffer compose(ByteBuffer bytes)
@@ -88,11 +83,6 @@ public class BytesType extends AbstractType<ByteBuffer>
         return this == previous || previous == AsciiType.instance || previous == UTF8Type.instance;
     }
 
-    public Set<Term.Type> supportedCQL3Constants()
-    {
-        return supportedCQL3Constants;
-    }
-
     public CQL3Type asCQL3Type()
     {
         return CQL3Type.Native.BLOB;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/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 b448f1b..d330e4c 100644
--- a/src/java/org/apache/cassandra/db/marshal/CollectionType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CollectionType.java
@@ -93,7 +93,7 @@ public abstract class CollectionType<T> extends AbstractType<T>
     }
 
     // Utilitary method
-    protected ByteBuffer pack(List<ByteBuffer> buffers, int elements, int size)
+    protected static ByteBuffer pack(List<ByteBuffer> buffers, int elements, int size)
     {
         ByteBuffer result = ByteBuffer.allocate(2 + size);
         result.putShort((short)elements);
@@ -105,6 +105,13 @@ public abstract class CollectionType<T> extends AbstractType<T>
         return (ByteBuffer)result.flip();
     }
 
+    public static ByteBuffer pack(List<ByteBuffer> buffers, int elements)
+    {
+        int size = 0;
+        for (ByteBuffer bb : buffers)
+            size += 2 + bb.remaining();
+        return pack(buffers, elements, size);
+    }
 
     public CQL3Type asCQL3Type()
     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/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 fb80906..2d7f4fc 100644
--- a/src/java/org/apache/cassandra/db/marshal/CompositeType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CompositeType.java
@@ -235,14 +235,12 @@ public class CompositeType extends AbstractCompositeType
             this.serializedSize = b.serializedSize;
         }
 
-        public Builder add(Term t, Relation.Type op, List<ByteBuffer> variables) throws InvalidRequestException
+        public Builder add(ByteBuffer buffer, Relation.Type op)
         {
             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);
 
             /*
@@ -272,13 +270,7 @@ public class CompositeType extends AbstractCompositeType
 
         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;
-            return this;
+            return add(bb, Relation.Type.EQ);
         }
 
         public int componentCount()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java b/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
index 8cd2457..1421476 100644
--- a/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
@@ -18,11 +18,9 @@
 package org.apache.cassandra.db.marshal;
 
 import java.nio.ByteBuffer;
-import java.util.EnumSet;
-import java.util.Set;
 
+import org.apache.cassandra.cql3.Constants;
 import org.apache.cassandra.cql3.CQL3Type;
-import org.apache.cassandra.cql3.Term;
 import org.apache.cassandra.db.*;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
@@ -30,8 +28,6 @@ public class CounterColumnType extends AbstractCommutativeType
 {
     public static final CounterColumnType instance = new CounterColumnType();
 
-    private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.INTEGER);
-
     CounterColumnType() {} // singleton
 
     public int compare(ByteBuffer o1, ByteBuffer o2)
@@ -66,11 +62,6 @@ public class CounterColumnType extends AbstractCommutativeType
             throw new MarshalException(String.format("Expected 8 or 0 byte long (%d)", bytes.remaining()));
     }
 
-    public Set<Term.Type> supportedCQL3Constants()
-    {
-        return supportedCQL3Constants;
-    }
-
     public CQL3Type asCQL3Type()
     {
         return CQL3Type.Native.COUNTER;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/src/java/org/apache/cassandra/db/marshal/DateType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/DateType.java b/src/java/org/apache/cassandra/db/marshal/DateType.java
index 0da1af5..ac27ba6 100644
--- a/src/java/org/apache/cassandra/db/marshal/DateType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DateType.java
@@ -23,12 +23,10 @@ import java.nio.ByteBuffer;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
-import java.util.EnumSet;
-import java.util.Set;
 
 import org.apache.cassandra.cql.jdbc.JdbcDate;
+import org.apache.cassandra.cql3.Constants;
 import org.apache.cassandra.cql3.CQL3Type;
-import org.apache.cassandra.cql3.Term;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.commons.lang.time.DateUtils;
 
@@ -39,8 +37,6 @@ public class DateType extends AbstractType<Date>
     static final String DEFAULT_FORMAT = iso8601Patterns[3];
     static final SimpleDateFormat FORMATTER = new SimpleDateFormat(DEFAULT_FORMAT);
 
-    private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.STRING, Term.Type.INTEGER);
-
     DateType() {} // singleton
 
     public Date compose(ByteBuffer bytes)
@@ -130,11 +126,6 @@ public class DateType extends AbstractType<Date>
             throw new MarshalException(String.format("Expected 8 or 0 byte long for date (%d)", bytes.remaining()));
     }
 
-    public Set<Term.Type> supportedCQL3Constants()
-    {
-        return supportedCQL3Constants;
-    }
-
     public CQL3Type asCQL3Type()
     {
         return CQL3Type.Native.TIMESTAMP;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/src/java/org/apache/cassandra/db/marshal/DecimalType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/DecimalType.java b/src/java/org/apache/cassandra/db/marshal/DecimalType.java
index 75e179e..825f208 100644
--- a/src/java/org/apache/cassandra/db/marshal/DecimalType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DecimalType.java
@@ -19,20 +19,15 @@ package org.apache.cassandra.db.marshal;
 
 import java.math.BigDecimal;
 import java.nio.ByteBuffer;
-import java.util.EnumSet;
-import java.util.Set;
 
 import org.apache.cassandra.cql.jdbc.JdbcDecimal;
 import org.apache.cassandra.cql3.CQL3Type;
-import org.apache.cassandra.cql3.Term;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
 public class DecimalType extends AbstractType<BigDecimal>
 {
     public static final DecimalType instance = new DecimalType();
 
-    private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.INTEGER, Term.Type.FLOAT);
-
     DecimalType() {} // singleton
 
     public int compare(ByteBuffer bb0, ByteBuffer bb1)
@@ -92,11 +87,6 @@ public class DecimalType extends AbstractType<BigDecimal>
         // no useful check for invalid decimals.
     }
 
-    public Set<Term.Type> supportedCQL3Constants()
-    {
-        return supportedCQL3Constants;
-    }
-
     public CQL3Type asCQL3Type()
     {
         return CQL3Type.Native.DECIMAL;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/31e669ab/src/java/org/apache/cassandra/db/marshal/DoubleType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/DoubleType.java b/src/java/org/apache/cassandra/db/marshal/DoubleType.java
index 23854bd..f2c7378 100644
--- a/src/java/org/apache/cassandra/db/marshal/DoubleType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DoubleType.java
@@ -18,20 +18,15 @@
 package org.apache.cassandra.db.marshal;
 
 import java.nio.ByteBuffer;
-import java.util.EnumSet;
-import java.util.Set;
 
 import org.apache.cassandra.cql.jdbc.JdbcDouble;
 import org.apache.cassandra.cql3.CQL3Type;
-import org.apache.cassandra.cql3.Term;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
 public class DoubleType extends AbstractType<Double>
 {
     public static final DoubleType instance = new DoubleType();
 
-    private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.INTEGER, Term.Type.FLOAT);
-
     DoubleType() {} // singleton
 
     public Double compose(ByteBuffer bytes)
@@ -95,11 +90,6 @@ public class DoubleType extends AbstractType<Double>
             throw new MarshalException(String.format("Expected 8 or 0 byte value for a double (%d)", bytes.remaining()));
     }
 
-    public Set<Term.Type> supportedCQL3Constants()
-    {
-        return supportedCQL3Constants;
-    }
-
     public CQL3Type asCQL3Type()
     {
         return CQL3Type.Native.DOUBLE;


Mime
View raw message