1 #ifndef SESSION_TRACKER_INCLUDED 2 #define SESSION_TRACKER_INCLUDED 3 4 /* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 5 Copyright (c) 2016, 2017, MariaDB Corporation. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; version 2 of the License. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 19 20 #include "m_string.h" 21 #include "thr_lock.h" 22 23 #ifndef EMBEDDED_LIBRARY 24 /* forward declarations */ 25 class THD; 26 class set_var; 27 class String; 28 29 30 enum enum_session_tracker 31 { 32 SESSION_SYSVARS_TRACKER, /* Session system variables */ 33 CURRENT_SCHEMA_TRACKER, /* Current schema */ 34 SESSION_STATE_CHANGE_TRACKER, 35 TRANSACTION_INFO_TRACKER, /* Transaction state */ 36 SESSION_TRACKER_END /* must be the last */ 37 }; 38 39 /** 40 State_tracker 41 42 An abstract class that defines the interface for any of the server's 43 'session state change tracker'. A tracker, however, is a sub- class of 44 this class which takes care of tracking the change in value of a part- 45 icular session state type and thus defines various methods listed in this 46 interface. The change information is later serialized and transmitted to 47 the client through protocol's OK packet. 48 49 Tracker system variables :- 50 A tracker is normally mapped to a system variable. So in order to enable, 51 disable or modify the sub-entities of a tracker, the user needs to modify 52 the respective system variable either through SET command or via command 53 line option. As required in system variable handling, this interface also 54 includes two functions to help in the verification of the supplied value 55 (ON_UPDATE) of the tracker system variable, namely - update(). 56 */ 57 58 class State_tracker 59 { 60 protected: 61 /** 62 Is tracking enabled for a particular session state type ? 63 64 @note: it is a cache of the corresponding thd->variables.session_track_xxx 65 variable 66 */ 67 bool m_enabled; 68 69 private: 70 /** Has the session state type changed ? */ 71 bool m_changed; 72 73 public: ~State_tracker()74 virtual ~State_tracker() {} 75 76 /** Getters */ is_enabled()77 bool is_enabled() const 78 { return m_enabled; } 79 is_changed()80 bool is_changed() const 81 { return m_changed; } 82 reset_changed()83 void reset_changed() { m_changed= false; } 84 85 /** 86 Called by THD::init() when new connection is being created 87 88 We may inherit m_changed from previous connection served by this THD if 89 connection was broken or client didn't have session tracking capability. 90 Thus we have to reset it here. 91 */ enable(THD * thd)92 virtual bool enable(THD *thd) 93 { 94 reset_changed(); 95 return update(thd, 0); 96 } 97 98 /** To be invoked when the tracker's system variable is updated (ON_UPDATE).*/ 99 virtual bool update(THD *thd, set_var *var)= 0; 100 101 /** Store changed data into the given buffer. */ 102 virtual bool store(THD *thd, String *buf)= 0; 103 104 /** Mark the entity as changed. */ 105 virtual void mark_as_changed(THD *thd, LEX_CSTRING *name); 106 }; 107 108 109 /** 110 Session_sysvars_tracker 111 112 This is a tracker class that enables & manages the tracking of session 113 system variables. It internally maintains a hash of user supplied variable 114 references and a boolean field to store if the variable was changed by the 115 last statement. 116 */ 117 118 class Session_sysvars_tracker: public State_tracker 119 { 120 struct sysvar_node_st { 121 sys_var *m_svar; 122 bool *test_load; 123 bool m_changed; 124 }; 125 126 class vars_list 127 { 128 /** 129 Registered system variables. (@@session_track_system_variables) 130 A hash to store the name of all the system variables specified by the 131 user. 132 */ 133 HASH m_registered_sysvars; 134 /** 135 If TRUE then we want to check all session variable. 136 */ 137 bool track_all; init()138 void init() 139 { 140 my_hash_init(&m_registered_sysvars, &my_charset_bin, 0, 0, 0, 141 (my_hash_get_key) sysvars_get_key, my_free, 142 HASH_UNIQUE | (mysqld_server_initialized ? 143 HASH_THREAD_SPECIFIC : 0)); 144 } free_hash()145 void free_hash() 146 { 147 DBUG_ASSERT(my_hash_inited(&m_registered_sysvars)); 148 my_hash_free(&m_registered_sysvars); 149 } 150 search(const sys_var * svar)151 sysvar_node_st *search(const sys_var *svar) 152 { 153 return reinterpret_cast<sysvar_node_st*>( 154 my_hash_search(&m_registered_sysvars, 155 reinterpret_cast<const uchar*>(&svar), 156 sizeof(sys_var*))); 157 } 158 at(ulong i)159 sysvar_node_st *at(ulong i) 160 { 161 DBUG_ASSERT(i < m_registered_sysvars.records); 162 return reinterpret_cast<sysvar_node_st*>( 163 my_hash_element(&m_registered_sysvars, i)); 164 } 165 public: vars_list()166 vars_list(): track_all(false) { init(); } ~vars_list()167 ~vars_list() { if (my_hash_inited(&m_registered_sysvars)) free_hash(); } deinit()168 void deinit() { free_hash(); } 169 insert_or_search(const sys_var * svar)170 sysvar_node_st *insert_or_search(const sys_var *svar) 171 { 172 sysvar_node_st *res= search(svar); 173 if (!res) 174 { 175 if (track_all) 176 { 177 insert(svar); 178 return search(svar); 179 } 180 } 181 return res; 182 } 183 184 bool insert(const sys_var *svar); 185 void reinit(); 186 void reset(); is_enabled()187 inline bool is_enabled() 188 { 189 return track_all || m_registered_sysvars.records; 190 } 191 void copy(vars_list* from, THD *thd); 192 bool parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error, 193 CHARSET_INFO *char_set); 194 bool construct_var_list(char *buf, size_t buf_len); 195 bool store(THD *thd, String *buf); 196 }; 197 /** 198 Two objects of vars_list type are maintained to manage 199 various operations. 200 */ 201 vars_list orig_list; 202 bool m_parsed; 203 204 public: 205 void init(THD *thd); 206 void deinit(THD *thd); 207 bool enable(THD *thd); 208 bool update(THD *thd, set_var *var); 209 bool store(THD *thd, String *buf); 210 void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name); deinit()211 void deinit() { orig_list.deinit(); } 212 /* callback */ 213 static uchar *sysvars_get_key(const char *entry, size_t *length, 214 my_bool not_used __attribute__((unused))); 215 216 friend bool sysvartrack_global_update(THD *thd, char *str, size_t len); 217 }; 218 219 220 bool sysvartrack_validate_value(THD *thd, const char *str, size_t len); 221 bool sysvartrack_global_update(THD *thd, char *str, size_t len); 222 223 224 /** 225 Current_schema_tracker, 226 227 This is a tracker class that enables & manages the tracking of current 228 schema for a particular connection. 229 */ 230 231 class Current_schema_tracker: public State_tracker 232 { 233 public: 234 bool update(THD *thd, set_var *var); 235 bool store(THD *thd, String *buf); 236 }; 237 238 239 /* 240 Session_state_change_tracker 241 242 This is a boolean tracker class that will monitor any change that contributes 243 to a session state change. 244 Attributes that contribute to session state change include: 245 - Successful change to System variables 246 - User defined variables assignments 247 - temporary tables created, altered or deleted 248 - prepared statements added or removed 249 - change in current database 250 - change of current role 251 */ 252 253 class Session_state_change_tracker: public State_tracker 254 { 255 public: 256 bool update(THD *thd, set_var *var); 257 bool store(THD *thd, String *buf); 258 }; 259 260 261 /* 262 Transaction_state_tracker 263 */ 264 265 /** 266 Transaction state (no transaction, transaction active, work attached, etc.) 267 */ 268 enum enum_tx_state { 269 TX_EMPTY = 0, ///< "none of the below" 270 TX_EXPLICIT = 1, ///< an explicit transaction is active 271 TX_IMPLICIT = 2, ///< an implicit transaction is active 272 TX_READ_TRX = 4, ///< transactional reads were done 273 TX_READ_UNSAFE = 8, ///< non-transaction reads were done 274 TX_WRITE_TRX = 16, ///< transactional writes were done 275 TX_WRITE_UNSAFE = 32, ///< non-transactional writes were done 276 TX_STMT_UNSAFE = 64, ///< "unsafe" (non-deterministic like UUID()) stmts 277 TX_RESULT_SET = 128, ///< result set was sent 278 TX_WITH_SNAPSHOT= 256, ///< WITH CONSISTENT SNAPSHOT was used 279 TX_LOCKED_TABLES= 512 ///< LOCK TABLES is active 280 }; 281 282 283 /** 284 Transaction access mode 285 */ 286 enum enum_tx_read_flags { 287 TX_READ_INHERIT = 0, ///< not explicitly set, inherit session.tx_read_only 288 TX_READ_ONLY = 1, ///< START TRANSACTION READ ONLY, or tx_read_only=1 289 TX_READ_WRITE = 2, ///< START TRANSACTION READ WRITE, or tx_read_only=0 290 }; 291 292 293 /** 294 Transaction isolation level 295 */ 296 enum enum_tx_isol_level { 297 TX_ISOL_INHERIT = 0, ///< not explicitly set, inherit session.tx_isolation 298 TX_ISOL_UNCOMMITTED = 1, 299 TX_ISOL_COMMITTED = 2, 300 TX_ISOL_REPEATABLE = 3, 301 TX_ISOL_SERIALIZABLE= 4 302 }; 303 304 305 /** 306 Transaction tracking level 307 */ 308 enum enum_session_track_transaction_info { 309 TX_TRACK_NONE = 0, ///< do not send tracker items on transaction info 310 TX_TRACK_STATE = 1, ///< track transaction status 311 TX_TRACK_CHISTICS = 2 ///< track status and characteristics 312 }; 313 314 315 /** 316 This is a tracker class that enables & manages the tracking of 317 current transaction info for a particular connection. 318 */ 319 320 class Transaction_state_tracker : public State_tracker 321 { 322 /** Helper function: turn table info into table access flag */ 323 enum_tx_state calc_trx_state(THD *thd, thr_lock_type l, bool has_trx); 324 public: 325 enable(THD * thd)326 bool enable(THD *thd) 327 { 328 m_enabled= false; 329 tx_changed= TX_CHG_NONE; 330 tx_curr_state= TX_EMPTY; 331 tx_reported_state= TX_EMPTY; 332 tx_read_flags= TX_READ_INHERIT; 333 tx_isol_level= TX_ISOL_INHERIT; 334 return State_tracker::enable(thd); 335 } 336 337 bool update(THD *thd, set_var *var); 338 bool store(THD *thd, String *buf); 339 340 /** Change transaction characteristics */ 341 void set_read_flags(THD *thd, enum enum_tx_read_flags flags); 342 void set_isol_level(THD *thd, enum enum_tx_isol_level level); 343 344 /** Change transaction state */ 345 void clear_trx_state(THD *thd, uint clear); 346 void add_trx_state(THD *thd, uint add); add_trx_state(THD * thd,thr_lock_type l,bool has_trx)347 void inline add_trx_state(THD *thd, thr_lock_type l, bool has_trx) 348 { 349 add_trx_state(thd, calc_trx_state(thd, l, has_trx)); 350 } 351 void add_trx_state_from_thd(THD *thd); 352 void end_trx(THD *thd); 353 354 355 private: 356 enum enum_tx_changed { 357 TX_CHG_NONE = 0, ///< no changes from previous stmt 358 TX_CHG_STATE = 1, ///< state has changed from previous stmt 359 TX_CHG_CHISTICS = 2 ///< characteristics have changed from previous stmt 360 }; 361 362 /** any trackable changes caused by this statement? */ 363 uint tx_changed; 364 365 /** transaction state */ 366 uint tx_curr_state, tx_reported_state; 367 368 /** r/w or r/o set? session default? */ 369 enum enum_tx_read_flags tx_read_flags; 370 371 /** isolation level */ 372 enum enum_tx_isol_level tx_isol_level; 373 update_change_flags(THD * thd)374 inline void update_change_flags(THD *thd) 375 { 376 tx_changed &= uint(~TX_CHG_STATE); 377 tx_changed |= (tx_curr_state != tx_reported_state) ? TX_CHG_STATE : 0; 378 if (tx_changed != TX_CHG_NONE) 379 mark_as_changed(thd, NULL); 380 } 381 }; 382 383 #define TRANSACT_TRACKER(X) \ 384 do { if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) \ 385 thd->session_tracker.transaction_info.X; } while(0) 386 #define SESSION_TRACKER_CHANGED(A,B,C) \ 387 thd->session_tracker.mark_as_changed(A,B,C) 388 389 390 /** 391 Session_tracker 392 393 This class holds an object each for all tracker classes and provides 394 methods necessary for systematic detection and generation of session 395 state change information. 396 */ 397 398 class Session_tracker 399 { 400 State_tracker *m_trackers[SESSION_TRACKER_END]; 401 402 /* The following two functions are private to disable copying. */ Session_tracker(Session_tracker const & other)403 Session_tracker(Session_tracker const &other) 404 { 405 DBUG_ASSERT(FALSE); 406 } 407 Session_tracker& operator= (Session_tracker const &rhs) 408 { 409 DBUG_ASSERT(FALSE); 410 return *this; 411 } 412 413 public: 414 Current_schema_tracker current_schema; 415 Session_state_change_tracker state_change; 416 Transaction_state_tracker transaction_info; 417 Session_sysvars_tracker sysvars; 418 Session_tracker()419 Session_tracker() 420 { 421 m_trackers[SESSION_SYSVARS_TRACKER]= &sysvars; 422 m_trackers[CURRENT_SCHEMA_TRACKER]= ¤t_schema; 423 m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change; 424 m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info; 425 } 426 enable(THD * thd)427 void enable(THD *thd) 428 { 429 for (int i= 0; i < SESSION_TRACKER_END; i++) 430 m_trackers[i]->enable(thd); 431 } 432 mark_as_changed(THD * thd,enum enum_session_tracker tracker,LEX_CSTRING * data)433 inline void mark_as_changed(THD *thd, enum enum_session_tracker tracker, 434 LEX_CSTRING *data) 435 { 436 if (m_trackers[tracker]->is_enabled()) 437 m_trackers[tracker]->mark_as_changed(thd, data); 438 } 439 440 441 void store(THD *thd, String *main_buf); 442 }; 443 444 445 int session_tracker_init(); 446 #else 447 448 #define TRANSACT_TRACKER(X) do{}while(0) 449 #define SESSION_TRACKER_CHANGED(A,B,C) do{}while(0) 450 451 #endif //EMBEDDED_LIBRARY 452 453 #endif /* SESSION_TRACKER_INCLUDED */ 454