Skip to content

Commit f40113c

Browse files
committed
Bug#36674083 session-variables aren't propagated if read-write splitting is enabled
If read-write splitting is used and the sequence: mysql> select @@sql_mode; ONLY_FULL_GROUP_BY,... mysql> set sql_mode="ansi"; mysql> select @@sql_mode; ONLY_FULL_GROUP_BY,... then the 2nd SELECT returns the initial sql_mode, not the updated one. Change ====== After taking a read-connection from the stash, apply all system-variable changes done on the write-connection (and vice versa). mysql> select @@sql_mode; ONLY_FULL_GROUP_BY,... mysql> set sql_mode="ansi"; mysql> select @@sql_mode; REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI Change-Id: I57c0f2d258a4037f75115a7719e1e889272f3b6e
1 parent 1e39733 commit f40113c

16 files changed

+342
-270
lines changed

router/src/routing/include/mysqlrouter/classic_protocol_state.h

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
#define ROUTING_CLASSIC_PROTOCOL_STATE_INCLUDED
2828

2929
#include <chrono>
30+
#include <map>
3031
#include <optional>
32+
#include <string>
3133

3234
#include "classic_prepared_statement.h"
3335

@@ -43,6 +45,98 @@ class ClassicProtocolState {
4345
kFinished,
4446
};
4547

48+
/**
49+
* system-variables as returned by the server.
50+
*
51+
* can be queried from the server with:
52+
*
53+
* - SELECT @@SESSION.{k}
54+
* - SELECT @@LOCAL.{k}
55+
*
56+
* can be set on the server with:
57+
*
58+
* - SET k = v;
59+
* - SET @@SESSION.k = v;
60+
* - SET @@LOCAL.k = v;
61+
* - SET SESSION k = v;
62+
* - SET LOCAL k = v;
63+
*
64+
* changes to system-vars on the server are returned via
65+
* the sesssion-tracker for system-variables.
66+
*/
67+
class SystemVariables {
68+
public:
69+
using key_type = std::string;
70+
using key_view_type = std::string_view;
71+
using value_type = std::optional<std::string>;
72+
73+
/**
74+
* set k to v.
75+
*
76+
* if k doesn't exist in the system-vars yet, it gets inserted.
77+
*/
78+
void set(key_type k, value_type v) {
79+
vars_.insert_or_assign(std::move(k), std::move(v));
80+
}
81+
82+
/**
83+
* find 'k' in sytem-vars.
84+
*
85+
* @param k key
86+
*
87+
* if 'k' does not exist in system-vars, a NULL-like value is returned.
88+
* otherwise return the value for the system-var referenced by 'k'
89+
*
90+
* @returns std::nullopt if key is not found, the found value otherwise.
91+
*/
92+
std::optional<value_type> find(const key_view_type &k) const {
93+
const auto it = vars_.find(k);
94+
if (it == vars_.end()) return {std::nullopt};
95+
96+
return it->second;
97+
}
98+
99+
/**
100+
* get 'k' from system-vars.
101+
*
102+
* @param k key
103+
*
104+
* if 'k' does not exist in system-vars, a NULL-like value is returned.
105+
* otherwise return the value for the system-var referenced by 'k' which may
106+
* be NULL-like or a string.
107+
*
108+
* @returns std::nullopt if key is not found or value is NULL-like, the
109+
* found value otherwise
110+
*/
111+
value_type get(const key_view_type &k) const {
112+
const auto it = vars_.find(k);
113+
if (it == vars_.end()) return {std::nullopt};
114+
115+
return it->second;
116+
}
117+
118+
using iterator = std::map<key_type, value_type>::iterator;
119+
using const_iterator = std::map<key_type, value_type>::const_iterator;
120+
121+
iterator begin() { return vars_.begin(); }
122+
const_iterator begin() const { return vars_.begin(); }
123+
iterator end() { return vars_.end(); }
124+
const_iterator end() const { return vars_.end(); }
125+
126+
/**
127+
* check if there is no system-var.
128+
*/
129+
bool empty() const { return vars_.empty(); }
130+
131+
/**
132+
* clear the system-vars.
133+
*/
134+
void clear() { vars_.clear(); }
135+
136+
private:
137+
std::map<key_type, value_type, std::less<>> vars_;
138+
};
139+
46140
ClassicProtocolState() = default;
47141

48142
ClassicProtocolState(
@@ -169,6 +263,10 @@ class ClassicProtocolState {
169263
}
170264
#endif
171265

266+
SystemVariables &system_variables() { return system_variables_; }
267+
268+
const SystemVariables &system_variables() const { return system_variables_; }
269+
172270
private:
173271
classic_protocol::capabilities::value_type server_caps_{};
174272
classic_protocol::capabilities::value_type client_caps_{};
@@ -193,6 +291,8 @@ class ClassicProtocolState {
193291
classic_protocol::status::value_type status_flags_{};
194292

195293
HandshakeState handshake_state_{HandshakeState::kConnected};
294+
295+
SystemVariables system_variables_;
196296
};
197297

198298
class ClientSideClassicProtocolState : public ClassicProtocolState {

router/src/routing/src/classic_change_user_forwarder.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,8 @@ stdx::expected<Processor::Result, std::error_code> ChangeUserForwarder::ok() {
331331
// if connection sharing is enabled in the config, enable the
332332
// session-tracker.
333333
connection()->push_processor(std::make_unique<QuerySender>(connection(), R"(
334-
SET @@SESSION.session_track_schema = 'ON',
335-
@@SESSION.session_track_system_variables = '*',
334+
SET @@SESSION.session_track_system_variables = '*',
335+
@@SESSION.session_track_schema = 'ON',
336336
@@SESSION.session_track_transaction_info = 'CHARACTERISTICS',
337337
@@SESSION.session_track_gtids = 'OWN_GTID',
338338
@@SESSION.session_track_state_change = 'ON')"));

router/src/routing/src/classic_change_user_sender.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ stdx::expected<Processor::Result, std::error_code> ChangeUserSender::command() {
286286

287287
dst_protocol.seq_id(0xff); // reset seq-id
288288

289+
dst_protocol.system_variables().clear();
290+
289291
auto send_res = ClassicFrame::send_msg(dst_conn, *change_user_msg_);
290292
if (!send_res) return send_server_failed(send_res.error());
291293

router/src/routing/src/classic_command.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,9 @@ class SelectSessionCollationConnectionHandler : public QuerySender::Handler {
282282
connection_->some_state_changed(true);
283283
} else {
284284
// all rows received,
285-
connection_->execution_context().system_variables().set(
285+
connection_->client_protocol().system_variables().set(
286+
"collation_connection", collation_connection_);
287+
connection_->server_protocol().system_variables().set(
286288
"collation_connection", collation_connection_);
287289

288290
connection_->collation_connection_maybe_dirty(false);
@@ -307,7 +309,7 @@ class SelectSessionCollationConnectionHandler : public QuerySender::Handler {
307309

308310
bool something_failed_{false};
309311

310-
Value collation_connection_{std::nullopt};
312+
std::optional<std::string> collation_connection_{std::nullopt};
311313
};
312314

313315
stdx::expected<Processor::Result, std::error_code>

router/src/routing/src/classic_connection_base.cc

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ MysqlRoutingClassicConnectionBase::track_session_changes(
532532
set_names_sysvar.set(3);
533533
}
534534

535-
auto value_from_kv = [](auto kv) -> Value {
535+
auto value_from_kv = [](auto kv) -> std::optional<std::string> {
536536
// the session tracker can't report NULL. Instead it reports "".
537537
//
538538
// In the case of 'character_set_results' setting "" leads to an
@@ -545,8 +545,10 @@ MysqlRoutingClassicConnectionBase::track_session_changes(
545545
return {std::string(kv.value())};
546546
};
547547

548-
exec_ctx_.system_variables().set(std::string(kv.key()),
549-
value_from_kv(kv));
548+
client_protocol().system_variables().set(std::string(kv.key()),
549+
value_from_kv(kv));
550+
server_protocol().system_variables().set(std::string(kv.key()),
551+
value_from_kv(kv));
550552

551553
if (auto &tr = tracer()) {
552554
std::ostringstream oss;
@@ -836,7 +838,7 @@ void MysqlRoutingClassicConnectionBase::loop() {
836838
}
837839

838840
bool MysqlRoutingClassicConnectionBase::connection_sharing_possible() const {
839-
const auto &sysvars = exec_ctx_.system_variables();
841+
const auto &sysvars = client_protocol().system_variables();
840842

841843
return context_.connection_sharing() && // config must allow it.
842844
client_protocol().password().has_value() && // a password is required
@@ -955,18 +957,18 @@ bool MysqlRoutingClassicConnectionBase::connection_sharing_allowed() const {
955957

956958
std::string MysqlRoutingClassicConnectionBase::connection_sharing_blocked_by()
957959
const {
958-
const auto &sysvars = exec_ctx_.system_variables();
960+
const auto &sysvars = client_protocol().system_variables();
959961

960962
// "possible"
961963
if (!context_.connection_sharing()) return "config";
962964
if (!client_protocol().password().has_value()) return "no-password";
963-
if (sysvars.get("session_track_gtids") != Value("OWN_GTID"))
965+
if (sysvars.get("session_track_gtids") != "OWN_GTID")
964966
return "session-track-gtids";
965-
if (sysvars.get("session_track_state_change") != Value("ON"))
967+
if (sysvars.get("session_track_state_change") != "ON")
966968
return "session-track-state-change";
967-
if (sysvars.get("session_track_system_variables") != Value("*"))
969+
if (sysvars.get("session_track_system_variables") != "*")
968970
return "session-track-system-variables";
969-
if (sysvars.get("session_track_transaction_info") != Value("CHARACTERISTICS"))
971+
if (sysvars.get("session_track_transaction_info") != "CHARACTERISTICS")
970972
return "session-track-transaction-info";
971973

972974
// "allowed"
@@ -1001,7 +1003,8 @@ void MysqlRoutingClassicConnectionBase::reset_to_initial() {
10011003
execution_context().diagnostics_area().warnings().clear();
10021004

10031005
// clear the tracked-system-vars like sql_mode, ...
1004-
execution_context().system_variables().clear();
1006+
src_protocol.system_variables().clear();
1007+
server_protocol().system_variables().clear();
10051008

10061009
// clear the prepared statements.
10071010
src_protocol.prepared_statements().clear();

0 commit comments

Comments
 (0)