1 #ifndef SYS_VARS_H_INCLUDED 2 #define SYS_VARS_H_INCLUDED 3 /* Copyright (c) 2002, 2021, Oracle and/or its affiliates. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License, version 2.0, 7 as published by the Free Software Foundation. 8 9 This program is also distributed with certain software (including 10 but not limited to OpenSSL) that is licensed under separate terms, 11 as designated in a particular file or component or in included license 12 documentation. The authors of MySQL hereby grant you an additional 13 permission to link the program and your derivative works with the 14 separately licensed software that they have included with MySQL. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License, version 2.0, for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program; if not, write to the Free Software 23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 24 25 /** 26 @file 27 "private" interface to sys_var - server configuration variables. 28 29 This header is included only by the file that contains declarations 30 of sys_var variables (sys_vars.cc). 31 */ 32 33 #include "my_global.h" 34 #include "keycaches.h" // dflt_key_cache 35 #include "my_bit.h" // my_count_bits 36 #include "my_getopt.h" // get_opt_arg_type 37 #include "mysql/plugin.h" // enum_mysql_show_type 38 #include "item.h" // Item 39 #include "log.h" // sql_print_information 40 #include "set_var.h" // sys_var 41 #include "sql_class.h" // THD 42 #include "sql_plugin.h" // my_plugin_lock_by_name 43 #include "strfunc.h" // find_type 44 #include "sys_vars_shared.h" // throw_bounds_warning 45 #include "tztime.h" // Time_zone 46 #include "binlog.h" // mysql_bin_log 47 #include "rpl_rli.h" // sql_slave_skip_counter 48 #include "rpl_msr.h" // channel_map 49 #include "rpl_group_replication.h"// is_group_replication_running 50 51 52 /* 53 a set of mostly trivial (as in f(X)=X) defines below to make system variable 54 declarations more readable 55 */ 56 #define VALID_RANGE(X,Y) X,Y 57 #define DEFAULT(X) X 58 #define BLOCK_SIZE(X) X 59 #define GLOBAL_VAR(X) sys_var::GLOBAL, (((char*)&(X))-(char*)&global_system_variables), sizeof(X) 60 #define SESSION_VAR(X) sys_var::SESSION, offsetof(SV, X), sizeof(((SV *)0)->X) 61 #define SESSION_ONLY(X) sys_var::ONLY_SESSION, offsetof(SV, X), sizeof(((SV *)0)->X) 62 #define NO_CMD_LINE CMD_LINE(NO_ARG, -1) 63 /* 64 the define below means that there's no *second* mutex guard, 65 LOCK_global_system_variables always guards all system variables 66 */ 67 #define NO_MUTEX_GUARD ((PolyLock*)0) 68 #define IN_BINLOG sys_var::SESSION_VARIABLE_IN_BINLOG 69 #define NOT_IN_BINLOG sys_var::VARIABLE_NOT_IN_BINLOG 70 #define ON_READ(X) X 71 #define ON_CHECK(X) X 72 #define PRE_UPDATE(X) X 73 #define ON_UPDATE(X) X 74 #define READ_ONLY sys_var::READONLY+ 75 #define NOT_VISIBLE sys_var::INVISIBLE+ 76 #define UNTRACKED_DEFAULT sys_var::TRI_LEVEL+ 77 // this means that Sys_var_charptr initial value was malloc()ed 78 #define PREALLOCATED sys_var::ALLOCATED+ 79 /* 80 Sys_var_bit meaning is reversed, like in 81 @@foreign_key_checks <-> OPTION_NO_FOREIGN_KEY_CHECKS 82 */ 83 #define REVERSE(X) ~(X) 84 #define DEPRECATED_VAR(X) X 85 86 #define session_var(THD, TYPE) (*(TYPE*)session_var_ptr(THD)) 87 #define global_var(TYPE) (*(TYPE*)global_var_ptr()) 88 89 #if SIZEOF_OFF_T > 4 90 #define GET_HA_ROWS GET_ULL 91 #else 92 #define GET_HA_ROWS GET_ULONG 93 #endif 94 95 extern sys_var_chain all_sys_vars; 96 97 enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET}; 98 99 static const char *bool_values[3]= {"OFF", "ON", 0}; 100 101 /** 102 A small wrapper class to pass getopt arguments as a pair 103 to the Sys_var_* constructors. It improves type safety and helps 104 to catch errors in the argument order. 105 */ 106 struct CMD_LINE 107 { 108 int id; 109 enum get_opt_arg_type arg_type; 110 CMD_LINE(enum get_opt_arg_type getopt_arg_type, int getopt_id=0) idCMD_LINE111 : id(getopt_id), arg_type(getopt_arg_type) {} 112 }; 113 114 /** 115 Sys_var_integer template is used to generate Sys_var_* classes 116 for variables that represent the value as a signed or unsigned integer. 117 They are Sys_var_uint, Sys_var_ulong, Sys_var_harows, Sys_var_ulonglong, 118 and Sys_var_long. 119 120 An integer variable has a minimal and maximal values, and a "block_size" 121 (any valid value of the variable must be divisible by the block_size). 122 123 Class specific constructor arguments: min, max, block_size 124 Backing store: uint, ulong, ha_rows, ulonglong, long, depending on the 125 Sys_var_* 126 */ 127 template 128 <typename T, ulong ARGT, enum enum_mysql_show_type SHOWT, bool SIGNED> 129 class Sys_var_integer: public sys_var 130 { 131 public: 132 Sys_var_integer(const char *name_arg, 133 const char *comment, int flag_args, ptrdiff_t off, size_t size, 134 CMD_LINE getopt, 135 T min_val, T max_val, T def_val, uint block_size, PolyLock *lock=0, 136 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 137 on_check_function on_check_func=0, 138 on_update_function on_update_func=0, 139 const char *substitute=0, 140 int parse_flag= PARSE_NORMAL) 141 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 142 getopt.arg_type, SHOWT, def_val, lock, binlog_status_arg, 143 on_check_func, on_update_func, 144 substitute, parse_flag) 145 { 146 option.var_type= ARGT; 147 option.min_value= min_val; 148 option.max_value= max_val; 149 option.block_size= block_size; 150 option.u_max_value= (uchar**)max_var_ptr(); 151 if (max_var_ptr()) 152 *max_var_ptr()= max_val; 153 154 // Do not set global_var for Sys_var_keycache objects 155 if (offset >= 0) 156 global_var(T)= def_val; 157 158 assert(size == sizeof(T)); 159 assert(min_val < max_val); 160 assert(min_val <= def_val); 161 assert(max_val >= def_val); 162 assert(block_size > 0); 163 assert(def_val % block_size == 0); 164 } 165 bool do_check(THD *thd, set_var *var) 166 { 167 my_bool fixed= FALSE; 168 longlong v; 169 ulonglong uv; 170 171 v= var->value->val_int(); 172 if (SIGNED) /* target variable has signed type */ 173 { 174 if (var->value->unsigned_flag) 175 { 176 /* 177 Input value is such a large positive number that MySQL used an 178 unsigned item to hold it. When cast to a signed longlong, if the 179 result is negative there is "cycling" and this is incorrect (large 180 positive input value should not end up as a large negative value in 181 the session signed variable to be set); instead, we need to pick the 182 allowed number closest to the positive input value, i.e. pick the 183 biggest allowed positive integer. 184 */ 185 if (v < 0) 186 uv= max_of_int_range(ARGT); 187 else /* no cycling, longlong can hold true value */ 188 uv= (ulonglong) v; 189 } 190 else 191 uv= v; 192 /* This will further restrict with VALID_RANGE, BLOCK_SIZE */ 193 var->save_result.ulonglong_value= 194 getopt_ll_limit_value(uv, &option, &fixed); 195 } 196 else 197 { 198 if (var->value->unsigned_flag) 199 { 200 /* Guaranteed positive input value, ulonglong can hold it */ 201 uv= (ulonglong) v; 202 } 203 else 204 { 205 /* 206 Maybe negative input value; in this case, cast to ulonglong makes it 207 positive, which is wrong. Pick the closest allowed value i.e. 0. 208 */ 209 uv= (ulonglong) (v < 0 ? 0 : v); 210 } 211 var->save_result.ulonglong_value= 212 getopt_ull_limit_value(uv, &option, &fixed); 213 } 214 215 if (max_var_ptr()) 216 { 217 /* check constraint set with --maximum-...=X */ 218 if (SIGNED) 219 { 220 longlong max_val= *max_var_ptr(); 221 if (((longlong)(var->save_result.ulonglong_value)) > max_val) 222 var->save_result.ulonglong_value= max_val; 223 /* 224 Signed variable probably has some kind of symmetry. Then it's good 225 to limit negative values just as we limit positive values. 226 */ 227 max_val= -max_val; 228 if (((longlong)(var->save_result.ulonglong_value)) < max_val) 229 var->save_result.ulonglong_value= max_val; 230 } 231 else 232 { 233 ulonglong max_val= *max_var_ptr(); 234 if (var->save_result.ulonglong_value > max_val) 235 var->save_result.ulonglong_value= max_val; 236 } 237 } 238 239 return throw_bounds_warning(thd, name.str, 240 var->save_result.ulonglong_value != 241 (ulonglong)v, 242 var->value->unsigned_flag, v); 243 } 244 bool session_update(THD *thd, set_var *var) 245 { 246 session_var(thd, T)= static_cast<T>(var->save_result.ulonglong_value); 247 return false; 248 } 249 bool global_update(THD *thd, set_var *var) 250 { 251 global_var(T)= static_cast<T>(var->save_result.ulonglong_value); 252 return false; 253 } 254 bool check_update_type(Item_result type) 255 { return type != INT_RESULT; } 256 void session_save_default(THD *thd, set_var *var) 257 { 258 var->save_result.ulonglong_value= 259 static_cast<ulonglong>(*(T*)global_value_ptr(thd, 0)); 260 } 261 void global_save_default(THD *thd, set_var *var) 262 { var->save_result.ulonglong_value= option.def_value; } 263 private: 264 T *max_var_ptr() 265 { 266 return scope() == SESSION ? (T*)(((uchar*)&max_system_variables) + offset) 267 : 0; 268 } 269 }; 270 271 typedef Sys_var_integer<int32, GET_UINT, SHOW_INT, FALSE> Sys_var_int32; 272 typedef Sys_var_integer<uint, GET_UINT, SHOW_INT, FALSE> Sys_var_uint; 273 typedef Sys_var_integer<ulong, GET_ULONG, SHOW_LONG, FALSE> Sys_var_ulong; 274 typedef Sys_var_integer<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS, FALSE> 275 Sys_var_harows; 276 typedef Sys_var_integer<ulonglong, GET_ULL, SHOW_LONGLONG, FALSE> 277 Sys_var_ulonglong; 278 typedef Sys_var_integer<long, GET_LONG, SHOW_SIGNED_LONG, TRUE> Sys_var_long; 279 280 /** 281 Helper class for variables that take values from a TYPELIB 282 */ 283 class Sys_var_typelib: public sys_var 284 { 285 protected: 286 TYPELIB typelib; 287 public: 288 Sys_var_typelib(const char *name_arg, 289 const char *comment, int flag_args, ptrdiff_t off, 290 CMD_LINE getopt, 291 SHOW_TYPE show_val_type_arg, const char *values[], 292 ulonglong def_val, PolyLock *lock, 293 enum binlog_status_enum binlog_status_arg, 294 on_check_function on_check_func, on_update_function on_update_func, 295 const char *substitute, int parse_flag= PARSE_NORMAL) 296 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 297 getopt.arg_type, show_val_type_arg, def_val, lock, 298 binlog_status_arg, on_check_func, 299 on_update_func, substitute, parse_flag) 300 { 301 for (typelib.count= 0; values[typelib.count]; typelib.count++) /*no-op */; 302 typelib.name=""; 303 typelib.type_names= values; 304 typelib.type_lengths= 0; // only used by Fields_enum and Field_set 305 option.typelib= &typelib; 306 } do_check(THD * thd,set_var * var)307 bool do_check(THD *thd, set_var *var) // works for enums and my_bool 308 { 309 char buff[STRING_BUFFER_USUAL_SIZE]; 310 String str(buff, sizeof(buff), system_charset_info), *res; 311 312 if (var->value->result_type() == STRING_RESULT) 313 { 314 if (!(res=var->value->val_str(&str))) 315 return true; 316 else 317 if (!(var->save_result.ulonglong_value= 318 find_type(&typelib, res->ptr(), res->length(), false))) 319 return true; 320 else 321 var->save_result.ulonglong_value--; 322 } 323 else 324 { 325 longlong tmp=var->value->val_int(); 326 if (tmp < 0 || tmp >= typelib.count) 327 return true; 328 else 329 var->save_result.ulonglong_value= tmp; 330 } 331 332 return false; 333 } check_update_type(Item_result type)334 bool check_update_type(Item_result type) 335 { return type != INT_RESULT && type != STRING_RESULT; } 336 }; 337 338 /** 339 The class for ENUM variables - variables that take one value from a fixed 340 list of values. 341 342 Class specific constructor arguments: 343 char* values[] - 0-terminated list of strings of valid values 344 345 Backing store: uint 346 347 @note 348 Do *not* use "enum FOO" variables as a backing store, there is no 349 guarantee that sizeof(enum FOO) == sizeof(uint), there is no guarantee 350 even that sizeof(enum FOO) == sizeof(enum BAR) 351 */ 352 class Sys_var_enum: public Sys_var_typelib 353 { 354 public: 355 Sys_var_enum(const char *name_arg, 356 const char *comment, int flag_args, ptrdiff_t off, size_t size, 357 CMD_LINE getopt, 358 const char *values[], uint def_val, PolyLock *lock=0, 359 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 360 on_check_function on_check_func=0, 361 on_update_function on_update_func=0, 362 const char *substitute=0) Sys_var_typelib(name_arg,comment,flag_args,off,getopt,SHOW_CHAR,values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)363 : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, 364 SHOW_CHAR, values, def_val, lock, 365 binlog_status_arg, on_check_func, on_update_func, 366 substitute) 367 { 368 option.var_type= GET_ENUM; 369 global_var(ulong)= def_val; 370 assert(def_val < typelib.count); 371 assert(size == sizeof(ulong)); 372 } session_update(THD * thd,set_var * var)373 bool session_update(THD *thd, set_var *var) 374 { 375 session_var(thd, ulong)= 376 static_cast<ulong>(var->save_result.ulonglong_value); 377 return false; 378 } global_update(THD * thd,set_var * var)379 bool global_update(THD *thd, set_var *var) 380 { 381 global_var(ulong)= 382 static_cast<ulong>(var->save_result.ulonglong_value); 383 return false; 384 } session_save_default(THD * thd,set_var * var)385 void session_save_default(THD *thd, set_var *var) 386 { var->save_result.ulonglong_value= global_var(ulong); } global_save_default(THD * thd,set_var * var)387 void global_save_default(THD *thd, set_var *var) 388 { var->save_result.ulonglong_value= option.def_value; } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)389 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 390 { return (uchar*)typelib.type_names[session_var(target_thd, ulong)]; } global_value_ptr(THD * thd,LEX_STRING * base)391 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 392 { return (uchar*)typelib.type_names[global_var(ulong)]; } 393 }; 394 395 /** 396 The class for boolean variables - a variant of ENUM variables 397 with the fixed list of values of { OFF , ON } 398 399 Backing store: my_bool 400 */ 401 class Sys_var_mybool: public Sys_var_typelib 402 { 403 public: 404 Sys_var_mybool(const char *name_arg, 405 const char *comment, int flag_args, ptrdiff_t off, size_t size, 406 CMD_LINE getopt, 407 my_bool def_val, PolyLock *lock=0, 408 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 409 on_check_function on_check_func=0, 410 on_update_function on_update_func=0, 411 const char *substitute=0, 412 int parse_flag= PARSE_NORMAL) Sys_var_typelib(name_arg,comment,flag_args,off,getopt,SHOW_MY_BOOL,bool_values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute,parse_flag)413 : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, 414 SHOW_MY_BOOL, bool_values, def_val, lock, 415 binlog_status_arg, on_check_func, on_update_func, 416 substitute, parse_flag) 417 { 418 option.var_type= GET_BOOL; 419 global_var(my_bool)= def_val; 420 assert(def_val < 2); 421 assert(getopt.arg_type == OPT_ARG || getopt.id == -1); 422 assert(size == sizeof(my_bool)); 423 } session_update(THD * thd,set_var * var)424 bool session_update(THD *thd, set_var *var) 425 { 426 session_var(thd, my_bool)= 427 static_cast<my_bool>(var->save_result.ulonglong_value); 428 return false; 429 } global_update(THD * thd,set_var * var)430 bool global_update(THD *thd, set_var *var) 431 { 432 global_var(my_bool)= 433 static_cast<my_bool>(var->save_result.ulonglong_value); 434 return false; 435 } session_save_default(THD * thd,set_var * var)436 void session_save_default(THD *thd, set_var *var) 437 { 438 var->save_result.ulonglong_value= 439 static_cast<ulonglong>(*(my_bool *)global_value_ptr(thd, 0)); 440 } global_save_default(THD * thd,set_var * var)441 void global_save_default(THD *thd, set_var *var) 442 { var->save_result.ulonglong_value= option.def_value; } 443 }; 444 445 446 /** 447 A variant of enum where: 448 - Each value may have multiple enum-like aliases. 449 - Instances of the class can specify different default values for 450 the cases: 451 - User specifies the command-line option without a value (i.e., 452 --option, not --option=value). 453 - User does not specify a command-line option at all. 454 455 This exists mainly to allow extending a variable that once was 456 boolean in a GA version, into an enumeration type. Booleans accept 457 multiple aliases (0=off=false, 1=on=true), but Sys_var_enum does 458 not, so we could not use Sys_var_enum without breaking backward 459 compatibility. Moreover, booleans default to false if option is not 460 given, and true if option is given without value. 461 462 This is *incompatible* with boolean in the following sense: 463 'SELECT @@variable' returns 0 or 1 for a boolean, whereas this class 464 (similar to enum) returns the textual form. (Note that both boolean, 465 enum, and this class return the textual form in SHOW VARIABLES and 466 SELECT * FROM information_schema.variables). 467 468 See enforce_gtid_consistency for an example of how this can be used. 469 */ 470 class Sys_var_multi_enum : public sys_var 471 { 472 public: 473 struct ALIAS 474 { 475 const char *alias; 476 uint number; 477 }; 478 479 /** 480 Class specific parameters: 481 482 @param aliases_arg Array of ALIASes, indicating which textual 483 values map to which number. Should be terminated with an ALIAS 484 having member variable alias set to NULL. The first 485 `value_count_arg' elements must map to 0, 1, etc; these will be 486 used when the value is displayed. Remaining elements may appear 487 in arbitrary order. 488 489 @param value_count_arg The number of allowed integer values. 490 491 @param def_val The default value if no command line option is 492 given. This must be a valid index into the aliases_arg array, but 493 it does not have to be less than value_count. The corresponding 494 alias will be used in mysqld --help to show the default value. 495 496 @param command_line_no_value The default value if a command line 497 option is given without a value ('--command-line-option' without 498 '=VALUE'). This must be less than value_count_arg. 499 */ 500 Sys_var_multi_enum(const char *name_arg, 501 const char *comment, int flag_args, ptrdiff_t off, size_t size, 502 CMD_LINE getopt, 503 const ALIAS aliases_arg[], uint value_count_arg, 504 uint def_val, uint command_line_no_value_arg, PolyLock *lock=0, 505 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 506 on_check_function on_check_func=0, 507 on_update_function on_update_func=0, 508 const char *substitute=0, 509 int parse_flag= PARSE_NORMAL) 510 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 511 getopt.arg_type, SHOW_CHAR, def_val, lock, 512 binlog_status_arg, on_check_func, 513 on_update_func, substitute, parse_flag), 514 value_count(value_count_arg), 515 aliases(aliases_arg), 516 command_line_no_value(command_line_no_value_arg) 517 { 518 for (alias_count= 0; aliases[alias_count].alias; alias_count++) 519 assert(aliases[alias_count].number < value_count); 520 assert(def_val < alias_count); 521 522 option.var_type= GET_STR; 523 option.value= &command_line_value; 524 option.def_value= (intptr)aliases[def_val].alias; 525 526 global_var(ulong)= aliases[def_val].number; 527 528 assert(getopt.arg_type == OPT_ARG || getopt.id == -1); 529 assert(size == sizeof(ulong)); 530 } 531 532 /** 533 Return the numeric value for a given alias string, or -1 if the 534 string is not a valid alias. 535 */ find_value(const char * text)536 int find_value(const char *text) 537 { 538 for (uint i= 0; aliases[i].alias != NULL; i++) 539 if (my_strcasecmp(system_charset_info, aliases[i].alias, text) == 0) 540 return aliases[i].number; 541 return -1; 542 } 543 544 /** 545 Because of limitations in the command-line parsing library, the 546 value given on the command-line cannot be automatically copied to 547 the global value. Instead, inheritants of this class should call 548 this function from mysqld.cc:mysqld_get_one_option. 549 550 @param value_str Pointer to the value specified on the command 551 line (as in --option=VALUE). 552 553 @retval NULL Success. 554 555 @retval non-NULL Pointer to the invalid string that was used as 556 argument. 557 */ fixup_command_line(const char * value_str)558 const char *fixup_command_line(const char *value_str) 559 { 560 DBUG_ENTER("Sys_var_multi_enum::fixup_command_line"); 561 char *end= NULL; 562 long value; 563 564 // User passed --option (not --option=value). 565 if (value_str == NULL) 566 { 567 value= command_line_no_value; 568 goto end; 569 } 570 571 // Get textual value. 572 value= find_value(value_str); 573 if (value != -1) 574 goto end; 575 576 // Get numeric value. 577 value= strtol(value_str, &end, 10); 578 // found a number and nothing else? 579 if (end > value_str && *end == '\0') 580 // value is in range? 581 if (value >= 0 && (longlong)value < (longlong)value_count) 582 goto end; 583 584 // Not a valid value. 585 DBUG_RETURN(value_str); 586 587 end: 588 global_var(ulong)= value; 589 DBUG_RETURN(NULL); 590 } 591 do_check(THD * thd,set_var * var)592 bool do_check(THD *thd, set_var *var) 593 { 594 DBUG_ENTER("Sys_var_multi_enum::do_check"); 595 char buff[STRING_BUFFER_USUAL_SIZE]; 596 String str(buff, sizeof(buff), system_charset_info), *res; 597 if (var->value->result_type() == STRING_RESULT) 598 { 599 res= var->value->val_str(&str); 600 if (!res) 601 DBUG_RETURN(true); 602 int value= find_value(res->ptr()); 603 if (value == -1) 604 DBUG_RETURN(true); 605 var->save_result.ulonglong_value= (uint)value; 606 } 607 else 608 { 609 longlong value= var->value->val_int(); 610 if (value < 0 || value >= (longlong)value_count) 611 DBUG_RETURN(true); 612 else 613 var->save_result.ulonglong_value= value; 614 } 615 616 DBUG_RETURN(false); 617 } check_update_type(Item_result type)618 bool check_update_type(Item_result type) 619 { return type != INT_RESULT && type != STRING_RESULT; } session_update(THD * thd,set_var * var)620 bool session_update(THD *thd, set_var *var) 621 { 622 DBUG_ENTER("Sys_var_multi_enum::session_update"); 623 assert(0); 624 /* 625 Currently not used: uncomment if this class is used as a base for 626 a session variable. 627 628 session_var(thd, ulong)= 629 static_cast<ulong>(var->save_result.ulonglong_value); 630 */ 631 DBUG_RETURN(false); 632 } global_update(THD * thd,set_var * var)633 bool global_update(THD *thd, set_var *var) 634 { 635 DBUG_ENTER("Sys_var_multi_enum::global_update"); 636 assert(0); 637 /* 638 Currently not used: uncomment if this some inheriting class does 639 not override.. 640 641 ulong val= 642 static_cast<ulong>(var->save_result.ulonglong_value); 643 global_var(ulong)= val; 644 */ 645 DBUG_RETURN(false); 646 } session_save_default(THD * thd,set_var * var)647 void session_save_default(THD *thd, set_var *var) 648 { 649 DBUG_ENTER("Sys_var_multi_enum::session_save_default"); 650 assert(0); 651 /* 652 Currently not used: uncomment if this class is used as a base for 653 a session variable. 654 655 int value= find_value((char *)option.def_value); 656 assert(value != -1); 657 var->save_result.ulonglong_value= value; 658 */ 659 DBUG_VOID_RETURN; 660 } global_save_default(THD * thd,set_var * var)661 void global_save_default(THD *thd, set_var *var) 662 { 663 DBUG_ENTER("Sys_var_multi_enum::global_save_default"); 664 int value= find_value((char *)option.def_value); 665 assert(value != -1); 666 var->save_result.ulonglong_value= value; 667 DBUG_VOID_RETURN; 668 } 669 session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)670 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 671 { 672 DBUG_ENTER("Sys_var_multi_enum::session_value_ptr"); 673 assert(0); 674 /* 675 Currently not used: uncomment if this class is used as a base for 676 a session variable. 677 678 DBUG_RETURN((uchar*)aliases[session_var(target_thd, ulong)].alias); 679 */ 680 DBUG_RETURN(0); 681 } global_value_ptr(THD * thd,LEX_STRING * base)682 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 683 { 684 DBUG_ENTER("Sys_var_multi_enum::global_value_ptr"); 685 DBUG_RETURN((uchar*)aliases[global_var(ulong)].alias); 686 } 687 private: 688 /// The number of allowed numeric values. 689 const uint value_count; 690 /// Array of all textual aliases. 691 const ALIAS *aliases; 692 /// The number of elements of aliases (computed in the constructor). 693 uint alias_count; 694 695 /** 696 Pointer to the value set by the command line (set by the command 697 line parser, copied to the global value in fixup_command_line()). 698 */ 699 const char *command_line_value; 700 uint command_line_no_value; 701 }; 702 703 /** 704 The class for string variables. The string can be in character_set_filesystem 705 or in character_set_system. The string can be allocated with my_malloc() 706 or not. The state of the initial value is specified in the constructor, 707 after that it's managed automatically. The value of NULL is supported. 708 709 Class specific constructor arguments: 710 enum charset_enum is_os_charset_arg 711 712 Backing store: char* 713 714 */ 715 class Sys_var_charptr: public sys_var 716 { 717 public: 718 Sys_var_charptr(const char *name_arg, 719 const char *comment, int flag_args, ptrdiff_t off, size_t size, 720 CMD_LINE getopt, 721 enum charset_enum is_os_charset_arg, 722 const char *def_val, PolyLock *lock= 0, 723 enum binlog_status_enum binlog_status_arg= VARIABLE_NOT_IN_BINLOG, 724 on_check_function on_check_func= 0, 725 on_update_function on_update_func= 0, 726 const char *substitute= 0, 727 int parse_flag= PARSE_NORMAL) 728 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 729 getopt.arg_type, SHOW_CHAR_PTR, (intptr) def_val, 730 lock, binlog_status_arg, on_check_func, on_update_func, 731 substitute, parse_flag) 732 { 733 is_os_charset= is_os_charset_arg == IN_FS_CHARSET; 734 option.var_type= (flags & ALLOCATED) ? GET_STR_ALLOC : GET_STR; 735 global_var(const char*)= def_val; 736 assert(size == sizeof(char *)); 737 } 738 cleanup()739 void cleanup() 740 { 741 if (flags & ALLOCATED) 742 my_free(global_var(char*)); 743 flags&= ~ALLOCATED; 744 } 745 do_check(THD * thd,set_var * var)746 bool do_check(THD *thd, set_var *var) 747 { 748 char buff[STRING_BUFFER_USUAL_SIZE], buff2[STRING_BUFFER_USUAL_SIZE]; 749 String str(buff, sizeof(buff), charset(thd)); 750 String str2(buff2, sizeof(buff2), charset(thd)), *res; 751 752 if (!(res=var->value->val_str(&str))) 753 var->save_result.string_value.str= 0; 754 else 755 { 756 size_t unused; 757 if (String::needs_conversion(res->length(), res->charset(), 758 charset(thd), &unused)) 759 { 760 uint errors; 761 str2.copy(res->ptr(), res->length(), res->charset(), charset(thd), 762 &errors); 763 res= &str2; 764 765 } 766 var->save_result.string_value.str= thd->strmake(res->ptr(), res->length()); 767 var->save_result.string_value.length= res->length(); 768 } 769 770 return false; 771 } 772 session_update(THD * thd,set_var * var)773 bool session_update(THD *thd, set_var *var) 774 { 775 char *new_val= var->save_result.string_value.str; 776 size_t new_val_len= var->save_result.string_value.length; 777 char *ptr= ((char *)&thd->variables + offset); 778 779 return thd->session_sysvar_res_mgr.update((char **) ptr, new_val, 780 new_val_len); 781 } 782 global_update(THD * thd,set_var * var)783 bool global_update(THD *thd, set_var *var) 784 { 785 char *new_val, *ptr= var->save_result.string_value.str; 786 size_t len=var->save_result.string_value.length; 787 if (ptr) 788 { 789 new_val= (char*) my_memdup(key_memory_Sys_var_charptr_value, 790 ptr, len+1, MYF(MY_WME)); 791 if (!new_val) return true; 792 new_val[len]= 0; 793 } 794 else 795 new_val= 0; 796 if (flags & ALLOCATED) 797 my_free(global_var(char*)); 798 flags |= ALLOCATED; 799 global_var(char*)= new_val; 800 return false; 801 } 802 session_save_default(THD * thd,set_var * var)803 void session_save_default(THD *thd, set_var *var) 804 { 805 char *ptr= (char*)(intptr)option.def_value; 806 var->save_result.string_value.str= ptr; 807 var->save_result.string_value.length= ptr ? strlen(ptr) : 0; 808 } 809 global_save_default(THD * thd,set_var * var)810 void global_save_default(THD *thd, set_var *var) 811 { 812 char *ptr= (char*)(intptr)option.def_value; 813 var->save_result.string_value.str= ptr; 814 var->save_result.string_value.length= ptr ? strlen(ptr) : 0; 815 } 816 check_update_type(Item_result type)817 bool check_update_type(Item_result type) 818 { return type != STRING_RESULT; } 819 }; 820 821 class Sys_var_version : public Sys_var_charptr 822 { 823 public: Sys_var_version(const char * name_arg,const char * comment,int flag_args,ptrdiff_t off,size_t size,CMD_LINE getopt,enum charset_enum is_os_charset_arg,const char * def_val)824 Sys_var_version(const char *name_arg, 825 const char *comment, int flag_args, ptrdiff_t off, size_t size, 826 CMD_LINE getopt, 827 enum charset_enum is_os_charset_arg, 828 const char *def_val) 829 : Sys_var_charptr(name_arg, comment, flag_args, off, size, getopt, is_os_charset_arg, def_val) 830 {} 831 ~Sys_var_version()832 ~Sys_var_version() 833 {} 834 global_value_ptr(THD * thd,LEX_STRING * base)835 virtual uchar *global_value_ptr(THD *thd, LEX_STRING *base) 836 { 837 uchar *value= Sys_var_charptr::global_value_ptr(thd, base); 838 839 DBUG_EXECUTE_IF("alter_server_version_str", 840 { 841 static const char *altered_value= "some-other-version"; 842 uchar *altered_value_ptr= reinterpret_cast<uchar*> (& altered_value); 843 value= altered_value_ptr; 844 }); 845 846 return value; 847 } 848 }; 849 850 851 class Sys_var_proxy_user: public sys_var 852 { 853 public: Sys_var_proxy_user(const char * name_arg,const char * comment,enum charset_enum is_os_charset_arg)854 Sys_var_proxy_user(const char *name_arg, 855 const char *comment, enum charset_enum is_os_charset_arg) 856 : sys_var(&all_sys_vars, name_arg, comment, 857 sys_var::READONLY+sys_var::ONLY_SESSION, 0, -1, 858 NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG, 859 NULL, NULL, NULL, PARSE_NORMAL) 860 { 861 is_os_charset= is_os_charset_arg == IN_FS_CHARSET; 862 option.var_type= GET_STR; 863 } do_check(THD * thd,set_var * var)864 bool do_check(THD *thd, set_var *var) 865 { 866 assert(FALSE); 867 return true; 868 } session_update(THD * thd,set_var * var)869 bool session_update(THD *thd, set_var *var) 870 { 871 assert(FALSE); 872 return true; 873 } global_update(THD * thd,set_var * var)874 bool global_update(THD *thd, set_var *var) 875 { 876 assert(FALSE); 877 return false; 878 } session_save_default(THD * thd,set_var * var)879 void session_save_default(THD *thd, set_var *var) 880 { assert(FALSE); } global_save_default(THD * thd,set_var * var)881 void global_save_default(THD *thd, set_var *var) 882 { assert(FALSE); } check_update_type(Item_result type)883 bool check_update_type(Item_result type) 884 { return true; } 885 protected: session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)886 virtual uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 887 { 888 const char* proxy_user= target_thd->security_context()->proxy_user().str; 889 return proxy_user[0] ? (uchar *)proxy_user : NULL; 890 } 891 }; 892 893 class Sys_var_external_user : public Sys_var_proxy_user 894 { 895 public: Sys_var_external_user(const char * name_arg,const char * comment_arg,enum charset_enum is_os_charset_arg)896 Sys_var_external_user(const char *name_arg, const char *comment_arg, 897 enum charset_enum is_os_charset_arg) 898 : Sys_var_proxy_user (name_arg, comment_arg, is_os_charset_arg) 899 {} 900 901 protected: session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)902 virtual uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 903 { 904 LEX_CSTRING external_user= target_thd->security_context()->external_user(); 905 return external_user.length ? (uchar *) external_user.str : NULL; 906 } 907 }; 908 909 /** 910 The class for string variables. Useful for strings that aren't necessarily 911 \0-terminated. Otherwise the same as Sys_var_charptr. 912 913 Class specific constructor arguments: 914 enum charset_enum is_os_charset_arg 915 916 Backing store: LEX_STRING 917 918 @note 919 Behaves exactly as Sys_var_charptr, only the backing store is different. 920 */ 921 class Sys_var_lexstring: public Sys_var_charptr 922 { 923 public: 924 Sys_var_lexstring(const char *name_arg, 925 const char *comment, int flag_args, ptrdiff_t off, size_t size, 926 CMD_LINE getopt, 927 enum charset_enum is_os_charset_arg, 928 const char *def_val, PolyLock *lock=0, 929 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 930 on_check_function on_check_func=0, 931 on_update_function on_update_func=0, 932 const char *substitute=0) Sys_var_charptr(name_arg,comment,flag_args,off,sizeof (char *),getopt,is_os_charset_arg,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)933 : Sys_var_charptr(name_arg, comment, flag_args, off, sizeof(char*), 934 getopt, is_os_charset_arg, def_val, lock, binlog_status_arg, 935 on_check_func, on_update_func, substitute) 936 { 937 global_var(LEX_STRING).length= strlen(def_val); 938 assert(size == sizeof(LEX_STRING)); 939 *const_cast<SHOW_TYPE*>(&show_val_type)= SHOW_LEX_STRING; 940 } global_update(THD * thd,set_var * var)941 bool global_update(THD *thd, set_var *var) 942 { 943 if (Sys_var_charptr::global_update(thd, var)) 944 return true; 945 global_var(LEX_STRING).length= var->save_result.string_value.length; 946 return false; 947 } 948 }; 949 950 #ifndef NDEBUG 951 /** 952 @@session.dbug and @@global.dbug variables. 953 954 @@dbug variable differs from other variables in one aspect: 955 if its value is not assigned in the session, it "points" to the global 956 value, and so when the global value is changed, the change 957 immediately takes effect in the session. 958 959 This semantics is intentional, to be able to debug one session from 960 another. 961 */ 962 class Sys_var_dbug: public sys_var 963 { 964 public: 965 Sys_var_dbug(const char *name_arg, 966 const char *comment, int flag_args, 967 CMD_LINE getopt, 968 const char *def_val, PolyLock *lock=0, 969 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 970 on_check_function on_check_func=0, 971 on_update_function on_update_func=0, 972 const char *substitute=0, 973 int parse_flag= PARSE_NORMAL) 974 : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id, 975 getopt.arg_type, SHOW_CHAR, (intptr)def_val, 976 lock, binlog_status_arg, on_check_func, on_update_func, 977 substitute, parse_flag) 978 { option.var_type= GET_NO_ARG; } do_check(THD * thd,set_var * var)979 bool do_check(THD *thd, set_var *var) 980 { 981 char buff[STRING_BUFFER_USUAL_SIZE]; 982 String str(buff, sizeof(buff), system_charset_info), *res; 983 984 if (!(res=var->value->val_str(&str))) 985 var->save_result.string_value.str= const_cast<char*>(""); 986 else 987 var->save_result.string_value.str= thd->strmake(res->ptr(), res->length()); 988 return false; 989 } session_update(THD * thd,set_var * var)990 bool session_update(THD *thd, set_var *var) 991 { 992 const char *val= var->save_result.string_value.str; 993 if (!var->value) 994 DBUG_POP(); 995 else 996 DBUG_SET(val); 997 return false; 998 } global_update(THD * thd,set_var * var)999 bool global_update(THD *thd, set_var *var) 1000 { 1001 const char *val= var->save_result.string_value.str; 1002 DBUG_SET_INITIAL(val); 1003 return false; 1004 } session_save_default(THD * thd,set_var * var)1005 void session_save_default(THD *thd, set_var *var) 1006 { } global_save_default(THD * thd,set_var * var)1007 void global_save_default(THD *thd, set_var *var) 1008 { 1009 char *ptr= (char*)(intptr)option.def_value; 1010 var->save_result.string_value.str= ptr; 1011 } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1012 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1013 { 1014 char buf[256]; 1015 DBUG_EXPLAIN(buf, sizeof(buf)); 1016 return (uchar*) running_thd->mem_strdup(buf); 1017 } global_value_ptr(THD * thd,LEX_STRING * base)1018 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1019 { 1020 char buf[256]; 1021 DBUG_EXPLAIN_INITIAL(buf, sizeof(buf)); 1022 return (uchar*) thd->mem_strdup(buf); 1023 } check_update_type(Item_result type)1024 bool check_update_type(Item_result type) 1025 { return type != STRING_RESULT; } 1026 }; 1027 #endif 1028 1029 #define KEYCACHE_VAR(X) sys_var::GLOBAL,offsetof(KEY_CACHE, X), sizeof(((KEY_CACHE *)0)->X) 1030 #define keycache_var_ptr(KC, OFF) (((uchar*)(KC))+(OFF)) 1031 #define keycache_var(KC, OFF) (*(ulonglong*)keycache_var_ptr(KC, OFF)) 1032 typedef bool (*keycache_update_function)(THD *, KEY_CACHE *, ptrdiff_t, ulonglong); 1033 1034 /** 1035 The class for keycache_* variables. Supports structured names, 1036 keycache_name.variable_name. 1037 1038 Class specific constructor arguments: 1039 everything derived from Sys_var_ulonglong 1040 1041 Backing store: ulonglong 1042 1043 @note these variables can be only GLOBAL 1044 */ 1045 class Sys_var_keycache: public Sys_var_ulonglong 1046 { 1047 keycache_update_function keycache_update; 1048 public: 1049 Sys_var_keycache(const char *name_arg, 1050 const char *comment, int flag_args, ptrdiff_t off, size_t size, 1051 CMD_LINE getopt, 1052 ulonglong min_val, ulonglong max_val, ulonglong def_val, 1053 uint block_size, PolyLock *lock, 1054 enum binlog_status_enum binlog_status_arg, 1055 on_check_function on_check_func, 1056 keycache_update_function on_update_func, 1057 const char *substitute=0) 1058 : Sys_var_ulonglong(name_arg, comment, flag_args, 1059 -1, /* offset, see base class CTOR */ 1060 size, 1061 getopt, min_val, max_val, def_val, 1062 block_size, lock, binlog_status_arg, on_check_func, 0, 1063 substitute), 1064 keycache_update(on_update_func) 1065 { 1066 offset= off; /* Remember offset in KEY_CACHE */ 1067 option.var_type|= GET_ASK_ADDR; 1068 option.value= (uchar**)1; // crash me, please 1069 keycache_var(dflt_key_cache, off)= def_val; 1070 assert(scope() == GLOBAL); 1071 } global_update(THD * thd,set_var * var)1072 bool global_update(THD *thd, set_var *var) 1073 { 1074 ulonglong new_value= var->save_result.ulonglong_value; 1075 LEX_STRING *base_name= &var->base; 1076 KEY_CACHE *key_cache; 1077 1078 /* If no basename, assume it's for the key cache named 'default' */ 1079 if (!base_name->length) 1080 base_name= &default_key_cache_base; 1081 1082 key_cache= get_key_cache(base_name); 1083 1084 if (!key_cache) 1085 { // Key cache didn't exists */ 1086 if (!new_value) // Tried to delete cache 1087 return false; // Ok, nothing to do 1088 if (!(key_cache= create_key_cache(base_name->str, base_name->length))) 1089 return true; 1090 } 1091 1092 /** 1093 Abort if some other thread is changing the key cache 1094 @todo This should be changed so that we wait until the previous 1095 assignment is done and then do the new assign 1096 */ 1097 if (key_cache->in_init) 1098 return true; 1099 1100 return keycache_update(thd, key_cache, offset, new_value); 1101 } global_value_ptr(THD * thd,LEX_STRING * base)1102 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1103 { 1104 KEY_CACHE *key_cache= get_key_cache(base); 1105 if (!key_cache) 1106 key_cache= &zero_key_cache; 1107 return keycache_var_ptr(key_cache, offset); 1108 } 1109 }; 1110 1111 /** 1112 The class for floating point variables 1113 1114 Class specific constructor arguments: min, max 1115 1116 Backing store: double 1117 */ 1118 class Sys_var_double: public sys_var 1119 { 1120 public: 1121 Sys_var_double(const char *name_arg, 1122 const char *comment, int flag_args, ptrdiff_t off, size_t size, 1123 CMD_LINE getopt, 1124 double min_val, double max_val, double def_val, PolyLock *lock=0, 1125 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 1126 on_check_function on_check_func=0, 1127 on_update_function on_update_func=0, 1128 const char *substitute=0, 1129 int parse_flag= PARSE_NORMAL) 1130 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 1131 getopt.arg_type, SHOW_DOUBLE, 1132 (longlong) getopt_double2ulonglong(def_val), 1133 lock, binlog_status_arg, on_check_func, on_update_func, 1134 substitute, parse_flag) 1135 { 1136 option.var_type= GET_DOUBLE; 1137 option.min_value= (longlong) getopt_double2ulonglong(min_val); 1138 option.max_value= (longlong) getopt_double2ulonglong(max_val); 1139 global_var(double)= (double)option.def_value; 1140 assert(min_val <= max_val); 1141 assert(min_val <= def_val); 1142 assert(max_val >= def_val); 1143 assert(size == sizeof(double)); 1144 } do_check(THD * thd,set_var * var)1145 bool do_check(THD *thd, set_var *var) 1146 { 1147 my_bool fixed; 1148 double v= var->value->val_real(); 1149 var->save_result.double_value= getopt_double_limit_value(v, &option, &fixed); 1150 1151 return throw_bounds_warning(thd, name.str, fixed, v); 1152 } session_update(THD * thd,set_var * var)1153 bool session_update(THD *thd, set_var *var) 1154 { 1155 session_var(thd, double)= var->save_result.double_value; 1156 return false; 1157 } global_update(THD * thd,set_var * var)1158 bool global_update(THD *thd, set_var *var) 1159 { 1160 global_var(double)= var->save_result.double_value; 1161 return false; 1162 } check_update_type(Item_result type)1163 bool check_update_type(Item_result type) 1164 { 1165 return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT; 1166 } session_save_default(THD * thd,set_var * var)1167 void session_save_default(THD *thd, set_var *var) 1168 { var->save_result.double_value= global_var(double); } global_save_default(THD * thd,set_var * var)1169 void global_save_default(THD *thd, set_var *var) 1170 { var->save_result.double_value= getopt_ulonglong2double(option.def_value); } 1171 }; 1172 1173 /** 1174 The class for @test_flags (core_file for now). 1175 It's derived from Sys_var_mybool. 1176 1177 Class specific constructor arguments: 1178 Caller need not pass in a variable as we make up the value on the 1179 fly, that is, we derive it from the global test_flags bit vector. 1180 1181 Backing store: my_bool 1182 */ 1183 class Sys_var_test_flag: public Sys_var_mybool 1184 { 1185 private: 1186 my_bool test_flag_value; 1187 uint test_flag_mask; 1188 public: Sys_var_test_flag(const char * name_arg,const char * comment,uint mask)1189 Sys_var_test_flag(const char *name_arg, const char *comment, uint mask) 1190 : Sys_var_mybool(name_arg, comment, READ_ONLY GLOBAL_VAR(test_flag_value), 1191 NO_CMD_LINE, DEFAULT(FALSE)) 1192 { 1193 test_flag_mask= mask; 1194 } global_value_ptr(THD * thd,LEX_STRING * base)1195 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1196 { 1197 test_flag_value= ((test_flags & test_flag_mask) > 0); 1198 return (uchar*) &test_flag_value; 1199 } 1200 }; 1201 1202 /** 1203 The class for the @max_user_connections. 1204 It's derived from Sys_var_uint, but non-standard session value 1205 requires a new class. 1206 1207 Class specific constructor arguments: 1208 everything derived from Sys_var_uint 1209 1210 Backing store: uint 1211 */ 1212 class Sys_var_max_user_conn: public Sys_var_uint 1213 { 1214 public: 1215 Sys_var_max_user_conn(const char *name_arg, 1216 const char *comment, int flag_args, ptrdiff_t off, size_t size, 1217 CMD_LINE getopt, 1218 uint min_val, uint max_val, uint def_val, 1219 uint block_size, PolyLock *lock=0, 1220 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 1221 on_check_function on_check_func=0, 1222 on_update_function on_update_func=0, 1223 const char *substitute=0) Sys_var_uint(name_arg,comment,SESSION,off,size,getopt,min_val,max_val,def_val,block_size,lock,binlog_status_arg,on_check_func,on_update_func,substitute)1224 : Sys_var_uint(name_arg, comment, SESSION, off, size, getopt, 1225 min_val, max_val, def_val, block_size, 1226 lock, binlog_status_arg, on_check_func, on_update_func, 1227 substitute) 1228 { } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1229 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1230 { 1231 const USER_CONN *uc= target_thd->get_user_connect(); 1232 if (uc && uc->user_resources.user_conn) 1233 return (uchar*) &(uc->user_resources.user_conn); 1234 return global_value_ptr(running_thd, base); 1235 } 1236 }; 1237 1238 // overflow-safe (1 << X)-1 1239 #define MAX_SET(X) ((((1UL << ((X)-1))-1) << 1) | 1) 1240 1241 /** 1242 The class for flagset variables - a variant of SET that allows in-place 1243 editing (turning on/off individual bits). String representations looks like 1244 a "flag=val,flag=val,...". Example: @@optimizer_switch 1245 1246 Class specific constructor arguments: 1247 char* values[] - 0-terminated list of strings of valid values 1248 1249 Backing store: ulonglong 1250 1251 @note 1252 the last value in the values[] array should 1253 *always* be the string "default". 1254 */ 1255 class Sys_var_flagset: public Sys_var_typelib 1256 { 1257 public: 1258 Sys_var_flagset(const char *name_arg, 1259 const char *comment, int flag_args, ptrdiff_t off, size_t size, 1260 CMD_LINE getopt, 1261 const char *values[], ulonglong def_val, PolyLock *lock=0, 1262 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 1263 on_check_function on_check_func=0, 1264 on_update_function on_update_func=0, 1265 const char *substitute=0) Sys_var_typelib(name_arg,comment,flag_args,off,getopt,SHOW_CHAR,values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)1266 : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, 1267 SHOW_CHAR, values, def_val, lock, 1268 binlog_status_arg, on_check_func, on_update_func, 1269 substitute) 1270 { 1271 option.var_type= GET_FLAGSET; 1272 global_var(ulonglong)= def_val; 1273 assert(typelib.count > 1); 1274 assert(typelib.count <= 65); 1275 assert(def_val < MAX_SET(typelib.count)); 1276 assert(strcmp(values[typelib.count-1], "default") == 0); 1277 assert(size == sizeof(ulonglong)); 1278 } do_check(THD * thd,set_var * var)1279 bool do_check(THD *thd, set_var *var) 1280 { 1281 char buff[STRING_BUFFER_USUAL_SIZE]; 1282 String str(buff, sizeof(buff), system_charset_info), *res; 1283 ulonglong default_value, current_value; 1284 if (var->type == OPT_GLOBAL) 1285 { 1286 default_value= option.def_value; 1287 current_value= global_var(ulonglong); 1288 } 1289 else 1290 { 1291 default_value= global_var(ulonglong); 1292 current_value= session_var(thd, ulonglong); 1293 } 1294 1295 if (var->value->result_type() == STRING_RESULT) 1296 { 1297 if (!(res=var->value->val_str(&str))) 1298 return true; 1299 else 1300 { 1301 char *error; 1302 uint error_len; 1303 1304 var->save_result.ulonglong_value= 1305 find_set_from_flags(&typelib, 1306 typelib.count, 1307 current_value, 1308 default_value, 1309 res->ptr(), 1310 static_cast<uint>(res->length()), 1311 &error, &error_len); 1312 if (error) 1313 { 1314 ErrConvString err(error, error_len, res->charset()); 1315 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr()); 1316 return true; 1317 } 1318 } 1319 } 1320 else 1321 { 1322 longlong tmp=var->value->val_int(); 1323 if ((tmp < 0 && ! var->value->unsigned_flag) 1324 || (ulonglong)tmp > MAX_SET(typelib.count)) 1325 return true; 1326 else 1327 var->save_result.ulonglong_value= tmp; 1328 } 1329 1330 return false; 1331 } session_update(THD * thd,set_var * var)1332 bool session_update(THD *thd, set_var *var) 1333 { 1334 session_var(thd, ulonglong)= var->save_result.ulonglong_value; 1335 return false; 1336 } global_update(THD * thd,set_var * var)1337 bool global_update(THD *thd, set_var *var) 1338 { 1339 global_var(ulonglong)= var->save_result.ulonglong_value; 1340 return false; 1341 } session_save_default(THD * thd,set_var * var)1342 void session_save_default(THD *thd, set_var *var) 1343 { var->save_result.ulonglong_value= global_var(ulonglong); } global_save_default(THD * thd,set_var * var)1344 void global_save_default(THD *thd, set_var *var) 1345 { var->save_result.ulonglong_value= option.def_value; } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1346 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1347 { 1348 return (uchar*)flagset_to_string(running_thd, 0, session_var(target_thd, ulonglong), 1349 typelib.type_names); 1350 } global_value_ptr(THD * thd,LEX_STRING * base)1351 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1352 { 1353 return (uchar*)flagset_to_string(thd, 0, global_var(ulonglong), 1354 typelib.type_names); 1355 } 1356 }; 1357 1358 /** 1359 The class for SET variables - variables taking zero or more values 1360 from the given list. Example: @@sql_mode 1361 1362 Class specific constructor arguments: 1363 char* values[] - 0-terminated list of strings of valid values 1364 1365 Backing store: ulonglong 1366 */ 1367 class Sys_var_set: public Sys_var_typelib 1368 { 1369 public: 1370 Sys_var_set(const char *name_arg, 1371 const char *comment, int flag_args, ptrdiff_t off, size_t size, 1372 CMD_LINE getopt, 1373 const char *values[], ulonglong def_val, PolyLock *lock=0, 1374 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 1375 on_check_function on_check_func=0, 1376 on_update_function on_update_func=0, 1377 const char *substitute=0) Sys_var_typelib(name_arg,comment,flag_args,off,getopt,SHOW_CHAR,values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)1378 : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, 1379 SHOW_CHAR, values, def_val, lock, 1380 binlog_status_arg, on_check_func, on_update_func, 1381 substitute) 1382 { 1383 option.var_type= GET_SET; 1384 global_var(ulonglong)= def_val; 1385 assert(typelib.count > 0); 1386 assert(typelib.count <= 64); 1387 assert(def_val < MAX_SET(typelib.count)); 1388 assert(size == sizeof(ulonglong)); 1389 } do_check(THD * thd,set_var * var)1390 bool do_check(THD *thd, set_var *var) 1391 { 1392 char buff[STRING_BUFFER_USUAL_SIZE]; 1393 String str(buff, sizeof(buff), system_charset_info), *res; 1394 1395 if (var->value->result_type() == STRING_RESULT) 1396 { 1397 if (!(res=var->value->val_str(&str))) 1398 return true; 1399 else 1400 { 1401 char *error; 1402 uint error_len; 1403 bool not_used; 1404 1405 var->save_result.ulonglong_value= 1406 find_set(&typelib, res->ptr(), 1407 static_cast<uint>(res->length()), NULL, 1408 &error, &error_len, ¬_used); 1409 /* 1410 note, we only issue an error if error_len > 0. 1411 That is even while empty (zero-length) values are considered 1412 errors by find_set(), these errors are ignored here 1413 */ 1414 if (error_len) 1415 { 1416 ErrConvString err(error, error_len, res->charset()); 1417 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr()); 1418 return true; 1419 } 1420 } 1421 } 1422 else 1423 { 1424 longlong tmp=var->value->val_int(); 1425 if ((tmp < 0 && ! var->value->unsigned_flag) 1426 || (ulonglong)tmp > MAX_SET(typelib.count)) 1427 return true; 1428 else 1429 var->save_result.ulonglong_value= tmp; 1430 } 1431 1432 return false; 1433 } session_update(THD * thd,set_var * var)1434 bool session_update(THD *thd, set_var *var) 1435 { 1436 session_var(thd, ulonglong)= var->save_result.ulonglong_value; 1437 return false; 1438 } global_update(THD * thd,set_var * var)1439 bool global_update(THD *thd, set_var *var) 1440 { 1441 global_var(ulonglong)= var->save_result.ulonglong_value; 1442 return false; 1443 } session_save_default(THD * thd,set_var * var)1444 void session_save_default(THD *thd, set_var *var) 1445 { var->save_result.ulonglong_value= global_var(ulonglong); } global_save_default(THD * thd,set_var * var)1446 void global_save_default(THD *thd, set_var *var) 1447 { var->save_result.ulonglong_value= option.def_value; } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1448 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1449 { 1450 return (uchar*)set_to_string(running_thd, 0, session_var(target_thd, ulonglong), 1451 typelib.type_names); 1452 } global_value_ptr(THD * thd,LEX_STRING * base)1453 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1454 { 1455 return (uchar*)set_to_string(thd, 0, global_var(ulonglong), 1456 typelib.type_names); 1457 } 1458 }; 1459 1460 /** 1461 The class for variables which value is a plugin. 1462 Example: @@default_storage_engine 1463 1464 Class specific constructor arguments: 1465 int plugin_type_arg (for example MYSQL_STORAGE_ENGINE_PLUGIN) 1466 1467 Backing store: plugin_ref 1468 1469 @note 1470 these variables don't support command-line equivalents, any such 1471 command-line options should be added manually to my_long_options in mysqld.cc 1472 */ 1473 class Sys_var_plugin: public sys_var 1474 { 1475 int plugin_type; 1476 public: 1477 Sys_var_plugin(const char *name_arg, 1478 const char *comment, int flag_args, ptrdiff_t off, size_t size, 1479 CMD_LINE getopt, 1480 int plugin_type_arg, char **def_val, PolyLock *lock=0, 1481 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 1482 on_check_function on_check_func=0, 1483 on_update_function on_update_func=0, 1484 const char *substitute=0, 1485 int parse_flag= PARSE_NORMAL) 1486 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 1487 getopt.arg_type, SHOW_CHAR, (intptr)def_val, 1488 lock, binlog_status_arg, on_check_func, on_update_func, 1489 substitute, parse_flag), 1490 plugin_type(plugin_type_arg) 1491 { 1492 option.var_type= GET_STR; 1493 assert(size == sizeof(plugin_ref)); 1494 assert(getopt.id == -1); // force NO_CMD_LINE 1495 } do_check(THD * thd,set_var * var)1496 bool do_check(THD *thd, set_var *var) 1497 { 1498 char buff[STRING_BUFFER_USUAL_SIZE]; 1499 String str(buff,sizeof(buff), system_charset_info), *res; 1500 1501 /* NULLs can't be used as a default storage engine */ 1502 if (!(res=var->value->val_str(&str))) 1503 return true; 1504 1505 const LEX_STRING pname= { const_cast<char*>(res->ptr()), res->length() }; 1506 plugin_ref plugin; 1507 1508 // special code for storage engines (e.g. to handle historical aliases) 1509 if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN) 1510 plugin= ha_resolve_by_name(thd, &pname, FALSE); 1511 else 1512 { 1513 LEX_CSTRING pname_cstr= { pname.str, pname.length }; 1514 plugin= my_plugin_lock_by_name(thd, pname_cstr, plugin_type); 1515 } 1516 1517 if (!plugin) 1518 { 1519 // historically different error code 1520 if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN) 1521 { 1522 ErrConvString err(res); 1523 my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr()); 1524 } 1525 return true; 1526 } 1527 var->save_result.plugin= plugin; 1528 return false; 1529 } do_update(plugin_ref * valptr,plugin_ref newval)1530 void do_update(plugin_ref *valptr, plugin_ref newval) 1531 { 1532 plugin_ref oldval= *valptr; 1533 if (oldval != newval) 1534 { 1535 *valptr= my_plugin_lock(NULL, &newval); 1536 plugin_unlock(NULL, oldval); 1537 } 1538 } session_update(THD * thd,set_var * var)1539 bool session_update(THD *thd, set_var *var) 1540 { 1541 do_update((plugin_ref*)session_var_ptr(thd), 1542 var->save_result.plugin); 1543 return false; 1544 } global_update(THD * thd,set_var * var)1545 bool global_update(THD *thd, set_var *var) 1546 { 1547 do_update((plugin_ref*)global_var_ptr(), 1548 var->save_result.plugin); 1549 return false; 1550 } session_save_default(THD * thd,set_var * var)1551 void session_save_default(THD *thd, set_var *var) 1552 { 1553 plugin_ref plugin= global_var(plugin_ref); 1554 var->save_result.plugin= my_plugin_lock(thd, &plugin); 1555 } global_save_default(THD * thd,set_var * var)1556 void global_save_default(THD *thd, set_var *var) 1557 { 1558 LEX_STRING pname; 1559 char **default_value= reinterpret_cast<char**>(option.def_value); 1560 pname.str= *default_value; 1561 pname.length= strlen(pname.str); 1562 1563 plugin_ref plugin; 1564 if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN) 1565 plugin= ha_resolve_by_name(thd, &pname, FALSE); 1566 else 1567 { 1568 LEX_CSTRING pname_cstr= {pname.str,pname.length}; 1569 plugin= my_plugin_lock_by_name(thd, pname_cstr, plugin_type); 1570 } 1571 assert(plugin); 1572 1573 var->save_result.plugin= my_plugin_lock(thd, &plugin); 1574 } check_update_type(Item_result type)1575 bool check_update_type(Item_result type) 1576 { return type != STRING_RESULT; } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1577 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1578 { 1579 plugin_ref plugin= session_var(target_thd, plugin_ref); 1580 return (uchar*)(plugin ? running_thd->strmake(plugin_name(plugin)->str, 1581 plugin_name(plugin)->length) : 0); 1582 } global_value_ptr(THD * thd,LEX_STRING * base)1583 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1584 { 1585 plugin_ref plugin= global_var(plugin_ref); 1586 return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str, 1587 plugin_name(plugin)->length) : 0); 1588 } 1589 }; 1590 1591 #if defined(ENABLED_DEBUG_SYNC) 1592 /** 1593 The class for @@debug_sync session-only variable 1594 */ 1595 class Sys_var_debug_sync :public sys_var 1596 { 1597 public: 1598 Sys_var_debug_sync(const char *name_arg, 1599 const char *comment, int flag_args, 1600 CMD_LINE getopt, 1601 const char *def_val, PolyLock *lock=0, 1602 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 1603 on_check_function on_check_func=0, 1604 on_update_function on_update_func=0, 1605 const char *substitute=0, 1606 int parse_flag= PARSE_NORMAL) 1607 : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id, 1608 getopt.arg_type, SHOW_CHAR, (intptr)def_val, 1609 lock, binlog_status_arg, on_check_func, on_update_func, 1610 substitute, parse_flag) 1611 { 1612 assert(scope() == ONLY_SESSION); 1613 option.var_type= GET_NO_ARG; 1614 } do_check(THD * thd,set_var * var)1615 bool do_check(THD *thd, set_var *var) 1616 { 1617 char buff[STRING_BUFFER_USUAL_SIZE]; 1618 String str(buff, sizeof(buff), system_charset_info), *res; 1619 1620 if (!(res=var->value->val_str(&str))) 1621 var->save_result.string_value.str= const_cast<char*>(""); 1622 else 1623 var->save_result.string_value.str= thd->strmake(res->ptr(), res->length()); 1624 return false; 1625 } session_update(THD * thd,set_var * var)1626 bool session_update(THD *thd, set_var *var) 1627 { 1628 extern bool debug_sync_update(THD *thd, char *val_str); 1629 return debug_sync_update(thd, var->save_result.string_value.str); 1630 } global_update(THD * thd,set_var * var)1631 bool global_update(THD *thd, set_var *var) 1632 { 1633 assert(FALSE); 1634 return true; 1635 } session_save_default(THD * thd,set_var * var)1636 void session_save_default(THD *thd, set_var *var) 1637 { 1638 var->save_result.string_value.str= const_cast<char*>(""); 1639 var->save_result.string_value.length= 0; 1640 } global_save_default(THD * thd,set_var * var)1641 void global_save_default(THD *thd, set_var *var) 1642 { 1643 assert(FALSE); 1644 } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1645 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1646 { 1647 extern uchar *debug_sync_value_ptr(THD *thd); 1648 return debug_sync_value_ptr(running_thd); 1649 } global_value_ptr(THD * thd,LEX_STRING * base)1650 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1651 { 1652 assert(FALSE); 1653 return 0; 1654 } check_update_type(Item_result type)1655 bool check_update_type(Item_result type) 1656 { return type != STRING_RESULT; } 1657 }; 1658 #endif /* defined(ENABLED_DEBUG_SYNC) */ 1659 1660 /** 1661 The class for bit variables - a variant of boolean that stores the value 1662 in a bit. 1663 1664 Class specific constructor arguments: 1665 ulonglong bitmask_arg - the mask for the bit to set in the ulonglong 1666 backing store 1667 1668 Backing store: ulonglong 1669 1670 @note 1671 This class supports the "reverse" semantics, when the value of the bit 1672 being 0 corresponds to the value of variable being set. To activate it 1673 use REVERSE(bitmask) instead of simply bitmask in the constructor. 1674 1675 @note 1676 variables of this class cannot be set from the command line as 1677 my_getopt does not support bits. 1678 */ 1679 class Sys_var_bit: public Sys_var_typelib 1680 { 1681 ulonglong bitmask; 1682 bool reverse_semantics; set(uchar * ptr,ulonglong value)1683 void set(uchar *ptr, ulonglong value) 1684 { 1685 if ((value != 0) ^ reverse_semantics) 1686 (*(ulonglong *)ptr)|= bitmask; 1687 else 1688 (*(ulonglong *)ptr)&= ~bitmask; 1689 } 1690 public: 1691 Sys_var_bit(const char *name_arg, 1692 const char *comment, int flag_args, ptrdiff_t off, size_t size, 1693 CMD_LINE getopt, 1694 ulonglong bitmask_arg, my_bool def_val, PolyLock *lock=0, 1695 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 1696 on_check_function on_check_func=0, 1697 pre_update_function pre_update_func=0, 1698 on_update_function on_update_func=0, 1699 const char *substitute=0) Sys_var_typelib(name_arg,comment,flag_args,off,getopt,SHOW_MY_BOOL,bool_values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)1700 : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, 1701 SHOW_MY_BOOL, bool_values, def_val, lock, 1702 binlog_status_arg, on_check_func, on_update_func, 1703 substitute) 1704 { 1705 option.var_type= GET_BOOL; 1706 pre_update= pre_update_func; 1707 reverse_semantics= my_count_bits(bitmask_arg) > 1; 1708 bitmask= reverse_semantics ? ~bitmask_arg : bitmask_arg; 1709 set(global_var_ptr(), def_val); 1710 assert(def_val < 2); 1711 assert(getopt.id == -1); // force NO_CMD_LINE 1712 assert(size == sizeof(ulonglong)); 1713 } session_update(THD * thd,set_var * var)1714 bool session_update(THD *thd, set_var *var) 1715 { 1716 set(session_var_ptr(thd), var->save_result.ulonglong_value); 1717 return false; 1718 } global_update(THD * thd,set_var * var)1719 bool global_update(THD *thd, set_var *var) 1720 { 1721 set(global_var_ptr(), var->save_result.ulonglong_value); 1722 return false; 1723 } session_save_default(THD * thd,set_var * var)1724 void session_save_default(THD *thd, set_var *var) 1725 { var->save_result.ulonglong_value= global_var(ulonglong) & bitmask; } global_save_default(THD * thd,set_var * var)1726 void global_save_default(THD *thd, set_var *var) 1727 { var->save_result.ulonglong_value= option.def_value; } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1728 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1729 { 1730 running_thd->sys_var_tmp.my_bool_value= 1731 static_cast<my_bool>(reverse_semantics ^ 1732 ((session_var(target_thd, ulonglong) & bitmask) != 0)); 1733 return (uchar*) &running_thd->sys_var_tmp.my_bool_value; 1734 } global_value_ptr(THD * thd,LEX_STRING * base)1735 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1736 { 1737 thd->sys_var_tmp.my_bool_value= 1738 static_cast<my_bool>(reverse_semantics ^ 1739 ((global_var(ulonglong) & bitmask) != 0)); 1740 return (uchar*) &thd->sys_var_tmp.my_bool_value; 1741 } 1742 }; 1743 1744 /** 1745 The class for variables that have a special meaning for a session, 1746 such as @@timestamp or @@rnd_seed1, their values typically cannot be read 1747 from SV structure, and a special "read" callback is provided. 1748 1749 Class specific constructor arguments: 1750 everything derived from Sys_var_ulonglong 1751 session_special_read_function read_func_arg 1752 1753 Backing store: ulonglong 1754 1755 @note 1756 These variables are session-only, global or command-line equivalents 1757 are not supported as they're generally meaningless. 1758 */ 1759 class Sys_var_session_special: public Sys_var_ulonglong 1760 { 1761 typedef bool (*session_special_update_function)(THD *thd, set_var *var); 1762 typedef ulonglong (*session_special_read_function)(THD *thd); 1763 1764 session_special_read_function read_func; 1765 session_special_update_function update_func; 1766 public: 1767 Sys_var_session_special(const char *name_arg, 1768 const char *comment, int flag_args, 1769 CMD_LINE getopt, 1770 ulonglong min_val, ulonglong max_val, uint block_size, 1771 PolyLock *lock, enum binlog_status_enum binlog_status_arg, 1772 on_check_function on_check_func, 1773 session_special_update_function update_func_arg, 1774 session_special_read_function read_func_arg, 1775 const char *substitute=0) 1776 : Sys_var_ulonglong(name_arg, comment, flag_args, 0, 1777 sizeof(ulonglong), getopt, min_val, 1778 max_val, 0, block_size, lock, binlog_status_arg, on_check_func, 0, 1779 substitute), 1780 read_func(read_func_arg), update_func(update_func_arg) 1781 { 1782 assert(scope() == ONLY_SESSION); 1783 assert(getopt.id == -1); // NO_CMD_LINE, because the offset is fake 1784 } session_update(THD * thd,set_var * var)1785 bool session_update(THD *thd, set_var *var) 1786 { return update_func(thd, var); } global_update(THD * thd,set_var * var)1787 bool global_update(THD *thd, set_var *var) 1788 { 1789 assert(FALSE); 1790 return true; 1791 } session_save_default(THD * thd,set_var * var)1792 void session_save_default(THD *thd, set_var *var) 1793 { var->value= 0; } global_save_default(THD * thd,set_var * var)1794 void global_save_default(THD *thd, set_var *var) 1795 { assert(FALSE); } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1796 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1797 { 1798 running_thd->sys_var_tmp.ulonglong_value= read_func(target_thd); 1799 return (uchar*) &running_thd->sys_var_tmp.ulonglong_value; 1800 } global_value_ptr(THD * thd,LEX_STRING * base)1801 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1802 { 1803 assert(FALSE); 1804 return 0; 1805 } 1806 }; 1807 1808 1809 /** 1810 Similar to Sys_var_session_special, but with double storage. 1811 */ 1812 class Sys_var_session_special_double: public Sys_var_double 1813 { 1814 typedef bool (*session_special_update_function)(THD *thd, set_var *var); 1815 typedef double (*session_special_read_double_function)(THD *thd); 1816 1817 session_special_read_double_function read_func; 1818 session_special_update_function update_func; 1819 public: 1820 Sys_var_session_special_double(const char *name_arg, 1821 const char *comment, int flag_args, 1822 CMD_LINE getopt, 1823 double min_val, double max_val, uint block_size, 1824 PolyLock *lock, enum binlog_status_enum binlog_status_arg, 1825 on_check_function on_check_func, 1826 session_special_update_function update_func_arg, 1827 session_special_read_double_function read_func_arg, 1828 const char *substitute=0) 1829 : Sys_var_double(name_arg, comment, flag_args, 0, 1830 sizeof(double), getopt, 1831 min_val, max_val, 0.0, 1832 lock, binlog_status_arg, on_check_func, 0, 1833 substitute), 1834 read_func(read_func_arg), update_func(update_func_arg) 1835 { 1836 assert(scope() == ONLY_SESSION); 1837 assert(getopt.id == -1); // NO_CMD_LINE, because the offset is fake 1838 } session_update(THD * thd,set_var * var)1839 bool session_update(THD *thd, set_var *var) 1840 { return update_func(thd, var); } global_update(THD * thd,set_var * var)1841 bool global_update(THD *thd, set_var *var) 1842 { 1843 assert(FALSE); 1844 return true; 1845 } session_save_default(THD * thd,set_var * var)1846 void session_save_default(THD *thd, set_var *var) 1847 { var->value= 0; } global_save_default(THD * thd,set_var * var)1848 void global_save_default(THD *thd, set_var *var) 1849 { assert(FALSE); } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1850 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1851 { 1852 running_thd->sys_var_tmp.double_value= read_func(target_thd); 1853 return (uchar *) &running_thd->sys_var_tmp.double_value; 1854 } global_value_ptr(THD * thd,LEX_STRING * base)1855 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1856 { 1857 assert(FALSE); 1858 return 0; 1859 } 1860 }; 1861 1862 1863 /** 1864 The class for read-only variables that show whether a particular 1865 feature is supported by the server. Example: have_compression 1866 1867 Backing store: enum SHOW_COMP_OPTION 1868 1869 @note 1870 These variables are necessarily read-only, only global, and have no 1871 command-line equivalent. 1872 */ 1873 class Sys_var_have: public sys_var 1874 { 1875 public: 1876 Sys_var_have(const char *name_arg, 1877 const char *comment, int flag_args, ptrdiff_t off, size_t size, 1878 CMD_LINE getopt, 1879 PolyLock *lock=0, 1880 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 1881 on_check_function on_check_func=0, 1882 on_update_function on_update_func=0, 1883 const char *substitute=0, 1884 int parse_flag= PARSE_NORMAL) 1885 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 1886 getopt.arg_type, SHOW_CHAR, 0, 1887 lock, binlog_status_arg, on_check_func, on_update_func, 1888 substitute, parse_flag) 1889 { 1890 assert(scope() == GLOBAL); 1891 assert(getopt.id == -1); 1892 assert(lock == 0); 1893 assert(binlog_status_arg == VARIABLE_NOT_IN_BINLOG); 1894 assert(is_readonly()); 1895 assert(on_update == 0); 1896 assert(size == sizeof(enum SHOW_COMP_OPTION)); 1897 } do_check(THD * thd,set_var * var)1898 bool do_check(THD *thd, set_var *var) { 1899 assert(FALSE); 1900 return true; 1901 } session_update(THD * thd,set_var * var)1902 bool session_update(THD *thd, set_var *var) 1903 { 1904 assert(FALSE); 1905 return true; 1906 } global_update(THD * thd,set_var * var)1907 bool global_update(THD *thd, set_var *var) 1908 { 1909 assert(FALSE); 1910 return true; 1911 } session_save_default(THD * thd,set_var * var)1912 void session_save_default(THD *thd, set_var *var) { } global_save_default(THD * thd,set_var * var)1913 void global_save_default(THD *thd, set_var *var) { } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1914 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1915 { 1916 assert(FALSE); 1917 return 0; 1918 } global_value_ptr(THD * thd,LEX_STRING * base)1919 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1920 { 1921 return (uchar*)show_comp_option_name[global_var(enum SHOW_COMP_OPTION)]; 1922 } check_update_type(Item_result type)1923 bool check_update_type(Item_result type) { return false; } 1924 }; 1925 1926 /** 1927 Generic class for variables for storing entities that are internally 1928 represented as structures, have names, and possibly can be referred to by 1929 numbers. Examples: character sets, collations, locales, 1930 1931 Class specific constructor arguments: 1932 ptrdiff_t name_offset - offset of the 'name' field in the structure 1933 1934 Backing store: void* 1935 1936 @note 1937 As every such a structure requires special treatment from my_getopt, 1938 these variables don't support command-line equivalents, any such 1939 command-line options should be added manually to my_long_options in mysqld.cc 1940 */ 1941 class Sys_var_struct: public sys_var 1942 { 1943 ptrdiff_t name_offset; // offset to the 'name' property in the structure 1944 public: 1945 Sys_var_struct(const char *name_arg, 1946 const char *comment, int flag_args, ptrdiff_t off, size_t size, 1947 CMD_LINE getopt, 1948 ptrdiff_t name_off, void *def_val, PolyLock *lock=0, 1949 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 1950 on_check_function on_check_func=0, 1951 on_update_function on_update_func=0, 1952 const char *substitute=0, 1953 int parse_flag= PARSE_NORMAL) 1954 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 1955 getopt.arg_type, SHOW_CHAR, (intptr)def_val, 1956 lock, binlog_status_arg, on_check_func, on_update_func, 1957 substitute, parse_flag), 1958 name_offset(name_off) 1959 { 1960 option.var_type= GET_STR; 1961 /* 1962 struct variables are special on the command line - often (e.g. for 1963 charsets) the name cannot be immediately resolved, but only after all 1964 options (in particular, basedir) are parsed. 1965 1966 thus all struct command-line options should be added manually 1967 to my_long_options in mysqld.cc 1968 */ 1969 assert(getopt.id == -1); 1970 assert(size == sizeof(void *)); 1971 } do_check(THD * thd,set_var * var)1972 bool do_check(THD *thd, set_var *var) 1973 { return false; } session_update(THD * thd,set_var * var)1974 bool session_update(THD *thd, set_var *var) 1975 { 1976 session_var(thd, const void*)= var->save_result.ptr; 1977 return false; 1978 } global_update(THD * thd,set_var * var)1979 bool global_update(THD *thd, set_var *var) 1980 { 1981 global_var(const void*)= var->save_result.ptr; 1982 return false; 1983 } session_save_default(THD * thd,set_var * var)1984 void session_save_default(THD *thd, set_var *var) 1985 { var->save_result.ptr= global_var(void*); } global_save_default(THD * thd,set_var * var)1986 void global_save_default(THD *thd, set_var *var) 1987 { 1988 void **default_value= reinterpret_cast<void**>(option.def_value); 1989 var->save_result.ptr= *default_value; 1990 } check_update_type(Item_result type)1991 bool check_update_type(Item_result type) 1992 { return type != INT_RESULT && type != STRING_RESULT; } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1993 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 1994 { 1995 uchar *ptr= session_var(target_thd, uchar*); 1996 return ptr ? *(uchar**)(ptr+name_offset) : 0; 1997 } global_value_ptr(THD * thd,LEX_STRING * base)1998 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 1999 { 2000 uchar *ptr= global_var(uchar*); 2001 return ptr ? *(uchar**)(ptr+name_offset) : 0; 2002 } 2003 }; 2004 2005 /** 2006 The class for variables that store time zones 2007 2008 Backing store: Time_zone* 2009 2010 @note 2011 Time zones cannot be supported directly by my_getopt, thus 2012 these variables don't support command-line equivalents, any such 2013 command-line options should be added manually to my_long_options in mysqld.cc 2014 */ 2015 class Sys_var_tz: public sys_var 2016 { 2017 public: 2018 Sys_var_tz(const char *name_arg, 2019 const char *comment, int flag_args, ptrdiff_t off, size_t size, 2020 CMD_LINE getopt, 2021 Time_zone **def_val, PolyLock *lock=0, 2022 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 2023 on_check_function on_check_func=0, 2024 on_update_function on_update_func=0, 2025 const char *substitute=0, 2026 int parse_flag= PARSE_NORMAL) 2027 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 2028 getopt.arg_type, SHOW_CHAR, (intptr)def_val, 2029 lock, binlog_status_arg, on_check_func, on_update_func, 2030 substitute, parse_flag) 2031 { 2032 assert(getopt.id == -1); 2033 assert(size == sizeof(Time_zone *)); 2034 } do_check(THD * thd,set_var * var)2035 bool do_check(THD *thd, set_var *var) 2036 { 2037 char buff[MAX_TIME_ZONE_NAME_LENGTH]; 2038 String str(buff, sizeof(buff), &my_charset_latin1); 2039 String *res= var->value->val_str(&str); 2040 2041 if (!res) 2042 return true; 2043 2044 if (!(var->save_result.time_zone= my_tz_find(thd, res))) 2045 { 2046 ErrConvString err(res); 2047 my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), err.ptr()); 2048 return true; 2049 } 2050 return false; 2051 } session_update(THD * thd,set_var * var)2052 bool session_update(THD *thd, set_var *var) 2053 { 2054 session_var(thd, Time_zone*)= var->save_result.time_zone; 2055 return false; 2056 } global_update(THD * thd,set_var * var)2057 bool global_update(THD *thd, set_var *var) 2058 { 2059 global_var(Time_zone*)= var->save_result.time_zone; 2060 return false; 2061 } session_save_default(THD * thd,set_var * var)2062 void session_save_default(THD *thd, set_var *var) 2063 { 2064 var->save_result.time_zone= global_var(Time_zone*); 2065 } global_save_default(THD * thd,set_var * var)2066 void global_save_default(THD *thd, set_var *var) 2067 { 2068 var->save_result.time_zone= 2069 *(Time_zone**)(intptr)option.def_value; 2070 } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2071 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 2072 { 2073 /* 2074 This is an ugly fix for replication: we don't replicate properly queries 2075 invoking system variables' values to update tables; but 2076 CONVERT_TZ(,,@@session.time_zone) is so popular that we make it 2077 replicable (i.e. we tell the binlog code to store the session 2078 timezone). If it's the global value which was used we can't replicate 2079 (binlog code stores session value only). 2080 */ 2081 target_thd->time_zone_used= 1; 2082 return (uchar *)(session_var(target_thd, Time_zone*)->get_name()->ptr()); 2083 } global_value_ptr(THD * thd,LEX_STRING * base)2084 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 2085 { 2086 return (uchar *)(global_var(Time_zone*)->get_name()->ptr()); 2087 } check_update_type(Item_result type)2088 bool check_update_type(Item_result type) 2089 { return type != STRING_RESULT; } 2090 }; 2091 2092 2093 /** 2094 Class representing the 'tx_isolation' system variable. This 2095 variable can also be indirectly set using 'SET TRANSACTION ISOLATION 2096 LEVEL'. This variable is deprecated and will be removed in a 2097 future release. 'transaction_isolation' is used an alternative 2098 instead. 2099 */ 2100 class Sys_var_tx_isolation: public Sys_var_enum 2101 { 2102 public: 2103 Sys_var_tx_isolation(const char *name_arg, 2104 const char *comment, int flag_args, ptrdiff_t off, size_t size, 2105 CMD_LINE getopt, 2106 const char *values[], uint def_val, PolyLock *lock, 2107 enum binlog_status_enum binlog_status_arg, 2108 on_check_function on_check_func, 2109 on_update_function on_update_func=0, 2110 const char *substitute=0) Sys_var_enum(name_arg,comment,flag_args,off,size,getopt,values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)2111 :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt, 2112 values, def_val, lock, binlog_status_arg, on_check_func, 2113 on_update_func, substitute) 2114 {} 2115 virtual bool session_update(THD *thd, set_var *var); 2116 }; 2117 2118 2119 /** 2120 Class representing the tx_read_only system variable for setting 2121 default transaction access mode. This variable is deprecated 2122 and will be removed in future release. 'transaction_read_only' 2123 is used as an alternative instead. 2124 2125 Note that there is a special syntax - SET TRANSACTION READ ONLY 2126 (or READ WRITE) that sets the access mode for the next transaction 2127 only. 2128 */ 2129 2130 class Sys_var_tx_read_only: public Sys_var_mybool 2131 { 2132 public: 2133 Sys_var_tx_read_only(const char *name_arg, const char *comment, int flag_args, 2134 ptrdiff_t off, size_t size, CMD_LINE getopt, 2135 my_bool def_val, PolyLock *lock, 2136 enum binlog_status_enum binlog_status_arg, 2137 on_check_function on_check_func, 2138 on_update_function on_update_func=0, 2139 const char *substitute=0) Sys_var_mybool(name_arg,comment,flag_args,off,size,getopt,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)2140 :Sys_var_mybool(name_arg, comment, flag_args, off, size, getopt, 2141 def_val, lock, binlog_status_arg, on_check_func, 2142 on_update_func, substitute) 2143 {} 2144 virtual bool session_update(THD *thd, set_var *var); 2145 }; 2146 2147 2148 /** 2149 Class representing the sql_log_bin system variable for controlling 2150 whether logging to the binary log is done. 2151 */ 2152 2153 class Sys_var_sql_log_bin: public Sys_var_mybool 2154 { 2155 public: Sys_var_sql_log_bin(const char * name_arg,const char * comment,int flag_args,ptrdiff_t off,size_t size,CMD_LINE getopt,my_bool def_val,PolyLock * lock,enum binlog_status_enum binlog_status_arg,on_check_function on_check_func,on_update_function on_update_func)2156 Sys_var_sql_log_bin(const char *name_arg, const char *comment, int flag_args, 2157 ptrdiff_t off, size_t size, CMD_LINE getopt, 2158 my_bool def_val, PolyLock *lock, 2159 enum binlog_status_enum binlog_status_arg, 2160 on_check_function on_check_func, 2161 on_update_function on_update_func) 2162 :Sys_var_mybool(name_arg, comment, flag_args, off, size, getopt, 2163 def_val, lock, binlog_status_arg, on_check_func, 2164 on_update_func) 2165 {} 2166 global_value_ptr(THD * thd,LEX_STRING * base)2167 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 2168 { 2169 /* Reading GLOBAL SQL_LOG_BIN produces a deprecation warning. */ 2170 if (base != NULL) 2171 push_warning_printf(thd, Sql_condition::SL_WARNING, 2172 ER_WARN_DEPRECATED_SYNTAX, 2173 ER(ER_WARN_DEPRECATED_SYNTAX), 2174 "@@global.sql_log_bin", "the constant 1 " 2175 "(since @@global.sql_log_bin is always equal to 1)"); 2176 2177 return Sys_var_mybool::global_value_ptr(thd, base); 2178 } 2179 }; 2180 2181 /** 2182 A class for @@global.binlog_checksum that has 2183 a specialized update method. 2184 */ 2185 class Sys_var_enum_binlog_checksum: public Sys_var_enum 2186 { 2187 public: 2188 Sys_var_enum_binlog_checksum(const char *name_arg, 2189 const char *comment, int flag_args, ptrdiff_t off, size_t size, 2190 CMD_LINE getopt, 2191 const char *values[], uint def_val, PolyLock *lock, 2192 enum binlog_status_enum binlog_status_arg, 2193 on_check_function on_check_func=0 2194 ) Sys_var_enum(name_arg,comment,flag_args,off,size,getopt,values,def_val,lock,binlog_status_arg,on_check_func,NULL)2195 :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt, 2196 values, def_val, lock, binlog_status_arg, on_check_func, NULL) 2197 {} 2198 virtual bool global_update(THD *thd, set_var *var); 2199 }; 2200 2201 2202 /** 2203 Class for gtid_next. 2204 */ 2205 class Sys_var_gtid_next: public sys_var 2206 { 2207 public: 2208 Sys_var_gtid_next(const char *name_arg, 2209 const char *comment, int flag_args, ptrdiff_t off, size_t size, 2210 CMD_LINE getopt, 2211 const char *def_val, 2212 PolyLock *lock= 0, 2213 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 2214 on_check_function on_check_func=0, 2215 on_update_function on_update_func=0, 2216 const char *substitute=0, 2217 int parse_flag= PARSE_NORMAL) 2218 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 2219 getopt.arg_type, SHOW_CHAR, (intptr)def_val, 2220 lock, binlog_status_arg, on_check_func, on_update_func, 2221 substitute, parse_flag) 2222 { 2223 assert(size == sizeof(Gtid_specification)); 2224 } session_update(THD * thd,set_var * var)2225 bool session_update(THD *thd, set_var *var) 2226 { 2227 DBUG_ENTER("Sys_var_gtid_next::session_update"); 2228 char buf[Gtid::MAX_TEXT_LENGTH + 1]; 2229 // Get the value 2230 String str(buf, sizeof(buf), &my_charset_latin1); 2231 char* res= NULL; 2232 if (!var->value) 2233 { 2234 // set session gtid_next= default 2235 assert(var->save_result.string_value.str); 2236 assert(var->save_result.string_value.length); 2237 res= var->save_result.string_value.str; 2238 } 2239 else if (var->value->val_str(&str)) 2240 res= var->value->val_str(&str)->c_ptr_safe(); 2241 if (!res) 2242 { 2243 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, "NULL"); 2244 DBUG_RETURN(true); 2245 } 2246 global_sid_lock->rdlock(); 2247 Gtid_specification spec; 2248 if (spec.parse(global_sid_map, res) != RETURN_STATUS_OK) 2249 { 2250 global_sid_lock->unlock(); 2251 DBUG_RETURN(true); 2252 } 2253 2254 bool ret= set_gtid_next(thd, spec); 2255 // set_gtid_next releases global_sid_lock 2256 DBUG_RETURN(ret); 2257 } global_update(THD * thd,set_var * var)2258 bool global_update(THD *thd, set_var *var) 2259 { assert(FALSE); return true; } session_save_default(THD * thd,set_var * var)2260 void session_save_default(THD *thd, set_var *var) 2261 { 2262 DBUG_ENTER("Sys_var_gtid_next::session_save_default"); 2263 char* ptr= (char*)(intptr)option.def_value; 2264 var->save_result.string_value.str= ptr; 2265 var->save_result.string_value.length= ptr ? strlen(ptr) : 0; 2266 DBUG_VOID_RETURN; 2267 } global_save_default(THD * thd,set_var * var)2268 void global_save_default(THD *thd, set_var *var) 2269 { assert(FALSE); } do_check(THD * thd,set_var * var)2270 bool do_check(THD *thd, set_var *var) 2271 { return false; } check_update_type(Item_result type)2272 bool check_update_type(Item_result type) 2273 { return type != STRING_RESULT; } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2274 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 2275 { 2276 DBUG_ENTER("Sys_var_gtid_next::session_value_ptr"); 2277 char buf[Gtid_specification::MAX_TEXT_LENGTH + 1]; 2278 global_sid_lock->rdlock(); 2279 ((Gtid_specification *)session_var_ptr(target_thd))-> 2280 to_string(global_sid_map, buf); 2281 global_sid_lock->unlock(); 2282 char *ret= running_thd->mem_strdup(buf); 2283 DBUG_RETURN((uchar *)ret); 2284 } global_value_ptr(THD * thd,LEX_STRING * base)2285 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 2286 { assert(FALSE); return NULL; } 2287 }; 2288 2289 #ifdef HAVE_GTID_NEXT_LIST 2290 /** 2291 Class for variables that store values of type Gtid_set. 2292 2293 The back-end storage should be a Gtid_set_or_null, and it should be 2294 set to null by default. When the variable is set for the first 2295 time, the Gtid_set* will be allocated. 2296 */ 2297 class Sys_var_gtid_set: public sys_var 2298 { 2299 public: 2300 Sys_var_gtid_set(const char *name_arg, 2301 const char *comment, int flag_args, ptrdiff_t off, size_t size, 2302 CMD_LINE getopt, 2303 const char *def_val, 2304 PolyLock *lock= 0, 2305 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 2306 on_check_function on_check_func=0, 2307 on_update_function on_update_func=0, 2308 const char *substitute=0, 2309 int parse_flag= PARSE_NORMAL) 2310 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 2311 getopt.arg_type, SHOW_CHAR, (intptr)def_val, 2312 lock, binlog_status_arg, on_check_func, on_update_func, 2313 substitute, parse_flag) 2314 { 2315 assert(size == sizeof(Gtid_set_or_null)); 2316 } session_update(THD * thd,set_var * var)2317 bool session_update(THD *thd, set_var *var) 2318 { 2319 DBUG_ENTER("Sys_var_gtid_set::session_update"); 2320 Gtid_set_or_null *gsn= 2321 (Gtid_set_or_null *)session_var_ptr(thd); 2322 char *value= var->save_result.string_value.str; 2323 if (value == NULL) 2324 gsn->set_null(); 2325 else 2326 { 2327 Gtid_set *gs= gsn->set_non_null(global_sid_map); 2328 if (gs == NULL) 2329 { 2330 my_error(ER_OUT_OF_RESOURCES, MYF(0)); // allocation failed 2331 DBUG_RETURN(true); 2332 } 2333 /* 2334 If string begins with '+', add to the existing set, otherwise 2335 replace existing set. 2336 */ 2337 while (isspace(*value)) 2338 value++; 2339 if (*value == '+') 2340 value++; 2341 else 2342 gs->clear(); 2343 // Add specified set of groups to Gtid_set. 2344 global_sid_lock->rdlock(); 2345 enum_return_status ret= gs->add_gtid_text(value); 2346 global_sid_lock->unlock(); 2347 if (ret != RETURN_STATUS_OK) 2348 { 2349 gsn->set_null(); 2350 DBUG_RETURN(true); 2351 } 2352 } 2353 DBUG_RETURN(false); 2354 } global_update(THD * thd,set_var * var)2355 bool global_update(THD *thd, set_var *var) 2356 { assert(FALSE); return true; } session_save_default(THD * thd,set_var * var)2357 void session_save_default(THD *thd, set_var *var) 2358 { 2359 DBUG_ENTER("Sys_var_gtid_set::session_save_default"); 2360 global_sid_lock->rdlock(); 2361 char *ptr= (char*)(intptr)option.def_value; 2362 var->save_result.string_value.str= ptr; 2363 var->save_result.string_value.length= ptr ? strlen(ptr) : 0; 2364 global_sid_lock->unlock(); 2365 DBUG_VOID_RETURN; 2366 } global_save_default(THD * thd,set_var * var)2367 void global_save_default(THD *thd, set_var *var) 2368 { assert(FALSE); } do_check(THD * thd,set_var * var)2369 bool do_check(THD *thd, set_var *var) 2370 { 2371 DBUG_ENTER("Sys_var_gtid_set::do_check"); 2372 String str; 2373 String *res= var->value->val_str(&str); 2374 if (res == NULL) 2375 { 2376 var->save_result.string_value.str= NULL; 2377 DBUG_RETURN(FALSE); 2378 } 2379 assert(res->ptr() != NULL); 2380 var->save_result.string_value.str= thd->strmake(res->ptr(), res->length()); 2381 if (var->save_result.string_value.str == NULL) 2382 { 2383 my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->strmake failed 2384 DBUG_RETURN(1); 2385 } 2386 var->save_result.string_value.length= res->length(); 2387 bool ret= !Gtid_set::is_valid(res->ptr()); 2388 DBUG_RETURN(ret); 2389 } check_update_type(Item_result type)2390 bool check_update_type(Item_result type) 2391 { return type != STRING_RESULT; } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2392 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 2393 { 2394 DBUG_ENTER("Sys_var_gtid_set::session_value_ptr"); 2395 Gtid_set_or_null *gsn= (Gtid_set_or_null *)session_var_ptr(target_thd); 2396 Gtid_set *gs= gsn->get_gtid_set(); 2397 if (gs == NULL) 2398 DBUG_RETURN(NULL); 2399 char *buf; 2400 global_sid_lock->rdlock(); 2401 buf= (char *)running_thd->alloc(gs->get_string_length() + 1); 2402 if (buf) 2403 gs->to_string(buf); 2404 else 2405 my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->alloc failed 2406 global_sid_lock->unlock(); 2407 DBUG_RETURN((uchar *)buf); 2408 } global_value_ptr(THD * thd,LEX_STRING * base)2409 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 2410 { assert(FALSE); return NULL; } 2411 }; 2412 #endif 2413 2414 2415 /** 2416 Abstract base class for read-only variables (global or session) of 2417 string type where the value is generated by some function. This 2418 needs to be subclassed; the session_value_ptr or global_value_ptr 2419 function should be overridden. 2420 */ 2421 class Sys_var_charptr_func: public sys_var 2422 { 2423 public: Sys_var_charptr_func(const char * name_arg,const char * comment,flag_enum flag_arg)2424 Sys_var_charptr_func(const char *name_arg, const char *comment, 2425 flag_enum flag_arg) 2426 : sys_var(&all_sys_vars, name_arg, comment, READ_ONLY flag_arg, 2427 0/*off*/, NO_CMD_LINE.id, NO_CMD_LINE.arg_type, 2428 SHOW_CHAR, (intptr)0/*def_val*/, 2429 NULL/*polylock*/, VARIABLE_NOT_IN_BINLOG, 2430 NULL/*on_check_func*/, NULL/*on_update_func*/, 2431 NULL/*substitute*/, PARSE_NORMAL/*parse_flag*/) 2432 { 2433 assert(flag_arg == sys_var::GLOBAL || flag_arg == sys_var::SESSION || 2434 flag_arg == sys_var::ONLY_SESSION); 2435 } session_update(THD * thd,set_var * var)2436 bool session_update(THD *thd, set_var *var) 2437 { assert(FALSE); return true; } global_update(THD * thd,set_var * var)2438 bool global_update(THD *thd, set_var *var) 2439 { assert(FALSE); return true; } session_save_default(THD * thd,set_var * var)2440 void session_save_default(THD *thd, set_var *var) { assert(FALSE); } global_save_default(THD * thd,set_var * var)2441 void global_save_default(THD *thd, set_var *var) { assert(FALSE); } do_check(THD * thd,set_var * var)2442 bool do_check(THD *thd, set_var *var) { assert(FALSE); return true; } check_update_type(Item_result type)2443 bool check_update_type(Item_result type) { assert(FALSE); return true; } session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2444 virtual uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 2445 { assert(FALSE); return NULL; } global_value_ptr(THD * thd,LEX_STRING * base)2446 virtual uchar *global_value_ptr(THD *thd, LEX_STRING *base) 2447 { assert(FALSE); return NULL; } 2448 }; 2449 2450 2451 /** 2452 Class for @@session.gtid_executed and @@global.gtid_executed. 2453 */ 2454 class Sys_var_gtid_executed : Sys_var_charptr_func 2455 { 2456 public: Sys_var_gtid_executed(const char * name_arg,const char * comment_arg)2457 Sys_var_gtid_executed(const char *name_arg, const char *comment_arg) 2458 : Sys_var_charptr_func(name_arg, comment_arg, SESSION) {} 2459 global_value_ptr(THD * thd,LEX_STRING * base)2460 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 2461 { 2462 DBUG_ENTER("Sys_var_gtid_executed::global_value_ptr"); 2463 global_sid_lock->wrlock(); 2464 const Gtid_set *gs= gtid_state->get_executed_gtids(); 2465 char *buf= (char *)thd->alloc(gs->get_string_length() + 1); 2466 if (buf == NULL) 2467 my_error(ER_OUT_OF_RESOURCES, MYF(0)); 2468 else 2469 gs->to_string(buf); 2470 global_sid_lock->unlock(); 2471 DBUG_RETURN((uchar *)buf); 2472 } 2473 2474 public: session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2475 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 2476 { 2477 DBUG_ENTER("Sys_var_gtid_executed::session_value_ptr"); 2478 2479 if (!running_thd->gtid_executed_warning_issued) 2480 { 2481 push_warning_printf(running_thd, Sql_condition::SL_WARNING, 2482 ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT, 2483 ER(ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT), 2484 "@@SESSION.GTID_EXECUTED"); 2485 running_thd->gtid_executed_warning_issued= true; 2486 } 2487 if (opt_bin_log && 2488 (target_thd == running_thd)) /* Supported for current thread only. */ 2489 { 2490 target_thd->binlog_setup_trx_data(); 2491 /* 2492 It is enough to check if the transaction cache is nonempty, we 2493 do not need to check the statement cache. The statement cache 2494 can only be nonempty for single-statement transactions. Since 2495 single-statement transactions are flushed to the binary log 2496 before the next statement gets to execute, there is no chance 2497 that the value of @@session.gtid_executed is read when the 2498 statement cache is nonempty. 2499 */ 2500 if (!target_thd->is_binlog_cache_empty(true)) 2501 { 2502 /* 2503 The case sidno == -1 cannot happen since it is not implemented. 2504 The cases sidno == 0 and sidno == -2 mean that we don't own any 2505 GTID, so we should return empty string. 2506 */ 2507 if (target_thd->owned_gtid.sidno > 0) 2508 { 2509 uchar *buf= (uchar *)running_thd->alloc(Gtid::MAX_TEXT_LENGTH + 1); 2510 if (buf == NULL) 2511 my_error(ER_OUT_OF_RESOURCES, MYF(0)); 2512 else 2513 target_thd->owned_gtid.to_string(target_thd->owned_sid, (char *)buf); 2514 DBUG_RETURN(buf); 2515 } 2516 } 2517 } 2518 2519 uchar *buf= (uchar *)running_thd->alloc(1); 2520 if (buf == NULL) 2521 my_error(ER_OUT_OF_RESOURCES, MYF(0)); 2522 else 2523 buf[0]= 0; 2524 DBUG_RETURN(buf); 2525 } 2526 }; 2527 2528 2529 /** 2530 Class for @@session.gtid_purged. 2531 */ 2532 class Sys_var_gtid_purged : public sys_var 2533 { 2534 public: 2535 Sys_var_gtid_purged(const char *name_arg, 2536 const char *comment, int flag_args, ptrdiff_t off, size_t size, 2537 CMD_LINE getopt, 2538 const char *def_val, 2539 PolyLock *lock= 0, 2540 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 2541 on_check_function on_check_func=0, 2542 on_update_function on_update_func=0, 2543 const char *substitute=0, 2544 int parse_flag= PARSE_NORMAL) 2545 : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, 2546 getopt.arg_type, SHOW_CHAR, (intptr)def_val, 2547 lock, binlog_status_arg, on_check_func, on_update_func, 2548 substitute, parse_flag) 2549 {} 2550 session_update(THD * thd,set_var * var)2551 bool session_update(THD *thd, set_var *var) 2552 { 2553 assert(FALSE); 2554 return true; 2555 } 2556 session_save_default(THD * thd,set_var * var)2557 void session_save_default(THD *thd, set_var *var) 2558 { assert(FALSE); } 2559 2560 bool global_update(THD *thd, set_var *var); 2561 global_save_default(THD * thd,set_var * var)2562 void global_save_default(THD *thd, set_var *var) 2563 { 2564 /* gtid_purged does not have default value */ 2565 my_error(ER_NO_DEFAULT, MYF(0), var->var->name.str); 2566 } 2567 do_check(THD * thd,set_var * var)2568 bool do_check(THD *thd, set_var *var) 2569 { 2570 DBUG_ENTER("Sys_var_gtid_purged::do_check"); 2571 char buf[1024]; 2572 String str(buf, sizeof(buf), system_charset_info); 2573 String *res= var->value->val_str(&str); 2574 if (!res) 2575 DBUG_RETURN(true); 2576 var->save_result.string_value.str= thd->strmake(res->c_ptr_safe(), 2577 res->length()); 2578 if (!var->save_result.string_value.str) 2579 { 2580 my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->strmake failed 2581 DBUG_RETURN(true); 2582 } 2583 var->save_result.string_value.length= res->length(); 2584 bool ret= Gtid_set::is_valid(res->c_ptr_safe()) ? false : true; 2585 DBUG_PRINT("info", ("ret=%d", ret)); 2586 DBUG_RETURN(ret); 2587 } 2588 check_update_type(Item_result type)2589 bool check_update_type(Item_result type) 2590 { return type != STRING_RESULT; } 2591 global_value_ptr(THD * thd,LEX_STRING * base)2592 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 2593 { 2594 DBUG_ENTER("Sys_var_gtid_purged::global_value_ptr"); 2595 const Gtid_set *gs; 2596 global_sid_lock->wrlock(); 2597 if (opt_bin_log) 2598 gs= gtid_state->get_lost_gtids(); 2599 else 2600 /* 2601 When binlog is off, report @@GLOBAL.GTID_PURGED from 2602 executed_gtids, since @@GLOBAL.GTID_PURGED and 2603 @@GLOBAL.GTID_EXECUTED are always same, so we did not 2604 save gtid into lost_gtids for every transaction for 2605 improving performance. 2606 */ 2607 gs= gtid_state->get_executed_gtids(); 2608 char *buf= (char *)thd->alloc(gs->get_string_length() + 1); 2609 if (buf == NULL) 2610 my_error(ER_OUT_OF_RESOURCES, MYF(0)); 2611 else 2612 gs->to_string(buf); 2613 global_sid_lock->unlock(); 2614 DBUG_RETURN((uchar *)buf); 2615 } 2616 session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2617 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 2618 { assert(0); return NULL; } 2619 }; 2620 2621 2622 class Sys_var_gtid_owned : Sys_var_charptr_func 2623 { 2624 public: Sys_var_gtid_owned(const char * name_arg,const char * comment_arg)2625 Sys_var_gtid_owned(const char *name_arg, const char *comment_arg) 2626 : Sys_var_charptr_func(name_arg, comment_arg, SESSION) {} 2627 2628 public: session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2629 uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base) 2630 { 2631 DBUG_ENTER("Sys_var_gtid_owned::session_value_ptr"); 2632 char *buf= NULL; 2633 bool remote= (target_thd != running_thd); 2634 2635 if (target_thd->owned_gtid.sidno == 0) 2636 DBUG_RETURN((uchar *)running_thd->mem_strdup("")); 2637 else if (target_thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS) 2638 { 2639 assert(gtid_state->get_anonymous_ownership_count() > 0); 2640 DBUG_RETURN((uchar *)running_thd->mem_strdup("ANONYMOUS")); 2641 } 2642 else if (target_thd->owned_gtid.sidno == THD::OWNED_SIDNO_GTID_SET) 2643 { 2644 #ifdef HAVE_GTID_NEXT_LIST 2645 buf= (char *)running_thd->alloc(target_thd->owned_gtid_set.get_string_length() + 1); 2646 if (buf) 2647 { 2648 global_sid_lock->rdlock(); 2649 target_thd->owned_gtid_set.to_string(buf); 2650 global_sid_lock->unlock(); 2651 } 2652 else 2653 my_error(ER_OUT_OF_RESOURCES, MYF(0)); 2654 #else 2655 assert(0); 2656 #endif 2657 } 2658 else 2659 { 2660 buf= (char *)running_thd->alloc(Gtid::MAX_TEXT_LENGTH + 1); 2661 if (buf) 2662 { 2663 /* Take the lock if accessing another session. */ 2664 if (remote) 2665 global_sid_lock->rdlock(); 2666 running_thd->owned_gtid.to_string(target_thd->owned_sid, buf); 2667 if (remote) 2668 global_sid_lock->unlock(); 2669 } 2670 else 2671 my_error(ER_OUT_OF_RESOURCES, MYF(0)); 2672 } 2673 DBUG_RETURN((uchar *)buf); 2674 } 2675 global_value_ptr(THD * thd,LEX_STRING * base)2676 uchar *global_value_ptr(THD *thd, LEX_STRING *base) 2677 { 2678 DBUG_ENTER("Sys_var_gtid_owned::global_value_ptr"); 2679 const Owned_gtids *owned_gtids= gtid_state->get_owned_gtids(); 2680 global_sid_lock->wrlock(); 2681 char *buf= (char *)thd->alloc(owned_gtids->get_max_string_length()); 2682 if (buf) 2683 owned_gtids->to_string(buf); 2684 else 2685 my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->alloc failed 2686 global_sid_lock->unlock(); 2687 DBUG_RETURN((uchar *)buf); 2688 } 2689 }; 2690 2691 #ifdef HAVE_REPLICATION 2692 class Sys_var_gtid_mode : public Sys_var_enum 2693 { 2694 public: 2695 Sys_var_gtid_mode(const char *name_arg, 2696 const char *comment, 2697 int flag_args, 2698 ptrdiff_t off, 2699 size_t size, 2700 CMD_LINE getopt, 2701 const char *values[], 2702 uint def_val, 2703 PolyLock *lock=0, 2704 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 2705 on_check_function on_check_func=0) : Sys_var_enum(name_arg,comment,flag_args,off,size,getopt,values,def_val,lock,binlog_status_arg,on_check_func)2706 Sys_var_enum(name_arg, comment, flag_args, off, size, 2707 getopt, values, def_val, lock, binlog_status_arg, 2708 on_check_func) 2709 { } 2710 global_update(THD * thd,set_var * var)2711 bool global_update(THD *thd, set_var *var) 2712 { 2713 DBUG_ENTER("Sys_var_gtid_mode::global_update"); 2714 bool ret= true; 2715 2716 /* 2717 SET GITD_MODE command should ignore 'read-only' and 'super_read_only' 2718 options so that it can update 'mysql.gtid_executed' replication repository 2719 table. 2720 */ 2721 thd->set_skip_readonly_check(); 2722 2723 /* 2724 Hold lock_log so that: 2725 - other transactions are not flushed while gtid_mode is changed; 2726 - gtid_mode is not changed while some other thread is rotating 2727 the binlog. 2728 2729 Hold channel_map lock so that: 2730 - gtid_mode is not changed during the execution of some 2731 replication command; particularly CHANGE MASTER. CHANGE MASTER 2732 checks if GTID_MODE is compatible with AUTO_POSITION, and 2733 later it actually updates the in-memory structure for 2734 AUTO_POSITION. If gtid_mode was changed between these calls, 2735 auto_position could be set incompatible with gtid_mode. 2736 2737 Hold global_sid_lock.wrlock so that: 2738 - other transactions cannot acquire ownership of any gtid. 2739 2740 Hold gtid_mode_lock so that all places that don't want to hold 2741 any of the other locks, but want to read gtid_mode, don't need 2742 to take the other locks. 2743 */ 2744 gtid_mode_lock->wrlock(); 2745 channel_map.wrlock(); 2746 mysql_mutex_lock(mysql_bin_log.get_log_lock()); 2747 global_sid_lock->wrlock(); 2748 int lock_count= 4; 2749 2750 enum_gtid_mode new_gtid_mode= 2751 (enum_gtid_mode)var->save_result.ulonglong_value; 2752 enum_gtid_mode old_gtid_mode= get_gtid_mode(GTID_MODE_LOCK_SID); 2753 assert(new_gtid_mode <= GTID_MODE_ON); 2754 2755 DBUG_PRINT("info", ("old_gtid_mode=%d new_gtid_mode=%d", 2756 old_gtid_mode, new_gtid_mode)); 2757 2758 if (new_gtid_mode == old_gtid_mode) 2759 goto end; 2760 2761 // Can only change one step at a time. 2762 if (abs((int)new_gtid_mode - (int)old_gtid_mode) > 1) 2763 { 2764 my_error(ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME, MYF(0)); 2765 goto err; 2766 } 2767 2768 // Not allowed with slave_sql_skip_counter 2769 DBUG_PRINT("info", ("sql_slave_skip_counter=%d", sql_slave_skip_counter)); 2770 if (new_gtid_mode == GTID_MODE_ON && sql_slave_skip_counter > 0) 2771 { 2772 my_error(ER_CANT_SET_GTID_MODE, MYF(0), "ON", 2773 "@@GLOBAL.SQL_SLAVE_SKIP_COUNTER is greater than zero"); 2774 goto err; 2775 } 2776 2777 // Cannot set OFF when some channel uses AUTO_POSITION. 2778 if (new_gtid_mode == GTID_MODE_OFF) 2779 { 2780 for (mi_map::iterator it= channel_map.begin(); it!= channel_map.end(); it++) 2781 { 2782 Master_info *mi= it->second; 2783 DBUG_PRINT("info", ("auto_position for channel '%s' is %d", 2784 mi->get_channel(), mi->is_auto_position())); 2785 if (mi != NULL && mi->is_auto_position()) 2786 { 2787 char buf[1024]; 2788 sprintf(buf, "replication channel '%.192s' is configured " 2789 "in AUTO_POSITION mode. Execute " 2790 "CHANGE MASTER TO MASTER_AUTO_POSITION = 0 " 2791 "FOR CHANNEL '%.192s' before you set " 2792 "@@GLOBAL.GTID_MODE = OFF.", 2793 mi->get_channel(), mi->get_channel()); 2794 my_error(ER_CANT_SET_GTID_MODE, MYF(0), "OFF", buf); 2795 goto err; 2796 } 2797 } 2798 } 2799 2800 // Can't set GTID_MODE != ON when group replication is enabled. 2801 if (is_group_replication_running()) 2802 { 2803 assert(old_gtid_mode == GTID_MODE_ON); 2804 assert(new_gtid_mode == GTID_MODE_ON_PERMISSIVE); 2805 my_error(ER_CANT_SET_GTID_MODE, MYF(0), 2806 get_gtid_mode_string(new_gtid_mode), 2807 "group replication requires @@GLOBAL.GTID_MODE=ON"); 2808 goto err; 2809 } 2810 2811 // Compatible with ongoing transactions. 2812 DBUG_PRINT("info", ("anonymous_ownership_count=%d owned_gtids->is_empty=%d", 2813 gtid_state->get_anonymous_ownership_count(), 2814 gtid_state->get_owned_gtids()->is_empty())); 2815 gtid_state->get_owned_gtids()->dbug_print("global owned_gtids"); 2816 if (new_gtid_mode == GTID_MODE_ON && 2817 gtid_state->get_anonymous_ownership_count() > 0) 2818 { 2819 my_error(ER_CANT_SET_GTID_MODE, MYF(0), "ON", 2820 "there are ongoing, anonymous transactions. Before " 2821 "setting @@GLOBAL.GTID_MODE = ON, wait until " 2822 "SHOW STATUS LIKE 'ANONYMOUS_TRANSACTION_COUNT' " 2823 "shows zero on all servers. Then wait for all " 2824 "existing, anonymous transactions to replicate to " 2825 "all slaves, and then execute " 2826 "SET @@GLOBAL.GTID_MODE = ON on all servers. " 2827 "See the Manual for details"); 2828 goto err; 2829 } 2830 2831 if (new_gtid_mode == GTID_MODE_OFF && 2832 !gtid_state->get_owned_gtids()->is_empty()) 2833 { 2834 my_error(ER_CANT_SET_GTID_MODE, MYF(0), "OFF", 2835 "there are ongoing transactions that have a GTID. " 2836 "Before you set @@GLOBAL.GTID_MODE = OFF, wait " 2837 "until SELECT @@GLOBAL.GTID_OWNED is empty on all " 2838 "servers. Then wait for all GTID-transactions to " 2839 "replicate to all servers, and then execute " 2840 "SET @@GLOBAL.GTID_MODE = OFF on all servers. " 2841 "See the Manual for details"); 2842 goto err; 2843 } 2844 2845 // Compatible with ongoing GTID-violating transactions 2846 DBUG_PRINT("info", ("automatic_gtid_violating_transaction_count=%d", 2847 gtid_state->get_automatic_gtid_violating_transaction_count())); 2848 if (new_gtid_mode >= GTID_MODE_ON_PERMISSIVE && 2849 gtid_state->get_automatic_gtid_violating_transaction_count() > 0) 2850 { 2851 my_error(ER_CANT_SET_GTID_MODE, MYF(0), "ON_PERMISSIVE", 2852 "there are ongoing transactions that use " 2853 "GTID_NEXT = 'AUTOMATIC', which violate GTID " 2854 "consistency. Adjust your workload to be " 2855 "GTID-consistent before setting " 2856 "@@GLOBAL.GTID_MODE = ON_PERMISSIVE. " 2857 "See the Manual for " 2858 "@@GLOBAL.ENFORCE_GTID_CONSISTENCY for details"); 2859 goto err; 2860 } 2861 2862 // Compatible with ENFORCE_GTID_CONSISTENCY. 2863 if (new_gtid_mode == GTID_MODE_ON && 2864 get_gtid_consistency_mode() != GTID_CONSISTENCY_MODE_ON) 2865 { 2866 my_error(ER_CANT_SET_GTID_MODE, MYF(0), "ON", 2867 "ENFORCE_GTID_CONSISTENCY is not ON"); 2868 goto err; 2869 } 2870 2871 // Can't set GTID_MODE=OFF with ongoing calls to 2872 // WAIT_FOR_EXECUTED_GTID_SET or 2873 // WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS. 2874 DBUG_PRINT("info", ("gtid_wait_count=%d", gtid_state->get_gtid_wait_count() > 0)); 2875 if (new_gtid_mode == GTID_MODE_OFF && 2876 gtid_state->get_gtid_wait_count() > 0) 2877 { 2878 my_error(ER_CANT_SET_GTID_MODE, MYF(0), "OFF", 2879 "there are ongoing calls to " 2880 "WAIT_FOR_EXECUTED_GTID_SET or " 2881 "WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS. Before you set " 2882 "@@GLOBAL.GTID_MODE = OFF, ensure that no other " 2883 "client is waiting for GTID-transactions to be " 2884 "committed"); 2885 goto err; 2886 } 2887 2888 // Update the mode 2889 global_var(ulong)= new_gtid_mode; 2890 global_sid_lock->unlock(); 2891 lock_count= 3; 2892 2893 // Generate note in log 2894 sql_print_information("Changed GTID_MODE from %s to %s.", 2895 gtid_mode_names[old_gtid_mode], 2896 gtid_mode_names[new_gtid_mode]); 2897 2898 // Rotate 2899 { 2900 bool dont_care= false; 2901 if (mysql_bin_log.rotate(true, &dont_care)) 2902 goto err; 2903 } 2904 2905 end: 2906 ret= false; 2907 err: 2908 assert(lock_count >= 0); 2909 assert(lock_count <= 4); 2910 if (lock_count == 4) 2911 global_sid_lock->unlock(); 2912 mysql_mutex_unlock(mysql_bin_log.get_log_lock()); 2913 channel_map.unlock(); 2914 gtid_mode_lock->unlock(); 2915 DBUG_RETURN(ret); 2916 } 2917 }; 2918 2919 #endif /* HAVE_REPLICATION */ 2920 2921 2922 class Sys_var_enforce_gtid_consistency : public Sys_var_multi_enum 2923 { 2924 public: 2925 Sys_var_enforce_gtid_consistency( 2926 const char *name_arg, 2927 const char *comment, 2928 int flag_args, 2929 ptrdiff_t off, 2930 size_t size, 2931 CMD_LINE getopt, 2932 const ALIAS aliases[], 2933 const uint value_count, 2934 uint def_val, 2935 uint command_line_no_value, 2936 PolyLock *lock=0, 2937 enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, 2938 on_check_function on_check_func=0) : Sys_var_multi_enum(name_arg,comment,flag_args,off,size,getopt,aliases,value_count,def_val,command_line_no_value,lock,binlog_status_arg,on_check_func)2939 Sys_var_multi_enum(name_arg, comment, flag_args, off, size, getopt, 2940 aliases, value_count, def_val, command_line_no_value, 2941 lock, binlog_status_arg, on_check_func) 2942 { } 2943 global_update(THD * thd,set_var * var)2944 bool global_update(THD *thd, set_var *var) 2945 { 2946 DBUG_ENTER("Sys_var_enforce_gtid_consistency::global_update"); 2947 bool ret= true; 2948 2949 /* 2950 Hold global_sid_lock.wrlock so that other transactions cannot 2951 acquire ownership of any gtid. 2952 */ 2953 global_sid_lock->wrlock(); 2954 2955 DBUG_PRINT("info", ("var->save_result.ulonglong_value=%llu", 2956 var->save_result.ulonglong_value)); 2957 enum_gtid_consistency_mode new_mode= 2958 (enum_gtid_consistency_mode)var->save_result.ulonglong_value; 2959 enum_gtid_consistency_mode old_mode= get_gtid_consistency_mode(); 2960 enum_gtid_mode gtid_mode= get_gtid_mode(GTID_MODE_LOCK_SID); 2961 2962 assert(new_mode <= GTID_CONSISTENCY_MODE_WARN); 2963 2964 DBUG_PRINT("info", ("old enforce_gtid_consistency=%d " 2965 "new enforce_gtid_consistency=%d " 2966 "gtid_mode=%d ", 2967 old_mode, new_mode, gtid_mode)); 2968 2969 if (new_mode == old_mode) 2970 goto end; 2971 2972 // Can't turn off GTID-consistency when GTID_MODE=ON. 2973 if (new_mode != GTID_CONSISTENCY_MODE_ON && gtid_mode == GTID_MODE_ON) 2974 { 2975 my_error(ER_GTID_MODE_ON_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON, MYF(0)); 2976 goto err; 2977 } 2978 // If there are ongoing GTID-violating transactions, and we are 2979 // moving from OFF->ON, WARN->ON, or OFF->WARN, generate warning 2980 // or error accordingly. 2981 if (new_mode == GTID_CONSISTENCY_MODE_ON || 2982 (old_mode == GTID_CONSISTENCY_MODE_OFF && 2983 new_mode == GTID_CONSISTENCY_MODE_WARN)) 2984 { 2985 DBUG_PRINT("info", 2986 ("automatic_gtid_violating_transaction_count=%d " 2987 "anonymous_gtid_violating_transaction_count=%d", 2988 gtid_state->get_automatic_gtid_violating_transaction_count(), 2989 gtid_state->get_anonymous_gtid_violating_transaction_count())); 2990 if (gtid_state->get_automatic_gtid_violating_transaction_count() > 0 || 2991 gtid_state->get_anonymous_gtid_violating_transaction_count() > 0) 2992 { 2993 if (new_mode == GTID_CONSISTENCY_MODE_ON) 2994 { 2995 my_error(ER_CANT_SET_ENFORCE_GTID_CONSISTENCY_ON_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS, MYF(0)); 2996 goto err; 2997 } 2998 else 2999 { 3000 push_warning_printf(thd, Sql_condition::SL_WARNING, 3001 ER_SET_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS, 3002 "%s", ER(ER_SET_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS)); 3003 } 3004 } 3005 } 3006 3007 // Update the mode 3008 global_var(ulong)= new_mode; 3009 3010 // Generate note in log 3011 sql_print_information("Changed ENFORCE_GTID_CONSISTENCY from %s to %s.", 3012 get_gtid_consistency_mode_string(old_mode), 3013 get_gtid_consistency_mode_string(new_mode)); 3014 3015 end: 3016 ret= false; 3017 err: 3018 global_sid_lock->unlock(); 3019 DBUG_RETURN(ret); 3020 } 3021 }; 3022 3023 #endif /* SYS_VARS_H_INCLUDED */ 3024 3025