diff --git a/CHANGES.txt b/CHANGES.txt index 179d9cf436..60fa830983 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,6 +6,8 @@ * Reduce info logging from automatic paxos repair (CASSANDRA-19445) * Support legacy plain_text_auth section in credentials file removed unintentionally (CASSANDRA-19498) Merged from 4.0: + * Fix schema.cql created by a snapshot after dropping more than one column (CASSANDRA-19747) + * UnsupportedOperationException when reducing scope for LCS compactions (CASSANDRA-19704) * Make LWT conditions behavior on frozen and non-frozen columns consistent for null column values (CASSANDRA-19637) * Add timeout specifically for bootstrapping nodes (CASSANDRA-15439) * Bring Redhat packge dirs/ownership/perms in line with Debian package (CASSANDRA-19565) diff --git a/src/java/org/apache/cassandra/schema/TableMetadata.java b/src/java/org/apache/cassandra/schema/TableMetadata.java index 2e9d507ba9..d1e26d20ce 100644 --- a/src/java/org/apache/cassandra/schema/TableMetadata.java +++ b/src/java/org/apache/cassandra/schema/TableMetadata.java @@ -1255,7 +1255,7 @@ public class TableMetadata implements SchemaElement DroppedColumn dropped = iterDropped.next(); dropped.column.appendCqlTo(builder); - if (!hasSingleColumnPrimaryKey || iter.hasNext()) + if (!hasSingleColumnPrimaryKey || iterDropped.hasNext()) builder.append(','); builder.newLine(); diff --git a/test/unit/org/apache/cassandra/db/SchemaCQLHelperTest.java b/test/unit/org/apache/cassandra/db/SchemaCQLHelperTest.java index 63ef861101..f9a9190002 100644 --- a/test/unit/org/apache/cassandra/db/SchemaCQLHelperTest.java +++ b/test/unit/org/apache/cassandra/db/SchemaCQLHelperTest.java @@ -452,6 +452,90 @@ public class SchemaCQLHelperTest extends CQLTester Assert.assertEquals(2, files.size()); } + @Test + public void testSnapshotWithDroppedColumnsWithoutReAdding() throws Throwable + { + String tableName = createTable("CREATE TABLE IF NOT EXISTS %s (" + + "pk1 varint," + + "pk2 ascii," + + "ck1 varint," + + "ck2 varint," + + "reg1 int," + + "reg2 int," + + "reg3 int," + + "PRIMARY KEY ((pk1, pk2), ck1, ck2)) WITH " + + "CLUSTERING ORDER BY (ck1 ASC, ck2 DESC);"); + + alterTable("ALTER TABLE %s DROP reg2 USING TIMESTAMP 10000;"); + alterTable("ALTER TABLE %s DROP reg3 USING TIMESTAMP 10000;"); + + for (int i = 0; i < 10; i++) + execute("INSERT INTO %s (pk1, pk2, ck1, ck2, reg1) VALUES (?, ?, ?, ?, ?)", i, i + 1, i + 2, i + 3, null); + + ColumnFamilyStore cfs = Keyspace.open(keyspace()).getColumnFamilyStore(tableName); + cfs.snapshot(SNAPSHOT); + + String schema = Files.toString(cfs.getDirectories().getSnapshotSchemaFile(SNAPSHOT).toJavaIOFile(), Charset.defaultCharset()); + schema = schema.substring(schema.indexOf("CREATE TABLE")); // trim to ensure order + String expected = "CREATE TABLE IF NOT EXISTS " + keyspace() + "." + tableName + " (\n" + + " pk1 varint,\n" + + " pk2 ascii,\n" + + " ck1 varint,\n" + + " ck2 varint,\n" + + " reg1 int,\n" + + " reg3 int,\n" + + " reg2 int,\n" + + " PRIMARY KEY ((pk1, pk2), ck1, ck2)\n" + + ") WITH ID = " + cfs.metadata.id + "\n" + + " AND CLUSTERING ORDER BY (ck1 ASC, ck2 DESC)"; + + assertThat(schema, + allOf(startsWith(expected), + containsString("ALTER TABLE " + keyspace() + "." + tableName + " DROP reg2 USING TIMESTAMP 10000;"), + containsString("ALTER TABLE " + keyspace() + "." + tableName + " DROP reg3 USING TIMESTAMP 10000;"))); + + JSONObject manifest = (JSONObject) new JSONParser().parse(new FileReader(cfs.getDirectories().getSnapshotManifestFile(SNAPSHOT))); + JSONArray files = (JSONArray) manifest.get("files"); + Assert.assertEquals(1, files.size()); + } + + @Test + public void testSnapshotWithDroppedColumnsWithoutReAddingOnSingleKeyTable() throws Throwable + { + String tableName = createTable("CREATE TABLE IF NOT EXISTS %s (" + + "pk1 varint PRIMARY KEY," + + "reg1 int," + + "reg2 int," + + "reg3 int);"); + + alterTable("ALTER TABLE %s DROP reg2 USING TIMESTAMP 10000;"); + alterTable("ALTER TABLE %s DROP reg3 USING TIMESTAMP 10000;"); + + for (int i = 0; i < 10; i++) + execute("INSERT INTO %s (pk1, reg1) VALUES (?, ?)", i, i + 1); + + ColumnFamilyStore cfs = Keyspace.open(keyspace()).getColumnFamilyStore(tableName); + cfs.snapshot(SNAPSHOT); + + String schema = Files.toString(cfs.getDirectories().getSnapshotSchemaFile(SNAPSHOT).toJavaIOFile(), Charset.defaultCharset()); + schema = schema.substring(schema.indexOf("CREATE TABLE")); // trim to ensure order + String expected = "CREATE TABLE IF NOT EXISTS " + keyspace() + "." + tableName + " (\n" + + " pk1 varint PRIMARY KEY,\n" + + " reg1 int,\n" + + " reg3 int,\n" + + " reg2 int\n" + + ") WITH ID = " + cfs.metadata.id + "\n"; + + assertThat(schema, + allOf(startsWith(expected), + containsString("ALTER TABLE " + keyspace() + "." + tableName + " DROP reg2 USING TIMESTAMP 10000;"), + containsString("ALTER TABLE " + keyspace() + "." + tableName + " DROP reg3 USING TIMESTAMP 10000;"))); + + JSONObject manifest = (JSONObject) new JSONParser().parse(new FileReader(cfs.getDirectories().getSnapshotManifestFile(SNAPSHOT))); + JSONArray files = (JSONArray) manifest.get("files"); + Assert.assertEquals(1, files.size()); + } + @Test public void testSystemKsSnapshot() {