Skip to content

Commit 6f057f4

Browse files
committed
perf: skip ColDesc creation in bind() when column encryption is disabled
Split BoundStatement.bind() into two code paths: when column_encryption_policy is None (the overwhelmingly common case), skip ColDesc namedtuple creation, ce_policy.contains_column() check, and ce_policy.column_type() lookup per column. Call col_spec.type.serialize() directly instead. When column encryption IS enabled, behavior is unchanged. Benchmark (inner loop only, 200k iters, Python 3.14): 3-col: 1375 -> 523 ns (2.63x, saving 852 ns/bind) 5-col: 2226 -> 1013 ns (2.20x, saving 1213 ns/bind) 8-col: 3495 -> 1317 ns (2.65x, saving 2178 ns/bind)
1 parent 86b9771 commit 6f057f4

1 file changed

Lines changed: 41 additions & 21 deletions

File tree

cassandra/query.py

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -636,28 +636,48 @@ def bind(self, values):
636636

637637
self.raw_values = values
638638
self.values = []
639-
for value, col_spec in zip(values, col_meta):
640-
if value is None:
641-
self.values.append(None)
642-
elif value is UNSET_VALUE:
643-
if proto_version >= 4:
644-
self._append_unset_value()
639+
if ce_policy:
640+
# Column encryption enabled — need ColDesc per column
641+
for value, col_spec in zip(values, col_meta):
642+
if value is None:
643+
self.values.append(None)
644+
elif value is UNSET_VALUE:
645+
if proto_version >= 4:
646+
self._append_unset_value()
647+
else:
648+
raise ValueError("Attempt to bind UNSET_VALUE while using unsuitable protocol version (%d < 4)" % proto_version)
645649
else:
646-
raise ValueError("Attempt to bind UNSET_VALUE while using unsuitable protocol version (%d < 4)" % proto_version)
647-
else:
648-
try:
649-
col_desc = ColDesc(col_spec.keyspace_name, col_spec.table_name, col_spec.name)
650-
uses_ce = ce_policy and ce_policy.contains_column(col_desc)
651-
col_type = ce_policy.column_type(col_desc) if uses_ce else col_spec.type
652-
col_bytes = col_type.serialize(value, proto_version)
653-
if uses_ce:
654-
col_bytes = ce_policy.encrypt(col_desc, col_bytes)
655-
self.values.append(col_bytes)
656-
except (TypeError, struct.error) as exc:
657-
actual_type = type(value)
658-
message = ('Received an argument of invalid type for column "%s". '
659-
'Expected: %s, Got: %s; (%s)' % (col_spec.name, col_spec.type, actual_type, exc))
660-
raise TypeError(message)
650+
try:
651+
col_desc = ColDesc(col_spec.keyspace_name, col_spec.table_name, col_spec.name)
652+
uses_ce = ce_policy.contains_column(col_desc)
653+
col_type = ce_policy.column_type(col_desc) if uses_ce else col_spec.type
654+
col_bytes = col_type.serialize(value, proto_version)
655+
if uses_ce:
656+
col_bytes = ce_policy.encrypt(col_desc, col_bytes)
657+
self.values.append(col_bytes)
658+
except (TypeError, struct.error) as exc:
659+
actual_type = type(value)
660+
message = ('Received an argument of invalid type for column "%s". '
661+
'Expected: %s, Got: %s; (%s)' % (col_spec.name, col_spec.type, actual_type, exc))
662+
raise TypeError(message)
663+
else:
664+
# Fast path — no column encryption (common case)
665+
for value, col_spec in zip(values, col_meta):
666+
if value is None:
667+
self.values.append(None)
668+
elif value is UNSET_VALUE:
669+
if proto_version >= 4:
670+
self._append_unset_value()
671+
else:
672+
raise ValueError("Attempt to bind UNSET_VALUE while using unsuitable protocol version (%d < 4)" % proto_version)
673+
else:
674+
try:
675+
self.values.append(col_spec.type.serialize(value, proto_version))
676+
except (TypeError, struct.error) as exc:
677+
actual_type = type(value)
678+
message = ('Received an argument of invalid type for column "%s". '
679+
'Expected: %s, Got: %s; (%s)' % (col_spec.name, col_spec.type, actual_type, exc))
680+
raise TypeError(message)
661681

662682
if proto_version >= 4:
663683
diff = col_meta_len - len(self.values)

0 commit comments

Comments
 (0)