http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/QueryProcessor.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/QueryProcessor.java 
b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
index cca93ff..6347f9c 100644
--- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java
+++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
@@ -69,11 +69,11 @@ public class QueryProcessor implements QueryHandler
 
     private static final Logger logger = 
LoggerFactory.getLogger(QueryProcessor.class);
 
-    private static final Cache<MD5Digest, ParsedStatement.Prepared> 
preparedStatements;
+    private static final Cache<MD5Digest, Prepared> preparedStatements;
 
     // A map for prepared statements used internally (which we don't want to 
mix with user statement, in particular we don't
     // bother with expiration on those.
-    private static final ConcurrentMap<String, ParsedStatement.Prepared> 
internalStatements = new ConcurrentHashMap<>();
+    private static final ConcurrentMap<String, Prepared> internalStatements = 
new ConcurrentHashMap<>();
 
     // Direct calls to processStatement do not increment the 
preparedStatementsExecuted/regularStatementsExecuted
     // counters. Callers of processStatement are responsible for correctly 
notifying metrics
@@ -117,7 +117,7 @@ public class QueryProcessor implements QueryHandler
     }
 
     // Work around initialization dependency
-    private static enum InternalStateInstance
+    private enum InternalStateInstance
     {
         INSTANCE;
 
@@ -125,9 +125,7 @@ public class QueryProcessor implements QueryHandler
 
         InternalStateInstance()
         {
-            ClientState state = ClientState.forInternalCalls();
-            state.setKeyspace(SchemaConstants.SYSTEM_KEYSPACE_NAME);
-            this.queryState = new QueryState(state);
+            queryState = new 
QueryState(ClientState.forInternalCalls(SchemaConstants.SYSTEM_KEYSPACE_NAME));
         }
     }
 
@@ -167,7 +165,7 @@ public class QueryProcessor implements QueryHandler
         Schema.instance.registerListener(new StatementInvalidatingListener());
     }
 
-    public ParsedStatement.Prepared getPrepared(MD5Digest id)
+    public Prepared getPrepared(MD5Digest id)
     {
         return preparedStatements.getIfPresent(id);
     }
@@ -194,7 +192,7 @@ public class QueryProcessor implements QueryHandler
     {
         logger.trace("Process {} @CL.{}", statement, options.getConsistency());
         ClientState clientState = queryState.getClientState();
-        statement.checkAccess(clientState);
+        statement.authorize(clientState);
         statement.validate(clientState);
 
         ResultMessage result = statement.execute(queryState, options, 
queryStartNanoTime);
@@ -219,10 +217,9 @@ public class QueryProcessor implements QueryHandler
     public ResultMessage process(String queryString, QueryState queryState, 
QueryOptions options, long queryStartNanoTime)
     throws RequestExecutionException, RequestValidationException
     {
-        ParsedStatement.Prepared p = getStatement(queryString, 
queryState.getClientState().cloneWithKeyspaceIfSet(options.getKeyspace()));
-        options.prepare(p.boundNames);
-        CQLStatement prepared = p.statement;
-        if (prepared.getBoundTerms() != options.getValues().size())
+        CQLStatement prepared = getStatement(queryString, 
queryState.getClientState().cloneWithKeyspaceIfSet(options.getKeyspace()));
+        options.prepare(prepared.getBindVariables());
+        if (prepared.getBindVariables().size() != options.getValues().size())
             throw new InvalidRequestException("Invalid amount of bind 
variables");
 
         if (!queryState.getClientState().isInternal)
@@ -231,7 +228,7 @@ public class QueryProcessor implements QueryHandler
         return processStatement(prepared, queryState, options, 
queryStartNanoTime);
     }
 
-    public static ParsedStatement.Prepared parseStatement(String queryStr, 
ClientState clientState) throws RequestValidationException
+    public static CQLStatement parseStatement(String queryStr, ClientState 
clientState) throws RequestValidationException
     {
         return getStatement(queryStr, clientState);
     }
@@ -250,43 +247,45 @@ public class QueryProcessor implements QueryHandler
             return null;
     }
 
-    private static QueryOptions makeInternalOptions(ParsedStatement.Prepared 
prepared, Object[] values)
+    private static QueryOptions makeInternalOptions(CQLStatement prepared, 
Object[] values)
     {
         return makeInternalOptions(prepared, values, ConsistencyLevel.ONE);
     }
 
-    private static QueryOptions makeInternalOptions(ParsedStatement.Prepared 
prepared, Object[] values, ConsistencyLevel cl)
+    private static QueryOptions makeInternalOptions(CQLStatement prepared, 
Object[] values, ConsistencyLevel cl)
     {
-        if (prepared.boundNames.size() != values.length)
-            throw new IllegalArgumentException(String.format("Invalid number 
of values. Expecting %d but got %d", prepared.boundNames.size(), 
values.length));
+        if (prepared.getBindVariables().size() != values.length)
+            throw new IllegalArgumentException(String.format("Invalid number 
of values. Expecting %d but got %d", prepared.getBindVariables().size(), 
values.length));
 
-        List<ByteBuffer> boundValues = new 
ArrayList<ByteBuffer>(values.length);
+        List<ByteBuffer> boundValues = new ArrayList<>(values.length);
         for (int i = 0; i < values.length; i++)
         {
             Object value = values[i];
-            AbstractType type = prepared.boundNames.get(i).type;
+            AbstractType type = prepared.getBindVariables().get(i).type;
             boundValues.add(value instanceof ByteBuffer || value == null ? 
(ByteBuffer)value : type.decompose(value));
         }
         return QueryOptions.forInternalCalls(cl, boundValues);
     }
 
-    public static ParsedStatement.Prepared prepareInternal(String query) 
throws RequestValidationException
+    public static Prepared prepareInternal(String query) throws 
RequestValidationException
     {
-        ParsedStatement.Prepared prepared = internalStatements.get(query);
+        Prepared prepared = internalStatements.get(query);
         if (prepared != null)
             return prepared;
 
         // Note: if 2 threads prepare the same query, we'll live so don't 
bother synchronizing
-        prepared = parseStatement(query, 
internalQueryState().getClientState());
-        prepared.statement.validate(internalQueryState().getClientState());
-        internalStatements.putIfAbsent(query, prepared);
+        CQLStatement statement = parseStatement(query, 
internalQueryState().getClientState());
+        statement.validate(internalQueryState().getClientState());
+
+        prepared = new Prepared(statement);
+        internalStatements.put(query, prepared);
         return prepared;
     }
 
     public static UntypedResultSet executeInternal(String query, Object... 
values)
     {
-        ParsedStatement.Prepared prepared = prepareInternal(query);
-        ResultMessage result = 
prepared.statement.executeInternal(internalQueryState(), 
makeInternalOptions(prepared, values));
+        Prepared prepared = prepareInternal(query);
+        ResultMessage result = 
prepared.statement.executeLocally(internalQueryState(), 
makeInternalOptions(prepared.statement, values));
         if (result instanceof ResultMessage.Rows)
             return 
UntypedResultSet.create(((ResultMessage.Rows)result).result);
         else
@@ -304,8 +303,8 @@ public class QueryProcessor implements QueryHandler
     {
         try
         {
-            ParsedStatement.Prepared prepared = prepareInternal(query);
-            ResultMessage result = prepared.statement.execute(state, 
makeInternalOptions(prepared, values, cl), System.nanoTime());
+            Prepared prepared = prepareInternal(query);
+            ResultMessage result = prepared.statement.execute(state, 
makeInternalOptions(prepared.statement, values, cl), System.nanoTime());
             if (result instanceof ResultMessage.Rows)
                 return 
UntypedResultSet.create(((ResultMessage.Rows)result).result);
             else
@@ -319,24 +318,24 @@ public class QueryProcessor implements QueryHandler
 
     public static UntypedResultSet executeInternalWithPaging(String query, int 
pageSize, Object... values)
     {
-        ParsedStatement.Prepared prepared = prepareInternal(query);
+        Prepared prepared = prepareInternal(query);
         if (!(prepared.statement instanceof SelectStatement))
             throw new IllegalArgumentException("Only SELECTs can be paged");
 
         SelectStatement select = (SelectStatement)prepared.statement;
-        QueryPager pager = select.getQuery(makeInternalOptions(prepared, 
values), FBUtilities.nowInSeconds()).getPager(null, ProtocolVersion.CURRENT);
+        QueryPager pager = 
select.getQuery(makeInternalOptions(prepared.statement, values), 
FBUtilities.nowInSeconds()).getPager(null, ProtocolVersion.CURRENT);
         return UntypedResultSet.create(select, pager, pageSize);
     }
 
     /**
-     * Same than executeInternal, but to use for queries we know are only 
executed once so that the
+     * Same than executeLocally, but to use for queries we know are only 
executed once so that the
      * created statement object is not cached.
      */
     public static UntypedResultSet executeOnceInternal(String query, Object... 
values)
     {
-        ParsedStatement.Prepared prepared = parseStatement(query, 
internalQueryState().getClientState());
-        prepared.statement.validate(internalQueryState().getClientState());
-        ResultMessage result = 
prepared.statement.executeInternal(internalQueryState(), 
makeInternalOptions(prepared, values));
+        CQLStatement statement = parseStatement(query, 
internalQueryState().getClientState());
+        statement.validate(internalQueryState().getClientState());
+        ResultMessage result = statement.executeLocally(internalQueryState(), 
makeInternalOptions(statement, values));
         if (result instanceof ResultMessage.Rows)
             return 
UntypedResultSet.create(((ResultMessage.Rows)result).result);
         else
@@ -344,16 +343,16 @@ public class QueryProcessor implements QueryHandler
     }
 
     /**
-     * A special version of executeInternal that takes the time used as "now" 
for the query in argument.
+     * A special version of executeLocally that takes the time used as "now" 
for the query in argument.
      * Note that this only make sense for Selects so this only accept SELECT 
statements and is only useful in rare
      * cases.
      */
     public static UntypedResultSet executeInternalWithNow(int nowInSec, long 
queryStartNanoTime, String query, Object... values)
     {
-        ParsedStatement.Prepared prepared = prepareInternal(query);
+        Prepared prepared = prepareInternal(query);
         assert prepared.statement instanceof SelectStatement;
         SelectStatement select = (SelectStatement)prepared.statement;
-        ResultMessage result = select.executeInternal(internalQueryState(), 
makeInternalOptions(prepared, values), nowInSec, queryStartNanoTime);
+        ResultMessage result = select.executeInternal(internalQueryState(), 
makeInternalOptions(prepared.statement, values), nowInSec, queryStartNanoTime);
         assert result instanceof ResultMessage.Rows;
         return UntypedResultSet.create(((ResultMessage.Rows)result).result);
     }
@@ -367,7 +366,7 @@ public class QueryProcessor implements QueryHandler
     {
         try (PartitionIterator iter = partitions)
         {
-            SelectStatement ss = (SelectStatement) getStatement(query, 
null).statement;
+            SelectStatement ss = (SelectStatement) getStatement(query, null);
             ResultSet cqlRows = ss.process(iter, FBUtilities.nowInSeconds());
             return UntypedResultSet.create(cqlRows);
         }
@@ -386,12 +385,13 @@ public class QueryProcessor implements QueryHandler
         if (existing != null)
             return existing;
 
-        ParsedStatement.Prepared prepared = getStatement(queryString, 
clientState);
-        prepared.rawCQLStatement = queryString;
-        int boundTerms = prepared.statement.getBoundTerms();
+        CQLStatement statement = getStatement(queryString, clientState);
+        Prepared prepared = new Prepared(statement, queryString);
+
+        int boundTerms = statement.getBindVariables().size();
         if (boundTerms > FBUtilities.MAX_UNSIGNED_SHORT)
             throw new InvalidRequestException(String.format("Too many 
markers(?). %d markers exceed the allowed maximum of %d", boundTerms, 
FBUtilities.MAX_UNSIGNED_SHORT));
-        assert boundTerms == prepared.boundNames.size();
+        assert boundTerms == statement.getBindVariables().size();
 
         return storePreparedStatement(queryString, 
clientState.getRawKeyspace(), prepared);
     }
@@ -406,16 +406,16 @@ public class QueryProcessor implements QueryHandler
     throws InvalidRequestException
     {
         MD5Digest statementId = computeId(queryString, keyspace);
-        ParsedStatement.Prepared existing = 
preparedStatements.getIfPresent(statementId);
+        Prepared existing = preparedStatements.getIfPresent(statementId);
         if (existing == null)
             return null;
 
         checkTrue(queryString.equals(existing.rawCQLStatement),
-                String.format("MD5 hash collision: query with the same MD5 
hash was already prepared. \n Existing: '%s'", existing.rawCQLStatement));
-        return new ResultMessage.Prepared(statementId, existing);
+                String.format("MD5 hash collision: query with the same MDnt5 
hash was already prepared. \n Existing: '%s'", existing.rawCQLStatement));
+        return new ResultMessage.Prepared(statementId, existing.statement);
     }
 
-    private static ResultMessage.Prepared storePreparedStatement(String 
queryString, String keyspace, ParsedStatement.Prepared prepared)
+    private static ResultMessage.Prepared storePreparedStatement(String 
queryString, String keyspace, Prepared prepared)
     throws InvalidRequestException
     {
         // Concatenate the current keyspace so we don't mix prepared 
statements between keyspace (#5352).
@@ -430,7 +430,7 @@ public class QueryProcessor implements QueryHandler
         MD5Digest statementId = computeId(queryString, keyspace);
         preparedStatements.put(statementId, prepared);
         SystemKeyspace.writePreparedStatement(keyspace, statementId, 
queryString);
-        return new ResultMessage.Prepared(statementId, prepared);
+        return new ResultMessage.Prepared(statementId, prepared.statement);
     }
 
     public ResultMessage processPrepared(CQLStatement statement,
@@ -448,11 +448,11 @@ public class QueryProcessor implements QueryHandler
     {
         List<ByteBuffer> variables = options.getValues();
         // Check to see if there are any bound variables to verify
-        if (!(variables.isEmpty() && (statement.getBoundTerms() == 0)))
+        if (!(variables.isEmpty() && statement.getBindVariables().isEmpty()))
         {
-            if (variables.size() != statement.getBoundTerms())
+            if (variables.size() != statement.getBindVariables().size())
                 throw new InvalidRequestException(String.format("there were %d 
markers(?) in CQL but %d bound variables",
-                                                                
statement.getBoundTerms(),
+                                                                
statement.getBindVariables().size(),
                                                                 
variables.size()));
 
             // at this point there is a match in count between markers and 
variables that is non-zero
@@ -480,31 +480,31 @@ public class QueryProcessor implements QueryHandler
     throws RequestExecutionException, RequestValidationException
     {
         ClientState clientState = 
queryState.getClientState().cloneWithKeyspaceIfSet(options.getKeyspace());
-        batch.checkAccess(clientState);
+        batch.authorize(clientState);
         batch.validate();
         batch.validate(clientState);
         return batch.execute(queryState, options, queryStartNanoTime);
     }
 
-    public static ParsedStatement.Prepared getStatement(String queryStr, 
ClientState clientState)
+    public static CQLStatement getStatement(String queryStr, ClientState 
clientState)
     throws RequestValidationException
     {
         Tracing.trace("Parsing {}", queryStr);
-        ParsedStatement statement = parseStatement(queryStr);
+        CQLStatement.Raw statement = parseStatement(queryStr);
 
         // Set keyspace for statement that require login
-        if (statement instanceof CFStatement)
-            ((CFStatement) statement).prepareKeyspace(clientState);
+        if (statement instanceof QualifiedStatement)
+            ((QualifiedStatement) statement).setKeyspace(clientState);
 
         Tracing.trace("Preparing statement");
-        return statement.prepare();
+        return statement.prepare(clientState);
     }
 
-    public static <T extends ParsedStatement> T parseStatement(String 
queryStr, Class<T> klass, String type) throws SyntaxException
+    public static <T extends CQLStatement.Raw> T parseStatement(String 
queryStr, Class<T> klass, String type) throws SyntaxException
     {
         try
         {
-            ParsedStatement stmt = parseStatement(queryStr);
+            CQLStatement.Raw stmt = parseStatement(queryStr);
 
             if (!klass.isAssignableFrom(stmt.getClass()))
                 throw new IllegalArgumentException("Invalid query, must be a " 
+ type + " statement but was: " + stmt.getClass());
@@ -516,7 +516,7 @@ public class QueryProcessor implements QueryHandler
             throw new IllegalArgumentException(e.getMessage(), e);
         }
     }
-    public static ParsedStatement parseStatement(String queryStr) throws 
SyntaxException
+    public static CQLStatement.Raw parseStatement(String queryStr) throws 
SyntaxException
     {
         try
         {
@@ -540,7 +540,7 @@ public class QueryProcessor implements QueryHandler
         }
     }
 
-    private static int measure(Object key, ParsedStatement.Prepared value)
+    private static int measure(Object key, Prepared value)
     {
         return Ints.checkedCast(ObjectSizes.measureDeep(key) + 
ObjectSizes.measureDeep(value));
     }
@@ -554,6 +554,30 @@ public class QueryProcessor implements QueryHandler
         internalStatements.clear();
     }
 
+    public static class Prepared
+    {
+        public final CQLStatement statement;
+
+        /**
+         * Contains the CQL statement source if the statement has been 
"regularly" perpared via
+         * {@link QueryProcessor#prepare(String, ClientState)} /
+         * {@link QueryHandler#prepare(String, ClientState, Map)}.
+         * Other usages of this class may or may not contain the CQL statement 
source.
+         */
+        public final String rawCQLStatement;
+
+        private Prepared(CQLStatement statement)
+        {
+            this(statement, "");
+        }
+
+        private Prepared(CQLStatement statement, String rawCQLStatement)
+        {
+            this.statement = statement;
+            this.rawCQLStatement = rawCQLStatement;
+        }
+    }
+
     private static class StatementInvalidatingListener extends 
SchemaChangeListener
     {
         private static void removeInvalidPreparedStatements(String ksName, 
String cfName)
@@ -566,10 +590,10 @@ public class QueryProcessor implements QueryHandler
         {
             Predicate<Function> matchesFunction = f -> 
ksName.equals(f.name().keyspace) && functionName.equals(f.name().name);
 
-            for (Iterator<Map.Entry<MD5Digest, ParsedStatement.Prepared>> iter 
= preparedStatements.asMap().entrySet().iterator();
+            for (Iterator<Map.Entry<MD5Digest, Prepared>> iter = 
preparedStatements.asMap().entrySet().iterator();
                  iter.hasNext();)
             {
-                Map.Entry<MD5Digest, ParsedStatement.Prepared> pstmt = 
iter.next();
+                Map.Entry<MD5Digest, Prepared> pstmt = iter.next();
                 if (Iterables.any(pstmt.getValue().statement.getFunctions(), 
matchesFunction))
                 {
                     SystemKeyspace.removePreparedStatement(pstmt.getKey());
@@ -582,12 +606,12 @@ public class QueryProcessor implements QueryHandler
                                statement -> 
Iterables.any(statement.statement.getFunctions(), matchesFunction));
         }
 
-        private static void 
removeInvalidPersistentPreparedStatements(Iterator<Map.Entry<MD5Digest, 
ParsedStatement.Prepared>> iterator,
+        private static void 
removeInvalidPersistentPreparedStatements(Iterator<Map.Entry<MD5Digest, 
Prepared>> iterator,
                                                                       String 
ksName, String cfName)
         {
             while (iterator.hasNext())
             {
-                Map.Entry<MD5Digest, ParsedStatement.Prepared> entry = 
iterator.next();
+                Map.Entry<MD5Digest, Prepared> entry = iterator.next();
                 if (shouldInvalidate(ksName, cfName, 
entry.getValue().statement))
                 {
                     SystemKeyspace.removePreparedStatement(entry.getKey());
@@ -596,7 +620,7 @@ public class QueryProcessor implements QueryHandler
             }
         }
 
-        private static void 
removeInvalidPreparedStatements(Iterator<ParsedStatement.Prepared> iterator, 
String ksName, String cfName)
+        private static void removeInvalidPreparedStatements(Iterator<Prepared> 
iterator, String ksName, String cfName)
         {
             while (iterator.hasNext())
             {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java 
b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
index 7bd7aac..84860f1 100644
--- a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
+++ b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
@@ -149,7 +149,7 @@ public final class SingleColumnRelation extends Relation
             entityAsString = String.format("%s[%s]", entityAsString, mapKey);
 
         if (isIN())
-            return String.format("%s IN %s", entityAsString, inValues);
+            return String.format("%s IN %s", entityAsString, 
Tuples.tupleToString(inValues));
 
         return String.format("%s %s %s", entityAsString, relationType, value);
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/VariableSpecifications.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/VariableSpecifications.java 
b/src/java/org/apache/cassandra/cql3/VariableSpecifications.java
index 96290a6..3cf0e5d 100644
--- a/src/java/org/apache/cassandra/cql3/VariableSpecifications.java
+++ b/src/java/org/apache/cassandra/cql3/VariableSpecifications.java
@@ -27,13 +27,13 @@ import org.apache.cassandra.schema.TableMetadata;
 public class VariableSpecifications
 {
     private final List<ColumnIdentifier> variableNames;
-    private final ColumnSpecification[] specs;
+    private final List<ColumnSpecification> specs;
     private final ColumnMetadata[] targetColumns;
 
     public VariableSpecifications(List<ColumnIdentifier> variableNames)
     {
         this.variableNames = variableNames;
-        this.specs = new ColumnSpecification[variableNames.size()];
+        this.specs = Arrays.asList(new 
ColumnSpecification[variableNames.size()]);
         this.targetColumns = new ColumnMetadata[variableNames.size()];
     }
 
@@ -43,17 +43,17 @@ public class VariableSpecifications
      */
     public static VariableSpecifications empty()
     {
-        return new VariableSpecifications(Collections.<ColumnIdentifier> 
emptyList());
+        return new VariableSpecifications(Collections.emptyList());
     }
 
-    public int size()
+    public boolean isEmpty()
     {
-        return variableNames.size();
+        return variableNames.isEmpty();
     }
 
     public List<ColumnSpecification> getSpecifications()
     {
-        return Arrays.asList(specs);
+        return specs;
     }
 
     /**
@@ -94,12 +94,12 @@ public class VariableSpecifications
         // Use the user name, if there is one
         if (bindMarkerName != null)
             spec = new ColumnSpecification(spec.ksName, spec.cfName, 
bindMarkerName, spec.type);
-        specs[bindIndex] = spec;
+        specs.set(bindIndex, spec);
     }
 
     @Override
     public String toString()
     {
-        return Arrays.toString(specs);
+        return specs.toString();
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/WhereClause.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/WhereClause.java 
b/src/java/org/apache/cassandra/cql3/WhereClause.java
index 9d4e51a..5c53b84 100644
--- a/src/java/org/apache/cassandra/cql3/WhereClause.java
+++ b/src/java/org/apache/cassandra/cql3/WhereClause.java
@@ -15,18 +15,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.cassandra.cql3;
 
 import java.util.List;
 
 import com.google.common.collect.ImmutableList;
 
+import org.antlr.runtime.RecognitionException;
 import org.apache.cassandra.cql3.restrictions.CustomIndexExpression;
+import org.apache.cassandra.schema.ColumnMetadata;
+
+import static java.lang.String.join;
+
+import static com.google.common.collect.Iterables.concat;
+import static com.google.common.collect.Iterables.transform;
 
 public final class WhereClause
 {
-
     private static final WhereClause EMPTY = new WhereClause(new Builder());
 
     public final List<Relation> relations;
@@ -34,9 +39,8 @@ public final class WhereClause
 
     private WhereClause(Builder builder)
     {
-        this.relations = builder.relations.build();
-        this.expressions = builder.expressions.build();
-
+        relations = builder.relations.build();
+        expressions = builder.expressions.build();
     }
 
     public static WhereClause empty()
@@ -49,6 +53,38 @@ public final class WhereClause
         return !expressions.isEmpty();
     }
 
+    /**
+     * Renames identifiers in all relations
+     * @param from the old identifier
+     * @param to the new identifier
+     * @return a new WhereClause with with "from" replaced by "to" in all 
relations
+     */
+    public WhereClause renameIdentifier(ColumnMetadata.Raw from, 
ColumnMetadata.Raw to)
+    {
+        WhereClause.Builder builder = new WhereClause.Builder();
+
+        relations.stream()
+                 .map(r -> r.renameIdentifier(from, to))
+                 .forEach(builder::add);
+
+        expressions.forEach(builder::add);
+
+        return builder.build();
+    }
+
+    public static WhereClause parse(String cql) throws RecognitionException
+    {
+        return CQLFragmentParser.parseAnyUnhandled(CqlParser::whereClause, 
cql).build();
+    }
+
+    @Override
+    public String toString()
+    {
+        return join(" AND ",
+                    concat(transform(relations, Relation::toString),
+                           transform(expressions, 
CustomIndexExpression::toString)));
+    }
+
     public static final class Builder
     {
         ImmutableList.Builder<Relation> relations = new 
ImmutableList.Builder<>();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java 
b/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java
index 5e10e9f..1d96d19 100644
--- a/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java
+++ b/src/java/org/apache/cassandra/cql3/functions/AbstractFunction.java
@@ -17,6 +17,7 @@
  */
 package org.apache.cassandra.cql3.functions;
 
+import java.nio.ByteBuffer;
 import java.util.List;
 
 import com.google.common.base.Objects;
@@ -25,6 +26,7 @@ import org.apache.cassandra.cql3.AssignmentTestable;
 import org.apache.cassandra.cql3.CQL3Type;
 import org.apache.cassandra.cql3.ColumnSpecification;
 import org.apache.cassandra.db.marshal.AbstractType;
+
 import org.apache.commons.lang3.text.StrBuilder;
 
 import static java.util.stream.Collectors.toList;
@@ -90,6 +92,11 @@ public abstract class AbstractFunction implements Function
         return false;
     }
 
+    public boolean referencesUserType(ByteBuffer name)
+    {
+        return false;
+    }
+
     @Override
     public int hashCode()
     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/functions/Function.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/Function.java 
b/src/java/org/apache/cassandra/cql3/functions/Function.java
index 5d258af..5e82c04 100644
--- a/src/java/org/apache/cassandra/cql3/functions/Function.java
+++ b/src/java/org/apache/cassandra/cql3/functions/Function.java
@@ -17,10 +17,13 @@
  */
 package org.apache.cassandra.cql3.functions;
 
+import java.nio.ByteBuffer;
 import java.util.List;
 
 import org.apache.cassandra.cql3.AssignmentTestable;
 import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.schema.Diff;
 import org.github.jamm.Unmetered;
 
 @Unmetered
@@ -48,6 +51,8 @@ public interface Function extends AssignmentTestable
 
     public boolean hasReferenceTo(Function function);
 
+    public boolean referencesUserType(ByteBuffer name);
+
     /**
      * Returns the name of the function to use within a ResultSet.
      *
@@ -55,4 +60,9 @@ public interface Function extends AssignmentTestable
      * @return the name of the function to use within a ResultSet
      */
     public String columnName(List<String> columnNames);
+
+    default boolean equals(Function other, Diff.Mode mode)
+    {
+        return equals(other);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java 
b/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java
index 1a3174c..6bc3cdf 100644
--- a/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java
+++ b/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java
@@ -21,16 +21,20 @@ import java.nio.ByteBuffer;
 import java.util.*;
 
 import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.datastax.driver.core.TypeCodec;
 import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.UserType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.schema.Functions;
 import org.apache.cassandra.tracing.Tracing;
 import org.apache.cassandra.transport.ProtocolVersion;
 
+import static com.google.common.collect.Iterables.any;
+
 /**
  * Base class for user-defined-aggregates.
  */
@@ -55,13 +59,13 @@ public class UDAggregate extends AbstractFunction 
implements AggregateFunction
         super(name, argTypes, returnType);
         this.stateFunction = stateFunc;
         this.finalFunction = finalFunc;
-        this.stateType = stateFunc != null ? stateFunc.returnType() : null;
-        this.stateTypeCodec = stateType != null ? 
UDHelper.codecFor(UDHelper.driverType(stateType)) : null;
-        this.returnTypeCodec = returnType != null ? 
UDHelper.codecFor(UDHelper.driverType(returnType)) : null;
+        this.stateType = stateFunc.returnType();
+        this.stateTypeCodec = 
UDHelper.codecFor(UDHelper.driverType(stateType));
+        this.returnTypeCodec = 
UDHelper.codecFor(UDHelper.driverType(returnType));
         this.initcond = initcond;
     }
 
-    public static UDAggregate create(Functions functions,
+    public static UDAggregate create(Collection<UDFunction> functions,
                                      FunctionName name,
                                      List<AbstractType<?>> argTypes,
                                      AbstractType<?> returnType,
@@ -69,7 +73,6 @@ public class UDAggregate extends AbstractFunction implements 
AggregateFunction
                                      FunctionName finalFunc,
                                      AbstractType<?> stateType,
                                      ByteBuffer initcond)
-    throws InvalidRequestException
     {
         List<AbstractType<?>> stateTypes = new ArrayList<>(argTypes.size() + 
1);
         stateTypes.add(stateType);
@@ -78,27 +81,17 @@ public class UDAggregate extends AbstractFunction 
implements AggregateFunction
         return new UDAggregate(name,
                                argTypes,
                                returnType,
-                               resolveScalar(functions, name, stateFunc, 
stateTypes),
-                               finalFunc != null ? resolveScalar(functions, 
name, finalFunc, finalTypes) : null,
+                               findFunction(functions, stateFunc, stateTypes),
+                               null == finalFunc ? null : 
findFunction(functions, finalFunc, finalTypes),
                                initcond);
     }
 
-    public static UDAggregate createBroken(FunctionName name,
-                                           List<AbstractType<?>> argTypes,
-                                           AbstractType<?> returnType,
-                                           ByteBuffer initcond,
-                                           InvalidRequestException reason)
+    private static UDFunction findFunction(Collection<UDFunction> functions, 
FunctionName name, List<AbstractType<?>> arguments)
     {
-        return new UDAggregate(name, argTypes, returnType, null, null, 
initcond)
-        {
-            public Aggregate newAggregate() throws InvalidRequestException
-            {
-                throw new InvalidRequestException(String.format("Aggregate 
'%s' exists but hasn't been loaded successfully for the following reason: %s. "
-                                                                + "Please see 
the server log for more details",
-                                                                this,
-                                                                
reason.getMessage()));
-            }
-        };
+        return functions.stream()
+                        .filter(f -> f.name().equals(name) && 
Functions.typesMatch(f.argTypes(), arguments))
+                        .findFirst()
+                        .orElseThrow(AssertionError::new);
     }
 
     public boolean hasReferenceTo(Function function)
@@ -107,6 +100,29 @@ public class UDAggregate extends AbstractFunction 
implements AggregateFunction
     }
 
     @Override
+    public boolean referencesUserType(ByteBuffer name)
+    {
+        return any(argTypes(), t -> t.referencesUserType(name))
+            || returnType.referencesUserType(name)
+            || (null != stateType && stateType.referencesUserType(name))
+            || stateFunction.referencesUserType(name)
+            || (null != finalFunction && 
finalFunction.referencesUserType(name));
+    }
+
+    public UDAggregate withUpdatedUserType(Collection<UDFunction> udfs, 
UserType udt)
+    {
+        if (!referencesUserType(udt.name))
+            return this;
+
+        return new UDAggregate(name,
+                               Lists.transform(argTypes, t -> 
t.withUpdatedUserType(udt)),
+                               returnType.withUpdatedUserType(udt),
+                               findFunction(udfs, stateFunction.name(), 
stateFunction.argTypes()),
+                               null == finalFunction ? null : 
findFunction(udfs, finalFunction.name(), finalFunction.argTypes()),
+                               initcond);
+    }
+
+    @Override
     public void addFunctionsTo(List<Function> functions)
     {
         functions.add(this);
@@ -214,23 +230,6 @@ public class UDAggregate extends AbstractFunction 
implements AggregateFunction
         };
     }
 
-    private static ScalarFunction resolveScalar(Functions functions, 
FunctionName aName, FunctionName fName, List<AbstractType<?>> argTypes) throws 
InvalidRequestException
-    {
-        Optional<Function> fun = functions.find(fName, argTypes);
-        if (!fun.isPresent())
-            throw new InvalidRequestException(String.format("Referenced state 
function '%s %s' for aggregate '%s' does not exist",
-                                                            fName,
-                                                            
Arrays.toString(UDHelper.driverTypes(argTypes)),
-                                                            aName));
-
-        if (!(fun.get() instanceof ScalarFunction))
-            throw new InvalidRequestException(String.format("Referenced state 
function '%s %s' for aggregate '%s' is not a scalar function",
-                                                            fName,
-                                                            
Arrays.toString(UDHelper.driverTypes(argTypes)),
-                                                            aName));
-        return (ScalarFunction) fun.get();
-    }
-
     @Override
     public boolean equals(Object o)
     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/UDFunction.java 
b/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
index b6fedcc..3df3239 100644
--- a/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
+++ b/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
@@ -37,6 +37,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
 import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,6 +45,7 @@ import com.datastax.driver.core.DataType;
 import com.datastax.driver.core.TypeCodec;
 import org.apache.cassandra.config.Config;
 import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.db.marshal.UserType;
 import org.apache.cassandra.schema.Schema;
 import org.apache.cassandra.cql3.ColumnIdentifier;
 import org.apache.cassandra.db.marshal.AbstractType;
@@ -56,6 +58,8 @@ import org.apache.cassandra.tracing.Tracing;
 import org.apache.cassandra.transport.ProtocolVersion;
 import org.apache.cassandra.utils.JVMStabilityInspector;
 
+import static com.google.common.collect.Iterables.any;
+
 /**
  * Base class for User Defined Functions.
  */
@@ -214,6 +218,24 @@ public abstract class UDFunction extends AbstractFunction 
implements ScalarFunct
                                              keyspaceMetadata);
     }
 
+    public static UDFunction tryCreate(FunctionName name,
+                                       List<ColumnIdentifier> argNames,
+                                       List<AbstractType<?>> argTypes,
+                                       AbstractType<?> returnType,
+                                       boolean calledOnNullInput,
+                                       String language,
+                                       String body)
+    {
+        try
+        {
+            return create(name, argNames, argTypes, returnType, 
calledOnNullInput, language, body);
+        }
+        catch (InvalidRequestException e)
+        {
+            return UDFunction.createBrokenFunction(name, argNames, argTypes, 
returnType, calledOnNullInput, language, body, e);
+        }
+    }
+
     public static UDFunction create(FunctionName name,
                                     List<ColumnIdentifier> argNames,
                                     List<AbstractType<?>> argTypes,
@@ -582,6 +604,26 @@ public abstract class UDFunction extends AbstractFunction 
implements ScalarFunct
     }
 
     @Override
+    public boolean referencesUserType(ByteBuffer name)
+    {
+        return any(argTypes(), t -> t.referencesUserType(name)) || 
returnType.referencesUserType(name);
+    }
+
+    public UDFunction withUpdatedUserType(UserType udt)
+    {
+        if (!referencesUserType(udt.name))
+            return this;
+
+        return tryCreate(name,
+                         argNames,
+                         Lists.transform(argTypes, t -> 
t.withUpdatedUserType(udt)),
+                         returnType.withUpdatedUserType(udt),
+                         calledOnNullInput,
+                         language,
+                         body);
+    }
+
+    @Override
     public boolean equals(Object o)
     {
         if (!(o instanceof UDFunction))

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/restrictions/CustomIndexExpression.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/restrictions/CustomIndexExpression.java 
b/src/java/org/apache/cassandra/cql3/restrictions/CustomIndexExpression.java
index 6ea6842..19090b2 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/CustomIndexExpression.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/CustomIndexExpression.java
@@ -27,12 +27,12 @@ public class CustomIndexExpression
 {
     private final ColumnIdentifier valueColId = new ColumnIdentifier("custom 
index expression", false);
 
-    public final IndexName targetIndex;
+    public final QualifiedName targetIndex;
     public final Term.Raw valueRaw;
 
     private Term value;
 
-    public CustomIndexExpression(IndexName targetIndex, Term.Raw value)
+    public CustomIndexExpression(QualifiedName targetIndex, Term.Raw value)
     {
         this.targetIndex = targetIndex;
         this.valueRaw = value;
@@ -49,8 +49,14 @@ public class CustomIndexExpression
     {
         filter.addCustomIndexExpression(table,
                                         table.indexes
-                                             .get(targetIndex.getIdx())
+                                             .get(targetIndex.getName())
                                              .orElseThrow(() -> 
IndexRestrictions.indexNotFound(targetIndex, table)),
                                         value.bindAndGet(options));
     }
+
+    @Override
+    public String toString()
+    {
+        return String.format("expr(%s,%s)", targetIndex, valueRaw);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/restrictions/IndexRestrictions.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/restrictions/IndexRestrictions.java 
b/src/java/org/apache/cassandra/cql3/restrictions/IndexRestrictions.java
index ced04ed..91038fb 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/IndexRestrictions.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/IndexRestrictions.java
@@ -21,8 +21,8 @@ package org.apache.cassandra.cql3.restrictions;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.cassandra.cql3.QualifiedName;
 import org.apache.cassandra.schema.TableMetadata;
-import org.apache.cassandra.cql3.IndexName;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 
 public class IndexRestrictions
@@ -61,23 +61,23 @@ public class IndexRestrictions
         return customExpressions;
     }
 
-    static InvalidRequestException invalidIndex(IndexName indexName, 
TableMetadata table)
+    static InvalidRequestException invalidIndex(QualifiedName indexName, 
TableMetadata table)
     {
-        return new InvalidRequestException(String.format(INVALID_INDEX, 
indexName.getIdx(), table.toString()));
+        return new InvalidRequestException(String.format(INVALID_INDEX, 
indexName.getName(), table));
     }
 
-    static InvalidRequestException indexNotFound(IndexName indexName, 
TableMetadata table)
+    static InvalidRequestException indexNotFound(QualifiedName indexName, 
TableMetadata table)
     {
-        return new InvalidRequestException(String.format(INDEX_NOT_FOUND, 
indexName.getIdx(), table.toString()));
+        return new InvalidRequestException(String.format(INDEX_NOT_FOUND, 
indexName.getName(), table));
     }
 
-    static InvalidRequestException nonCustomIndexInExpression(IndexName 
indexName)
+    static InvalidRequestException nonCustomIndexInExpression(QualifiedName 
indexName)
     {
-        return new 
InvalidRequestException(String.format(NON_CUSTOM_INDEX_IN_EXPRESSION, 
indexName.getIdx()));
+        return new 
InvalidRequestException(String.format(NON_CUSTOM_INDEX_IN_EXPRESSION, 
indexName.getName()));
     }
 
-    static InvalidRequestException customExpressionNotSupported(IndexName 
indexName)
+    static InvalidRequestException customExpressionNotSupported(QualifiedName 
indexName)
     {
-        return new 
InvalidRequestException(String.format(CUSTOM_EXPRESSION_NOT_SUPPORTED, 
indexName.getIdx()));
+        return new 
InvalidRequestException(String.format(CUSTOM_EXPRESSION_NOT_SUPPORTED, 
indexName.getName()));
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java 
b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
index b368c22..8fb02fe 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
@@ -129,12 +129,27 @@ public final class StatementRestrictions
                                  boolean allowFiltering,
                                  boolean forView)
     {
+        this(type, table, whereClause, boundNames, selectsOnlyStaticColumns, 
type.allowUseOfSecondaryIndices(), allowFiltering, forView);
+    }
+
+
+    // allowUseOfSecondaryIndices override for CREATE MV statement restriction 
processing purposes (we do not want
+    // the statement to trigger Keyspace.open to determine the value)
+    public StatementRestrictions(StatementType type,
+                                 TableMetadata table,
+                                 WhereClause whereClause,
+                                 VariableSpecifications boundNames,
+                                 boolean selectsOnlyStaticColumns,
+                                 boolean allowUseOfSecondaryIndices,
+                                 boolean allowFiltering,
+                                 boolean forView)
+    {
         this(type, table, allowFiltering);
 
         ColumnFamilyStore cfs;
         SecondaryIndexManager secondaryIndexManager = null;
 
-        if (type.allowUseOfSecondaryIndices())
+        if (allowUseOfSecondaryIndices)
         {
             cfs = 
Keyspace.open(table.keyspace).getColumnFamilyStore(table.name);
             secondaryIndexManager = cfs.indexManager;
@@ -156,14 +171,13 @@ public final class StatementRestrictions
                 if (!forView)
                     throw new InvalidRequestException("Unsupported 
restriction: " + relation);
 
-                for (ColumnMetadata def : relation.toRestriction(table, 
boundNames).getColumnDefs())
-                    this.notNullColumns.add(def);
+                this.notNullColumns.addAll(relation.toRestriction(table, 
boundNames).getColumnDefs());
             }
             else if (relation.isLIKE())
             {
                 Restriction restriction = relation.toRestriction(table, 
boundNames);
 
-                if (!type.allowUseOfSecondaryIndices() || 
!restriction.hasSupportingIndex(secondaryIndexManager))
+                if (!allowUseOfSecondaryIndices || 
!restriction.hasSupportingIndex(secondaryIndexManager))
                     throw new InvalidRequestException(String.format("LIKE 
restriction is only supported on properly " +
                                                                     "indexed 
columns. %s is not valid.",
                                                                     
relation.toString()));
@@ -181,7 +195,7 @@ public final class StatementRestrictions
         boolean hasQueriableClusteringColumnIndex = false;
         boolean hasQueriableIndex = false;
 
-        if (type.allowUseOfSecondaryIndices())
+        if (allowUseOfSecondaryIndices)
         {
             if (whereClause.containsCustomExpressions())
                 processCustomIndexExpressions(whereClause.expressions, 
boundNames, secondaryIndexManager);
@@ -569,18 +583,15 @@ public final class StatementRestrictions
 
         CustomIndexExpression expression = expressions.get(0);
 
-        CFName cfName = expression.targetIndex.getCfName();
-        if (cfName.hasKeyspace()
-            && !expression.targetIndex.getKeyspace().equals(table.keyspace))
-            throw IndexRestrictions.invalidIndex(expression.targetIndex, 
table);
+        QualifiedName name = expression.targetIndex;
 
-        if (cfName.getColumnFamily() != null && 
!cfName.getColumnFamily().equals(table.name))
+        if (name.hasKeyspace() && !name.getKeyspace().equals(table.keyspace))
             throw IndexRestrictions.invalidIndex(expression.targetIndex, 
table);
 
-        if (!table.indexes.has(expression.targetIndex.getIdx()))
+        if (!table.indexes.has(expression.targetIndex.getName()))
             throw IndexRestrictions.indexNotFound(expression.targetIndex, 
table);
 
-        Index index = 
indexManager.getIndex(table.indexes.get(expression.targetIndex.getIdx()).get());
+        Index index = 
indexManager.getIndex(table.indexes.get(expression.targetIndex.getName()).get());
 
         if (!index.getIndexMetadata().isCustom())
             throw 
IndexRestrictions.nonCustomIndexInExpression(expression.targetIndex);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
deleted file mode 100644
index 0de5b2a..0000000
--- a/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.cql3.statements;
-
-import org.apache.cassandra.auth.Permission;
-import org.apache.cassandra.config.DatabaseDescriptor;
-import org.apache.cassandra.exceptions.*;
-import org.apache.cassandra.locator.AbstractReplicationStrategy;
-import org.apache.cassandra.locator.LocalStrategy;
-import org.apache.cassandra.schema.KeyspaceMetadata;
-import org.apache.cassandra.schema.KeyspaceParams;
-import org.apache.cassandra.schema.MigrationManager;
-import org.apache.cassandra.schema.Schema;
-import org.apache.cassandra.schema.SchemaConstants;
-import org.apache.cassandra.service.ClientState;
-import org.apache.cassandra.service.ClientWarn;
-import org.apache.cassandra.service.QueryState;
-import org.apache.cassandra.service.StorageService;
-import org.apache.cassandra.transport.Event;
-
-public class AlterKeyspaceStatement extends SchemaAlteringStatement
-{
-    private final String name;
-    private final KeyspaceAttributes attrs;
-
-    public AlterKeyspaceStatement(String name, KeyspaceAttributes attrs)
-    {
-        super();
-        this.name = name;
-        this.attrs = attrs;
-    }
-
-    @Override
-    public String keyspace()
-    {
-        return name;
-    }
-
-    public void checkAccess(ClientState state) throws UnauthorizedException, 
InvalidRequestException
-    {
-        state.hasKeyspaceAccess(name, Permission.ALTER);
-    }
-
-    public void validate(ClientState state) throws RequestValidationException
-    {
-        KeyspaceMetadata ksm = Schema.instance.getKeyspaceMetadata(name);
-        if (ksm == null)
-            throw new InvalidRequestException("Unknown keyspace " + name);
-        if (SchemaConstants.isSystemKeyspace(ksm.name))
-            throw new InvalidRequestException("Cannot alter system keyspace");
-
-        attrs.validate();
-
-        if (attrs.getReplicationStrategyClass() == null && 
!attrs.getReplicationOptions().isEmpty())
-            throw new ConfigurationException("Missing replication strategy 
class");
-
-        if (attrs.getReplicationStrategyClass() != null)
-        {
-            // The strategy is validated through KSMetaData.validate() in 
announceKeyspaceUpdate below.
-            // However, for backward compatibility with thrift, this doesn't 
validate unexpected options yet,
-            // so doing proper validation here.
-            KeyspaceParams params = attrs.asAlteredKeyspaceParams(ksm.params);
-            params.validate(name);
-            if (params.replication.klass.equals(LocalStrategy.class))
-                throw new ConfigurationException("Unable to use given strategy 
class: LocalStrategy is reserved for internal use.");
-            warnIfIncreasingRF(ksm, params);
-        }
-    }
-
-    private void warnIfIncreasingRF(KeyspaceMetadata ksm, KeyspaceParams 
params)
-    {
-        AbstractReplicationStrategy oldStrategy = 
AbstractReplicationStrategy.createReplicationStrategy(ksm.name,
-                                                                               
                         ksm.params.replication.klass,
-                                                                               
                         StorageService.instance.getTokenMetadata(),
-                                                                               
                         DatabaseDescriptor.getEndpointSnitch(),
-                                                                               
                         ksm.params.replication.options);
-        AbstractReplicationStrategy newStrategy = 
AbstractReplicationStrategy.createReplicationStrategy(keyspace(),
-                                                                               
                         params.replication.klass,
-                                                                               
                         StorageService.instance.getTokenMetadata(),
-                                                                               
                         DatabaseDescriptor.getEndpointSnitch(),
-                                                                               
                         params.replication.options);
-        if (newStrategy.getReplicationFactor() > 
oldStrategy.getReplicationFactor())
-            ClientWarn.instance.warn("When increasing replication factor you 
need to run a full (-full) repair to distribute the data.");
-    }
-
-    public Event.SchemaChange announceMigration(QueryState queryState, boolean 
isLocalOnly) throws RequestValidationException
-    {
-        KeyspaceMetadata oldKsm = Schema.instance.getKeyspaceMetadata(name);
-        // In the (very) unlikely case the keyspace was dropped since 
validate()
-        if (oldKsm == null)
-            throw new InvalidRequestException("Unknown keyspace " + name);
-
-        KeyspaceMetadata newKsm = 
oldKsm.withSwapped(attrs.asAlteredKeyspaceParams(oldKsm.params));
-        MigrationManager.announceKeyspaceUpdate(newKsm, isLocalOnly);
-        return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, 
keyspace());
-    }
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java
index 6134741..6572267 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java
@@ -43,13 +43,13 @@ public class AlterRoleStatement extends 
AuthenticationStatement
         if (opts.isEmpty())
             throw new InvalidRequestException("ALTER [ROLE|USER] can't be 
empty");
 
-        // validate login here before checkAccess to avoid leaking user 
existence to anonymous users.
+        // validate login here before authorize to avoid leaking user 
existence to anonymous users.
         state.ensureNotAnonymous();
         if (!DatabaseDescriptor.getRoleManager().isExistingRole(role))
             throw new InvalidRequestException(String.format("%s doesn't 
exist", role.getRoleName()));
     }
 
-    public void checkAccess(ClientState state) throws UnauthorizedException
+    public void authorize(ClientState state) throws UnauthorizedException
     {
         AuthenticatedUser user = state.getUser();
         boolean isSuper = user.isSuper();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
index 35459de..22f781a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
@@ -56,7 +56,7 @@ public class AlterTableStatement extends 
SchemaAlteringStatement
     private final List<AlterTableStatementColumn> colNameList;
     private final Long deleteTimestamp;
 
-    public AlterTableStatement(CFName name,
+    public AlterTableStatement(QualifiedName name,
                                Type type,
                                List<AlterTableStatementColumn> colDataList,
                                TableAttributes attrs,
@@ -71,9 +71,9 @@ public class AlterTableStatement extends 
SchemaAlteringStatement
         this.deleteTimestamp = deleteTimestamp;
     }
 
-    public void checkAccess(ClientState state) throws UnauthorizedException, 
InvalidRequestException
+    public void authorize(ClientState state) throws UnauthorizedException, 
InvalidRequestException
     {
-        state.hasColumnFamilyAccess(keyspace(), columnFamily(), 
Permission.ALTER);
+        state.ensureTablePermission(keyspace(), name(), Permission.ALTER);
     }
 
     public void validate(ClientState state)
@@ -83,7 +83,7 @@ public class AlterTableStatement extends 
SchemaAlteringStatement
 
     public Event.SchemaChange announceMigration(QueryState queryState, boolean 
isLocalOnly) throws RequestValidationException
     {
-        TableMetadata current = Schema.instance.validateTable(keyspace(), 
columnFamily());
+        TableMetadata current = Schema.instance.validateTable(keyspace(), 
name());
         if (current.isView())
             throw new InvalidRequestException("Cannot use ALTER TABLE on 
Materialized View");
 
@@ -96,7 +96,7 @@ public class AlterTableStatement extends 
SchemaAlteringStatement
         CQL3Type validator = null;
 
         List<ViewMetadata> viewUpdates = new ArrayList<>();
-        Iterable<ViewMetadata> views = View.findAll(keyspace(), 
columnFamily());
+        Iterable<ViewMetadata> views = View.findAll(keyspace(), name());
 
         switch (oType)
         {
@@ -187,7 +187,7 @@ public class AlterTableStatement extends 
SchemaAlteringStatement
                     def = builder.getColumn(columnName);
 
                     if (def == null)
-                        throw new 
InvalidRequestException(String.format("Column %s was not found in table %s", 
columnName, columnFamily()));
+                        throw new 
InvalidRequestException(String.format("Column %s was not found in table %s", 
columnName, name()));
 
                     switch (def.kind)
                     {
@@ -228,7 +228,7 @@ public class AlterTableStatement extends 
SchemaAlteringStatement
                         if (rejectAlter)
                             viewNames.append(',');
                         rejectAlter = true;
-                        viewNames.append(view.name);
+                        viewNames.append(view.name());
                     }
                     if (rejectAlter)
                         throw new 
InvalidRequestException(String.format("Cannot drop column %s, depended on by 
materialized views (%s.{%s})",
@@ -298,7 +298,7 @@ public class AlterTableStatement extends 
SchemaAlteringStatement
 
                         ColumnIdentifier viewFrom = 
entry.getKey().getIdentifier(view.metadata);
                         ColumnIdentifier viewTo = 
entry.getValue().getIdentifier(view.metadata);
-                        viewUpdates.add(view.renamePrimaryKeyColumn(viewFrom, 
viewTo));
+                        
viewUpdates.add(view.withRenamedPrimaryKeyColumn(viewFrom, viewTo));
                     }
                 }
                 break;
@@ -309,14 +309,14 @@ public class AlterTableStatement extends 
SchemaAlteringStatement
         for (ViewMetadata viewUpdate : viewUpdates)
             MigrationManager.announceViewUpdate(viewUpdate, isLocalOnly);
 
-        return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, 
Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
+        return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, 
Event.SchemaChange.Target.TABLE, keyspace(), name());
     }
 
     @Override
     public String toString()
     {
         return String.format("AlterTableStatement(name=%s, type=%s)",
-                             cfName,
+                             qualifiedName,
                              oType);
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
index 614b482..2cff49c 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
@@ -30,6 +30,8 @@ import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.QueryState;
 import org.apache.cassandra.transport.Event;
 
+import static java.util.function.Predicate.isEqual;
+
 public abstract class AlterTypeStatement extends SchemaAlteringStatement
 {
     protected final UTName name;
@@ -40,7 +42,7 @@ public abstract class AlterTypeStatement extends 
SchemaAlteringStatement
     }
 
     @Override
-    public void prepareKeyspace(ClientState state) throws 
InvalidRequestException
+    public void setKeyspace(ClientState state) throws InvalidRequestException
     {
         if (!name.hasKeyspace())
             name.setKeyspace(state.getKeyspace());
@@ -66,9 +68,9 @@ public abstract class AlterTypeStatement extends 
SchemaAlteringStatement
         return new Renames(name, renames);
     }
 
-    public void checkAccess(ClientState state) throws UnauthorizedException, 
InvalidRequestException
+    public void authorize(ClientState state) throws UnauthorizedException, 
InvalidRequestException
     {
-        state.hasKeyspaceAccess(keyspace(), Permission.ALTER);
+        state.ensureKeyspacePermission(keyspace(), Permission.ALTER);
     }
 
     public void validate(ClientState state) throws RequestValidationException
@@ -104,7 +106,7 @@ public abstract class AlterTypeStatement extends 
SchemaAlteringStatement
 
     protected void checkTypeNotUsedByAggregate(KeyspaceMetadata ksm)
     {
-        ksm.functions.udas().filter(aggregate -> aggregate.initialCondition() 
!= null && aggregate.stateType().referencesUserType(name.getStringTypeName()))
+        ksm.functions.udas().filter(aggregate -> aggregate.initialCondition() 
!= null && aggregate.stateType().referencesUserType(name.getUserTypeName()))
                      .findAny()
                      .ifPresent((aggregate) -> {
                          throw new 
InvalidRequestException(String.format("Cannot alter user type %s as it is still 
used as an INITCOND by aggregate %s", name, aggregate));
@@ -133,7 +135,7 @@ public abstract class AlterTypeStatement extends 
SchemaAlteringStatement
             newNames.add(fieldName);
 
             AbstractType<?> addType = type.prepare(keyspace()).getType();
-            if (addType.referencesUserType(toUpdate.getNameAsString()))
+            if (addType.referencesUserType(toUpdate.name))
                 throw new InvalidRequestException(String.format("Cannot add 
new field %s of type %s to type %s as this would create a circular reference", 
fieldName, type, name));
 
             List<AbstractType<?>> newTypes = new ArrayList<>(toUpdate.size() + 
1);
@@ -172,7 +174,15 @@ public abstract class AlterTypeStatement extends 
SchemaAlteringStatement
             }
 
             UserType updated = new UserType(toUpdate.keyspace, toUpdate.name, 
newNames, newTypes, toUpdate.isMultiCell());
-            CreateTypeStatement.checkForDuplicateNames(updated);
+
+            List<FieldIdentifier> fieldNames = new 
ArrayList<>(updated.fieldNames());
+
+            fieldNames.forEach(name ->
+            {
+                if (fieldNames.stream().filter(isEqual(name)).count() > 1)
+                    throw new InvalidRequestException(String.format("Duplicate 
field name %s in type %s", name, updated.getNameAsString()));
+            });
+
             return updated;
         }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/statements/AlterViewStatement.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/AlterViewStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/AlterViewStatement.java
deleted file mode 100644
index fbfc54c..0000000
--- a/src/java/org/apache/cassandra/cql3/statements/AlterViewStatement.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.cql3.statements;
-
-import org.apache.cassandra.auth.Permission;
-import org.apache.cassandra.cql3.CFName;
-import org.apache.cassandra.db.view.View;
-import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.exceptions.RequestValidationException;
-import org.apache.cassandra.exceptions.UnauthorizedException;
-import org.apache.cassandra.schema.MigrationManager;
-import org.apache.cassandra.schema.Schema;
-import org.apache.cassandra.schema.TableMetadata;
-import org.apache.cassandra.schema.TableMetadataRef;
-import org.apache.cassandra.schema.TableParams;
-import org.apache.cassandra.schema.ViewMetadata;
-import org.apache.cassandra.service.ClientState;
-import org.apache.cassandra.service.QueryState;
-import org.apache.cassandra.transport.Event;
-
-public class AlterViewStatement extends SchemaAlteringStatement
-{
-    private final TableAttributes attrs;
-
-    public AlterViewStatement(CFName name, TableAttributes attrs)
-    {
-        super(name);
-        this.attrs = attrs;
-    }
-
-    public void checkAccess(ClientState state) throws UnauthorizedException, 
InvalidRequestException
-    {
-        TableMetadataRef baseTable = View.findBaseTable(keyspace(), 
columnFamily());
-        if (baseTable != null)
-            state.hasColumnFamilyAccess(keyspace(), baseTable.name, 
Permission.ALTER);
-    }
-
-    public void validate(ClientState state)
-    {
-        // validated in announceMigration()
-    }
-
-    public Event.SchemaChange announceMigration(QueryState queryState, boolean 
isLocalOnly) throws RequestValidationException
-    {
-        TableMetadata meta = Schema.instance.validateTable(keyspace(), 
columnFamily());
-        if (!meta.isView())
-            throw new InvalidRequestException("Cannot use ALTER MATERIALIZED 
VIEW on Table");
-
-        ViewMetadata current = Schema.instance.getView(keyspace(), 
columnFamily());
-
-        if (attrs == null)
-            throw new InvalidRequestException("ALTER MATERIALIZED VIEW WITH 
invoked, but no parameters found");
-
-        attrs.validate();
-
-        TableParams params = 
attrs.asAlteredTableParams(current.metadata.params);
-        if (params.gcGraceSeconds == 0)
-        {
-            throw new InvalidRequestException("Cannot alter gc_grace_seconds 
of a materialized view to 0, since this " +
-                                              "value is used to TTL 
undelivered updates. Setting gc_grace_seconds too " +
-                                              "low might cause undelivered 
updates to expire before being replayed.");
-        }
-
-        if (params.defaultTimeToLive > 0)
-        {
-            throw new InvalidRequestException("Cannot set or alter 
default_time_to_live for a materialized view. " +
-                                              "Data in a materialized view 
always expire at the same time than " +
-                                              "the corresponding data in the 
parent table.");
-        }
-
-        ViewMetadata updated = 
current.copy(current.metadata.unbuild().params(params).build());
-
-        MigrationManager.announceViewUpdate(updated, isLocalOnly);
-        return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, 
Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
-    }
-
-    public String toString()
-    {
-        return String.format("AlterViewStatement(name=%s)", cfName);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java
index 0283009..a8cbaa7 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java
@@ -28,17 +28,11 @@ import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.QueryState;
 import org.apache.cassandra.transport.messages.ResultMessage;
 
-public abstract class AuthenticationStatement extends ParsedStatement 
implements CQLStatement
+public abstract class AuthenticationStatement extends CQLStatement.Raw 
implements CQLStatement
 {
-    @Override
-    public Prepared prepare()
+    public AuthenticationStatement prepare(ClientState state)
     {
-        return new Prepared(this);
-    }
-
-    public int getBoundTerms()
-    {
-        return 0;
+        return this;
     }
 
     public ResultMessage execute(QueryState state, QueryOptions options, long 
queryStartNanoTime)
@@ -49,9 +43,9 @@ public abstract class AuthenticationStatement extends 
ParsedStatement implements
 
     public abstract ResultMessage execute(ClientState state) throws 
RequestExecutionException, RequestValidationException;
 
-    public ResultMessage executeInternal(QueryState state, QueryOptions 
options)
+    public ResultMessage executeLocally(QueryState state, QueryOptions options)
     {
-        // executeInternal is for local query only, thus altering users 
doesn't make sense and is not supported
+        // executeLocally is for local query only, thus altering users doesn't 
make sense and is not supported
         throw new UnsupportedOperationException();
     }
 
@@ -59,7 +53,7 @@ public abstract class AuthenticationStatement extends 
ParsedStatement implements
     {
         try
         {
-            state.ensureHasPermission(required, resource);
+            state.ensurePermission(required, resource);
         }
         catch (UnauthorizedException e)
         {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/statements/AuthorizationStatement.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/AuthorizationStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/AuthorizationStatement.java
index 83081c8..50ca005 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AuthorizationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AuthorizationStatement.java
@@ -17,7 +17,6 @@
  */
 package org.apache.cassandra.cql3.statements;
 
-
 import org.apache.cassandra.auth.DataResource;
 import org.apache.cassandra.auth.IResource;
 import org.apache.cassandra.cql3.CQLStatement;
@@ -29,17 +28,11 @@ import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.QueryState;
 import org.apache.cassandra.transport.messages.ResultMessage;
 
-public abstract class AuthorizationStatement extends ParsedStatement 
implements CQLStatement
+public abstract class AuthorizationStatement extends CQLStatement.Raw 
implements CQLStatement
 {
-    @Override
-    public Prepared prepare()
-    {
-        return new Prepared(this);
-    }
-
-    public int getBoundTerms()
+    public AuthorizationStatement prepare(ClientState state)
     {
-        return 0;
+        return this;
     }
 
     public ResultMessage execute(QueryState state, QueryOptions options, long 
queryStartNanoTime)
@@ -50,9 +43,9 @@ public abstract class AuthorizationStatement extends 
ParsedStatement implements
 
     public abstract ResultMessage execute(ClientState state) throws 
RequestValidationException, RequestExecutionException;
 
-    public ResultMessage executeInternal(QueryState state, QueryOptions 
options)
+    public ResultMessage executeLocally(QueryState state, QueryOptions options)
     {
-        // executeInternal is for local query only, thus altering permission 
doesn't make sense and is not supported
+        // executeLocally is for local query only, thus altering permission 
doesn't make sense and is not supported
         throw new UnsupportedOperationException();
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
index e181968..b5976a3 100644
--- a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
@@ -44,6 +44,8 @@ import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.NoSpamLogger;
 import org.apache.cassandra.utils.Pair;
 
+import static java.util.function.Predicate.isEqual;
+
 import static 
org.apache.cassandra.cql3.statements.RequestValidations.checkFalse;
 
 /**
@@ -56,8 +58,8 @@ public class BatchStatement implements CQLStatement
         LOGGED, UNLOGGED, COUNTER
     }
 
-    private final int boundTerms;
     public final Type type;
+    private final VariableSpecifications bindVariables;
     private final List<ModificationStatement> statements;
 
     // Columns modified for each table (keyed by the table ID)
@@ -90,10 +92,10 @@ public class BatchStatement implements CQLStatement
      * @param statements the list of statements in the batch
      * @param attrs      additional attributes for statement (CL, timestamp, 
timeToLive)
      */
-    public BatchStatement(int boundTerms, Type type, 
List<ModificationStatement> statements, Attributes attrs)
+    public BatchStatement(Type type, VariableSpecifications bindVariables, 
List<ModificationStatement> statements, Attributes attrs)
     {
-        this.boundTerms = boundTerms;
         this.type = type;
+        this.bindVariables = bindVariables;
         this.statements = statements;
         this.attrs = attrs;
 
@@ -122,6 +124,26 @@ public class BatchStatement implements CQLStatement
         this.hasConditions = hasConditions;
     }
 
+    @Override
+    public List<ColumnSpecification> getBindVariables()
+    {
+        return bindVariables.getSpecifications();
+    }
+
+    @Override
+    public short[] getPartitionKeyBindVariableIndexes()
+    {
+        boolean affectsMultipleTables =
+            !statements.isEmpty() && statements.stream().map(s -> 
s.metadata().id).allMatch(isEqual(statements.get(0).metadata().id));
+
+        // Use the TableMetadata of the first statement for partition key bind 
indexes.  If the statements affect
+        // multiple tables, we won't send partition key bind indexes.
+        return (affectsMultipleTables || statements.isEmpty())
+             ? null
+             : 
bindVariables.getPartitionKeyBindIndexes(statements.get(0).metadata());
+    }
+
+    @Override
     public Iterable<org.apache.cassandra.cql3.functions.Function> 
getFunctions()
     {
         List<org.apache.cassandra.cql3.functions.Function> functions = new 
ArrayList<>();
@@ -130,15 +152,10 @@ public class BatchStatement implements CQLStatement
         return functions;
     }
 
-    public int getBoundTerms()
-    {
-        return boundTerms;
-    }
-
-    public void checkAccess(ClientState state) throws InvalidRequestException, 
UnauthorizedException
+    public void authorize(ClientState state) throws InvalidRequestException, 
UnauthorizedException
     {
         for (ModificationStatement statement : statements)
-            statement.checkAccess(state);
+            statement.authorize(state);
     }
 
     // Validates a prepared batch statement without validating its nested 
statements.
@@ -458,7 +475,7 @@ public class BatchStatement implements CQLStatement
         return Pair.create(casRequest, columnsWithConditions);
     }
 
-    public ResultMessage executeInternal(QueryState queryState, QueryOptions 
options) throws RequestValidationException, RequestExecutionException
+    public ResultMessage executeLocally(QueryState queryState, QueryOptions 
options) throws RequestValidationException, RequestExecutionException
     {
         if (hasConditions)
             return 
executeInternalWithConditions(BatchQueryOptions.withoutPerStatementVariables(options),
 queryState);
@@ -494,7 +511,7 @@ public class BatchStatement implements CQLStatement
         return String.format("BatchStatement(type=%s, statements=%s)", type, 
statements);
     }
 
-    public static class Parsed extends CFStatement
+    public static class Parsed extends QualifiedStatement
     {
         private final Type type;
         private final Attributes.Raw attrs;
@@ -509,48 +526,24 @@ public class BatchStatement implements CQLStatement
         }
 
         @Override
-        public void prepareKeyspace(ClientState state) throws 
InvalidRequestException
+        public void setKeyspace(ClientState state) throws 
InvalidRequestException
         {
             for (ModificationStatement.Parsed statement : parsedStatements)
-                statement.prepareKeyspace(state);
+                statement.setKeyspace(state);
         }
 
-        public ParsedStatement.Prepared prepare() throws 
InvalidRequestException
+        public BatchStatement prepare(ClientState state)
         {
-            VariableSpecifications boundNames = getBoundVariables();
-
-            String firstKS = null;
-            String firstCF = null;
-            boolean haveMultipleCFs = false;
-
             List<ModificationStatement> statements = new 
ArrayList<>(parsedStatements.size());
-            for (ModificationStatement.Parsed parsed : parsedStatements)
-            {
-                if (firstKS == null)
-                {
-                    firstKS = parsed.keyspace();
-                    firstCF = parsed.columnFamily();
-                }
-                else if (!haveMultipleCFs)
-                {
-                    haveMultipleCFs = !firstKS.equals(parsed.keyspace()) || 
!firstCF.equals(parsed.columnFamily());
-                }
-
-                statements.add(parsed.prepare(boundNames));
-            }
+            parsedStatements.forEach(s -> 
statements.add(s.prepare(bindVariables)));
 
             Attributes prepAttrs = attrs.prepare("[batch]", "[batch]");
-            prepAttrs.collectMarkerSpecification(boundNames);
+            prepAttrs.collectMarkerSpecification(bindVariables);
 
-            BatchStatement batchStatement = new 
BatchStatement(boundNames.size(), type, statements, prepAttrs);
+            BatchStatement batchStatement = new BatchStatement(type, 
bindVariables, statements, prepAttrs);
             batchStatement.validate();
 
-            // Use the TableMetadata of the first statement for partition key 
bind indexes.  If the statements affect
-            // multiple tables, we won't send partition key bind indexes.
-            short[] partitionKeyBindIndexes = (haveMultipleCFs || 
batchStatement.statements.isEmpty())? null
-                                                              : 
boundNames.getPartitionKeyBindIndexes(batchStatement.statements.get(0).metadata());
-
-            return new ParsedStatement.Prepared(batchStatement, boundNames, 
partitionKeyBindIndexes);
+            return batchStatement;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aaddbd49/src/java/org/apache/cassandra/cql3/statements/CFStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CFStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/CFStatement.java
deleted file mode 100644
index 136860e..0000000
--- a/src/java/org/apache/cassandra/cql3/statements/CFStatement.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.cql3.statements;
-
-import org.apache.cassandra.cql3.CFName;
-import org.apache.cassandra.service.ClientState;
-import org.apache.cassandra.exceptions.InvalidRequestException;
-
-/**
- * Abstract class for statements that apply on a given column family.
- */
-public abstract class CFStatement extends ParsedStatement
-{
-    protected final CFName cfName;
-
-    protected CFStatement(CFName cfName)
-    {
-        this.cfName = cfName;
-    }
-
-    public void prepareKeyspace(ClientState state) throws 
InvalidRequestException
-    {
-        if (!cfName.hasKeyspace())
-        {
-            // XXX: We explicitly only want to call state.getKeyspace() in 
this case, as we don't want to throw
-            // if not logged in any keyspace but a keyspace is explicitly set 
on the statement. So don't move
-            // the call outside the 'if' or replace the method by 
'prepareKeyspace(state.getKeyspace())'
-            cfName.setKeyspace(state.getKeyspace(), true);
-        }
-    }
-
-    // Only for internal calls, use the version with ClientState for user 
queries. In particular, the
-    // version with ClientState throws an exception if the statement does not 
have keyspace set *and*
-    // ClientState has no keyspace.
-    public void prepareKeyspace(String keyspace)
-    {
-        if (!cfName.hasKeyspace())
-            cfName.setKeyspace(keyspace, true);
-    }
-
-    public String keyspace()
-    {
-        assert cfName.hasKeyspace() : "The statement hasn't be prepared 
correctly";
-        return cfName.getKeyspace();
-    }
-
-    public String columnFamily()
-    {
-        return cfName.getColumnFamily();
-    }
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to