Merge branch 'cassandra-4.0' into cassandra-4.1

This commit is contained in:
Jon Meredith 2023-05-09 17:47:55 -06:00
commit 7f4e9bb67b
7 changed files with 60 additions and 10 deletions

View File

@ -6,6 +6,7 @@
* Fix COPY ... TO STDOUT behavior in cqlsh (CASSANDRA-18353)
* Remove six and Py2SaferScanner merge cruft (CASSANDRA-18354)
Merged from 4.0:
* NPE when deserializing malformed collections from client (CASSANDRA-18505)
* Improve 'Not enough space for compaction' logging messages (CASSANDRA-18260)
* Incremental repairs fail on mixed IPv4/v6 addresses serializing SyncRequest (CASSANDRA-18474)
* Deadlock updating sstable metadata if disk boundaries need reloading (CASSANDRA-18443)

View File

@ -127,6 +127,14 @@ public abstract class CollectionSerializer<T> extends TypeSerializer<T>
return accessor.slice(input, offset + TypeSizes.INT_SIZE, size);
}
public static <V> V readNonNullValue(V input, ValueAccessor<V> accessor, int offset, ProtocolVersion version)
{
V value = readValue(input, accessor, offset, version);
if (value == null)
throw new MarshalException("Null value read when not allowed");
return value;
}
protected static void skipValue(ByteBuffer input, ProtocolVersion version)
{
int size = input.getInt();

View File

@ -72,7 +72,7 @@ public class ListSerializer<T> extends CollectionSerializer<List<T>>
int offset = sizeOfCollectionSize(n, version);
for (int i = 0; i < n; i++)
{
V value = readValue(input, accessor, offset, version);
V value = readNonNullValue(input, accessor, offset, version);
offset += sizeOfValue(value, accessor, version);
elements.validate(value, accessor);
}
@ -103,7 +103,12 @@ public class ListSerializer<T> extends CollectionSerializer<List<T>>
List<T> l = new ArrayList<T>(Math.min(n, 256));
for (int i = 0; i < n; i++)
{
// We can have nulls in lists that are used for IN values
// CASSANDRA-6839: "We can have nulls in lists that are used for IN values"
// CASSANDRA-8613 checks IN clauses and throws an exception if null is in the list.
// Leaving for this as-is for now in case there is some unknown use
// for it, but should likely be changed to readNonNull. Validate has been
// changed to throw on null elements as otherwise it would NPE, and it's unclear
// if callers could handle null elements.
V databb = readValue(input, accessor, offset, version);
offset += sizeOfValue(databb, accessor, version);
if (databb != null)

View File

@ -88,11 +88,11 @@ public class MapSerializer<K, V> extends CollectionSerializer<Map<K, V>>
int offset = sizeOfCollectionSize(n, version);
for (int i = 0; i < n; i++)
{
T key = readValue(input, accessor, offset, version);
T key = readNonNullValue(input, accessor, offset, version);
offset += sizeOfValue(key, accessor, version);
keys.validate(key, accessor);
T value = readValue(input, accessor, offset, version);
T value = readNonNullValue(input, accessor, offset, version);
offset += sizeOfValue(value, accessor, version);
values.validate(value, accessor);
}
@ -122,11 +122,11 @@ public class MapSerializer<K, V> extends CollectionSerializer<Map<K, V>>
Map<K, V> m = new LinkedHashMap<K, V>(Math.min(n, 256));
for (int i = 0; i < n; i++)
{
I key = readValue(input, accessor, offset, version);
I key = readNonNullValue(input, accessor, offset, version);
offset += sizeOfValue(key, accessor, version);
keys.validate(key, accessor);
I value = readValue(input, accessor, offset, version);
I value = readNonNullValue(input, accessor, offset, version);
offset += sizeOfValue(value, accessor, version);
values.validate(value, accessor);

View File

@ -79,7 +79,7 @@ public class SetSerializer<T> extends CollectionSerializer<Set<T>>
int offset = sizeOfCollectionSize(n, version);
for (int i = 0; i < n; i++)
{
V value = readValue(input, accessor, offset, version);
V value = readNonNullValue(input, accessor, offset, version);
offset += sizeOfValue(value, accessor, version);
elements.validate(value, accessor);
}
@ -110,7 +110,7 @@ public class SetSerializer<T> extends CollectionSerializer<Set<T>>
for (int i = 0; i < n; i++)
{
V value = readValue(input, accessor, offset, version);
V value = readNonNullValue(input, accessor, offset, version);
offset += sizeOfValue(value, accessor, version);
elements.validate(value, accessor);
l.add(elements.deserialize(value, accessor));

View File

@ -976,7 +976,7 @@ public class CollectionsTest extends CQLTester
createTable("CREATE TABLE %s(pk int PRIMARY KEY, s set<text>)");
assertInvalidMessage("Not enough bytes to read a set",
"INSERT INTO %s (pk, s) VALUES (?, ?)", 1, "test");
assertInvalidMessage("String didn't validate.",
assertInvalidMessage("Null value read when not allowed",
"INSERT INTO %s (pk, s) VALUES (?, ?)", 1, Long.MAX_VALUE);
assertInvalidMessage("Not enough bytes to read a set",
"INSERT INTO %s (pk, s) VALUES (?, ?)", 1, "");
@ -990,7 +990,7 @@ public class CollectionsTest extends CQLTester
createTable("CREATE TABLE %s(pk int PRIMARY KEY, m map<text, text>)");
assertInvalidMessage("Not enough bytes to read a map",
"INSERT INTO %s (pk, m) VALUES (?, ?)", 1, "test");
assertInvalidMessage("String didn't validate.",
assertInvalidMessage("Null value read when not allowed",
"INSERT INTO %s (pk, m) VALUES (?, ?)", 1, Long.MAX_VALUE);
assertInvalidMessage("Not enough bytes to read a map",
"INSERT INTO %s (pk, m) VALUES (?, ?)", 1, "");

View File

@ -34,6 +34,7 @@ import org.apache.cassandra.cql3.*;
import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.db.marshal.*;
import org.apache.cassandra.serializers.CollectionSerializer;
import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.QueryState;
import org.apache.cassandra.transport.Event.TopologyChange;
@ -107,6 +108,41 @@ public class SerDeserTest
assertEquals(m, mt.getSerializer().deserializeForNativeProtocol(CollectionSerializer.pack(mb, m.size(), version), version));
}
@Test(expected = MarshalException.class)
public void setsMayNotContainNullsTest()
{
ProtocolVersion version = ProtocolVersion.MIN_SUPPORTED_VERSION;
SetType<?> st = SetType.getInstance(UTF8Type.instance, true);
List<ByteBuffer> sb = new ArrayList<>(1);
sb.add(null);
st.getSerializer().deserializeForNativeProtocol(CollectionSerializer.pack(sb, sb.size(), version), version);
}
@Test(expected = MarshalException.class)
public void mapKeysMayNotContainNullsTest()
{
ProtocolVersion version = ProtocolVersion.MIN_SUPPORTED_VERSION;
MapType<?, ?> mt = MapType.getInstance(UTF8Type.instance, LongType.instance, true);
List<ByteBuffer> mb = new ArrayList<>(2);
mb.add(null);
mb.add(LongType.instance.decompose(999L));
mt.getSerializer().deserializeForNativeProtocol(CollectionSerializer.pack(mb, mb.size(), version), version);
}
@Test(expected = MarshalException.class)
public void mapValueMayNotContainNullsTest()
{
ProtocolVersion version = ProtocolVersion.MIN_SUPPORTED_VERSION;
MapType<?, ?> mt = MapType.getInstance(UTF8Type.instance, LongType.instance, true);
List<ByteBuffer> mb = new ArrayList<>(2);
mb.add(UTF8Type.instance.decompose("danger"));
mb.add(null);
mt.getSerializer().deserializeForNativeProtocol(CollectionSerializer.pack(mb, mb.size(), version), version);
}
@Test
public void eventSerDeserTest() throws Exception
{