Author: jbellis
Date: Wed Jun 1 12:58:40 2011
New Revision: 1130132
URL: http://svn.apache.org/viewvc?rev=1130132&view=rev
Log:
add CQL ALTER TABLE
patch by pyaskevich; reviewed by jbellis for CASSANDRA-1709
Modified:
cassandra/branches/cassandra-0.8/CHANGES.txt
cassandra/branches/cassandra-0.8/doc/cql/CQL.textile
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Cql.g
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/StatementType.java
cassandra/branches/cassandra-0.8/test/system/test_cql.py
Modified: cassandra/branches/cassandra-0.8/CHANGES.txt
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/CHANGES.txt?rev=1130132&r1=1130131&r2=1130132&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/CHANGES.txt (original)
+++ cassandra/branches/cassandra-0.8/CHANGES.txt Wed Jun 1 12:58:40 2011
@@ -30,6 +30,8 @@
* Added support for making bootstrap retry if nodes flap (CASSANDRA-2644)
* Added statusthrift to nodetool to report if thrift server is running
(CASSANDRA-2722)
* Fixed rows being cached if they do not exist (CASSANDRA-2723)
+ * Add CQL ALTER TABLE (CASSANDRA-1709)
+
0.8.0-final
* fix CQL grammar warning and cqlsh regression from CASSANDRA-2622
Modified: cassandra/branches/cassandra-0.8/doc/cql/CQL.textile
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/doc/cql/CQL.textile?rev=1130132&r1=1130131&r2=1130132&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/doc/cql/CQL.textile (original)
+++ cassandra/branches/cassandra-0.8/doc/cql/CQL.textile Wed Jun 1 12:58:40
2011
@@ -69,6 +69,21 @@ SELECT ... WHERE <CLAUSE> [LIMIT N] ...
Limiting the number of rows returned can be achieved by adding the @LIMIT@
option to a @SELECT@ expression. @LIMIT@ defaults to 10,000 when left unset.
+h2. ALTER TABLE
+
+_Synopsis:_
+
+bc.
+ALTER TABLE <columnFamily> ADD <column> <validator>;
+ALTER TABLE <columnFamily> ALTER <column> TYPE <validator>;
+ALTER TABLE <columnFamily> DROP <column>;
+
+An @ALTER@ is used to manipulate with ColumnFamily columns. It allows you to
add new column definitions and drop existing ones. No results are returned.
+
+Remember that in Cassandra the column definition is always optional; the
definition is only used for validation (and index creation). Columns that have
not yet been defined can still be inserted, but Cassandra won't know how to
validate them or provide type information to clients.
+
+Similarly, DROP only removes the definition, it does not actually destroy data.
+
h2. INSERT
_Synopsis:_
Modified:
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Cql.g
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Cql.g?rev=1130132&r1=1130131&r2=1130132&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Cql.g
(original)
+++ cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/Cql.g
Wed Jun 1 12:58:40 2011
@@ -35,6 +35,8 @@ options {
import java.util.ArrayList;
import org.apache.cassandra.thrift.ConsistencyLevel;
import org.apache.cassandra.thrift.InvalidRequestException;
+
+ import static org.apache.cassandra.cql.AlterTableStatement.OperationType;
}
@members {
@@ -113,6 +115,7 @@ query returns [CQLStatement stmnt]
| createIndexStatement { $stmnt = new
CQLStatement(StatementType.CREATE_INDEX, $createIndexStatement.expr); }
| dropKeyspaceStatement { $stmnt = new
CQLStatement(StatementType.DROP_KEYSPACE, $dropKeyspaceStatement.ksp); }
| dropColumnFamilyStatement { $stmnt = new
CQLStatement(StatementType.DROP_COLUMNFAMILY, $dropColumnFamilyStatement.cfam);
}
+ | alterTableStatement { $stmnt = new
CQLStatement(StatementType.ALTER_TABLE, $alterTableStatement.expr); }
;
// USE <KEYSPACE>;
@@ -386,6 +389,27 @@ dropKeyspaceStatement returns [String ks
: K_DROP K_KEYSPACE name=( IDENT | STRING_LITERAL | INTEGER ) endStmnt {
$ksp = $name.text; }
;
+
+alterTableStatement returns [AlterTableStatement expr]
+ :
+ {
+ OperationType type = null;
+ String columnFamily = null, columnName = null, validator = null;
+ }
+ K_ALTER K_TABLE name=( IDENT | STRING_LITERAL | INTEGER ) { columnFamily =
$name.text; }
+ ( K_ALTER { type = OperationType.ALTER; }
+ (col=( IDENT | STRING_LITERAL | INTEGER ) { columnName =
$col.text; })
+ K_TYPE alterValidator=comparatorType { validator =
$alterValidator.text; }
+ | K_ADD { type = OperationType.ADD; }
+ (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; }))
+ endStmnt
+ {
+ $expr = new AlterTableStatement(columnFamily, type, columnName,
validator);
+ }
+ ;
/** DROP COLUMNFAMILY <CF>; */
dropColumnFamilyStatement returns [String cfam]
: K_DROP K_COLUMNFAMILY name=( IDENT | STRING_LITERAL | INTEGER ) endStmnt
{ $cfam = $name.text; }
@@ -468,6 +492,10 @@ K_INTO: I N T O;
K_VALUES: V A L U E S;
K_TIMESTAMP: T I M E S T A M P;
K_TTL: T T L;
+K_ALTER: A L T E R;
+K_TABLE: T A B L E;
+K_ADD: A D D;
+K_TYPE: T Y P E;
// Case-insensitive alpha characters
fragment A: ('a'|'A');
Modified:
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java?rev=1130132&r1=1130131&r2=1130132&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java
(original)
+++
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java
Wed Jun 1 12:58:40 2011
@@ -58,7 +58,7 @@ public class CreateColumnFamilyStatement
private static final String KW_ROW_CACHE_PROVIDER = "row_cache_provider";
// Maps CQL short names to the respective Cassandra comparator/validator
class names
- private static final Map<String, String> comparators = new HashMap<String,
String>();
+ public static final Map<String, String> comparators = new HashMap<String,
String>();
private static final Set<String> keywords = new HashSet<String>();
static
Modified:
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java?rev=1130132&r1=1130131&r2=1130132&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java
(original)
+++
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java
Wed Jun 1 12:58:40 2011
@@ -48,7 +48,6 @@ import org.apache.cassandra.db.migration
import org.apache.cassandra.db.migration.avro.CfDef;
import org.apache.cassandra.dht.*;
import org.apache.cassandra.dht.Token;
-import org.apache.cassandra.locator.AbstractReplicationStrategy;
import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.StorageProxy;
import org.apache.cassandra.service.StorageService;
@@ -791,7 +790,35 @@ public class QueryProcessor
result.type = CqlResultType.VOID;
return result;
-
+
+ case ALTER_TABLE:
+ AlterTableStatement alterTable = (AlterTableStatement)
statement.statement;
+
+ System.out.println(alterTable);
+
+ validateColumnFamily(keyspace, alterTable.columnFamily);
+ clientState.hasColumnFamilyAccess(alterTable.columnFamily,
Permission.WRITE);
+ validateSchemaAgreement();
+
+ try
+ {
+ applyMigrationOnStage(new
UpdateColumnFamily(alterTable.getCfDef(keyspace)));
+ }
+ catch (ConfigurationException e)
+ {
+ InvalidRequestException ex = new
InvalidRequestException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ }
+ catch (IOException e)
+ {
+ InvalidRequestException ex = new
InvalidRequestException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ }
+
+ result.type = CqlResultType.VOID;
+ return result;
}
return null; // We should never get here.
Modified:
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/StatementType.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/StatementType.java?rev=1130132&r1=1130131&r2=1130132&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/StatementType.java
(original)
+++
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/StatementType.java
Wed Jun 1 12:58:40 2011
@@ -25,7 +25,7 @@ import java.util.EnumSet;
public enum StatementType
{
SELECT, INSERT, UPDATE, BATCH, USE, TRUNCATE, DELETE, CREATE_KEYSPACE,
CREATE_COLUMNFAMILY, CREATE_INDEX,
- DROP_KEYSPACE, DROP_COLUMNFAMILY;
+ DROP_KEYSPACE, DROP_COLUMNFAMILY, ALTER_TABLE;
// Statement types that don't require a keyspace to be set.
private static final EnumSet<StatementType> topLevel = EnumSet.of(USE,
CREATE_KEYSPACE, DROP_KEYSPACE);
Modified: cassandra/branches/cassandra-0.8/test/system/test_cql.py
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/test/system/test_cql.py?rev=1130132&r1=1130131&r2=1130132&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/test/system/test_cql.py (original)
+++ cassandra/branches/cassandra-0.8/test/system/test_cql.py Wed Jun 1
12:58:40 2011
@@ -1006,3 +1006,78 @@ class TestCql(ThriftTester):
r = cursor.fetchone()
assert len(r) == 1, "expected 0 results, got %d" % len(r)
+
+ def test_alter_table_statement(self):
+ "test ALTER TABLE statement"
+ cursor = init()
+ cursor.execute("""
+ CREATE KEYSPACE AlterTableKS WITH
strategy_options:replication_factor = '1'
+ AND strategy_class = 'SimpleStrategy';
+ """)
+ cursor.execute("USE AlterTableKS;")
+
+ cursor.execute("""
+ CREATE COLUMNFAMILY NewCf1 (KEY varint PRIMARY KEY) WITH
default_validation = ascii;
+ """)
+
+ # TODO: temporary (until this can be done with CQL).
+ ksdef = thrift_client.describe_keyspace("AlterTableKS")
+ assert len(ksdef.cf_defs) == 1, \
+ "expected 1 column family total, found %d" % len(ksdef.cf_defs)
+ cfam = ksdef.cf_defs[0]
+
+ assert len(cfam.column_metadata) == 0
+
+ # testing "add a new column"
+ cursor.execute("ALTER TABLE NewCf1 ADD name varchar")
+
+ ksdef = thrift_client.describe_keyspace("AlterTableKS")
+ assert len(ksdef.cf_defs) == 1, \
+ "expected 1 column family total, found %d" % len(ksdef.cf_defs)
+ columns = ksdef.cf_defs[0].column_metadata
+
+ assert len(columns) == 1
+ assert columns[0].name == 'name'
+ assert columns[0].validation_class ==
'org.apache.cassandra.db.marshal.UTF8Type'
+
+ # testing "alter a column type"
+ cursor.execute("ALTER TABLE NewCf1 ALTER name TYPE ascii")
+
+ ksdef = thrift_client.describe_keyspace("AlterTableKS")
+ assert len(ksdef.cf_defs) == 1, \
+ "expected 1 column family total, found %d" % len(ksdef.cf_defs)
+ columns = ksdef.cf_defs[0].column_metadata
+
+ assert len(columns) == 1
+ assert columns[0].name == 'name'
+ assert columns[0].validation_class ==
'org.apache.cassandra.db.marshal.AsciiType'
+
+ # alter column with unknown validator
+ assert_raises(cql.ProgrammingError,
+ cursor.execute,
+ "ALTER TABLE NewCf1 ADD name utf8")
+
+ # testing 'drop an existing column'
+ cursor.execute("ALTER TABLE NewCf1 DROP name")
+
+ ksdef = thrift_client.describe_keyspace("AlterTableKS")
+ assert len(ksdef.cf_defs) == 1, \
+ "expected 1 column family total, found %d" % len(ksdef.cf_defs)
+ columns = ksdef.cf_defs[0].column_metadata
+
+ assert len(columns) == 0
+
+ # add column with unknown validator
+ assert_raises(cql.ProgrammingError,
+ cursor.execute,
+ "ALTER TABLE NewCf1 ADD name utf8")
+
+ # alter not existing column
+ assert_raises(cql.ProgrammingError,
+ cursor.execute,
+ "ALTER TABLE NewCf1 ALTER name TYPE uuid")
+
+ # drop not existing column
+ assert_raises(cql.ProgrammingError,
+ cursor.execute,
+ "ALTER TABLE NewCf1 DROP name")