@@ -891,9 +891,9 @@ def read_type(cls, f, user_type_map):
891891 num_fields = read_short (f )
892892 names , types = zip (* ((read_string (f ), cls .read_type (f , user_type_map ))
893893 for _ in range (num_fields )))
894- specialized_type = typeclass . make_udt_class (ks , udt_name , names , types )
895- specialized_type . mapped_class = user_type_map . get ( ks , {}). get ( udt_name )
896- typeclass = specialized_type
894+ mapped_class = user_type_map . get (ks , {}). get ( udt_name )
895+ typeclass = typeclass . make_udt_class (
896+ ks , udt_name , names , types , mapped_class = mapped_class )
897897 elif typeclass == CUSTOM_TYPE :
898898 classname = read_string (f )
899899 typeclass = lookup_casstype (classname )
@@ -1100,6 +1100,76 @@ def send_body(self, f, protocol_version, protocol_features=None):
11001100 "Continuous paging backpressure is not supported." )
11011101
11021102
1103+ _PREPARED_METADATA_RESULT_ATTRIBUTES = (
1104+ 'opcode' ,
1105+ 'name' ,
1106+ 'kind' ,
1107+ 'results' ,
1108+ 'paging_state' ,
1109+ '_FLAGS_GLOBAL_TABLES_SPEC' ,
1110+ '_HAS_MORE_PAGES_FLAG' ,
1111+ '_NO_METADATA_FLAG' ,
1112+ '_CONTINUOUS_PAGING_FLAG' ,
1113+ '_CONTINUOUS_PAGING_LAST_FLAG' ,
1114+ '_METADATA_ID_FLAG' ,
1115+ 'column_names' ,
1116+ 'column_types' ,
1117+ 'parsed_rows' ,
1118+ 'continuous_paging_seq' ,
1119+ 'continuous_paging_last' ,
1120+ 'new_keyspace' ,
1121+ 'column_metadata' ,
1122+ 'query_id' ,
1123+ 'bind_metadata' ,
1124+ 'pk_indexes' ,
1125+ 'schema_change_event' ,
1126+ 'is_lwt' ,
1127+ 'tracing' ,
1128+ 'custom_payload' ,
1129+ 'warnings' ,
1130+ '__init__' ,
1131+ 'recv' ,
1132+ 'recv_body' ,
1133+ 'recv_results_rows' ,
1134+ 'recv_results_prepared' ,
1135+ 'recv_results_metadata' ,
1136+ 'recv_prepared_metadata' ,
1137+ 'recv_results_schema_change' ,
1138+ 'read_type' ,
1139+ 'recv_row' ,
1140+ )
1141+
1142+
1143+ def _class_attribute (cls , name ):
1144+ for base in cls .__mro__ :
1145+ if name in vars (base ):
1146+ return vars (base )[name ]
1147+ return None
1148+
1149+
1150+ def _prepared_metadata_cache_config (handler , result_message_type ):
1151+ """
1152+ Capture the canonical driver-owned result-decoder configuration.
1153+
1154+ Cluster-side snapshots compare against this exact configuration. Installing
1155+ an application ResultMessage or mutating a decoding attribute therefore
1156+ makes the handler ineligible for skip-metadata instead of attempting to
1157+ freeze arbitrary application class state.
1158+ """
1159+ return (
1160+ tuple (handler .message_types_by_opcode .items ()),
1161+ result_message_type ,
1162+ tuple (result_message_type .type_codes .items ()),
1163+ tuple (getattr (result_message_type , 'code_to_type' , {}).items ()),
1164+ _class_attribute (handler , 'decode_message' ),
1165+ tuple (
1166+ (name , _class_attribute (result_message_type , name ))
1167+ for name in _PREPARED_METADATA_RESULT_ATTRIBUTES
1168+ ),
1169+ handler .column_encryption_policy ,
1170+ )
1171+
1172+
11031173class _ProtocolHandler (object ):
11041174 """
11051175 _ProtocolHander handles encoding and decoding messages.
@@ -1121,6 +1191,11 @@ class _ProtocolHandler(object):
11211191 column_encryption_policy = None
11221192 """Instance of :class:`cassandra.policies.ColumnEncryptionPolicy` in use by this handler"""
11231193
1194+ # Marks handlers whose result-decoder configuration the driver may copy
1195+ # into an immutable per-request snapshot. Subclasses do not inherit
1196+ # eligibility because their opcode and type maps are application-owned.
1197+ _prepared_metadata_cache_token = object ()
1198+
11241199 @classmethod
11251200 def encode_message (cls , msg , stream_id , protocol_version , compressor , allow_beta_protocol_version ,
11261201 protocol_features ):
@@ -1245,6 +1320,10 @@ def decode_message(cls, protocol_version, protocol_features, user_type_map, stre
12451320 return msg
12461321
12471322
1323+ _ProtocolHandler ._prepared_metadata_cache_config = \
1324+ _prepared_metadata_cache_config (_ProtocolHandler , ResultMessage )
1325+
1326+
12481327def cython_protocol_handler (colparser ):
12491328 """
12501329 Given a column parser to deserialize ResultMessages, return a suitable
@@ -1284,7 +1363,11 @@ class CythonProtocolHandler(_ProtocolHandler):
12841363 message_types_by_opcode = my_opcodes
12851364
12861365 col_parser = colparser
1366+ _prepared_metadata_cache_token = object ()
12871367
1368+ CythonProtocolHandler ._prepared_metadata_cache_config = \
1369+ _prepared_metadata_cache_config (
1370+ CythonProtocolHandler , FastResultMessage )
12881371 return CythonProtocolHandler
12891372
12901373
0 commit comments