http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/src/java/org/apache/cassandra/cql3/QualifiedName.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/QualifiedName.java 
b/src/java/org/apache/cassandra/cql3/QualifiedName.java
new file mode 100644
index 0000000..fb2e110
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/QualifiedName.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Class for the names of the keyspace-prefixed elements (e.g. table, index, 
view names)
+ */
+public class QualifiedName
+{
+    /**
+     * The keyspace name as stored internally.
+     */
+    private String keyspace;
+    private String name;
+
+    public QualifiedName()
+    {
+    }
+
+    public QualifiedName(String keyspace, String name)
+    {
+        this.keyspace = keyspace;
+        this.name = name;
+    }
+
+    /**
+     * Sets the keyspace.
+     *
+     * @param ks the keyspace name
+     * @param keepCase <code>true</code> if the case must be kept, 
<code>false</code> otherwise.
+     */
+    public final void setKeyspace(String ks, boolean keepCase)
+    {
+        keyspace = toInternalName(ks, keepCase);
+    }
+
+    /**
+     * Checks if the keyspace is specified.
+     * @return <code>true</code> if the keyspace is specified, 
<code>false</code> otherwise.
+     */
+    public final boolean hasKeyspace()
+    {
+        return keyspace != null;
+    }
+
+    public final String getKeyspace()
+    {
+        return keyspace;
+    }
+
+    public void setName(String cf, boolean keepCase)
+    {
+        name = toInternalName(cf, keepCase);
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public String toString()
+    {
+        return hasKeyspace()
+             ? String.format("%s.%s", keyspace, name)
+             : name;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash(keyspace, name);
+    }
+
+    public boolean equals(Object o)
+    {
+        if (this == o)
+            return true;
+
+        if (!(o instanceof QualifiedName))
+            return false;
+
+        QualifiedName qn = (QualifiedName) o;
+        return Objects.equals(keyspace, qn.keyspace) && name.equals(qn.name);
+    }
+
+    /**
+     * Converts the specified name into the name used internally.
+     *
+     * @param name the name
+     * @param keepCase <code>true</code> if the case must be kept, 
<code>false</code> otherwise.
+     * @return the name used internally.
+     */
+    private static String toInternalName(String name, boolean keepCase)
+    {
+        return keepCase ? name : name.toLowerCase(Locale.US);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/src/java/org/apache/cassandra/cql3/QueryHandler.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/QueryHandler.java 
b/src/java/org/apache/cassandra/cql3/QueryHandler.java
index d3b41f0..b21f9e3 100644
--- a/src/java/org/apache/cassandra/cql3/QueryHandler.java
+++ b/src/java/org/apache/cassandra/cql3/QueryHandler.java
@@ -21,7 +21,6 @@ import java.nio.ByteBuffer;
 import java.util.Map;
 
 import org.apache.cassandra.cql3.statements.BatchStatement;
-import org.apache.cassandra.cql3.statements.ParsedStatement;
 import org.apache.cassandra.exceptions.RequestExecutionException;
 import org.apache.cassandra.exceptions.RequestValidationException;
 import org.apache.cassandra.service.ClientState;
@@ -41,7 +40,7 @@ public interface QueryHandler
                                    ClientState clientState,
                                    Map<String, ByteBuffer> customPayload) 
throws RequestValidationException;
 
-    ParsedStatement.Prepared getPrepared(MD5Digest id);
+    QueryHandler.Prepared getPrepared(MD5Digest id);
 
     ResultMessage processPrepared(CQLStatement statement,
                                   QueryState state,
@@ -54,4 +53,30 @@ public interface QueryHandler
                                BatchQueryOptions options,
                                Map<String, ByteBuffer> customPayload,
                                long queryStartNanoTime) throws 
RequestExecutionException, RequestValidationException;
+
+    public static class Prepared
+    {
+        public final CQLStatement statement;
+
+        public final MD5Digest resultMetadataId;
+
+        /**
+         * Contains the CQL statement source if the statement has been 
"regularly" perpared via
+         * {@link QueryHandler#prepare(String, ClientState, Map)}.
+         * Other usages of this class may or may not contain the CQL statement 
source.
+         */
+        public final String rawCQLStatement;
+
+        public Prepared(CQLStatement statement)
+        {
+            this(statement, "");
+        }
+
+        public Prepared(CQLStatement statement, String rawCQLStatement)
+        {
+            this.statement = statement;
+            this.rawCQLStatement = rawCQLStatement;
+            this.resultMetadataId = 
ResultSet.ResultMetadata.fromPrepared(statement).getResultMetadataId();
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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 3f0b196..77b4cdc 100644
--- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java
+++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
@@ -67,11 +67,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
@@ -118,7 +118,7 @@ public class QueryProcessor implements QueryHandler
     }
 
     // Work around initialization dependency
-    private static enum InternalStateInstance
+    private enum InternalStateInstance
     {
         INSTANCE;
 
@@ -126,9 +126,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));
         }
     }
 
@@ -174,7 +172,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);
     }
@@ -201,7 +199,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);
@@ -226,10 +224,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)
@@ -238,7 +235,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);
     }
@@ -257,43 +254,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
@@ -311,8 +310,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
@@ -326,24 +325,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
@@ -351,16 +350,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);
     }
@@ -374,7 +373,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);
         }
@@ -393,12 +392,12 @@ 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();
 
         return storePreparedStatement(queryString, 
clientState.getRawKeyspace(), prepared);
     }
@@ -413,19 +412,19 @@ 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));
 
-        ResultSet.PreparedMetadata preparedMetadata = 
ResultSet.PreparedMetadata.fromPrepared(existing);
-        ResultSet.ResultMetadata resultMetadata = 
ResultSet.ResultMetadata.fromPrepared(existing);
+        ResultSet.PreparedMetadata preparedMetadata = 
ResultSet.PreparedMetadata.fromPrepared(existing.statement);
+        ResultSet.ResultMetadata resultMetadata = 
ResultSet.ResultMetadata.fromPrepared(existing.statement);
         return new ResultMessage.Prepared(statementId, 
resultMetadata.getResultMetadataId(), preparedMetadata, resultMetadata);
     }
 
-    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).
@@ -440,8 +439,8 @@ public class QueryProcessor implements QueryHandler
         MD5Digest statementId = computeId(queryString, keyspace);
         preparedStatements.put(statementId, prepared);
         SystemKeyspace.writePreparedStatement(keyspace, statementId, 
queryString);
-        ResultSet.PreparedMetadata preparedMetadata = 
ResultSet.PreparedMetadata.fromPrepared(prepared);
-        ResultSet.ResultMetadata resultMetadata = 
ResultSet.ResultMetadata.fromPrepared(prepared);
+        ResultSet.PreparedMetadata preparedMetadata = 
ResultSet.PreparedMetadata.fromPrepared(prepared.statement);
+        ResultSet.ResultMetadata resultMetadata = 
ResultSet.ResultMetadata.fromPrepared(prepared.statement);
         return new ResultMessage.Prepared(statementId, 
resultMetadata.getResultMetadataId(), preparedMetadata, resultMetadata);
     }
 
@@ -460,11 +459,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
@@ -491,31 +490,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());
@@ -527,7 +526,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
         {
@@ -551,7 +550,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));
     }
@@ -577,10 +576,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());
@@ -593,12 +592,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());
@@ -607,7 +606,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/207c80c1/src/java/org/apache/cassandra/cql3/ResultSet.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/ResultSet.java 
b/src/java/org/apache/cassandra/cql3/ResultSet.java
index 9d79dea..455f7c4 100644
--- a/src/java/org/apache/cassandra/cql3/ResultSet.java
+++ b/src/java/org/apache/cassandra/cql3/ResultSet.java
@@ -31,7 +31,6 @@ import java.util.Objects;
 import com.google.common.annotations.VisibleForTesting;
 
 import io.netty.buffer.ByteBuf;
-import org.apache.cassandra.cql3.statements.ParsedStatement;
 import org.apache.cassandra.cql3.statements.SelectStatement;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.service.pager.PagingState;
@@ -306,10 +305,8 @@ public class ResultSet
             return resultMetadataId;
         }
 
-        public static ResultMetadata fromPrepared(ParsedStatement.Prepared 
prepared)
+        public static ResultMetadata fromPrepared(CQLStatement statement)
         {
-            CQLStatement statement = prepared.statement;
-
             if (statement instanceof SelectStatement)
                 return ((SelectStatement)statement).getResultMetadata();
 
@@ -569,9 +566,9 @@ public class ResultSet
             return sb.toString();
         }
 
-        public static PreparedMetadata fromPrepared(ParsedStatement.Prepared 
prepared)
+        public static PreparedMetadata fromPrepared(CQLStatement statement)
         {
-            return new PreparedMetadata(prepared.boundNames, 
prepared.partitionKeyBindIndexes);
+            return new PreparedMetadata(statement.getBindVariables(), 
statement.getPartitionKeyBindVariableIndexes());
         }
 
         private static class Codec implements CBCodec<PreparedMetadata>

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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..d9c5b26 100644
--- a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
+++ b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
@@ -20,6 +20,7 @@ package org.apache.cassandra.cql3;
 import java.util.Collections;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 import org.apache.cassandra.schema.ColumnMetadata;
 import org.apache.cassandra.schema.TableMetadata;
@@ -149,12 +150,34 @@ 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);
     }
 
     @Override
+    public int hashCode()
+    {
+        return Objects.hash(relationType, entity, mapKey, value, inValues);
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+            return true;
+
+        if (!(o instanceof SingleColumnRelation))
+            return false;
+
+        SingleColumnRelation scr = (SingleColumnRelation) o;
+        return Objects.equals(entity, scr.entity)
+            && Objects.equals(mapKey, scr.mapKey)
+            && Objects.equals(value, scr.value)
+            && Objects.equals(inValues, scr.inValues);
+    }
+
+    @Override
     protected Restriction newEQRestriction(TableMetadata table, 
VariableSpecifications boundNames)
     {
         ColumnMetadata columnDef = entity.prepare(table);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/src/java/org/apache/cassandra/cql3/Term.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Term.java 
b/src/java/org/apache/cassandra/cql3/Term.java
index f1737d1..f536baa 100644
--- a/src/java/org/apache/cassandra/cql3/Term.java
+++ b/src/java/org/apache/cassandra/cql3/Term.java
@@ -124,6 +124,18 @@ public interface Term
         {
             return getText();
         }
+
+        @Override
+        public int hashCode()
+        {
+            return getText().hashCode();
+        }
+
+        @Override
+        public boolean equals(Object o)
+        {
+            return this == o || (o instanceof Raw && getText().equals(((Raw) 
o).getText()));
+        }
     }
 
     public abstract class MultiColumnRaw extends Term.Raw

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/src/java/org/apache/cassandra/cql3/TokenRelation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/TokenRelation.java 
b/src/java/org/apache/cassandra/cql3/TokenRelation.java
index 62f603b..4e3313d 100644
--- a/src/java/org/apache/cassandra/cql3/TokenRelation.java
+++ b/src/java/org/apache/cassandra/cql3/TokenRelation.java
@@ -20,6 +20,7 @@ package org.apache.cassandra.cql3;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 import com.google.common.base.Joiner;
@@ -143,6 +144,25 @@ public final class TokenRelation extends Relation
         return String.format("token%s %s %s", Tuples.tupleToString(entities), 
relationType, value);
     }
 
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash(relationType, entities, value);
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+            return true;
+
+        if (!(o instanceof TokenRelation))
+            return false;
+
+        TokenRelation tr = (TokenRelation) o;
+        return entities.equals(tr.entities) && value.equals(tr.value);
+    }
+
     /**
      * Returns the definition of the columns to which apply the token 
restriction.
      *

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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..e58290e 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()
+    public List<ColumnSpecification> getBindVariables()
     {
-        return Arrays.asList(specs);
+        return specs;
     }
 
     /**
@@ -63,7 +63,7 @@ public class VariableSpecifications
      *
      * Callers of this method should ensure that all statements operate on the 
same table.
      */
-    public short[] getPartitionKeyBindIndexes(TableMetadata metadata)
+    public short[] getPartitionKeyBindVariableIndexes(TableMetadata metadata)
     {
         short[] partitionKeyPositions = new 
short[metadata.partitionKeyColumns().size()];
         boolean[] set = new boolean[partitionKeyPositions.length];
@@ -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/207c80c1/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 fb783a5..87041f9 100644
--- a/src/java/org/apache/cassandra/cql3/WhereClause.java
+++ b/src/java/org/apache/cassandra/cql3/WhereClause.java
@@ -15,20 +15,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.cassandra.cql3;
 
 import java.util.List;
+import java.util.Objects;
 
 import com.google.common.collect.ImmutableList;
 
+import org.antlr.runtime.RecognitionException;
+import org.apache.cassandra.schema.ColumnMetadata;
 import org.apache.cassandra.cql3.restrictions.CustomIndexExpression;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
+
+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;
@@ -36,9 +40,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()
@@ -51,6 +54,57 @@ 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)));
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+            return true;
+
+        if (!(o instanceof WhereClause))
+            return false;
+
+        WhereClause wc = (WhereClause) o;
+        return relations.equals(wc.relations) && 
expressions.equals(wc.expressions);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash(relations, expressions);
+    }
+
     public static final class Builder
     {
         ImmutableList.Builder<Relation> relations = new 
ImmutableList.Builder<>();
@@ -73,10 +127,4 @@ public final class WhereClause
             return new WhereClause(this);
         }
     }
-    
-    @Override
-    public String toString()
-    {
-        return ToStringBuilder.reflectionToString(this, 
ToStringStyle.SHORT_PREFIX_STYLE);
-    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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..aea0d01 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;
@@ -85,7 +87,7 @@ public abstract class AbstractFunction implements Function
         functions.add(this);
     }
 
-    public boolean hasReferenceTo(Function function)
+    public boolean referencesUserType(ByteBuffer name)
     {
         return false;
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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..e13e906 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 java.util.Optional;
 
 import org.apache.cassandra.cql3.AssignmentTestable;
 import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.schema.Difference;
 import org.github.jamm.Unmetered;
 
 @Unmetered
@@ -46,7 +49,7 @@ public interface Function extends AssignmentTestable
 
     public void addFunctionsTo(List<Function> functions);
 
-    public boolean hasReferenceTo(Function function);
+    public boolean referencesUserType(ByteBuffer name);
 
     /**
      * Returns the name of the function to use within a ResultSet.
@@ -55,4 +58,9 @@ public interface Function extends AssignmentTestable
      * @return the name of the function to use within a ResultSet
      */
     public String columnName(List<String> columnNames);
+
+    public default Optional<Difference> compare(Function other)
+    {
+        throw new UnsupportedOperationException();
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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..1a49b33 100644
--- a/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java
+++ b/src/java/org/apache/cassandra/cql3/functions/UDAggregate.java
@@ -21,16 +21,23 @@ 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.ConfigurationException;
 import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.schema.Difference;
 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;
+import static com.google.common.collect.Iterables.transform;
+
 /**
  * Base class for user-defined-aggregates.
  */
@@ -55,13 +62,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 +76,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 +84,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(name, functions, stateFunc, 
stateTypes),
+                               null == finalFunc ? null : findFunction(name, 
functions, finalFunc, finalTypes),
                                initcond);
     }
 
-    public static UDAggregate createBroken(FunctionName name,
-                                           List<AbstractType<?>> argTypes,
-                                           AbstractType<?> returnType,
-                                           ByteBuffer initcond,
-                                           InvalidRequestException reason)
+    private static UDFunction findFunction(FunctionName udaName, 
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(() -> new 
ConfigurationException(String.format("Unable to find function %s referenced by 
UDA %s", name, udaName)));
     }
 
     public boolean hasReferenceTo(Function function)
@@ -107,16 +103,37 @@ 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.newArrayList(transform(argTypes, t -> 
t.withUpdatedUserType(udt))),
+                               returnType.withUpdatedUserType(udt),
+                               findFunction(name, udfs, stateFunction.name(), 
stateFunction.argTypes()),
+                               null == finalFunction ? null : 
findFunction(name, udfs, finalFunction.name(), finalFunction.argTypes()),
+                               initcond);
+    }
+
+    @Override
     public void addFunctionsTo(List<Function> functions)
     {
         functions.add(this);
-        if (stateFunction != null)
-        {
-            stateFunction.addFunctionsTo(functions);
 
-            if (finalFunction != null)
-                finalFunction.addFunctionsTo(functions);
-        }
+        stateFunction.addFunctionsTo(functions);
+
+        if (finalFunction != null)
+            finalFunction.addFunctionsTo(functions);
     }
 
     public boolean isAggregate()
@@ -214,23 +231,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)
     {
@@ -238,13 +238,83 @@ public class UDAggregate extends AbstractFunction 
implements AggregateFunction
             return false;
 
         UDAggregate that = (UDAggregate) o;
-        return Objects.equal(name, that.name)
-            && Functions.typesMatch(argTypes, that.argTypes)
-            && Functions.typesMatch(returnType, that.returnType)
+        return equalsWithoutTypesAndFunctions(that)
+            && argTypes.equals(that.argTypes)
+            && returnType.equals(that.returnType)
             && Objects.equal(stateFunction, that.stateFunction)
             && Objects.equal(finalFunction, that.finalFunction)
-            && ((stateType == that.stateType) || ((stateType != null) && 
stateType.equals(that.stateType, true)))  // ignore freezing
-            && Objects.equal(initcond, that.initcond);
+            && ((stateType == that.stateType) || ((stateType != null) && 
stateType.equals(that.stateType)));
+    }
+
+    private boolean equalsWithoutTypesAndFunctions(UDAggregate other)
+    {
+        return name.equals(other.name)
+            && argTypes.size() == other.argTypes.size()
+            && Objects.equal(initcond, other.initcond);
+    }
+
+    @Override
+    public Optional<Difference> compare(Function function)
+    {
+        if (!(function instanceof UDAggregate))
+            throw new IllegalArgumentException();
+
+        UDAggregate other = (UDAggregate) function;
+
+        if (!equalsWithoutTypesAndFunctions(other)
+        || ((null == finalFunction) != (null == other.finalFunction))
+        || ((null == stateType) != (null == other.stateType)))
+            return Optional.of(Difference.SHALLOW);
+
+        boolean differsDeeply = false;
+
+        if (null != finalFunction && 
!finalFunction.equals(other.finalFunction))
+        {
+            if (finalFunction.name().equals(other.finalFunction.name()))
+                differsDeeply = true;
+            else
+                return Optional.of(Difference.SHALLOW);
+        }
+
+        if (null != stateType && !stateType.equals(other.stateType))
+        {
+            if 
(stateType.asCQL3Type().toString().equals(other.stateType.asCQL3Type().toString()))
+                differsDeeply = true;
+            else
+                return Optional.of(Difference.SHALLOW);
+        }
+
+        if (!returnType.equals(other.returnType))
+        {
+            if 
(returnType.asCQL3Type().toString().equals(other.returnType.asCQL3Type().toString()))
+                differsDeeply = true;
+            else
+                return Optional.of(Difference.SHALLOW);
+        }
+
+        for (int i = 0; i < argTypes().size(); i++)
+        {
+            AbstractType<?> thisType = argTypes.get(i);
+            AbstractType<?> thatType = other.argTypes.get(i);
+
+            if (!thisType.equals(thatType))
+            {
+                if 
(thisType.asCQL3Type().toString().equals(thatType.asCQL3Type().toString()))
+                    differsDeeply = true;
+                else
+                    return Optional.of(Difference.SHALLOW);
+            }
+        }
+
+        if (!stateFunction.equals(other.stateFunction))
+        {
+            if (stateFunction.name().equals(other.stateFunction.name()))
+                differsDeeply = true;
+            else
+                return Optional.of(Difference.SHALLOW);
+        }
+
+        return differsDeeply ? Optional.of(Difference.DEEP) : Optional.empty();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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..8c5a07e 100644
--- a/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
+++ b/src/java/org/apache/cassandra/cql3/functions/UDFunction.java
@@ -27,6 +27,7 @@ import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
@@ -37,6 +38,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 +46,8 @@ 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.Difference;
 import org.apache.cassandra.schema.Schema;
 import org.apache.cassandra.cql3.ColumnIdentifier;
 import org.apache.cassandra.db.marshal.AbstractType;
@@ -56,6 +60,9 @@ 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;
+import static com.google.common.collect.Iterables.transform;
+
 /**
  * Base class for User Defined Functions.
  */
@@ -214,6 +221,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 createBrokenFunction(name, argNames, argTypes, returnType, 
calledOnNullInput, language, body, e);
+        }
+    }
+
     public static UDFunction create(FunctionName name,
                                     List<ColumnIdentifier> argNames,
                                     List<AbstractType<?>> argTypes,
@@ -222,7 +247,7 @@ public abstract class UDFunction extends AbstractFunction 
implements ScalarFunct
                                     String language,
                                     String body)
     {
-        UDFunction.assertUdfsEnabled(language);
+        assertUdfsEnabled(language);
 
         switch (language)
         {
@@ -399,7 +424,7 @@ public abstract class UDFunction extends AbstractFunction 
implements ScalarFunct
     }
 
     /**
-     * Like {@link #executeAsync(int, List)} but the first parameter is 
already in non-serialized form.
+     * Like {@link #executeAsync(ProtocolVersion, List)} but the first 
parameter is already in non-serialized form.
      * Remaining parameters (2nd paramters and all others) are in {@code 
parameters}.
      * This is used to prevent superfluous (de)serialization of the state of 
aggregates.
      * Means: scalar functions of aggregates are called using this variant.
@@ -582,18 +607,83 @@ 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.newArrayList(transform(argTypes, t -> 
t.withUpdatedUserType(udt))),
+                         returnType.withUpdatedUserType(udt),
+                         calledOnNullInput,
+                         language,
+                         body);
+    }
+
+    @Override
     public boolean equals(Object o)
     {
         if (!(o instanceof UDFunction))
             return false;
 
         UDFunction that = (UDFunction)o;
-        return Objects.equal(name, that.name)
-            && Objects.equal(argNames, that.argNames)
-            && Functions.typesMatch(argTypes, that.argTypes)
-            && Functions.typesMatch(returnType, that.returnType)
-            && Objects.equal(language, that.language)
-            && Objects.equal(body, that.body);
+        return equalsWithoutTypes(that)
+            && argTypes.equals(that.argTypes)
+            && returnType.equals(that.returnType);
+    }
+
+    private boolean equalsWithoutTypes(UDFunction other)
+    {
+        return name.equals(other.name)
+            && argTypes.size() == other.argTypes.size()
+            && argNames.equals(other.argNames)
+            && body.equals(other.body)
+            && language.equals(other.language)
+            && calledOnNullInput == other.calledOnNullInput;
+    }
+
+    @Override
+    public Optional<Difference> compare(Function function)
+    {
+        if (!(function instanceof UDFunction))
+            throw new IllegalArgumentException();
+
+        UDFunction other = (UDFunction) function;
+
+        if (!equalsWithoutTypes(other))
+            return Optional.of(Difference.SHALLOW);
+
+        boolean typesDifferDeeply = false;
+
+        if (!returnType.equals(other.returnType))
+        {
+            if 
(returnType.asCQL3Type().toString().equals(other.returnType.asCQL3Type().toString()))
+                typesDifferDeeply = true;
+            else
+                return Optional.of(Difference.SHALLOW);
+        }
+
+        for (int i = 0; i < argTypes().size(); i++)
+        {
+            AbstractType<?> thisType = argTypes.get(i);
+            AbstractType<?> thatType = other.argTypes.get(i);
+
+            if (!thisType.equals(thatType))
+            {
+                if 
(thisType.asCQL3Type().toString().equals(thatType.asCQL3Type().toString()))
+                    typesDifferDeeply = true;
+                else
+                    return Optional.of(Difference.SHALLOW);
+            }
+        }
+
+        return typesDifferDeeply ? Optional.of(Difference.DEEP) : 
Optional.empty();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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 8048862..539715c 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/CustomIndexExpression.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/CustomIndexExpression.java
@@ -15,26 +15,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.cassandra.cql3.restrictions;
 
-import org.apache.cassandra.schema.TableMetadata;
+import java.util.Objects;
+
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.db.filter.RowFilter;
 import org.apache.cassandra.db.marshal.AbstractType;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.cassandra.schema.TableMetadata;
 
 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;
@@ -51,14 +50,33 @@ 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 ToStringBuilder.reflectionToString(this, 
ToStringStyle.SHORT_PREFIX_STYLE);
+        return String.format("expr(%s,%s)", targetIndex, valueRaw);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash(targetIndex, valueRaw);
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+            return true;
+
+        if (!(o instanceof CustomIndexExpression))
+            return false;
+
+        CustomIndexExpression cie = (CustomIndexExpression) o;
+        return targetIndex.equals(cie.targetIndex) && 
valueRaw.equals(cie.valueRaw);
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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 ac2e58a..fd89d1b 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;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
@@ -63,24 +63,24 @@ 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()));
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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 af1a964..5a41da0 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
@@ -131,6 +131,22 @@ public final class StatementRestrictions
                                  boolean allowFiltering,
                                  boolean forView)
     {
+        this(type, table, whereClause, boundNames, selectsOnlyStaticColumns, 
type.allowUseOfSecondaryIndices(), allowFiltering, forView);
+    }
+
+    /*
+     * We want to override allowUseOfSecondaryIndices flag from the 
StatementType for MV statements
+     * to avoid initing the Keyspace and SecondaryIndexManager.
+     */
+    public StatementRestrictions(StatementType type,
+                                 TableMetadata table,
+                                 WhereClause whereClause,
+                                 VariableSpecifications boundNames,
+                                 boolean selectsOnlyStaticColumns,
+                                 boolean allowUseOfSecondaryIndices,
+                                 boolean allowFiltering,
+                                 boolean forView)
+    {
         this(type, table, allowFiltering);
 
         IndexRegistry indexRegistry = null;
@@ -153,8 +169,7 @@ 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())
             {
@@ -178,7 +193,7 @@ public final class StatementRestrictions
         boolean hasQueriableClusteringColumnIndex = false;
         boolean hasQueriableIndex = false;
 
-        if (type.allowUseOfSecondaryIndices())
+        if (allowUseOfSecondaryIndices)
         {
             if (whereClause.containsCustomExpressions())
                 processCustomIndexExpressions(whereClause.expressions, 
boundNames, indexRegistry);
@@ -566,19 +581,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 = 
indexRegistry.getIndex(table.indexes.get(expression.targetIndex.getIdx()).get());
-
+        Index index = 
indexRegistry.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/207c80c1/src/java/org/apache/cassandra/cql3/selection/Selectable.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/Selectable.java 
b/src/java/org/apache/cassandra/cql3/selection/Selectable.java
index 998baca..220bb89 100644
--- a/src/java/org/apache/cassandra/cql3/selection/Selectable.java
+++ b/src/java/org/apache/cassandra/cql3/selection/Selectable.java
@@ -1296,6 +1296,12 @@ public interface Selectable extends AssignmentTestable
             {
                 return new WithElementSelection(selected.prepare(cfm), 
element);
             }
+
+            @Override
+            public String toString()
+            {
+                return String.format("%s[%s]", selected, element);
+            }
         }
     }
 
@@ -1379,6 +1385,12 @@ public interface Selectable extends AssignmentTestable
             {
                 return new WithSliceSelection(selected.prepare(cfm), from, to);
             }
+
+            @Override
+            public String toString()
+            {
+                return String.format("%s[%s..%s]", selected, from == null ? "" 
: from, to == null ? "" : to);
+            }
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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 00d2b94..0000000
--- a/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
+++ /dev/null
@@ -1,129 +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.audit.AuditLogEntryType;
-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;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-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.isLocalSystemKeyspace(ksm.name))
-            throw new InvalidRequestException("Cannot alter system keyspace");
-        if (ksm.isVirtual())
-            throw new InvalidRequestException("Cannot alter virtual 
keyspaces");
-
-        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());
-    }
-    
-    @Override
-    public String toString()
-    {
-        return ToStringBuilder.reflectionToString(this, 
ToStringStyle.SHORT_PREFIX_STYLE);
-    }
-
-    @Override
-    public AuditLogContext getAuditLogContext()
-    {
-        return new AuditLogContext(AuditLogEntryType.ALTER_KEYSPACE, 
keyspace(), null);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/207c80c1/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 957ac97..7a748e8 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterRoleStatement.java
@@ -17,6 +17,7 @@
  */
 package org.apache.cassandra.cql3.statements;
 
+import org.apache.cassandra.audit.AuditLogContext;
 import org.apache.cassandra.audit.AuditLogEntryType;
 import org.apache.cassandra.auth.*;
 import org.apache.cassandra.auth.IRoleManager.Option;
@@ -58,13 +59,13 @@ public class AlterRoleStatement extends 
AuthenticationStatement
         if (opts.isEmpty() && dcPermissions == null)
             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();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to