diff --git a/CHANGES.txt b/CHANGES.txt index 41ed08f0f8..e14e6cf3fe 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -97,8 +97,8 @@ * fix nodetool names that reference column families (CASSANDRA-8872) 2.1.5 - * Update collection types that use a user-defined type when that UDT is - modified (CASSANDRA-9148) + * Update tuple and collection types that use a user-defined type when that UDT + is modified (CASSANDRA-9148, CASSANDRA-9192) * Re-add deprecated cold_reads_to_omit param for backwards compat (CASSANDRA-9203) * Make anticompaction visible in compactionstats (CASSANDRA-9098) * Improve nodetool getendpoints documentation about the partition diff --git a/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java b/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java index 0b64f94851..74fafd67a8 100644 --- a/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/AlterTypeStatement.java @@ -191,6 +191,12 @@ public abstract class AlterTypeStatement extends SchemaAlteringStatement List> updatedTypes = updateTypes(ut.fieldTypes(), keyspace, toReplace, updated); return updatedTypes == null ? null : new UserType(ut.keyspace, ut.name, new ArrayList<>(ut.fieldNames()), updatedTypes); } + else if (type instanceof TupleType) + { + TupleType tt = (TupleType)type; + List> updatedTypes = updateTypes(tt.allTypes(), keyspace, toReplace, updated); + return updatedTypes == null ? null : new TupleType(updatedTypes); + } else if (type instanceof CompositeType) { CompositeType ct = (CompositeType)type; diff --git a/test/unit/org/apache/cassandra/cql3/UserTypesTest.java b/test/unit/org/apache/cassandra/cql3/UserTypesTest.java index 4055d30ce4..bfd3e9f318 100644 --- a/test/unit/org/apache/cassandra/cql3/UserTypesTest.java +++ b/test/unit/org/apache/cassandra/cql3/UserTypesTest.java @@ -237,4 +237,98 @@ public class UserTypesTest extends CQLTester row(4, list(userType(null, 4)))); } } + + @Test + public void testAlteringUserTypeNestedWithinTuple() throws Throwable + { + String type = createType("CREATE TYPE %s (a int, b int)"); + + createTable("CREATE TABLE %s (a int PRIMARY KEY, b frozen>)"); + + execute("INSERT INTO %s (a, b) VALUES(1, (1, {a:1, b:1}))"); + assertRows(execute("SELECT * FROM %s"), row(1, tuple(1, userType(1, 1)))); + flush(); + + execute("ALTER TYPE " + KEYSPACE + "." + type + " ADD c int"); + execute("INSERT INTO %s (a, b) VALUES(2, (2, {a: 2, b: 2, c: 2}))"); + execute("INSERT INTO %s (a, b) VALUES(3, (3, {a: 3, b: 3}))"); + execute("INSERT INTO %s (a, b) VALUES(4, (4, {b:4}))"); + + assertRows(execute("SELECT * FROM %s"), + row(1, tuple(1, userType(1, 1))), + row(2, tuple(2, userType(2, 2, 2))), + row(3, tuple(3, userType(3, 3, null))), + row(4, tuple(4, userType(null, 4, null)))); + + flush(); + + assertRows(execute("SELECT * FROM %s"), + row(1, tuple(1, userType(1, 1))), + row(2, tuple(2, userType(2, 2, 2))), + row(3, tuple(3, userType(3, 3, null))), + row(4, tuple(4, userType(null, 4, null)))); + } + + @Test + public void testAlteringUserTypeNestedWithinNestedTuple() throws Throwable + { + String type = createType("CREATE TYPE %s (a int, b int)"); + + createTable("CREATE TABLE %s (a int PRIMARY KEY, b frozen>>)"); + + execute("INSERT INTO %s (a, b) VALUES(1, (1, (1, {a:1, b:1})))"); + assertRows(execute("SELECT * FROM %s"), row(1, tuple(1, tuple(1, userType(1, 1))))); + flush(); + + execute("ALTER TYPE " + KEYSPACE + "." + type + " ADD c int"); + execute("INSERT INTO %s (a, b) VALUES(2, (2, (1, {a: 2, b: 2, c: 2})))"); + execute("INSERT INTO %s (a, b) VALUES(3, (3, (1, {a: 3, b: 3})))"); + execute("INSERT INTO %s (a, b) VALUES(4, (4, (1, {b:4})))"); + + assertRows(execute("SELECT * FROM %s"), + row(1, tuple(1, tuple(1, userType(1, 1)))), + row(2, tuple(2, tuple(1, userType(2, 2, 2)))), + row(3, tuple(3, tuple(1, userType(3, 3, null)))), + row(4, tuple(4, tuple(1, userType(null, 4, null))))); + + flush(); + + assertRows(execute("SELECT * FROM %s"), + row(1, tuple(1, tuple(1, userType(1, 1)))), + row(2, tuple(2, tuple(1, userType(2, 2, 2)))), + row(3, tuple(3, tuple(1, userType(3, 3, null)))), + row(4, tuple(4, tuple(1, userType(null, 4, null))))); + } + + @Test + public void testAlteringUserTypeNestedWithinUserType() throws Throwable + { + String type = createType("CREATE TYPE %s (a int, b int)"); + String otherType = createType("CREATE TYPE %s (x frozen<" + KEYSPACE + "." + type + ">)"); + + createTable("CREATE TABLE %s (a int PRIMARY KEY, b frozen<" + KEYSPACE + "." + otherType + ">)"); + + execute("INSERT INTO %s (a, b) VALUES(1, {x: {a:1, b:1}})"); + assertRows(execute("SELECT b.x.a, b.x.b FROM %s"), row(1, 1)); + flush(); + + execute("ALTER TYPE " + KEYSPACE + "." + type + " ADD c int"); + execute("INSERT INTO %s (a, b) VALUES(2, {x: {a: 2, b: 2, c: 2}})"); + execute("INSERT INTO %s (a, b) VALUES(3, {x: {a: 3, b: 3}})"); + execute("INSERT INTO %s (a, b) VALUES(4, {x: {b:4}})"); + + assertRows(execute("SELECT b.x.a, b.x.b, b.x.c FROM %s"), + row(1, 1, null), + row(2, 2, 2), + row(3, 3, null), + row(null, 4, null)); + + flush(); + + assertRows(execute("SELECT b.x.a, b.x.b, b.x.c FROM %s"), + row(1, 1, null), + row(2, 2, 2), + row(3, 3, null), + row(null, 4, null)); + } }