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 2015/05/27 16:03:50 UTC

cassandra git commit: Fix error executing bound statement after adding a collection

Repository: cassandra
Updated Branches:
  refs/heads/cassandra-2.0 3e4ed9666 -> 63165a719


Fix error executing bound statement after adding a collection

patch by blerer; reviewed by slebresne for CASSANDRA-9411


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

Branch: refs/heads/cassandra-2.0
Commit: 63165a719cd8ec9d7f06c186f61d39403e192edc
Parents: 3e4ed96
Author: Benjamin Lerer <be...@datastax.com>
Authored: Wed May 27 16:00:52 2015 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Wed May 27 16:00:52 2015 +0200

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 .../cql3/statements/ModificationStatement.java  |   6 +-
 .../cql3/statements/SelectStatement.java        | 186 +++++++++++--------
 3 files changed, 110 insertions(+), 83 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/63165a71/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index af08802..709100b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 2.0.16:
+ * Fix failing bound statement after adding a collection (CASSANDRA-9411)
  * Fix counting cache serialization in request metrics (CASSANDRA-9466)
  * (cqlsh) Add LOGIN command to switch users (CASSANDRA-7212)
  * Clone SliceQueryFilter in AbstractReadCommand implementations (CASSANDRA-8940)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63165a71/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
index db22e7d..3852920 100644
--- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
@@ -668,7 +668,8 @@ public abstract class ModificationStatement implements CQLStatement, MeasurableF
     private static ResultSet buildCasFailureResultSet(ByteBuffer key, ColumnFamily cf, Iterable<ColumnIdentifier> columnsWithConditions, boolean isBatch)
     throws InvalidRequestException
     {
-        CFDefinition cfDef = cf.metadata().getCfDef();
+        CFMetaData cfm = cf.metadata();
+        CFDefinition cfDef = cfm.getCfDef();
 
         Selection selection;
         if (columnsWithConditions == null)
@@ -694,7 +695,8 @@ public abstract class ModificationStatement implements CQLStatement, MeasurableF
 
         long now = System.currentTimeMillis();
         Selection.ResultSetBuilder builder = selection.resultSetBuilder(now);
-        SelectStatement.forSelection(cfDef, selection).processColumnFamily(key, cf, Collections.<ByteBuffer>emptyList(), now, builder);
+        SelectStatement.forSelection(cfm, selection)
+                       .processColumnFamily(cfDef, key, cf, Collections.<ByteBuffer>emptyList(), now, builder);
 
         return builder.build();
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/63165a71/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 8a4deb6..95e0441 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -46,6 +46,7 @@ import org.apache.cassandra.service.StorageProxy;
 import org.apache.cassandra.service.StorageService;
 import org.apache.cassandra.service.pager.*;
 import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.thrift.ColumnDef;
 import org.apache.cassandra.thrift.IndexExpression;
 import org.apache.cassandra.thrift.IndexOperator;
 import org.apache.cassandra.thrift.ThriftValidation;
@@ -68,7 +69,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
     private static final int DEFAULT_COUNT_PAGE_SIZE = 10000;
 
     private final int boundTerms;
-    public final CFDefinition cfDef;
+    public final CFMetaData cfm;
     public final Parameters parameters;
     private final Selection selection;
     private final Term limit;
@@ -110,13 +111,13 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         }
     };
 
-    public SelectStatement(CFDefinition cfDef, int boundTerms, Parameters parameters, Selection selection, Term limit)
+    public SelectStatement(CFMetaData cfm, int boundTerms, Parameters parameters, Selection selection, Term limit)
     {
-        this.cfDef = cfDef;
+        this.cfm = cfm;
         this.boundTerms = boundTerms;
         this.selection = selection;
-        this.keyRestrictions = new Restriction[cfDef.partitionKeyCount()];
-        this.columnRestrictions = new Restriction[cfDef.clusteringColumnsCount()];
+        this.keyRestrictions = new Restriction[cfm.partitionKeyColumns().size()];
+        this.columnRestrictions = new Restriction[cfm.clusteringKeyColumns().size()];
         this.parameters = parameters;
         this.limit = limit;
 
@@ -126,7 +127,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
 
     private void initStaticColumnsInfo()
     {
-        if (!cfDef.cfm.hasStaticColumns())
+        if (!cfm.hasStaticColumns())
             return;
 
         // If it's a wildcard, we do select static but not only them
@@ -152,9 +153,9 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
     // Creates a simple select based on the given selection.
     // Note that the results select statement should not be used for actual queries, but only for processing already
     // queried data through processColumnFamily.
-    static SelectStatement forSelection(CFDefinition cfDef, Selection selection)
+    static SelectStatement forSelection(CFMetaData cfm, Selection selection)
     {
-        return new SelectStatement(cfDef, 0, defaultParameters, selection, null);
+        return new SelectStatement(cfm, 0, defaultParameters, selection, null);
     }
 
     public ResultSet.Metadata getResultMetadata()
@@ -195,6 +196,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
 
     public ResultMessage.Rows execute(QueryState state, QueryOptions options) throws RequestExecutionException, RequestValidationException
     {
+        CFDefinition cfDef = cfm.getCfDef();
         ConsistencyLevel cl = options.getConsistency();
         List<ByteBuffer> variables = options.getValues();
         if (cl == null)
@@ -208,11 +210,11 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         Pageable command;
         if (isKeyRange || usesSecondaryIndexing)
         {
-            command = getRangeCommand(variables, limitForQuery, now);
+            command = getRangeCommand(cfDef, variables, limitForQuery, now);
         }
         else
         {
-            List<ReadCommand> commands = getSliceCommands(variables, limitForQuery, now);
+            List<ReadCommand> commands = getSliceCommands(cfDef, variables, limitForQuery, now);
             command = commands == null ? null : new Pageable.ReadCommands(commands, limitForQuery);
         }
 
@@ -225,13 +227,13 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
 
         if (pageSize <= 0 || command == null || !QueryPagers.mayNeedPaging(command, pageSize))
         {
-            return execute(command, cl, variables, limit, now);
+            return execute(cfDef, command, cl, variables, limit, now);
         }
         else
         {
             QueryPager pager = QueryPagers.pager(command, cl, options.getPagingState());
             if (parameters.isCount)
-                return pageCountQuery(pager, variables, pageSize, now, limit);
+                return pageCountQuery(cfDef, pager, variables, pageSize, now, limit);
 
             // We can't properly do post-query ordering if we page (see #6722)
             if (needsPostQueryOrdering())
@@ -239,14 +241,19 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
                                                 + "ORDER BY or the IN and sort client side, or disable paging for this query");
 
             List<Row> page = pager.fetchPage(pageSize);
-            ResultMessage.Rows msg = processResults(page, variables, limit, now);
+            ResultMessage.Rows msg = processResults(cfDef, page, variables, limit, now);
             if (!pager.isExhausted())
                 msg.result.metadata.setHasMorePages(pager.state());
             return msg;
         }
     }
 
-    private ResultMessage.Rows execute(Pageable command, ConsistencyLevel cl, List<ByteBuffer> variables, int limit, long now) throws RequestValidationException, RequestExecutionException
+    private ResultMessage.Rows execute(CFDefinition cfDef,
+                                       Pageable command,
+                                       ConsistencyLevel cl,
+                                       List<ByteBuffer> variables,
+                                       int limit,
+                                       long now) throws RequestValidationException, RequestExecutionException
     {
         List<Row> rows;
         if (command == null)
@@ -260,17 +267,22 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
                  : StorageProxy.getRangeSlice((RangeSliceCommand)command, cl);
         }
 
-        return processResults(rows, variables, limit, now);
+        return processResults(cfDef, rows, variables, limit, now);
     }
 
-    private ResultMessage.Rows pageCountQuery(QueryPager pager, List<ByteBuffer> variables, int pageSize, long now, int limit) throws RequestValidationException, RequestExecutionException
+    private ResultMessage.Rows pageCountQuery(CFDefinition cfDef,
+                                              QueryPager pager,
+                                              List<ByteBuffer> variables,
+                                              int pageSize,
+                                              long now,
+                                              int limit) throws RequestValidationException, RequestExecutionException
     {
         int count = 0;
         while (!pager.isExhausted())
         {
             int maxLimit = pager.maxRemaining();
             logger.debug("New maxLimit for paged count query is {}", maxLimit);
-            ResultSet rset = process(pager.fetchPage(pageSize), variables, maxLimit, now);
+            ResultSet rset = process(cfDef, pager.fetchPage(pageSize), variables, maxLimit, now);
             count += rset.rows.size();
         }
 
@@ -280,10 +292,10 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         return new ResultMessage.Rows(result);
     }
 
-    public ResultMessage.Rows processResults(List<Row> rows, List<ByteBuffer> variables, int limit, long now) throws RequestValidationException
+    public ResultMessage.Rows processResults(CFDefinition cfDef, List<Row> rows, List<ByteBuffer> variables, int limit, long now) throws RequestValidationException
     {
         // Even for count, we need to process the result as it'll group some column together in sparse column families
-        ResultSet rset = process(rows, variables, limit, now);
+        ResultSet rset = process(cfDef, rows, variables, limit, now);
         rset = parameters.isCount ? rset.makeCountResult(parameters.countAlias) : rset;
         return new ResultMessage.Rows(rset);
     }
@@ -299,6 +311,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
 
     public ResultMessage.Rows executeInternal(QueryState state, QueryOptions options) throws RequestExecutionException, RequestValidationException
     {
+        CFDefinition cfDef = cfm.getCfDef();
         List<ByteBuffer> variables = options.getValues();
         int limit = getLimit(variables);
         int limitForQuery = updateLimitForQuery(limit);
@@ -306,43 +319,47 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         List<Row> rows;
         if (isKeyRange || usesSecondaryIndexing)
         {
-            RangeSliceCommand command = getRangeCommand(variables, limitForQuery, now);
+            RangeSliceCommand command = getRangeCommand(cfDef, variables, limitForQuery, now);
             rows = command == null ? Collections.<Row>emptyList() : command.executeLocally();
         }
         else
         {
-            List<ReadCommand> commands = getSliceCommands(variables, limitForQuery, now);
+            List<ReadCommand> commands = getSliceCommands(cfDef, variables, limitForQuery, now);
             rows = commands == null ? Collections.<Row>emptyList() : readLocally(keyspace(), commands);
         }
 
-        return processResults(rows, variables, limit, now);
+        return processResults(cfDef, rows, variables, limit, now);
     }
 
     public ResultSet process(List<Row> rows) throws InvalidRequestException
     {
         assert !parameters.isCount; // not yet needed
-        return process(rows, Collections.<ByteBuffer>emptyList(), getLimit(Collections.<ByteBuffer>emptyList()), System.currentTimeMillis());
+        return process(cfm.getCfDef(),
+                       rows,
+                       Collections.<ByteBuffer>emptyList(),
+                       getLimit(Collections.<ByteBuffer>emptyList()),
+                       System.currentTimeMillis());
     }
 
     public String keyspace()
     {
-        return cfDef.cfm.ksName;
+        return cfm.ksName;
     }
 
     public String columnFamily()
     {
-        return cfDef.cfm.cfName;
+        return cfm.cfName;
     }
 
-    private List<ReadCommand> getSliceCommands(List<ByteBuffer> variables, int limit, long now) throws RequestValidationException
+    private List<ReadCommand> getSliceCommands(CFDefinition cfDef, List<ByteBuffer> variables, int limit, long now) throws RequestValidationException
     {
-        Collection<ByteBuffer> keys = getKeys(variables);
+        Collection<ByteBuffer> keys = getKeys(cfDef, variables);
         if (keys.isEmpty()) // in case of IN () for (the last column of) the partition key.
             return null;
 
         List<ReadCommand> commands = new ArrayList<>(keys.size());
 
-        IDiskAtomFilter filter = makeFilter(variables, limit);
+        IDiskAtomFilter filter = makeFilter(cfDef, variables, limit);
         if (filter == null)
             return null;
 
@@ -360,22 +377,22 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         return commands;
     }
 
-    private RangeSliceCommand getRangeCommand(List<ByteBuffer> variables, int limit, long now) throws RequestValidationException
+    private RangeSliceCommand getRangeCommand(CFDefinition cfDef, List<ByteBuffer> variables, int limit, long now) throws RequestValidationException
     {
-        IDiskAtomFilter filter = makeFilter(variables, limit);
+        IDiskAtomFilter filter = makeFilter(cfDef, variables, limit);
         if (filter == null)
             return null;
 
         List<IndexExpression> expressions = getIndexExpressions(variables);
         // The LIMIT provided by the user is the number of CQL row he wants returned.
         // We want to have getRangeSlice to count the number of columns, not the number of keys.
-        AbstractBounds<RowPosition> keyBounds = getKeyBounds(variables);
+        AbstractBounds<RowPosition> keyBounds = getKeyBounds(cfDef, variables);
         return keyBounds == null
              ? null
              : new RangeSliceCommand(keyspace(), columnFamily(), now,  filter, keyBounds, expressions, limit, !parameters.isDistinct, false);
     }
 
-    private AbstractBounds<RowPosition> getKeyBounds(List<ByteBuffer> variables) throws InvalidRequestException
+    private AbstractBounds<RowPosition> getKeyBounds(CFDefinition cfDef, List<ByteBuffer> variables) throws InvalidRequestException
     {
         IPartitioner<?> p = StorageService.getPartitioner();
 
@@ -408,8 +425,8 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         }
         else
         {
-            ByteBuffer startKeyBytes = getKeyBound(Bound.START, variables);
-            ByteBuffer finishKeyBytes = getKeyBound(Bound.END, variables);
+            ByteBuffer startKeyBytes = getKeyBound(cfDef, Bound.START, variables);
+            ByteBuffer finishKeyBytes = getKeyBound(cfDef, Bound.END, variables);
 
             RowPosition startKey = RowPosition.forKey(startKeyBytes, p);
             RowPosition finishKey = RowPosition.forKey(finishKeyBytes, p);
@@ -434,7 +451,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
 
     private ColumnSlice makeStaticSlice()
     {
-        ColumnNameBuilder staticPrefix = cfDef.cfm.getStaticColumnNameBuilder();
+        ColumnNameBuilder staticPrefix = cfm.getStaticColumnNameBuilder();
         // Note: we could use staticPrefix.build() for the start bound, but EMPTY_BYTE_BUFFER gives us the
         // same effect while saving a few CPU cycles.
         return isReversed
@@ -442,7 +459,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
              : new ColumnSlice(ByteBufferUtil.EMPTY_BYTE_BUFFER, staticPrefix.buildAsEndOfRange());
     }
 
-    private IDiskAtomFilter makeFilter(List<ByteBuffer> variables, int limit)
+    private IDiskAtomFilter makeFilter(CFDefinition cfDef, List<ByteBuffer> variables, int limit)
     throws InvalidRequestException
     {
         int toGroup = cfDef.isCompact ? -1 : cfDef.clusteringColumnsCount();
@@ -457,14 +474,14 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
             toGroup = selectsStaticColumns ? toGroup : SliceQueryFilter.IGNORE_TOMBSTONED_PARTITIONS;
             return new SliceQueryFilter(ColumnSlice.ALL_COLUMNS_ARRAY, false, 1, toGroup);
         }
-        else if (isColumnRange())
+        else if (isColumnRange(cfDef))
         {
             // For sparse, we used to ask for 'defined columns' * 'asked limit' (where defined columns includes the row marker)
             // to account for the grouping of columns.
             // Since that doesn't work for maps/sets/lists, we now use the compositesToGroup option of SliceQueryFilter.
             // But we must preserve backward compatibility too (for mixed version cluster that is).
-            List<ByteBuffer> startBounds = getRequestedBound(Bound.START, variables);
-            List<ByteBuffer> endBounds = getRequestedBound(Bound.END, variables);
+            List<ByteBuffer> startBounds = getRequestedBound(cfDef, Bound.START, variables);
+            List<ByteBuffer> endBounds = getRequestedBound(cfDef, Bound.END, variables);
             assert startBounds.size() == endBounds.size();
 
             // Handles fetching static columns. Note that for 2i, the filter is just used to restrict
@@ -478,18 +495,18 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
             if (startBounds.size() == 1)
             {
                 ColumnSlice slice = new ColumnSlice(startBounds.get(0), endBounds.get(0));
-                if (slice.isAlwaysEmpty(cfDef.cfm.comparator, isReversed))
+                if (slice.isAlwaysEmpty(cfm.comparator, isReversed))
                     return staticSlice == null ? null : sliceFilter(staticSlice, limit, toGroup);
 
                 if (staticSlice == null)
                     return sliceFilter(slice, limit, toGroup);
 
                 if (isReversed)
-                    return slice.includes(cfDef.cfm.comparator.reverseComparator, staticSlice.start)
+                    return slice.includes(cfm.comparator.reverseComparator, staticSlice.start)
                             ? sliceFilter(new ColumnSlice(slice.start, staticSlice.finish), limit, toGroup)
                             : sliceFilter(new ColumnSlice[]{ slice, staticSlice }, limit, toGroup);
                 else
-                    return slice.includes(cfDef.cfm.comparator, staticSlice.finish)
+                    return slice.includes(cfm.comparator, staticSlice.finish)
                             ? sliceFilter(new ColumnSlice(staticSlice.start, slice.finish), limit, toGroup)
                             : sliceFilter(new ColumnSlice[]{ staticSlice, slice }, limit, toGroup);
             }
@@ -498,7 +515,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
             for (int i = 0; i < startBounds.size(); i++)
             {
                 ColumnSlice slice = new ColumnSlice(startBounds.get(i), endBounds.get(i));
-                if (!slice.isAlwaysEmpty(cfDef.cfm.comparator, isReversed))
+                if (!slice.isAlwaysEmpty(cfm.comparator, isReversed))
                     l.add(slice);
             }
 
@@ -513,7 +530,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
             ColumnSlice[] slices;
             if (isReversed)
             {
-                if (l.get(l.size() - 1).includes(cfDef.cfm.comparator.reverseComparator, staticSlice.start))
+                if (l.get(l.size() - 1).includes(cfm.comparator.reverseComparator, staticSlice.start))
                 {
                     slices = l.toArray(new ColumnSlice[l.size()]);
                     slices[slices.length-1] = new ColumnSlice(slices[slices.length-1].start, ByteBufferUtil.EMPTY_BYTE_BUFFER);
@@ -526,7 +543,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
             }
             else
             {
-                if (l.get(0).includes(cfDef.cfm.comparator, staticSlice.finish))
+                if (l.get(0).includes(cfm.comparator, staticSlice.finish))
                 {
                     slices = new ColumnSlice[l.size()];
                     slices[0] = new ColumnSlice(ByteBufferUtil.EMPTY_BYTE_BUFFER, l.get(0).finish);
@@ -545,7 +562,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         }
         else
         {
-            SortedSet<ByteBuffer> cellNames = getRequestedColumns(variables);
+            SortedSet<ByteBuffer> cellNames = getRequestedColumns(cfDef, variables);
             if (cellNames == null) // in case of IN () for the last column of the key
                 return null;
             QueryProcessor.validateCellNames(cellNames);
@@ -598,7 +615,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
              : limit;
     }
 
-    private Collection<ByteBuffer> getKeys(final List<ByteBuffer> variables) throws InvalidRequestException
+    private Collection<ByteBuffer> getKeys(CFDefinition cfDef, List<ByteBuffer> variables) throws InvalidRequestException
     {
         List<ByteBuffer> keys = new ArrayList<ByteBuffer>();
         ColumnNameBuilder builder = cfDef.getKeyNameBuilder();
@@ -632,7 +649,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         return keys;
     }
 
-    private ByteBuffer getKeyBound(Bound b, List<ByteBuffer> variables) throws InvalidRequestException
+    private ByteBuffer getKeyBound(CFDefinition cfDef, Bound b, List<ByteBuffer> variables) throws InvalidRequestException
     {
         // Deal with unrestricted partition key components (special-casing is required to deal with 2i queries on the first
         // component of a composite partition key).
@@ -694,7 +711,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         return true;
     }
 
-    private boolean isColumnRange()
+    private boolean isColumnRange(CFDefinition cfDef)
     {
         // Due to CASSANDRA-5762, we always do a slice for CQL3 tables (not compact, composite).
         // Static CF (non compact but non composite) never entails a column slice however
@@ -711,11 +728,11 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         return false;
     }
 
-    private SortedSet<ByteBuffer> getRequestedColumns(List<ByteBuffer> variables) throws InvalidRequestException
+    private SortedSet<ByteBuffer> getRequestedColumns(CFDefinition cfDef, List<ByteBuffer> variables) throws InvalidRequestException
     {
         // Note: getRequestedColumns don't handle static columns, but due to CASSANDRA-5762
         // we always do a slice for CQL3 tables, so it's ok to ignore them here
-        assert !isColumnRange();
+        assert !isColumnRange(cfDef);
 
         ColumnNameBuilder builder = cfDef.getColumnNameBuilder();
         Iterator<CFDefinition.Name> idIter = cfDef.clusteringColumns().iterator();
@@ -771,7 +788,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
                         if (cfDef.isCompact)
                             columns.add(b.build());
                         else
-                            columns.addAll(addSelectedColumns(b));
+                            columns.addAll(addSelectedColumns(cfDef, b));
                     }
                     return columns;
                 }
@@ -797,35 +814,35 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
                         if (cfDef.isCompact)
                             inValues.add(b.build());
                         else
-                            inValues.addAll(addSelectedColumns(b));
+                            inValues.addAll(addSelectedColumns(cfDef, b));
                     }
                     return inValues;
                 }
             }
         }
 
-        return addSelectedColumns(builder);
+        return addSelectedColumns(cfDef, builder);
     }
 
-    private SortedSet<ByteBuffer> addSelectedColumns(ColumnNameBuilder builder)
+    private SortedSet<ByteBuffer> addSelectedColumns(CFDefinition cfDef, ColumnNameBuilder builder)
     {
         if (cfDef.isCompact)
         {
-            return FBUtilities.singleton(builder.build(), cfDef.cfm.comparator);
+            return FBUtilities.singleton(builder.build(), cfm.comparator);
         }
         else
         {
             // Collections require doing a slice query because a given collection is a
             // non-know set of columns, so we shouldn't get there
-            assert !selectACollection();
+            assert !selectACollection(cfDef);
 
-            SortedSet<ByteBuffer> columns = new TreeSet<ByteBuffer>(cfDef.cfm.comparator);
+            SortedSet<ByteBuffer> columns = new TreeSet<ByteBuffer>(cfm.comparator);
 
             // We need to query the selected column as well as the marker
             // column (for the case where the row exists but has no columns outside the PK)
             // Two exceptions are "static CF" (non-composite non-compact CF) and "super CF"
             // that don't have marker and for which we must query all columns instead
-            if (cfDef.isComposite && !cfDef.cfm.isSuper())
+            if (cfDef.isComposite && !cfm.isSuper())
             {
                 // marker
                 columns.add(builder.copy().add(ByteBufferUtil.EMPTY_BYTE_BUFFER).build());
@@ -850,7 +867,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         }
     }
 
-    private boolean selectACollection()
+    private boolean selectACollection(CFDefinition cfDef)
     {
         if (!cfDef.hasCollections)
             return false;
@@ -1036,9 +1053,11 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         return slice.bound(b, variables);
     }
 
-    private List<ByteBuffer> getRequestedBound(Bound b, List<ByteBuffer> variables) throws InvalidRequestException
+    private List<ByteBuffer> getRequestedBound(CFDefinition cfDef,
+                                               Bound b,
+                                               List<ByteBuffer> variables) throws InvalidRequestException
     {
-        assert isColumnRange();
+        assert isColumnRange(cfDef);
         return buildBound(b,
                           new ArrayList<Name>(cfDef.clusteringColumns()),
                           columnRestrictions,
@@ -1137,7 +1156,8 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         }
     }
 
-    private ResultSet process(List<Row> rows, List<ByteBuffer> variables, int limit, long now) throws InvalidRequestException
+    private ResultSet process(CFDefinition cfDef, List<Row> rows, List<ByteBuffer> variables, int limit, long now)
+    throws InvalidRequestException
     {
         Selection.ResultSetBuilder result = selection.resultSetBuilder(now);
         for (org.apache.cassandra.db.Row row : rows)
@@ -1146,12 +1166,12 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
             if (row.cf == null)
                 continue;
 
-            processColumnFamily(row.key.key, row.cf, variables, now, result);
+            processColumnFamily(cfDef, row.key.key, row.cf, variables, now, result);
         }
 
         ResultSet cqlRows = result.build();
 
-        orderResults(cqlRows);
+        orderResults(cfDef, cqlRows);
 
         // Internal calls always return columns in the comparator order, even when reverse was set
         if (isReversed)
@@ -1163,11 +1183,15 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
     }
 
     // Used by ModificationStatement for CAS operations
-    void processColumnFamily(ByteBuffer key, ColumnFamily cf, List<ByteBuffer> variables, long now, Selection.ResultSetBuilder result)
-    throws InvalidRequestException
+    void processColumnFamily(CFDefinition cfDef,
+                             ByteBuffer key,
+                             ColumnFamily cf,
+                             List<ByteBuffer> variables,
+                             long now,
+                             Selection.ResultSetBuilder result) throws InvalidRequestException
     {
         ByteBuffer[] keyComponents = cfDef.hasCompositeKey
-                                   ? ((CompositeType)cfDef.cfm.getKeyValidator()).split(key)
+                                   ? ((CompositeType) cfm.getKeyValidator()).split(key)
                                    : new ByteBuffer[]{ key };
 
         if (parameters.isDistinct && !selectsStaticColumns)
@@ -1191,11 +1215,11 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
                 ByteBuffer[] components = null;
                 if (cfDef.isComposite)
                 {
-                    components = ((CompositeType)cfDef.cfm.comparator).split(c.name());
+                    components = ((CompositeType) cfm.comparator).split(c.name());
                 }
                 else if (sliceRestriction != null)
                 {
-                    Comparator<ByteBuffer> comp = cfDef.cfm.comparator;
+                    Comparator<ByteBuffer> comp = cfm.comparator;
                     // For dynamic CF, the column could be out of the requested bounds, filter here
 
                     if (!sliceRestriction.isInclusive(Bound.START))
@@ -1251,7 +1275,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         else if (cfDef.isComposite)
         {
             // Sparse case: group column in cqlRow when composite prefix is equal
-            CompositeType composite = (CompositeType)cfDef.cfm.comparator;
+            CompositeType composite = (CompositeType) cfm.comparator;
 
             ColumnGroupMap.Builder builder = new ColumnGroupMap.Builder(composite, cfDef.hasCollections, now);
 
@@ -1325,7 +1349,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
     /**
      * Orders results when multiple keys are selected (using IN)
      */
-    private void orderResults(ResultSet cqlRows)
+    private void orderResults(CFDefinition cfDef, ResultSet cqlRows)
     {
         if (cqlRows.size() == 0 || !needsPostQueryOrdering())
             return;
@@ -1336,7 +1360,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         // because there is no point of using composite comparator if there is only one order condition
         if (parameters.orderings.size() == 1)
         {
-            CFDefinition.Name ordering = cfDef.get(parameters.orderings.keySet().iterator().next().prepare(cfDef.cfm));
+            CFDefinition.Name ordering = cfDef.get(parameters.orderings.keySet().iterator().next().prepare(cfm));
             Collections.sort(cqlRows.rows, new SingleColumnComparator(orderingIndexes.get(ordering), ordering.type));
             return;
         }
@@ -1430,7 +1454,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         return false;
     }
 
-    private void validateDistinctSelection()
+    private void validateDistinctSelection(CFDefinition cfDef)
     throws InvalidRequestException
     {
         Collection<CFDefinition.Name> requestedColumns = selection.getColumns();
@@ -1460,7 +1484,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         private final List<Relation> whereClause;
         private final Term.Raw limit;
 
-        public RawStatement(CFName cfName, Parameters parameters, List<RawSelector> selectClause, List<Relation> whereClause, Term.Raw limit)
+        public RawStatement(CFName cfName,Parameters parameters, List<RawSelector> selectClause, List<Relation> whereClause, Term.Raw limit)
         {
             super(cfName);
             this.parameters = parameters;
@@ -1485,7 +1509,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
                                 ? Selection.wildcard(cfDef)
                                 : Selection.fromSelectors(cfDef, selectClause);
 
-            SelectStatement stmt = new SelectStatement(cfDef, boundNames.size(), parameters, selection, prepareLimit(boundNames));
+            SelectStatement stmt = new SelectStatement(cfm, boundNames.size(), parameters, selection, prepareLimit(boundNames));
 
             /*
              * WHERE clause. For a given entity, rules are:
@@ -1570,10 +1594,10 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
             if (!stmt.parameters.orderings.isEmpty())
                 processOrderingClause(stmt, cfDef);
 
-            checkNeedsFiltering(stmt);
+            checkNeedsFiltering(stmt, cfDef);
 
             if (parameters.isDistinct)
-                stmt.validateDistinctSelection();
+                stmt.validateDistinctSelection(cfDef);
 
             return new ParsedStatement.Prepared(stmt, boundNames);
         }
@@ -2054,7 +2078,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
                 {
                     if (!restriction.isMultiColumn() && i != stmt.columnRestrictions.length - 1)
                         throw new InvalidRequestException(String.format("Clustering column \"%s\" cannot be restricted by an IN relation", cname));
-                    if (stmt.selectACollection())
+                    if (stmt.selectACollection(cfDef))
                         throw new InvalidRequestException(String.format("Cannot restrict column \"%s\" by IN relation as a collection is selected by the query", cname));
 
                     if (restriction.isMultiColumn())
@@ -2187,7 +2211,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
         }
 
         /** If ALLOW FILTERING was not specified, this verifies that it is not needed */
-        private void checkNeedsFiltering(SelectStatement stmt) throws InvalidRequestException
+        private void checkNeedsFiltering(SelectStatement stmt, CFDefinition cfDef) throws InvalidRequestException
         {
             // non-key-range non-indexed queries cannot involve filtering underneath
             if (!parameters.allowFiltering && (stmt.isKeyRange || stmt.usesSecondaryIndexing))
@@ -2213,7 +2237,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
             // than answering with something that is wrong.
             if (stmt.sliceRestriction != null && stmt.isKeyRange && limit != null)
             {
-                SingleColumnRelation rel = findInclusiveClusteringRelationForCompact(stmt.cfDef);
+                SingleColumnRelation rel = findInclusiveClusteringRelationForCompact(cfDef);
                 throw new InvalidRequestException(String.format("The query requests a restriction of rows with a strict bound (%s) over a range of partitions. "
                                                               + "This is not supported by the underlying storage engine for COMPACT tables if a LIMIT is provided. "
                                                               + "Please either make the condition non strict (%s) or remove the user LIMIT", rel, rel.withNonStrictOperator()));