Skip to content

Commit 0374390

Browse files
authored
Merge pull request scylladb#26 from riptano/python-1123
PYTHON-1123: Support NULL in collection deserializer
2 parents e2c5873 + 90a231f commit 0374390

File tree

3 files changed

+64
-10
lines changed

3 files changed

+64
-10
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Features
1111
* Remove *read_repair_chance table options (PYTHON-1140)
1212
* Flexible version parsing (PYTHON-1174)
1313
* [GRAPH] Ability to execute Fluent Graph queries asynchronously (PYTHON-1129)
14+
* Support NULL in collection deserializer (PYTHON-1123)
1415
1516
Bug Fixes
1617
---------

cassandra/cqltypes.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -813,9 +813,12 @@ def deserialize_safe(cls, byts, protocol_version):
813813
for _ in range(numelements):
814814
itemlen = unpack(byts[p:p + length])
815815
p += length
816-
item = byts[p:p + itemlen]
817-
p += itemlen
818-
result.append(subtype.from_binary(item, inner_proto))
816+
if itemlen < 0:
817+
result.append(None)
818+
else:
819+
item = byts[p:p + itemlen]
820+
p += itemlen
821+
result.append(subtype.from_binary(item, inner_proto))
819822
return cls.adapter(result)
820823

821824
@classmethod
@@ -867,14 +870,23 @@ def deserialize_safe(cls, byts, protocol_version):
867870
for _ in range(numelements):
868871
key_len = unpack(byts[p:p + length])
869872
p += length
870-
keybytes = byts[p:p + key_len]
871-
p += key_len
873+
if key_len < 0:
874+
keybytes = None
875+
key = None
876+
else:
877+
keybytes = byts[p:p + key_len]
878+
p += key_len
879+
key = key_type.from_binary(keybytes, inner_proto)
880+
872881
val_len = unpack(byts[p:p + length])
873882
p += length
874-
valbytes = byts[p:p + val_len]
875-
p += val_len
876-
key = key_type.from_binary(keybytes, inner_proto)
877-
val = value_type.from_binary(valbytes, inner_proto)
883+
if val_len < 0:
884+
val = None
885+
else:
886+
valbytes = byts[p:p + val_len]
887+
p += val_len
888+
val = value_type.from_binary(valbytes, inner_proto)
889+
878890
themap._insert_unchecked(key, keybytes, val)
879891
return themap
880892

tests/unit/test_types.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
CassandraType, DateRangeType, DateType, DecimalType,
3030
EmptyValue, LongType, SetType, UTF8Type,
3131
cql_typename, int8_pack, int64_pack, lookup_casstype,
32-
lookup_casstype_simple, parse_casstype_args
32+
lookup_casstype_simple, parse_casstype_args,
33+
int32_pack, Int32Type, ListType, MapType
3334
)
3435
from cassandra.encoder import cql_quote
3536
from cassandra.pool import Host
@@ -226,6 +227,46 @@ def test_datetype(self):
226227
expected = 2177403010.123
227228
self.assertEqual(DateType.deserialize(int64_pack(int(1000 * expected)), 0), datetime.datetime(2038, 12, 31, 10, 10, 10, 123000))
228229

230+
def test_collection_null_support(self):
231+
"""
232+
Test that null values in collection are decoded properly.
233+
234+
@jira_ticket PYTHON-1123
235+
"""
236+
int_list = ListType.apply_parameters([Int32Type])
237+
value = (
238+
int32_pack(2) + # num items
239+
int32_pack(-1) + # size of item1
240+
int32_pack(4) + # size of item2
241+
int32_pack(42) # item2
242+
)
243+
self.assertEqual(
244+
[None, 42],
245+
int_list.deserialize(value, 3)
246+
)
247+
248+
set_list = SetType.apply_parameters([Int32Type])
249+
self.assertEqual(
250+
{None, 42},
251+
set(set_list.deserialize(value, 3))
252+
)
253+
254+
value = (
255+
int32_pack(2) + # num items
256+
int32_pack(4) + # key size of item1
257+
int32_pack(42) + # key item1
258+
int32_pack(-1) + # value size of item1
259+
int32_pack(-1) + # key size of item2
260+
int32_pack(4) + # value size of item2
261+
int32_pack(42) # value of item2
262+
)
263+
264+
map_list = MapType.apply_parameters([Int32Type, Int32Type])
265+
self.assertEqual(
266+
[(42, None), (None, 42)],
267+
map_list.deserialize(value, 3)._items # OrderedMapSerializedKey
268+
)
269+
229270
def test_write_read_string(self):
230271
with tempfile.TemporaryFile() as f:
231272
value = u'test'

0 commit comments

Comments
 (0)