You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ty...@apache.org on 2014/08/21 21:23:29 UTC

[1/4] git commit: Don't send schema change msg for no-op DDL stmts

Repository: cassandra
Updated Branches:
  refs/heads/cassandra-2.1 d088f0299 -> edbd7d392


Don't send schema change msg for no-op DDL stmts

Patch by Tyler Hobbs; review by Mikhail Stepura for CASSANDRA-7600


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

Branch: refs/heads/cassandra-2.1
Commit: e4d5edae72838533445efadc001d2b6b656fd0ce
Parents: fe39eb7
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Thu Aug 21 14:18:40 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Thu Aug 21 14:20:15 2014 -0500

----------------------------------------------------------------------
 CHANGES.txt                                          |  2 ++
 .../cql3/statements/AlterKeyspaceStatement.java      |  3 ++-
 .../cql3/statements/AlterTableStatement.java         |  3 ++-
 .../cql3/statements/CreateIndexStatement.java        |  5 +++--
 .../cql3/statements/CreateKeyspaceStatement.java     |  8 +++++---
 .../cql3/statements/CreateTableStatement.java        | 10 ++++++----
 .../cql3/statements/CreateTriggerStatement.java      |  3 ++-
 .../cql3/statements/DropIndexStatement.java          |  5 +++--
 .../cql3/statements/DropKeyspaceStatement.java       |  8 +++++---
 .../cql3/statements/DropTableStatement.java          |  8 +++++---
 .../cql3/statements/DropTriggerStatement.java        |  3 ++-
 .../cql3/statements/SchemaAlteringStatement.java     | 15 +++++++++++++--
 12 files changed, 50 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 71cfca0..9aeeb29 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,6 @@
 2.0.10
+ * Don't send schema change responses and events for no-op DDL
+   statements (CASSANDRA-7600)
  * (Hadoop) fix cluster initialisation for a split fetching (CASSANDRA-7774)
  * Configure system.paxos with LeveledCompactionStrategy (CASSANDRA-7753)
  * Fix ALTER clustering column type from DateType to TimestampType when

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java b/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
index 39d1cde..4f6d1f2 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
@@ -79,7 +79,7 @@ public class AlterKeyspaceStatement extends SchemaAlteringStatement
         }
     }
 
-    public void announceMigration() throws RequestValidationException
+    public boolean announceMigration() throws RequestValidationException
     {
         KSMetaData ksm = Schema.instance.getKSMetaData(name);
         // In the (very) unlikely case the keyspace was dropped since validate()
@@ -87,6 +87,7 @@ public class AlterKeyspaceStatement extends SchemaAlteringStatement
             throw new InvalidRequestException("Unknown keyspace " + name);
 
         MigrationManager.announceKeyspaceUpdate(attrs.asKSMetadataUpdate(ksm));
+        return true;
     }
 
     public ResultMessage.SchemaChange.Change changeType()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/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 136c430..dfcd601 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
@@ -76,7 +76,7 @@ public class AlterTableStatement extends SchemaAlteringStatement
         // validated in announceMigration()
     }
 
-    public void announceMigration() throws RequestValidationException
+    public boolean announceMigration() throws RequestValidationException
     {
         CFMetaData meta = validateColumnFamily(keyspace(), columnFamily());
         CFMetaData cfm = meta.clone();
@@ -266,6 +266,7 @@ public class AlterTableStatement extends SchemaAlteringStatement
         }
 
         MigrationManager.announceColumnFamilyUpdate(cfm, false);
+        return true;
     }
 
     public String toString()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
index 376fa4a..8b40978 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
@@ -103,14 +103,14 @@ public class CreateIndexStatement extends SchemaAlteringStatement
             throw new InvalidRequestException(String.format("Cannot add secondary index to already primarily indexed column %s", columnName));
     }
 
-    public void announceMigration() throws RequestValidationException
+    public boolean announceMigration() throws RequestValidationException
     {
         logger.debug("Updating column {} definition for index {}", columnName, indexName);
         CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
         ColumnDefinition cd = cfm.getColumnDefinition(columnName.key);
 
         if (cd.getIndexType() != null && ifNotExists)
-            return;
+            return false;
 
         if (properties.isCustom)
             cd.setIndexType(IndexType.CUSTOM, properties.getOptions());
@@ -122,6 +122,7 @@ public class CreateIndexStatement extends SchemaAlteringStatement
         cd.setIndexName(indexName);
         cfm.addDefaultIndexNames();
         MigrationManager.announceColumnFamilyUpdate(cfm, false);
+        return true;
     }
 
     public ResultMessage.SchemaChange.Change changeType()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
index 2ed1d91..7a8473a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
@@ -97,16 +97,18 @@ public class CreateKeyspaceStatement extends SchemaAlteringStatement
                                                                 attrs.getReplicationOptions());
     }
 
-    public void announceMigration() throws RequestValidationException
+    public boolean announceMigration() throws RequestValidationException
     {
         try
         {
             MigrationManager.announceNewKeyspace(attrs.asKSMetadata(name));
+            return true;
         }
         catch (AlreadyExistsException e)
         {
-            if (!ifNotExists)
-                throw e;
+            if (ifNotExists)
+                return false;
+            throw e;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/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 08ad069..b7f43d3 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
@@ -114,16 +114,18 @@ public class CreateTableStatement extends SchemaAlteringStatement
         return columnDefs;
     }
 
-    public void announceMigration() throws RequestValidationException
+    public boolean announceMigration() throws RequestValidationException
     {
         try
         {
-           MigrationManager.announceNewColumnFamily(getCFMetaData());
+            MigrationManager.announceNewColumnFamily(getCFMetaData());
+            return true;
         }
         catch (AlreadyExistsException e)
         {
-            if (!ifNotExists)
-                throw e;
+            if (ifNotExists)
+                return false;
+            throw e;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/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 760d870..70b3acb 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
@@ -65,12 +65,13 @@ public class CreateTriggerStatement extends SchemaAlteringStatement
         }
     }
 
-    public void announceMigration() throws ConfigurationException
+    public boolean announceMigration() throws ConfigurationException
     {
         CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
         cfm.addTriggerDefinition(TriggerDefinition.create(triggerName, triggerClass));
         logger.info("Adding trigger with name {} and class {}", triggerName, triggerClass);
         MigrationManager.announceColumnFamilyUpdate(cfm, false);
+        return true;
     }
 
     public ResultMessage.SchemaChange.Change changeType()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
index c62ad47..ac5262e 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
@@ -60,14 +60,15 @@ public class DropIndexStatement extends SchemaAlteringStatement
         return ResultMessage.SchemaChange.Change.UPDATED;
     }
 
-    public void announceMigration() throws InvalidRequestException, ConfigurationException
+    public boolean announceMigration() throws InvalidRequestException, ConfigurationException
     {
         CFMetaData cfm = findIndexedCF();
         if (cfm == null)
-            return;
+            return false;
 
         CFMetaData updatedCfm = updateCFMetadata(cfm);
         MigrationManager.announceColumnFamilyUpdate(updatedCfm, false);
+        return true;
     }
 
     private CFMetaData updateCFMetadata(CFMetaData cfm)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
index 30fd964..7582af0 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
@@ -55,16 +55,18 @@ public class DropKeyspaceStatement extends SchemaAlteringStatement
         return keyspace;
     }
 
-    public void announceMigration() throws ConfigurationException
+    public boolean announceMigration() throws ConfigurationException
     {
         try
         {
             MigrationManager.announceKeyspaceDrop(keyspace);
+            return true;
         }
         catch(ConfigurationException e)
         {
-            if (!ifExists)
-                throw e;
+            if (ifExists)
+                return false;
+            throw e;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
index d27261c..65a3f14 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
@@ -54,16 +54,18 @@ public class DropTableStatement extends SchemaAlteringStatement
         // validated in announceMigration()
     }
 
-    public void announceMigration() throws ConfigurationException
+    public boolean announceMigration() throws ConfigurationException
     {
         try
         {
             MigrationManager.announceColumnFamilyDrop(keyspace(), columnFamily());
+            return true;
         }
         catch (ConfigurationException e)
         {
-            if (!ifExists)
-                throw e;
+            if (ifExists)
+                return false;
+            throw e;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
index ce17047..f0bd637 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
@@ -53,13 +53,14 @@ public class DropTriggerStatement extends SchemaAlteringStatement
         ThriftValidation.validateColumnFamily(keyspace(), columnFamily());
     }
 
-    public void announceMigration() throws ConfigurationException
+    public boolean announceMigration() throws ConfigurationException
     {
         CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
         if (!cfm.removeTrigger(triggerName))
             throw new ConfigurationException(String.format("Trigger %s was not found", triggerName));
         logger.info("Dropping trigger with name {}", triggerName);
         MigrationManager.announceColumnFamilyUpdate(cfm, false);
+        return true;
     }
 
     public ResultMessage.SchemaChange.Change changeType()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e4d5edae/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java b/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
index 94df854..845d8cc 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
@@ -64,11 +64,22 @@ public abstract class SchemaAlteringStatement extends CFStatement implements CQL
 
     public abstract ResultMessage.SchemaChange.Change changeType();
 
-    public abstract void announceMigration() throws RequestValidationException;
+    /**
+     * Announces the migration to other nodes in the cluster.
+     * @return true if the execution of this statement resulted in a schema change, false otherwise (when IF NOT EXISTS
+     * is used, for example)
+     * @throws RequestValidationException
+     */
+    public abstract boolean announceMigration() throws RequestValidationException;
 
     public ResultMessage execute(QueryState state, QueryOptions options) throws RequestValidationException
     {
-        announceMigration();
+        // If an IF [NOT] EXISTS clause was used, this may not result in an actual schema change.  To avoid doing
+        // extra work in the drivers to handle schema changes, we return an empty message in this case. (CASSANDRA-7600)
+        boolean didChangeSchema = announceMigration();
+        if (!didChangeSchema)
+            return new ResultMessage.Void();
+
         String tableName = cfName == null || columnFamily() == null ? "" : columnFamily();
         return new ResultMessage.SchemaChange(changeType(), keyspace(), tableName);
     }


[2/4] git commit: Merge branch 'cassandra-2.0' into cassandra-2.1.0

Posted by ty...@apache.org.
Merge branch 'cassandra-2.0' into cassandra-2.1.0


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

Branch: refs/heads/cassandra-2.1
Commit: a0923dbc0461352cc2f735dee8260b68f015063c
Parents: a41d527 e4d5eda
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Thu Aug 21 14:20:49 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Thu Aug 21 14:20:49 2014 -0500

----------------------------------------------------------------------

----------------------------------------------------------------------



[3/4] git commit: Merge branch 'cassandra-2.0' into cassandra-2.1

Posted by ty...@apache.org.
Merge branch 'cassandra-2.0' into cassandra-2.1


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

Branch: refs/heads/cassandra-2.1
Commit: 664efd41b037d17a7e2c991a9ad660c5d2ec2ce5
Parents: d088f02 e4d5eda
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Thu Aug 21 14:23:07 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Thu Aug 21 14:23:07 2014 -0500

----------------------------------------------------------------------
 CHANGES.txt                                       |  2 ++
 .../cql3/statements/AlterKeyspaceStatement.java   |  3 ++-
 .../cql3/statements/AlterTableStatement.java      |  3 ++-
 .../cql3/statements/AlterTypeStatement.java       |  3 ++-
 .../cql3/statements/CreateIndexStatement.java     |  5 +++--
 .../cql3/statements/CreateKeyspaceStatement.java  |  8 +++++---
 .../cql3/statements/CreateTableStatement.java     | 10 ++++++----
 .../cql3/statements/CreateTriggerStatement.java   |  3 ++-
 .../cql3/statements/CreateTypeStatement.java      |  5 +++--
 .../cql3/statements/DropIndexStatement.java       |  5 +++--
 .../cql3/statements/DropKeyspaceStatement.java    |  8 +++++---
 .../cql3/statements/DropTableStatement.java       |  8 +++++---
 .../cql3/statements/DropTriggerStatement.java     |  3 ++-
 .../cql3/statements/DropTypeStatement.java        |  9 ++++++---
 .../cql3/statements/SchemaAlteringStatement.java  | 18 +++++++++++++-----
 15 files changed, 61 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 701fd38,9aeeb29..80eb279
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,52 -1,7 +1,54 @@@
 -2.0.10
 +2.1.1
 + * (cqlsh) Order UDTs according to cross-type dependencies in DESCRIBE
 +   output (CASSANDRA-7659)
 + * (cqlsh) Fix handling of CAS statement results (CASSANDRA-7671)
 + * (cqlsh) COPY TO/FROM improvements (CASSANDRA-7405)
 + * Support list index operations with conditions (CASSANDRA-7499)
 + * Add max live/tombstoned cells to nodetool cfstats output (CASSANDRA-7731)
 + * Validate IPv6 wildcard addresses properly (CASSANDRA-7680)
 + * (cqlsh) Error when tracing query (CASSANDRA-7613)
 + * Avoid IOOBE when building SyntaxError message snippet (CASSANDRA-7569)
 + * SSTableExport uses correct validator to create string representation of partition
 +   keys (CASSANDRA-7498)
 + * Avoid NPEs when receiving type changes for an unknown keyspace (CASSANDRA-7689)
 + * Add support for custom 2i validation (CASSANDRA-7575)
 + * Pig support for hadoop CqlInputFormat (CASSANDRA-6454)
 + * Add listen_interface and rpc_interface options (CASSANDRA-7417)
 + * Improve schema merge performance (CASSANDRA-7444)
 + * Adjust MT depth based on # of partition validating (CASSANDRA-5263)
 + * Optimise NativeCell comparisons (CASSANDRA-6755)
 + * Configurable client timeout for cqlsh (CASSANDRA-7516)
 + * Include snippet of CQL query near syntax error in messages (CASSANDRA-7111)
 +Merged from 2.0:
+  * Don't send schema change responses and events for no-op DDL
+    statements (CASSANDRA-7600)
   * (Hadoop) fix cluster initialisation for a split fetching (CASSANDRA-7774)
 + * Throw InvalidRequestException when queries contain relations on entire
 +   collection columns (CASSANDRA-7506)
 + * (cqlsh) enable CTRL-R history search with libedit (CASSANDRA-7577)
 + * (Hadoop) allow ACFRW to limit nodes to local DC (CASSANDRA-7252)
 + * (cqlsh) cqlsh should automatically disable tracing when selecting
 +   from system_traces (CASSANDRA-7641)
 + * (Hadoop) Add CqlOutputFormat (CASSANDRA-6927)
 + * Don't depend on cassandra config for nodetool ring (CASSANDRA-7508)
 + * (cqlsh) Fix failing cqlsh formatting tests (CASSANDRA-7703)
 + * Fix IncompatibleClassChangeError from hadoop2 (CASSANDRA-7229)
 + * Add 'nodetool sethintedhandoffthrottlekb' (CASSANDRA-7635)
 + * (cqlsh) Add tab-completion for CREATE/DROP USER IF [NOT] EXISTS (CASSANDRA-7611)
 + * Catch errors when the JVM pulls the rug out from GCInspector (CASSANDRA-5345)
 + * cqlsh fails when version number parts are not int (CASSANDRA-7524)
 +Merged from 1.2:
 + * Improve PasswordAuthenticator default super user setup (CASSANDRA-7788)
 +
 +
 +2.1.0
 + * Correctly remove tmplink files (CASSANDRA-7803)
 + * (cqlsh) Fix column name formatting for functions, CAS operations,
 +   and UDT field selections (CASSANDRA-7806)
 + * (cqlsh) Fix COPY FROM handling of null/empty primary key
 +   values (CASSANDRA-7792)
 + * Fix ordering of static cells (CASSANDRA-7763)
 +Merged from 2.0:
   * Configure system.paxos with LeveledCompactionStrategy (CASSANDRA-7753)
   * Fix ALTER clustering column type from DateType to TimestampType when
     using DESC clustering order (CASSANRDA-7797)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
index 27cda49,4f6d1f2..e65a51e
--- a/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterKeyspaceStatement.java
@@@ -79,18 -79,19 +79,19 @@@ public class AlterKeyspaceStatement ext
          }
      }
  
-     public void announceMigration(boolean isLocalOnly) throws RequestValidationException
 -    public boolean announceMigration() throws RequestValidationException
++    public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
      {
          KSMetaData ksm = Schema.instance.getKSMetaData(name);
          // In the (very) unlikely case the keyspace was dropped since validate()
          if (ksm == null)
              throw new InvalidRequestException("Unknown keyspace " + name);
  
 -        MigrationManager.announceKeyspaceUpdate(attrs.asKSMetadataUpdate(ksm));
 +        MigrationManager.announceKeyspaceUpdate(attrs.asKSMetadataUpdate(ksm), isLocalOnly);
+         return true;
      }
  
 -    public ResultMessage.SchemaChange.Change changeType()
 +    public Event.SchemaChange changeEvent()
      {
 -        return ResultMessage.SchemaChange.Change.UPDATED;
 +        return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, keyspace());
      }
  }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
index be28943,dfcd601..3005ac7
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
@@@ -74,14 -76,13 +74,14 @@@ public class AlterTableStatement extend
          // validated in announceMigration()
      }
  
-     public void announceMigration(boolean isLocalOnly) throws RequestValidationException
 -    public boolean announceMigration() throws RequestValidationException
++    public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
      {
          CFMetaData meta = validateColumnFamily(keyspace(), columnFamily());
 -        CFMetaData cfm = meta.clone();
 +        CFMetaData cfm = meta.copy();
  
 -        CFDefinition cfDef = meta.getCfDef();
 -        CFDefinition.Name name = columnName == null ? null : cfDef.get(columnName);
 +        CQL3Type validator = this.validator == null ? null : this.validator.prepare(keyspace());
 +
 +        ColumnDefinition def = columnName == null ? null : cfm.getColumnDefinition(columnName);
          switch (oType)
          {
              case ADD:
@@@ -256,7 -265,8 +256,8 @@@
                  break;
          }
  
 -        MigrationManager.announceColumnFamilyUpdate(cfm, false);
 +        MigrationManager.announceColumnFamilyUpdate(cfm, false, isLocalOnly);
+         return true;
      }
  
      public String toString()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
index 94f7c87,0000000..cfdd65f
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java
@@@ -1,343 -1,0 +1,344 @@@
 +/*
 + * 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.nio.ByteBuffer;
 +import java.util.*;
 +
 +import org.apache.cassandra.auth.Permission;
 +import org.apache.cassandra.config.*;
 +import org.apache.cassandra.cql3.*;
 +import org.apache.cassandra.db.composites.CellNames;
 +import org.apache.cassandra.db.marshal.*;
 +import org.apache.cassandra.exceptions.*;
 +import org.apache.cassandra.service.ClientState;
 +import org.apache.cassandra.service.MigrationManager;
 +import org.apache.cassandra.transport.Event;
 +
 +public abstract class AlterTypeStatement extends SchemaAlteringStatement
 +{
 +    protected final UTName name;
 +
 +    protected AlterTypeStatement(UTName name)
 +    {
 +        super();
 +        this.name = name;
 +    }
 +
 +    @Override
 +    public void prepareKeyspace(ClientState state) throws InvalidRequestException
 +    {
 +        if (!name.hasKeyspace())
 +            name.setKeyspace(state.getKeyspace());
 +
 +        if (name.getKeyspace() == null)
 +            throw new InvalidRequestException("You need to be logged in a keyspace or use a fully qualified user type name");
 +    }
 +
 +    protected abstract UserType makeUpdatedType(UserType toUpdate) throws InvalidRequestException;
 +
 +    public static AlterTypeStatement addition(UTName name, ColumnIdentifier fieldName, CQL3Type.Raw type)
 +    {
 +        return new AddOrAlter(name, true, fieldName, type);
 +    }
 +
 +    public static AlterTypeStatement alter(UTName name, ColumnIdentifier fieldName, CQL3Type.Raw type)
 +    {
 +        return new AddOrAlter(name, false, fieldName, type);
 +    }
 +
 +    public static AlterTypeStatement renames(UTName name, Map<ColumnIdentifier, ColumnIdentifier> renames)
 +    {
 +        return new Renames(name, renames);
 +    }
 +
 +    public void checkAccess(ClientState state) throws UnauthorizedException, InvalidRequestException
 +    {
 +        state.hasKeyspaceAccess(keyspace(), Permission.ALTER);
 +    }
 +
 +    public void validate(ClientState state) throws RequestValidationException
 +    {
 +        // Validation is left to announceMigration as it's easier to do it while constructing the updated type.
 +        // It doesn't really change anything anyway.
 +    }
 +
 +    public Event.SchemaChange changeEvent()
 +    {
 +        return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TYPE, keyspace(), name.getStringTypeName());
 +    }
 +
 +    @Override
 +    public String keyspace()
 +    {
 +        return name.getKeyspace();
 +    }
 +
-     public void announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
++    public boolean announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
 +    {
 +        KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
 +        if (ksm == null)
 +            throw new InvalidRequestException(String.format("Cannot alter type in unknown keyspace %s", name.getKeyspace()));
 +
 +        UserType toUpdate = ksm.userTypes.getType(name.getUserTypeName());
 +        // Shouldn't happen, unless we race with a drop
 +        if (toUpdate == null)
 +            throw new InvalidRequestException(String.format("No user type named %s exists.", name));
 +
 +        UserType updated = makeUpdatedType(toUpdate);
 +
 +        // Now, we need to announce the type update to basically change it for new tables using this type,
 +        // but we also need to find all existing user types and CF using it and change them.
 +        MigrationManager.announceTypeUpdate(updated, isLocalOnly);
 +
 +        for (KSMetaData ksm2 : Schema.instance.getKeyspaceDefinitions())
 +        {
 +            for (CFMetaData cfm : ksm2.cfMetaData().values())
 +            {
 +                CFMetaData copy = cfm.copy();
 +                boolean modified = false;
 +                for (ColumnDefinition def : copy.allColumns())
 +                    modified |= updateDefinition(copy, def, toUpdate.keyspace, toUpdate.name, updated);
 +                if (modified)
 +                    MigrationManager.announceColumnFamilyUpdate(copy, false, isLocalOnly);
 +            }
 +
 +            // Other user types potentially using the updated type
 +            for (UserType ut : ksm2.userTypes.getAllTypes().values())
 +            {
 +                // Re-updating the type we've just updated would be harmless but useless so we avoid it.
 +                // Besides, we use the occasion to drop the old version of the type if it's a type rename
 +                if (ut.keyspace.equals(toUpdate.keyspace) && ut.name.equals(toUpdate.name))
 +                {
 +                    if (!ut.keyspace.equals(updated.keyspace) || !ut.name.equals(updated.name))
 +                        MigrationManager.announceTypeDrop(ut);
 +                    continue;
 +                }
 +                AbstractType<?> upd = updateWith(ut, toUpdate.keyspace, toUpdate.name, updated);
 +                if (upd != null)
 +                    MigrationManager.announceTypeUpdate((UserType)upd, isLocalOnly);
 +            }
 +        }
++        return true;
 +    }
 +
 +    private static int getIdxOfField(UserType type, ColumnIdentifier field)
 +    {
 +        for (int i = 0; i < type.size(); i++)
 +            if (field.bytes.equals(type.fieldName(i)))
 +                return i;
 +        return -1;
 +    }
 +
 +    private boolean updateDefinition(CFMetaData cfm, ColumnDefinition def, String keyspace, ByteBuffer toReplace, UserType updated)
 +    {
 +        AbstractType<?> t = updateWith(def.type, keyspace, toReplace, updated);
 +        if (t == null)
 +            return false;
 +
 +        // We need to update this validator ...
 +        cfm.addOrReplaceColumnDefinition(def.withNewType(t));
 +
 +        // ... but if it's part of the comparator or key validator, we need to go update those too.
 +        switch (def.kind)
 +        {
 +            case PARTITION_KEY:
 +                cfm.keyValidator(updateWith(cfm.getKeyValidator(), keyspace, toReplace, updated));
 +                break;
 +            case CLUSTERING_COLUMN:
 +                cfm.comparator = CellNames.fromAbstractType(updateWith(cfm.comparator.asAbstractType(), keyspace, toReplace, updated), cfm.comparator.isDense());
 +                break;
 +            default:
 +                // If it's a collection, we still want to modify the comparator because the collection is aliased in it
 +                if (def.type instanceof CollectionType)
 +                    cfm.comparator = CellNames.fromAbstractType(updateWith(cfm.comparator.asAbstractType(), keyspace, toReplace, updated), cfm.comparator.isDense());
 +        }
 +        return true;
 +    }
 +
 +    // Update the provided type were all instance of a given userType is replaced by a new version
 +    // Note that this methods reaches inside other UserType, CompositeType and CollectionType.
 +    private static AbstractType<?> updateWith(AbstractType<?> type, String keyspace, ByteBuffer toReplace, UserType updated)
 +    {
 +        if (type instanceof UserType)
 +        {
 +            UserType ut = (UserType)type;
 +
 +            // If it's directly the type we've updated, then just use the new one.
 +            if (keyspace.equals(ut.keyspace) && toReplace.equals(ut.name))
 +                return updated;
 +
 +            // Otherwise, check for nesting
 +            List<AbstractType<?>> updatedTypes = updateTypes(ut.fieldTypes(), keyspace, toReplace, updated);
 +            return updatedTypes == null ? null : new UserType(ut.keyspace, ut.name, new ArrayList<>(ut.fieldNames()), updatedTypes);
 +        }
 +        else if (type instanceof CompositeType)
 +        {
 +            CompositeType ct = (CompositeType)type;
 +            List<AbstractType<?>> updatedTypes = updateTypes(ct.types, keyspace, toReplace, updated);
 +            return updatedTypes == null ? null : CompositeType.getInstance(updatedTypes);
 +        }
 +        else if (type instanceof ColumnToCollectionType)
 +        {
 +            ColumnToCollectionType ctct = (ColumnToCollectionType)type;
 +            Map<ByteBuffer, CollectionType> updatedTypes = null;
 +            for (Map.Entry<ByteBuffer, CollectionType> entry : ctct.defined.entrySet())
 +            {
 +                AbstractType<?> t = updateWith(entry.getValue(), keyspace, toReplace, updated);
 +                if (t == null)
 +                    continue;
 +
 +                if (updatedTypes == null)
 +                    updatedTypes = new HashMap<>(ctct.defined);
 +
 +                updatedTypes.put(entry.getKey(), (CollectionType)t);
 +            }
 +            return updatedTypes == null ? null : ColumnToCollectionType.getInstance(updatedTypes);
 +        }
 +        else if (type instanceof CollectionType)
 +        {
 +            if (type instanceof ListType)
 +            {
 +                AbstractType<?> t = updateWith(((ListType)type).elements, keyspace, toReplace, updated);
 +                return t == null ? null : ListType.getInstance(t);
 +            }
 +            else if (type instanceof SetType)
 +            {
 +                AbstractType<?> t = updateWith(((SetType)type).elements, keyspace, toReplace, updated);
 +                return t == null ? null : SetType.getInstance(t);
 +            }
 +            else
 +            {
 +                assert type instanceof MapType;
 +                MapType mt = (MapType)type;
 +                AbstractType<?> k = updateWith(mt.keys, keyspace, toReplace, updated);
 +                AbstractType<?> v = updateWith(mt.values, keyspace, toReplace, updated);
 +                if (k == null && v == null)
 +                    return null;
 +                return MapType.getInstance(k == null ? mt.keys : k, v == null ? mt.values : v);
 +            }
 +        }
 +        else
 +        {
 +            return null;
 +        }
 +    }
 +
 +    private static List<AbstractType<?>> updateTypes(List<AbstractType<?>> toUpdate, String keyspace, ByteBuffer toReplace, UserType updated)
 +    {
 +        // But this can also be nested.
 +        List<AbstractType<?>> updatedTypes = null;
 +        for (int i = 0; i < toUpdate.size(); i++)
 +        {
 +            AbstractType<?> t = updateWith(toUpdate.get(i), keyspace, toReplace, updated);
 +            if (t == null)
 +                continue;
 +
 +            if (updatedTypes == null)
 +                updatedTypes = new ArrayList<>(toUpdate);
 +
 +            updatedTypes.set(i, t);
 +        }
 +        return updatedTypes;
 +    }
 +
 +    private static class AddOrAlter extends AlterTypeStatement
 +    {
 +        private final boolean isAdd;
 +        private final ColumnIdentifier fieldName;
 +        private final CQL3Type.Raw type;
 +
 +        public AddOrAlter(UTName name, boolean isAdd, ColumnIdentifier fieldName, CQL3Type.Raw type)
 +        {
 +            super(name);
 +            this.isAdd = isAdd;
 +            this.fieldName = fieldName;
 +            this.type = type;
 +        }
 +
 +        private UserType doAdd(UserType toUpdate) throws InvalidRequestException
 +        {
 +            if (getIdxOfField(toUpdate, fieldName) >= 0)
 +                throw new InvalidRequestException(String.format("Cannot add new field %s to type %s: a field of the same name already exists", fieldName, name));
 +
 +            List<ByteBuffer> newNames = new ArrayList<>(toUpdate.size() + 1);
 +            newNames.addAll(toUpdate.fieldNames());
 +            newNames.add(fieldName.bytes);
 +
 +            List<AbstractType<?>> newTypes = new ArrayList<>(toUpdate.size() + 1);
 +            newTypes.addAll(toUpdate.fieldTypes());
 +            newTypes.add(type.prepare(keyspace()).getType());
 +
 +            return new UserType(toUpdate.keyspace, toUpdate.name, newNames, newTypes);
 +        }
 +
 +        private UserType doAlter(UserType toUpdate) throws InvalidRequestException
 +        {
 +            int idx = getIdxOfField(toUpdate, fieldName);
 +            if (idx < 0)
 +                throw new InvalidRequestException(String.format("Unknown field %s in type %s", fieldName, name));
 +
 +            AbstractType<?> previous = toUpdate.fieldType(idx);
 +            if (!type.prepare(keyspace()).getType().isCompatibleWith(previous))
 +                throw new InvalidRequestException(String.format("Type %s is incompatible with previous type %s of field %s in user type %s", type, previous.asCQL3Type(), fieldName, name));
 +
 +            List<ByteBuffer> newNames = new ArrayList<>(toUpdate.fieldNames());
 +            List<AbstractType<?>> newTypes = new ArrayList<>(toUpdate.fieldTypes());
 +            newTypes.set(idx, type.prepare(keyspace()).getType());
 +
 +            return new UserType(toUpdate.keyspace, toUpdate.name, newNames, newTypes);
 +        }
 +
 +        protected UserType makeUpdatedType(UserType toUpdate) throws InvalidRequestException
 +        {
 +            return isAdd ? doAdd(toUpdate) : doAlter(toUpdate);
 +        }
 +    }
 +
 +    private static class Renames extends AlterTypeStatement
 +    {
 +        private final Map<ColumnIdentifier, ColumnIdentifier> renames;
 +
 +        public Renames(UTName name, Map<ColumnIdentifier, ColumnIdentifier> renames)
 +        {
 +            super(name);
 +            this.renames = renames;
 +        }
 +
 +        protected UserType makeUpdatedType(UserType toUpdate) throws InvalidRequestException
 +        {
 +            List<ByteBuffer> newNames = new ArrayList<>(toUpdate.fieldNames());
 +            List<AbstractType<?>> newTypes = new ArrayList<>(toUpdate.fieldTypes());
 +
 +            for (Map.Entry<ColumnIdentifier, ColumnIdentifier> entry : renames.entrySet())
 +            {
 +                ColumnIdentifier from = entry.getKey();
 +                ColumnIdentifier to = entry.getValue();
 +                int idx = getIdxOfField(toUpdate, from);
 +                if (idx < 0)
 +                    throw new InvalidRequestException(String.format("Unknown field %s in type %s", from, name));
 +                newNames.set(idx, to.bytes);
 +            }
 +
 +            UserType updated = new UserType(toUpdate.keyspace, toUpdate.name, newNames, newTypes);
 +            CreateTypeStatement.checkForDuplicateNames(updated);
 +            return updated;
 +        }
 +
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
index 3f2635f,8b40978..4809187
--- a/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
@@@ -110,49 -93,41 +110,50 @@@ public class CreateIndexStatement exten
          // would pull the full partition every time the static column of partition is 'bar', which sounds like offering a
          // fair potential for foot-shooting, so I prefer leaving that to a follow up ticket once we have identified cases where
          // such indexing is actually useful.
 -        if (cd.type == ColumnDefinition.Type.STATIC)
 +        if (cd.isStatic())
              throw new InvalidRequestException("Secondary indexes are not allowed on static columns");
  
 -        if (cd.getValidator().isCollection() && !properties.isCustom)
 -            throw new InvalidRequestException("Indexes on collections are no yet supported");
 -
 -        if (cd.type == ColumnDefinition.Type.PARTITION_KEY && cd.componentIndex == null)
 -            throw new InvalidRequestException(String.format("Cannot add secondary index to already primarily indexed column %s", columnName));
 +        if (cd.kind == ColumnDefinition.Kind.PARTITION_KEY && cd.isOnAllComponents())
 +            throw new InvalidRequestException(String.format("Cannot add secondary index to already primarily indexed column %s", target.column));
      }
  
-     public void announceMigration(boolean isLocalOnly) throws RequestValidationException
 -    public boolean announceMigration() throws RequestValidationException
++    public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
      {
 -        logger.debug("Updating column {} definition for index {}", columnName, indexName);
 -        CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
 -        ColumnDefinition cd = cfm.getColumnDefinition(columnName.key);
 +        logger.debug("Updating column {} definition for index {}", target.column, indexName);
 +        CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).copy();
 +        ColumnDefinition cd = cfm.getColumnDefinition(target.column);
  
          if (cd.getIndexType() != null && ifNotExists)
-             return;
+             return false;
  
          if (properties.isCustom)
 +        {
              cd.setIndexType(IndexType.CUSTOM, properties.getOptions());
 -        else if (cfm.getCfDef().isComposite)
 -            cd.setIndexType(IndexType.COMPOSITES, Collections.<String, String>emptyMap());
 +        }
 +        else if (cfm.comparator.isCompound())
 +        {
 +            Map<String, String> options = Collections.emptyMap();
 +            // For now, we only allow indexing values for collections, but we could later allow
 +            // to also index map keys, so we record that this is the values we index to make our
 +            // lives easier then.
 +            if (cd.type.isCollection())
 +                options = ImmutableMap.of(target.isCollectionKeys ? "index_keys" : "index_values", "");
 +            cd.setIndexType(IndexType.COMPOSITES, options);
 +        }
          else
 +        {
              cd.setIndexType(IndexType.KEYS, Collections.<String, String>emptyMap());
 +        }
  
          cd.setIndexName(indexName);
          cfm.addDefaultIndexNames();
 -        MigrationManager.announceColumnFamilyUpdate(cfm, false);
 +        MigrationManager.announceColumnFamilyUpdate(cfm, false, isLocalOnly);
+         return true;
      }
  
 -    public ResultMessage.SchemaChange.Change changeType()
 +    public Event.SchemaChange changeEvent()
      {
          // Creating an index is akin to updating the CF
 -        return ResultMessage.SchemaChange.Change.UPDATED;
 +        return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
      }
  }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
index 78263b6,7a8473a..8281cbd
--- a/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java
@@@ -97,11 -97,12 +97,12 @@@ public class CreateKeyspaceStatement ex
                                                                  attrs.getReplicationOptions());
      }
  
-     public void announceMigration(boolean isLocalOnly) throws RequestValidationException
 -    public boolean announceMigration() throws RequestValidationException
++    public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
      {
          try
          {
 -            MigrationManager.announceNewKeyspace(attrs.asKSMetadata(name));
 +            MigrationManager.announceNewKeyspace(attrs.asKSMetadata(name), isLocalOnly);
+             return true;
          }
          catch (AlreadyExistsException e)
          {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
index 47f05bb,b7f43d3..891a895
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
@@@ -107,11 -114,12 +107,12 @@@ public class CreateTableStatement exten
          return columnDefs;
      }
  
-     public void announceMigration(boolean isLocalOnly) throws RequestValidationException
 -    public boolean announceMigration() throws RequestValidationException
++    public boolean announceMigration(boolean isLocalOnly) throws RequestValidationException
      {
          try
          {
-            MigrationManager.announceNewColumnFamily(getCFMetaData(), isLocalOnly);
 -            MigrationManager.announceNewColumnFamily(getCFMetaData());
++            MigrationManager.announceNewColumnFamily(getCFMetaData(), isLocalOnly);
+             return true;
          }
          catch (AlreadyExistsException e)
          {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
index 9b7313f,70b3acb..db0cc22
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTriggerStatement.java
@@@ -65,16 -65,17 +65,17 @@@ public class CreateTriggerStatement ext
          }
      }
  
-     public void announceMigration(boolean isLocalOnly) throws ConfigurationException
 -    public boolean announceMigration() throws ConfigurationException
++    public boolean announceMigration(boolean isLocalOnly) throws ConfigurationException
      {
 -        CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
 +        CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).copy();
          cfm.addTriggerDefinition(TriggerDefinition.create(triggerName, triggerClass));
          logger.info("Adding trigger with name {} and class {}", triggerName, triggerClass);
 -        MigrationManager.announceColumnFamilyUpdate(cfm, false);
 +        MigrationManager.announceColumnFamilyUpdate(cfm, false, isLocalOnly);
+         return true;
      }
  
 -    public ResultMessage.SchemaChange.Change changeType()
 +    public Event.SchemaChange changeEvent()
      {
 -        return ResultMessage.SchemaChange.Change.UPDATED;
 +        return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
      }
  }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/CreateTypeStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CreateTypeStatement.java
index 5224474,0000000..82c2808
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTypeStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTypeStatement.java
@@@ -1,132 -1,0 +1,133 @@@
 +/*
 + * 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.nio.ByteBuffer;
 +import java.util.*;
 +
 +import org.apache.cassandra.auth.Permission;
 +import org.apache.cassandra.config.*;
 +import org.apache.cassandra.cql3.*;
 +import org.apache.cassandra.db.marshal.AbstractType;
 +import org.apache.cassandra.db.marshal.UTF8Type;
 +import org.apache.cassandra.db.marshal.UserType;
 +import org.apache.cassandra.exceptions.*;
 +import org.apache.cassandra.service.ClientState;
 +import org.apache.cassandra.service.MigrationManager;
 +import org.apache.cassandra.transport.Event;
 +
 +public class CreateTypeStatement extends SchemaAlteringStatement
 +{
 +    private final UTName name;
 +    private final List<ColumnIdentifier> columnNames = new ArrayList<>();
 +    private final List<CQL3Type.Raw> columnTypes = new ArrayList<>();
 +    private final boolean ifNotExists;
 +
 +    public CreateTypeStatement(UTName name, boolean ifNotExists)
 +    {
 +        super();
 +        this.name = name;
 +        this.ifNotExists = ifNotExists;
 +    }
 +
 +    @Override
 +    public void prepareKeyspace(ClientState state) throws InvalidRequestException
 +    {
 +        if (!name.hasKeyspace())
 +            name.setKeyspace(state.getKeyspace());
 +    }
 +
 +    public void addDefinition(ColumnIdentifier name, CQL3Type.Raw type)
 +    {
 +        columnNames.add(name);
 +        columnTypes.add(type);
 +    }
 +
 +    public void checkAccess(ClientState state) throws UnauthorizedException, InvalidRequestException
 +    {
 +        state.hasKeyspaceAccess(keyspace(), Permission.CREATE);
 +    }
 +
 +    public void validate(ClientState state) throws RequestValidationException
 +    {
 +        KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
 +        if (ksm == null)
 +            throw new InvalidRequestException(String.format("Cannot add type in unknown keyspace %s", name.getKeyspace()));
 +
 +        if (ksm.userTypes.getType(name.getUserTypeName()) != null && !ifNotExists)
 +            throw new InvalidRequestException(String.format("A user type of name %s already exists", name));
 +
 +        for (CQL3Type.Raw type : columnTypes)
 +            if (type.isCounter())
 +                throw new InvalidRequestException("A user type cannot contain counters");
 +    }
 +
 +    public static void checkForDuplicateNames(UserType type) throws InvalidRequestException
 +    {
 +        for (int i = 0; i < type.size() - 1; i++)
 +        {
 +            ByteBuffer fieldName = type.fieldName(i);
 +            for (int j = i+1; j < type.size(); j++)
 +            {
 +                if (fieldName.equals(type.fieldName(j)))
 +                    throw new InvalidRequestException(String.format("Duplicate field name %s in type %s",
 +                                                                    UTF8Type.instance.getString(fieldName),
 +                                                                    UTF8Type.instance.getString(type.name)));
 +            }
 +        }
 +    }
 +
 +    public Event.SchemaChange changeEvent()
 +    {
 +        return new Event.SchemaChange(Event.SchemaChange.Change.CREATED, Event.SchemaChange.Target.TYPE, keyspace(), name.getStringTypeName());
 +    }
 +
 +    @Override
 +    public String keyspace()
 +    {
 +        return name.getKeyspace();
 +    }
 +
 +    private UserType createType() throws InvalidRequestException
 +    {
 +        List<ByteBuffer> names = new ArrayList<>(columnNames.size());
 +        for (ColumnIdentifier name : columnNames)
 +            names.add(name.bytes);
 +
 +        List<AbstractType<?>> types = new ArrayList<>(columnTypes.size());
 +        for (CQL3Type.Raw type : columnTypes)
 +            types.add(type.prepare(keyspace()).getType());
 +
 +        return new UserType(name.getKeyspace(), name.getUserTypeName(), names, types);
 +    }
 +
-     public void announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
++    public boolean announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
 +    {
 +        KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
 +        assert ksm != null; // should haven't validate otherwise
 +
 +        // Can happen with ifNotExists
 +        if (ksm.userTypes.getType(name.getUserTypeName()) != null)
-             return;
++            return false;
 +
 +        UserType type = createType();
 +        checkForDuplicateNames(type);
 +        MigrationManager.announceNewType(type, isLocalOnly);
++        return true;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
index f70f526,ac5262e..5df8188
--- a/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropIndexStatement.java
@@@ -60,28 -54,21 +60,29 @@@ public class DropIndexStatement extend
          // validated in findIndexedCf()
      }
  
 -    public ResultMessage.SchemaChange.Change changeType()
 +    public Event.SchemaChange changeEvent()
      {
          // Dropping an index is akin to updating the CF
 -        return ResultMessage.SchemaChange.Change.UPDATED;
 +        return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
 +    }
 +
 +    @Override
 +    public ResultMessage execute(QueryState state, QueryOptions options) throws RequestValidationException
 +    {
 +        announceMigration(false);
 +        return indexedCF == null ? null : new ResultMessage.SchemaChange(changeEvent());
      }
  
-     public void announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
 -    public boolean announceMigration() throws InvalidRequestException, ConfigurationException
++    public boolean announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
      {
          CFMetaData cfm = findIndexedCF();
          if (cfm == null)
-             return;
+             return false;
  
          CFMetaData updatedCfm = updateCFMetadata(cfm);
 -        MigrationManager.announceColumnFamilyUpdate(updatedCfm, false);
 +        indexedCF = updatedCfm.cfName;
 +        MigrationManager.announceColumnFamilyUpdate(updatedCfm, false, isLocalOnly);
+         return true;
      }
  
      private CFMetaData updateCFMetadata(CFMetaData cfm)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
index 0a3a510,7582af0..ba6b917
--- a/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropKeyspaceStatement.java
@@@ -55,11 -55,12 +55,12 @@@ public class DropKeyspaceStatement exte
          return keyspace;
      }
  
-     public void announceMigration(boolean isLocalOnly) throws ConfigurationException
 -    public boolean announceMigration() throws ConfigurationException
++    public boolean announceMigration(boolean isLocalOnly) throws ConfigurationException
      {
          try
          {
 -            MigrationManager.announceKeyspaceDrop(keyspace);
 +            MigrationManager.announceKeyspaceDrop(keyspace, isLocalOnly);
+             return true;
          }
          catch(ConfigurationException e)
          {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
index 49979b1,65a3f14..e690c3e
--- a/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTableStatement.java
@@@ -54,11 -54,12 +54,12 @@@ public class DropTableStatement extend
          // validated in announceMigration()
      }
  
-     public void announceMigration(boolean isLocalOnly) throws ConfigurationException
 -    public boolean announceMigration() throws ConfigurationException
++    public boolean announceMigration(boolean isLocalOnly) throws ConfigurationException
      {
          try
          {
 -            MigrationManager.announceColumnFamilyDrop(keyspace(), columnFamily());
 +            MigrationManager.announceColumnFamilyDrop(keyspace(), columnFamily(), isLocalOnly);
+             return true;
          }
          catch (ConfigurationException e)
          {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
index 594aeac,f0bd637..4fdc21e
--- a/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTriggerStatement.java
@@@ -53,17 -53,18 +53,18 @@@ public class DropTriggerStatement exten
          ThriftValidation.validateColumnFamily(keyspace(), columnFamily());
      }
  
-     public void announceMigration(boolean isLocalOnly) throws ConfigurationException
 -    public boolean announceMigration() throws ConfigurationException
++    public boolean announceMigration(boolean isLocalOnly) throws ConfigurationException
      {
 -        CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).clone();
 +        CFMetaData cfm = Schema.instance.getCFMetaData(keyspace(), columnFamily()).copy();
          if (!cfm.removeTrigger(triggerName))
              throw new ConfigurationException(String.format("Trigger %s was not found", triggerName));
          logger.info("Dropping trigger with name {}", triggerName);
 -        MigrationManager.announceColumnFamilyUpdate(cfm, false);
 +        MigrationManager.announceColumnFamilyUpdate(cfm, false, isLocalOnly);
+         return true;
      }
  
 -    public ResultMessage.SchemaChange.Change changeType()
 +    public Event.SchemaChange changeEvent()
      {
 -        return ResultMessage.SchemaChange.Change.UPDATED;
 +        return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
      }
  }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
index 5acfdea,0000000..8bcaaf6
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropTypeStatement.java
@@@ -1,150 -1,0 +1,153 @@@
 +/*
 + * 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.*;
 +import org.apache.cassandra.cql3.*;
 +import org.apache.cassandra.db.marshal.*;
 +import org.apache.cassandra.exceptions.*;
 +import org.apache.cassandra.service.ClientState;
 +import org.apache.cassandra.service.MigrationManager;
 +import org.apache.cassandra.transport.Event;
 +
 +public class DropTypeStatement extends SchemaAlteringStatement
 +{
 +    private final UTName name;
 +    private final boolean ifExists;
 +
 +    public DropTypeStatement(UTName name, boolean ifExists)
 +    {
 +        super();
 +        this.name = name;
 +        this.ifExists = ifExists;
 +    }
 +
 +    @Override
 +    public void prepareKeyspace(ClientState state) throws InvalidRequestException
 +    {
 +        if (!name.hasKeyspace())
 +            name.setKeyspace(state.getKeyspace());
 +    }
 +
 +    public void checkAccess(ClientState state) throws UnauthorizedException, InvalidRequestException
 +    {
 +        state.hasKeyspaceAccess(keyspace(), Permission.DROP);
 +    }
 +
 +    public void validate(ClientState state) throws RequestValidationException
 +    {
 +        KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
 +        if (ksm == null)
 +            throw new InvalidRequestException(String.format("Cannot drop type in unknown keyspace %s", name.getKeyspace()));
 +
 +        UserType old = ksm.userTypes.getType(name.getUserTypeName());
 +        if (old == null)
 +        {
 +            if (ifExists)
 +                return;
 +            else
 +                throw new InvalidRequestException(String.format("No user type named %s exists.", name));
 +        }
 +
 +        // We don't want to drop a type unless it's not used anymore (mainly because
 +        // if someone drops a type and recreates one with the same name but different
 +        // definition with the previous name still in use, things can get messy).
 +        // We have two places to check: 1) other user type that can nest the one
 +        // we drop and 2) existing tables referencing the type (maybe in a nested
 +        // way).
 +
 +        for (KSMetaData ksm2 : Schema.instance.getKeyspaceDefinitions())
 +        {
 +            for (UserType ut : ksm2.userTypes.getAllTypes().values())
 +            {
 +                if (ut.keyspace.equals(name.getKeyspace()) && ut.name.equals(name.getUserTypeName()))
 +                    continue;
 +                if (isUsedBy(ut))
 +                    throw new InvalidRequestException(String.format("Cannot drop user type %s as it is still used by user type %s", name, ut.asCQL3Type()));
 +            }
 +
 +            for (CFMetaData cfm : ksm2.cfMetaData().values())
 +                for (ColumnDefinition def : cfm.allColumns())
 +                    if (isUsedBy(def.type))
 +                        throw new InvalidRequestException(String.format("Cannot drop user type %s as it is still used by table %s.%s", name, cfm.ksName, cfm.cfName));
 +        }
 +    }
 +
 +    private boolean isUsedBy(AbstractType<?> toCheck) throws RequestValidationException
 +    {
 +        if (toCheck instanceof UserType)
 +        {
 +            UserType ut = (UserType)toCheck;
 +            if (name.getKeyspace().equals(ut.keyspace) && name.getUserTypeName().equals(ut.name))
 +                return true;
 +
 +            for (AbstractType<?> subtype : ut.fieldTypes())
 +                if (isUsedBy(subtype))
 +                    return true;
 +        }
 +        else if (toCheck instanceof CompositeType)
 +        {
 +            CompositeType ct = (CompositeType)toCheck;
 +            for (AbstractType<?> subtype : ct.types)
 +                if (isUsedBy(subtype))
 +                    return true;
 +        }
 +        else if (toCheck instanceof ColumnToCollectionType)
 +        {
 +            for (CollectionType collection : ((ColumnToCollectionType)toCheck).defined.values())
 +                if (isUsedBy(collection))
 +                    return true;
 +        }
 +        else if (toCheck instanceof CollectionType)
 +        {
 +            if (toCheck instanceof ListType)
 +                return isUsedBy(((ListType)toCheck).elements);
 +            else if (toCheck instanceof SetType)
 +                return isUsedBy(((SetType)toCheck).elements);
 +            else
 +                return isUsedBy(((MapType)toCheck).keys) || isUsedBy(((MapType)toCheck).keys);
 +        }
 +        return false;
 +    }
 +
 +    public Event.SchemaChange changeEvent()
 +    {
 +        return new Event.SchemaChange(Event.SchemaChange.Change.DROPPED, Event.SchemaChange.Target.TYPE, keyspace(), name.getStringTypeName());
 +    }
 +
 +    @Override
 +    public String keyspace()
 +    {
 +        return name.getKeyspace();
 +    }
 +
-     public void announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
++    public boolean announceMigration(boolean isLocalOnly) throws InvalidRequestException, ConfigurationException
 +    {
 +        KSMetaData ksm = Schema.instance.getKSMetaData(name.getKeyspace());
 +        assert ksm != null;
 +
 +        UserType toDrop = ksm.userTypes.getType(name.getUserTypeName());
 +        // Can be null with ifExists
-         if (toDrop != null)
-             MigrationManager.announceTypeDrop(toDrop, isLocalOnly);
++        if (toDrop == null)
++            return false;
++
++        MigrationManager.announceTypeDrop(toDrop, isLocalOnly);
++        return true;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/664efd41/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
index e70aac9,845d8cc..8882871
--- a/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
@@@ -63,26 -62,31 +63,34 @@@ public abstract class SchemaAlteringSta
          return new Prepared(this);
      }
  
 -    public abstract ResultMessage.SchemaChange.Change changeType();
 +    public abstract Event.SchemaChange changeEvent();
  
-     public abstract void announceMigration(boolean isLocalOnly) throws RequestValidationException;
+     /**
+      * Announces the migration to other nodes in the cluster.
+      * @return true if the execution of this statement resulted in a schema change, false otherwise (when IF NOT EXISTS
+      * is used, for example)
+      * @throws RequestValidationException
+      */
 -    public abstract boolean announceMigration() throws RequestValidationException;
++    public abstract boolean announceMigration(boolean isLocalOnly) throws RequestValidationException;
  
      public ResultMessage execute(QueryState state, QueryOptions options) throws RequestValidationException
      {
-         announceMigration(false);
-         return new ResultMessage.SchemaChange(changeEvent());
+         // If an IF [NOT] EXISTS clause was used, this may not result in an actual schema change.  To avoid doing
+         // extra work in the drivers to handle schema changes, we return an empty message in this case. (CASSANDRA-7600)
 -        boolean didChangeSchema = announceMigration();
 -        if (!didChangeSchema)
 -            return new ResultMessage.Void();
 -
 -        String tableName = cfName == null || columnFamily() == null ? "" : columnFamily();
 -        return new ResultMessage.SchemaChange(changeType(), keyspace(), tableName);
++        boolean didChangeSchema = announceMigration(false);
++        return didChangeSchema ? new ResultMessage.SchemaChange(changeEvent()) : new ResultMessage.Void();
      }
  
      public ResultMessage executeInternal(QueryState state, QueryOptions options)
      {
 -        // executeInternal is for local query only, thus altering schema is not supported
 -        throw new UnsupportedOperationException();
 +        try
 +        {
-             announceMigration(true);
-             return new ResultMessage.SchemaChange(changeEvent());
++            boolean didChangeSchema = announceMigration(true);
++            return didChangeSchema ? new ResultMessage.SchemaChange(changeEvent()) : new ResultMessage.Void();
 +        }
 +        catch (RequestValidationException e)
 +        {
 +            throw new RuntimeException(e);
 +        }
      }
  }


[4/4] git commit: Merge branch 'cassandra-2.1.0' into cassandra-2.1

Posted by ty...@apache.org.
Merge branch 'cassandra-2.1.0' into cassandra-2.1


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

Branch: refs/heads/cassandra-2.1
Commit: edbd7d3922743ba0c81f61b7c3358249421f3205
Parents: 664efd4 a0923db
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Thu Aug 21 14:23:17 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Thu Aug 21 14:23:17 2014 -0500

----------------------------------------------------------------------

----------------------------------------------------------------------