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/09/16 16:35:17 UTC

[6/6] cassandra git commit: Improve MV schema representation

Improve MV schema representation

patch by Carl Yeksigian; reviewed by Aleksey Yeschenko for
CASSANDRA-9921


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

Branch: refs/heads/cassandra-3.0
Commit: a3a8dbca5cc190caea36c5029d83f02977b6d149
Parents: f542a20
Author: Carl Yeksigian <ca...@apache.org>
Authored: Tue Aug 11 12:01:48 2015 -0400
Committer: Aleksey Yeschenko <al...@apache.org>
Committed: Wed Sep 16 15:34:18 2015 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |    1 +
 ...ore-3.0.0-alpha3-55db84c-SNAPSHOT-shaded.jar |  Bin 2209303 -> 0 bytes
 ...ore-3.0.0-alpha3-8bd064d-SNAPSHOT-shaded.jar |  Bin 0 -> 2218913 bytes
 ...iver-internal-only-3.0.0a2.post0-2429ba3.zip |  Bin 229078 -> 0 bytes
 ...iver-internal-only-3.0.0a2.post0-96883eb.zip |  Bin 0 -> 230630 bytes
 .../org/apache/cassandra/concurrent/Stage.java  |    4 +-
 .../cassandra/concurrent/StageManager.java      |    2 +-
 .../org/apache/cassandra/config/CFMetaData.java |   55 +-
 .../cassandra/config/DatabaseDescriptor.java    |    2 +-
 .../config/MaterializedViewDefinition.java      |   93 --
 .../org/apache/cassandra/config/Schema.java     |  111 +-
 .../apache/cassandra/config/ViewDefinition.java |  114 ++
 src/java/org/apache/cassandra/cql3/Cql.g        |   12 +-
 .../AlterMaterializedViewStatement.java         |   91 --
 .../cql3/statements/AlterTableStatement.java    |   99 +-
 .../cql3/statements/AlterTypeStatement.java     |   10 +
 .../cql3/statements/AlterViewStatement.java     |   94 ++
 .../CreateMaterializedViewStatement.java        |  286 ----
 .../cql3/statements/CreateTriggerStatement.java |    2 +-
 .../cql3/statements/CreateViewStatement.java    |  321 +++++
 .../DropMaterializedViewStatement.java          |   92 --
 .../cql3/statements/DropTableStatement.java     |   21 +-
 .../cql3/statements/DropTypeStatement.java      |    2 +-
 .../cql3/statements/DropViewStatement.java      |   93 ++
 .../cql3/statements/ModificationStatement.java  |   38 +-
 .../cql3/statements/SelectStatement.java        |    6 +-
 .../cql3/statements/TruncateStatement.java      |    2 +-
 .../apache/cassandra/db/ColumnFamilyStore.java  |   18 +-
 src/java/org/apache/cassandra/db/Keyspace.java  |   20 +-
 .../org/apache/cassandra/db/SystemKeyspace.java |   72 +-
 src/java/org/apache/cassandra/db/WriteType.java |    2 +-
 .../db/compaction/CompactionManager.java        |    4 +-
 .../cassandra/db/compaction/OperationType.java  |    2 +-
 .../cassandra/db/view/MaterializedView.java     |  749 ----------
 .../db/view/MaterializedViewBuilder.java        |  215 ---
 .../db/view/MaterializedViewManager.java        |  241 ----
 .../db/view/MaterializedViewUtils.java          |  109 --
 src/java/org/apache/cassandra/db/view/View.java |  682 +++++++++
 .../apache/cassandra/db/view/ViewBuilder.java   |  214 +++
 .../apache/cassandra/db/view/ViewManager.java   |  271 ++++
 .../org/apache/cassandra/db/view/ViewUtils.java |  109 ++
 .../cassandra/dht/ByteOrderedPartitioner.java   |    2 +-
 .../dht/OrderPreservingPartitioner.java         |    2 +-
 .../cassandra/metrics/MVWriteMetrics.java       |   42 -
 .../cassandra/metrics/ViewWriteMetrics.java     |   42 +
 .../cassandra/schema/KeyspaceMetadata.java      |   52 +-
 .../cassandra/schema/MaterializedViews.java     |  149 --
 .../apache/cassandra/schema/SchemaKeyspace.java |  292 ++--
 src/java/org/apache/cassandra/schema/Views.java |  171 +++
 .../cassandra/service/CassandraDaemon.java      |   11 +-
 .../cassandra/service/MigrationListener.java    |   14 +
 .../cassandra/service/MigrationManager.java     |   62 +-
 .../apache/cassandra/service/StartupChecks.java |    2 +-
 .../apache/cassandra/service/StorageProxy.java  |   60 +-
 .../cassandra/service/StorageService.java       |   18 +-
 .../cassandra/streaming/StreamReceiveTask.java  |   15 +-
 .../cassandra/thrift/CassandraServer.java       |   19 +-
 .../cassandra/thrift/ThriftConversion.java      |    8 +-
 .../utils/NativeSSTableLoaderClient.java        |   82 +-
 .../cql3/MaterializedViewLongTest.java          |  188 ---
 .../org/apache/cassandra/cql3/ViewLongTest.java |  188 +++
 .../unit/org/apache/cassandra/SchemaLoader.java |    2 +-
 .../config/DatabaseDescriptorTest.java          |    2 +-
 .../cassandra/cql3/MaterializedViewTest.java    | 1251 ----------------
 .../org/apache/cassandra/cql3/ViewTest.java     | 1355 ++++++++++++++++++
 .../db/view/MaterializedViewUtilsTest.java      |  115 --
 .../apache/cassandra/db/view/ViewUtilsTest.java |  115 ++
 .../apache/cassandra/dht/LengthPartitioner.java |    2 +-
 .../org/apache/cassandra/hints/HintTest.java    |    2 +-
 .../schema/LegacySchemaMigratorTest.java        |    3 +
 70 files changed, 4484 insertions(+), 4041 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index c688615..b213260 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0.0-rc1
+ * Improve MV schema representation (CASSANDRA-9921)
  * Add flag to enable/disable coordinator batchlog for MV writes (CASSANDRA-10230)
  * Update cqlsh COPY for new internal driver serialization interface (CASSANDRA-10318)
  * Give index implementations more control over rebuild operations (CASSANDRA-10312)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/lib/cassandra-driver-core-3.0.0-alpha3-55db84c-SNAPSHOT-shaded.jar
----------------------------------------------------------------------
diff --git a/lib/cassandra-driver-core-3.0.0-alpha3-55db84c-SNAPSHOT-shaded.jar b/lib/cassandra-driver-core-3.0.0-alpha3-55db84c-SNAPSHOT-shaded.jar
deleted file mode 100644
index 385d947..0000000
Binary files a/lib/cassandra-driver-core-3.0.0-alpha3-55db84c-SNAPSHOT-shaded.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/lib/cassandra-driver-core-3.0.0-alpha3-8bd064d-SNAPSHOT-shaded.jar
----------------------------------------------------------------------
diff --git a/lib/cassandra-driver-core-3.0.0-alpha3-8bd064d-SNAPSHOT-shaded.jar b/lib/cassandra-driver-core-3.0.0-alpha3-8bd064d-SNAPSHOT-shaded.jar
new file mode 100644
index 0000000..fc5d2f0
Binary files /dev/null and b/lib/cassandra-driver-core-3.0.0-alpha3-8bd064d-SNAPSHOT-shaded.jar differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/lib/cassandra-driver-internal-only-3.0.0a2.post0-2429ba3.zip
----------------------------------------------------------------------
diff --git a/lib/cassandra-driver-internal-only-3.0.0a2.post0-2429ba3.zip b/lib/cassandra-driver-internal-only-3.0.0a2.post0-2429ba3.zip
deleted file mode 100644
index 435c5e1..0000000
Binary files a/lib/cassandra-driver-internal-only-3.0.0a2.post0-2429ba3.zip and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/lib/cassandra-driver-internal-only-3.0.0a2.post0-96883eb.zip
----------------------------------------------------------------------
diff --git a/lib/cassandra-driver-internal-only-3.0.0a2.post0-96883eb.zip b/lib/cassandra-driver-internal-only-3.0.0a2.post0-96883eb.zip
new file mode 100644
index 0000000..e55b4c3
Binary files /dev/null and b/lib/cassandra-driver-internal-only-3.0.0a2.post0-96883eb.zip differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/src/java/org/apache/cassandra/concurrent/Stage.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/concurrent/Stage.java b/src/java/org/apache/cassandra/concurrent/Stage.java
index a57587c..ccb1565 100644
--- a/src/java/org/apache/cassandra/concurrent/Stage.java
+++ b/src/java/org/apache/cassandra/concurrent/Stage.java
@@ -27,7 +27,7 @@ public enum Stage
     READ,
     MUTATION,
     COUNTER_MUTATION,
-    MATERIALIZED_VIEW_MUTATION,
+    VIEW_MUTATION,
     GOSSIP,
     REQUEST_RESPONSE,
     ANTI_ENTROPY,
@@ -61,7 +61,7 @@ public enum Stage
                 return "internal";
             case MUTATION:
             case COUNTER_MUTATION:
-            case MATERIALIZED_VIEW_MUTATION:
+            case VIEW_MUTATION:
             case READ:
             case REQUEST_RESPONSE:
             case READ_REPAIR:

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/src/java/org/apache/cassandra/concurrent/StageManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/concurrent/StageManager.java b/src/java/org/apache/cassandra/concurrent/StageManager.java
index ee1fbe5..a2ad892 100644
--- a/src/java/org/apache/cassandra/concurrent/StageManager.java
+++ b/src/java/org/apache/cassandra/concurrent/StageManager.java
@@ -47,7 +47,7 @@ public class StageManager
     {
         stages.put(Stage.MUTATION, multiThreadedLowSignalStage(Stage.MUTATION, getConcurrentWriters()));
         stages.put(Stage.COUNTER_MUTATION, multiThreadedLowSignalStage(Stage.COUNTER_MUTATION, getConcurrentCounterWriters()));
-        stages.put(Stage.MATERIALIZED_VIEW_MUTATION, multiThreadedLowSignalStage(Stage.MATERIALIZED_VIEW_MUTATION, getConcurrentMaterializedViewWriters()));
+        stages.put(Stage.VIEW_MUTATION, multiThreadedLowSignalStage(Stage.VIEW_MUTATION, getConcurrentViewWriters()));
         stages.put(Stage.READ, multiThreadedLowSignalStage(Stage.READ, getConcurrentReaders()));
         stages.put(Stage.REQUEST_RESPONSE, multiThreadedLowSignalStage(Stage.REQUEST_RESPONSE, FBUtilities.getAvailableProcessors()));
         stages.put(Stage.INTERNAL_RESPONSE, multiThreadedStage(Stage.INTERNAL_RESPONSE, FBUtilities.getAvailableProcessors()));

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/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 a26b19d..cf1dbbf 100644
--- a/src/java/org/apache/cassandra/config/CFMetaData.java
+++ b/src/java/org/apache/cassandra/config/CFMetaData.java
@@ -62,7 +62,7 @@ public final class CFMetaData
 {
     public enum Flag
     {
-        SUPER, COUNTER, DENSE, COMPOUND, VIEW
+        SUPER, COUNTER, DENSE, COMPOUND
     }
 
     private static final Logger logger = LoggerFactory.getLogger(CFMetaData.class);
@@ -79,7 +79,7 @@ public final class CFMetaData
     private final boolean isCompound;
     private final boolean isSuper;
     private final boolean isCounter;
-    private final boolean isMaterializedView;
+    private final boolean isView;
 
     private final boolean isIndex;
 
@@ -94,7 +94,6 @@ public final class CFMetaData
     private volatile AbstractType<?> keyValidator = BytesType.instance;
     private volatile Map<ByteBuffer, DroppedColumn> droppedColumns = new HashMap<>();
     private volatile Triggers triggers = Triggers.none();
-    private volatile MaterializedViews materializedViews = MaterializedViews.none();
     private volatile Indexes indexes = Indexes.none();
 
     /*
@@ -219,12 +218,6 @@ public final class CFMetaData
         return this;
     }
 
-    public CFMetaData materializedViews(MaterializedViews prop)
-    {
-        materializedViews = prop;
-        return this;
-    }
-
     public CFMetaData indexes(Indexes indexes)
     {
         this.indexes = indexes;
@@ -238,7 +231,7 @@ public final class CFMetaData
                        boolean isCounter,
                        boolean isDense,
                        boolean isCompound,
-                       boolean isMaterializedView,
+                       boolean isView,
                        List<ColumnDefinition> partitionKeyColumns,
                        List<ColumnDefinition> clusteringColumns,
                        PartitionColumns partitionColumns,
@@ -252,7 +245,7 @@ public final class CFMetaData
         this.isCompound = isCompound;
         this.isSuper = isSuper;
         this.isCounter = isCounter;
-        this.isMaterializedView = isMaterializedView;
+        this.isView = isView;
 
         EnumSet<Flag> flags = EnumSet.noneOf(Flag.class);
         if (isSuper)
@@ -263,8 +256,6 @@ public final class CFMetaData
             flags.add(Flag.DENSE);
         if (isCompound)
             flags.add(Flag.COMPOUND);
-        if (isMaterializedView)
-            flags.add(Flag.VIEW);
         this.flags = Sets.immutableEnumSet(flags);
 
         isIndex = cfName.contains(".");
@@ -307,16 +298,6 @@ public final class CFMetaData
             this.compactValueColumn = CompactTables.getCompactValueColumn(partitionColumns, isSuper());
     }
 
-    public MaterializedViews getMaterializedViews()
-    {
-        return materializedViews;
-    }
-
-    public boolean hasMaterializedViews()
-    {
-        return !materializedViews.isEmpty();
-    }
-
     public Indexes getIndexes()
     {
         return indexes;
@@ -329,7 +310,7 @@ public final class CFMetaData
                                     boolean isCompound,
                                     boolean isSuper,
                                     boolean isCounter,
-                                    boolean isMaterializedView,
+                                    boolean isView,
                                     List<ColumnDefinition> columns,
                                     IPartitioner partitioner)
     {
@@ -363,7 +344,7 @@ public final class CFMetaData
                               isCounter,
                               isDense,
                               isCompound,
-                              isMaterializedView,
+                              isView,
                               partitions,
                               clusterings,
                               builder.build(),
@@ -464,7 +445,7 @@ public final class CFMetaData
                                        isCounter(),
                                        isDense(),
                                        isCompound(),
-                                       isMaterializedView(),
+                                       isView(),
                                        copy(partitionKeyColumns),
                                        copy(clusteringColumns),
                                        copy(partitionColumns),
@@ -481,7 +462,7 @@ public final class CFMetaData
                                        isCounter,
                                        isDense,
                                        isCompound,
-                                       isMaterializedView,
+                                       isView,
                                        copy(partitionKeyColumns),
                                        copy(clusteringColumns),
                                        copy(partitionColumns),
@@ -511,7 +492,6 @@ public final class CFMetaData
         return newCFMD.params(oldCFMD.params)
                       .droppedColumns(new HashMap<>(oldCFMD.droppedColumns))
                       .triggers(oldCFMD.triggers)
-                      .materializedViews(oldCFMD.materializedViews)
                       .indexes(oldCFMD.indexes);
     }
 
@@ -702,7 +682,6 @@ public final class CFMetaData
             && Objects.equal(columnMetadata, other.columnMetadata)
             && Objects.equal(droppedColumns, other.droppedColumns)
             && Objects.equal(triggers, other.triggers)
-            && Objects.equal(materializedViews, other.materializedViews)
             && Objects.equal(indexes, other.indexes);
     }
 
@@ -720,7 +699,6 @@ public final class CFMetaData
             .append(columnMetadata)
             .append(droppedColumns)
             .append(triggers)
-            .append(materializedViews)
             .append(indexes)
             .toHashCode();
     }
@@ -731,7 +709,8 @@ public final class CFMetaData
      */
     public boolean reload()
     {
-        return apply(SchemaKeyspace.createTableFromName(ksName, cfName));
+        return apply(isView ? SchemaKeyspace.createViewFromName(ksName, cfName).metadata
+                            : SchemaKeyspace.createTableFromName(ksName, cfName));
     }
 
     /**
@@ -766,7 +745,6 @@ public final class CFMetaData
             droppedColumns = cfm.droppedColumns;
 
         triggers = cfm.triggers;
-        materializedViews = cfm.materializedViews;
         indexes = cfm.indexes;
 
         logger.debug("application result is {}", this);
@@ -1070,9 +1048,9 @@ public final class CFMetaData
         return isCompound;
     }
 
-    public boolean isMaterializedView()
+    public boolean isView()
     {
-        return isMaterializedView;
+        return isView;
     }
 
     public Serializers serializers()
@@ -1121,7 +1099,6 @@ public final class CFMetaData
             .append("columnMetadata", columnMetadata.values())
             .append("droppedColumns", droppedColumns)
             .append("triggers", triggers)
-            .append("materializedViews", materializedViews)
             .append("indexes", indexes)
             .toString();
     }
@@ -1134,7 +1111,7 @@ public final class CFMetaData
         private final boolean isCompound;
         private final boolean isSuper;
         private final boolean isCounter;
-        private final boolean isMaterializedView;
+        private final boolean isView;
         private IPartitioner partitioner;
 
         private UUID tableId;
@@ -1144,7 +1121,7 @@ public final class CFMetaData
         private final List<Pair<ColumnIdentifier, AbstractType>> staticColumns = new ArrayList<>();
         private final List<Pair<ColumnIdentifier, AbstractType>> regularColumns = new ArrayList<>();
 
-        private Builder(String keyspace, String table, boolean isDense, boolean isCompound, boolean isSuper, boolean isCounter, boolean isMaterializedView)
+        private Builder(String keyspace, String table, boolean isDense, boolean isCompound, boolean isSuper, boolean isCounter, boolean isView)
         {
             this.keyspace = keyspace;
             this.table = table;
@@ -1152,7 +1129,7 @@ public final class CFMetaData
             this.isCompound = isCompound;
             this.isSuper = isSuper;
             this.isCounter = isCounter;
-            this.isMaterializedView = isMaterializedView;
+            this.isView = isView;
             this.partitioner = DatabaseDescriptor.getPartitioner();
         }
 
@@ -1296,7 +1273,7 @@ public final class CFMetaData
                                   isCounter,
                                   isDense,
                                   isCompound,
-                                  isMaterializedView,
+                                  isView,
                                   partitions,
                                   clusterings,
                                   builder.build(),

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
index ed220b8..7553c92 100644
--- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
+++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
@@ -1143,7 +1143,7 @@ public class DatabaseDescriptor
         return conf.concurrent_counter_writes;
     }
 
-    public static int getConcurrentMaterializedViewWriters()
+    public static int getConcurrentViewWriters()
     {
         return conf.concurrent_materialized_view_writes;
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/src/java/org/apache/cassandra/config/MaterializedViewDefinition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/MaterializedViewDefinition.java b/src/java/org/apache/cassandra/config/MaterializedViewDefinition.java
deleted file mode 100644
index 90fa35c..0000000
--- a/src/java/org/apache/cassandra/config/MaterializedViewDefinition.java
+++ /dev/null
@@ -1,93 +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.config;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.cassandra.cql3.ColumnIdentifier;
-
-public class MaterializedViewDefinition
-{
-    public final String baseCfName;
-    public final String viewName;
-    // The order of partititon columns and clustering columns is important, so we cannot switch these two to sets
-    public final List<ColumnIdentifier> partitionColumns;
-    public final List<ColumnIdentifier> clusteringColumns;
-    public final Set<ColumnIdentifier> included;
-    public final boolean includeAll;
-
-    public MaterializedViewDefinition(MaterializedViewDefinition def)
-    {
-        this(def.baseCfName, def.viewName, new ArrayList<>(def.partitionColumns), new ArrayList<>(def.clusteringColumns), new HashSet<>(def.included));
-    }
-
-    /**
-     * @param baseCfName        Name of the column family from which this view is based
-     * @param viewName          Name of the view
-     * @param partitionColumns  List of all of the partition columns, in the order they are defined
-     * @param clusteringColumns List of all of the clustering columns, in the order they are defined
-     * @param included
-     */
-    public MaterializedViewDefinition(String baseCfName, String viewName, List<ColumnIdentifier> partitionColumns, List<ColumnIdentifier> clusteringColumns, Set<ColumnIdentifier> included)
-    {
-        assert partitionColumns != null && !partitionColumns.isEmpty();
-        assert included != null;
-        this.baseCfName = baseCfName;
-        this.viewName = viewName;
-        this.partitionColumns = partitionColumns;
-        this.clusteringColumns = clusteringColumns;
-        this.includeAll = included.isEmpty();
-        this.included = included;
-    }
-
-    /**
-     * @return true if the view specified by this definition will include the column, false otherwise
-     */
-    public boolean includes(ColumnIdentifier column)
-    {
-        return includeAll
-               || partitionColumns.contains(column)
-               || clusteringColumns.contains(column)
-               || included.contains(column);
-    }
-
-    /**
-     * Replace the column {@param from} with {@param to} in this materialized view definition's partition,
-     * clustering, or included columns.
-     */
-    public void renameColumn(ColumnIdentifier from, ColumnIdentifier to)
-    {
-        if (!includeAll && included.contains(from))
-        {
-            included.remove(from);
-            included.add(to);
-        }
-
-        int partitionIndex = partitionColumns.indexOf(from);
-        if (partitionIndex >= 0)
-            partitionColumns.set(partitionIndex, to);
-
-        int clusteringIndex = clusteringColumns.indexOf(from);
-        if (clusteringIndex >= 0)
-            clusteringColumns.set(clusteringIndex, to);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/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 7cc8394..bcde978 100644
--- a/src/java/org/apache/cassandra/config/Schema.java
+++ b/src/java/org/apache/cassandra/config/Schema.java
@@ -147,6 +147,7 @@ public class Schema
     public Schema load(KeyspaceMetadata keyspaceDef)
     {
         keyspaceDef.tables.forEach(this::load);
+        keyspaceDef.views.forEach(this::load);
         setKeyspaceMetadata(keyspaceDef);
         return this;
     }
@@ -224,8 +225,11 @@ public class Schema
     public CFMetaData getCFMetaData(String keyspaceName, String cfName)
     {
         assert keyspaceName != null;
+
         KeyspaceMetadata ksm = keyspaces.get(keyspaceName);
-        return (ksm == null) ? null : ksm.tables.getNullable(cfName);
+        return ksm == null
+             ? null
+             : ksm.getTableOrViewNullable(cfName);
     }
 
     /**
@@ -246,6 +250,13 @@ public class Schema
         return getCFMetaData(descriptor.ksname, descriptor.cfname);
     }
 
+    public ViewDefinition getView(String keyspaceName, String viewName)
+    {
+        assert keyspaceName != null;
+        KeyspaceMetadata ksm = keyspaces.get(keyspaceName);
+        return (ksm == null) ? null : ksm.views.getNullable(viewName);
+    }
+
     /**
      * Get metadata about keyspace by its name
      *
@@ -274,12 +285,12 @@ public class Schema
      *
      * @return metadata about ColumnFamilies the belong to the given keyspace
      */
-    public Tables getTables(String keyspaceName)
+    public Iterable<CFMetaData> getTablesAndViews(String keyspaceName)
     {
         assert keyspaceName != null;
         KeyspaceMetadata ksm = keyspaces.get(keyspaceName);
         assert ksm != null;
-        return ksm.tables;
+        return ksm.tablesAndViews();
     }
 
     /**
@@ -356,6 +367,24 @@ public class Schema
     }
 
     /**
+     * Load individual View Definition to the schema
+     * (to make View lookup faster)
+     *
+     * @param view The View definition to load
+     */
+    public void load(ViewDefinition view)
+    {
+        CFMetaData cfm = view.metadata;
+        Pair<String, String> key = Pair.create(cfm.ksName, cfm.cfName);
+
+        if (cfIdMap.containsKey(key))
+            throw new RuntimeException(String.format("Attempting to load already loaded view %s.%s", cfm.ksName, cfm.cfName));
+
+        logger.debug("Adding {} to cfIdMap", cfm);
+        cfIdMap.put(key, cfm.cfId);
+    }
+
+    /**
      * Used for ColumnFamily data eviction out from the schema
      *
      * @param cfm The ColumnFamily Definition to evict
@@ -365,6 +394,16 @@ public class Schema
         cfIdMap.remove(Pair.create(cfm.ksName, cfm.cfName));
     }
 
+    /**
+     * Used for View eviction from the schema
+     *
+     * @param view The view definition to evict
+     */
+    private void unload(ViewDefinition view)
+    {
+        cfIdMap.remove(Pair.create(view.ksName, view.viewName));
+    }
+
     /* Function helpers */
 
     /**
@@ -442,6 +481,7 @@ public class Schema
         {
             KeyspaceMetadata ksm = getKSMetaData(keyspaceName);
             ksm.tables.forEach(this::unload);
+            ksm.views.forEach(this::unload);
             clearKeyspaceMetadata(ksm);
         }
 
@@ -468,13 +508,13 @@ public class Schema
         KeyspaceMetadata ksm = Schema.instance.getKSMetaData(ksName);
         String snapshotName = Keyspace.getTimestampedSnapshotName(ksName);
 
-        CompactionManager.instance.interruptCompactionFor(ksm.tables, true);
+        CompactionManager.instance.interruptCompactionFor(ksm.tablesAndViews(), true);
 
         Keyspace keyspace = Keyspace.open(ksm.name);
 
         // remove all cfs from the keyspace instance.
         List<UUID> droppedCfs = new ArrayList<>();
-        for (CFMetaData cfm : ksm.tables)
+        for (CFMetaData cfm : ksm.tablesAndViews())
         {
             ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(cfm.cfName);
 
@@ -556,6 +596,67 @@ public class Schema
         CommitLog.instance.forceRecycleAllSegments(Collections.singleton(cfm.cfId));
     }
 
+    public void addView(ViewDefinition view)
+    {
+        assert getCFMetaData(view.ksName, view.viewName) == null;
+
+        update(view.ksName, ks ->
+        {
+            load(view);
+
+            // make sure it's init-ed w/ the old definitions first,
+            // since we're going to call initCf on the new one manually
+            Keyspace.open(view.ksName);
+
+            return ks.withSwapped(ks.views.with(view));
+        });
+
+        Keyspace.open(view.ksName).initCf(view.metadata.cfId, view.viewName, true);
+        Keyspace.open(view.ksName).viewManager.reload();
+        MigrationManager.instance.notifyCreateView(view);
+    }
+
+    public void updateView(String ksName, String viewName)
+    {
+        Optional<ViewDefinition> optView = getKSMetaData(ksName).views.get(viewName);
+        assert optView.isPresent();
+        ViewDefinition view = optView.get();
+        boolean columnsDidChange = view.metadata.reload();
+
+        Keyspace keyspace = Keyspace.open(view.ksName);
+        keyspace.getColumnFamilyStore(view.viewName).reload();
+        Keyspace.open(view.ksName).viewManager.update(view.viewName);
+        MigrationManager.instance.notifyUpdateView(view, columnsDidChange);
+    }
+
+    public void dropView(String ksName, String viewName)
+    {
+        KeyspaceMetadata oldKsm = getKSMetaData(ksName);
+        assert oldKsm != null;
+        ColumnFamilyStore cfs = Keyspace.open(ksName).getColumnFamilyStore(viewName);
+        assert cfs != null;
+
+        // make sure all the indexes are dropped, or else.
+        cfs.indexManager.markAllIndexesRemoved();
+
+        // reinitialize the keyspace.
+        ViewDefinition view = oldKsm.views.get(viewName).get();
+        KeyspaceMetadata newKsm = oldKsm.withSwapped(oldKsm.views.without(viewName));
+
+        unload(view);
+        setKeyspaceMetadata(newKsm);
+
+        CompactionManager.instance.interruptCompactionFor(Collections.singleton(view.metadata), true);
+
+        if (DatabaseDescriptor.isAutoSnapshot())
+            cfs.snapshot(Keyspace.getTimestampedSnapshotName(cfs.name));
+        Keyspace.open(ksName).dropCf(view.metadata.cfId);
+        Keyspace.open(ksName).viewManager.reload();
+        MigrationManager.instance.notifyDropView(view);
+
+        CommitLog.instance.forceRecycleAllSegments(Collections.singleton(view.metadata.cfId));
+    }
+
     public void addType(UserType ut)
     {
         update(ut.keyspace, ks -> ks.withSwapped(ks.types.with(ut)));

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/src/java/org/apache/cassandra/config/ViewDefinition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/ViewDefinition.java b/src/java/org/apache/cassandra/config/ViewDefinition.java
new file mode 100644
index 0000000..39695b9
--- /dev/null
+++ b/src/java/org/apache/cassandra/config/ViewDefinition.java
@@ -0,0 +1,114 @@
+/*
+ * 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.config;
+
+import java.util.Objects;
+import java.util.UUID;
+
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+import org.apache.cassandra.cql3.ColumnIdentifier;
+
+public class ViewDefinition
+{
+    public final String ksName;
+    public final String viewName;
+    public final UUID baseTableId;
+    public final boolean includeAllColumns;
+    // The order of partititon columns and clustering columns is important, so we cannot switch these two to sets
+    public final CFMetaData metadata;
+
+    public ViewDefinition(ViewDefinition def)
+    {
+        this(def.ksName, def.viewName, def.baseTableId, def.includeAllColumns, def.metadata);
+    }
+
+    /**
+     * @param viewName          Name of the view
+     * @param baseTableId       Internal ID of the table which this view is based off of
+     * @param includeAllColumns Whether to include all columns or not
+     */
+    public ViewDefinition(String ksName, String viewName, UUID baseTableId, boolean includeAllColumns, CFMetaData metadata)
+    {
+        this.ksName = ksName;
+        this.viewName = viewName;
+        this.baseTableId = baseTableId;
+        this.includeAllColumns = includeAllColumns;
+        this.metadata = metadata;
+    }
+
+    /**
+     * @return true if the view specified by this definition will include the column, false otherwise
+     */
+    public boolean includes(ColumnIdentifier column)
+    {
+        return metadata.getColumnDefinition(column) != null;
+    }
+
+    public ViewDefinition copy()
+    {
+        return new ViewDefinition(ksName, viewName, baseTableId, includeAllColumns, metadata.copy());
+    }
+
+    public CFMetaData baseTableMetadata()
+    {
+        return Schema.instance.getCFMetaData(baseTableId);
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+            return true;
+
+        if (!(o instanceof ViewDefinition))
+            return false;
+
+        ViewDefinition other = (ViewDefinition) o;
+        return Objects.equals(ksName, other.ksName)
+               && Objects.equals(viewName, other.viewName)
+               && Objects.equals(baseTableId, other.baseTableId)
+               && Objects.equals(includeAllColumns, other.includeAllColumns)
+               && Objects.equals(metadata, other.metadata);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return new HashCodeBuilder(29, 1597)
+               .append(ksName)
+               .append(viewName)
+               .append(baseTableId)
+               .append(includeAllColumns)
+               .append(metadata)
+               .toHashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return new ToStringBuilder(this)
+               .append("ksName", ksName)
+               .append("viewName", viewName)
+               .append("baseTableId", baseTableId)
+               .append("includeAllColumns", includeAllColumns)
+               .append("metadata", metadata)
+               .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/src/java/org/apache/cassandra/cql3/Cql.g
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Cql.g b/src/java/org/apache/cassandra/cql3/Cql.g
index 87bec4b..f6d54f5 100644
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -740,7 +740,7 @@ indexIdent returns [IndexTarget.Raw id]
  *  PRIMARY KEY (<pkColumns>)
  *  WITH <property> = <value> AND ...;
  */
-createMaterializedViewStatement returns [CreateMaterializedViewStatement expr]
+createMaterializedViewStatement returns [CreateViewStatement expr]
     @init {
         boolean ifNotExists = false;
         List<ColumnIdentifier.Raw> partitionKeys = new ArrayList<>();
@@ -753,7 +753,7 @@ createMaterializedViewStatement returns [CreateMaterializedViewStatement expr]
         '(' '(' k1=cident { partitionKeys.add(k1); } ( ',' kn=cident { partitionKeys.add(kn); } )* ')' ( ',' c1=cident { compositeKeys.add(c1); } )* ')'
     |   '(' k1=cident { partitionKeys.add(k1); } ( ',' cn=cident { compositeKeys.add(cn); } )* ')'
         )
-        { $expr = new CreateMaterializedViewStatement(cf, basecf, sclause, wclause, partitionKeys, compositeKeys, ifNotExists); }
+        { $expr = new CreateViewStatement(cf, basecf, sclause, wclause, partitionKeys, compositeKeys, ifNotExists); }
         ( K_WITH cfamProperty[expr.properties] ( K_AND cfamProperty[expr.properties] )*)?
     ;
 
@@ -820,14 +820,14 @@ alterTableStatement returns [AlterTableStatement expr]
     }
     ;
 
-alterMaterializedViewStatement returns [AlterMaterializedViewStatement expr]
+alterMaterializedViewStatement returns [AlterViewStatement expr]
     @init {
         TableAttributes attrs = new TableAttributes();
     }
     : K_ALTER K_MATERIALIZED K_VIEW name=columnFamilyName
           K_WITH properties[attrs]
     {
-        $expr = new AlterMaterializedViewStatement(name, attrs);
+        $expr = new AlterViewStatement(name, attrs);
     }
     ;
     
@@ -886,10 +886,10 @@ dropIndexStatement returns [DropIndexStatement expr]
 /**
  * DROP MATERIALIZED VIEW [IF EXISTS] <view_name>
  */
-dropMaterializedViewStatement returns [DropMaterializedViewStatement expr]
+dropMaterializedViewStatement returns [DropViewStatement expr]
     @init { boolean ifExists = false; }
     : K_DROP K_MATERIALIZED K_VIEW (K_IF K_EXISTS { ifExists = true; } )? cf=columnFamilyName
-      { $expr = new DropMaterializedViewStatement(cf, ifExists); }
+      { $expr = new DropViewStatement(cf, ifExists); }
     ;
 
 /**

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

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
index fac0c53..af9a75c 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
@@ -19,6 +19,8 @@ package org.apache.cassandra.cql3.statements;
 
 import java.util.*;
 
+import com.google.common.collect.Iterables;
+
 import org.apache.cassandra.auth.Permission;
 import org.apache.cassandra.config.*;
 import org.apache.cassandra.cql3.CFName;
@@ -27,6 +29,7 @@ import org.apache.cassandra.cql3.ColumnIdentifier;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.CollectionType;
 import org.apache.cassandra.db.marshal.CounterColumnType;
+import org.apache.cassandra.db.view.View;
 import org.apache.cassandra.exceptions.*;
 import org.apache.cassandra.schema.IndexMetadata;
 import org.apache.cassandra.schema.Indexes;
@@ -81,7 +84,7 @@ public class AlterTableStatement extends SchemaAlteringStatement
     public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
     {
         CFMetaData meta = validateColumnFamily(keyspace(), columnFamily());
-        if (meta.isMaterializedView())
+        if (meta.isView())
             throw new InvalidRequestException("Cannot use ALTER TABLE on Materialized View");
 
         CFMetaData cfm = meta.copy();
@@ -95,7 +98,8 @@ public class AlterTableStatement extends SchemaAlteringStatement
             def = cfm.getColumnDefinition(columnName);
         }
 
-        List<CFMetaData> materializedViewUpdates = null;
+        List<ViewDefinition> viewUpdates = null;
+        Iterable<ViewDefinition> views = View.findAll(keyspace(), columnFamily());
 
         switch (oType)
         {
@@ -156,19 +160,20 @@ public class AlterTableStatement extends SchemaAlteringStatement
                                         ? ColumnDefinition.staticDef(cfm, columnName.bytes, type)
                                         : ColumnDefinition.regularDef(cfm, columnName.bytes, type));
 
-                // Adding a column to a table which has an include all materialized view requires the column to be added
-                // to the materialized view as well
-                for (MaterializedViewDefinition mv : cfm.getMaterializedViews())
+                // Adding a column to a table which has an include all view requires the column to be added to the view
+                // as well
+                if (!isStatic)
                 {
-                    if (mv.includeAll)
+                    for (ViewDefinition view : views)
                     {
-                        CFMetaData indexCfm = Schema.instance.getCFMetaData(keyspace(), mv.viewName).copy();
-                        indexCfm.addColumnDefinition(isStatic
-                                                     ? ColumnDefinition.staticDef(indexCfm, columnName.bytes, type)
-                                                     : ColumnDefinition.regularDef(indexCfm, columnName.bytes, type));
-                        if (materializedViewUpdates == null)
-                            materializedViewUpdates = new ArrayList<>();
-                        materializedViewUpdates.add(indexCfm);
+                        if (view.includeAllColumns)
+                        {
+                            ViewDefinition viewCopy = view.copy();
+                            viewCopy.metadata.addColumnDefinition(ColumnDefinition.regularDef(viewCopy.metadata, columnName.bytes, type));
+                            if (viewUpdates == null)
+                                viewUpdates = new ArrayList<>();
+                            viewUpdates.add(viewCopy);
+                        }
                     }
                 }
                 break;
@@ -221,17 +226,16 @@ public class AlterTableStatement extends SchemaAlteringStatement
                 // In any case, we update the column definition
                 cfm.addOrReplaceColumnDefinition(def.withNewType(validatorType));
 
-                // We have to alter the schema of the materialized view table as well; it doesn't affect the definition however
-                for (MaterializedViewDefinition mv : cfm.getMaterializedViews())
+                // We have to alter the schema of the view table as well; it doesn't affect the definition however
+                for (ViewDefinition view : views)
                 {
-                    if (!mv.includes(columnName)) continue;
-                    // We have to use the pre-adjusted CFM, otherwise we can't resolve the Index
-                    CFMetaData indexCfm = Schema.instance.getCFMetaData(keyspace(), mv.viewName).copy();
-                    indexCfm.addOrReplaceColumnDefinition(def.withNewType(validatorType));
-
-                    if (materializedViewUpdates == null)
-                        materializedViewUpdates = new ArrayList<>();
-                    materializedViewUpdates.add(indexCfm);
+                    if (!view.includes(columnName)) continue;
+                    ViewDefinition viewCopy = view.copy();
+                    viewCopy.metadata.addOrReplaceColumnDefinition(def.withNewType(validatorType));
+
+                    if (viewUpdates == null)
+                        viewUpdates = new ArrayList<>();
+                    viewUpdates.add(viewCopy);
                 }
                 break;
 
@@ -276,20 +280,16 @@ public class AlterTableStatement extends SchemaAlteringStatement
                 }
                 cfm.indexes(allIndexes);
 
-                // If a column is dropped which is the target of a materialized view,
-                // then we need to drop the view.
-                // If a column is dropped which was selected into a materialized view,
-                // we need to drop that column from the included materialzied view table
-                // and definition.
+                // If a column is dropped which is included in a view, we don't allow the drop to take place.
                 boolean rejectAlter = false;
                 StringBuilder builder = new StringBuilder();
-                for (MaterializedViewDefinition mv : cfm.getMaterializedViews())
+                for (ViewDefinition view : views)
                 {
-                    if (!mv.includes(columnName)) continue;
+                    if (!view.includes(columnName)) continue;
                     if (rejectAlter)
                         builder.append(',');
                     rejectAlter = true;
-                    builder.append(mv.viewName);
+                    builder.append(view.viewName);
                 }
                 if (rejectAlter)
                     throw new InvalidRequestException(String.format("Cannot drop column %s, depended on by materialized views (%s.{%s})",
@@ -304,7 +304,7 @@ public class AlterTableStatement extends SchemaAlteringStatement
 
                 TableParams params = attrs.asAlteredTableParams(cfm.params);
 
-                if (cfm.hasMaterializedViews() && params.gcGraceSeconds == 0)
+                if (!Iterables.isEmpty(views) && params.gcGraceSeconds == 0)
                 {
                     throw new InvalidRequestException("Cannot alter gc_grace_seconds of the base table of a " +
                                                       "materialized view to 0, since this value is used to TTL " +
@@ -326,36 +326,31 @@ public class AlterTableStatement extends SchemaAlteringStatement
                     ColumnIdentifier to = entry.getValue().prepare(cfm);
                     cfm.renameColumn(from, to);
 
-                    // If the materialized view includes a renamed column, it must be renamed in the index table and the definition.
-                    for (MaterializedViewDefinition mv : cfm.getMaterializedViews())
+                    // If the view includes a renamed column, it must be renamed in the view table and the definition.
+                    for (ViewDefinition view : views)
                     {
-                        if (!mv.includes(from)) continue;
-
-                        CFMetaData indexCfm = Schema.instance.getCFMetaData(keyspace(), mv.viewName).copy();
-                        ColumnIdentifier indexFrom = entry.getKey().prepare(indexCfm);
-                        ColumnIdentifier indexTo = entry.getValue().prepare(indexCfm);
-                        indexCfm.renameColumn(indexFrom, indexTo);
+                        if (!view.includes(from)) continue;
 
-                        MaterializedViewDefinition mvCopy = new MaterializedViewDefinition(mv);
-                        mvCopy.renameColumn(from, to);
+                        ViewDefinition viewCopy = view.copy();
+                        ColumnIdentifier viewFrom = entry.getKey().prepare(viewCopy.metadata);
+                        ColumnIdentifier viewTo = entry.getValue().prepare(viewCopy.metadata);
+                        viewCopy.metadata.renameColumn(viewFrom, viewTo);
 
-                        cfm.materializedViews(cfm.getMaterializedViews().replace(mvCopy));
-
-                        if (materializedViewUpdates == null)
-                            materializedViewUpdates = new ArrayList<>();
-                        materializedViewUpdates.add(indexCfm);
+                        if (viewUpdates == null)
+                            viewUpdates = new ArrayList<>();
+                        viewUpdates.add(viewCopy);
                     }
                 }
                 break;
         }
 
-        if (materializedViewUpdates != null)
+        MigrationManager.announceColumnFamilyUpdate(cfm, false, isLocalOnly);
+
+        if (viewUpdates != null)
         {
-            for (CFMetaData mvUpdates : materializedViewUpdates)
-                MigrationManager.announceColumnFamilyUpdate(mvUpdates, false, isLocalOnly);
+            for (ViewDefinition viewUpdate : viewUpdates)
+                MigrationManager.announceViewUpdate(viewUpdate, isLocalOnly);
         }
-
-        MigrationManager.announceColumnFamilyUpdate(cfm, false, isLocalOnly);
         return true;
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java b/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
index 4298c22..e176cec 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
@@ -115,6 +115,16 @@ public abstract class AlterTypeStatement extends SchemaAlteringStatement
                 MigrationManager.announceColumnFamilyUpdate(copy, false, isLocalOnly);
         }
 
+        for (ViewDefinition view : ksm.views)
+        {
+            ViewDefinition copy = view.copy();
+            boolean modified = false;
+            for (ColumnDefinition def : copy.metadata.allColumns())
+                modified |= updateDefinition(copy.metadata, def, toUpdate.keyspace, toUpdate.name, updated);
+            if (modified)
+                MigrationManager.announceViewUpdate(copy, isLocalOnly);
+        }
+
         // Other user types potentially using the updated type
         for (UserType ut : ksm.types)
         {

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

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/src/java/org/apache/cassandra/cql3/statements/CreateMaterializedViewStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateMaterializedViewStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateMaterializedViewStatement.java
deleted file mode 100644
index dee0577..0000000
--- a/src/java/org/apache/cassandra/cql3/statements/CreateMaterializedViewStatement.java
+++ /dev/null
@@ -1,286 +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 java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import com.google.common.collect.Iterables;
-
-import org.apache.cassandra.auth.Permission;
-import org.apache.cassandra.config.CFMetaData;
-import org.apache.cassandra.config.ColumnDefinition;
-import org.apache.cassandra.config.MaterializedViewDefinition;
-import org.apache.cassandra.cql3.CFName;
-import org.apache.cassandra.cql3.ColumnIdentifier;
-import org.apache.cassandra.cql3.selection.RawSelector;
-import org.apache.cassandra.cql3.selection.Selectable;
-import org.apache.cassandra.db.view.MaterializedView;
-import org.apache.cassandra.exceptions.AlreadyExistsException;
-import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.exceptions.RequestValidationException;
-import org.apache.cassandra.exceptions.UnauthorizedException;
-import org.apache.cassandra.service.ClientState;
-import org.apache.cassandra.service.ClientWarn;
-import org.apache.cassandra.service.MigrationManager;
-import org.apache.cassandra.thrift.ThriftValidation;
-import org.apache.cassandra.transport.Event;
-
-public class CreateMaterializedViewStatement extends SchemaAlteringStatement
-{
-    private final CFName baseName;
-    private final List<RawSelector> selectClause;
-    private final List<ColumnIdentifier.Raw> notNullWhereClause;
-    private final List<ColumnIdentifier.Raw> partitionKeys;
-    private final List<ColumnIdentifier.Raw> clusteringKeys;
-    public final CFProperties properties = new CFProperties();
-    private final boolean ifNotExists;
-
-    public CreateMaterializedViewStatement(CFName viewName,
-                                           CFName baseName,
-                                           List<RawSelector> selectClause,
-                                           List<ColumnIdentifier.Raw> notNullWhereClause,
-                                           List<ColumnIdentifier.Raw> partitionKeys,
-                                           List<ColumnIdentifier.Raw> clusteringKeys,
-                                           boolean ifNotExists)
-    {
-        super(viewName);
-        this.baseName = baseName;
-        this.selectClause = selectClause;
-        this.notNullWhereClause = notNullWhereClause;
-        this.partitionKeys = partitionKeys;
-        this.clusteringKeys = clusteringKeys;
-        this.ifNotExists = ifNotExists;
-    }
-
-
-    public void checkAccess(ClientState state) throws UnauthorizedException, InvalidRequestException
-    {
-        if (!baseName.hasKeyspace())
-            baseName.setKeyspace(keyspace(), true);
-        state.hasColumnFamilyAccess(keyspace(), baseName.getColumnFamily(), Permission.ALTER);
-    }
-
-    public void validate(ClientState state) throws RequestValidationException
-    {
-        // We do validation in announceMigration to reduce doubling up of work
-    }
-
-    public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
-    {
-        // We need to make sure that:
-        //  - primary key includes all columns in base table's primary key
-        //  - make sure that the select statement does not have anything other than columns
-        //    and their names match the base table's names
-        //  - make sure that primary key does not include any collections
-        //  - make sure there is no where clause in the select statement
-        //  - make sure there is not currently a table or view
-        //  - make sure baseTable gcGraceSeconds > 0
-
-        properties.validate();
-
-        if (properties.useCompactStorage)
-            throw new InvalidRequestException("Cannot use 'COMPACT STORAGE' when defining a materialized view");
-
-        // We enforce the keyspace because if the RF is different, the logic to wait for a
-        // specific replica would break
-        if (!baseName.getKeyspace().equals(keyspace()))
-            throw new InvalidRequestException("Cannot create a materialized view on a table in a separate keyspace");
-
-        CFMetaData cfm = ThriftValidation.validateColumnFamily(baseName.getKeyspace(), baseName.getColumnFamily());
-
-        if (cfm.isCounter())
-            throw new InvalidRequestException("Materialized views are not supported on counter tables");
-
-        if (cfm.isMaterializedView())
-            throw new InvalidRequestException("Materialized views cannot be created against other materialized views");
-
-        if (cfm.params.gcGraceSeconds == 0)
-        {
-            throw new InvalidRequestException(String.format("Cannot create materialized view '%s' for base table " +
-                                                            "'%s' with gc_grace_seconds of 0, since this value is " +
-                                                            "used to TTL undelivered updates. Setting gc_grace_seconds" +
-                                                            " too low might cause undelivered updates to expire " +
-                                                            "before being replayed.", cfName.getColumnFamily(),
-                                                            baseName.getColumnFamily()));
-        }
-
-        Set<ColumnIdentifier> included = new HashSet<>();
-        for (RawSelector selector : selectClause)
-        {
-            Selectable.Raw selectable = selector.selectable;
-            if (selectable instanceof Selectable.WithFieldSelection.Raw)
-                throw new InvalidRequestException("Cannot select out a part of type when defining a materialized view");
-            if (selectable instanceof Selectable.WithFunction.Raw)
-                throw new InvalidRequestException("Cannot use function when defining a materialized view");
-            if (selectable instanceof Selectable.WritetimeOrTTL.Raw)
-                throw new InvalidRequestException("Cannot use function when defining a materialized view");
-            ColumnIdentifier identifier = (ColumnIdentifier) selectable.prepare(cfm);
-            if (selector.alias != null)
-                throw new InvalidRequestException(String.format("Cannot alias column '%s' as '%s' when defining a materialized view", identifier.toString(), selector.alias.toString()));
-
-            ColumnDefinition cdef = cfm.getColumnDefinition(identifier);
-
-            if (cdef == null)
-                throw new InvalidRequestException("Unknown column name detected in CREATE MATERIALIZED VIEW statement : "+identifier);
-
-            if (cdef.isStatic())
-                ClientWarn.warn(String.format("Unable to include static column '%s' in Materialized View SELECT statement", identifier));
-            else
-                included.add(identifier);
-        }
-
-        Set<ColumnIdentifier.Raw> targetPrimaryKeys = new HashSet<>();
-        for (ColumnIdentifier.Raw identifier : Iterables.concat(partitionKeys, clusteringKeys))
-        {
-            if (!targetPrimaryKeys.add(identifier))
-                throw new InvalidRequestException("Duplicate entry found in PRIMARY KEY: "+identifier);
-
-            ColumnDefinition cdef = cfm.getColumnDefinition(identifier.prepare(cfm));
-
-            if (cdef == null)
-                throw new InvalidRequestException("Unknown column name detected in CREATE MATERIALIZED VIEW statement : "+identifier);
-
-            if (cfm.getColumnDefinition(identifier.prepare(cfm)).type.isMultiCell())
-                throw new InvalidRequestException(String.format("Cannot use MultiCell column '%s' in PRIMARY KEY of materialized view", identifier));
-
-            if (cdef.isStatic())
-                throw new InvalidRequestException(String.format("Cannot use Static column '%s' in PRIMARY KEY of materialized view", identifier));
-        }
-
-        Set<ColumnIdentifier> basePrimaryKeyCols = new HashSet<>();
-        for (ColumnDefinition definition : Iterables.concat(cfm.partitionKeyColumns(), cfm.clusteringColumns()))
-            basePrimaryKeyCols.add(definition.name);
-
-        List<ColumnIdentifier> targetClusteringColumns = new ArrayList<>();
-        List<ColumnIdentifier> targetPartitionKeys = new ArrayList<>();
-        Set<ColumnIdentifier> notNullColumns = new HashSet<>();
-        if (notNullWhereClause != null)
-        {
-            for (ColumnIdentifier.Raw raw : notNullWhereClause)
-            {
-                notNullColumns.add(raw.prepare(cfm));
-            }
-        }
-
-        // This is only used as an intermediate state; this is to catch whether multiple non-PK columns are used
-        boolean hasNonPKColumn = false;
-        for (ColumnIdentifier.Raw raw : partitionKeys)
-        {
-            hasNonPKColumn = getColumnIdentifier(cfm, basePrimaryKeyCols, hasNonPKColumn, raw, targetPartitionKeys, notNullColumns);
-        }
-
-        for (ColumnIdentifier.Raw raw : clusteringKeys)
-        {
-            hasNonPKColumn = getColumnIdentifier(cfm, basePrimaryKeyCols, hasNonPKColumn, raw, targetClusteringColumns, notNullColumns);
-        }
-
-        // We need to include all of the primary key colums from the base table in order to make sure that we do not
-        // overwrite values in the materialized view. We cannot support "collapsing" the base table into a smaller
-        // number of rows in the view because if we need to generate a tombstone, we have no way of knowing which value
-        // is currently being used in the view and whether or not to generate a tombstone.
-        // In order to not surprise our users, we require that they include all of the columns. We provide them with
-        // a list of all of the columns left to include.
-        boolean missingClusteringColumns = false;
-        StringBuilder columnNames = new StringBuilder();
-        for (ColumnDefinition def : cfm.allColumns())
-        {
-            if (!def.isPrimaryKeyColumn()) continue;
-
-            ColumnIdentifier identifier = def.name;
-            if (!targetClusteringColumns.contains(identifier) && !targetPartitionKeys.contains(identifier))
-            {
-                if (missingClusteringColumns)
-                    columnNames.append(',');
-                else
-                    missingClusteringColumns = true;
-                columnNames.append(identifier);
-            }
-        }
-        if (missingClusteringColumns)
-            throw new InvalidRequestException(String.format("Cannot create Materialized View %s without primary key columns from base %s (%s)",
-                                                            columnFamily(), baseName.getColumnFamily(), columnNames.toString()));
-
-        if (targetPartitionKeys.isEmpty())
-            throw new InvalidRequestException("Must select at least a column for a Materialized View");
-
-        if (targetClusteringColumns.isEmpty())
-            throw new InvalidRequestException("No columns are defined for Materialized View other than primary key");
-
-        MaterializedViewDefinition definition = new MaterializedViewDefinition(baseName.getColumnFamily(),
-                                                                               columnFamily(),
-                                                                               targetPartitionKeys,
-                                                                               targetClusteringColumns,
-                                                                               included);
-
-        CFMetaData indexCf = MaterializedView.getCFMetaData(definition, cfm, properties);
-        try
-        {
-            MigrationManager.announceNewColumnFamily(indexCf, isLocalOnly);
-        }
-        catch (AlreadyExistsException e)
-        {
-            if (ifNotExists)
-                return false;
-            throw e;
-        }
-
-        CFMetaData newCfm = cfm.copy();
-        newCfm.materializedViews(newCfm.getMaterializedViews().with(definition));
-
-        MigrationManager.announceColumnFamilyUpdate(newCfm, false, isLocalOnly);
-
-        return true;
-    }
-
-    private static boolean getColumnIdentifier(CFMetaData cfm,
-                                               Set<ColumnIdentifier> basePK,
-                                               boolean hasNonPKColumn,
-                                               ColumnIdentifier.Raw raw,
-                                               List<ColumnIdentifier> columns,
-                                               Set<ColumnIdentifier> allowedPKColumns)
-    {
-        ColumnIdentifier identifier = raw.prepare(cfm);
-
-        boolean isPk = basePK.contains(identifier);
-        if (!isPk && hasNonPKColumn)
-        {
-            throw new InvalidRequestException(String.format("Cannot include more than one non-primary key column '%s' in materialized view partition key", identifier));
-        }
-
-        // We don't need to include the "IS NOT NULL" filter on a non-composite partition key
-        // because we will never allow a single partition key to be NULL
-        boolean isSinglePartitionKey = cfm.getColumnDefinition(identifier).isPartitionKey()
-                                       && cfm.partitionKeyColumns().size() == 1;
-        if (!allowedPKColumns.remove(identifier) && !isSinglePartitionKey)
-        {
-            throw new InvalidRequestException(String.format("Primary key column '%s' is required to be filtered by 'IS NOT NULL'", identifier));
-        }
-
-        columns.add(identifier);
-        return !isPk;
-    }
-
-    public Event.SchemaChange changeEvent()
-    {
-        return new Event.SchemaChange(Event.SchemaChange.Change.CREATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
-    }
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3a8dbca/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
index 706cfea..2589622 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
@@ -59,7 +59,7 @@ public class CreateTriggerStatement extends SchemaAlteringStatement
     public void validate(ClientState state) throws RequestValidationException
     {
         CFMetaData cfm = ThriftValidation.validateColumnFamily(keyspace(), columnFamily());
-        if (cfm.isMaterializedView())
+        if (cfm.isView())
             throw new InvalidRequestException("Cannot CREATE TRIGGER against a materialized view");
 
         try