cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From alek...@apache.org
Subject cassandra git commit: Fix and move dropped columns info to a separate schema table
Date Fri, 17 Jul 2015 21:52:21 GMT
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 <aleksey@apache.org>
Authored: Sat Jul 18 00:52:40 2015 +0300
Committer: Aleksey Yeschenko <aleksey@apache.org>
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";


Mime
View raw message