add ALTER COLUMNFAMILY WITH

allows modification of columnfamily properties after creation

patch by pcannon; reviewed by jbellis for CASSANDRA-3523


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

Branch: refs/heads/trunk
Commit: f458cc1ad94acb06cc8a7b59d15b03d4150ad353
Parents: 890fcc9
Author: paul cannon <[email protected]>
Authored: Fri Jan 13 14:48:39 2012 -0600
Committer: Jonathan Ellis <[email protected]>
Committed: Mon Jan 16 13:28:40 2012 -0600

----------------------------------------------------------------------
 bin/cqlsh                                          |   21 ++++-
 doc/cql/CQL.textile                                |   17 +++-
 .../apache/cassandra/cql/AlterTableStatement.java  |   77 ++++++++++++++-
 src/java/org/apache/cassandra/cql/CFPropDefs.java  |    5 +
 src/java/org/apache/cassandra/cql/Cql.g            |    9 ++-
 5 files changed, 119 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/f458cc1a/bin/cqlsh
----------------------------------------------------------------------
diff --git a/bin/cqlsh b/bin/cqlsh
index 0f02a0c..ccbd495 100755
--- a/bin/cqlsh
+++ b/bin/cqlsh
@@ -1366,17 +1366,19 @@ class Shell(cmd.Cmd):
         ALTER COLUMNFAMILY <cfname> ALTER <columnname> TYPE <type>;
         ALTER COLUMNFAMILY <cfname> ADD <columnname> <type>;
         ALTER COLUMNFAMILY <cfname> DROP <columnname>;
+        ALTER COLUMNFAMILY <cfname> WITH <optionname> = <val> [AND 
<optionname> = <val> [...]];
 
         An ALTER statement is used to manipulate column family column
-        metadata. It allows you to add new columns, drop existing columns, or
-        change the data storage type of existing columns. No results are
-        returned.
+        metadata. It allows you to add new columns, drop existing columns,
+        change the data storage type of existing columns, or change column
+        family properties. No results are returned.
 
         See one of the following for more information:
 
           HELP ALTER_ALTER;
           HELP ALTER_ADD;
           HELP ALTER_DROP;
+          HELP ALTER_WITH;
         """
 
     def help_alter_alter(self):
@@ -1419,6 +1421,19 @@ class Shell(cmd.Cmd):
         according to a certain type.
         """
 
+    def help_alter_with(self):
+        print """
+        ALTER COLUMNFAMILY: changing column family properties
+
+          ALTER COLUMNFAMILY addamsFamily WITH comment = 'Glad to be here!'
+                                           AND read_repair_chance = 0.2;
+
+        An ALTER COLUMNFAMILY ... WITH statement makes adjustments to the
+        column family properties, as defined when the column family was created
+        (see HELP CREATE_COLUMNFAMILY_OPTIONS, and your Cassandra documentation
+        for information about the supported parameter names and values).
+        """
+
     def printout(self, text, color=None, newline=True, out=sys.stdout):
         if not color or not self.color:
             out.write(text)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f458cc1a/doc/cql/CQL.textile
----------------------------------------------------------------------
diff --git a/doc/cql/CQL.textile b/doc/cql/CQL.textile
index 08b276b..4fd3d74 100644
--- a/doc/cql/CQL.textile
+++ b/doc/cql/CQL.textile
@@ -533,7 +533,7 @@ CREATE ... ( ... , name1 type1, name2 type2, ... ) ...
 
 It is possible to assign columns a type during column family creation. Columns 
configured with a type are validated accordingly when a write occurs, and 
intelligent CQL drivers and interfaces will be able to decode the column values 
correctly when receiving them. Column types are specified as a parenthesized, 
comma-separated list of column term and type pairs. See "Data Storage 
Types":#storageTypes for the list of recognized types.
 
-h3. Column Family Options (optional)
+h3(#cfopts). Column Family Options (optional)
 
 bc(sample). 
 CREATE COLUMNFAMILY ... WITH keyword1 = arg1 AND keyword2 = arg2;
@@ -621,11 +621,13 @@ bc(syntax).
 <alterInstructions> ::= "ALTER" <name> "TYPE" <storageType>
                       | "ADD" <name> <storageType>
                       | "DROP" <name>
+                      | "WITH" <optionName> "=" <cfOptionVal>
+                               ( "AND" <optionName> "=" <cfOptionVal> )*
                       ;
 
-An @ALTER@ statement is used to manipulate column family column metadata. It 
allows you to add new columns, drop existing columns, or change the data 
storage type of existing columns. No results are returned.
+An @ALTER@ statement is used to manipulate column family column metadata. It 
allows you to add new columns, drop existing columns, data storage type of 
existing columns, or change the column family properties. No results are 
returned.
 
-Specify the name of the column family to be changed after the @ALTER 
COLUMNFAMILY@ keywords, and the name of the column to be changed, added, or 
dropped after the keyword corresponding to the type of change desired (@ALTER@, 
@ADD@, @DROP@).
+Specify the name of the column family to be changed after the @ALTER 
COLUMNFAMILY@ keywords, followed by the type of change desired (@ALTER@, @ADD@, 
@DROP@, or @WITH@), and provide the rest of the needed information, as 
explained below.
 
 h3. Changing the type of a typed column
 
@@ -648,6 +650,15 @@ ALTER COLUMNFAMILY addamsFamily DROP gender;
 
 An @ALTER COLUMNFAMILY ... DROP@ statement removes the type of a column from 
the column family metadata. Note that this does _not_ remove the column from 
current rows; it just removes the metadata saying that the bytes stored under 
that column are expected to be deserializable according to a certain type.
 
+h3. Modifying column family properties
+
+bc(sample). 
+ALTER COLUMNFAMILY addamsFamily WITH comment = 'A most excellent and useful 
column family' AND read_repair_chance = 0.2;
+
+An @ALTER COLUMNFAMILY ... WITH@ statement makes adjustments to the column 
family properties, as defined when the column family was created (see "CREATE 
COLUMNFAMILY options":#cfopts for information about the supported options and 
values).
+
+Note that setting any @compaction_strategy_options:*@ parameters has the 
effect of erasing all previous @compaction_strategy_options:*@ parameters, so 
you will need to re-specify any such parameters which have already been set, if 
you want to keep them. The same note applies to the set of 
@compression_parameters:*@ parameters.
+
 h2. Common Idioms
 
 h3(#consistency). Specifying Consistency

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f458cc1a/src/java/org/apache/cassandra/cql/AlterTableStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql/AlterTableStatement.java 
b/src/java/org/apache/cassandra/cql/AlterTableStatement.java
index 930cb8e..6f10f50 100644
--- a/src/java/org/apache/cassandra/cql/AlterTableStatement.java
+++ b/src/java/org/apache/cassandra/cql/AlterTableStatement.java
@@ -20,6 +20,7 @@
  */
 package org.apache.cassandra.cql;
 
+import org.apache.avro.util.Utf8;
 import org.apache.cassandra.config.*;
 import org.apache.cassandra.db.marshal.TypeParser;
 import org.apache.cassandra.db.migration.avro.CfDef;
@@ -27,16 +28,19 @@ import org.apache.cassandra.db.migration.avro.ColumnDef;
 import org.apache.cassandra.thrift.InvalidRequestException;
 
 import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
 
 public class AlterTableStatement
 {
     public static enum OperationType
     {
-        ADD, ALTER, DROP
+        ADD, ALTER, DROP, OPTS
     }
 
     public final OperationType oType;
     public final String columnFamily, columnName, validator;
+    private final CFPropDefs cfProps = new CFPropDefs();
 
     public AlterTableStatement(String columnFamily, OperationType type, String 
columnName)
     {
@@ -45,10 +49,23 @@ public class AlterTableStatement
 
     public AlterTableStatement(String columnFamily, OperationType type, String 
columnName, String validator)
     {
+        this(columnFamily, type, columnName, validator, null);
+    }
+
+    public AlterTableStatement(String columnFamily, OperationType type, String 
columnName, String validator, Map<String, String> propertyMap)
+    {
         this.columnFamily = columnFamily;
         this.oType = type;
         this.columnName = columnName;
         this.validator = CFPropDefs.comparators.get(validator); // used only 
for ADD/ALTER commands
+
+        if (propertyMap != null)
+        {
+            for (Map.Entry<String, String> prop : propertyMap.entrySet())
+            {
+                cfProps.addProperty(prop.getKey(), prop.getValue());
+            }
+        }
     }
 
     public CfDef getCfDef(String keyspace) throws ConfigurationException, 
InvalidRequestException
@@ -57,7 +74,8 @@ public class AlterTableStatement
 
         CfDef cfDef = meta.toAvro();
 
-        ByteBuffer columnName = meta.comparator.fromString(this.columnName);
+        ByteBuffer columnName = this.oType == OperationType.OPTS ? null
+                                                                 : 
meta.comparator.fromString(this.columnName);
 
         switch (oType)
         {
@@ -108,6 +126,14 @@ public class AlterTableStatement
                 // some where deep inside of Avro
                 cfDef.column_metadata.remove(toDelete);
                 break;
+
+            case OPTS:
+                if (cfProps == null)
+                    throw new InvalidRequestException(String.format("ALTER 
COLUMNFAMILY WITH invoked, but no parameters found"));
+
+                cfProps.validate();
+                applyPropertiesToCfDef(cfDef, cfProps);
+                break;
         }
 
         return cfDef;
@@ -122,4 +148,51 @@ public class AlterTableStatement
                              validator);
     }
 
+    public static void applyPropertiesToCfDef(CfDef cfDef, CFPropDefs cfProps) 
throws InvalidRequestException
+    {
+        if (cfProps.hasProperty(CFPropDefs.KW_COMPARATOR))
+        {
+            throw new InvalidRequestException("Can't change CF comparator 
after creation");
+        }
+        if (cfProps.hasProperty(CFPropDefs.KW_COMMENT))
+        {
+            cfDef.comment = new 
Utf8(cfProps.getProperty(CFPropDefs.KW_COMMENT));
+        }
+        if (cfProps.hasProperty(CFPropDefs.KW_DEFAULTVALIDATION))
+        {
+            try
+            {
+                cfDef.default_validation_class = new 
Utf8(cfProps.getValidator().toString());
+            }
+            catch (ConfigurationException e)
+            {
+                throw new InvalidRequestException(String.format("Invalid 
validation type %s",
+                                                                
cfProps.getProperty(CFPropDefs.KW_DEFAULTVALIDATION)));
+            }
+        }
+
+        cfDef.read_repair_chance = 
cfProps.getPropertyDouble(CFPropDefs.KW_READREPAIRCHANCE, 
cfDef.read_repair_chance);
+        cfDef.gc_grace_seconds = 
cfProps.getPropertyInt(CFPropDefs.KW_GCGRACESECONDS, cfDef.gc_grace_seconds);
+        cfDef.replicate_on_write = 
cfProps.getPropertyBoolean(CFPropDefs.KW_REPLICATEONWRITE, 
cfDef.replicate_on_write);
+        cfDef.min_compaction_threshold = 
cfProps.getPropertyInt(CFPropDefs.KW_MINCOMPACTIONTHRESHOLD, 
cfDef.min_compaction_threshold);
+        cfDef.max_compaction_threshold = 
cfProps.getPropertyInt(CFPropDefs.KW_MAXCOMPACTIONTHRESHOLD, 
cfDef.max_compaction_threshold);
+
+        if (!cfProps.compactionStrategyOptions.isEmpty())
+        {
+            cfDef.compaction_strategy_options = new HashMap<CharSequence, 
CharSequence>();
+            for (Map.Entry<String, String> entry : 
cfProps.compactionStrategyOptions.entrySet())
+            {
+                cfDef.compaction_strategy_options.put(new 
Utf8(entry.getKey()), new Utf8(entry.getValue()));
+            }
+        }
+
+        if (!cfProps.compressionParameters.isEmpty())
+        {
+            cfDef.compression_options = new HashMap<CharSequence, 
CharSequence>();
+            for (Map.Entry<String, String> entry : 
cfProps.compressionParameters.entrySet())
+            {
+                cfDef.compression_options.put(new Utf8(entry.getKey()), new 
Utf8(entry.getValue()));
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f458cc1a/src/java/org/apache/cassandra/cql/CFPropDefs.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql/CFPropDefs.java 
b/src/java/org/apache/cassandra/cql/CFPropDefs.java
index 94b5178..5103b24 100644
--- a/src/java/org/apache/cassandra/cql/CFPropDefs.java
+++ b/src/java/org/apache/cassandra/cql/CFPropDefs.java
@@ -172,6 +172,11 @@ public class CFPropDefs {
         properties.put(name, value);
     }
 
+    public Boolean hasProperty(String name)
+    {
+        return properties.containsKey(name);
+    }
+
     /* If not comparator/validator is not specified, default to text 
(BytesType is the wrong default for CQL
      * since it uses hex terms).  If the value specified is not found in the 
comparators map, assume the user
      * knows what they are doing (a custom comparator/validator for example), 
and pass it on as-is.

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f458cc1a/src/java/org/apache/cassandra/cql/Cql.g
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql/Cql.g 
b/src/java/org/apache/cassandra/cql/Cql.g
index b911a8e..b6d4545 100644
--- a/src/java/org/apache/cassandra/cql/Cql.g
+++ b/src/java/org/apache/cassandra/cql/Cql.g
@@ -426,6 +426,7 @@ alterTableStatement returns [AlterTableStatement expr]
     {
         OperationType type = null;
         String columnFamily = null, columnName = null, validator = null;
+        Map<String, String> propertyMap = null;
     }
     K_ALTER K_COLUMNFAMILY name=( IDENT | STRING_LITERAL | INTEGER ) { 
columnFamily = $name.text; }
           ( K_ALTER { type = OperationType.ALTER; }
@@ -435,12 +436,16 @@ alterTableStatement returns [AlterTableStatement expr]
                (col=( IDENT | STRING_LITERAL | INTEGER ) { columnName = 
$col.text; })
                addValidator=comparatorType { validator = $addValidator.text; }
           | K_DROP { type = OperationType.DROP; }
-               (col=( IDENT | STRING_LITERAL | INTEGER ) { columnName = 
$col.text; }))
+               (col=( IDENT | STRING_LITERAL | INTEGER ) { columnName = 
$col.text; })
+          | K_WITH { type = OperationType.OPTS; propertyMap = new 
HashMap<String, String>(); }
+               prop1=(COMPIDENT | IDENT) '=' arg1=createCfamKeywordArgument { 
propertyMap.put($prop1.text, $arg1.arg); }
+               ( K_AND propN=(COMPIDENT | IDENT) '=' 
argN=createCfamKeywordArgument { propertyMap.put($propN.text, $argN.arg); } )* )
     endStmnt
       {
-          $expr = new AlterTableStatement(columnFamily, type, columnName, 
validator);
+          $expr = new AlterTableStatement(columnFamily, type, columnName, 
validator, propertyMap);
       }
     ;
+
 /** DROP COLUMNFAMILY <CF>; */
 dropColumnFamilyStatement returns [String cfam]
     : K_DROP K_COLUMNFAMILY name=( IDENT | STRING_LITERAL | INTEGER ) endStmnt 
{ $cfam = $name.text; }

Reply via email to