Repository: cassandra Updated Branches: refs/heads/trunk b8f4ae004 -> 93b3aa8a4
Added compatibility table and test for primitive types Patch by Giampaolo Trapasso; reviewed by Alex Petrov for CASSANDRA-11114 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/93b3aa8a Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/93b3aa8a Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/93b3aa8a Branch: refs/heads/trunk Commit: 93b3aa8a469f76a49e4d0975d0b6ad6e85432a47 Parents: b8f4ae0 Author: Alex Petrov <[email protected]> Authored: Fri May 20 18:46:37 2016 +0200 Committer: Josh McKenzie <[email protected]> Committed: Mon May 23 16:12:25 2016 -0400 ---------------------------------------------------------------------- doc/cql3/CQL.textile | 24 +++++- .../apache/cassandra/config/CFMetaDataTest.java | 87 ++++++++++++++++++-- 2 files changed, 101 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b3aa8a/doc/cql3/CQL.textile ---------------------------------------------------------------------- diff --git a/doc/cql3/CQL.textile b/doc/cql3/CQL.textile index 4afdb4a..171bf77 100644 --- a/doc/cql3/CQL.textile +++ b/doc/cql3/CQL.textile @@ -417,11 +417,33 @@ p. The @ALTER@ statement is used to manipulate table definitions. It allows for adding new columns, dropping existing ones, changing the type of existing columns, or updating the table options. As with table creation, @ALTER COLUMNFAMILY@ is allowed as an alias for @ALTER TABLE@. The @<tablename>@ is the table name optionally preceded by the keyspace name. The @<instruction>@ defines the alteration to perform: -* @ALTER@: Update the type of a given defined column. Note that the type of the "clustering columns":#createTablepartitionClustering cannot be modified as it induces the on-disk ordering of rows. Columns on which a "secondary index":#createIndexStmt is defined have the same restriction. Other columns are free from those restrictions (no validation of existing data is performed), but it is usually a bad idea to change the type to a non-compatible one, unless no data have been inserted for that column yet, as this could confuse CQL drivers/tools. +* @ALTER@: Update the type of a given defined column. Note that the type of the "clustering columns":#createTablepartitionClustering can be modified only in very limited cases, as it induces the on-disk ordering of rows. Columns on which a "secondary index":#createIndexStmt is defined have the same restriction. To change the type of any other column, the column must already exist in type definition and its type should be compatible with the new type. No validation of existing data is performed. The compatibility table is available below. * @ADD@: Adds a new column to the table. The @<identifier>@ for the new column must not conflict with an existing column. Moreover, columns cannot be added to tables defined with the @COMPACT STORAGE@ option. * @DROP@: Removes a column from the table. Dropped columns will immediately become unavailable in the queries and will not be included in compacted sstables in the future. If a column is readded, queries won't return values written before the column was last dropped. It is assumed that timestamps represent actual time, so if this is not your case, you should NOT readd previously dropped columns. Columns can't be dropped from tables defined with the @COMPACT STORAGE@ option. * @WITH@: Allows to update the options of the table. The "supported @<option>@":#createTableOptions (and syntax) are the same as for the @CREATE TABLE@ statement except that @COMPACT STORAGE@ is not supported. Note that setting any @compaction@ sub-options has the effect of erasing all previous @compaction@ options, so you need to re-specify all the sub-options if you want to keep them. The same note applies to the set of @compression@ sub-options. +h4. CQL type compatibility: + +CQL data types may be converted only as the following table. + +|_. Data type may be altered to:|_.Data type| +|timestamp|bigint| +|ascii, bigint, boolean, date, decimal, double, float, inet, int, smallint, text, time, timestamp, timeuuid, tinyint, uuid, varchar, varint|blob| +|int|date| +|ascii, varchar|text| +|bigint|time| +|bigint|timestamp| +|timeuuid|uuid| +|ascii, text|varchar| +|bigint, int, timestamp|varint| + +Clustering columns have stricter requirements, only the below conversions are allowed. + +|_. Data type may be altered to:|_.Data type| +|ascii, text, varchar|blob| +|ascii, varchar|text| +|ascii, text|varchar| + h3(#dropTableStmt). DROP TABLE __Syntax:__ http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b3aa8a/test/unit/org/apache/cassandra/config/CFMetaDataTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/config/CFMetaDataTest.java b/test/unit/org/apache/cassandra/config/CFMetaDataTest.java index 188f72f..6bfe5c0 100644 --- a/test/unit/org/apache/cassandra/config/CFMetaDataTest.java +++ b/test/unit/org/apache/cassandra/config/CFMetaDataTest.java @@ -26,18 +26,11 @@ import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.db.Mutation; -import org.apache.cassandra.db.marshal.AsciiType; -import org.apache.cassandra.db.marshal.Int32Type; -import org.apache.cassandra.db.marshal.UTF8Type; +import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.db.partitions.PartitionUpdate; import org.apache.cassandra.db.rows.UnfilteredRowIterators; import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.cassandra.schema.CompressionParams; -import org.apache.cassandra.schema.KeyspaceMetadata; -import org.apache.cassandra.schema.KeyspaceParams; -import org.apache.cassandra.schema.SchemaKeyspace; -import org.apache.cassandra.schema.TableParams; -import org.apache.cassandra.schema.Types; +import org.apache.cassandra.schema.*; import org.apache.cassandra.thrift.CfDef; import org.apache.cassandra.thrift.ColumnDef; import org.apache.cassandra.thrift.IndexType; @@ -193,4 +186,80 @@ public class CFMetaDataTest assertFalse(CFMetaData.isNameValid("@")); assertFalse(CFMetaData.isNameValid("!")); } + + private static Set<String> primitiveTypes = new HashSet<String>(Arrays.asList(new String[] { "ascii", "bigint", "blob", "boolean", "date", + "decimal", "double", "float", "inet", "int", + "smallint", "text", "time", "timestamp", + "timeuuid", "tinyint", "uuid", "varchar", + "varint" })); + + @Test + public void typeCompatibilityTest() throws Throwable + { + Map<String, Set<String>> compatibilityMap = new HashMap<>(); + compatibilityMap.put("bigint", new HashSet<>(Arrays.asList(new String[] {"timestamp"}))); + compatibilityMap.put("blob", new HashSet<>(Arrays.asList(new String[] {"ascii", "bigint", "boolean", "date", "decimal", "double", + "float", "inet", "int", "smallint", "text", "time", "timestamp", + "timeuuid", "tinyint", "uuid", "varchar", "varint"}))); + compatibilityMap.put("date", new HashSet<>(Arrays.asList(new String[] {"int"}))); + compatibilityMap.put("time", new HashSet<>(Arrays.asList(new String[] {"bigint"}))); + compatibilityMap.put("text", new HashSet<>(Arrays.asList(new String[] {"ascii", "varchar"}))); + compatibilityMap.put("timestamp", new HashSet<>(Arrays.asList(new String[] {"bigint"}))); + compatibilityMap.put("varchar", new HashSet<>(Arrays.asList(new String[] {"ascii", "text"}))); + compatibilityMap.put("varint", new HashSet<>(Arrays.asList(new String[] {"bigint", "int", "timestamp"}))); + compatibilityMap.put("uuid", new HashSet<>(Arrays.asList(new String[] {"timeuuid"}))); + + for (String sourceTypeString: primitiveTypes) + { + AbstractType sourceType = CQLTypeParser.parse("KEYSPACE", sourceTypeString, Types.none()); + for (String destinationTypeString: primitiveTypes) + { + AbstractType destinationType = CQLTypeParser.parse("KEYSPACE", destinationTypeString, Types.none()); + + if (compatibilityMap.get(destinationTypeString) != null && + compatibilityMap.get(destinationTypeString).contains(sourceTypeString) || + sourceTypeString.equals(destinationTypeString)) + { + assertTrue(sourceTypeString + " should be compatible with " + destinationTypeString, + destinationType.isValueCompatibleWith(sourceType)); + } + else + { + assertFalse(sourceTypeString + " should not be compatible with " + destinationTypeString, + destinationType.isValueCompatibleWith(sourceType)); + } + } + } + } + + @Test + public void clusteringColumnTypeCompatibilityTest() throws Throwable + { + Map<String, Set<String>> compatibilityMap = new HashMap<>(); + compatibilityMap.put("blob", new HashSet<>(Arrays.asList(new String[] {"ascii", "text", "varchar"}))); + compatibilityMap.put("text", new HashSet<>(Arrays.asList(new String[] {"ascii", "varchar"}))); + compatibilityMap.put("varchar", new HashSet<>(Arrays.asList(new String[] {"ascii", "text" }))); + + for (String sourceTypeString: primitiveTypes) + { + AbstractType sourceType = CQLTypeParser.parse("KEYSPACE", sourceTypeString, Types.none()); + for (String destinationTypeString: primitiveTypes) + { + AbstractType destinationType = CQLTypeParser.parse("KEYSPACE", destinationTypeString, Types.none()); + + if (compatibilityMap.get(destinationTypeString) != null && + compatibilityMap.get(destinationTypeString).contains(sourceTypeString) || + sourceTypeString.equals(destinationTypeString)) + { + assertTrue(sourceTypeString + " should be compatible with " + destinationTypeString, + destinationType.isCompatibleWith(sourceType)); + } + else + { + assertFalse(sourceTypeString + " should not be compatible with " + destinationTypeString, + destinationType.isCompatibleWith(sourceType)); + } + } + } + } }
