When user is trying to delete a row or a few rows using CQL (Cassandra Query Language), the deletion will fail as long as there is a NULL value in any of the columns in the rows to delete.
Similarly, if there is a NULL value in one row, the user cannot retrieve the row using CQL, nor can she use the Range() function.
Critical (new feature in version 0.8.0)
assert ['kd', None, None] == r, r - AssertionError: [u'kd'] and AssertionError: [u'kc']
assert ['Row Key', 'ca1', 'col', 'cd1'] == [col_dscptn for col_dscptn in d], d - AssertionError: [('Row Key', 'org.apache.cassandra.db.marshal.UTF8Type', None, None, None, None, None, False), ('col', 'org.apache.cassandra.db.marshal.AsciiType', None, None, None, None, True), ('cd1', 'org.apache.cassandra.db.marshal.AsciiType', None, None, None, None, True)]
Yes, There could be multiple exception from different part of Cassandra (delete column from a row, delete columns from multiple rows, delete entire rows, retrieve multiple rows, range)
Single file. CQL API component is affected
Must use CQL (Cassandra query language)
1. CREATE COLUMNFAMILY users (KEY varchar PRIMARY KEY, password varchar, gender varchar);
2. INSERT INTO users (KEY, password) VALUES ('user', 'password);
3. select name from users (problem will show up here because gender field is null)
There are multiple ways of producing this failure. The above mentioned is accessing rows.
Delete column from a row, delete columns from multiple rows, delete entire rows, range operation on the affected row will also go into the same code path (decode row function).
The reproduction is easy. Insert into a row, but do not insert into all columns. Then delete the row.
When trying to delete column from a row, delete columns from multiple rows, delete entire rows, access multiple rows and range on rows containing null columns, the operation will fail.
Looking into the logs, we see assertions where one or more of the column is (NONE)
The bug is in the decode_row function in CQL’s code. CQL will use this library to decode the rows, and the code does not handle the NULL value correctly, terminating too early.
Yes, a testcase exposed this problem
In the CQL decoder function, if a value is NULL, do not terminate the processing.
- if column.value == None:
description.append((unmarshal(column.name), comparator, None, None, None, None, True))
validator = self.__validator_for(keyspace, column_family, column.name)
- values.append(unmarshallers.get(validator, unmarshal_noop)(column.value))
+ if column.value == None:
+ values.append(unmarshallers.get(validator, unmarshal_noop)(column.value))
return description, values