Bug: Collection types written via prepared statement not checked for nulls
Status: Triage Needed
Priority: Normal
Created: 06/Jul/20 10:35

To reproduce:
{code:java}
>>> cluster = Cluster()

>>> session = cluster.connect()

>>> session.execute("create keyspace frozen_int_test with replication = {'class': 'SimpleStrategy', 'replication_factor': 1}")

>>> session.execute("create table frozen_int_test.mytable (id int primary key, value frozen<list<int>>)")

>>> session.execute(session.prepare("insert into frozen_int_test.mytable (id, value) values (?, ?)"), (1, [1,2,3]))

>>> list(session.execute("select * from frozen_int_test.mytable"))
[Row(id=1, value=[1, 2, 3])]

>>> session.execute(session.prepare("insert into frozen_int_test.mytable (id, value) values (?, ?)"), (1, [1,2,None]))

>>> list(session.execute("select * from frozen_int_test.mytable"))
[Row(id=1, value=[1, 2, None])] {code}
Now you might say "But Tom, that just shows that it works!", but this does not work as a CQL literal:
{code:java}
>>> session.execute("insert into frozen_int_test.mytable (id, value) values (1, [1,2,null])")
[...] cassandra.InvalidRequest: Error from server: code=2200 [Invalid query] message="null is not supported inside collections" {code}
Worse, if a mutation like this makes it way into the hints, it will be retried indefinitely as it fails validation with a NullPointerException:
{code:java}
ERROR [MutationStage-11] 2020-07-06 09:23:25,696 AbstractLocalAwareExecutorService.java:169 - Uncaught exception on thread Thread[MutationStage-11,5,main]
java.lang.NullPointerException: null
    at org.apache.cassandra.serializers.Int32Serializer.validate(Int32Serializer.java:41) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.serializers.ListSerializer.validateForNativeProtocol(ListSerializer.java:70) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.serializers.CollectionSerializer.validate(CollectionSerializer.java:56) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.db.marshal.AbstractType.validate(AbstractType.java:162) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.db.marshal.AbstractType.validateCellValue(AbstractType.java:196) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.db.marshal.CollectionType.validateCellValue(CollectionType.java:124) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.config.ColumnDefinition.validateCell(ColumnDefinition.java:410) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.db.rows.AbstractCell.validate(AbstractCell.java:154) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.db.partitions.PartitionUpdate.validate(PartitionUpdate.java:486) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at java.util.Collections$SingletonSet.forEach(Collections.java:4769) ~[na:1.8.0_252]
    at org.apache.cassandra.hints.HintVerbHandler.doVerb(HintVerbHandler.java:69) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.net.MessageDeliveryTask.run(MessageDeliveryTask.java:66) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[na:1.8.0_252]
    at org.apache.cassandra.concurrent.AbstractLocalAwareExecutorService$FutureTask.run(AbstractLocalAwareExecutorService.java:165) ~[apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.concurrent.AbstractLocalAwareExecutorService$LocalSessionFutureTask.run(AbstractLocalAwareExecutorService.java:137) [apache-cassandra-3.11.6.jar:3.11.6]
    at org.apache.cassandra.concurrent.SEPWorker.run(SEPWorker.java:113) [apache-cassandra-3.11.6.jar:3.11.6]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_252] {code}
A similar problem is reproducible when writing into a non-frozen column.