Skip to content

Commit efa0ead

Browse files
committed
Merge branch 'cassandra-4.0' into cassandra-4.1
2 parents c79f176 + 4c33f1f commit efa0ead

File tree

5 files changed

+89
-7
lines changed

5 files changed

+89
-7
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* ReadCommandController should close fast to avoid deadlock when building secondary index (CASSANDRA-19564)
44
* Redact security-sensitive information in system_views.settings (CASSANDRA-20856)
55
Merged from 4.0:
6+
* Restrict BytesType compatibility to scalar types only (CASSANDRA-20982)
67
* Backport fix to nodetool gcstats output for direct memory (CASSANDRA-21037)
78
* ArrayIndexOutOfBoundsException with repaired data tracking and counters (CASSANDRA-20871)
89
* Fix cleanup of old incremental repair sessions in case of owned token range changes or a table deleting (CASSANDRA-20877)

src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,10 @@ private void addColumn(KeyspaceMetadata keyspace,
240240
// columns is pushed deeper down the line. The latter would still be problematic in cases of schema races.
241241
if (!type.isSerializationCompatibleWith(droppedColumn.type))
242242
{
243-
throw ire("Cannot re-add previously dropped column '%s' of type %s, incompatible with previous type %s",
243+
throw ire("Cannot add a column '%s' of type %s, incompatible with previously dropped column '%s' of type %s",
244244
name,
245245
type.asCQL3Type(),
246+
name,
246247
droppedColumn.type.asCQL3Type());
247248
}
248249

src/java/org/apache/cassandra/db/marshal/BytesType.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@ public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
8585
return true;
8686
}
8787

88+
@Override
89+
public boolean isSerializationCompatibleWith(AbstractType<?> previous)
90+
{
91+
// BytesType should only be compatible with simple scalar types, not with collections or UDTs
92+
// because converting a collection or UDT to raw bytes is nonsensical
93+
return !previous.isCollection() && !previous.isUDT() && super.isSerializationCompatibleWith(previous);
94+
}
95+
8896
public CQL3Type asCQL3Type()
8997
{
9098
return CQL3Type.Native.BLOB;

test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,29 +59,30 @@ public void testNonFrozenCollectionsAreIncompatibleWithBlob() throws Throwable
5959
{
6060
createTable("CREATE TABLE %s (a int, b " + type + ", PRIMARY KEY (a));");
6161
alterTable("ALTER TABLE %s DROP b;");
62-
assertInvalidMessage("Cannot re-add previously dropped column 'b' of type blob, incompatible with previous type " + type,
62+
assertInvalidMessage("Cannot add a column 'b' of type blob, incompatible with previously dropped column 'b' of type " + type,
6363
"ALTER TABLE %s ADD b blob;");
6464
}
6565

6666
for (String type : collectionTypes)
6767
{
6868
createTable("CREATE TABLE %s (a int, b blob, PRIMARY KEY (a));");
6969
alterTable("ALTER TABLE %s DROP b;");
70-
assertInvalidMessage("Cannot re-add previously dropped column 'b' of type " + type + ", incompatible with previous type blob",
70+
assertInvalidMessage("Cannot add a column 'b' of type " + type + ", incompatible with previously dropped column 'b' of type blob",
7171
"ALTER TABLE %s ADD b " + type + ';');
7272
}
7373
}
7474

7575
@Test
76-
public void testFrozenCollectionsAreCompatibleWithBlob()
76+
public void testFrozenCollectionsAreNotCompatibleWithBlob() throws Throwable
7777
{
7878
String[] collectionTypes = new String[] {"frozen<map<int, int>>", "frozen<set<int>>", "frozen<list<int>>"};
7979

8080
for (String type : collectionTypes)
8181
{
8282
createTable("CREATE TABLE %s (a int, b " + type + ", PRIMARY KEY (a));");
8383
alterTable("ALTER TABLE %s DROP b;");
84-
alterTable("ALTER TABLE %s ADD b blob;");
84+
assertInvalidMessage("Cannot add a column 'b' of type blob, incompatible with previously dropped column 'b' of type " + type,
85+
"ALTER TABLE %s ADD b blob;");
8586
}
8687
}
8788

@@ -561,8 +562,8 @@ public void testInvalidDroppingAndAddingOfCollections() throws Throwable
561562
{
562563
createTable("create table %s (k int, c int, v " + typePair[0] + ", PRIMARY KEY (k, c))");
563564
execute("alter table %s drop v");
564-
assertInvalidMessage("Cannot re-add previously dropped column 'v' of type "
565-
+ typePair[1] + ", incompatible with previous type " + typePair[0],
565+
assertInvalidMessage("Cannot add a column 'v' of type "
566+
+ typePair[1] + ", incompatible with previously dropped column 'v' of type " + typePair[0],
566567
"alter table %s add v " + typePair[1]);
567568
}
568569
}

test/unit/org/apache/cassandra/db/marshal/BytesTypeTest.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,16 @@
1919
*/
2020
package org.apache.cassandra.db.marshal;
2121

22+
import java.util.Arrays;
23+
24+
import org.apache.cassandra.cql3.FieldIdentifier;
2225
import org.apache.cassandra.serializers.MarshalException;
26+
import org.apache.cassandra.utils.ByteBufferUtil;
2327
import org.junit.Test;
2428

29+
import static org.junit.Assert.assertFalse;
30+
import static org.junit.Assert.assertTrue;
31+
2532
public class BytesTypeTest
2633
{
2734
private static final String INVALID_HEX = "33AG45F"; // Invalid (has a G)
@@ -38,4 +45,68 @@ public void testFromStringWithValidString()
3845
{
3946
BytesType.instance.fromString(VALID_HEX);
4047
}
48+
49+
@Test
50+
public void testValueCompatibilityWithScalarTypes()
51+
{
52+
// BytesType should be value-compatible with simple scalar types
53+
assertTrue("BytesType should be value-compatible with AsciiType",
54+
BytesType.instance.isValueCompatibleWith(AsciiType.instance));
55+
assertTrue("BytesType should be value-compatible with UTF8Type",
56+
BytesType.instance.isValueCompatibleWith(UTF8Type.instance));
57+
assertTrue("BytesType should be value-compatible with Int32Type",
58+
BytesType.instance.isValueCompatibleWith(Int32Type.instance));
59+
assertTrue("BytesType should be value-compatible with LongType",
60+
BytesType.instance.isValueCompatibleWith(LongType.instance));
61+
assertTrue("BytesType should be value-compatible with UUIDType",
62+
BytesType.instance.isValueCompatibleWith(UUIDType.instance));
63+
assertTrue("BytesType should be value-compatible with BooleanType",
64+
BytesType.instance.isValueCompatibleWith(BooleanType.instance));
65+
assertTrue("BytesType should be value-compatible with itself",
66+
BytesType.instance.isValueCompatibleWith(BytesType.instance));
67+
}
68+
69+
@Test
70+
public void testSerializationIncompatibilityWithCollections()
71+
{
72+
// BytesType should NOT be serialization-compatible with collections (even frozen ones)
73+
// because converting a collection to raw bytes for schema changes is nonsensical
74+
ListType<?> frozenList = ListType.getInstance(Int32Type.instance, false);
75+
SetType<?> frozenSet = SetType.getInstance(Int32Type.instance, false);
76+
MapType<?, ?> frozenMap = MapType.getInstance(Int32Type.instance, UTF8Type.instance, false);
77+
78+
assertFalse("BytesType should NOT be serialization-compatible with frozen<list>",
79+
BytesType.instance.isSerializationCompatibleWith(frozenList));
80+
assertFalse("BytesType should NOT be serialization-compatible with frozen<set>",
81+
BytesType.instance.isSerializationCompatibleWith(frozenSet));
82+
assertFalse("BytesType should NOT be serialization-compatible with frozen<map>",
83+
BytesType.instance.isSerializationCompatibleWith(frozenMap));
84+
85+
// Also test with multi-cell collections
86+
ListType<?> multiCellList = ListType.getInstance(Int32Type.instance, true);
87+
SetType<?> multiCellSet = SetType.getInstance(Int32Type.instance, true);
88+
MapType<?, ?> multiCellMap = MapType.getInstance(Int32Type.instance, UTF8Type.instance, true);
89+
90+
assertFalse("BytesType should NOT be serialization-compatible with list",
91+
BytesType.instance.isSerializationCompatibleWith(multiCellList));
92+
assertFalse("BytesType should NOT be serialization-compatible with set",
93+
BytesType.instance.isSerializationCompatibleWith(multiCellSet));
94+
assertFalse("BytesType should NOT be serialization-compatible with map",
95+
BytesType.instance.isSerializationCompatibleWith(multiCellMap));
96+
}
97+
98+
@Test
99+
public void testSerializationIncompatibilityWithUDT()
100+
{
101+
// BytesType should NOT be serialization-compatible with User Defined Types
102+
// because converting a UDT to raw bytes for schema changes is nonsensical
103+
UserType udt = new UserType("ks",
104+
ByteBufferUtil.bytes("myType"),
105+
Arrays.asList(FieldIdentifier.forQuoted("field1"), FieldIdentifier.forQuoted("field2")),
106+
Arrays.asList(Int32Type.instance, UTF8Type.instance),
107+
true);
108+
109+
assertFalse("BytesType should NOT be serialization-compatible with UDT",
110+
BytesType.instance.isSerializationCompatibleWith(udt));
111+
}
41112
}

0 commit comments

Comments
 (0)