@@ -175,6 +175,12 @@ sstring to_string(const event::schema_change::target_type t) {
175175 SCYLLA_ASSERT (false && " unreachable" );
176176}
177177
178+ bool is_metadata_id_supported (const service::client_state& client_state) {
179+ // TODO: metadata_id is mandatory in CQLv5, so extend the check below
180+ // when CQLv5 support is implemented
181+ return client_state.is_protocol_extension_set (cql_transport::cql_protocol_extension::USE_METADATA_ID);
182+ }
183+
178184event::event_type parse_event_type (const sstring& value)
179185{
180186 if (value == " TOPOLOGY_CHANGE" ) {
@@ -1009,7 +1015,7 @@ future<std::unique_ptr<cql_server::response>> cql_server::connection::process_op
10091015
10101016std::unique_ptr<cql_server::response>
10111017make_result (int16_t stream, messages::result_message& msg, const tracing::trace_state_ptr& tr_state,
1012- cql_protocol_version_type version, bool skip_metadata = false );
1018+ cql_protocol_version_type version, cql_metadata_id_wrapper&& metadata_id, bool skip_metadata = false );
10131019
10141020template <typename Process>
10151021 requires std::is_invocable_r_v<future<cql_server::process_fn_return_type>,
@@ -1104,7 +1110,8 @@ process_query_internal(service::client_state& client_state, distributed<cql3::qu
11041110 return cql_server::process_fn_return_type (convert_error_message_to_coordinator_result (msg.get ()));
11051111 } else {
11061112 tracing::trace (q_state->query_state .get_trace_state (), " Done processing - preparing a result" );
1107- return cql_server::process_fn_return_type (make_foreign (make_result (stream, *msg, q_state->query_state .get_trace_state (), version, skip_metadata)));
1113+
1114+ return cql_server::process_fn_return_type (make_foreign (make_result (stream, *msg, q_state->query_state .get_trace_state (), version, cql_metadata_id_wrapper{}, skip_metadata)));
11081115 }
11091116 });
11101117}
@@ -1127,11 +1134,14 @@ future<std::unique_ptr<cql_server::response>> cql_server::connection::process_pr
11271134 return qp.prepare (std::move (query), client_state, dialect).discard_result ();
11281135 }).then ([this , query, stream, &client_state, trace_state, dialect] () mutable {
11291136 tracing::trace (trace_state, " Done preparing on remote shards" );
1130- return _server._query_processor .local ().prepare (std::move (query), client_state, dialect).then ([this , stream, trace_state] (auto msg) {
1137+ return _server._query_processor .local ().prepare (std::move (query), client_state, dialect).then ([this , stream, &client_state, trace_state] (auto msg) {
11311138 tracing::trace (trace_state, " Done preparing on a local shard - preparing a result. ID is [{}]" , seastar::value_of ([&msg] {
11321139 return messages::result_message::prepared::cql::get_id (msg);
11331140 }));
1134- return make_result (stream, *msg, trace_state, _version);
1141+ cql_metadata_id_wrapper metadata_id = is_metadata_id_supported (client_state)
1142+ ? cql_metadata_id_wrapper (msg->get_metadata_id ())
1143+ : cql_metadata_id_wrapper ();
1144+ return make_result (stream, *msg, trace_state, _version, std::move (metadata_id));
11351145 });
11361146 });
11371147}
@@ -1157,6 +1167,10 @@ process_execute_internal(service::client_state& client_state, distributed<cql3::
11571167 throw exceptions::prepared_query_not_found_exception (id);
11581168 }
11591169
1170+ cql_metadata_id_wrapper metadata_id = is_metadata_id_supported (client_state)
1171+ ? cql_metadata_id_wrapper (cql3::cql_metadata_id_type (in.read_short_bytes ()), prepared->get_metadata_id ())
1172+ : cql_metadata_id_wrapper ();
1173+
11601174 auto q_state = std::make_unique<cql_query_state>(client_state, trace_state, std::move (permit));
11611175 auto & query_state = q_state->query_state ;
11621176 q_state->options = in.read_options (version, qp.local ().get_cql_config ());
@@ -1195,14 +1209,14 @@ process_execute_internal(service::client_state& client_state, distributed<cql3::
11951209
11961210 tracing::trace (trace_state, " Processing a statement" );
11971211 return qp.local ().execute_prepared_without_checking_exception_message (query_state, std::move (stmt), options, std::move (prepared), std::move (cache_key), needs_authorization)
1198- .then ([trace_state = query_state.get_trace_state (), skip_metadata, q_state = std::move (q_state), stream, version] (auto msg) {
1212+ .then ([trace_state = query_state.get_trace_state (), skip_metadata, q_state = std::move (q_state), stream, version, metadata_id = std::move (metadata_id) ] (auto msg) mutable {
11991213 if (msg->move_to_shard ()) {
12001214 return cql_server::process_fn_return_type (make_foreign (dynamic_pointer_cast<messages::result_message::bounce_to_shard>(msg)));
12011215 } else if (msg->is_exception ()) {
12021216 return cql_server::process_fn_return_type (convert_error_message_to_coordinator_result (msg.get ()));
12031217 } else {
12041218 tracing::trace (q_state->query_state .get_trace_state (), " Done processing - preparing a result" );
1205- return cql_server::process_fn_return_type (make_foreign (make_result (stream, *msg, q_state->query_state .get_trace_state (), version, skip_metadata)));
1219+ return cql_server::process_fn_return_type (make_foreign (make_result (stream, *msg, q_state->query_state .get_trace_state (), version, std::move (metadata_id), skip_metadata)));
12061220 }
12071221 });
12081222}
@@ -1323,7 +1337,8 @@ process_batch_internal(service::client_state& client_state, distributed<cql3::qu
13231337 return cql_server::process_fn_return_type (convert_error_message_to_coordinator_result (msg.get ()));
13241338 } else {
13251339 tracing::trace (q_state->query_state .get_trace_state (), " Done processing - preparing a result" );
1326- return cql_server::process_fn_return_type (make_foreign (make_result (stream, *msg, trace_state, version)));
1340+
1341+ return cql_server::process_fn_return_type (make_foreign (make_result (stream, *msg, trace_state, version, cql_metadata_id_wrapper{})));
13271342 }
13281343 });
13291344}
@@ -1538,11 +1553,13 @@ class cql_server::fmt_visitor : public messages::result_message::visitor_base {
15381553 uint8_t _version;
15391554 cql_server::response& _response;
15401555 bool _skip_metadata;
1556+ cql_metadata_id_wrapper _metadata_id;
15411557public:
1542- fmt_visitor (uint8_t version, cql_server::response& response, bool skip_metadata)
1558+ fmt_visitor (uint8_t version, cql_server::response& response, bool skip_metadata, cql_metadata_id_wrapper&& metadata_id )
15431559 : _version{version}
15441560 , _response{response}
15451561 , _skip_metadata{skip_metadata}
1562+ , _metadata_id(std::move(metadata_id))
15461563 { }
15471564
15481565 virtual void visit (const messages::result_message::void_message&) override {
@@ -1557,8 +1574,11 @@ class cql_server::fmt_visitor : public messages::result_message::visitor_base {
15571574 virtual void visit (const messages::result_message::prepared::cql& m) override {
15581575 _response.write_int (0x0004 );
15591576 _response.write_short_bytes (m.get_id ());
1577+ if (_metadata_id.has_response_metadata_id ()) {
1578+ _response.write_short_bytes (_metadata_id.get_response_metadata_id ()._metadata_id );
1579+ }
15601580 _response.write (m.metadata (), _version);
1561- _response.write (*m.result_metadata ());
1581+ _response.write (*m.result_metadata (), _metadata_id );
15621582 }
15631583
15641584 virtual void visit (const messages::result_message::schema_change& m) override {
@@ -1578,7 +1598,7 @@ class cql_server::fmt_visitor : public messages::result_message::visitor_base {
15781598 virtual void visit (const messages::result_message::rows& m) override {
15791599 _response.write_int (0x0002 );
15801600 auto & rs = m.rs ();
1581- _response.write (rs.get_metadata (), _skip_metadata);
1601+ _response.write (rs.get_metadata (), _metadata_id, _skip_metadata);
15821602 auto row_count_plhldr = _response.write_int_placeholder ();
15831603
15841604 class visitor {
@@ -1606,7 +1626,7 @@ class cql_server::fmt_visitor : public messages::result_message::visitor_base {
16061626
16071627std::unique_ptr<cql_server::response>
16081628make_result (int16_t stream, messages::result_message& msg, const tracing::trace_state_ptr& tr_state,
1609- cql_protocol_version_type version, bool skip_metadata) {
1629+ cql_protocol_version_type version, cql_metadata_id_wrapper&& metadata_id, bool skip_metadata) {
16101630 auto response = std::make_unique<cql_server::response>(stream, cql_binary_opcode::RESULT, tr_state);
16111631 if (__builtin_expect (!msg.warnings ().empty () && version > 3 , false )) {
16121632 response->set_frame_flag (cql_frame_flags::warning);
@@ -1616,7 +1636,7 @@ make_result(int16_t stream, messages::result_message& msg, const tracing::trace_
16161636 response->set_frame_flag (cql_frame_flags::custom_payload);
16171637 response->write_string_bytes_map (msg.custom_payload ().value ());
16181638 }
1619- cql_server::fmt_visitor fmt{version, *response, skip_metadata};
1639+ cql_server::fmt_visitor fmt{version, *response, skip_metadata, std::move (metadata_id) };
16201640 msg.accept (fmt);
16211641 return response;
16221642}
@@ -2024,7 +2044,7 @@ thread_local const type_codec::type_id_to_type_type type_codec::type_id_to_type
20242044 { inet_addr_type, type_id::INET },
20252045};
20262046
2027- void cql_server::response::write (const cql3::metadata& m, bool no_metadata) {
2047+ void cql_server::response::write (const cql3::metadata& m, const cql_metadata_id_wrapper& metadata_id, bool no_metadata) {
20282048 auto flags = m.flags ();
20292049 bool global_tables_spec = m.flags ().contains <cql3::metadata::flag::GLOBAL_TABLES_SPEC>();
20302050 bool has_more_pages = m.flags ().contains <cql3::metadata::flag::HAS_MORE_PAGES>();
@@ -2033,6 +2053,15 @@ void cql_server::response::write(const cql3::metadata& m, bool no_metadata) {
20332053 flags.set <cql3::metadata::flag::NO_METADATA>();
20342054 }
20352055
2056+ cql3::cql_metadata_id_type calculated_metadata_id{bytes{}};
2057+ if (metadata_id.has_request_metadata_id () && metadata_id.has_response_metadata_id ()) {
2058+ if (metadata_id.get_request_metadata_id () != metadata_id.get_response_metadata_id ()) {
2059+ flags.remove <cql3::metadata::flag::NO_METADATA>();
2060+ flags.set <cql3::metadata::flag::METADATA_CHANGED>();
2061+ no_metadata = false ;
2062+ }
2063+ }
2064+
20362065 write_int (flags.mask ());
20372066 write_int (m.column_count ());
20382067
@@ -2044,6 +2073,10 @@ void cql_server::response::write(const cql3::metadata& m, bool no_metadata) {
20442073 return ;
20452074 }
20462075
2076+ if (flags.contains <cql3::metadata::flag::METADATA_CHANGED>()) {
2077+ write_short_bytes (metadata_id.get_response_metadata_id ()._metadata_id );
2078+ }
2079+
20472080 auto names_i = m.get_names ().begin ();
20482081
20492082 if (global_tables_spec) {
@@ -2096,6 +2129,28 @@ void cql_server::response::write(const cql3::prepared_metadata& m, uint8_t versi
20962129 }
20972130}
20982131
2132+ bool cql_metadata_id_wrapper::has_request_metadata_id () const {
2133+ return _request_metadata_id.has_value ();
2134+ }
2135+
2136+ bool cql_metadata_id_wrapper::has_response_metadata_id () const {
2137+ return _response_metadata_id.has_value ();
2138+ }
2139+
2140+ const cql3::cql_metadata_id_type& cql_metadata_id_wrapper::get_request_metadata_id () const {
2141+ if (!has_request_metadata_id ()) {
2142+ on_internal_error (clogger, " request metadata_id is empty" );
2143+ }
2144+ return _request_metadata_id.value ();
2145+ }
2146+
2147+ const cql3::cql_metadata_id_type& cql_metadata_id_wrapper::get_response_metadata_id () const {
2148+ if (!has_response_metadata_id ()) {
2149+ on_internal_error (clogger, " response metadata_id is empty" );
2150+ }
2151+ return _response_metadata_id.value ();
2152+ }
2153+
20992154future<utils::chunked_vector<client_data>> cql_server::get_client_data () {
21002155 utils::chunked_vector<client_data> ret;
21012156 co_await for_each_gently ([&ret] (const generic_server::connection& c) {
0 commit comments