You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by al...@apache.org on 2015/11/04 18:08:47 UTC

[3/4] cassandra git commit: Use CQL type names in schema metadata tables

Use CQL type names in schema metadata tables

patch by Aleksey Yeschenko; reviewed by Sylvain Lebresne for
CASSANDRA-10365


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

Branch: refs/heads/trunk
Commit: 340df43fb74f7f3ef021d10ad1b4510636ee3f14
Parents: f4af154
Author: Aleksey Yeschenko <al...@apache.org>
Authored: Mon Sep 21 12:02:53 2015 -0700
Committer: Aleksey Yeschenko <al...@apache.org>
Committed: Wed Nov 4 17:06:07 2015 +0000

----------------------------------------------------------------------
 CHANGES.txt                                     |    1 +
 NOTICE.txt                                      |    4 +
 build.xml                                       |    9 +-
 ...assandra-driver-core-3.0.0-alpha4-shaded.jar |  Bin 2275541 -> 0 bytes
 ...core-3.0.0-beta1-92c4c80-SNAPSHOT-shaded.jar |  Bin 0 -> 2284484 bytes
 ...iver-internal-only-3.0.0a2.post0-95c6008.zip |  Bin 233564 -> 0 bytes
 ...iver-internal-only-3.0.0a3.post0-a983923.zip |  Bin 0 -> 229492 bytes
 lib/jgrapht-core-0.9.1.jar                      |  Bin 0 -> 351208 bytes
 lib/licenses/jgrapht-core-0.9.1.txt             |  227 +++
 .../org/apache/cassandra/config/CFMetaData.java |   12 +-
 .../org/apache/cassandra/config/Schema.java     |   44 +-
 .../org/apache/cassandra/cql3/CQL3Type.java     |   77 +-
 .../apache/cassandra/cql3/ColumnIdentifier.java |    2 +-
 .../cql3/statements/CreateTableStatement.java   |   12 +-
 .../db/DefinitionsUpdateVerbHandler.java        |    3 +-
 src/java/org/apache/cassandra/db/Keyspace.java  |    1 -
 .../apache/cassandra/db/marshal/EmptyType.java  |    7 +
 .../apache/cassandra/db/marshal/TypeParser.java |   45 -
 .../cassandra/io/sstable/CQLSSTableWriter.java  |   14 +-
 .../apache/cassandra/schema/CQLTypeParser.java  |   93 ++
 .../org/apache/cassandra/schema/Keyspaces.java  |  124 ++
 .../apache/cassandra/schema/SchemaKeyspace.java | 1421 +++++++-----------
 .../org/apache/cassandra/schema/Tables.java     |    7 +
 src/java/org/apache/cassandra/schema/Types.java |  135 +-
 src/java/org/apache/cassandra/schema/Views.java |    7 +
 .../cassandra/service/MigrationManager.java     |   15 +-
 .../apache/cassandra/service/MigrationTask.java |    4 -
 .../apache/cassandra/config/CFMetaDataTest.java |   29 +-
 .../cql3/validation/entities/TupleTypeTest.java |    4 +-
 .../cql3/validation/entities/UFTest.java        |    4 +-
 .../schema/LegacySchemaMigratorTest.java        |   12 +-
 .../cassandra/schema/SchemaKeyspaceTest.java    |   30 +-
 32 files changed, 1318 insertions(+), 1025 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index eb575e8..1914fa1 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0
+ * Use CQL type names in schema metadata tables (CASSANDRA-10365)
  * Guard batchlog replay against integer division by zero (CASSANDRA-9223)
  * Fix bug when adding a column to thrift with the same name than a primary key (CASSANDRA-10608)
  * Add client address argument to IAuthenticator::newSaslNegotiator (CASSANDRA-8068)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/NOTICE.txt
----------------------------------------------------------------------
diff --git a/NOTICE.txt b/NOTICE.txt
index a20994f..b880183 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -83,3 +83,7 @@ BSD 3-clause
 ASM
 (http://asm.ow2.org/)
 Copyright (c) 2000-2011 INRIA, France Telecom
+
+JGraphT
+(http://jgrapht.org)
+Copyright 2003-2015, by Barak Naveh and Contributors.

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/build.xml
----------------------------------------------------------------------
diff --git a/build.xml b/build.xml
index c8707cd..261d0e6 100644
--- a/build.xml
+++ b/build.xml
@@ -406,6 +406,7 @@
           <dependency groupId="org.mindrot" artifactId="jbcrypt" version="0.3m" />
           <dependency groupId="io.airlift" artifactId="airline" version="0.6" />
           <dependency groupId="io.netty" artifactId="netty-all" version="4.0.23.Final" />
+          <dependency groupId="org.jgrapht" artifactId="jgrapht-core" version="0.9.1" />
           <dependency groupId="com.google.code.findbugs" artifactId="jsr305" version="2.0.2" />
           <dependency groupId="com.clearspring.analytics" artifactId="stream" version="2.5.2" />
           <!-- TODO CASSANDRA-9543
@@ -561,16 +562,14 @@
 
         <!-- don't need jna to run, but nice to have -->
         <dependency groupId="net.java.dev.jna" artifactId="jna"/>
-        
+
         <!-- don't need jamm unless running a server in which case it needs to be a -javagent to be used anyway -->
         <dependency groupId="com.github.jbellis" artifactId="jamm"/>
 
         <dependency groupId="io.netty" artifactId="netty-all"/>
-      	
-      	<dependency groupId="joda-time" artifactId="joda-time"/>
-
+        <dependency groupId="org.jgrapht" artifactId="jgrapht-core"/>
+        <dependency groupId="joda-time" artifactId="joda-time"/>
         <dependency groupId="org.fusesource" artifactId="sigar"/>
-      	
         <dependency groupId="org.eclipse.jdt.core.compiler" artifactId="ecj" />
       </artifact:pom>
       <artifact:pom id="thrift-pom"

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/lib/cassandra-driver-core-3.0.0-alpha4-shaded.jar
----------------------------------------------------------------------
diff --git a/lib/cassandra-driver-core-3.0.0-alpha4-shaded.jar b/lib/cassandra-driver-core-3.0.0-alpha4-shaded.jar
deleted file mode 100644
index 9a4921e..0000000
Binary files a/lib/cassandra-driver-core-3.0.0-alpha4-shaded.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/lib/cassandra-driver-core-3.0.0-beta1-92c4c80-SNAPSHOT-shaded.jar
----------------------------------------------------------------------
diff --git a/lib/cassandra-driver-core-3.0.0-beta1-92c4c80-SNAPSHOT-shaded.jar b/lib/cassandra-driver-core-3.0.0-beta1-92c4c80-SNAPSHOT-shaded.jar
new file mode 100644
index 0000000..2026c52
Binary files /dev/null and b/lib/cassandra-driver-core-3.0.0-beta1-92c4c80-SNAPSHOT-shaded.jar differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/lib/cassandra-driver-internal-only-3.0.0a2.post0-95c6008.zip
----------------------------------------------------------------------
diff --git a/lib/cassandra-driver-internal-only-3.0.0a2.post0-95c6008.zip b/lib/cassandra-driver-internal-only-3.0.0a2.post0-95c6008.zip
deleted file mode 100644
index da7fa0d..0000000
Binary files a/lib/cassandra-driver-internal-only-3.0.0a2.post0-95c6008.zip and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/lib/cassandra-driver-internal-only-3.0.0a3.post0-a983923.zip
----------------------------------------------------------------------
diff --git a/lib/cassandra-driver-internal-only-3.0.0a3.post0-a983923.zip b/lib/cassandra-driver-internal-only-3.0.0a3.post0-a983923.zip
new file mode 100644
index 0000000..66ec36e
Binary files /dev/null and b/lib/cassandra-driver-internal-only-3.0.0a3.post0-a983923.zip differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/lib/jgrapht-core-0.9.1.jar
----------------------------------------------------------------------
diff --git a/lib/jgrapht-core-0.9.1.jar b/lib/jgrapht-core-0.9.1.jar
new file mode 100644
index 0000000..f491e25
Binary files /dev/null and b/lib/jgrapht-core-0.9.1.jar differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/lib/licenses/jgrapht-core-0.9.1.txt
----------------------------------------------------------------------
diff --git a/lib/licenses/jgrapht-core-0.9.1.txt b/lib/licenses/jgrapht-core-0.9.1.txt
new file mode 100644
index 0000000..5d80026
--- /dev/null
+++ b/lib/licenses/jgrapht-core-0.9.1.txt
@@ -0,0 +1,227 @@
+Eclipse Public License - v 1.0
+
+   THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+   PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF
+   THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+   1. DEFINITIONS
+
+   "Contribution" means:
+
+   a) in the case of the initial Contributor, the initial code and
+   documentation distributed under this Agreement, and
+
+   b) in the case of each subsequent Contributor:
+
+   i) changes to the Program, and
+
+   ii) additions to the Program;
+
+   where such changes and/or additions to the Program originate from and
+   are distributed by that particular Contributor. A Contribution
+   'originates' from a Contributor if it was added to the Program by such
+   Contributor itself or anyone acting on such Contributor's behalf.
+   Contributions do not include additions to the Program which: (i) are
+   separate modules of software distributed in conjunction with the
+   Program under their own license agreement, and (ii) are not derivative
+   works of the Program.
+
+   "Contributor" means any person or entity that distributes the Program.
+
+   "Licensed Patents" mean patent claims licensable by a Contributor which
+   are necessarily infringed by the use or sale of its Contribution alone
+   or when combined with the Program.
+
+   "Program" means the Contributions distributed in accordance with this
+   Agreement.
+
+   "Recipient" means anyone who receives the Program under this Agreement,
+   including all Contributors.
+
+   2. GRANT OF RIGHTS
+
+   a) Subject to the terms of this Agreement, each Contributor hereby
+   grants Recipient a non-exclusive, worldwide, royalty-free copyright
+   license to reproduce, prepare derivative works of, publicly display,
+   publicly perform, distribute and sublicense the Contribution of such
+   Contributor, if any, and such derivative works, in source code and
+   object code form.
+
+   b) Subject to the terms of this Agreement, each Contributor hereby
+   grants Recipient a non-exclusive, worldwide, royalty-free patent
+   license under Licensed Patents to make, use, sell, offer to sell,
+   import and otherwise transfer the Contribution of such Contributor, if
+   any, in source code and object code form. This patent license shall
+   apply to the combination of the Contribution and the Program if, at the
+   time the Contribution is added by the Contributor, such addition of the
+   Contribution causes such combination to be covered by the Licensed
+   Patents. The patent license shall not apply to any other combinations
+   which include the Contribution. No hardware per se is licensed
+   hereunder.
+
+   c) Recipient understands that although each Contributor grants the
+   licenses to its Contributions set forth herein, no assurances are
+   provided by any Contributor that the Program does not infringe the
+   patent or other intellectual property rights of any other entity. Each
+   Contributor disclaims any liability to Recipient for claims brought by
+   any other entity based on infringement of intellectual property rights
+   or otherwise. As a condition to exercising the rights and licenses
+   granted hereunder, each Recipient hereby assumes sole responsibility to
+   secure any other intellectual property rights needed, if any. For
+   example, if a third party patent license is required to allow Recipient
+   to distribute the Program, it is Recipient's responsibility to acquire
+   that license before distributing the Program.
+
+   d) Each Contributor represents that to its knowledge it has sufficient
+   copyright rights in its Contribution, if any, to grant the copyright
+   license set forth in this Agreement.
+
+   3. REQUIREMENTS
+
+   A Contributor may choose to distribute the Program in object code form
+   under its own license agreement, provided that:
+
+   a) it complies with the terms and conditions of this Agreement; and
+
+   b) its license agreement:
+
+   i) effectively disclaims on behalf of all Contributors all warranties
+   and conditions, express and implied, including warranties or conditions
+   of title and non-infringement, and implied warranties or conditions of
+   merchantability and fitness for a particular purpose;
+
+   ii) effectively excludes on behalf of all Contributors all liability
+   for damages, including direct, indirect, special, incidental and
+   consequential damages, such as lost profits;
+
+   iii) states that any provisions which differ from this Agreement are
+   offered by that Contributor alone and not by any other party; and
+
+   iv) states that source code for the Program is available from such
+   Contributor, and informs licensees how to obtain it in a reasonable
+   manner on or through a medium customarily used for software exchange.
+
+   When the Program is made available in source code form:
+
+   a) it must be made available under this Agreement; and
+
+   b) a copy of this Agreement must be included with each copy of the
+   Program.
+
+   Contributors may not remove or alter any copyright notices contained
+   within the Program.
+
+   Each Contributor must identify itself as the originator of its
+   Contribution, if any, in a manner that reasonably allows subsequent
+   Recipients to identify the originator of the Contribution.
+
+   4. COMMERCIAL DISTRIBUTION
+
+   Commercial distributors of software may accept certain responsibilities
+   with respect to end users, business partners and the like. While this
+   license is intended to facilitate the commercial use of the Program,
+   the Contributor who includes the Program in a commercial product
+   offering should do so in a manner which does not create potential
+   liability for other Contributors. Therefore, if a Contributor includes
+   the Program in a commercial product offering, such Contributor
+   ("Commercial Contributor") hereby agrees to defend and indemnify every
+   other Contributor ("Indemnified Contributor") against any losses,
+   damages and costs (collectively "Losses") arising from claims, lawsuits
+   and other legal actions brought by a third party against the
+   Indemnified Contributor to the extent caused by the acts or omissions
+   of such Commercial Contributor in connection with its distribution of
+   the Program in a commercial product offering. The obligations in this
+   section do not apply to any claims or Losses relating to any actual or
+   alleged intellectual property infringement. In order to qualify, an
+   Indemnified Contributor must: a) promptly notify the Commercial
+   Contributor in writing of such claim, and b) allow the Commercial
+   Contributor to control, and cooperate with the Commercial Contributor
+   in, the defense and any related settlement negotiations. The
+   Indemnified Contributor may participate in any such claim at its own
+   expense.
+
+   For example, a Contributor might include the Program in a commercial
+   product offering, Product X. That Contributor is then a Commercial
+   Contributor. If that Commercial Contributor then makes performance
+   claims, or offers warranties related to Product X, those performance
+   claims and warranties are such Commercial Contributor's responsibility
+   alone. Under this section, the Commercial Contributor would have to
+   defend claims against the other Contributors related to those
+   performance claims and warranties, and if a court requires any other
+   Contributor to pay any damages as a result, the Commercial Contributor
+   must pay those damages.
+
+   5. NO WARRANTY
+
+   EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+   PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+   WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
+   FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible
+   for determining the appropriateness of using and distributing the
+   Program and assumes all risks associated with its exercise of rights
+   under this Agreement , including but not limited to the risks and costs
+   of program errors, compliance with applicable laws, damage to or loss
+   of data, programs or equipment, and unavailability or interruption of
+   operations.
+
+   6. DISCLAIMER OF LIABILITY
+
+   EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
+   ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+   WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+   DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+   7. GENERAL
+
+   If any provision of this Agreement is invalid or unenforceable under
+   applicable law, it shall not affect the validity or enforceability of
+   the remainder of the terms of this Agreement, and without further
+   action by the parties hereto, such provision shall be reformed to the
+   minimum extent necessary to make such provision valid and enforceable.
+
+   If Recipient institutes patent litigation against any entity (including
+   a cross-claim or counterclaim in a lawsuit) alleging that the Program
+   itself (excluding combinations of the Program with other software or
+   hardware) infringes such Recipient's patent(s), then such Recipient's
+   rights granted under Section 2(b) shall terminate as of the date such
+   litigation is filed.
+
+   All Recipient's rights under this Agreement shall terminate if it fails
+   to comply with any of the material terms or conditions of this
+   Agreement and does not cure such failure in a reasonable period of time
+   after becoming aware of such noncompliance. If all Recipient's rights
+   under this Agreement terminate, Recipient agrees to cease use and
+   distribution of the Program as soon as reasonably practicable. However,
+   Recipient's obligations under this Agreement and any licenses granted
+   by Recipient relating to the Program shall continue and survive.
+
+   Everyone is permitted to copy and distribute copies of this Agreement,
+   but in order to avoid inconsistency the Agreement is copyrighted and
+   may only be modified in the following manner. The Agreement Steward
+   reserves the right to publish new versions (including revisions) of
+   this Agreement from time to time. No one other than the Agreement
+   Steward has the right to modify this Agreement. The Eclipse Foundation
+   is the initial Agreement Steward. The Eclipse Foundation may assign the
+   responsibility to serve as the Agreement Steward to a suitable separate
+   entity. Each new version of the Agreement will be given a
+   distinguishing version number. The Program (including Contributions)
+   may always be distributed subject to the version of the Agreement under
+   which it was received. In addition, after a new version of the
+   Agreement is published, Contributor may elect to distribute the Program
+   (including its Contributions) under the new version. Except as
+   expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
+   rights or licenses to the intellectual property of any Contributor
+   under this Agreement, whether expressly, by implication, estoppel or
+   otherwise. All rights in the Program not expressly granted under this
+   Agreement are reserved.
+
+   This Agreement is governed by the laws of the State of New York and the
+   intellectual property laws of the United States of America. No party to
+   this Agreement will bring a legal action under this Agreement more than
+   one year after the cause of action arose. Each party waives its rights
+   to a jury trial in any resulting litigation.

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/config/CFMetaData.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/CFMetaData.java b/src/java/org/apache/cassandra/config/CFMetaData.java
index 0387060..86f78eb 100644
--- a/src/java/org/apache/cassandra/config/CFMetaData.java
+++ b/src/java/org/apache/cassandra/config/CFMetaData.java
@@ -401,7 +401,7 @@ public final class CFMetaData
     {
         CFStatement parsed = (CFStatement)QueryProcessor.parseStatement(cql);
         parsed.prepareKeyspace(keyspace);
-        CreateTableStatement statement = (CreateTableStatement) parsed.prepare().statement;
+        CreateTableStatement statement = (CreateTableStatement) ((CreateTableStatement.RawStatement) parsed).prepare(Types.none()).statement;
 
         return statement.metadataBuilder()
                         .withId(generateLegacyCfId(keyspace, statement.columnFamily()))
@@ -721,16 +721,6 @@ public final class CFMetaData
     }
 
     /**
-     * Updates this object in place to match the definition in the system schema tables.
-     * @return true if any columns were added, removed, or altered; otherwise, false is returned
-     */
-    public boolean reload()
-    {
-        return apply(isView ? SchemaKeyspace.createViewFromName(ksName, cfName).metadata
-                            : SchemaKeyspace.createTableFromName(ksName, cfName));
-    }
-
-    /**
      * Updates CFMetaData in-place to match cfm
      *
      * @return true if any columns were added, removed, or altered; otherwise, false is returned

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/config/Schema.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/Schema.java b/src/java/org/apache/cassandra/config/Schema.java
index df4e984..117c5cd 100644
--- a/src/java/org/apache/cassandra/config/Schema.java
+++ b/src/java/org/apache/cassandra/config/Schema.java
@@ -122,7 +122,7 @@ public class Schema
      */
     public Schema loadFromDisk(boolean updateVersion)
     {
-        load(SchemaKeyspace.readSchemaFromSystemTables());
+        load(SchemaKeyspace.fetchNonSystemKeyspaces());
         if (updateVersion)
             updateVersion();
         return this;
@@ -135,7 +135,7 @@ public class Schema
      *
      * @return self to support chaining calls
      */
-    public Schema load(Collection<KeyspaceMetadata> keyspaceDefs)
+    public Schema load(Iterable<KeyspaceMetadata> keyspaceDefs)
     {
         keyspaceDefs.forEach(this::load);
         return this;
@@ -354,6 +354,16 @@ public class Schema
         return keyspaces.keySet();
     }
 
+    public Keyspaces getKeyspaces(Set<String> includedKeyspaceNames)
+    {
+        Keyspaces.Builder builder = Keyspaces.builder();
+        keyspaces.values()
+                 .stream()
+                 .filter(k -> includedKeyspaceNames.contains(k.name))
+                 .forEach(builder::add);
+        return builder.build();
+    }
+
     /**
      * Update (or insert) new keyspace definition
      *
@@ -611,15 +621,15 @@ public class Schema
         MigrationManager.instance.notifyCreateColumnFamily(cfm);
     }
 
-    public void updateTable(String ksName, String tableName)
+    public void updateTable(CFMetaData table)
     {
-        CFMetaData cfm = getCFMetaData(ksName, tableName);
-        assert cfm != null;
-        boolean columnsDidChange = cfm.reload();
+        CFMetaData current = getCFMetaData(table.ksName, table.cfName);
+        assert current != null;
+        boolean columnsDidChange = current.apply(table);
 
-        Keyspace keyspace = Keyspace.open(cfm.ksName);
-        keyspace.getColumnFamilyStore(cfm.cfName).reload();
-        MigrationManager.instance.notifyUpdateColumnFamily(cfm, columnsDidChange);
+        Keyspace keyspace = Keyspace.open(current.ksName);
+        keyspace.getColumnFamilyStore(current.cfName).reload();
+        MigrationManager.instance.notifyUpdateColumnFamily(current, columnsDidChange);
     }
 
     public void dropTable(String ksName, String tableName)
@@ -669,17 +679,15 @@ public class Schema
         MigrationManager.instance.notifyCreateView(view);
     }
 
-    public void updateView(String ksName, String viewName)
+    public void updateView(ViewDefinition view)
     {
-        Optional<ViewDefinition> optView = getKSMetaData(ksName).views.get(viewName);
-        assert optView.isPresent();
-        ViewDefinition view = optView.get();
-        boolean columnsDidChange = view.metadata.reload();
+        ViewDefinition current = getKSMetaData(view.ksName).views.get(view.viewName).get();
+        boolean columnsDidChange = current.metadata.apply(view.metadata);
 
-        Keyspace keyspace = Keyspace.open(view.ksName);
-        keyspace.getColumnFamilyStore(view.viewName).reload();
-        Keyspace.open(view.ksName).viewManager.update(view.viewName);
-        MigrationManager.instance.notifyUpdateView(view, columnsDidChange);
+        Keyspace keyspace = Keyspace.open(current.ksName);
+        keyspace.getColumnFamilyStore(current.viewName).reload();
+        Keyspace.open(current.ksName).viewManager.update(current.viewName);
+        MigrationManager.instance.notifyUpdateView(current, columnsDidChange);
     }
 
     public void dropView(String ksName, String viewName)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/cql3/CQL3Type.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/CQL3Type.java b/src/java/org/apache/cassandra/cql3/CQL3Type.java
index 749b989..7f5afa6 100644
--- a/src/java/org/apache/cassandra/cql3/CQL3Type.java
+++ b/src/java/org/apache/cassandra/cql3/CQL3Type.java
@@ -17,19 +17,21 @@
  */
 package org.apache.cassandra.cql3;
 
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.config.Schema;
-import org.apache.cassandra.db.SystemKeyspace;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.exceptions.ConfigurationException;
 import org.apache.cassandra.exceptions.SyntaxException;
 import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Types;
 
 public interface CQL3Type
 {
@@ -45,21 +47,22 @@ public interface CQL3Type
         BLOB        (BytesType.instance),
         BOOLEAN     (BooleanType.instance),
         COUNTER     (CounterColumnType.instance),
+        DATE        (SimpleDateType.instance),
         DECIMAL     (DecimalType.instance),
         DOUBLE      (DoubleType.instance),
+        EMPTY       (EmptyType.instance),
         FLOAT       (FloatType.instance),
         INET        (InetAddressType.instance),
         INT         (Int32Type.instance),
         SMALLINT    (ShortType.instance),
         TEXT        (UTF8Type.instance),
+        TIME        (TimeType.instance),
         TIMESTAMP   (TimestampType.instance),
+        TIMEUUID    (TimeUUIDType.instance),
         TINYINT     (ByteType.instance),
         UUID        (UUIDType.instance),
         VARCHAR     (UTF8Type.instance),
-        VARINT      (IntegerType.instance),
-        TIMEUUID    (TimeUUIDType.instance),
-        DATE        (SimpleDateType.instance),
-        TIME        (TimeType.instance);
+        VARINT      (IntegerType.instance);
 
         private final AbstractType<?> type;
 
@@ -243,7 +246,7 @@ public interface CQL3Type
         @Override
         public String toString()
         {
-            return name;
+            return "frozen<" + ColumnIdentifier.maybeQuote(name) + '>';
         }
     }
 
@@ -291,14 +294,14 @@ public interface CQL3Type
         public String toString()
         {
             StringBuilder sb = new StringBuilder();
-            sb.append("tuple<");
+            sb.append("frozen<tuple<");
             for (int i = 0; i < type.size(); i++)
             {
                 if (i > 0)
                     sb.append(", ");
                 sb.append(type.type(i).asCQL3Type());
             }
-            sb.append(">");
+            sb.append(">>");
             return sb.toString();
         }
     }
@@ -342,7 +345,20 @@ public interface CQL3Type
             throw new InvalidRequestException(message);
         }
 
-        public abstract CQL3Type prepare(String keyspace) throws InvalidRequestException;
+        public CQL3Type prepare(String keyspace)
+        {
+            KeyspaceMetadata ksm = Schema.instance.getKSMetaData(keyspace);
+            if (ksm == null)
+                throw new ConfigurationException(String.format("Keyspace %s doesn't exist", keyspace));
+            return prepare(keyspace, ksm.types);
+        }
+
+        public abstract CQL3Type prepare(String keyspace, Types udts) throws InvalidRequestException;
+
+        public boolean referencesUserType(String name)
+        {
+            return false;
+        }
 
         public static Raw from(CQL3Type type)
         {
@@ -382,14 +398,14 @@ public interface CQL3Type
 
         private static class RawType extends Raw
         {
-            private CQL3Type type;
+            private final CQL3Type type;
 
             private RawType(CQL3Type type)
             {
                 this.type = type;
             }
 
-            public CQL3Type prepare(String keyspace) throws InvalidRequestException
+            public CQL3Type prepare(String keyspace, Types udts) throws InvalidRequestException
             {
                 return type;
             }
@@ -443,7 +459,7 @@ public interface CQL3Type
                 return true;
             }
 
-            public CQL3Type prepare(String keyspace) throws InvalidRequestException
+            public CQL3Type prepare(String keyspace, Types udts) throws InvalidRequestException
             {
                 assert values != null : "Got null values type for a collection";
 
@@ -461,16 +477,21 @@ public interface CQL3Type
                 switch (kind)
                 {
                     case LIST:
-                        return new Collection(ListType.getInstance(values.prepare(keyspace).getType(), !frozen));
+                        return new Collection(ListType.getInstance(values.prepare(keyspace, udts).getType(), !frozen));
                     case SET:
-                        return new Collection(SetType.getInstance(values.prepare(keyspace).getType(), !frozen));
+                        return new Collection(SetType.getInstance(values.prepare(keyspace, udts).getType(), !frozen));
                     case MAP:
                         assert keys != null : "Got null keys type for a collection";
-                        return new Collection(MapType.getInstance(keys.prepare(keyspace).getType(), values.prepare(keyspace).getType(), !frozen));
+                        return new Collection(MapType.getInstance(keys.prepare(keyspace, udts).getType(), values.prepare(keyspace, udts).getType(), !frozen));
                 }
                 throw new AssertionError();
             }
 
+            public boolean referencesUserType(String name)
+            {
+                return (keys != null && keys.referencesUserType(name)) || values.referencesUserType(name);
+            }
+
             @Override
             public String toString()
             {
@@ -510,13 +531,13 @@ public interface CQL3Type
                 return false;
             }
 
-            public CQL3Type prepare(String keyspace) throws InvalidRequestException
+            public CQL3Type prepare(String keyspace, Types udts) throws InvalidRequestException
             {
                 if (name.hasKeyspace())
                 {
                     // The provided keyspace is the one of the current statement this is part of. If it's different from the keyspace of
                     // the UTName, we reject since we want to limit user types to their own keyspace (see #6643)
-                    if (keyspace != null && !SystemKeyspace.NAME.equals(name.getKeyspace()) && !keyspace.equals(name.getKeyspace()))
+                    if (!keyspace.equals(name.getKeyspace()))
                         throw new InvalidRequestException(String.format("Statement on keyspace %s cannot refer to a user type in keyspace %s; "
                                                                         + "user types can only be used in the keyspace they are defined in",
                                                                         keyspace, name.getKeyspace()));
@@ -526,10 +547,7 @@ public interface CQL3Type
                     name.setKeyspace(keyspace);
                 }
 
-                KeyspaceMetadata ksm = Schema.instance.getKSMetaData(name.getKeyspace());
-                if (ksm == null)
-                    throw new InvalidRequestException("Unknown keyspace " + name.getKeyspace());
-                UserType type = ksm.types.getNullable(name.getUserTypeName());
+                UserType type = udts.getNullable(name.getUserTypeName());
                 if (type == null)
                     throw new InvalidRequestException("Unknown type " + name);
 
@@ -539,6 +557,11 @@ public interface CQL3Type
                 return new UserDefined(name.toString(), type);
             }
 
+            public boolean referencesUserType(String name)
+            {
+                return this.name.getStringTypeName().equals(name);
+            }
+
             protected boolean supportsFreezing()
             {
                 return true;
@@ -573,14 +596,13 @@ public interface CQL3Type
             public void freeze() throws InvalidRequestException
             {
                 for (CQL3Type.Raw t : types)
-                {
                     if (t.supportsFreezing())
                         t.freeze();
-                }
+
                 frozen = true;
             }
 
-            public CQL3Type prepare(String keyspace) throws InvalidRequestException
+            public CQL3Type prepare(String keyspace, Types udts) throws InvalidRequestException
             {
                 if (!frozen)
                     freeze();
@@ -591,11 +613,16 @@ public interface CQL3Type
                     if (t.isCounter())
                         throw new InvalidRequestException("Counters are not allowed inside tuples");
 
-                    ts.add(t.prepare(keyspace).getType());
+                    ts.add(t.prepare(keyspace, udts).getType());
                 }
                 return new Tuple(new TupleType(ts));
             }
 
+            public boolean referencesUserType(String name)
+            {
+                return types.stream().anyMatch(t -> t.referencesUserType(name));
+            }
+
             @Override
             public String toString()
             {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
index eb16f93..745e4f0 100644
--- a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
@@ -328,7 +328,7 @@ public class ColumnIdentifier extends org.apache.cassandra.cql3.selection.Select
         }
     }
 
-    private static String maybeQuote(String text)
+    static String maybeQuote(String text)
     {
         if (UNQUOTED_IDENTIFIER.matcher(text).matches())
             return text;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
index 8e1d6c6..a1947df 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
@@ -30,7 +30,9 @@ import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.db.*;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.exceptions.*;
+import org.apache.cassandra.schema.KeyspaceMetadata;
 import org.apache.cassandra.schema.TableParams;
+import org.apache.cassandra.schema.Types;
 import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.MigrationManager;
 import org.apache.cassandra.service.QueryState;
@@ -193,6 +195,14 @@ public class CreateTableStatement extends SchemaAlteringStatement
          */
         public ParsedStatement.Prepared prepare() throws RequestValidationException
         {
+            KeyspaceMetadata ksm = Schema.instance.getKSMetaData(keyspace());
+            if (ksm == null)
+                throw new ConfigurationException(String.format("Keyspace %s doesn't exist", keyspace()));
+            return prepare(ksm.types);
+        }
+
+        public ParsedStatement.Prepared prepare(Types udts) throws RequestValidationException
+        {
             // Column family name
             if (!columnFamily().matches("\\w+"))
                 throw new InvalidRequestException(String.format("\"%s\" is not a valid table name (must be alphanumeric character or underscore only: [a-zA-Z_0-9]+)", columnFamily()));
@@ -212,7 +222,7 @@ public class CreateTableStatement extends SchemaAlteringStatement
             for (Map.Entry<ColumnIdentifier, CQL3Type.Raw> entry : definitions.entrySet())
             {
                 ColumnIdentifier id = entry.getKey();
-                CQL3Type pt = entry.getValue().prepare(keyspace());
+                CQL3Type pt = entry.getValue().prepare(keyspace(), udts);
                 if (pt.isCollection() && ((CollectionType)pt.getType()).isMultiCell())
                     stmt.collections.put(id.bytes, (CollectionType)pt.getType());
                 if (entry.getValue().isCounter())

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/db/DefinitionsUpdateVerbHandler.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/DefinitionsUpdateVerbHandler.java b/src/java/org/apache/cassandra/db/DefinitionsUpdateVerbHandler.java
index b849f95..8b3e121 100644
--- a/src/java/org/apache/cassandra/db/DefinitionsUpdateVerbHandler.java
+++ b/src/java/org/apache/cassandra/db/DefinitionsUpdateVerbHandler.java
@@ -24,6 +24,7 @@ import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.concurrent.Stage;
 import org.apache.cassandra.concurrent.StageManager;
+import org.apache.cassandra.exceptions.ConfigurationException;
 import org.apache.cassandra.net.IVerbHandler;
 import org.apache.cassandra.net.MessageIn;
 import org.apache.cassandra.schema.SchemaKeyspace;
@@ -45,7 +46,7 @@ public class DefinitionsUpdateVerbHandler implements IVerbHandler<Collection<Mut
 
         StageManager.getStage(Stage.MIGRATION).submit(new WrappedRunnable()
         {
-            public void runMayThrow() throws Exception
+            public void runMayThrow() throws ConfigurationException
             {
                 SchemaKeyspace.mergeSchemaAndAnnounceVersion(message.payload);
             }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/db/Keyspace.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/Keyspace.java b/src/java/org/apache/cassandra/db/Keyspace.java
index 293f8a3..eb28b2c 100644
--- a/src/java/org/apache/cassandra/db/Keyspace.java
+++ b/src/java/org/apache/cassandra/db/Keyspace.java
@@ -377,7 +377,6 @@ public class Keyspace
             // re-initializing an existing CF.  This will happen if you cleared the schema
             // on this node and it's getting repopulated from the rest of the cluster.
             assert cfs.name.equals(cfName);
-            cfs.metadata.reload();
             cfs.reload();
         }
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/db/marshal/EmptyType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/EmptyType.java b/src/java/org/apache/cassandra/db/marshal/EmptyType.java
index 9cd7226..c653084 100644
--- a/src/java/org/apache/cassandra/db/marshal/EmptyType.java
+++ b/src/java/org/apache/cassandra/db/marshal/EmptyType.java
@@ -19,6 +19,7 @@ package org.apache.cassandra.db.marshal;
 
 import java.nio.ByteBuffer;
 
+import org.apache.cassandra.cql3.CQL3Type;
 import org.apache.cassandra.cql3.Constants;
 import org.apache.cassandra.cql3.Term;
 import org.apache.cassandra.serializers.TypeSerializer;
@@ -65,6 +66,12 @@ public class EmptyType extends AbstractType<Void>
         return new Constants.Value(ByteBufferUtil.EMPTY_BYTE_BUFFER);
     }
 
+    @Override
+    public CQL3Type asCQL3Type()
+    {
+        return CQL3Type.Native.EMPTY;
+    }
+
     public TypeSerializer<Void> getSerializer()
     {
         return EmptySerializer.instance;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/db/marshal/TypeParser.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/TypeParser.java b/src/java/org/apache/cassandra/db/marshal/TypeParser.java
index faa678e..35d15ab 100644
--- a/src/java/org/apache/cassandra/db/marshal/TypeParser.java
+++ b/src/java/org/apache/cassandra/db/marshal/TypeParser.java
@@ -23,7 +23,6 @@ import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
 import java.util.*;
 
-import org.apache.cassandra.cql3.CQL3Type;
 import org.apache.cassandra.exceptions.*;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
@@ -94,50 +93,6 @@ public class TypeParser
         return parse(compareWith == null ? null : compareWith.toString());
     }
 
-    public static String parseCqlNativeType(String str)
-    {
-        return CQL3Type.Native.valueOf(str.trim().toUpperCase(Locale.ENGLISH)).getType().toString();
-    }
-
-    public static String parseCqlCollectionOrFrozenType(String str) throws SyntaxException
-    {
-        str = str.trim().toLowerCase();
-        switch (str)
-        {
-            case "map": return "MapType";
-            case "set": return "SetType";
-            case "list": return "ListType";
-            case "frozen": return "FrozenType";
-            default: throw new SyntaxException("Invalid type name" + str);
-        }
-    }
-
-    /**
-     * Turns user facing type names into Abstract Types, 'text' -> UTF8Type
-     */
-    public static AbstractType<?> parseCqlName(String str) throws SyntaxException, ConfigurationException
-    {
-        return parse(parseCqlNameRecurse(str));
-    }
-
-    private static String parseCqlNameRecurse(String str) throws SyntaxException
-    {
-        if (str.indexOf(',') >= 0 && (!str.contains("<") || (str.indexOf(',') < str.indexOf('<'))))
-        {
-            String[] parseString = str.split(",", 2);
-            return parseCqlNameRecurse(parseString[0]) + "," + parseCqlNameRecurse(parseString[1]);
-        }
-        else if (str.contains("<"))
-        {
-            String[] parseString = str.trim().split("<", 2);
-            return parseCqlCollectionOrFrozenType(parseString[0]) + "(" + parseCqlNameRecurse(parseString[1].substring(0, parseString[1].length()-1)) + ")";
-        }
-        else
-        {
-            return parseCqlNativeType(str);
-        }
-    }
-
     /**
      * Parse an AbstractType from current position of this parser.
      */

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java b/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java
index 70380f4..0006a81 100644
--- a/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java
+++ b/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java
@@ -25,6 +25,7 @@ import java.util.*;
 
 import org.apache.cassandra.config.*;
 import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.statements.CFStatement;
 import org.apache.cassandra.cql3.statements.CreateTableStatement;
 import org.apache.cassandra.cql3.statements.ParsedStatement;
 import org.apache.cassandra.cql3.statements.UpdateStatement;
@@ -40,6 +41,7 @@ import org.apache.cassandra.io.sstable.format.SSTableFormat;
 import org.apache.cassandra.schema.KeyspaceMetadata;
 import org.apache.cassandra.schema.KeyspaceParams;
 import org.apache.cassandra.schema.Tables;
+import org.apache.cassandra.schema.Types;
 import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.utils.Pair;
 
@@ -348,7 +350,7 @@ public class CQLSSTableWriter implements Closeable
             {
                 synchronized (CQLSSTableWriter.class)
                 {
-                    this.schema = getStatement(schema, CreateTableStatement.class, "CREATE TABLE").left.getCFMetaData();
+                    this.schema = getTableMetadata(schema);
 
                     // We need to register the keyspace/table metadata through Schema, otherwise we won't be able to properly
                     // build the insert statement in using().
@@ -482,6 +484,16 @@ public class CQLSSTableWriter implements Closeable
             return this;
         }
 
+        private static CFMetaData getTableMetadata(String schema)
+        {
+            CFStatement parsed = (CFStatement)QueryProcessor.parseStatement(schema);
+            // tables with UDTs are currently not supported by CQLSSTableWrite, so we just use Types.none(), for now
+            // see CASSANDRA-10624 for more details
+            CreateTableStatement statement = (CreateTableStatement) ((CreateTableStatement.RawStatement) parsed).prepare(Types.none()).statement;
+            statement.validate(ClientState.forInternalCalls());
+            return statement.getCFMetaData();
+        }
+
         private static <T extends CQLStatement> Pair<T, List<ColumnSpecification>> getStatement(String query, Class<T> klass, String type)
         {
             try

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/schema/CQLTypeParser.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/schema/CQLTypeParser.java b/src/java/org/apache/cassandra/schema/CQLTypeParser.java
new file mode 100644
index 0000000..87eebd7
--- /dev/null
+++ b/src/java/org/apache/cassandra/schema/CQLTypeParser.java
@@ -0,0 +1,93 @@
+/*
+ * 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.schema;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.antlr.runtime.*;
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.exceptions.SyntaxException;
+
+import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
+
+public final class CQLTypeParser
+{
+    private static final ImmutableSet<String> PRIMITIVE_TYPES;
+
+    static
+    {
+        ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+        for (CQL3Type.Native primitive : CQL3Type.Native.values())
+            builder.add(primitive.name().toLowerCase());
+        PRIMITIVE_TYPES = builder.build();
+    }
+
+    public static AbstractType<?> parse(String keyspace, String unparsed, Types userTypes)
+    {
+        String lowercased = unparsed.toLowerCase();
+
+        // fast path for the common case of a primitive type
+        if (PRIMITIVE_TYPES.contains(lowercased))
+            return CQL3Type.Native.valueOf(unparsed.toUpperCase()).getType();
+
+        // special-case top-level UDTs
+        UserType udt = userTypes.getNullable(bytes(lowercased));
+        if (udt != null)
+            return udt;
+
+        return parseRaw(unparsed).prepare(keyspace, userTypes).getType();
+    }
+
+    static CQL3Type.Raw parseRaw(String type)
+    {
+        try
+        {
+            // Lexer and parser
+            ErrorCollector errorCollector = new ErrorCollector(type);
+            CharStream stream = new ANTLRStringStream(type);
+            CqlLexer lexer = new CqlLexer(stream);
+            lexer.addErrorListener(errorCollector);
+
+            TokenStream tokenStream = new CommonTokenStream(lexer);
+            CqlParser parser = new CqlParser(tokenStream);
+            parser.addErrorListener(errorCollector);
+
+            // Parse the query string to a statement instance
+            CQL3Type.Raw rawType = parser.comparatorType();
+
+            // The errorCollector has queue up any errors that the lexer and parser may have encountered
+            // along the way, if necessary, we turn the last error into exceptions here.
+            errorCollector.throwFirstSyntaxError();
+
+            return rawType;
+        }
+        catch (RuntimeException re)
+        {
+            throw new SyntaxException(String.format("Failed parsing statement: [%s] reason: %s %s",
+                                                    type,
+                                                    re.getClass().getSimpleName(),
+                                                    re.getMessage()));
+        }
+        catch (RecognitionException e)
+        {
+            throw new SyntaxException("Invalid or malformed CQL type: " + e.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/340df43f/src/java/org/apache/cassandra/schema/Keyspaces.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/schema/Keyspaces.java b/src/java/org/apache/cassandra/schema/Keyspaces.java
new file mode 100644
index 0000000..8c0a63e
--- /dev/null
+++ b/src/java/org/apache/cassandra/schema/Keyspaces.java
@@ -0,0 +1,124 @@
+/*
+ * 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.schema;
+
+import java.util.Iterator;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.MapDifference;
+import com.google.common.collect.Maps;
+
+public final class Keyspaces implements Iterable<KeyspaceMetadata>
+{
+    private final ImmutableMap<String, KeyspaceMetadata> keyspaces;
+
+    private Keyspaces(Builder builder)
+    {
+        keyspaces = builder.keyspaces.build();
+    }
+
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    public static Keyspaces none()
+    {
+        return builder().build();
+    }
+
+    public static Keyspaces of(KeyspaceMetadata... keyspaces)
+    {
+        return builder().add(keyspaces).build();
+    }
+
+    public Iterator<KeyspaceMetadata> iterator()
+    {
+        return keyspaces.values().iterator();
+    }
+
+    public Stream<KeyspaceMetadata> stream()
+    {
+        return keyspaces.values().stream();
+    }
+
+    public Keyspaces filter(Predicate<KeyspaceMetadata> predicate)
+    {
+        Builder builder = builder();
+        stream().filter(predicate).forEach(builder::add);
+        return builder.build();
+    }
+
+    MapDifference<String, KeyspaceMetadata> diff(Keyspaces other)
+    {
+        return Maps.difference(keyspaces, other.keyspaces);
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        return this == o || (o instanceof Keyspaces && keyspaces.equals(((Keyspaces) o).keyspaces));
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return keyspaces.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return keyspaces.values().toString();
+    }
+
+    public static final class Builder
+    {
+        private final ImmutableMap.Builder<String, KeyspaceMetadata> keyspaces = new ImmutableMap.Builder<>();
+
+        private Builder()
+        {
+        }
+
+        public Keyspaces build()
+        {
+            return new Keyspaces(this);
+        }
+
+        public Builder add(KeyspaceMetadata keyspace)
+        {
+            keyspaces.put(keyspace.name, keyspace);
+            return this;
+        }
+
+        public Builder add(KeyspaceMetadata... keyspaces)
+        {
+            for (KeyspaceMetadata keyspace : keyspaces)
+                add(keyspace);
+            return this;
+        }
+
+        public Builder add(Iterable<KeyspaceMetadata> keyspaces)
+        {
+            keyspaces.forEach(this::add);
+            return this;
+        }
+    }
+}