You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sl...@apache.org on 2014/02/20 17:51:33 UTC

[6/6] git commit: Merge branch 'cassandra-2.0' into cassandra-2.1

Merge branch 'cassandra-2.0' into cassandra-2.1

Conflicts:
	src/java/org/apache/cassandra/config/CFMetaData.java
	src/java/org/apache/cassandra/config/ColumnDefinition.java
	src/java/org/apache/cassandra/cql3/CFDefinition.java
	src/java/org/apache/cassandra/cql3/Constants.java
	src/java/org/apache/cassandra/cql3/Cql.g
	src/java/org/apache/cassandra/cql3/Lists.java
	src/java/org/apache/cassandra/cql3/Maps.java
	src/java/org/apache/cassandra/cql3/Operation.java
	src/java/org/apache/cassandra/cql3/Sets.java
	src/java/org/apache/cassandra/cql3/functions/TokenFct.java
	src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
	src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
	src/java/org/apache/cassandra/cql3/statements/ColumnGroupMap.java
	src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
	src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
	src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
	src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
	src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
	src/java/org/apache/cassandra/cql3/statements/Selection.java
	src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
	src/java/org/apache/cassandra/db/filter/ColumnSlice.java
	src/java/org/apache/cassandra/db/index/composites/CompositesSearcher.java
	src/java/org/apache/cassandra/hadoop/pig/AbstractCassandraStorage.java
	src/java/org/apache/cassandra/hadoop/pig/CqlStorage.java
	src/java/org/apache/cassandra/thrift/ThriftValidation.java


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

Branch: refs/heads/cassandra-2.1
Commit: 63b1ef4eebb26523d69b96cfcf20d9e5ae0b15c0
Parents: a73db3f b09d876
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Thu Feb 20 17:51:13 2014 +0100
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Thu Feb 20 17:51:13 2014 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 doc/cql3/CQL.textile                            |  29 +-
 .../org/apache/cassandra/config/CFMetaData.java |  30 +-
 .../cassandra/config/ColumnDefinition.java      |  16 +
 src/java/org/apache/cassandra/cql3/CQL3Row.java |   7 +-
 .../apache/cassandra/cql3/ColumnCondition.java  | 183 ++++++++++
 .../org/apache/cassandra/cql3/Constants.java    |   8 +-
 src/java/org/apache/cassandra/cql3/Cql.g        |  29 +-
 src/java/org/apache/cassandra/cql3/Lists.java   |  12 +-
 src/java/org/apache/cassandra/cql3/Maps.java    |  14 +-
 src/java/org/apache/cassandra/cql3/Sets.java    |  12 +-
 .../cql3/statements/AlterTableStatement.java    |  30 +-
 .../cql3/statements/BatchStatement.java         | 162 +++++++--
 .../cql3/statements/CQL3CasConditions.java      | 164 +++++++++
 .../cql3/statements/CreateIndexStatement.java   |   9 +
 .../cql3/statements/CreateTableStatement.java   |  41 ++-
 .../cql3/statements/DeleteStatement.java        |  23 +-
 .../cql3/statements/ModificationStatement.java  | 330 ++++++++++---------
 .../cql3/statements/SelectStatement.java        | 238 +++++++++++--
 .../cassandra/cql3/statements/Selection.java    |  29 +-
 .../cql3/statements/UpdateStatement.java        |  20 +-
 .../org/apache/cassandra/db/CFRowAdder.java     |  10 +-
 .../cassandra/db/composites/AbstractCType.java  |   7 +-
 .../db/composites/AbstractCellNameType.java     | 188 +++++++----
 .../db/composites/AbstractComposite.java        |  17 +-
 .../AbstractCompoundCellNameType.java           |  37 ++-
 .../db/composites/BoundedComposite.java         |   5 +
 .../cassandra/db/composites/CellNameType.java   |  21 +-
 .../cassandra/db/composites/Composite.java      |   2 +
 .../cassandra/db/composites/Composites.java     |   5 +
 .../cassandra/db/composites/CompoundCType.java  |  14 +-
 .../db/composites/CompoundComposite.java        |  16 +-
 .../db/composites/CompoundDenseCellName.java    |   2 +-
 .../composites/CompoundDenseCellNameType.java   |  14 +-
 .../db/composites/CompoundSparseCellName.java   |  34 +-
 .../composites/CompoundSparseCellNameType.java  |  98 ++++--
 .../db/composites/SimpleDenseCellNameType.java  |   5 +-
 .../db/composites/SimpleSparseCellNameType.java |   7 +-
 .../cassandra/db/filter/ExtendedFilter.java     |  10 +-
 .../CompositesIndexOnCollectionKey.java         |   2 +-
 .../CompositesIndexOnCollectionValue.java       |   2 +-
 .../composites/CompositesIndexOnRegular.java    |   2 +-
 .../db/index/composites/CompositesSearcher.java |  25 +-
 .../db/marshal/AbstractCompositeType.java       |  47 +--
 .../cassandra/db/marshal/CompositeType.java     |  72 +++-
 .../db/marshal/DynamicCompositeType.java        |   6 +
 .../hadoop/pig/AbstractCassandraStorage.java    |   3 +-
 .../apache/cassandra/service/CASConditions.java |   3 +-
 48 files changed, 1552 insertions(+), 489 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/CHANGES.txt
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/doc/cql3/CQL.textile
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/config/CFMetaData.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/config/CFMetaData.java
index ba7e6e6,a319930..25b7314
--- a/src/java/org/apache/cassandra/config/CFMetaData.java
+++ b/src/java/org/apache/cassandra/config/CFMetaData.java
@@@ -26,12 -27,12 +26,13 @@@ import java.util.*
  
  import com.google.common.annotations.VisibleForTesting;
  import com.google.common.base.Objects;
 +import com.google.common.collect.AbstractIterator;
+ import com.google.common.collect.Iterables;
  import com.google.common.collect.MapDifference;
  import com.google.common.collect.Maps;
 +import org.apache.cassandra.db.composites.*;
  import org.apache.commons.lang3.ArrayUtils;
  import org.apache.commons.lang3.StringUtils;
 -import org.apache.commons.lang3.builder.EqualsBuilder;
  import org.apache.commons.lang3.builder.HashCodeBuilder;
  import org.apache.commons.lang3.builder.ToStringBuilder;
  import org.slf4j.Logger;
@@@ -474,10 -405,11 +475,11 @@@ public final class CFMetaDat
      public static final String DEFAULT_COLUMN_ALIAS = "column";
      public static final String DEFAULT_VALUE_ALIAS = "value";
  
 -    private volatile Map<ByteBuffer, ColumnDefinition> column_metadata = new HashMap<>();
 +    private volatile Map<ByteBuffer, ColumnDefinition> columnMetadata = new HashMap<>();
      private volatile List<ColumnDefinition> partitionKeyColumns;  // Always of size keyValidator.componentsCount, null padded if necessary
 -    private volatile List<ColumnDefinition> clusteringKeyColumns; // Of size comparator.componentsCount or comparator.componentsCount -1, null padded if necessary
 -    private volatile Set<ColumnDefinition> regularColumns;
 -    private volatile Set<ColumnDefinition> staticColumns;
 +    private volatile List<ColumnDefinition> clusteringColumns;    // Of size comparator.componentsCount or comparator.componentsCount -1, null padded if necessary
 +    private volatile SortedSet<ColumnDefinition> regularColumns;  // We use a sorted set so iteration is of predictable order (for SELECT for instance)
++    private volatile SortedSet<ColumnDefinition> staticColumns;   // Same as above
      private volatile ColumnDefinition compactValueColumn;
  
      public volatile Class<? extends AbstractCompactionStrategy> compactionStrategyClass = DEFAULT_COMPACTION_STRATEGY_CLASS;
@@@ -793,42 -705,7 +795,46 @@@
  
      public Collection<ColumnDefinition> allColumns()
      {
 -        return column_metadata.values();
 +        return columnMetadata.values();
 +    }
 +
 +    // An iterator over all column definitions but that respect the order of a SELECT *.
 +    public Iterator<ColumnDefinition> allColumnsInSelectOrder()
 +    {
 +        return new AbstractIterator<ColumnDefinition>()
 +        {
 +            private final Iterator<ColumnDefinition> partitionKeyIter = partitionKeyColumns.iterator();
 +            private final Iterator<ColumnDefinition> clusteringIter = clusteringColumns.iterator();
 +            private boolean valueDone;
++            private final Iterator<ColumnDefinition> staticIter = staticColumns.iterator();
 +            private final Iterator<ColumnDefinition> regularIter = regularColumns.iterator();
 +
 +            protected ColumnDefinition computeNext()
 +            {
 +                if (partitionKeyIter.hasNext())
 +                    return partitionKeyIter.next();
 +
 +                if (clusteringIter.hasNext())
 +                    return clusteringIter.next();
 +
++                if (staticIter.hasNext())
++                    return staticIter.next();
++
 +                if (compactValueColumn != null && !valueDone)
 +                {
 +                    valueDone = true;
 +                    // If the compactValueColumn is empty, this means we have a dense table but
 +                    // with only a PK. As far as selects are concerned, we should ignore the value.
 +                    if (compactValueColumn.name.bytes.hasRemaining())
 +                        return compactValueColumn;
 +                }
 +
 +                if (regularIter.hasNext())
 +                    return regularIter.next();
 +
 +                return endOfData();
 +            }
 +        };
      }
  
      public List<ColumnDefinition> partitionKeyColumns()
@@@ -1507,9 -1340,9 +1523,9 @@@
          // Mixing counter with non counter columns is not supported (#2614)
          if (defaultValidator instanceof CounterColumnType)
          {
-             for (ColumnDefinition def : regularColumns)
+             for (ColumnDefinition def : regularAndStaticColumns())
 -                if (!(def.getValidator() instanceof CounterColumnType))
 -                    throw new ConfigurationException("Cannot add a non counter column (" + getColumnDefinitionComparator(def).getString(def.name) + ") in a counter column family");
 +                if (!(def.type instanceof CounterColumnType))
 +                    throw new ConfigurationException("Cannot add a non counter column (" + def.name + ") in a counter column family");
          }
          else
          {
@@@ -2017,18 -1842,18 +2033,18 @@@
          droppedColumns.put(def.name, FBUtilities.timestampMicros());
      }
  
 -    public void renameColumn(ByteBuffer from, String strFrom, ByteBuffer to, String strTo) throws InvalidRequestException
 +    public void renameColumn(ColumnIdentifier from, ColumnIdentifier to) throws InvalidRequestException
      {
 -        ColumnDefinition def = column_metadata.get(from);
 +        ColumnDefinition def = getColumnDefinition(from);
          if (def == null)
 -            throw new InvalidRequestException(String.format("Cannot rename unknown column %s in keyspace %s", strFrom, cfName));
 +            throw new InvalidRequestException(String.format("Cannot rename unknown column %s in keyspace %s", from, cfName));
  
 -        if (column_metadata.get(to) != null)
 -            throw new InvalidRequestException(String.format("Cannot rename column %s to %s in keyspace %s; another column of that name already exist", strFrom, strTo, cfName));
 +        if (getColumnDefinition(to) != null)
 +            throw new InvalidRequestException(String.format("Cannot rename column %s to %s in keyspace %s; another column of that name already exist", from, to, cfName));
  
-         if (def.kind == ColumnDefinition.Kind.REGULAR)
 -        if (def.type == ColumnDefinition.Type.REGULAR || def.type == ColumnDefinition.Type.STATIC)
++        if (def.kind == ColumnDefinition.Kind.REGULAR || def.kind == ColumnDefinition.Kind.STATIC)
          {
 -            throw new InvalidRequestException(String.format("Cannot rename non PRIMARY KEY part %s", strFrom));
 +            throw new InvalidRequestException(String.format("Cannot rename non PRIMARY KEY part %s", from));
          }
          else if (def.isIndexed())
          {
@@@ -2044,23 -1869,46 +2060,24 @@@
  
      public CFMetaData rebuild()
      {
 -        /*
 -         * TODO: There is definitively some repetition between the CQL3  metadata stored in this
 -         * object (partitionKeyColumns, ...) and the one stored in CFDefinition.
 -         * Ultimately, we should probably merge both. However, there is enough details to fix that
 -         * it's worth doing that in a separate issue.
 -         */
 -        rebuildCQL3Metadata();
 -        cqlCfDef = new CFDefinition(this);
 -        return this;
 -    }
 -
 -    public CFDefinition getCfDef()
 -    {
 -        assert cqlCfDef != null;
 -        return cqlCfDef;
 -    }
 -
 -    private void rebuildCQL3Metadata()
 -    {
          List<ColumnDefinition> pkCols = nullInitializedList(keyValidator.componentsCount());
 -        boolean isDense = isDense(comparator, column_metadata.values());
 -        int nbCkCols = isDense
 -                     ? comparator.componentsCount()
 -                     : comparator.componentsCount() - (hasCollection() ? 2 : 1);
 -        List<ColumnDefinition> ckCols = nullInitializedList(nbCkCols);
 -        Set<ColumnDefinition> regCols = new HashSet<ColumnDefinition>();
 -        Set<ColumnDefinition> statCols = new HashSet<ColumnDefinition>();
 +        List<ColumnDefinition> ckCols = nullInitializedList(comparator.clusteringPrefixSize());
 +        // We keep things sorted to get consistent/predicatable order in select queries
 +        SortedSet<ColumnDefinition> regCols = new TreeSet<>(regularColumnComparator);
++        SortedSet<ColumnDefinition> statCols = new TreeSet<>(regularColumnComparator);
          ColumnDefinition compactCol = null;
  
 -        for (ColumnDefinition def : column_metadata.values())
 +        for (ColumnDefinition def : allColumns())
          {
 -            switch (def.type)
 +            switch (def.kind)
              {
                  case PARTITION_KEY:
 -                    assert !(def.componentIndex == null && keyValidator instanceof CompositeType);
 -                    pkCols.set(def.componentIndex == null ? 0 : def.componentIndex, def);
 +                    assert !(def.isOnAllComponents() && keyValidator instanceof CompositeType);
 +                    pkCols.set(def.position(), def);
                      break;
 -                case CLUSTERING_KEY:
 -                    assert !(def.componentIndex == null && comparator instanceof CompositeType);
 -                    ckCols.set(def.componentIndex == null ? 0 : def.componentIndex, def);
 +                case CLUSTERING_COLUMN:
 +                    assert !(def.isOnAllComponents() && comparator.isCompound());
 +                    ckCols.set(def.position(), def);
                      break;
                  case REGULAR:
                      regCols.add(def);
@@@ -2074,10 -1925,10 +2094,11 @@@
  
          // Now actually assign the correct value. This is not atomic, but then again, updating CFMetaData is never atomic anyway.
          partitionKeyColumns = addDefaultKeyAliases(pkCols);
 -        clusteringKeyColumns = addDefaultColumnAliases(ckCols);
 +        clusteringColumns = addDefaultColumnAliases(ckCols);
          regularColumns = regCols;
+         staticColumns = statCols;
 -        compactValueColumn = addDefaultValueAlias(compactCol, isDense);
 +        compactValueColumn = addDefaultValueAlias(compactCol, comparator.isDense());
 +        return this;
      }
  
      private List<ColumnDefinition> addDefaultKeyAliases(List<ColumnDefinition> pkCols)
@@@ -2241,15 -2091,24 +2262,20 @@@
          return true;
      }
  
 -    public boolean hasStaticColumns()
 +    public boolean isCounter()
      {
 -        return !staticColumns.isEmpty();
 +        return defaultValidator.isCounter();
      }
  
 -    public ColumnNameBuilder getStaticColumnNameBuilder()
++    public boolean hasStaticColumns()
+     {
 -        assert comparator instanceof CompositeType && clusteringKeyColumns().size() > 0;
 -        CompositeType.Builder builder = CompositeType.Builder.staticBuilder((CompositeType)comparator);
 -        for (int i = 0; i < clusteringKeyColumns().size(); i++)
 -            builder.add(ByteBufferUtil.EMPTY_BYTE_BUFFER);
 -        return builder;
++        return !staticColumns.isEmpty();
+     }
+ 
 -    public void validateColumns(Iterable<Column> columns)
 +    public void validateColumns(Iterable<Cell> columns)
      {
 -        for (Column column : columns)
 -            column.validateFields(this);
 +        for (Cell cell : columns)
 +            cell.validateFields(this);
      }
  
      @Override

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/config/ColumnDefinition.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/config/ColumnDefinition.java
index 79f50bf,11340e7..bb1dd71
--- a/src/java/org/apache/cassandra/config/ColumnDefinition.java
+++ b/src/java/org/apache/cassandra/config/ColumnDefinition.java
@@@ -58,71 -59,57 +58,77 @@@ public class ColumnDefinition extends C
       * Note that thrift/CQL2 only know about definitions of type REGULAR (and
       * the ones whose componentIndex == null).
       */
 -    public enum Type
 +    public enum Kind
      {
          PARTITION_KEY,
 -        CLUSTERING_KEY,
 +        CLUSTERING_COLUMN,
          REGULAR,
 -        COMPACT_VALUE,
 -        STATIC
++        STATIC,
 +        COMPACT_VALUE;
 +
 +        public String serialize()
 +        {
 +            // For backward compatibility we need to special case CLUSTERING_COLUMN
 +            return this == CLUSTERING_COLUMN ? "clustering_key" : this.toString().toLowerCase();
 +        }
 +
 +        public static Kind deserialize(String value)
 +        {
 +            if (value.equalsIgnoreCase("clustering_key"))
 +                return CLUSTERING_COLUMN;
 +            return Enum.valueOf(Kind.class, value.toUpperCase());
 +        }
      }
  
 -    public final ByteBuffer name;
 -    private AbstractType<?> validator;
 +    public final Kind kind;
 +
 +    private String indexName;
      private IndexType indexType;
      private Map<String,String> indexOptions;
 -    private String indexName;
 -    public final Type type;
  
      /*
       * If the column comparator is a composite type, indicates to which
       * component this definition refers to. If null, the definition refers to
       * the full column name.
       */
 -    public final Integer componentIndex;
 +    private final Integer componentIndex;
  
 -    public static ColumnDefinition partitionKeyDef(ByteBuffer name, AbstractType<?> validator, Integer componentIndex)
 +    public static ColumnDefinition partitionKeyDef(CFMetaData cfm, ByteBuffer name, AbstractType<?> validator, Integer componentIndex)
      {
 -        return new ColumnDefinition(name, validator, componentIndex, Type.PARTITION_KEY);
 +        return new ColumnDefinition(cfm, name, validator, componentIndex, Kind.PARTITION_KEY);
      }
  
 -    public static ColumnDefinition clusteringKeyDef(ByteBuffer name, AbstractType<?> validator, Integer componentIndex)
 +    public static ColumnDefinition clusteringKeyDef(CFMetaData cfm, ByteBuffer name, AbstractType<?> validator, Integer componentIndex)
      {
 -        return new ColumnDefinition(name, validator, componentIndex, Type.CLUSTERING_KEY);
 +        return new ColumnDefinition(cfm, name, validator, componentIndex, Kind.CLUSTERING_COLUMN);
      }
  
 -    public static ColumnDefinition regularDef(ByteBuffer name, AbstractType<?> validator, Integer componentIndex)
 +    public static ColumnDefinition regularDef(CFMetaData cfm, ByteBuffer name, AbstractType<?> validator, Integer componentIndex)
      {
 -        return new ColumnDefinition(name, validator, componentIndex, Type.REGULAR);
 +        return new ColumnDefinition(cfm, name, validator, componentIndex, Kind.REGULAR);
      }
  
 -    public static ColumnDefinition staticDef(ByteBuffer name, AbstractType<?> validator, Integer componentIndex)
++    public static ColumnDefinition staticDef(CFMetaData cfm, ByteBuffer name, AbstractType<?> validator, Integer componentIndex)
+     {
 -        return new ColumnDefinition(name, validator, componentIndex, Type.STATIC);
++        return new ColumnDefinition(cfm, name, validator, componentIndex, Kind.STATIC);
+     }
+ 
 -    public static ColumnDefinition compactValueDef(ByteBuffer name, AbstractType<?> validator)
 +    public static ColumnDefinition compactValueDef(CFMetaData cfm, ByteBuffer name, AbstractType<?> validator)
      {
 -        return new ColumnDefinition(name, validator, null, Type.COMPACT_VALUE);
 +        return new ColumnDefinition(cfm, name, validator, null, Kind.COMPACT_VALUE);
      }
  
 -    public ColumnDefinition(ByteBuffer name, AbstractType<?> validator, Integer componentIndex, Type type)
 +    public ColumnDefinition(CFMetaData cfm, ByteBuffer name, AbstractType<?> validator, Integer componentIndex, Kind kind)
      {
 -        this(name, validator, null, null, null, componentIndex, type);
 +        this(cfm.ksName,
 +             cfm.cfName,
 +             new ColumnIdentifier(name, cfm.getComponentComparator(componentIndex, kind)),
 +             validator,
 +             null,
 +             null,
 +             null,
 +             componentIndex,
 +             kind);
      }
  
      @VisibleForTesting
@@@ -134,42 -119,25 +140,47 @@@
                              Map<String, String> indexOptions,
                              String indexName,
                              Integer componentIndex,
 -                            Type type)
 +                            Kind kind)
      {
 +        super(ksName, cfName, name, validator);
          assert name != null && validator != null;
 -        this.name = name;
 +        this.kind = kind;
          this.indexName = indexName;
 -        this.validator = validator;
          this.componentIndex = componentIndex;
          this.setIndexType(indexType, indexOptions);
 -        this.type = type;
      }
  
 -    public ColumnDefinition clone()
 +    public ColumnDefinition copy()
 +    {
 +        return new ColumnDefinition(ksName, cfName, name, type, indexType, indexOptions, indexName, componentIndex, kind);
 +    }
 +
 +    public ColumnDefinition withNewName(ColumnIdentifier newName)
 +    {
 +        return new ColumnDefinition(ksName, cfName, newName, type, indexType, indexOptions, indexName, componentIndex, kind);
 +    }
 +
 +    public ColumnDefinition withNewType(AbstractType<?> newType)
      {
 -        return new ColumnDefinition(name, validator, indexType, indexOptions, indexName, componentIndex, type);
 +        return new ColumnDefinition(ksName, cfName, name, newType, indexType, indexOptions, indexName, componentIndex, kind);
      }
  
 -    public ColumnDefinition cloneWithNewName(ByteBuffer newName)
 +    public boolean isOnAllComponents()
      {
 -        return new ColumnDefinition(newName, validator, indexType, indexOptions, indexName, componentIndex, type);
 +        return componentIndex == null;
 +    }
 +
++    public boolean isStatic()
++    {
++        return kind == Kind.STATIC;
++    }
++
 +    // The componentIndex. This never return null however for convenience sake:
 +    // if componentIndex == null, this return 0. So caller should first check
 +    // isOnAllComponents() to distinguish if that's a possibility.
 +    public int position()
 +    {
 +        return componentIndex == null ? 0 : componentIndex;
      }
  
      @Override
@@@ -215,9 -180,10 +226,14 @@@
  
      public boolean isThriftCompatible()
      {
 -        // componentIndex == null should always imply isStatic in practice, but there is no harm in being too careful here.
 -        return type == ColumnDefinition.Type.REGULAR && componentIndex == null;
 +        return kind == ColumnDefinition.Kind.REGULAR && componentIndex == null;
 +    }
 +
++    public boolean isPrimaryKeyColumn()
++    {
++        return kind == Kind.PARTITION_KEY || kind == Kind.CLUSTERING_COLUMN;
+     }
+ 
      public static List<ColumnDef> toThrift(Map<ByteBuffer, ColumnDefinition> columns)
      {
          List<ColumnDef> thriftDefs = new ArrayList<>(columns.size());

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/CQL3Row.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/CQL3Row.java
index afeb095,0000000..6fa2b64
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/CQL3Row.java
+++ b/src/java/org/apache/cassandra/cql3/CQL3Row.java
@@@ -1,36 -1,0 +1,41 @@@
 +/*
 + * 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.nio.ByteBuffer;
 +import java.util.Iterator;
 +import java.util.List;
 +
 +import org.apache.cassandra.db.Cell;
 +
 +public interface CQL3Row
 +{
 +    public ByteBuffer getClusteringColumn(int i);
 +    public Cell getColumn(ColumnIdentifier name);
 +    public List<Cell> getCollection(ColumnIdentifier name);
 +
 +    public interface Builder
 +    {
-         Iterator<CQL3Row> group(Iterator<Cell> cells);
++        public RowIterator group(Iterator<Cell> cells);
++    }
++
++    public interface RowIterator extends Iterator<CQL3Row>
++    {
++        public CQL3Row getStaticRow();
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/ColumnCondition.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/ColumnCondition.java
index 0000000,797dba6..735388d
mode 000000,100644..100644
--- a/src/java/org/apache/cassandra/cql3/ColumnCondition.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnCondition.java
@@@ -1,0 -1,191 +1,183 @@@
+ /*
+  * 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.nio.ByteBuffer;
+ import java.util.*;
+ 
+ import com.google.common.base.Predicate;
+ import com.google.common.collect.Iterators;
+ 
+ import org.apache.cassandra.config.CFMetaData;
++import org.apache.cassandra.config.ColumnDefinition;
+ import org.apache.cassandra.db.*;
++import org.apache.cassandra.db.composites.CellName;
++import org.apache.cassandra.db.composites.Composite;
+ import org.apache.cassandra.db.filter.ColumnSlice;
+ import org.apache.cassandra.db.marshal.CollectionType;
+ import org.apache.cassandra.db.marshal.CounterColumnType;
+ import org.apache.cassandra.db.marshal.CompositeType;
+ import org.apache.cassandra.exceptions.InvalidRequestException;
+ 
+ /**
+  * A CQL3 condition.
+  */
+ public class ColumnCondition
+ {
 -    public final CFDefinition.Name column;
++    public final ColumnDefinition column;
+     private final Term value;
+ 
+     private List<ByteBuffer> variables;
+ 
 -    private ColumnCondition(CFDefinition.Name column, Term value)
++    private ColumnCondition(ColumnDefinition column, Term value)
+     {
+         this.column = column;
+         this.value = value;
+     }
+ 
+     // The only ones we support so far
 -    public static ColumnCondition equal(CFDefinition.Name column, Term value)
++    public static ColumnCondition equal(ColumnDefinition column, Term value)
+     {
+         return new ColumnCondition(column, value);
+     }
+ 
+     // See CQL3CasConditions for why it's convenient to have this
+     public ColumnCondition attach(List<ByteBuffer> variables)
+     {
+         this.variables = variables;
+         return this;
+     }
+ 
+     /**
+      * Collects the column specification for the bind variables of this operation.
+      *
+      * @param boundNames the list of column specification where to collect the
+      * bind variables of this term in.
+      */
+     public void collectMarkerSpecification(VariableSpecifications boundNames)
+     {
+         value.collectMarkerSpecification(boundNames);
+     }
+ 
+     // Not overriding equals() because we need the variables to have been attached when this is
+     // called and so having a non standard method name might help avoid mistakes
+     public boolean equalsTo(ColumnCondition other) throws InvalidRequestException
+     {
+         return column.equals(other.column)
+             && value.bindAndGet(variables).equals(other.value.bindAndGet(other.variables));
+     }
+ 
 -    private ColumnNameBuilder copyOrUpdatePrefix(CFMetaData cfm, ColumnNameBuilder rowPrefix)
 -    {
 -        return column.kind == CFDefinition.Name.Kind.STATIC ? cfm.getStaticColumnNameBuilder() : rowPrefix.copy();
 -    }
 -
+     /**
+      * Validates whether this condition applies to {@code current}.
+      */
 -    public boolean appliesTo(ColumnNameBuilder rowPrefix, ColumnFamily current, long now) throws InvalidRequestException
++    public boolean appliesTo(Composite rowPrefix, ColumnFamily current, long now) throws InvalidRequestException
+     {
+         if (column.type instanceof CollectionType)
+             return collectionAppliesTo((CollectionType)column.type, rowPrefix, current, now);
+ 
 -        Column c = current.getColumn(copyOrUpdatePrefix(current.metadata(), rowPrefix).add(column.name.key).build());
++        Cell c = current.getColumn(current.metadata().comparator.create(rowPrefix, column));
+         ByteBuffer v = value.bindAndGet(variables);
+         return v == null
+              ? c == null || !c.isLive(now)
+              : c != null && c.isLive(now) && c.value().equals(v);
+     }
+ 
 -    private boolean collectionAppliesTo(CollectionType type, ColumnNameBuilder rowPrefix, ColumnFamily current, final long now) throws InvalidRequestException
++    private boolean collectionAppliesTo(CollectionType type, Composite rowPrefix, ColumnFamily current, final long now) throws InvalidRequestException
+     {
 -        ColumnNameBuilder collectionPrefix = copyOrUpdatePrefix(current.metadata(), rowPrefix).add(column.name.key);
++        CellName name = current.metadata().comparator.create(rowPrefix, column);
+         // We are testing for collection equality, so we need to have the expected values *and* only those.
 -        ColumnSlice[] collectionSlice = new ColumnSlice[]{ new ColumnSlice(collectionPrefix.build(), collectionPrefix.buildAsEndOfRange()) };
++        ColumnSlice[] collectionSlice = new ColumnSlice[]{ name.slice() };
+         // Filter live columns, this makes things simpler afterwards
 -        Iterator<Column> iter = Iterators.filter(current.iterator(collectionSlice), new Predicate<Column>()
++        Iterator<Cell> iter = Iterators.filter(current.iterator(collectionSlice), new Predicate<Cell>()
+         {
 -            public boolean apply(Column c)
++            public boolean apply(Cell c)
+             {
+                 // we only care about live columns
+                 return c.isLive(now);
+             }
+         });
+ 
+         Term.Terminal v = value.bind(variables);
+         if (v == null)
+             return !iter.hasNext();
+ 
+         switch (type.kind)
+         {
+             case LIST: return listAppliesTo(current.metadata(), iter, ((Lists.Value)v).elements);
+             case SET: return setAppliesTo(current.metadata(), iter, ((Sets.Value)v).elements);
+             case MAP: return mapAppliesTo(current.metadata(), iter, ((Maps.Value)v).map);
+         }
+         throw new AssertionError();
+     }
+ 
 -    private static ByteBuffer collectionKey(CFMetaData cfm, Column c)
 -    {
 -        ByteBuffer[] bbs = ((CompositeType)cfm.comparator).split(c.name());
 -        return bbs[bbs.length - 1];
 -    }
 -
 -    private boolean listAppliesTo(CFMetaData cfm, Iterator<Column> iter, List<ByteBuffer> elements)
++    private boolean listAppliesTo(CFMetaData cfm, Iterator<Cell> iter, List<ByteBuffer> elements)
+     {
+         for (ByteBuffer e : elements)
+             if (!iter.hasNext() || iter.next().value().equals(e))
+                 return false;
+         // We must not have more elements than expected
+         return !iter.hasNext();
+     }
+ 
 -    private boolean setAppliesTo(CFMetaData cfm, Iterator<Column> iter, Set<ByteBuffer> elements)
++    private boolean setAppliesTo(CFMetaData cfm, Iterator<Cell> iter, Set<ByteBuffer> elements)
+     {
+         Set<ByteBuffer> remaining = new HashSet<>(elements);
+         while (iter.hasNext())
+         {
+             if (remaining.isEmpty())
+                 return false;
+ 
 -            if (!remaining.remove(collectionKey(cfm, iter.next())))
++            if (!remaining.remove(iter.next().name().collectionElement()))
+                 return false;
+         }
+         return remaining.isEmpty();
+     }
+ 
 -    private boolean mapAppliesTo(CFMetaData cfm, Iterator<Column> iter, Map<ByteBuffer, ByteBuffer> elements)
++    private boolean mapAppliesTo(CFMetaData cfm, Iterator<Cell> iter, Map<ByteBuffer, ByteBuffer> elements)
+     {
+         Map<ByteBuffer, ByteBuffer> remaining = new HashMap<>(elements);
+         while (iter.hasNext())
+         {
+             if (remaining.isEmpty())
+                 return false;
+ 
 -            Column c = iter.next();
 -            if (!remaining.remove(collectionKey(cfm, c)).equals(c.value()))
++            Cell c = iter.next();
++            if (!remaining.remove(c.name().collectionElement()).equals(c.value()))
+                 return false;
+         }
+         return remaining.isEmpty();
+     }
+ 
+     public static class Raw
+     {
+         private final Term.Raw value;
+ 
+         public Raw(Term.Raw value)
+         {
+             this.value = value;
+         }
+ 
 -        public ColumnCondition prepare(CFDefinition.Name receiver) throws InvalidRequestException
++        public ColumnCondition prepare(String keyspace, ColumnDefinition receiver) throws InvalidRequestException
+         {
+             if (receiver.type instanceof CounterColumnType)
+                 throw new InvalidRequestException("Condtions on counters are not supported");
+ 
 -            return ColumnCondition.equal(receiver, value.prepare(receiver));
++            return ColumnCondition.equal(receiver, value.prepare(keyspace, receiver));
+         }
+     }
+ }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/Constants.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Constants.java
index 44e96ef,f99fd02..3b7b4c4
--- a/src/java/org/apache/cassandra/cql3/Constants.java
+++ b/src/java/org/apache/cassandra/cql3/Constants.java
@@@ -296,9 -294,10 +296,9 @@@ public abstract class Constant
              super(column, t);
          }
  
 -        public void execute(ByteBuffer rowKey, ColumnFamily cf, ColumnNameBuilder prefix, UpdateParameters params) throws InvalidRequestException
 +        public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
          {
-             CellName cname = cf.getComparator().create(prefix, column.name);
 -            prefix = maybeUpdatePrefix(cf.metadata(), prefix);
 -            ByteBuffer cname = columnName == null ? prefix.build() : prefix.add(columnName.key).build();
++            CellName cname = cf.getComparator().create(prefix, column);
              ByteBuffer value = t.bindAndGet(params.variables);
              cf.addColumn(value == null ? params.makeTombstone(cname) : params.makeColumn(cname, value));
          }
@@@ -317,7 -316,8 +317,7 @@@
              if (bytes == null)
                  throw new InvalidRequestException("Invalid null value for counter increment");
              long increment = ByteBufferUtil.toLong(bytes);
-             CellName cname = cf.getComparator().create(prefix, column.name);
 -            prefix = maybeUpdatePrefix(cf.metadata(), prefix);
 -            ByteBuffer cname = columnName == null ? prefix.build() : prefix.add(columnName.key).build();
++            CellName cname = cf.getComparator().create(prefix, column);
              cf.addCounter(cname, increment);
          }
      }
@@@ -339,7 -339,8 +339,7 @@@
              if (increment == Long.MIN_VALUE)
                  throw new InvalidRequestException("The negation of " + increment + " overflows supported counter precision (signed 8 bytes integer)");
  
-             CellName cname = cf.getComparator().create(prefix, column.name);
 -            prefix = maybeUpdatePrefix(cf.metadata(), prefix);
 -            ByteBuffer cname = columnName == null ? prefix.build() : prefix.add(columnName.key).build();
++            CellName cname = cf.getComparator().create(prefix, column);
              cf.addCounter(cname, -increment);
          }
      }
@@@ -348,18 -349,22 +348,18 @@@
      // duplicating this further
      public static class Deleter extends Operation
      {
 -        private final boolean isCollection;
 -
 -        public Deleter(ColumnIdentifier column, boolean isCollection)
 +        public Deleter(ColumnDefinition column)
          {
              super(column, null);
 -            this.isCollection = isCollection;
          }
  
 -        public void execute(ByteBuffer rowKey, ColumnFamily cf, ColumnNameBuilder prefix, UpdateParameters params) throws InvalidRequestException
 +        public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
          {
-             CellName cname = cf.getComparator().create(prefix, column.name);
 -            ColumnNameBuilder column = maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key);
 -
 -            if (isCollection)
 -                cf.addAtom(params.makeRangeTombstone(column.build(), column.buildAsEndOfRange()));
++            CellName cname = cf.getComparator().create(prefix, column);
 +            if (column.type.isCollection())
 +                cf.addAtom(params.makeRangeTombstone(cname.slice()));
              else
 -                cf.addColumn(params.makeTombstone(column.build()));
 +                cf.addColumn(params.makeTombstone(cname));
          }
      };
  }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/Cql.g
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Cql.g
index 55d8aac,a11a818..0ec283c
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@@ -1081,8 -988,9 +1088,9 @@@ basic_unreserved_keyword returns [Strin
          | K_CUSTOM
          | K_TRIGGER
          | K_DISTINCT
 +        | K_CONTAINS
+         | K_STATIC
          ) { $str = $k.text; }
 -    | t=native_type { $str = t.toString(); }
      ;
  
  

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/Lists.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Lists.java
index 8dbe59c,4ad39db..580a2c9
--- a/src/java/org/apache/cassandra/cql3/Lists.java
+++ b/src/java/org/apache/cassandra/cql3/Lists.java
@@@ -265,12 -263,12 +265,12 @@@ public abstract class List
              super(column, t);
          }
  
 -        public void execute(ByteBuffer rowKey, ColumnFamily cf, ColumnNameBuilder prefix, UpdateParameters params) throws InvalidRequestException
 +        public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
          {
              // delete + append
-             CellName name = cf.getComparator().create(prefix, column.name);
 -            ColumnNameBuilder column = maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key);
 -            cf.addAtom(params.makeTombstoneForOverwrite(column.build(), column.buildAsEndOfRange()));
 -            Appender.doAppend(t, cf, column, params);
++            CellName name = cf.getComparator().create(prefix, column);
 +            cf.addAtom(params.makeTombstoneForOverwrite(name.slice()));
-             Appender.doAppend(t, cf, prefix, column.name, params);
++            Appender.doAppend(t, cf, prefix, column, params);
          }
      }
  
@@@ -335,12 -335,12 +335,12 @@@
              super(column, t);
          }
  
 -        public void execute(ByteBuffer rowKey, ColumnFamily cf, ColumnNameBuilder prefix, UpdateParameters params) throws InvalidRequestException
 +        public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
          {
-             doAppend(t, cf, prefix, column.name, params);
 -            doAppend(t, cf, maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key), params);
++            doAppend(t, cf, prefix, column, params);
          }
  
-         static void doAppend(Term t, ColumnFamily cf, Composite prefix, ColumnIdentifier columnName, UpdateParameters params) throws InvalidRequestException
 -        static void doAppend(Term t, ColumnFamily cf, ColumnNameBuilder columnName, UpdateParameters params) throws InvalidRequestException
++        static void doAppend(Term t, ColumnFamily cf, Composite prefix, ColumnDefinition column, UpdateParameters params) throws InvalidRequestException
          {
              Term.Terminal value = t.bind(params.variables);
              // If we append null, do nothing. Note that for Setter, we've
@@@ -352,8 -352,10 +352,8 @@@
              List<ByteBuffer> toAdd = ((Lists.Value)value).elements;
              for (int i = 0; i < toAdd.size(); i++)
              {
 -                ColumnNameBuilder b = i == toAdd.size() - 1 ? columnName : columnName.copy();
                  ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes());
-                 cf.addColumn(params.makeColumn(cf.getComparator().create(prefix, columnName, uuid), toAdd.get(i)));
 -                ByteBuffer cellName = b.add(uuid).build();
 -                cf.addColumn(params.makeColumn(cellName, toAdd.get(i)));
++                cf.addColumn(params.makeColumn(cf.getComparator().create(prefix, column, uuid), toAdd.get(i)));
              }
          }
      }
@@@ -375,11 -377,14 +375,11 @@@
              long time = PrecisionTime.REFERENCE_TIME - (System.currentTimeMillis() - PrecisionTime.REFERENCE_TIME);
  
              List<ByteBuffer> toAdd = ((Lists.Value)value).elements;
 -            ColumnNameBuilder column = maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key);
              for (int i = 0; i < toAdd.size(); i++)
              {
 -                ColumnNameBuilder b = i == toAdd.size() - 1 ? column : column.copy();
                  PrecisionTime pt = PrecisionTime.getNext(time);
                  ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(pt.millis, pt.nanos));
-                 cf.addColumn(params.makeColumn(cf.getComparator().create(prefix, column.name, uuid), toAdd.get(i)));
 -                ByteBuffer cellName = b.add(uuid).build();
 -                cf.addColumn(params.makeColumn(cellName, toAdd.get(i)));
++                cf.addColumn(params.makeColumn(cf.getComparator().create(prefix, column, uuid), toAdd.get(i)));
              }
          }
      }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/Maps.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Maps.java
index 3f9cc95,c332999..d113b57
--- a/src/java/org/apache/cassandra/cql3/Maps.java
+++ b/src/java/org/apache/cassandra/cql3/Maps.java
@@@ -244,12 -241,12 +244,12 @@@ public abstract class Map
              super(column, t);
          }
  
 -        public void execute(ByteBuffer rowKey, ColumnFamily cf, ColumnNameBuilder prefix, UpdateParameters params) throws InvalidRequestException
 +        public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
          {
              // delete + put
-             CellName name = cf.getComparator().create(prefix, column.name);
 -            ColumnNameBuilder column = maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key);
 -            cf.addAtom(params.makeTombstoneForOverwrite(column.build(), column.buildAsEndOfRange()));
 -            Putter.doPut(t, cf, column, params);
++            CellName name = cf.getComparator().create(prefix, column);
 +            cf.addAtom(params.makeTombstoneForOverwrite(name.slice()));
-             Putter.doPut(t, cf, prefix, column.name, params);
++            Putter.doPut(t, cf, prefix, column, params);
          }
      }
  
@@@ -277,7 -274,7 +277,7 @@@
              if (key == null)
                  throw new InvalidRequestException("Invalid null map key");
  
-             CellName cellName = cf.getComparator().create(prefix, column.name, key);
 -            ByteBuffer cellName = maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key).add(key).build();
++            CellName cellName = cf.getComparator().create(prefix, column, key);
  
              if (value == null)
              {
@@@ -303,12 -300,12 +303,12 @@@
              super(column, t);
          }
  
 -        public void execute(ByteBuffer rowKey, ColumnFamily cf, ColumnNameBuilder prefix, UpdateParameters params) throws InvalidRequestException
 +        public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
          {
-             doPut(t, cf, prefix, column.name, params);
 -            doPut(t, cf, maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key), params);
++            doPut(t, cf, prefix, column, params);
          }
  
-         static void doPut(Term t, ColumnFamily cf, Composite prefix, ColumnIdentifier columnName, UpdateParameters params) throws InvalidRequestException
 -        static void doPut(Term t, ColumnFamily cf, ColumnNameBuilder columnName, UpdateParameters params) throws InvalidRequestException
++        static void doPut(Term t, ColumnFamily cf, Composite prefix, ColumnDefinition column, UpdateParameters params) throws InvalidRequestException
          {
              Term.Terminal value = t.bind(params.variables);
              if (value == null)
@@@ -318,7 -315,7 +318,7 @@@
              Map<ByteBuffer, ByteBuffer> toAdd = ((Maps.Value)value).map;
              for (Map.Entry<ByteBuffer, ByteBuffer> entry : toAdd.entrySet())
              {
-                 CellName cellName = cf.getComparator().create(prefix, columnName, entry.getKey());
 -                ByteBuffer cellName = columnName.copy().add(entry.getKey()).build();
++                CellName cellName = cf.getComparator().create(prefix, column, entry.getKey());
                  cf.addColumn(params.makeColumn(cellName, entry.getValue()));
              }
          }
@@@ -338,7 -335,7 +338,7 @@@
                  throw new InvalidRequestException("Invalid null map key");
              assert key instanceof Constants.Value;
  
-             CellName cellName = cf.getComparator().create(prefix, column.name, ((Constants.Value)key).bytes);
 -            ByteBuffer cellName = maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key).add(((Constants.Value)key).bytes).build();
++            CellName cellName = cf.getComparator().create(prefix, column, ((Constants.Value)key).bytes);
              cf.addColumn(params.makeTombstone(cellName));
          }
      }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/Sets.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Sets.java
index dddea09,69bc3d3..e48a3ce
--- a/src/java/org/apache/cassandra/cql3/Sets.java
+++ b/src/java/org/apache/cassandra/cql3/Sets.java
@@@ -230,12 -227,12 +230,12 @@@ public abstract class Set
              super(column, t);
          }
  
 -        public void execute(ByteBuffer rowKey, ColumnFamily cf, ColumnNameBuilder prefix, UpdateParameters params) throws InvalidRequestException
 +        public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
          {
              // delete + add
-             CellName name = cf.getComparator().create(prefix, column.name);
 -            ColumnNameBuilder column = maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key);
 -            cf.addAtom(params.makeTombstoneForOverwrite(column.build(), column.buildAsEndOfRange()));
 -            Adder.doAdd(t, cf, column, params);
++            CellName name = cf.getComparator().create(prefix, column);
 +            cf.addAtom(params.makeTombstoneForOverwrite(name.slice()));
-             Adder.doAdd(t, cf, prefix, column.name, params);
++            Adder.doAdd(t, cf, prefix, column, params);
          }
      }
  
@@@ -246,12 -243,12 +246,12 @@@
              super(column, t);
          }
  
 -        public void execute(ByteBuffer rowKey, ColumnFamily cf, ColumnNameBuilder prefix, UpdateParameters params) throws InvalidRequestException
 +        public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException
          {
-             doAdd(t, cf, prefix, column.name, params);
 -            doAdd(t, cf, maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key), params);
++            doAdd(t, cf, prefix, column, params);
          }
  
-         static void doAdd(Term t, ColumnFamily cf, Composite prefix, ColumnIdentifier columnName, UpdateParameters params) throws InvalidRequestException
 -        static void doAdd(Term t, ColumnFamily cf, ColumnNameBuilder columnName, UpdateParameters params) throws InvalidRequestException
++        static void doAdd(Term t, ColumnFamily cf, Composite prefix, ColumnDefinition column, UpdateParameters params) throws InvalidRequestException
          {
              Term.Terminal value = t.bind(params.variables);
              if (value == null)
@@@ -262,7 -259,7 +262,7 @@@
              Set<ByteBuffer> toAdd = ((Sets.Value)value).elements;
              for (ByteBuffer bb : toAdd)
              {
-                 CellName cellName = cf.getComparator().create(prefix, columnName, bb);
 -                ByteBuffer cellName = columnName.copy().add(bb).build();
++                CellName cellName = cf.getComparator().create(prefix, column, bb);
                  cf.addColumn(params.makeColumn(cellName, ByteBufferUtil.EMPTY_BYTE_BUFFER));
              }
          }
@@@ -286,9 -283,11 +286,9 @@@
                                        ? Collections.singleton(((Constants.Value)value).bytes)
                                        : ((Sets.Value)value).elements;
  
 -            ColumnNameBuilder column = maybeUpdatePrefix(cf.metadata(), prefix).add(columnName.key);
              for (ByteBuffer bb : toDiscard)
              {
-                 cf.addColumn(params.makeTombstone(cf.getComparator().create(prefix, column.name, bb)));
 -                ByteBuffer cellName = column.copy().add(bb).build();
 -                cf.addColumn(params.makeTombstone(cellName));
++                cf.addColumn(params.makeTombstone(cf.getComparator().create(prefix, column, bb)));
              }
          }
      }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
index 0932b5c,85b3547..9c097a3
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
@@@ -45,8 -47,15 +45,15 @@@ public class AlterTableStatement extend
      public final ColumnIdentifier columnName;
      private final CFPropDefs cfProps;
      private final Map<ColumnIdentifier, ColumnIdentifier> renames;
- 
-     public AlterTableStatement(CFName name, Type type, ColumnIdentifier columnName, CQL3Type.Raw validator, CFPropDefs cfProps, Map<ColumnIdentifier, ColumnIdentifier> renames)
+     private final boolean isStatic; // Only for ALTER ADD
+ 
+     public AlterTableStatement(CFName name,
+                                Type type,
+                                ColumnIdentifier columnName,
 -                               CQL3Type validator,
++                               CQL3Type.Raw validator,
+                                CFPropDefs cfProps,
+                                Map<ColumnIdentifier, ColumnIdentifier> renames,
+                                boolean isStatic)
      {
          super(name);
          this.oType = type;
@@@ -77,16 -86,20 +85,18 @@@
          switch (oType)
          {
              case ADD:
 -                if (cfDef.isCompact)
 +                if (cfm.comparator.isDense())
-                     throw new InvalidRequestException("Cannot add new column to a compact CF");
+                     throw new InvalidRequestException("Cannot add new column to a COMPACT STORAGE table");
 -
 -                if (isStatic && !cfDef.isComposite)
++                if (isStatic && !cfm.comparator.isCompound())
+                     throw new InvalidRequestException("Static columns are not allowed in COMPACT STORAGE tables");
 -
 -                if (name != null)
 +                if (def != null)
                  {
 -                    switch (name.kind)
 +                    switch (def.kind)
                      {
 -                        case KEY_ALIAS:
 -                        case COLUMN_ALIAS:
 +                        case PARTITION_KEY:
 +                        case CLUSTERING_COLUMN:
                              throw new InvalidRequestException(String.format("Invalid column name %s because it conflicts with a PRIMARY KEY part", columnName));
-                         case REGULAR:
+                         default:
                              throw new InvalidRequestException(String.format("Invalid column name %s because it conflicts with an existing column", columnName));
                      }
                  }
@@@ -94,16 -107,31 +104,18 @@@
                  AbstractType<?> type = validator.getType();
                  if (type instanceof CollectionType)
                  {
 -                    if (!cfDef.isComposite)
 +                    if (!cfm.comparator.supportCollections())
                          throw new InvalidRequestException("Cannot use collection types with non-composite PRIMARY KEY");
 -                    if (cfDef.cfm.isSuper())
 +                    if (cfm.isSuper())
                          throw new InvalidRequestException("Cannot use collection types with Super column family");
  
 -                    Map<ByteBuffer, CollectionType> collections = cfDef.hasCollections
 -                                                                ? new HashMap<ByteBuffer, CollectionType>(cfDef.getCollectionType().defined)
 -                                                                : new HashMap<ByteBuffer, CollectionType>();
 -
 -                    collections.put(columnName.key, (CollectionType)type);
 -                    ColumnToCollectionType newColType = ColumnToCollectionType.getInstance(collections);
 -                    List<AbstractType<?>> ctypes = new ArrayList<AbstractType<?>>(((CompositeType)cfm.comparator).types);
 -                    if (cfDef.hasCollections)
 -                        ctypes.set(ctypes.size() - 1, newColType);
 -                    else
 -                        ctypes.add(newColType);
 -                    cfm.comparator = CompositeType.getInstance(ctypes);
 +                    cfm.comparator = cfm.comparator.addCollection(columnName, (CollectionType)type);
                  }
  
 -                Integer componentIndex = cfDef.isComposite
 -                                       ? ((CompositeType)meta.comparator).types.size() - (cfDef.hasCollections ? 2 : 1)
 -                                       : null;
 +                Integer componentIndex = cfm.comparator.isCompound() ? cfm.comparator.clusteringPrefixSize() : null;
-                 cfm.addColumnDefinition(ColumnDefinition.regularDef(cfm, columnName.bytes, type, componentIndex));
+                 cfm.addColumnDefinition(isStatic
 -                                        ? ColumnDefinition.staticDef(columnName.key, type, componentIndex)
 -                                        : ColumnDefinition.regularDef(columnName.key, type, componentIndex));
++                                        ? ColumnDefinition.staticDef(cfm, columnName.bytes, type, componentIndex)
++                                        : ColumnDefinition.regularDef(cfm, columnName.bytes, type, componentIndex));
                  break;
  
              case ALTER:
@@@ -161,7 -191,9 +173,8 @@@
                                                                             validator));
                          cfm.defaultValidator(validator.getType());
                          break;
 -                    case COLUMN_METADATA:
 +                    case REGULAR:
+                     case STATIC:
 -                        ColumnDefinition column = cfm.getColumnDefinition(columnName.key);
                          // Thrift allows to change a column validator so CFMetaData.validateCompatibility will let it slide
                          // if we change to an incompatible type (contrarily to the comparator case). But we don't want to
                          // allow it for CQL3 (see #5882) so validating it explicitly here. We only care about value compatibility
@@@ -180,21 -211,22 +193,22 @@@
                  break;
  
              case DROP:
 -                if (cfDef.isCompact || !cfDef.isComposite)
 -                    throw new InvalidRequestException("Cannot drop columns from a COMPACT STORAGE table");
 -                if (name == null)
 +                if (!cfm.isCQL3Table())
-                     throw new InvalidRequestException("Cannot drop columns from a non-CQL3 CF");
++                    throw new InvalidRequestException("Cannot drop columns from a non-CQL3 table");
 +                if (def == null)
-                     throw new InvalidRequestException(String.format("Cell %s was not found in table %s", columnName, columnFamily()));
+                     throw new InvalidRequestException(String.format("Column %s was not found in table %s", columnName, columnFamily()));
  
 -                switch (name.kind)
 +                switch (def.kind)
                  {
 -                    case KEY_ALIAS:
 -                    case COLUMN_ALIAS:
 +                    case PARTITION_KEY:
 +                    case CLUSTERING_COLUMN:
                          throw new InvalidRequestException(String.format("Cannot drop PRIMARY KEY part %s", columnName));
 -                    case COLUMN_METADATA:
 +                    case REGULAR:
+                     case STATIC:
                          ColumnDefinition toDelete = null;
-                         for (ColumnDefinition columnDef : cfm.regularColumns())
+                         for (ColumnDefinition columnDef : cfm.regularAndStaticColumns())
                          {
 -                            if (columnDef.name.equals(columnName.key))
 +                            if (columnDef.name.equals(columnName))
                                  toDelete = columnDef;
                          }
                          assert toDelete != null;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
index 2c8b2b7,d4acbae..ab2b4bc
--- a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
@@@ -20,12 -20,11 +20,13 @@@ package org.apache.cassandra.cql3.state
  import java.nio.ByteBuffer;
  import java.util.*;
  
+ import com.google.common.collect.Iterables;
  import org.github.jamm.MemoryMeter;
  
++import org.apache.cassandra.config.ColumnDefinition;
  import org.apache.cassandra.cql3.*;
- import org.apache.cassandra.db.ConsistencyLevel;
- import org.apache.cassandra.db.IMutation;
- import org.apache.cassandra.db.Mutation;
+ import org.apache.cassandra.db.*;
++import org.apache.cassandra.db.composites.Composite;
  import org.apache.cassandra.exceptions.*;
  import org.apache.cassandra.service.ClientState;
  import org.apache.cassandra.service.QueryState;
@@@ -175,17 -182,103 +184,108 @@@ public class BatchStatement implements 
          StorageProxy.mutateWithTriggers(mutations, cl, mutateAtomic);
      }
  
+     private ResultMessage executeWithConditions(BatchVariables variables, ConsistencyLevel cl, ConsistencyLevel serialCf, long now)
+     throws RequestExecutionException, RequestValidationException
+     {
+         ByteBuffer key = null;
+         String ksName = null;
+         String cfName = null;
+         ColumnFamily updates = null;
+         CQL3CasConditions conditions = null;
 -        Set<ColumnIdentifier> columnsWithConditions = new LinkedHashSet<ColumnIdentifier>();
++        Set<ColumnDefinition> columnsWithConditions = new LinkedHashSet<ColumnDefinition>();
+ 
+         for (int i = 0; i < statements.size(); i++)
+         {
+             ModificationStatement statement = statements.get(i);
+             List<ByteBuffer> statementVariables = variables.getVariablesForStatement(i);
+             long timestamp = attrs.getTimestamp(now, statementVariables);
+             List<ByteBuffer> pks = statement.buildPartitionKeyNames(statementVariables);
+             if (pks.size() > 1)
+                 throw new IllegalArgumentException("Batch with conditions cannot span multiple partitions (you cannot use IN on the partition key)");
+             if (key == null)
+             {
+                 key = pks.get(0);
+                 ksName = statement.cfm.ksName;
+                 cfName = statement.cfm.cfName;
+                 conditions = new CQL3CasConditions(statement.cfm, now);
 -                updates = UnsortedColumns.factory.create(statement.cfm);
++                updates = ArrayBackedSortedColumns.factory.create(statement.cfm);
+             }
+             else if (!key.equals(pks.get(0)))
+             {
+                 throw new InvalidRequestException("Batch with conditions cannot span multiple partitions");
+             }
+ 
+             if (statement.hasConditions())
+             {
 -                ColumnNameBuilder clusteringPrefix = statement.createClusteringPrefixBuilder(statementVariables);
++                Composite clusteringPrefix = statement.createClusteringPrefix(statementVariables);
+                 statement.addUpdatesAndConditions(key, clusteringPrefix, updates, conditions, statementVariables, timestamp);
+                 // As soon as we have a ifNotExists, we set columnsWithConditions to null so that everything is in the resultSet
+                 if (statement.hasIfNotExistCondition())
+                     columnsWithConditions = null;
+                 else if (columnsWithConditions != null)
+                     Iterables.addAll(columnsWithConditions, statement.getColumnsWithConditions());
+             }
+             else
+             {
+                 // getPartitionKey will already have thrown if there is more than one key involved
+                 IMutation mut = statement.getMutations(statementVariables, false, cl, timestamp, true).iterator().next();
 -                updates.resolve(mut.getColumnFamilies().iterator().next());
++                updates.addAll(mut.getColumnFamilies().iterator().next());
+             }
+         }
+ 
+         ColumnFamily result = StorageProxy.cas(ksName, cfName, key, conditions, updates, serialCf, cl);
+         return new ResultMessage.Rows(ModificationStatement.buildCasResultSet(ksName, key, cfName, result, columnsWithConditions, true));
+     }
+ 
      public ResultMessage executeInternal(QueryState queryState) throws RequestValidationException, RequestExecutionException
      {
-         for (IMutation mutation : getMutations(Collections.<ByteBuffer>emptyList(), true, null, queryState.getTimestamp()))
+         assert !hasConditions;
 -
 -        for (IMutation mutation : getMutations(new PreparedBatchVariables(Collections.<ByteBuffer>emptyList()), true, null, queryState.getTimestamp()))
 -            mutation.apply();
++        for (IMutation mutation : getMutations(PreparedBatchVariables.EMPTY, true, null, queryState.getTimestamp()))
 +        {
 +            // We don't use counters internally.
 +            assert mutation instanceof Mutation;
 +            ((Mutation) mutation).apply();
 +        }
          return null;
      }
  
+     public interface BatchVariables
+     {
+         public List<ByteBuffer> getVariablesForStatement(int statementInBatch);
+     }
+ 
+     public static class PreparedBatchVariables implements BatchVariables
+     {
++        public static final BatchVariables EMPTY = new PreparedBatchVariables(Collections.<ByteBuffer>emptyList());
++
+         private final List<ByteBuffer> variables;
+ 
+         public PreparedBatchVariables(List<ByteBuffer> variables)
+         {
+             this.variables = variables;
+         }
+ 
+         public List<ByteBuffer> getVariablesForStatement(int statementInBatch)
+         {
+             return variables;
+         }
+     }
+ 
+     public static class BatchOfPreparedVariables implements BatchVariables
+     {
+         private final List<List<ByteBuffer>> variables;
+ 
+         public BatchOfPreparedVariables(List<List<ByteBuffer>> variables)
+         {
+             this.variables = variables;
+         }
+ 
+         public List<ByteBuffer> getVariablesForStatement(int statementInBatch)
+         {
+             return variables.get(statementInBatch);
+         }
+     }
+ 
      public String toString()
      {
          return String.format("BatchStatement(type=%s, statements=%s)", type, statements);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java
index 0000000,194ff0c..56692f9
mode 000000,100644..100644
--- a/src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java
@@@ -1,0 -1,164 +1,164 @@@
+ /*
+  * 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.*;
+ 
+ import org.apache.cassandra.cql3.*;
+ import org.apache.cassandra.config.CFMetaData;
+ import org.apache.cassandra.db.*;
++import org.apache.cassandra.db.composites.Composite;
+ import org.apache.cassandra.db.filter.*;
+ import org.apache.cassandra.exceptions.InvalidRequestException;
+ import org.apache.cassandra.service.CASConditions;
+ 
+ /**
+  * Processed CAS conditions on potentially multiple rows of the same partition.
+  */
+ public class CQL3CasConditions implements CASConditions
+ {
+     private final CFMetaData cfm;
+     private final long now;
+ 
+     // We index RowCondition by the prefix of the row they applied to for 2 reasons:
+     //   1) this allows to keep things sorted to build the ColumnSlice array below
+     //   2) this allows to detect when contradictory conditions are set (not exists with some other conditions on the same row)
 -    private final SortedMap<ByteBuffer, RowCondition> conditions;
++    private final SortedMap<Composite, RowCondition> conditions;
+ 
+     public CQL3CasConditions(CFMetaData cfm, long now)
+     {
+         this.cfm = cfm;
+         this.now = now;
+         this.conditions = new TreeMap<>(cfm.comparator);
+     }
+ 
 -    public void addNotExist(ColumnNameBuilder prefix) throws InvalidRequestException
++    public void addNotExist(Composite prefix) throws InvalidRequestException
+     {
 -        RowCondition previous = conditions.put(prefix.build(), new NotExistCondition(prefix, now));
++        RowCondition previous = conditions.put(prefix, new NotExistCondition(prefix, now));
+         if (previous != null && !(previous instanceof NotExistCondition))
+             throw new InvalidRequestException("Cannot mix IF conditions and IF NOT EXISTS for the same row");
+     }
+ 
 -    public void addConditions(ColumnNameBuilder prefix, Collection<ColumnCondition> conds, List<ByteBuffer> variables) throws InvalidRequestException
++    public void addConditions(Composite prefix, Collection<ColumnCondition> conds, List<ByteBuffer> variables) throws InvalidRequestException
+     {
 -        ByteBuffer b = prefix.build();
 -        RowCondition condition = conditions.get(b);
++        RowCondition condition = conditions.get(prefix);
+         if (condition == null)
+         {
+             condition = new ColumnsConditions(prefix, now);
 -            conditions.put(b, condition);
++            conditions.put(prefix, condition);
+         }
+         else if (!(condition instanceof ColumnsConditions))
+         {
+             throw new InvalidRequestException("Cannot mix IF conditions and IF NOT EXISTS for the same row");
+         }
+         ((ColumnsConditions)condition).addConditions(conds, variables);
+     }
+ 
+     public IDiskAtomFilter readFilter()
+     {
+         assert !conditions.isEmpty();
+         ColumnSlice[] slices = new ColumnSlice[conditions.size()];
+         int i = 0;
+         // We always read CQL rows entirely as on CAS failure we want to be able to distinguish between "row exists
 -        // but all values on why there were conditions are null" and "row doesn't exists", and we can't rely on the
++        // but all values for which there were conditions are null" and "row doesn't exists", and we can't rely on the
+         // row marker for that (see #6623)
 -        for (Map.Entry<ByteBuffer, RowCondition> entry : conditions.entrySet())
 -            slices[i++] = new ColumnSlice(entry.getKey(), entry.getValue().rowPrefix.buildAsEndOfRange());
++        for (Composite prefix : conditions.keySet())
++            slices[i++] = prefix.slice();
+ 
 -        return new SliceQueryFilter(slices, false, slices.length, cfm.clusteringKeyColumns().size());
++        return new SliceQueryFilter(slices, false, slices.length, cfm.clusteringColumns().size());
+     }
+ 
+     public boolean appliesTo(ColumnFamily current) throws InvalidRequestException
+     {
+         for (RowCondition condition : conditions.values())
+         {
+             if (!condition.appliesTo(current))
+                 return false;
+         }
+         return true;
+     }
+ 
+     private static abstract class RowCondition
+     {
 -        public final ColumnNameBuilder rowPrefix;
++        public final Composite rowPrefix;
+         protected final long now;
+ 
 -        protected RowCondition(ColumnNameBuilder rowPrefix, long now)
++        protected RowCondition(Composite rowPrefix, long now)
+         {
+             this.rowPrefix = rowPrefix;
+             this.now = now;
+         }
+ 
+         public abstract boolean appliesTo(ColumnFamily current) throws InvalidRequestException;
+     }
+ 
+     private static class NotExistCondition extends RowCondition
+     {
 -        private NotExistCondition(ColumnNameBuilder rowPrefix, long now)
++        private NotExistCondition(Composite rowPrefix, long now)
+         {
+             super(rowPrefix, now);
+         }
+ 
+         public boolean appliesTo(ColumnFamily current)
+         {
+             if (current == null)
+                 return true;
+ 
 -            Iterator<Column> iter = current.iterator(new ColumnSlice[]{ new ColumnSlice(rowPrefix.build(), rowPrefix.buildAsEndOfRange()) });
++            Iterator<Cell> iter = current.iterator(new ColumnSlice[]{ rowPrefix.slice() });
+             while (iter.hasNext())
+                 if (iter.next().isLive(now))
+                     return false;
+             return true;
+         }
+     }
+ 
+     private static class ColumnsConditions extends RowCondition
+     {
+         private final Map<ColumnIdentifier, ColumnCondition> conditions = new HashMap<>();
+ 
 -        private ColumnsConditions(ColumnNameBuilder rowPrefix, long now)
++        private ColumnsConditions(Composite rowPrefix, long now)
+         {
+             super(rowPrefix, now);
+         }
+ 
+         public void addConditions(Collection<ColumnCondition> conds, List<ByteBuffer> variables) throws InvalidRequestException
+         {
+             for (ColumnCondition condition : conds)
+             {
+                 // We will need the variables in appliesTo but with protocol batches, each condition in this object can have a
+                 // different list of variables. So attach them to the condition directly, it's not particulary elegant but its simpler
+                 ColumnCondition previous = conditions.put(condition.column.name, condition.attach(variables));
+                 // If 2 conditions are actually equal, let it slide
+                 if (previous != null && !previous.equalsTo(condition))
+                     throw new InvalidRequestException("Duplicate and incompatible conditions for column " + condition.column.name);
+             }
+         }
+ 
+         public boolean appliesTo(ColumnFamily current) throws InvalidRequestException
+         {
+             if (current == null)
+                 return conditions.isEmpty();
+ 
+             for (ColumnCondition condition : conditions.values())
+                 if (!condition.appliesTo(rowPrefix, current, now))
+                     return false;
+             return true;
+         }
+     }
+ }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
index fe5508b,376fa4a..49a669f
--- a/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
@@@ -101,11 -84,23 +101,20 @@@ public class CreateIndexStatement exten
          properties.validate();
  
          // TODO: we could lift that limitation
 -        if (cfm.getCfDef().isCompact && cd.type != ColumnDefinition.Type.REGULAR)
 -            throw new InvalidRequestException(String.format("Secondary index on %s column %s is not yet supported for compact table", cd.type, columnName));
 +        if (cfm.comparator.isDense() && cd.kind != ColumnDefinition.Kind.REGULAR)
 +            throw new InvalidRequestException(String.format("Secondary index on %s column %s is not yet supported for compact table", cd.kind, target.column));
  
+         // It would be possible to support 2ndary index on static columns (but not without modifications of at least ExtendedFilter and
+         // CompositesIndex) and maybe we should, but that means a query like:
+         //     SELECT * FROM foo WHERE static_column = 'bar'
+         // would pull the full partition every time the static column of partition is 'bar', which sounds like offering a
+         // fair potential for foot-shooting, so I prefer leaving that to a follow up ticket once we have identified cases where
+         // such indexing is actually useful.
 -        if (cd.type == ColumnDefinition.Type.STATIC)
++        if (cd.isStatic())
+             throw new InvalidRequestException("Secondary indexes are not allowed on static columns");
+ 
 -        if (cd.getValidator().isCollection() && !properties.isCustom)
 -            throw new InvalidRequestException("Indexes on collections are no yet supported");
 -
 -        if (cd.type == ColumnDefinition.Type.PARTITION_KEY && cd.componentIndex == null)
 -            throw new InvalidRequestException(String.format("Cannot add secondary index to already primarily indexed column %s", columnName));
 +        if (cd.kind == ColumnDefinition.Kind.PARTITION_KEY && cd.isOnAllComponents())
 +            throw new InvalidRequestException(String.format("Cannot add secondary index to already primarily indexed column %s", target.column));
      }
  
      public void announceMigration() throws RequestValidationException

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63b1ef4e/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
index 8351e71,632194c..7cef999
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
@@@ -88,12 -89,25 +90,17 @@@ public class CreateTableStatement exten
      }
  
      // Column definitions
 -    private Map<ByteBuffer, ColumnDefinition> getColumns()
 +    private List<ColumnDefinition> getColumns(CFMetaData cfm)
      {
 -        Map<ByteBuffer, ColumnDefinition> columnDefs = new HashMap<ByteBuffer, ColumnDefinition>();
 -        Integer componentIndex = null;
 -        if (comparator instanceof CompositeType)
 -        {
 -            CompositeType ct = (CompositeType) comparator;
 -            componentIndex = ct.types.get(ct.types.size() - 1) instanceof ColumnToCollectionType
 -                           ? ct.types.size() - 2
 -                           : ct.types.size() - 1;
 -        }
 -
 +        List<ColumnDefinition> columnDefs = new ArrayList<>(columns.size());
 +        Integer componentIndex = comparator.isCompound() ? comparator.clusteringPrefixSize() : null;
          for (Map.Entry<ColumnIdentifier, AbstractType> col : columns.entrySet())
-             columnDefs.add(ColumnDefinition.regularDef(cfm, col.getKey().bytes, col.getValue(), componentIndex));
+         {
+             ColumnIdentifier id = col.getKey();
 -            columnDefs.put(id.key, staticColumns.contains(id)
 -                                   ? ColumnDefinition.staticDef(id.key, col.getValue(), componentIndex)
 -                                   : ColumnDefinition.regularDef(id.key, col.getValue(), componentIndex));
++            columnDefs.add(staticColumns.contains(id)
++                           ? ColumnDefinition.staticDef(cfm, col.getKey().bytes, col.getValue(), componentIndex)
++                           : ColumnDefinition.regularDef(cfm, col.getKey().bytes, col.getValue(), componentIndex));
+         }
  
          return columnDefs;
      }
@@@ -185,13 -201,13 +193,13 @@@
  
              properties.validate();
  
-             CreateTableStatement stmt = new CreateTableStatement(cfName, properties, ifNotExists);
+             CreateTableStatement stmt = new CreateTableStatement(cfName, properties, ifNotExists, staticColumns);
  
              Map<ByteBuffer, CollectionType> definedCollections = null;
 -            for (Map.Entry<ColumnIdentifier, CQL3Type> entry : definitions.entrySet())
 +            for (Map.Entry<ColumnIdentifier, CQL3Type.Raw> entry : definitions.entrySet())
              {
                  ColumnIdentifier id = entry.getKey();
 -                CQL3Type pt = entry.getValue();
 +                CQL3Type pt = entry.getValue().prepare(keyspace());
                  if (pt.isCollection())
                  {
                      if (definedCollections == null)
@@@ -248,11 -268,13 +258,16 @@@
                  {
                      if (definedCollections != null)
                          throw new InvalidRequestException("Collection types are not supported with COMPACT STORAGE");
-                     stmt.columnAliases.add(columnAliases.get(0).bytes);
-                     AbstractType<?> at = getTypeAndRemove(stmt.columns, columnAliases.get(0));
++
+                     ColumnIdentifier alias = columnAliases.get(0);
 -                    stmt.columnAliases.add(alias.key);
 -                    stmt.comparator = getTypeAndRemove(stmt.columns, alias);
 -                    if (stmt.comparator instanceof CounterColumnType)
 -                        throw new InvalidRequestException(String.format("counter type is not supported for PRIMARY KEY part %s", alias));
+                     if (staticColumns.contains(alias))
+                         throw new InvalidRequestException(String.format("Static column %s cannot be part of the PRIMARY KEY", alias));
++
++                    stmt.columnAliases.add(alias.bytes);
++                    AbstractType<?> at = getTypeAndRemove(stmt.columns, alias);
 +                    if (at instanceof CounterColumnType)
 +                        throw new InvalidRequestException(String.format("counter type is not supported for PRIMARY KEY part %s", stmt.columnAliases.get(0)));
 +                    stmt.comparator = new SimpleDenseCellNameType(at);
                  }
                  else
                  {
@@@ -263,7 -285,9 +278,9 @@@
  
                          AbstractType<?> type = getTypeAndRemove(stmt.columns, t);
                          if (type instanceof CounterColumnType)
 -                            throw new InvalidRequestException(String.format("counter type is not supported for PRIMARY KEY part %s", t.key));
 +                            throw new InvalidRequestException(String.format("counter type is not supported for PRIMARY KEY part %s", t));
+                         if (staticColumns.contains(t))
+                             throw new InvalidRequestException(String.format("Static column %s cannot be part of the PRIMARY KEY", t));
                          types.add(type);
                      }
  
@@@ -358,7 -396,7 +385,7 @@@
              return isReversed != null && isReversed ? ReversedType.getInstance(type) : type;
          }
  
-         public void addDefinition(ColumnIdentifier def, CQL3Type.Raw type)
 -        public void addDefinition(ColumnIdentifier def, CQL3Type type, boolean isStatic)
++        public void addDefinition(ColumnIdentifier def, CQL3Type.Raw type, boolean isStatic)
          {
              definedNames.add(def);
              definitions.put(def, type);