Skip to content

Commit 3c3fea8

Browse files
committed
fix: preserve wrapped decode errors in inline row path
1 parent a9e0328 commit 3c3fea8

2 files changed

Lines changed: 32 additions & 17 deletions

File tree

cassandra/protocol.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -722,17 +722,10 @@ def recv_results_rows(self, f, protocol_version, user_type_map, result_metadata,
722722

723723
if not column_encryption_policy:
724724
# Fast path: no column encryption — decode inline, skip ColDesc creation
725-
col_types = self.column_types
726-
colcount = len(col_types)
727-
try:
728-
self.parsed_rows = [
729-
_decode_row_inline(f, colcount, col_types, protocol_version)
730-
for _ in range(rowcount)
731-
]
732-
except Exception:
733-
# Re-read is not possible since we consumed the buffer.
734-
# This path should be extremely rare (type mismatch in server response).
735-
raise
725+
self.parsed_rows = [
726+
_decode_row_inline(f, column_metadata, protocol_version)
727+
for _ in range(rowcount)
728+
]
736729
else:
737730
# Slow path: column encryption enabled — need ColDesc and per-column CE check
738731
rows = [self.recv_row(f, len(column_metadata)) for _ in range(rowcount)]
@@ -1436,16 +1429,21 @@ def read_error_code_map(f):
14361429

14371430

14381431

1439-
def _decode_row_inline(f, colcount, col_types, protocol_version):
1432+
def _decode_row_inline(f, column_metadata, protocol_version):
14401433
"""Decode a single row directly from the buffer (no column encryption)."""
14411434
row = []
1442-
for i in range(colcount):
1435+
for col_md in column_metadata:
14431436
size = read_int(f)
14441437
if size < 0:
14451438
row.append(None)
14461439
else:
14471440
val = f.read(size)
1448-
row.append(col_types[i].from_binary(val, protocol_version))
1441+
try:
1442+
row.append(col_md[3].from_binary(val, protocol_version))
1443+
except Exception as e:
1444+
raise DriverException('Failed decoding result column "%s" of type %s: %s' % (col_md[2],
1445+
col_md[3].cql_parameterized_type(),
1446+
str(e)))
14491447
return tuple(row)
14501448

14511449

tests/unit/test_protocol.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,17 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import io
1516
import unittest
1617

1718
from unittest.mock import Mock
1819

19-
from cassandra import ProtocolVersion, UnsupportedOperation
20+
from cassandra import DriverException, ProtocolVersion, UnsupportedOperation, type_codes
2021
from cassandra.protocol import (
21-
PrepareMessage, QueryMessage, ExecuteMessage, UnsupportedOperation,
22+
PrepareMessage, QueryMessage, ExecuteMessage, ResultMessage, UnsupportedOperation,
2223
_PAGING_OPTIONS_FLAG, _WITH_SERIAL_CONSISTENCY_FLAG,
2324
_PAGE_SIZE_FLAG, _WITH_PAGING_STATE_FLAG,
24-
BatchMessage
25+
BatchMessage, RESULT_KIND_ROWS, write_int, write_short, write_string
2526
)
2627
from cassandra.query import BatchType
2728
from cassandra.marshal import uint32_unpack
@@ -31,6 +32,22 @@
3132

3233
class MessageTest(unittest.TestCase):
3334

35+
def test_result_message_wraps_inline_decode_errors(self):
36+
body = io.BytesIO()
37+
write_int(body, RESULT_KIND_ROWS)
38+
write_int(body, 0)
39+
write_int(body, 1)
40+
write_string(body, "ks")
41+
write_string(body, "tbl")
42+
write_string(body, "v")
43+
write_short(body, type_codes.DateType)
44+
write_int(body, 1)
45+
write_int(body, 1)
46+
body.write(b"\x00")
47+
48+
with pytest.raises(DriverException, match='Failed decoding result column "v"'):
49+
ResultMessage.recv_body(io.BytesIO(body.getvalue()), ProtocolVersion.V4, 0, {}, None, None)
50+
3451
def test_prepare_message(self):
3552
"""
3653
Test to check the appropriate calls are made

0 commit comments

Comments
 (0)