Repository: cassandra Updated Branches: refs/heads/trunk dc8523819 -> 1b5fa8ce3
Fix and move dropped columns info to a separate schema table patch by Aleksey Yeschenko; reviewed by Tyler Hobbs for CASSANDRA-6717 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/1b5fa8ce Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/1b5fa8ce Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/1b5fa8ce Branch: refs/heads/trunk Commit: 1b5fa8ce3cbd238b0e735ed067eb95c83b67f262 Parents: dc85238 Author: Aleksey Yeschenko <[email protected]> Authored: Sat Jul 18 00:52:40 2015 +0300 Committer: Aleksey Yeschenko <[email protected]> Committed: Sat Jul 18 00:52:40 2015 +0300 ---------------------------------------------------------------------- .../org/apache/cassandra/config/CFMetaData.java | 48 +++++++- .../cql3/statements/AlterTableStatement.java | 5 +- .../org/apache/cassandra/db/LegacyLayout.java | 15 ++- .../cassandra/schema/LegacySchemaMigrator.java | 27 ++++- .../apache/cassandra/schema/SchemaKeyspace.java | 115 ++++++++++++------- .../cassandra/schema/SchemaKeyspace.java.rej | 80 ------------- .../schema/LegacySchemaMigratorTest.java | 27 +++++ 7 files changed, 184 insertions(+), 133 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5fa8ce/src/java/org/apache/cassandra/config/CFMetaData.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/CFMetaData.java b/src/java/org/apache/cassandra/config/CFMetaData.java index 81ef217..6c53699 100644 --- a/src/java/org/apache/cassandra/config/CFMetaData.java +++ b/src/java/org/apache/cassandra/config/CFMetaData.java @@ -27,6 +27,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.base.Strings; import com.google.common.collect.*; @@ -1193,7 +1194,7 @@ public final class CFMetaData public void recordColumnDrop(ColumnDefinition def) { - droppedColumns.put(def.name.bytes, new DroppedColumn(def.type, FBUtilities.timestampMicros())); + droppedColumns.put(def.name.bytes, new DroppedColumn(def.name.toString(), def.type, FBUtilities.timestampMicros())); } public void renameColumn(ColumnIdentifier from, ColumnIdentifier to) throws InvalidRequestException @@ -1261,6 +1262,14 @@ public final class CFMetaData return false; } + public boolean hasDroppedCollectionColumns() + { + for (DroppedColumn def : getDroppedColumns().values()) + if (def.type instanceof CollectionType && def.type.isMultiCell()) + return true; + return false; + } + public boolean isSuper() { return isSuper; @@ -1536,13 +1545,48 @@ public final class CFMetaData public static class DroppedColumn { + // we only allow dropping REGULAR columns, from CQL-native tables, so the names are always of UTF8Type + public final String name; public final AbstractType<?> type; + + // drop timestamp, in microseconds, yet with millisecond granularity public final long droppedTime; - public DroppedColumn(AbstractType<?> type, long droppedTime) + public DroppedColumn(String name, AbstractType<?> type, long droppedTime) { + this.name = name; this.type = type; this.droppedTime = droppedTime; } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + + if (!(o instanceof DroppedColumn)) + return false; + + DroppedColumn dc = (DroppedColumn) o; + + return name.equals(dc.name) && type.equals(dc.type) && droppedTime == dc.droppedTime; + } + + @Override + public int hashCode() + { + return Objects.hashCode(name, type, droppedTime); + } + + @Override + public String toString() + { + return MoreObjects.toStringHelper(this) + .add("name", name) + .add("type", type) + .add("droppedTime", droppedTime) + .toString(); + } } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5fa8ce/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 e0c5f4e..a247cdb 100644 --- a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java @@ -129,11 +129,10 @@ public class AlterTableStatement extends SchemaAlteringStatement // some data using the old type, and so we can't allow adding a collection with the same name unless // the types are compatible (see #6276). CFMetaData.DroppedColumn dropped = cfm.getDroppedColumns().get(columnName.bytes); - // We could have type == null for old dropped columns, in which case we play it safe and refuse - if (dropped != null && (dropped.type == null || (dropped.type instanceof CollectionType && !type.isCompatibleWith(dropped.type)))) + if (dropped != null && dropped.type instanceof CollectionType && !type.isCompatibleWith(dropped.type)) throw new InvalidRequestException(String.format("Cannot add a collection with the name %s " + "because a collection with the same name and a different type%s has already been used in the past", - columnName, dropped.type == null ? "" : " (" + dropped.type.asCQL3Type() + ")")); + columnName, " (" + dropped.type.asCQL3Type() + ')')); } Integer componentIndex = cfm.isCompound() ? cfm.comparator.size() : null; http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5fa8ce/src/java/org/apache/cassandra/db/LegacyLayout.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/LegacyLayout.java b/src/java/org/apache/cassandra/db/LegacyLayout.java index 9eb7145..f063256 100644 --- a/src/java/org/apache/cassandra/db/LegacyLayout.java +++ b/src/java/org/apache/cassandra/db/LegacyLayout.java @@ -41,6 +41,8 @@ import org.apache.cassandra.thrift.ColumnDef; import org.apache.cassandra.utils.*; import org.apache.hadoop.io.serializer.Serialization; +import static org.apache.cassandra.utils.ByteBufferUtil.bytes; + /** * Functions to deal with the old format. */ @@ -67,7 +69,7 @@ public abstract class LegacyLayout return comparator.subtype(0); } - boolean hasCollections = metadata.hasCollectionColumns(); + boolean hasCollections = metadata.hasCollectionColumns() || metadata.hasDroppedCollectionColumns(); List<AbstractType<?>> types = new ArrayList<>(comparator.size() + (metadata.isDense() ? 0 : 1) + (hasCollections ? 1 : 0)); types.addAll(comparator.subtypes()); @@ -75,14 +77,19 @@ public abstract class LegacyLayout if (!metadata.isDense()) { types.add(UTF8Type.instance); + if (hasCollections) { Map<ByteBuffer, CollectionType> defined = new HashMap<>(); + + for (CFMetaData.DroppedColumn def : metadata.getDroppedColumns().values()) + if (def.type instanceof CollectionType && def.type.isMultiCell()) + defined.put(bytes(def.name), (CollectionType) def.type); + for (ColumnDefinition def : metadata.partitionColumns()) - { if (def.type instanceof CollectionType && def.type.isMultiCell()) - defined.put(def.name.bytes, (CollectionType)def.type); - } + defined.put(def.name.bytes, (CollectionType) def.type); + types.add(ColumnToCollectionType.getInstance(defined)); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5fa8ce/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java b/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java index 159396b..879a505 100644 --- a/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java +++ b/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java @@ -330,7 +330,7 @@ public final class LegacySchemaMigrator cfm.bloomFilterFpChance(cfm.getBloomFilterFpChance()); if (tableRow.has("dropped_columns")) - addDroppedColumns(cfm, tableRow.getMap("dropped_columns", UTF8Type.instance, LongType.instance), Collections.emptyMap()); + addDroppedColumns(cfm, rawComparator, tableRow.getMap("dropped_columns", UTF8Type.instance, LongType.instance)); cfm.triggers(createTriggersFromTriggerRows(triggerRows)); @@ -396,14 +396,33 @@ public final class LegacySchemaMigrator return false; } - private static void addDroppedColumns(CFMetaData cfm, Map<String, Long> droppedTimes, Map<String, String> types) + /* + * Prior to 3.0 we used to not store the type of the dropped columns, relying on all collection info being + * present in the comparator, forever. That allowed us to perform certain validations in AlterTableStatement + * (namely not allowing to re-add incompatible collection columns, with the same name, but a different type). + * + * In 3.0, we no longer preserve the original comparator, and reconstruct it from the columns instead. That means + * that we should preserve the type of the dropped columns now, and, during migration, fetch the types from + * the original comparator if necessary. + */ + private static void addDroppedColumns(CFMetaData cfm, AbstractType<?> comparator, Map<String, Long> droppedTimes) { + AbstractType<?> last = comparator.getComponents().get(comparator.componentsCount() - 1); + Map<ByteBuffer, CollectionType> collections = last instanceof ColumnToCollectionType + ? ((ColumnToCollectionType) last).defined + : Collections.emptyMap(); + for (Map.Entry<String, Long> entry : droppedTimes.entrySet()) { String name = entry.getKey(); + ByteBuffer nameBytes = UTF8Type.instance.decompose(name); long time = entry.getValue(); - AbstractType<?> type = types.containsKey(name) ? TypeParser.parse(types.get(name)) : null; - cfm.getDroppedColumns().put(UTF8Type.instance.decompose(name), new CFMetaData.DroppedColumn(type, time)); + + AbstractType<?> type = collections.containsKey(nameBytes) + ? collections.get(nameBytes) + : BytesType.instance; + + cfm.getDroppedColumns().put(nameBytes, new CFMetaData.DroppedColumn(name, type, time)); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5fa8ce/src/java/org/apache/cassandra/schema/SchemaKeyspace.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/schema/SchemaKeyspace.java b/src/java/org/apache/cassandra/schema/SchemaKeyspace.java index 739d8a3..4228a46 100644 --- a/src/java/org/apache/cassandra/schema/SchemaKeyspace.java +++ b/src/java/org/apache/cassandra/schema/SchemaKeyspace.java @@ -74,6 +74,7 @@ public final class SchemaKeyspace public static final String KEYSPACES = "keyspaces"; public static final String TABLES = "tables"; public static final String COLUMNS = "columns"; + public static final String DROPPED_COLUMNS = "dropped_columns"; public static final String TRIGGERS = "triggers"; public static final String TYPES = "types"; public static final String FUNCTIONS = "functions"; @@ -97,7 +98,6 @@ public final class SchemaKeyspace "CREATE TABLE %s (" + "keyspace_name text," + "table_name text," - + "id uuid," + "bloom_filter_fp_chance double," + "caching map<text, text>," + "comment text," @@ -107,16 +107,12 @@ public final class SchemaKeyspace + "default_time_to_live int," + "flags set<text>," // SUPER, COUNTER, DENSE, COMPOUND + "gc_grace_seconds int," + + "id uuid," + "max_index_interval int," + "memtable_flush_period_in_ms int," + "min_index_interval int," + "read_repair_chance double," + "speculative_retry text," - - // TODO: move into a separate table - + "dropped_columns map<text, bigint>," - + "dropped_columns_types map<text, text>," - + "PRIMARY KEY ((keyspace_name), table_name))"); private static final CFMetaData Columns = @@ -135,6 +131,17 @@ public final class SchemaKeyspace + "validator text," + "PRIMARY KEY ((keyspace_name), table_name, column_name))"); + private static final CFMetaData DroppedColumns = + compile(DROPPED_COLUMNS, + "dropped column registry", + "CREATE TABLE %s (" + + "keyspace_name text," + + "table_name text," + + "column_name text," + + "dropped_time timestamp," + + "type text," + + "PRIMARY KEY ((keyspace_name), table_name, column_name))"); + private static final CFMetaData Triggers = compile(TRIGGERS, "trigger definitions", @@ -186,7 +193,7 @@ public final class SchemaKeyspace + "PRIMARY KEY ((keyspace_name), aggregate_name, signature))"); public static final List<CFMetaData> All = - ImmutableList.of(Keyspaces, Tables, Columns, Triggers, Types, Functions, Aggregates); + ImmutableList.of(Keyspaces, Tables, Columns, DroppedColumns, Triggers, Types, Functions, Aggregates); private static CFMetaData compile(String name, String description, String schema) { @@ -810,27 +817,20 @@ public final class SchemaKeyspace .map("caching", table.getCaching().asMap()) .map("compaction", buildCompactionMap(table)) .map("compression", table.compressionParameters().asMap()) - .set("flags", flagsToStrings(table.flags())); - - for (Map.Entry<ByteBuffer, CFMetaData.DroppedColumn> entry : table.getDroppedColumns().entrySet()) - { - String name = UTF8Type.instance.getString(entry.getKey()); - CFMetaData.DroppedColumn column = entry.getValue(); - adder.addMapEntry("dropped_columns", name, column.droppedTime); - if (column.type != null) - adder.addMapEntry("dropped_columns_types", name, column.type.toString()); - } + .set("flags", flagsToStrings(table.flags())) + .build(); if (withColumnsAndTriggers) { for (ColumnDefinition column : table.allColumns()) addColumnToSchemaMutation(table, column, timestamp, mutation); + for (CFMetaData.DroppedColumn column : table.getDroppedColumns().values()) + addDroppedColumnToSchemaMutation(table, column, timestamp, mutation); + for (TriggerMetadata trigger : table.getTriggers()) addTriggerToSchemaMutation(table, trigger, timestamp, mutation); } - - adder.build(); } /* @@ -885,7 +885,7 @@ public final class SchemaKeyspace { // Thrift only knows about the REGULAR ColumnDefinition type, so don't consider other type // are being deleted just because they are not here. - if (fromThrift && column.kind != ColumnDefinition.Kind.REGULAR) + if (fromThrift && column.kind != ColumnDefinition.Kind.REGULAR) // TODO FIXME continue; dropColumnFromSchemaMutation(oldTable, column, timestamp, mutation); @@ -899,6 +899,18 @@ public final class SchemaKeyspace for (ByteBuffer name : columnDiff.entriesDiffering().keySet()) addColumnToSchemaMutation(newTable, newTable.getColumnDefinition(name), timestamp, mutation); + // dropped columns + MapDifference<ByteBuffer, CFMetaData.DroppedColumn> droppedColumnDiff = + Maps.difference(oldTable.getDroppedColumns(), newTable.getDroppedColumns()); + + // newly dropped columns + for (CFMetaData.DroppedColumn column : droppedColumnDiff.entriesOnlyOnRight().values()) + addDroppedColumnToSchemaMutation(newTable, column, timestamp, mutation); + + // columns added then dropped again + for (ByteBuffer name : droppedColumnDiff.entriesDiffering().keySet()) + addDroppedColumnToSchemaMutation(newTable, newTable.getDroppedColumns().get(name), timestamp, mutation); + MapDifference<String, TriggerMetadata> triggerDiff = triggersDiff(oldTable.getTriggers(), newTable.getTriggers()); // dropped triggers @@ -994,10 +1006,14 @@ public final class SchemaKeyspace List<ColumnDefinition> columns = readSchemaPartitionForTableAndApply(COLUMNS, keyspace, table, SchemaKeyspace::createColumnsFromColumnsPartition); + Map<ByteBuffer, CFMetaData.DroppedColumn> droppedColumns = + readSchemaPartitionForTableAndApply(DROPPED_COLUMNS, keyspace, table, SchemaKeyspace::createDroppedColumnsFromDroppedColumnsPartition); + Triggers triggers = readSchemaPartitionForTableAndApply(TRIGGERS, keyspace, table, SchemaKeyspace::createTriggersFromTriggersPartition); - return createTableFromTableRowAndColumns(row, columns).triggers(triggers); + return createTableFromTableRowAndColumns(row, columns).droppedColumns(droppedColumns) + .triggers(triggers); } public static CFMetaData createTableFromTableRowAndColumns(UntypedResultSet.Row row, List<ColumnDefinition> columns) @@ -1046,14 +1062,6 @@ public final class SchemaKeyspace .readRepairChance(row.getDouble("read_repair_chance")) .speculativeRetry(CFMetaData.SpeculativeRetry.fromString(row.getString("speculative_retry"))); - if (row.has("dropped_columns")) - { - Map<String, String> types = row.has("dropped_columns_types") - ? row.getTextMap("dropped_columns_types") - : Collections.<String, String>emptyMap(); - addDroppedColumns(cfm, row.getMap("dropped_columns", UTF8Type.instance, LongType.instance), types); - } - return cfm; } @@ -1073,17 +1081,6 @@ public final class SchemaKeyspace .collect(toSet()); } - private static void addDroppedColumns(CFMetaData cfm, Map<String, Long> droppedTimes, Map<String, String> types) - { - for (Map.Entry<String, Long> entry : droppedTimes.entrySet()) - { - String name = entry.getKey(); - long time = entry.getValue(); - AbstractType<?> type = types.containsKey(name) ? TypeParser.parse(types.get(name)) : null; - cfm.getDroppedColumns().put(UTF8Type.instance.decompose(name), new CFMetaData.DroppedColumn(type, time)); - } - } - /* * Column metadata serialization/deserialization. */ @@ -1146,6 +1143,44 @@ public final class SchemaKeyspace } /* + * Dropped column metadata serialization/deserialization. + */ + + private static void addDroppedColumnToSchemaMutation(CFMetaData table, CFMetaData.DroppedColumn column, long timestamp, Mutation mutation) + { + RowUpdateBuilder adder = new RowUpdateBuilder(DroppedColumns, timestamp, mutation).clustering(table.cfName, column.name); + + adder.add("dropped_time", new Date(TimeUnit.MICROSECONDS.toMillis(column.droppedTime))) + .add("type", column.type.toString()) + .build(); + } + + private static Map<ByteBuffer, CFMetaData.DroppedColumn> createDroppedColumnsFromDroppedColumnsPartition(RowIterator serializedColumns) + { + String query = String.format("SELECT * FROM %s.%s", NAME, DROPPED_COLUMNS); + Map<ByteBuffer, CFMetaData.DroppedColumn> columns = new HashMap<>(); + for (CFMetaData.DroppedColumn column : createDroppedColumnsFromDroppedColumnRows(QueryProcessor.resultify(query, serializedColumns))) + columns.put(UTF8Type.instance.decompose(column.name), column); + return columns; + } + + private static List<CFMetaData.DroppedColumn> createDroppedColumnsFromDroppedColumnRows(UntypedResultSet rows) + { + List<CFMetaData.DroppedColumn> columns = new ArrayList<>(rows.size()); + rows.forEach(row -> columns.add(createDroppedColumnFromDroppedColumnRow(row))); + return columns; + } + + private static CFMetaData.DroppedColumn createDroppedColumnFromDroppedColumnRow(UntypedResultSet.Row row) + { + String name = row.getString("column_name"); + AbstractType type = TypeParser.parse(row.getString("type")); + long droppedTime = TimeUnit.MILLISECONDS.toMicros(row.getLong("dropped_time")); + + return new CFMetaData.DroppedColumn(name, type, droppedTime); + } + + /* * Trigger metadata serialization/deserialization. */ http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5fa8ce/src/java/org/apache/cassandra/schema/SchemaKeyspace.java.rej ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/schema/SchemaKeyspace.java.rej b/src/java/org/apache/cassandra/schema/SchemaKeyspace.java.rej deleted file mode 100644 index 460fc3a..0000000 --- a/src/java/org/apache/cassandra/schema/SchemaKeyspace.java.rej +++ /dev/null @@ -1,80 +0,0 @@ -diff a/src/java/org/apache/cassandra/schema/SchemaKeyspace.java b/src/java/org/apache/cassandra/schema/SchemaKeyspace.java (rejected hunks) -@@ -1095,68 +1095,32 @@ public final class SchemaKeyspace - .build(); - } - -- private static String serializeKind(ColumnDefinition.Kind kind, boolean isDense) -- { -- // For backward compatibility, we special case CLUSTERING_COLUMN and the case where the table is dense. -- if (kind == ColumnDefinition.Kind.CLUSTERING_COLUMN) -- return "clustering_key"; -- -- if (kind == ColumnDefinition.Kind.REGULAR && isDense) -- return "compact_value"; -- -- return kind.toString().toLowerCase(); -- } -- -- public static ColumnDefinition.Kind deserializeKind(String kind) -- { -- if ("clustering_key".equalsIgnoreCase(kind)) -- return ColumnDefinition.Kind.CLUSTERING_COLUMN; -- if ("compact_value".equalsIgnoreCase(kind)) -- return ColumnDefinition.Kind.REGULAR; -- return Enum.valueOf(ColumnDefinition.Kind.class, kind.toUpperCase()); -- } -- - private static void dropColumnFromSchemaMutation(CFMetaData table, ColumnDefinition column, long timestamp, Mutation mutation) - { - // Note: we do want to use name.toString(), not name.bytes directly for backward compatibility (For CQL3, this won't make a difference). - RowUpdateBuilder.deleteRow(Columns, timestamp, mutation, table.cfName, column.name.toString()); - } - -- private static List<ColumnDefinition> createColumnsFromColumnRows(UntypedResultSet rows, -- String keyspace, -- String table, -- AbstractType<?> rawComparator, -- AbstractType<?> rawSubComparator, -- boolean isSuper, -- boolean isCQLTable) -+ private static List<ColumnDefinition> createColumnsFromColumnRows(UntypedResultSet rows) - { -- List<ColumnDefinition> columns = new ArrayList<>(); -- for (UntypedResultSet.Row row : rows) -- columns.add(createColumnFromColumnRow(row, keyspace, table, rawComparator, rawSubComparator, isSuper, isCQLTable)); -+ List<ColumnDefinition> columns = new ArrayList<>(rows.size()); -+ rows.forEach(row -> columns.add(createColumnFromColumnRow(row))); - return columns; - } - -- private static ColumnDefinition createColumnFromColumnRow(UntypedResultSet.Row row, -- String keyspace, -- String table, -- AbstractType<?> rawComparator, -- AbstractType<?> rawSubComparator, -- boolean isSuper, -- boolean isCQLTable) -+ private static ColumnDefinition createColumnFromColumnRow(UntypedResultSet.Row row) - { -- ColumnDefinition.Kind kind = deserializeKind(row.getString("type")); -+ String keyspace = row.getString("keyspace_name"); -+ String table = row.getString("table_name"); -+ -+ ColumnIdentifier name = ColumnIdentifier.getInterned(row.getBytes("column_name_bytes"), row.getString("column_name")); -+ -+ ColumnDefinition.Kind kind = ColumnDefinition.Kind.valueOf(row.getString("type").toUpperCase()); - - Integer componentIndex = null; - if (row.has("component_index")) - componentIndex = row.getInt("component_index"); - -- // Note: we save the column name as string, but we should not assume that it is an UTF8 name, we -- // we need to use the comparator fromString method -- AbstractType<?> comparator = isCQLTable -- ? UTF8Type.instance -- : CompactTables.columnDefinitionComparator(kind, isSuper, rawComparator, rawSubComparator); -- ColumnIdentifier name = ColumnIdentifier.getInterned(comparator.fromString(row.getString("column_name")), comparator); -- - AbstractType<?> validator = parseType(row.getString("validator")); - - IndexType indexType = null; http://git-wip-us.apache.org/repos/asf/cassandra/blob/1b5fa8ce/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java b/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java index 659b6c6..eb5e5f5 100644 --- a/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java +++ b/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java @@ -241,6 +241,7 @@ public class LegacySchemaMigratorTest + "PRIMARY KEY((bar, baz), qux, quz) ) " + "WITH COMPACT STORAGE", ks_cql)))); + keyspaces.add(keyspaceWithDroppedCollections()); keyspaces.add(keyspaceWithTriggers()); keyspaces.add(keyspaceWithUDTs()); keyspaces.add(keyspaceWithUDFs()); @@ -249,6 +250,32 @@ public class LegacySchemaMigratorTest return keyspaces; } + private static KeyspaceMetadata keyspaceWithDroppedCollections() + { + String keyspace = KEYSPACE_PREFIX + "DroppedCollections"; + + CFMetaData table = + CFMetaData.compile("CREATE TABLE dropped_columns (" + + "foo text," + + "bar text," + + "map1 map<text, text>," + + "map2 map<int, int>," + + "set1 set<ascii>," + + "list1 list<blob>," + + "PRIMARY KEY ((foo), bar))", + keyspace); + + String[] collectionColumnNames = { "map1", "map2", "set1", "list1" }; + for (String name : collectionColumnNames) + { + ColumnDefinition column = table.getColumnDefinition(bytes(name)); + table.recordColumnDrop(column); + table.removeColumnDefinition(column); + } + + return KeyspaceMetadata.create(keyspace, KeyspaceParams.simple(1), Tables.of(table)); + } + private static KeyspaceMetadata keyspaceWithTriggers() { String keyspace = KEYSPACE_PREFIX + "Triggers";
