1 | /* Copyright (c) 2002, 2011, Oracle and/or its affiliates. |
2 | Copyright (c) 2010, 2013, Monty Program Ab. |
3 | |
4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by |
6 | the Free Software Foundation; version 2 of the License. |
7 | |
8 | This program is distributed in the hope that it will be useful, |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | GNU General Public License for more details. |
12 | |
13 | You should have received a copy of the GNU General Public License |
14 | along with this program; if not, write to the Free Software |
15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
16 | |
17 | /** |
18 | @file |
19 | "private" interface to sys_var - server configuration variables. |
20 | |
21 | This header is included only by the file that contains declarations |
22 | of sys_var variables (sys_vars.cc). |
23 | */ |
24 | |
25 | #include "sys_vars_shared.h" |
26 | #include <my_getopt.h> |
27 | #include <my_bit.h> |
28 | #include <my_dir.h> |
29 | #include "keycaches.h" |
30 | #include "strfunc.h" |
31 | #include "tztime.h" // my_tz_find, my_tz_SYSTEM, struct Time_zone |
32 | #include "rpl_mi.h" // For Multi-Source Replication |
33 | #include "debug_sync.h" |
34 | |
35 | /* |
36 | a set of mostly trivial (as in f(X)=X) defines below to make system variable |
37 | declarations more readable |
38 | */ |
39 | #define VALID_RANGE(X,Y) X,Y |
40 | #define DEFAULT(X) X |
41 | #define BLOCK_SIZE(X) X |
42 | #define GLOBAL_VAR(X) sys_var::GLOBAL, (((char*)&(X))-(char*)&global_system_variables), sizeof(X) |
43 | #define SESSION_VAR(X) sys_var::SESSION, offsetof(SV, X), sizeof(((SV *)0)->X) |
44 | #define SESSION_ONLY(X) sys_var::ONLY_SESSION, offsetof(SV, X), sizeof(((SV *)0)->X) |
45 | #define NO_CMD_LINE CMD_LINE(NO_ARG, sys_var::NO_GETOPT) |
46 | #define CMD_LINE_HELP_ONLY CMD_LINE(NO_ARG, sys_var::GETOPT_ONLY_HELP) |
47 | /* |
48 | the define below means that there's no *second* mutex guard, |
49 | LOCK_global_system_variables always guards all system variables |
50 | */ |
51 | #define NO_MUTEX_GUARD ((PolyLock*)0) |
52 | #define IN_BINLOG sys_var::SESSION_VARIABLE_IN_BINLOG |
53 | #define NOT_IN_BINLOG sys_var::VARIABLE_NOT_IN_BINLOG |
54 | #define ON_READ(X) X |
55 | #define ON_CHECK(X) X |
56 | #define ON_UPDATE(X) X |
57 | #define READ_ONLY sys_var::READONLY+ |
58 | #define AUTO_SET sys_var::AUTO_SET+ |
59 | // this means that Sys_var_charptr initial value was malloc()ed |
60 | #define PREALLOCATED sys_var::ALLOCATED+ |
61 | #define PARSED_EARLY sys_var::PARSE_EARLY+ |
62 | #define NO_SET_STMT sys_var::NO_SET_STATEMENT+ |
63 | |
64 | /* |
65 | Sys_var_bit meaning is reversed, like in |
66 | @@foreign_key_checks <-> OPTION_NO_FOREIGN_KEY_CHECKS |
67 | */ |
68 | #define REVERSE(X) ~(X) |
69 | #define DEPRECATED(X) X |
70 | |
71 | #define session_var(THD, TYPE) (*(TYPE*)session_var_ptr(THD)) |
72 | #define global_var(TYPE) (*(TYPE*)global_var_ptr()) |
73 | |
74 | #if SIZEOF_OFF_T > 4 && defined(BIG_TABLES) |
75 | #define GET_HA_ROWS GET_ULL |
76 | #else |
77 | #define GET_HA_ROWS GET_ULONG |
78 | #endif |
79 | |
80 | // Disable warning caused by SESSION_VAR() macro |
81 | #ifdef __clang__ |
82 | #pragma clang diagnostic ignored "-Winvalid-offsetof" |
83 | #endif |
84 | |
85 | /* |
86 | special assert for sysvars. Tells the name of the variable, |
87 | and fails even in non-debug builds. |
88 | |
89 | It is supposed to be used *only* in Sys_var* constructors, |
90 | and has name_arg hard-coded to prevent incorrect usage. |
91 | */ |
92 | #define SYSVAR_ASSERT(X) \ |
93 | while(!(X)) \ |
94 | { \ |
95 | fprintf(stderr, "Sysvar '%s' failed '%s'\n", name_arg, #X); \ |
96 | DBUG_ASSERT(0); \ |
97 | exit(255); \ |
98 | } |
99 | |
100 | enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET}; |
101 | |
102 | static const char *bool_values[3]= {"OFF" , "ON" , 0}; |
103 | TYPELIB bool_typelib={ array_elements(bool_values)-1, "" , bool_values, 0 }; |
104 | |
105 | /** |
106 | A small wrapper class to pass getopt arguments as a pair |
107 | to the Sys_var_* constructors. It improves type safety and helps |
108 | to catch errors in the argument order. |
109 | */ |
110 | struct CMD_LINE |
111 | { |
112 | int id; |
113 | enum get_opt_arg_type arg_type; |
114 | CMD_LINE(enum get_opt_arg_type getopt_arg_type, int getopt_id=0) |
115 | : id(getopt_id), arg_type(getopt_arg_type) {} |
116 | }; |
117 | |
118 | /** |
119 | Sys_var_integer template is used to generate Sys_var_* classes |
120 | for variables that represent the value as an integer number. |
121 | They are Sys_var_uint, Sys_var_ulong, Sys_var_harows, Sys_var_ulonglong, |
122 | Sys_var_int. |
123 | |
124 | An integer variable has a minimal and maximal values, and a "block_size" |
125 | (any valid value of the variable must be divisible by the block_size). |
126 | |
127 | Class specific constructor arguments: min, max, block_size |
128 | Backing store: int, uint, ulong, ha_rows, ulonglong, depending on the class |
129 | */ |
130 | template <typename T, ulong ARGT, enum enum_mysql_show_type SHOWT> |
131 | class Sys_var_integer: public sys_var |
132 | { |
133 | public: |
134 | Sys_var_integer(const char *name_arg, |
135 | const char *, int flag_args, ptrdiff_t off, size_t size, |
136 | CMD_LINE getopt, |
137 | T min_val, T max_val, T def_val, uint block_size, PolyLock *lock=0, |
138 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
139 | on_check_function on_check_func=0, |
140 | on_update_function on_update_func=0, |
141 | const char *substitute=0) |
142 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
143 | getopt.arg_type, SHOWT, def_val, lock, binlog_status_arg, |
144 | on_check_func, on_update_func, substitute) |
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 | global_var(T)= def_val; |
155 | SYSVAR_ASSERT(size == sizeof(T)); |
156 | SYSVAR_ASSERT(min_val < max_val); |
157 | SYSVAR_ASSERT(min_val <= def_val); |
158 | SYSVAR_ASSERT(max_val >= def_val); |
159 | SYSVAR_ASSERT(block_size > 0); |
160 | SYSVAR_ASSERT(def_val % block_size == 0); |
161 | } |
162 | bool do_check(THD *thd, set_var *var) |
163 | { |
164 | my_bool fixed= FALSE, unused; |
165 | longlong v= var->value->val_int(); |
166 | |
167 | if ((ARGT == GET_HA_ROWS) || (ARGT == GET_UINT) || |
168 | (ARGT == GET_ULONG) || (ARGT == GET_ULL)) |
169 | { |
170 | ulonglong uv; |
171 | |
172 | /* |
173 | if the value is signed and negative, |
174 | and a variable is unsigned, it is set to zero |
175 | */ |
176 | if ((fixed= (!var->value->unsigned_flag && v < 0))) |
177 | uv= 0; |
178 | else |
179 | uv= v; |
180 | |
181 | var->save_result.ulonglong_value= |
182 | getopt_ull_limit_value(uv, &option, &unused); |
183 | |
184 | if (max_var_ptr() && (T)var->save_result.ulonglong_value > *max_var_ptr()) |
185 | var->save_result.ulonglong_value= *max_var_ptr(); |
186 | |
187 | fixed= fixed || var->save_result.ulonglong_value != uv; |
188 | } |
189 | else |
190 | { |
191 | /* |
192 | if the value is unsigned and has the highest bit set |
193 | and a variable is signed, it is set to max signed value |
194 | */ |
195 | if ((fixed= (var->value->unsigned_flag && v < 0))) |
196 | v= LONGLONG_MAX; |
197 | |
198 | var->save_result.longlong_value= |
199 | getopt_ll_limit_value(v, &option, &unused); |
200 | |
201 | if (max_var_ptr() && (T)var->save_result.longlong_value > *max_var_ptr()) |
202 | var->save_result.longlong_value= *max_var_ptr(); |
203 | |
204 | fixed= fixed || var->save_result.longlong_value != v; |
205 | } |
206 | return throw_bounds_warning(thd, name.str, fixed, |
207 | var->value->unsigned_flag, v); |
208 | } |
209 | bool session_update(THD *thd, set_var *var) |
210 | { |
211 | session_var(thd, T)= static_cast<T>(var->save_result.ulonglong_value); |
212 | return false; |
213 | } |
214 | bool global_update(THD *thd, set_var *var) |
215 | { |
216 | global_var(T)= static_cast<T>(var->save_result.ulonglong_value); |
217 | return false; |
218 | } |
219 | void session_save_default(THD *thd, set_var *var) |
220 | { var->save_result.ulonglong_value= (ulonglong)*(T*)global_value_ptr(thd, 0); } |
221 | void global_save_default(THD *thd, set_var *var) |
222 | { var->save_result.ulonglong_value= option.def_value; } |
223 | private: |
224 | T *max_var_ptr() |
225 | { |
226 | return scope() == SESSION ? (T*)(((uchar*)&max_system_variables) + offset) |
227 | : 0; |
228 | } |
229 | uchar *default_value_ptr(THD *thd) { return (uchar*) &option.def_value; } |
230 | }; |
231 | |
232 | typedef Sys_var_integer<int, GET_INT, SHOW_SINT> Sys_var_int; |
233 | typedef Sys_var_integer<uint, GET_UINT, SHOW_UINT> Sys_var_uint; |
234 | typedef Sys_var_integer<ulong, GET_ULONG, SHOW_ULONG> Sys_var_ulong; |
235 | typedef Sys_var_integer<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS> Sys_var_harows; |
236 | typedef Sys_var_integer<ulonglong, GET_ULL, SHOW_ULONGLONG> Sys_var_ulonglong; |
237 | typedef Sys_var_integer<long, GET_LONG, SHOW_SLONG> Sys_var_long; |
238 | |
239 | |
240 | template<> uchar *Sys_var_int::default_value_ptr(THD *thd) |
241 | { |
242 | thd->sys_var_tmp.int_value= (int)option.def_value; |
243 | return (uchar*) &thd->sys_var_tmp.int_value; |
244 | } |
245 | |
246 | template<> uchar *Sys_var_uint::default_value_ptr(THD *thd) |
247 | { |
248 | thd->sys_var_tmp.uint_value= (uint)option.def_value; |
249 | return (uchar*) &thd->sys_var_tmp.uint_value; |
250 | } |
251 | |
252 | template<> uchar *Sys_var_long::default_value_ptr(THD *thd) |
253 | { |
254 | thd->sys_var_tmp.long_value= (long)option.def_value; |
255 | return (uchar*) &thd->sys_var_tmp.long_value; |
256 | } |
257 | |
258 | template<> uchar *Sys_var_ulong::default_value_ptr(THD *thd) |
259 | { |
260 | thd->sys_var_tmp.ulong_value= (ulong)option.def_value; |
261 | return (uchar*) &thd->sys_var_tmp.ulong_value; |
262 | } |
263 | |
264 | |
265 | /** |
266 | Helper class for variables that take values from a TYPELIB |
267 | */ |
268 | class Sys_var_typelib: public sys_var |
269 | { |
270 | protected: |
271 | TYPELIB typelib; |
272 | public: |
273 | Sys_var_typelib(const char *name_arg, |
274 | const char *, int flag_args, ptrdiff_t off, |
275 | CMD_LINE getopt, |
276 | SHOW_TYPE show_val_type_arg, const char *values[], |
277 | ulonglong def_val, PolyLock *lock, |
278 | enum binlog_status_enum binlog_status_arg, |
279 | on_check_function on_check_func, on_update_function on_update_func, |
280 | const char *substitute) |
281 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
282 | getopt.arg_type, show_val_type_arg, def_val, lock, |
283 | binlog_status_arg, on_check_func, |
284 | on_update_func, substitute) |
285 | { |
286 | for (typelib.count= 0; values[typelib.count]; typelib.count++) /*no-op */; |
287 | typelib.name="" ; |
288 | typelib.type_names= values; |
289 | typelib.type_lengths= 0; // only used by Fields_enum and Field_set |
290 | option.typelib= &typelib; |
291 | } |
292 | bool do_check(THD *thd, set_var *var) // works for enums and my_bool |
293 | { |
294 | char buff[STRING_BUFFER_USUAL_SIZE]; |
295 | String str(buff, sizeof(buff), system_charset_info), *res; |
296 | |
297 | if (var->value->result_type() == STRING_RESULT) |
298 | { |
299 | if (!(res=var->value->val_str(&str))) |
300 | return true; |
301 | else |
302 | if (!(var->save_result.ulonglong_value= |
303 | find_type(&typelib, res->ptr(), res->length(), false))) |
304 | return true; |
305 | else |
306 | var->save_result.ulonglong_value--; |
307 | } |
308 | else |
309 | { |
310 | longlong tmp=var->value->val_int(); |
311 | if (tmp < 0 || tmp >= typelib.count) |
312 | return true; |
313 | else |
314 | var->save_result.ulonglong_value= tmp; |
315 | } |
316 | |
317 | return false; |
318 | } |
319 | }; |
320 | |
321 | /** |
322 | The class for ENUM variables - variables that take one value from a fixed |
323 | list of values. |
324 | |
325 | Class specific constructor arguments: |
326 | char* values[] - 0-terminated list of strings of valid values |
327 | |
328 | Backing store: ulong |
329 | |
330 | @note |
331 | Do *not* use "enum FOO" variables as a backing store, there is no |
332 | guarantee that sizeof(enum FOO) == sizeof(uint), there is no guarantee |
333 | even that sizeof(enum FOO) == sizeof(enum BAR) |
334 | */ |
335 | class Sys_var_enum: public Sys_var_typelib |
336 | { |
337 | public: |
338 | Sys_var_enum(const char *name_arg, |
339 | const char *, int flag_args, ptrdiff_t off, size_t size, |
340 | CMD_LINE getopt, |
341 | const char *values[], uint def_val, PolyLock *lock=0, |
342 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
343 | on_check_function on_check_func=0, |
344 | on_update_function on_update_func=0, |
345 | const char *substitute=0) |
346 | : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, |
347 | SHOW_CHAR, values, def_val, lock, |
348 | binlog_status_arg, on_check_func, on_update_func, |
349 | substitute) |
350 | { |
351 | option.var_type|= GET_ENUM; |
352 | global_var(ulong)= def_val; |
353 | SYSVAR_ASSERT(def_val < typelib.count); |
354 | SYSVAR_ASSERT(size == sizeof(ulong)); |
355 | } |
356 | bool session_update(THD *thd, set_var *var) |
357 | { |
358 | session_var(thd, ulong)= static_cast<ulong>(var->save_result.ulonglong_value); |
359 | return false; |
360 | } |
361 | bool global_update(THD *thd, set_var *var) |
362 | { |
363 | global_var(ulong)= static_cast<ulong>(var->save_result.ulonglong_value); |
364 | return false; |
365 | } |
366 | void session_save_default(THD *thd, set_var *var) |
367 | { var->save_result.ulonglong_value= global_var(ulong); } |
368 | void global_save_default(THD *thd, set_var *var) |
369 | { var->save_result.ulonglong_value= option.def_value; } |
370 | uchar *valptr(THD *thd, ulong val) |
371 | { return (uchar*)typelib.type_names[val]; } |
372 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
373 | { return valptr(thd, session_var(thd, ulong)); } |
374 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
375 | { return valptr(thd, global_var(ulong)); } |
376 | uchar *default_value_ptr(THD *thd) |
377 | { return valptr(thd, (ulong)option.def_value); } |
378 | }; |
379 | |
380 | /** |
381 | The class for boolean variables - a variant of ENUM variables |
382 | with the fixed list of values of { OFF , ON } |
383 | |
384 | Backing store: my_bool |
385 | */ |
386 | class Sys_var_mybool: public Sys_var_typelib |
387 | { |
388 | public: |
389 | Sys_var_mybool(const char *name_arg, |
390 | const char *, int flag_args, ptrdiff_t off, size_t size, |
391 | CMD_LINE getopt, |
392 | my_bool def_val, PolyLock *lock=0, |
393 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
394 | on_check_function on_check_func=0, |
395 | on_update_function on_update_func=0, |
396 | const char *substitute=0) |
397 | : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, |
398 | SHOW_MY_BOOL, bool_values, def_val, lock, |
399 | binlog_status_arg, on_check_func, on_update_func, |
400 | substitute) |
401 | { |
402 | option.var_type|= GET_BOOL; |
403 | global_var(my_bool)= def_val; |
404 | SYSVAR_ASSERT(def_val < 2); |
405 | SYSVAR_ASSERT(getopt.arg_type == OPT_ARG || getopt.id < 0); |
406 | SYSVAR_ASSERT(size == sizeof(my_bool)); |
407 | } |
408 | bool session_update(THD *thd, set_var *var) |
409 | { |
410 | session_var(thd, my_bool)= var->save_result.ulonglong_value != 0; |
411 | return false; |
412 | } |
413 | bool global_update(THD *thd, set_var *var) |
414 | { |
415 | global_var(my_bool)= var->save_result.ulonglong_value != 0; |
416 | return false; |
417 | } |
418 | void session_save_default(THD *thd, set_var *var) |
419 | { var->save_result.ulonglong_value= (ulonglong)*(my_bool *)global_value_ptr(thd, 0); } |
420 | void global_save_default(THD *thd, set_var *var) |
421 | { var->save_result.ulonglong_value= option.def_value; } |
422 | uchar *default_value_ptr(THD *thd) |
423 | { |
424 | thd->sys_var_tmp.my_bool_value=(my_bool) option.def_value; |
425 | return (uchar*) &thd->sys_var_tmp.my_bool_value; |
426 | } |
427 | }; |
428 | |
429 | /** |
430 | The class for string variables. The string can be in character_set_filesystem |
431 | or in character_set_system. The string can be allocated with my_malloc() |
432 | or not. The state of the initial value is specified in the constructor, |
433 | after that it's managed automatically. The value of NULL is supported. |
434 | |
435 | Class specific constructor arguments: |
436 | enum charset_enum is_os_charset_arg |
437 | |
438 | Backing store: char* |
439 | |
440 | @note |
441 | This class supports only GLOBAL variables, because THD on destruction |
442 | does not destroy individual members of SV, there's no way to free |
443 | allocated string variables for every thread. |
444 | */ |
445 | class Sys_var_charptr_base: public sys_var |
446 | { |
447 | public: |
448 | Sys_var_charptr_base(const char *name_arg, |
449 | const char *, int flag_args, ptrdiff_t off, size_t size, |
450 | CMD_LINE getopt, |
451 | enum charset_enum is_os_charset_arg, |
452 | const char *def_val, PolyLock *lock=0, |
453 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
454 | on_check_function on_check_func=0, |
455 | on_update_function on_update_func=0, |
456 | const char *substitute=0) |
457 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
458 | getopt.arg_type, SHOW_CHAR_PTR, (intptr)def_val, |
459 | lock, binlog_status_arg, on_check_func, on_update_func, |
460 | substitute) |
461 | { |
462 | is_os_charset= is_os_charset_arg == IN_FS_CHARSET; |
463 | /* |
464 | use GET_STR_ALLOC - if ALLOCATED it must be *always* allocated, |
465 | otherwise (GET_STR) you'll never know whether to free it or not. |
466 | (think of an exit because of an error right after my_getopt) |
467 | */ |
468 | option.var_type|= (flags & ALLOCATED) ? GET_STR_ALLOC : GET_STR; |
469 | global_var(const char*)= def_val; |
470 | } |
471 | void cleanup() |
472 | { |
473 | if (flags & ALLOCATED) |
474 | { |
475 | my_free(global_var(char*)); |
476 | global_var(char *)= NULL; |
477 | } |
478 | flags&= ~ALLOCATED; |
479 | } |
480 | static bool do_string_check(THD *thd, set_var *var, CHARSET_INFO *charset) |
481 | { |
482 | char buff[STRING_BUFFER_USUAL_SIZE], buff2[STRING_BUFFER_USUAL_SIZE]; |
483 | String str(buff, sizeof(buff), charset); |
484 | String str2(buff2, sizeof(buff2), charset), *res; |
485 | |
486 | if (!(res=var->value->val_str(&str))) |
487 | var->save_result.string_value.str= 0; |
488 | else |
489 | { |
490 | uint32 unused; |
491 | if (String::needs_conversion(res->length(), res->charset(), |
492 | charset, &unused)) |
493 | { |
494 | uint errors; |
495 | str2.copy(res->ptr(), res->length(), res->charset(), charset, |
496 | &errors); |
497 | res=&str2; |
498 | |
499 | } |
500 | var->save_result.string_value.str= thd->strmake(res->ptr(), res->length()); |
501 | var->save_result.string_value.length= res->length(); |
502 | } |
503 | |
504 | return false; |
505 | } |
506 | bool do_check(THD *thd, set_var *var) |
507 | { return do_string_check(thd, var, charset(thd)); } |
508 | bool session_update(THD *thd, set_var *var)= 0; |
509 | char *global_update_prepare(THD *thd, set_var *var) |
510 | { |
511 | char *new_val, *ptr= var->save_result.string_value.str; |
512 | size_t len=var->save_result.string_value.length; |
513 | if (ptr) |
514 | { |
515 | new_val= (char*)my_memdup(ptr, len+1, MYF(MY_WME)); |
516 | if (!new_val) return 0; |
517 | new_val[len]=0; |
518 | } |
519 | else |
520 | new_val= 0; |
521 | return new_val; |
522 | } |
523 | void global_update_finish(char *new_val) |
524 | { |
525 | if (flags & ALLOCATED) |
526 | my_free(global_var(char*)); |
527 | flags|= ALLOCATED; |
528 | global_var(char*)= new_val; |
529 | } |
530 | bool global_update(THD *thd, set_var *var) |
531 | { |
532 | char *new_val= global_update_prepare(thd, var); |
533 | global_update_finish(new_val); |
534 | return (new_val == 0 && var->save_result.string_value.str != 0); |
535 | } |
536 | void session_save_default(THD *thd, set_var *var)= 0; |
537 | void global_save_default(THD *thd, set_var *var) |
538 | { |
539 | char *ptr= (char*)(intptr)option.def_value; |
540 | var->save_result.string_value.str= ptr; |
541 | var->save_result.string_value.length= ptr ? strlen(ptr) : 0; |
542 | } |
543 | }; |
544 | |
545 | class Sys_var_charptr: public Sys_var_charptr_base |
546 | { |
547 | public: |
548 | Sys_var_charptr(const char *name_arg, |
549 | const char *, int flag_args, ptrdiff_t off, size_t size, |
550 | CMD_LINE getopt, |
551 | enum charset_enum is_os_charset_arg, |
552 | const char *def_val, PolyLock *lock=0, |
553 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
554 | on_check_function on_check_func=0, |
555 | on_update_function on_update_func=0, |
556 | const char *substitute=0) : |
557 | Sys_var_charptr_base(name_arg, comment, flag_args, off, size, getopt, |
558 | is_os_charset_arg, def_val, lock, binlog_status_arg, |
559 | on_check_func, on_update_func, substitute) |
560 | { |
561 | SYSVAR_ASSERT(scope() == GLOBAL); |
562 | SYSVAR_ASSERT(size == sizeof(char *)); |
563 | } |
564 | |
565 | bool session_update(THD *thd, set_var *var) |
566 | { |
567 | DBUG_ASSERT(FALSE); |
568 | return true; |
569 | } |
570 | void session_save_default(THD *thd, set_var *var) |
571 | { DBUG_ASSERT(FALSE); } |
572 | }; |
573 | |
574 | #ifndef EMBEDDED_LIBRARY |
575 | class Sys_var_sesvartrack: public Sys_var_charptr_base |
576 | { |
577 | public: |
578 | Sys_var_sesvartrack(const char *name_arg, |
579 | const char *, |
580 | CMD_LINE getopt, |
581 | enum charset_enum is_os_charset_arg, |
582 | const char *def_val, PolyLock *lock) : |
583 | Sys_var_charptr_base(name_arg, comment, |
584 | SESSION_VAR(session_track_system_variables), |
585 | getopt, is_os_charset_arg, def_val, lock, |
586 | VARIABLE_NOT_IN_BINLOG, 0, 0, 0) |
587 | {} |
588 | bool do_check(THD *thd, set_var *var) |
589 | { |
590 | if (Sys_var_charptr_base::do_check(thd, var) || |
591 | sysvartrack_validate_value(thd, var->save_result.string_value.str, |
592 | var->save_result.string_value.length)) |
593 | return TRUE; |
594 | return FALSE; |
595 | } |
596 | bool global_update(THD *thd, set_var *var) |
597 | { |
598 | char *new_val= global_update_prepare(thd, var); |
599 | if (new_val) |
600 | { |
601 | if (sysvartrack_reprint_value(thd, new_val, |
602 | var->save_result.string_value.length)) |
603 | new_val= 0; |
604 | } |
605 | global_update_finish(new_val); |
606 | return (new_val == 0 && var->save_result.string_value.str != 0); |
607 | } |
608 | bool session_update(THD *thd, set_var *var) |
609 | { |
610 | return sysvartrack_update(thd, var); |
611 | } |
612 | void session_save_default(THD *thd, set_var *var) |
613 | { |
614 | var->save_result.string_value.str= global_var(char*); |
615 | var->save_result.string_value.length= |
616 | strlen(var->save_result.string_value.str); |
617 | /* parse and feel list with default values */ |
618 | if (thd) |
619 | { |
620 | #ifdef DBUG_ASSERT_EXISTS |
621 | bool res= |
622 | #endif |
623 | sysvartrack_validate_value(thd, |
624 | var->save_result.string_value.str, |
625 | var->save_result.string_value.length); |
626 | DBUG_ASSERT(res == 0); |
627 | } |
628 | } |
629 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
630 | { |
631 | DBUG_ASSERT(thd != NULL); |
632 | size_t len= sysvartrack_value_len(thd); |
633 | char *res= (char *)thd->alloc(len + sizeof(char *)); |
634 | if (res) |
635 | { |
636 | char *buf= res + sizeof(char *); |
637 | *((char**) res)= buf; |
638 | sysvartrack_value_construct(thd, buf, len); |
639 | } |
640 | return (uchar *)res; |
641 | } |
642 | }; |
643 | #endif //EMBEDDED_LIBRARY |
644 | |
645 | |
646 | class Sys_var_proxy_user: public sys_var |
647 | { |
648 | public: |
649 | Sys_var_proxy_user(const char *name_arg, |
650 | const char *, enum charset_enum is_os_charset_arg) |
651 | : sys_var(&all_sys_vars, name_arg, comment, |
652 | sys_var::READONLY+sys_var::ONLY_SESSION, 0, NO_GETOPT, |
653 | NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG, |
654 | NULL, NULL, NULL) |
655 | { |
656 | is_os_charset= is_os_charset_arg == IN_FS_CHARSET; |
657 | option.var_type|= GET_STR; |
658 | } |
659 | bool do_check(THD *thd, set_var *var) |
660 | { |
661 | DBUG_ASSERT(FALSE); |
662 | return true; |
663 | } |
664 | bool session_update(THD *thd, set_var *var) |
665 | { |
666 | DBUG_ASSERT(FALSE); |
667 | return true; |
668 | } |
669 | bool global_update(THD *thd, set_var *var) |
670 | { |
671 | DBUG_ASSERT(FALSE); |
672 | return false; |
673 | } |
674 | void session_save_default(THD *thd, set_var *var) |
675 | { DBUG_ASSERT(FALSE); } |
676 | void global_save_default(THD *thd, set_var *var) |
677 | { DBUG_ASSERT(FALSE); } |
678 | protected: |
679 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
680 | { |
681 | return thd->security_ctx->proxy_user[0] ? |
682 | (uchar *) &(thd->security_ctx->proxy_user[0]) : NULL; |
683 | } |
684 | }; |
685 | |
686 | class Sys_var_external_user : public Sys_var_proxy_user |
687 | { |
688 | public: |
689 | Sys_var_external_user(const char *name_arg, const char *, |
690 | enum charset_enum is_os_charset_arg) |
691 | : Sys_var_proxy_user (name_arg, comment_arg, is_os_charset_arg) |
692 | {} |
693 | |
694 | protected: |
695 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
696 | { |
697 | return (uchar*)thd->security_ctx->external_user; |
698 | } |
699 | }; |
700 | |
701 | class Master_info; |
702 | class Sys_var_rpl_filter: public sys_var |
703 | { |
704 | private: |
705 | int opt_id; |
706 | |
707 | public: |
708 | Sys_var_rpl_filter(const char *name, int getopt_id, const char *) |
709 | : sys_var(&all_sys_vars, name, comment, sys_var::GLOBAL, 0, NO_GETOPT, |
710 | NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG, |
711 | NULL, NULL, NULL), opt_id(getopt_id) |
712 | { |
713 | option.var_type|= GET_STR | GET_ASK_ADDR; |
714 | } |
715 | |
716 | bool do_check(THD *thd, set_var *var) |
717 | { |
718 | return Sys_var_charptr::do_string_check(thd, var, charset(thd)); |
719 | } |
720 | void session_save_default(THD *thd, set_var *var) |
721 | { DBUG_ASSERT(FALSE); } |
722 | |
723 | void global_save_default(THD *thd, set_var *var) |
724 | { DBUG_ASSERT(FALSE); } |
725 | |
726 | bool session_update(THD *thd, set_var *var) |
727 | { |
728 | DBUG_ASSERT(FALSE); |
729 | return true; |
730 | } |
731 | |
732 | bool global_update(THD *thd, set_var *var); |
733 | |
734 | protected: |
735 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base); |
736 | bool set_filter_value(const char *value, Master_info *mi); |
737 | }; |
738 | |
739 | /** |
740 | The class for string variables. Useful for strings that aren't necessarily |
741 | \0-terminated. Otherwise the same as Sys_var_charptr. |
742 | |
743 | Class specific constructor arguments: |
744 | enum charset_enum is_os_charset_arg |
745 | |
746 | Backing store: LEX_CSTRING |
747 | |
748 | @note |
749 | Behaves exactly as Sys_var_charptr, only the backing store is different. |
750 | */ |
751 | class Sys_var_lexstring: public Sys_var_charptr |
752 | { |
753 | public: |
754 | Sys_var_lexstring(const char *name_arg, |
755 | const char *, int flag_args, ptrdiff_t off, size_t size, |
756 | CMD_LINE getopt, |
757 | enum charset_enum is_os_charset_arg, |
758 | const char *def_val, PolyLock *lock=0, |
759 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
760 | on_check_function on_check_func=0, |
761 | on_update_function on_update_func=0, |
762 | const char *substitute=0) |
763 | : Sys_var_charptr(name_arg, comment, flag_args, off, sizeof(char*), |
764 | getopt, is_os_charset_arg, def_val, lock, binlog_status_arg, |
765 | on_check_func, on_update_func, substitute) |
766 | { |
767 | global_var(LEX_CSTRING).length= strlen(def_val); |
768 | SYSVAR_ASSERT(size == sizeof(LEX_CSTRING)); |
769 | *const_cast<SHOW_TYPE*>(&show_val_type)= SHOW_LEX_STRING; |
770 | } |
771 | bool global_update(THD *thd, set_var *var) |
772 | { |
773 | if (Sys_var_charptr::global_update(thd, var)) |
774 | return true; |
775 | global_var(LEX_CSTRING).length= var->save_result.string_value.length; |
776 | return false; |
777 | } |
778 | }; |
779 | |
780 | |
781 | /* |
782 | A LEX_CSTRING stored only in thd->variables |
783 | Only to be used for small buffers |
784 | */ |
785 | |
786 | class Sys_var_session_lexstring: public sys_var |
787 | { |
788 | size_t max_length; |
789 | public: |
790 | Sys_var_session_lexstring(const char *name_arg, |
791 | const char *, int flag_args, |
792 | ptrdiff_t off, size_t size, CMD_LINE getopt, |
793 | enum charset_enum is_os_charset_arg, |
794 | const char *def_val, size_t max_length_arg, |
795 | on_check_function on_check_func=0, |
796 | on_update_function on_update_func=0) |
797 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
798 | getopt.arg_type, SHOW_CHAR, (intptr)def_val, |
799 | 0, VARIABLE_NOT_IN_BINLOG, on_check_func, on_update_func, |
800 | 0),max_length(max_length_arg) |
801 | { |
802 | option.var_type|= GET_STR; |
803 | SYSVAR_ASSERT(scope() == ONLY_SESSION) |
804 | *const_cast<SHOW_TYPE*>(&show_val_type)= SHOW_LEX_STRING; |
805 | } |
806 | bool do_check(THD *thd, set_var *var) |
807 | { |
808 | char buff[STRING_BUFFER_USUAL_SIZE]; |
809 | String str(buff, sizeof(buff), system_charset_info), *res; |
810 | |
811 | if (!(res=var->value->val_str(&str))) |
812 | { |
813 | var->save_result.string_value.str= 0; /* NULL */ |
814 | var->save_result.string_value.length= 0; |
815 | } |
816 | else |
817 | { |
818 | if (res->length() > max_length) |
819 | { |
820 | my_error(ER_WRONG_STRING_LENGTH, MYF(0), |
821 | res->ptr(), name.str, (int) max_length); |
822 | return true; |
823 | } |
824 | var->save_result.string_value.str= thd->strmake(res->ptr(), |
825 | res->length()); |
826 | var->save_result.string_value.length= res->length(); |
827 | } |
828 | return false; |
829 | } |
830 | bool session_update(THD *thd, set_var *var) |
831 | { |
832 | LEX_CSTRING *tmp= &session_var(thd, LEX_CSTRING); |
833 | tmp->length= var->save_result.string_value.length; |
834 | /* Store as \0 terminated string (just to be safe) */ |
835 | strmake((char*) tmp->str, var->save_result.string_value.str, tmp->length); |
836 | return false; |
837 | } |
838 | bool global_update(THD *thd, set_var *var) |
839 | { |
840 | DBUG_ASSERT(FALSE); |
841 | return false; |
842 | } |
843 | void session_save_default(THD *thd, set_var *var) |
844 | { |
845 | char *ptr= (char*)(intptr)option.def_value; |
846 | var->save_result.string_value.str= ptr; |
847 | var->save_result.string_value.length= strlen(ptr); |
848 | } |
849 | void global_save_default(THD *thd, set_var *var) |
850 | { |
851 | DBUG_ASSERT(FALSE); |
852 | } |
853 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
854 | { |
855 | DBUG_ASSERT(FALSE); |
856 | return NULL; |
857 | } |
858 | }; |
859 | |
860 | |
861 | #ifndef DBUG_OFF |
862 | /** |
863 | @@session.debug_dbug and @@global.debug_dbug variables. |
864 | |
865 | @@dbug variable differs from other variables in one aspect: |
866 | if its value is not assigned in the session, it "points" to the global |
867 | value, and so when the global value is changed, the change |
868 | immediately takes effect in the session. |
869 | |
870 | This semantics is intentional, to be able to debug one session from |
871 | another. |
872 | */ |
873 | class Sys_var_dbug: public sys_var |
874 | { |
875 | public: |
876 | Sys_var_dbug(const char *name_arg, |
877 | const char *comment, int flag_args, |
878 | CMD_LINE getopt, |
879 | const char *def_val, PolyLock *lock=0, |
880 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
881 | on_check_function on_check_func=0, |
882 | on_update_function on_update_func=0, |
883 | const char *substitute=0) |
884 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, |
885 | (char*)¤t_dbug_option-(char*)&global_system_variables, getopt.id, |
886 | getopt.arg_type, SHOW_CHAR, (intptr)def_val, |
887 | lock, binlog_status_arg, on_check_func, on_update_func, |
888 | substitute) |
889 | { option.var_type|= GET_STR; } |
890 | bool do_check(THD *thd, set_var *var) |
891 | { |
892 | char buff[STRING_BUFFER_USUAL_SIZE]; |
893 | String str(buff, sizeof(buff), system_charset_info), *res; |
894 | |
895 | if (!(res=var->value->val_str(&str))) |
896 | var->save_result.string_value.str= const_cast<char*>("" ); |
897 | else |
898 | var->save_result.string_value.str= thd->strmake(res->ptr(), res->length()); |
899 | return false; |
900 | } |
901 | bool session_update(THD *thd, set_var *var) |
902 | { |
903 | const char *val= var->save_result.string_value.str; |
904 | if (!var->value) |
905 | DBUG_POP(); |
906 | else |
907 | DBUG_SET(val); |
908 | return false; |
909 | } |
910 | bool global_update(THD *thd, set_var *var) |
911 | { |
912 | const char *val= var->save_result.string_value.str; |
913 | DBUG_SET_INITIAL(val); |
914 | return false; |
915 | } |
916 | void session_save_default(THD *thd, set_var *var) |
917 | { } |
918 | void global_save_default(THD *thd, set_var *var) |
919 | { |
920 | char *ptr= (char*)(intptr)option.def_value; |
921 | var->save_result.string_value.str= ptr; |
922 | } |
923 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
924 | { |
925 | char buf[256]; |
926 | DBUG_EXPLAIN(buf, sizeof(buf)); |
927 | return (uchar*) thd->strdup(buf); |
928 | } |
929 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
930 | { |
931 | char buf[256]; |
932 | DBUG_EXPLAIN_INITIAL(buf, sizeof(buf)); |
933 | return (uchar*) thd->strdup(buf); |
934 | } |
935 | uchar *default_value_ptr(THD *thd) |
936 | { return (uchar*)"" ; } |
937 | }; |
938 | #endif |
939 | |
940 | #define KEYCACHE_VAR(X) GLOBAL_VAR(dflt_key_cache_var.X) |
941 | #define keycache_var_ptr(KC, OFF) (((uchar*)(KC))+(OFF)) |
942 | #define keycache_var(KC, OFF) (*(ulonglong*)keycache_var_ptr(KC, OFF)) |
943 | typedef bool (*keycache_update_function)(THD *, KEY_CACHE *, ptrdiff_t, ulonglong); |
944 | |
945 | /** |
946 | The class for keycache_* variables. Supports structured names, |
947 | keycache_name.variable_name. |
948 | |
949 | Class specific constructor arguments: |
950 | everything derived from Sys_var_ulonglong |
951 | |
952 | Backing store: ulonglong |
953 | |
954 | @note these variables can be only GLOBAL |
955 | */ |
956 | class Sys_var_keycache: public Sys_var_ulonglong |
957 | { |
958 | keycache_update_function keycache_update; |
959 | public: |
960 | Sys_var_keycache(const char *name_arg, |
961 | const char *, int flag_args, ptrdiff_t off, size_t size, |
962 | CMD_LINE getopt, |
963 | ulonglong min_val, ulonglong max_val, ulonglong def_val, |
964 | uint block_size, PolyLock *lock, |
965 | enum binlog_status_enum binlog_status_arg, |
966 | on_check_function on_check_func, |
967 | keycache_update_function on_update_func, |
968 | const char *substitute=0) |
969 | : Sys_var_ulonglong(name_arg, comment, flag_args, off, size, |
970 | getopt, min_val, max_val, def_val, |
971 | block_size, lock, binlog_status_arg, on_check_func, 0, |
972 | substitute), |
973 | keycache_update(on_update_func) |
974 | { |
975 | option.var_type|= GET_ASK_ADDR; |
976 | option.value= (uchar**)1; // crash me, please |
977 | // fix an offset from global_system_variables to be an offset in KEY_CACHE |
978 | offset= global_var_ptr() - (uchar*)dflt_key_cache; |
979 | SYSVAR_ASSERT(scope() == GLOBAL); |
980 | } |
981 | bool global_update(THD *thd, set_var *var) |
982 | { |
983 | ulonglong new_value= var->save_result.ulonglong_value; |
984 | LEX_CSTRING *base_name= &var->base; |
985 | KEY_CACHE *key_cache; |
986 | |
987 | /* If no basename, assume it's for the key cache named 'default' */ |
988 | if (!base_name->length) |
989 | base_name= &default_key_cache_base; |
990 | |
991 | key_cache= get_key_cache(base_name); |
992 | |
993 | if (!key_cache) |
994 | { // Key cache didn't exists */ |
995 | if (!new_value) // Tried to delete cache |
996 | return false; // Ok, nothing to do |
997 | if (!(key_cache= create_key_cache(base_name->str, base_name->length))) |
998 | return true; |
999 | } |
1000 | |
1001 | /** |
1002 | Abort if some other thread is changing the key cache |
1003 | @todo This should be changed so that we wait until the previous |
1004 | assignment is done and then do the new assign |
1005 | */ |
1006 | if (key_cache->in_init) |
1007 | return true; |
1008 | |
1009 | return keycache_update(thd, key_cache, offset, new_value); |
1010 | } |
1011 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
1012 | { |
1013 | KEY_CACHE *key_cache= get_key_cache(base); |
1014 | if (!key_cache) |
1015 | key_cache= &zero_key_cache; |
1016 | return keycache_var_ptr(key_cache, offset); |
1017 | } |
1018 | }; |
1019 | |
1020 | static bool update_buffer_size(THD *thd, KEY_CACHE *key_cache, |
1021 | ptrdiff_t offset, ulonglong new_value) |
1022 | { |
1023 | bool error= false; |
1024 | DBUG_ASSERT(offset == offsetof(KEY_CACHE, param_buff_size)); |
1025 | |
1026 | if (new_value == 0) |
1027 | { |
1028 | if (key_cache == dflt_key_cache) |
1029 | { |
1030 | my_error(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, MYF(0)); |
1031 | return true; |
1032 | } |
1033 | |
1034 | if (key_cache->key_cache_inited) // If initied |
1035 | { |
1036 | /* |
1037 | Move tables using this key cache to the default key cache |
1038 | and clear the old key cache. |
1039 | */ |
1040 | key_cache->in_init= 1; |
1041 | mysql_mutex_unlock(&LOCK_global_system_variables); |
1042 | key_cache->param_buff_size= 0; |
1043 | ha_resize_key_cache(key_cache); |
1044 | ha_change_key_cache(key_cache, dflt_key_cache); |
1045 | /* |
1046 | We don't delete the key cache as some running threads my still be in |
1047 | the key cache code with a pointer to the deleted (empty) key cache |
1048 | */ |
1049 | mysql_mutex_lock(&LOCK_global_system_variables); |
1050 | key_cache->in_init= 0; |
1051 | } |
1052 | return error; |
1053 | } |
1054 | |
1055 | key_cache->param_buff_size= new_value; |
1056 | |
1057 | /* If key cache didn't exist initialize it, else resize it */ |
1058 | key_cache->in_init= 1; |
1059 | mysql_mutex_unlock(&LOCK_global_system_variables); |
1060 | |
1061 | if (!key_cache->key_cache_inited) |
1062 | error= ha_init_key_cache(0, key_cache, 0); |
1063 | else |
1064 | error= ha_resize_key_cache(key_cache); |
1065 | |
1066 | mysql_mutex_lock(&LOCK_global_system_variables); |
1067 | key_cache->in_init= 0; |
1068 | |
1069 | return error; |
1070 | } |
1071 | |
1072 | static bool update_keycache(THD *thd, KEY_CACHE *key_cache, |
1073 | ptrdiff_t offset, ulonglong new_value, |
1074 | int (*func)(KEY_CACHE *)) |
1075 | { |
1076 | bool error= false; |
1077 | DBUG_ASSERT(offset != offsetof(KEY_CACHE, param_buff_size)); |
1078 | |
1079 | keycache_var(key_cache, offset)= new_value; |
1080 | |
1081 | key_cache->in_init= 1; |
1082 | mysql_mutex_unlock(&LOCK_global_system_variables); |
1083 | error= func(key_cache); |
1084 | mysql_mutex_lock(&LOCK_global_system_variables); |
1085 | key_cache->in_init= 0; |
1086 | |
1087 | return error; |
1088 | } |
1089 | |
1090 | static bool resize_keycache(THD *thd, KEY_CACHE *key_cache, |
1091 | ptrdiff_t offset, ulonglong new_value) |
1092 | { |
1093 | return update_keycache(thd, key_cache, offset, new_value, |
1094 | ha_resize_key_cache); |
1095 | } |
1096 | |
1097 | static bool change_keycache_param(THD *thd, KEY_CACHE *key_cache, |
1098 | ptrdiff_t offset, ulonglong new_value) |
1099 | { |
1100 | return update_keycache(thd, key_cache, offset, new_value, |
1101 | ha_change_key_cache_param); |
1102 | } |
1103 | |
1104 | static bool repartition_keycache(THD *thd, KEY_CACHE *key_cache, |
1105 | ptrdiff_t offset, ulonglong new_value) |
1106 | { |
1107 | return update_keycache(thd, key_cache, offset, new_value, |
1108 | ha_repartition_key_cache); |
1109 | } |
1110 | |
1111 | |
1112 | /** |
1113 | The class for floating point variables |
1114 | |
1115 | Class specific constructor arguments: min, max |
1116 | |
1117 | Backing store: double |
1118 | */ |
1119 | class Sys_var_double: public sys_var |
1120 | { |
1121 | public: |
1122 | Sys_var_double(const char *name_arg, |
1123 | const char *, int flag_args, ptrdiff_t off, size_t size, |
1124 | CMD_LINE getopt, |
1125 | double min_val, double max_val, double def_val, PolyLock *lock=0, |
1126 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
1127 | on_check_function on_check_func=0, |
1128 | on_update_function on_update_func=0, |
1129 | const char *substitute=0) |
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) |
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 | SYSVAR_ASSERT(min_val < max_val); |
1141 | SYSVAR_ASSERT(min_val <= def_val); |
1142 | SYSVAR_ASSERT(max_val >= def_val); |
1143 | SYSVAR_ASSERT(size == sizeof(double)); |
1144 | } |
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 | } |
1153 | bool session_update(THD *thd, set_var *var) |
1154 | { |
1155 | session_var(thd, double)= var->save_result.double_value; |
1156 | return false; |
1157 | } |
1158 | bool global_update(THD *thd, set_var *var) |
1159 | { |
1160 | global_var(double)= var->save_result.double_value; |
1161 | return false; |
1162 | } |
1163 | void session_save_default(THD *thd, set_var *var) |
1164 | { var->save_result.double_value= global_var(double); } |
1165 | void global_save_default(THD *thd, set_var *var) |
1166 | { var->save_result.double_value= getopt_ulonglong2double(option.def_value); } |
1167 | }; |
1168 | |
1169 | /** |
1170 | The class for the @max_user_connections. |
1171 | It's derived from Sys_var_uint, but non-standard session value |
1172 | requires a new class. |
1173 | |
1174 | Class specific constructor arguments: |
1175 | everything derived from Sys_var_uint |
1176 | |
1177 | Backing store: uint |
1178 | */ |
1179 | class Sys_var_max_user_conn: public Sys_var_int |
1180 | { |
1181 | public: |
1182 | Sys_var_max_user_conn(const char *name_arg, |
1183 | const char *, int flag_args, ptrdiff_t off, size_t size, |
1184 | CMD_LINE getopt, |
1185 | int min_val, int max_val, int def_val, |
1186 | uint block_size, PolyLock *lock=0, |
1187 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
1188 | on_check_function on_check_func=0, |
1189 | on_update_function on_update_func=0, |
1190 | const char *substitute=0) |
1191 | : Sys_var_int(name_arg, comment, SESSION, off, size, getopt, |
1192 | min_val, max_val, def_val, block_size, |
1193 | lock, binlog_status_arg, on_check_func, on_update_func, |
1194 | substitute) |
1195 | { } |
1196 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
1197 | { |
1198 | if (thd->user_connect && thd->user_connect->user_resources.user_conn) |
1199 | return (uchar*) &(thd->user_connect->user_resources.user_conn); |
1200 | return global_value_ptr(thd, base); |
1201 | } |
1202 | }; |
1203 | |
1204 | /** |
1205 | The class for flagset variables - a variant of SET that allows in-place |
1206 | editing (turning on/off individual bits). String representations looks like |
1207 | a "flag=val,flag=val,...". Example: @@optimizer_switch |
1208 | |
1209 | Class specific constructor arguments: |
1210 | char* values[] - 0-terminated list of strings of valid values |
1211 | |
1212 | Backing store: ulonglong |
1213 | |
1214 | @note |
1215 | the last value in the values[] array should |
1216 | *always* be the string "default". |
1217 | */ |
1218 | class Sys_var_flagset: public Sys_var_typelib |
1219 | { |
1220 | public: |
1221 | Sys_var_flagset(const char *name_arg, |
1222 | const char *, int flag_args, ptrdiff_t off, size_t size, |
1223 | CMD_LINE getopt, |
1224 | const char *values[], ulonglong def_val, PolyLock *lock=0, |
1225 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
1226 | on_check_function on_check_func=0, |
1227 | on_update_function on_update_func=0, |
1228 | const char *substitute=0) |
1229 | : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, |
1230 | SHOW_CHAR, values, def_val, lock, |
1231 | binlog_status_arg, on_check_func, on_update_func, |
1232 | substitute) |
1233 | { |
1234 | option.var_type|= GET_FLAGSET; |
1235 | global_var(ulonglong)= def_val; |
1236 | SYSVAR_ASSERT(typelib.count > 1); |
1237 | SYSVAR_ASSERT(typelib.count <= 65); |
1238 | SYSVAR_ASSERT(def_val <= my_set_bits(typelib.count-1)); |
1239 | SYSVAR_ASSERT(strcmp(values[typelib.count-1], "default" ) == 0); |
1240 | SYSVAR_ASSERT(size == sizeof(ulonglong)); |
1241 | } |
1242 | bool do_check(THD *thd, set_var *var) |
1243 | { |
1244 | char buff[STRING_BUFFER_USUAL_SIZE]; |
1245 | String str(buff, sizeof(buff), system_charset_info), *res; |
1246 | ulonglong default_value, current_value; |
1247 | if (var->type == OPT_GLOBAL) |
1248 | { |
1249 | default_value= option.def_value; |
1250 | current_value= global_var(ulonglong); |
1251 | } |
1252 | else |
1253 | { |
1254 | default_value= global_var(ulonglong); |
1255 | current_value= session_var(thd, ulonglong); |
1256 | } |
1257 | |
1258 | if (var->value->result_type() == STRING_RESULT) |
1259 | { |
1260 | if (!(res=var->value->val_str(&str))) |
1261 | return true; |
1262 | else |
1263 | { |
1264 | char *error; |
1265 | uint error_len; |
1266 | |
1267 | var->save_result.ulonglong_value= |
1268 | find_set_from_flags(&typelib, |
1269 | typelib.count, |
1270 | current_value, |
1271 | default_value, |
1272 | res->ptr(), res->length(), |
1273 | &error, &error_len); |
1274 | if (unlikely(error)) |
1275 | { |
1276 | ErrConvString err(error, error_len, res->charset()); |
1277 | my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr()); |
1278 | return true; |
1279 | } |
1280 | } |
1281 | } |
1282 | else |
1283 | { |
1284 | longlong tmp=var->value->val_int(); |
1285 | if ((tmp < 0 && ! var->value->unsigned_flag) |
1286 | || (ulonglong)tmp > my_set_bits(typelib.count)) |
1287 | return true; |
1288 | else |
1289 | var->save_result.ulonglong_value= tmp; |
1290 | } |
1291 | |
1292 | return false; |
1293 | } |
1294 | bool session_update(THD *thd, set_var *var) |
1295 | { |
1296 | session_var(thd, ulonglong)= var->save_result.ulonglong_value; |
1297 | return false; |
1298 | } |
1299 | bool global_update(THD *thd, set_var *var) |
1300 | { |
1301 | global_var(ulonglong)= var->save_result.ulonglong_value; |
1302 | return false; |
1303 | } |
1304 | void session_save_default(THD *thd, set_var *var) |
1305 | { var->save_result.ulonglong_value= global_var(ulonglong); } |
1306 | void global_save_default(THD *thd, set_var *var) |
1307 | { var->save_result.ulonglong_value= option.def_value; } |
1308 | uchar *valptr(THD *thd, ulonglong val) |
1309 | { return (uchar*)flagset_to_string(thd, 0, val, typelib.type_names); } |
1310 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
1311 | { return valptr(thd, session_var(thd, ulonglong)); } |
1312 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
1313 | { return valptr(thd, global_var(ulonglong)); } |
1314 | uchar *default_value_ptr(THD *thd) |
1315 | { return valptr(thd, option.def_value); } |
1316 | }; |
1317 | |
1318 | /** |
1319 | The class for SET variables - variables taking zero or more values |
1320 | from the given list. Example: @@sql_mode |
1321 | |
1322 | Class specific constructor arguments: |
1323 | char* values[] - 0-terminated list of strings of valid values |
1324 | |
1325 | Backing store: ulonglong |
1326 | */ |
1327 | class Sys_var_set: public Sys_var_typelib |
1328 | { |
1329 | public: |
1330 | Sys_var_set(const char *name_arg, |
1331 | const char *, int flag_args, ptrdiff_t off, size_t size, |
1332 | CMD_LINE getopt, |
1333 | const char *values[], ulonglong def_val, PolyLock *lock=0, |
1334 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
1335 | on_check_function on_check_func=0, |
1336 | on_update_function on_update_func=0, |
1337 | const char *substitute=0) |
1338 | : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, |
1339 | SHOW_CHAR, values, def_val, lock, |
1340 | binlog_status_arg, on_check_func, on_update_func, |
1341 | substitute) |
1342 | { |
1343 | option.var_type|= GET_SET; |
1344 | global_var(ulonglong)= def_val; |
1345 | SYSVAR_ASSERT(typelib.count > 0); |
1346 | SYSVAR_ASSERT(typelib.count <= 64); |
1347 | SYSVAR_ASSERT(def_val <= my_set_bits(typelib.count)); |
1348 | SYSVAR_ASSERT(size == sizeof(ulonglong)); |
1349 | } |
1350 | bool do_check(THD *thd, set_var *var) |
1351 | { |
1352 | char buff[STRING_BUFFER_USUAL_SIZE]; |
1353 | String str(buff, sizeof(buff), system_charset_info), *res; |
1354 | |
1355 | if (var->value->result_type() == STRING_RESULT) |
1356 | { |
1357 | if (!(res=var->value->val_str_ascii(&str))) |
1358 | return true; |
1359 | else |
1360 | { |
1361 | char *error; |
1362 | uint error_len; |
1363 | bool not_used; |
1364 | |
1365 | var->save_result.ulonglong_value= |
1366 | find_set(&typelib, res->ptr(), res->length(), NULL, |
1367 | &error, &error_len, ¬_used); |
1368 | /* |
1369 | note, we only issue an error if error_len > 0. |
1370 | That is even while empty (zero-length) values are considered |
1371 | errors by find_set(), these errors are ignored here |
1372 | */ |
1373 | if (unlikely(error_len)) |
1374 | { |
1375 | ErrConvString err(error, error_len, res->charset()); |
1376 | my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr()); |
1377 | return true; |
1378 | } |
1379 | } |
1380 | } |
1381 | else |
1382 | { |
1383 | longlong tmp=var->value->val_int(); |
1384 | if ((tmp < 0 && ! var->value->unsigned_flag) |
1385 | || (ulonglong)tmp > my_set_bits(typelib.count)) |
1386 | return true; |
1387 | else |
1388 | var->save_result.ulonglong_value= tmp; |
1389 | } |
1390 | |
1391 | return false; |
1392 | } |
1393 | bool session_update(THD *thd, set_var *var) |
1394 | { |
1395 | session_var(thd, ulonglong)= var->save_result.ulonglong_value; |
1396 | return false; |
1397 | } |
1398 | bool global_update(THD *thd, set_var *var) |
1399 | { |
1400 | global_var(ulonglong)= var->save_result.ulonglong_value; |
1401 | return false; |
1402 | } |
1403 | void session_save_default(THD *thd, set_var *var) |
1404 | { var->save_result.ulonglong_value= global_var(ulonglong); } |
1405 | void global_save_default(THD *thd, set_var *var) |
1406 | { var->save_result.ulonglong_value= option.def_value; } |
1407 | uchar *valptr(THD *thd, ulonglong val) |
1408 | { return (uchar*)set_to_string(thd, 0, val, typelib.type_names); } |
1409 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
1410 | { return valptr(thd, session_var(thd, ulonglong)); } |
1411 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
1412 | { return valptr(thd, global_var(ulonglong)); } |
1413 | uchar *default_value_ptr(THD *thd) |
1414 | { return valptr(thd, option.def_value); } |
1415 | }; |
1416 | |
1417 | /** |
1418 | The class for variables which value is a plugin. |
1419 | Example: @@default_storage_engine |
1420 | |
1421 | Class specific constructor arguments: |
1422 | int plugin_type_arg (for example MYSQL_STORAGE_ENGINE_PLUGIN) |
1423 | |
1424 | Backing store: plugin_ref |
1425 | |
1426 | @note |
1427 | these variables don't support command-line equivalents, any such |
1428 | command-line options should be added manually to my_long_options in mysqld.cc |
1429 | */ |
1430 | class Sys_var_plugin: public sys_var |
1431 | { |
1432 | int plugin_type; |
1433 | public: |
1434 | Sys_var_plugin(const char *name_arg, |
1435 | const char *, int flag_args, ptrdiff_t off, size_t size, |
1436 | CMD_LINE getopt, |
1437 | int plugin_type_arg, char **def_val, PolyLock *lock=0, |
1438 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
1439 | on_check_function on_check_func=0, |
1440 | on_update_function on_update_func=0, |
1441 | const char *substitute=0) |
1442 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
1443 | getopt.arg_type, SHOW_CHAR, (intptr)def_val, |
1444 | lock, binlog_status_arg, on_check_func, on_update_func, |
1445 | substitute), |
1446 | plugin_type(plugin_type_arg) |
1447 | { |
1448 | option.var_type|= GET_STR; |
1449 | SYSVAR_ASSERT(size == sizeof(plugin_ref)); |
1450 | SYSVAR_ASSERT(getopt.id < 0); // force NO_CMD_LINE |
1451 | } |
1452 | bool do_check(THD *thd, set_var *var) |
1453 | { |
1454 | char buff[STRING_BUFFER_USUAL_SIZE]; |
1455 | String str(buff,sizeof(buff), system_charset_info), *res; |
1456 | if (!(res=var->value->val_str(&str))) |
1457 | var->save_result.plugin= NULL; |
1458 | else |
1459 | { |
1460 | const LEX_CSTRING pname= { const_cast<char*>(res->ptr()), res->length() }; |
1461 | plugin_ref plugin; |
1462 | |
1463 | // special code for storage engines (e.g. to handle historical aliases) |
1464 | if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN) |
1465 | plugin= ha_resolve_by_name(thd, &pname, false); |
1466 | else |
1467 | plugin= my_plugin_lock_by_name(thd, &pname, plugin_type); |
1468 | if (unlikely(!plugin)) |
1469 | { |
1470 | // historically different error code |
1471 | if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN) |
1472 | { |
1473 | ErrConvString err(res); |
1474 | my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr()); |
1475 | } |
1476 | return true; |
1477 | } |
1478 | var->save_result.plugin= plugin; |
1479 | } |
1480 | return false; |
1481 | } |
1482 | void do_update(plugin_ref *valptr, plugin_ref newval) |
1483 | { |
1484 | plugin_ref oldval= *valptr; |
1485 | if (oldval != newval) |
1486 | { |
1487 | *valptr= newval ? my_plugin_lock(NULL, newval) : 0; |
1488 | plugin_unlock(NULL, oldval); |
1489 | } |
1490 | } |
1491 | bool session_update(THD *thd, set_var *var) |
1492 | { |
1493 | do_update((plugin_ref*)session_var_ptr(thd), |
1494 | var->save_result.plugin); |
1495 | return false; |
1496 | } |
1497 | bool global_update(THD *thd, set_var *var) |
1498 | { |
1499 | do_update((plugin_ref*)global_var_ptr(), |
1500 | var->save_result.plugin); |
1501 | return false; |
1502 | } |
1503 | void session_save_default(THD *thd, set_var *var) |
1504 | { |
1505 | plugin_ref plugin= global_var(plugin_ref); |
1506 | var->save_result.plugin= plugin ? my_plugin_lock(thd, plugin) : 0; |
1507 | } |
1508 | plugin_ref get_default(THD *thd) |
1509 | { |
1510 | char *default_value= *reinterpret_cast<char**>(option.def_value); |
1511 | if (!default_value) |
1512 | return 0; |
1513 | |
1514 | LEX_CSTRING pname= { default_value, strlen(default_value) }; |
1515 | plugin_ref plugin; |
1516 | |
1517 | if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN) |
1518 | plugin= ha_resolve_by_name(thd, &pname, false); |
1519 | else |
1520 | plugin= my_plugin_lock_by_name(thd, &pname, plugin_type); |
1521 | DBUG_ASSERT(plugin); |
1522 | return my_plugin_lock(thd, plugin); |
1523 | } |
1524 | |
1525 | void global_save_default(THD *thd, set_var *var) |
1526 | { |
1527 | var->save_result.plugin= get_default(thd); |
1528 | } |
1529 | |
1530 | uchar *valptr(THD *thd, plugin_ref plugin) |
1531 | { |
1532 | return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str, |
1533 | plugin_name(plugin)->length) : 0); |
1534 | } |
1535 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
1536 | { return valptr(thd, session_var(thd, plugin_ref)); } |
1537 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
1538 | { return valptr(thd, global_var(plugin_ref)); } |
1539 | uchar *default_value_ptr(THD *thd) |
1540 | { return valptr(thd, get_default(thd)); } |
1541 | }; |
1542 | |
1543 | /** |
1544 | Class for variables that containg a list of plugins. |
1545 | Currently this is used only for @@gtid_pos_auto_create_engines |
1546 | |
1547 | Backing store: plugin_ref |
1548 | |
1549 | @note |
1550 | Currently this is only used for storage engine type plugins, and thus only |
1551 | storage engine type plugin is implemented. It could be extended to other |
1552 | plugin types later if needed, similar to Sys_var_plugin. |
1553 | |
1554 | These variables don't support command-line equivalents, any such |
1555 | command-line options should be added manually to my_long_options in mysqld.cc |
1556 | |
1557 | Note on lifetimes of resources allocated: We allocate a zero-terminated array |
1558 | of plugin_ref*, and lock the contained plugins. The list in the global |
1559 | variable must be freed (with free_engine_list()). However, the way Sys_var |
1560 | works, there is no place to explicitly free other lists, like the one |
1561 | returned from get_default(). |
1562 | |
1563 | Therefore, the code needs to work with temporary lists, which are |
1564 | registered in the THD to be automatically freed (and plugins similarly |
1565 | automatically unlocked). This is why do_check() allocates a temporary |
1566 | list, from which do_update() then makes a permanent copy. |
1567 | */ |
1568 | class Sys_var_pluginlist: public sys_var |
1569 | { |
1570 | public: |
1571 | Sys_var_pluginlist(const char *name_arg, |
1572 | const char *, int flag_args, ptrdiff_t off, size_t size, |
1573 | CMD_LINE getopt, |
1574 | char **def_val, PolyLock *lock=0, |
1575 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
1576 | on_check_function on_check_func=0, |
1577 | on_update_function on_update_func=0, |
1578 | const char *substitute=0) |
1579 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
1580 | getopt.arg_type, SHOW_CHAR, (intptr)def_val, |
1581 | lock, binlog_status_arg, on_check_func, on_update_func, |
1582 | substitute) |
1583 | { |
1584 | option.var_type|= GET_STR; |
1585 | SYSVAR_ASSERT(size == sizeof(plugin_ref)); |
1586 | SYSVAR_ASSERT(getopt.id < 0); // force NO_CMD_LINE |
1587 | } |
1588 | bool do_check(THD *thd, set_var *var) |
1589 | { |
1590 | char buff[STRING_BUFFER_USUAL_SIZE]; |
1591 | String str(buff,sizeof(buff), system_charset_info), *res; |
1592 | plugin_ref *plugins; |
1593 | |
1594 | if (!(res=var->value->val_str(&str))) |
1595 | plugins= resolve_engine_list(thd, "" , 0, true, true); |
1596 | else |
1597 | plugins= resolve_engine_list(thd, res->ptr(), res->length(), true, true); |
1598 | if (!plugins) |
1599 | return true; |
1600 | var->save_result.plugins= plugins; |
1601 | return false; |
1602 | } |
1603 | void do_update(plugin_ref **valptr, plugin_ref* newval) |
1604 | { |
1605 | plugin_ref *oldval= *valptr; |
1606 | *valptr= copy_engine_list(newval); |
1607 | free_engine_list(oldval); |
1608 | } |
1609 | bool session_update(THD *thd, set_var *var) |
1610 | { |
1611 | do_update((plugin_ref**)session_var_ptr(thd), |
1612 | var->save_result.plugins); |
1613 | return false; |
1614 | } |
1615 | bool global_update(THD *thd, set_var *var) |
1616 | { |
1617 | do_update((plugin_ref**)global_var_ptr(), |
1618 | var->save_result.plugins); |
1619 | return false; |
1620 | } |
1621 | void session_save_default(THD *thd, set_var *var) |
1622 | { |
1623 | plugin_ref* plugins= global_var(plugin_ref *); |
1624 | var->save_result.plugins= plugins ? temp_copy_engine_list(thd, plugins) : 0; |
1625 | } |
1626 | plugin_ref *get_default(THD *thd) |
1627 | { |
1628 | char *default_value= *reinterpret_cast<char**>(option.def_value); |
1629 | if (!default_value) |
1630 | return 0; |
1631 | return resolve_engine_list(thd, default_value, strlen(default_value), |
1632 | false, true); |
1633 | } |
1634 | |
1635 | void global_save_default(THD *thd, set_var *var) |
1636 | { |
1637 | var->save_result.plugins= get_default(thd); |
1638 | } |
1639 | |
1640 | uchar *valptr(THD *thd, plugin_ref *plugins) |
1641 | { |
1642 | return (uchar*)pretty_print_engine_list(thd, plugins); |
1643 | } |
1644 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
1645 | { return valptr(thd, session_var(thd, plugin_ref*)); } |
1646 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
1647 | { return valptr(thd, global_var(plugin_ref*)); } |
1648 | uchar *default_value_ptr(THD *thd) |
1649 | { return valptr(thd, get_default(thd)); } |
1650 | }; |
1651 | |
1652 | #if defined(ENABLED_DEBUG_SYNC) |
1653 | |
1654 | #include "debug_sync.h" |
1655 | |
1656 | /** |
1657 | The class for @@debug_sync session-only variable |
1658 | */ |
1659 | class Sys_var_debug_sync :public sys_var |
1660 | { |
1661 | public: |
1662 | Sys_var_debug_sync(const char *name_arg, |
1663 | const char *comment, int flag_args, |
1664 | CMD_LINE getopt, |
1665 | const char *def_val, PolyLock *lock=0, |
1666 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
1667 | on_check_function on_check_func=0, |
1668 | on_update_function on_update_func=0, |
1669 | const char *substitute=0) |
1670 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id, |
1671 | getopt.arg_type, SHOW_CHAR, (intptr)def_val, |
1672 | lock, binlog_status_arg, on_check_func, on_update_func, |
1673 | substitute) |
1674 | { |
1675 | SYSVAR_ASSERT(scope() == ONLY_SESSION); |
1676 | option.var_type|= GET_STR; |
1677 | } |
1678 | bool do_check(THD *thd, set_var *var) |
1679 | { |
1680 | char buff[STRING_BUFFER_USUAL_SIZE]; |
1681 | String str(buff, sizeof(buff), system_charset_info), *res; |
1682 | |
1683 | if (!(res=var->value->val_str(&str))) |
1684 | var->save_result.string_value= empty_lex_str; |
1685 | else |
1686 | { |
1687 | if (!thd->make_lex_string(&var->save_result.string_value, |
1688 | res->ptr(), res->length())) |
1689 | return true; |
1690 | } |
1691 | return false; |
1692 | } |
1693 | bool session_update(THD *thd, set_var *var) |
1694 | { |
1695 | return debug_sync_update(thd, var->save_result.string_value.str, |
1696 | var->save_result.string_value.length); |
1697 | } |
1698 | bool global_update(THD *thd, set_var *var) |
1699 | { |
1700 | DBUG_ASSERT(FALSE); |
1701 | return true; |
1702 | } |
1703 | void session_save_default(THD *thd, set_var *var) |
1704 | { |
1705 | var->save_result.string_value.str= const_cast<char*>("" ); |
1706 | var->save_result.string_value.length= 0; |
1707 | } |
1708 | void global_save_default(THD *thd, set_var *var) |
1709 | { |
1710 | DBUG_ASSERT(FALSE); |
1711 | } |
1712 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
1713 | { |
1714 | return debug_sync_value_ptr(thd); |
1715 | } |
1716 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
1717 | { |
1718 | DBUG_ASSERT(FALSE); |
1719 | return 0; |
1720 | } |
1721 | uchar *default_value_ptr(THD *thd) |
1722 | { return (uchar*)"" ; } |
1723 | }; |
1724 | #endif /* defined(ENABLED_DEBUG_SYNC) */ |
1725 | |
1726 | |
1727 | /** |
1728 | The class for bit variables - a variant of boolean that stores the value |
1729 | in a bit. |
1730 | |
1731 | Class specific constructor arguments: |
1732 | ulonglong bitmask_arg - the mask for the bit to set in the ulonglong |
1733 | backing store |
1734 | |
1735 | Backing store: ulonglong |
1736 | |
1737 | @note |
1738 | This class supports the "reverse" semantics, when the value of the bit |
1739 | being 0 corresponds to the value of variable being set. To activate it |
1740 | use REVERSE(bitmask) instead of simply bitmask in the constructor. |
1741 | |
1742 | @note |
1743 | variables of this class cannot be set from the command line as |
1744 | my_getopt does not support bits. |
1745 | */ |
1746 | class Sys_var_bit: public Sys_var_typelib |
1747 | { |
1748 | ulonglong bitmask; |
1749 | bool reverse_semantics; |
1750 | void set(uchar *ptr, ulonglong value) |
1751 | { |
1752 | if ((value != 0) ^ reverse_semantics) |
1753 | (*(ulonglong *)ptr)|= bitmask; |
1754 | else |
1755 | (*(ulonglong *)ptr)&= ~bitmask; |
1756 | } |
1757 | public: |
1758 | Sys_var_bit(const char *name_arg, |
1759 | const char *, int flag_args, ptrdiff_t off, size_t size, |
1760 | CMD_LINE getopt, |
1761 | ulonglong bitmask_arg, my_bool def_val, PolyLock *lock=0, |
1762 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
1763 | on_check_function on_check_func=0, |
1764 | on_update_function on_update_func=0, |
1765 | const char *substitute=0) |
1766 | : Sys_var_typelib(name_arg, comment, flag_args, off, getopt, |
1767 | SHOW_MY_BOOL, bool_values, def_val, lock, |
1768 | binlog_status_arg, on_check_func, on_update_func, |
1769 | substitute) |
1770 | { |
1771 | option.var_type|= GET_BIT; |
1772 | reverse_semantics= my_count_bits(bitmask_arg) > 1; |
1773 | bitmask= reverse_semantics ? ~bitmask_arg : bitmask_arg; |
1774 | option.block_size= reverse_semantics ? -(long) bitmask : (long)bitmask; |
1775 | set(global_var_ptr(), def_val); |
1776 | SYSVAR_ASSERT(def_val < 2); |
1777 | SYSVAR_ASSERT(size == sizeof(ulonglong)); |
1778 | } |
1779 | bool session_update(THD *thd, set_var *var) |
1780 | { |
1781 | set(session_var_ptr(thd), var->save_result.ulonglong_value); |
1782 | return false; |
1783 | } |
1784 | bool global_update(THD *thd, set_var *var) |
1785 | { |
1786 | set(global_var_ptr(), var->save_result.ulonglong_value); |
1787 | return false; |
1788 | } |
1789 | void session_save_default(THD *thd, set_var *var) |
1790 | { var->save_result.ulonglong_value= global_var(ulonglong) & bitmask; } |
1791 | void global_save_default(THD *thd, set_var *var) |
1792 | { var->save_result.ulonglong_value= option.def_value; } |
1793 | |
1794 | uchar *valptr(THD *thd, ulonglong val) |
1795 | { |
1796 | thd->sys_var_tmp.my_bool_value= reverse_semantics ^ ((val & bitmask) != 0); |
1797 | return (uchar*) &thd->sys_var_tmp.my_bool_value; |
1798 | } |
1799 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
1800 | { return valptr(thd, session_var(thd, ulonglong)); } |
1801 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
1802 | { return valptr(thd, global_var(ulonglong)); } |
1803 | uchar *default_value_ptr(THD *thd) |
1804 | { |
1805 | thd->sys_var_tmp.my_bool_value= option.def_value != 0; |
1806 | return (uchar*) &thd->sys_var_tmp.my_bool_value; |
1807 | } |
1808 | }; |
1809 | |
1810 | /** |
1811 | The class for variables that have a special meaning for a session, |
1812 | such as @@timestamp or @@rnd_seed1, their values typically cannot be read |
1813 | from SV structure, and a special "read" callback is provided. |
1814 | |
1815 | Class specific constructor arguments: |
1816 | everything derived from Sys_var_ulonglong |
1817 | session_special_read_function read_func_arg |
1818 | |
1819 | Backing store: ulonglong |
1820 | |
1821 | @note |
1822 | These variables are session-only, global or command-line equivalents |
1823 | are not supported as they're generally meaningless. |
1824 | */ |
1825 | class Sys_var_session_special: public Sys_var_ulonglong |
1826 | { |
1827 | typedef bool (*session_special_update_function)(THD *thd, set_var *var); |
1828 | typedef ulonglong (*session_special_read_function)(THD *thd); |
1829 | |
1830 | session_special_read_function read_func; |
1831 | session_special_update_function update_func; |
1832 | public: |
1833 | Sys_var_session_special(const char *name_arg, |
1834 | const char *, int flag_args, |
1835 | CMD_LINE getopt, |
1836 | ulonglong min_val, ulonglong max_val, uint block_size, |
1837 | PolyLock *lock, enum binlog_status_enum binlog_status_arg, |
1838 | on_check_function on_check_func, |
1839 | session_special_update_function update_func_arg, |
1840 | session_special_read_function read_func_arg, |
1841 | const char *substitute=0) |
1842 | : Sys_var_ulonglong(name_arg, comment, flag_args, 0, |
1843 | sizeof(ulonglong), getopt, min_val, |
1844 | max_val, 0, block_size, lock, binlog_status_arg, on_check_func, 0, |
1845 | substitute), |
1846 | read_func(read_func_arg), update_func(update_func_arg) |
1847 | { |
1848 | SYSVAR_ASSERT(scope() == ONLY_SESSION); |
1849 | SYSVAR_ASSERT(getopt.id < 0); // NO_CMD_LINE, because the offset is fake |
1850 | } |
1851 | bool session_update(THD *thd, set_var *var) |
1852 | { return update_func(thd, var); } |
1853 | bool global_update(THD *thd, set_var *var) |
1854 | { |
1855 | DBUG_ASSERT(FALSE); |
1856 | return true; |
1857 | } |
1858 | void session_save_default(THD *thd, set_var *var) |
1859 | { var->value= 0; } |
1860 | void global_save_default(THD *thd, set_var *var) |
1861 | { DBUG_ASSERT(FALSE); } |
1862 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
1863 | { |
1864 | thd->sys_var_tmp.ulonglong_value= read_func(thd); |
1865 | return (uchar*) &thd->sys_var_tmp.ulonglong_value; |
1866 | } |
1867 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
1868 | { |
1869 | DBUG_ASSERT(FALSE); |
1870 | return 0; |
1871 | } |
1872 | uchar *default_value_ptr(THD *thd) |
1873 | { |
1874 | thd->sys_var_tmp.ulonglong_value= 0; |
1875 | return (uchar*) &thd->sys_var_tmp.ulonglong_value; |
1876 | } |
1877 | }; |
1878 | |
1879 | |
1880 | /* |
1881 | Dedicated class because of a weird behavior of a default value. |
1882 | Assigning timestamp to itself |
1883 | |
1884 | SET @@timestamp = @@timestamp |
1885 | |
1886 | make it non-default and stops the time flow. |
1887 | */ |
1888 | class Sys_var_timestamp: public Sys_var_double |
1889 | { |
1890 | public: |
1891 | Sys_var_timestamp(const char *name_arg, |
1892 | const char *, int flag_args, |
1893 | CMD_LINE getopt, |
1894 | double min_val, double max_val, |
1895 | PolyLock *lock, enum binlog_status_enum binlog_status_arg, |
1896 | on_check_function on_check_func=0) |
1897 | : Sys_var_double(name_arg, comment, flag_args, 0, |
1898 | sizeof(double), getopt, min_val, |
1899 | max_val, 0, lock, binlog_status_arg, on_check_func) |
1900 | { |
1901 | SYSVAR_ASSERT(scope() == ONLY_SESSION); |
1902 | SYSVAR_ASSERT(getopt.id < 0); // NO_CMD_LINE, because the offset is fake |
1903 | } |
1904 | bool session_update(THD *thd, set_var *var) |
1905 | { |
1906 | if (var->value) |
1907 | { |
1908 | my_hrtime_t hrtime = { hrtime_from_time(var->save_result.double_value) }; |
1909 | thd->set_time(hrtime); |
1910 | } |
1911 | else // SET timestamp=DEFAULT |
1912 | thd->user_time.val= 0; |
1913 | return false; |
1914 | } |
1915 | bool global_update(THD *thd, set_var *var) |
1916 | { |
1917 | DBUG_ASSERT(FALSE); |
1918 | return true; |
1919 | } |
1920 | bool session_is_default(THD *thd) |
1921 | { |
1922 | return thd->user_time.val == 0; |
1923 | } |
1924 | void session_save_default(THD *thd, set_var *var) |
1925 | { var->value= 0; } |
1926 | void global_save_default(THD *thd, set_var *var) |
1927 | { DBUG_ASSERT(FALSE); } |
1928 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
1929 | { |
1930 | thd->sys_var_tmp.double_value= thd->start_time + |
1931 | thd->start_time_sec_part/(double)TIME_SECOND_PART_FACTOR; |
1932 | return (uchar*) &thd->sys_var_tmp.double_value; |
1933 | } |
1934 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
1935 | { |
1936 | DBUG_ASSERT(FALSE); |
1937 | return 0; |
1938 | } |
1939 | uchar *default_value_ptr(THD *thd) |
1940 | { |
1941 | thd->sys_var_tmp.double_value= 0; |
1942 | return (uchar*) &thd->sys_var_tmp.double_value; |
1943 | } |
1944 | }; |
1945 | |
1946 | |
1947 | /** |
1948 | The class for read-only variables that show whether a particular |
1949 | feature is supported by the server. Example: have_compression |
1950 | |
1951 | Backing store: enum SHOW_COMP_OPTION |
1952 | |
1953 | @note |
1954 | These variables are necessarily read-only, only global, and have no |
1955 | command-line equivalent. |
1956 | */ |
1957 | class Sys_var_have: public sys_var |
1958 | { |
1959 | public: |
1960 | Sys_var_have(const char *name_arg, |
1961 | const char *, int flag_args, ptrdiff_t off, size_t size, |
1962 | CMD_LINE getopt, |
1963 | PolyLock *lock=0, |
1964 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
1965 | on_check_function on_check_func=0, |
1966 | on_update_function on_update_func=0, |
1967 | const char *substitute=0) |
1968 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
1969 | getopt.arg_type, SHOW_CHAR, 0, |
1970 | lock, binlog_status_arg, on_check_func, on_update_func, |
1971 | substitute) |
1972 | { |
1973 | SYSVAR_ASSERT(scope() == GLOBAL); |
1974 | SYSVAR_ASSERT(getopt.id < 0); |
1975 | SYSVAR_ASSERT(lock == 0); |
1976 | SYSVAR_ASSERT(binlog_status_arg == VARIABLE_NOT_IN_BINLOG); |
1977 | SYSVAR_ASSERT(is_readonly()); |
1978 | SYSVAR_ASSERT(on_update == 0); |
1979 | SYSVAR_ASSERT(size == sizeof(enum SHOW_COMP_OPTION)); |
1980 | option.var_type|= GET_STR; |
1981 | } |
1982 | bool do_check(THD *thd, set_var *var) { |
1983 | DBUG_ASSERT(FALSE); |
1984 | return true; |
1985 | } |
1986 | bool session_update(THD *thd, set_var *var) |
1987 | { |
1988 | DBUG_ASSERT(FALSE); |
1989 | return true; |
1990 | } |
1991 | bool global_update(THD *thd, set_var *var) |
1992 | { |
1993 | DBUG_ASSERT(FALSE); |
1994 | return true; |
1995 | } |
1996 | void session_save_default(THD *thd, set_var *var) { } |
1997 | void global_save_default(THD *thd, set_var *var) { } |
1998 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
1999 | { |
2000 | DBUG_ASSERT(FALSE); |
2001 | return 0; |
2002 | } |
2003 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
2004 | { |
2005 | return (uchar*)show_comp_option_name[global_var(enum SHOW_COMP_OPTION)]; |
2006 | } |
2007 | }; |
2008 | |
2009 | /** |
2010 | Generic class for variables for storing entities that are internally |
2011 | represented as structures, have names, and possibly can be referred to by |
2012 | numbers. Examples: character sets, collations, locales, |
2013 | |
2014 | Class specific constructor arguments: |
2015 | ptrdiff_t name_offset - offset of the 'name' field in the structure |
2016 | |
2017 | Backing store: void* |
2018 | |
2019 | @note |
2020 | As every such a structure requires special treatment from my_getopt, |
2021 | these variables don't support command-line equivalents, any such |
2022 | command-line options should be added manually to my_long_options in mysqld.cc |
2023 | */ |
2024 | class Sys_var_struct: public sys_var |
2025 | { |
2026 | ptrdiff_t name_offset; // offset to the 'name' property in the structure |
2027 | public: |
2028 | Sys_var_struct(const char *name_arg, |
2029 | const char *, int flag_args, ptrdiff_t off, size_t size, |
2030 | CMD_LINE getopt, |
2031 | ptrdiff_t name_off, void *def_val, PolyLock *lock=0, |
2032 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
2033 | on_check_function on_check_func=0, |
2034 | on_update_function on_update_func=0, |
2035 | const char *substitute=0) |
2036 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
2037 | getopt.arg_type, SHOW_CHAR, (intptr)def_val, |
2038 | lock, binlog_status_arg, on_check_func, on_update_func, |
2039 | substitute), |
2040 | name_offset(name_off) |
2041 | { |
2042 | option.var_type|= GET_ENUM; // because we accept INT and STRING here |
2043 | /* |
2044 | struct variables are special on the command line - often (e.g. for |
2045 | charsets) the name cannot be immediately resolved, but only after all |
2046 | options (in particular, basedir) are parsed. |
2047 | |
2048 | thus all struct command-line options should be added manually |
2049 | to my_long_options in mysqld.cc |
2050 | */ |
2051 | SYSVAR_ASSERT(getopt.id < 0); |
2052 | SYSVAR_ASSERT(size == sizeof(void *)); |
2053 | } |
2054 | bool do_check(THD *thd, set_var *var) |
2055 | { return false; } |
2056 | bool session_update(THD *thd, set_var *var) |
2057 | { |
2058 | session_var(thd, const void*)= var->save_result.ptr; |
2059 | return false; |
2060 | } |
2061 | bool global_update(THD *thd, set_var *var) |
2062 | { |
2063 | global_var(const void*)= var->save_result.ptr; |
2064 | return false; |
2065 | } |
2066 | void session_save_default(THD *thd, set_var *var) |
2067 | { var->save_result.ptr= global_var(void*); } |
2068 | void global_save_default(THD *thd, set_var *var) |
2069 | { |
2070 | void **default_value= reinterpret_cast<void**>(option.def_value); |
2071 | var->save_result.ptr= *default_value; |
2072 | } |
2073 | uchar *valptr(THD *thd, uchar *val) |
2074 | { return val ? *(uchar**)(val+name_offset) : 0; } |
2075 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
2076 | { return valptr(thd, session_var(thd, uchar*)); } |
2077 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
2078 | { return valptr(thd, global_var(uchar*)); } |
2079 | uchar *default_value_ptr(THD *thd) |
2080 | { return valptr(thd, *(uchar**)option.def_value); } |
2081 | }; |
2082 | |
2083 | /** |
2084 | The class for variables that store time zones |
2085 | |
2086 | Backing store: Time_zone* |
2087 | |
2088 | @note |
2089 | Time zones cannot be supported directly by my_getopt, thus |
2090 | these variables don't support command-line equivalents, any such |
2091 | command-line options should be added manually to my_long_options in mysqld.cc |
2092 | */ |
2093 | class Sys_var_tz: public sys_var |
2094 | { |
2095 | public: |
2096 | Sys_var_tz(const char *name_arg, |
2097 | const char *, int flag_args, ptrdiff_t off, size_t size, |
2098 | CMD_LINE getopt, |
2099 | Time_zone **def_val, PolyLock *lock=0, |
2100 | enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, |
2101 | on_check_function on_check_func=0, |
2102 | on_update_function on_update_func=0, |
2103 | const char *substitute=0) |
2104 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
2105 | getopt.arg_type, SHOW_CHAR, (intptr)def_val, |
2106 | lock, binlog_status_arg, on_check_func, on_update_func, |
2107 | substitute) |
2108 | { |
2109 | SYSVAR_ASSERT(getopt.id < 0); |
2110 | SYSVAR_ASSERT(size == sizeof(Time_zone *)); |
2111 | option.var_type|= GET_STR; |
2112 | } |
2113 | bool do_check(THD *thd, set_var *var) |
2114 | { |
2115 | char buff[MAX_TIME_ZONE_NAME_LENGTH]; |
2116 | String str(buff, sizeof(buff), &my_charset_latin1); |
2117 | String *res= var->value->val_str(&str); |
2118 | |
2119 | if (!res) |
2120 | return true; |
2121 | |
2122 | if (!(var->save_result.time_zone= my_tz_find(thd, res))) |
2123 | { |
2124 | ErrConvString err(res); |
2125 | my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), err.ptr()); |
2126 | return true; |
2127 | } |
2128 | return false; |
2129 | } |
2130 | bool session_update(THD *thd, set_var *var) |
2131 | { |
2132 | session_var(thd, Time_zone*)= var->save_result.time_zone; |
2133 | return false; |
2134 | } |
2135 | bool global_update(THD *thd, set_var *var) |
2136 | { |
2137 | global_var(Time_zone*)= var->save_result.time_zone; |
2138 | return false; |
2139 | } |
2140 | void session_save_default(THD *thd, set_var *var) |
2141 | { |
2142 | var->save_result.time_zone= global_var(Time_zone*); |
2143 | } |
2144 | void global_save_default(THD *thd, set_var *var) |
2145 | { |
2146 | var->save_result.time_zone= |
2147 | *(Time_zone**)(intptr)option.def_value; |
2148 | } |
2149 | uchar *valptr(THD *thd, Time_zone *val) |
2150 | { return (uchar *)(val->get_name()->ptr()); } |
2151 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
2152 | { |
2153 | /* |
2154 | This is an ugly fix for replication: we don't replicate properly queries |
2155 | invoking system variables' values to update tables; but |
2156 | CONVERT_TZ(,,@@session.time_zone) is so popular that we make it |
2157 | replicable (i.e. we tell the binlog code to store the session |
2158 | timezone). If it's the global value which was used we can't replicate |
2159 | (binlog code stores session value only). |
2160 | */ |
2161 | thd->time_zone_used= 1; |
2162 | return valptr(thd, session_var(thd, Time_zone *)); |
2163 | } |
2164 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
2165 | { return valptr(thd, global_var(Time_zone*)); } |
2166 | uchar *default_value_ptr(THD *thd) |
2167 | { return valptr(thd, *(Time_zone**)option.def_value); } |
2168 | }; |
2169 | |
2170 | /** |
2171 | Special implementation for transaction isolation, that |
2172 | distingushes between |
2173 | |
2174 | SET GLOBAL TRANSACTION ISOLATION (stored in global_system_variables) |
2175 | SET SESSION TRANSACTION ISOLATION (stored in thd->variables) |
2176 | SET TRANSACTION ISOLATION (stored in thd->tx_isolation) |
2177 | |
2178 | where the last statement sets isolation level for the next transaction only |
2179 | */ |
2180 | class Sys_var_tx_isolation: public Sys_var_enum |
2181 | { |
2182 | public: |
2183 | Sys_var_tx_isolation(const char *name_arg, |
2184 | const char *, int flag_args, ptrdiff_t off, size_t size, |
2185 | CMD_LINE getopt, |
2186 | const char *values[], uint def_val, PolyLock *lock, |
2187 | enum binlog_status_enum binlog_status_arg, |
2188 | on_check_function on_check_func) |
2189 | :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt, |
2190 | values, def_val, lock, binlog_status_arg, on_check_func) |
2191 | {} |
2192 | bool session_update(THD *thd, set_var *var) |
2193 | { |
2194 | if (var->type == OPT_SESSION && Sys_var_enum::session_update(thd, var)) |
2195 | return TRUE; |
2196 | if (var->type == OPT_DEFAULT || !thd->in_active_multi_stmt_transaction()) |
2197 | { |
2198 | #ifndef EMBEDDED_LIBRARY |
2199 | Transaction_state_tracker *tst= NULL; |
2200 | |
2201 | if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) |
2202 | tst= (Transaction_state_tracker *) |
2203 | thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER); |
2204 | #endif //EMBEDDED_LIBRARY |
2205 | |
2206 | thd->tx_isolation= (enum_tx_isolation) var->save_result.ulonglong_value; |
2207 | |
2208 | #ifndef EMBEDDED_LIBRARY |
2209 | if (var->type == OPT_DEFAULT) |
2210 | { |
2211 | enum enum_tx_isol_level l; |
2212 | switch (thd->tx_isolation) { |
2213 | case ISO_READ_UNCOMMITTED: |
2214 | l= TX_ISOL_UNCOMMITTED; |
2215 | break; |
2216 | case ISO_READ_COMMITTED: |
2217 | l= TX_ISOL_COMMITTED; |
2218 | break; |
2219 | case ISO_REPEATABLE_READ: |
2220 | l= TX_ISOL_REPEATABLE; |
2221 | break; |
2222 | case ISO_SERIALIZABLE: |
2223 | l= TX_ISOL_SERIALIZABLE; |
2224 | break; |
2225 | default: |
2226 | DBUG_ASSERT(0); |
2227 | return TRUE; |
2228 | } |
2229 | if (tst) |
2230 | tst->set_isol_level(thd, l); |
2231 | } |
2232 | else if (tst) |
2233 | { |
2234 | tst->set_isol_level(thd, TX_ISOL_INHERIT); |
2235 | } |
2236 | #endif //EMBEDDED_LIBRARY |
2237 | } |
2238 | return FALSE; |
2239 | } |
2240 | }; |
2241 | |
2242 | |
2243 | /** |
2244 | Class representing the tx_read_only system variable for setting |
2245 | default transaction access mode. |
2246 | |
2247 | Note that there is a special syntax - SET TRANSACTION READ ONLY |
2248 | (or READ WRITE) that sets the access mode for the next transaction |
2249 | only. |
2250 | */ |
2251 | |
2252 | class Sys_var_tx_read_only: public Sys_var_mybool |
2253 | { |
2254 | public: |
2255 | Sys_var_tx_read_only(const char *name_arg, const char *, int flag_args, |
2256 | ptrdiff_t off, size_t size, CMD_LINE getopt, |
2257 | my_bool def_val, PolyLock *lock, |
2258 | enum binlog_status_enum binlog_status_arg, |
2259 | on_check_function on_check_func) |
2260 | :Sys_var_mybool(name_arg, comment, flag_args, off, size, getopt, |
2261 | def_val, lock, binlog_status_arg, on_check_func) |
2262 | {} |
2263 | virtual bool session_update(THD *thd, set_var *var); |
2264 | }; |
2265 | |
2266 | /* |
2267 | Class for replicate_events_marked_for_skip. |
2268 | We need a custom update function that ensures the slave is stopped when |
2269 | the update is happening. |
2270 | */ |
2271 | class Sys_var_replicate_events_marked_for_skip: public Sys_var_enum |
2272 | { |
2273 | public: |
2274 | Sys_var_replicate_events_marked_for_skip(const char *name_arg, |
2275 | const char *, int flag_args, ptrdiff_t off, size_t size, |
2276 | CMD_LINE getopt, |
2277 | const char *values[], uint def_val, PolyLock *lock= 0, |
2278 | enum binlog_status_enum binlog_status_arg= VARIABLE_NOT_IN_BINLOG) |
2279 | :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt, |
2280 | values, def_val, lock, binlog_status_arg) |
2281 | {} |
2282 | bool global_update(THD *thd, set_var *var); |
2283 | }; |
2284 | |
2285 | /* |
2286 | Class for handing multi-source replication variables |
2287 | Variable values are store in Master_info, but to make it possible to |
2288 | access variable without locks we also store it thd->variables. |
2289 | These can be used as GLOBAL or SESSION, but both points to the same |
2290 | variable. This is to make things compatible with MySQL 5.5 where variables |
2291 | like sql_slave_skip_counter are GLOBAL. |
2292 | */ |
2293 | |
2294 | #define MASTER_INFO_VAR(X) my_offsetof(Master_info, X), sizeof(((Master_info *)0x10)->X) |
2295 | class Sys_var_multi_source_ulonglong; |
2296 | class Master_info; |
2297 | |
2298 | typedef bool (*on_multi_source_update_function)(sys_var *self, THD *thd, |
2299 | Master_info *mi); |
2300 | bool update_multi_source_variable(sys_var *self, |
2301 | THD *thd, enum_var_type type); |
2302 | |
2303 | |
2304 | class Sys_var_multi_source_ulonglong :public Sys_var_ulonglong |
2305 | { |
2306 | ptrdiff_t master_info_offset; |
2307 | on_multi_source_update_function update_multi_source_variable_func; |
2308 | public: |
2309 | Sys_var_multi_source_ulonglong(const char *name_arg, |
2310 | const char *, int flag_args, |
2311 | ptrdiff_t off, size_t size, |
2312 | CMD_LINE getopt, |
2313 | ptrdiff_t master_info_offset_arg, |
2314 | size_t master_info_arg_size, |
2315 | ulonglong min_val, ulonglong max_val, |
2316 | ulonglong def_val, uint block_size, |
2317 | on_multi_source_update_function on_update_func) |
2318 | :Sys_var_ulonglong(name_arg, comment, flag_args, off, size, |
2319 | getopt, min_val, max_val, def_val, block_size, |
2320 | 0, VARIABLE_NOT_IN_BINLOG, 0, update_multi_source_variable), |
2321 | master_info_offset(master_info_offset_arg), |
2322 | update_multi_source_variable_func(on_update_func) |
2323 | { |
2324 | SYSVAR_ASSERT(master_info_arg_size == size); |
2325 | } |
2326 | bool global_update(THD *thd, set_var *var) |
2327 | { |
2328 | return session_update(thd, var); |
2329 | } |
2330 | void session_save_default(THD *thd, set_var *var) |
2331 | { |
2332 | /* Use value given in variable declaration */ |
2333 | global_save_default(thd, var); |
2334 | } |
2335 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
2336 | { |
2337 | ulonglong *tmp, res; |
2338 | tmp= (ulonglong*) (((uchar*)&(thd->variables)) + offset); |
2339 | res= get_master_info_ulonglong_value(thd, master_info_offset); |
2340 | *tmp= res; |
2341 | return (uchar*) tmp; |
2342 | } |
2343 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
2344 | { |
2345 | return session_value_ptr(thd, base); |
2346 | } |
2347 | ulonglong get_master_info_ulonglong_value(THD *thd, ptrdiff_t offset); |
2348 | bool update_variable(THD *thd, Master_info *mi) |
2349 | { |
2350 | return update_multi_source_variable_func(this, thd, mi); |
2351 | } |
2352 | }; |
2353 | |
2354 | |
2355 | /** |
2356 | Class for @@global.gtid_current_pos. |
2357 | */ |
2358 | class Sys_var_gtid_current_pos: public sys_var |
2359 | { |
2360 | public: |
2361 | Sys_var_gtid_current_pos(const char *name_arg, |
2362 | const char *, int flag_args, ptrdiff_t off, size_t size, |
2363 | CMD_LINE getopt) |
2364 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
2365 | getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG, |
2366 | NULL, NULL, NULL) |
2367 | { |
2368 | SYSVAR_ASSERT(getopt.id < 0); |
2369 | SYSVAR_ASSERT(is_readonly()); |
2370 | option.var_type|= GET_STR; |
2371 | } |
2372 | bool do_check(THD *thd, set_var *var) |
2373 | { |
2374 | DBUG_ASSERT(false); |
2375 | return true; |
2376 | } |
2377 | bool session_update(THD *thd, set_var *var) |
2378 | { |
2379 | DBUG_ASSERT(false); |
2380 | return true; |
2381 | } |
2382 | bool global_update(THD *thd, set_var *var) |
2383 | { |
2384 | DBUG_ASSERT(false); |
2385 | return true; |
2386 | } |
2387 | void session_save_default(THD *thd, set_var *var) |
2388 | { |
2389 | DBUG_ASSERT(false); |
2390 | } |
2391 | void global_save_default(THD *thd, set_var *var) |
2392 | { |
2393 | DBUG_ASSERT(false); |
2394 | } |
2395 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
2396 | { |
2397 | DBUG_ASSERT(false); |
2398 | return NULL; |
2399 | } |
2400 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base); |
2401 | }; |
2402 | |
2403 | |
2404 | /** |
2405 | Class for @@global.gtid_binlog_pos. |
2406 | */ |
2407 | class Sys_var_gtid_binlog_pos: public sys_var |
2408 | { |
2409 | public: |
2410 | Sys_var_gtid_binlog_pos(const char *name_arg, |
2411 | const char *, int flag_args, ptrdiff_t off, size_t size, |
2412 | CMD_LINE getopt) |
2413 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
2414 | getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG, |
2415 | NULL, NULL, NULL) |
2416 | { |
2417 | SYSVAR_ASSERT(getopt.id < 0); |
2418 | SYSVAR_ASSERT(is_readonly()); |
2419 | option.var_type|= GET_STR; |
2420 | } |
2421 | bool do_check(THD *thd, set_var *var) |
2422 | { |
2423 | DBUG_ASSERT(false); |
2424 | return true; |
2425 | } |
2426 | bool session_update(THD *thd, set_var *var) |
2427 | { |
2428 | DBUG_ASSERT(false); |
2429 | return true; |
2430 | } |
2431 | bool global_update(THD *thd, set_var *var) |
2432 | { |
2433 | DBUG_ASSERT(false); |
2434 | return true; |
2435 | } |
2436 | void session_save_default(THD *thd, set_var *var) |
2437 | { |
2438 | DBUG_ASSERT(false); |
2439 | } |
2440 | void global_save_default(THD *thd, set_var *var) |
2441 | { |
2442 | DBUG_ASSERT(false); |
2443 | } |
2444 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
2445 | { |
2446 | DBUG_ASSERT(false); |
2447 | return NULL; |
2448 | } |
2449 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base); |
2450 | }; |
2451 | |
2452 | |
2453 | /** |
2454 | Class for @@global.gtid_slave_pos. |
2455 | */ |
2456 | class Sys_var_gtid_slave_pos: public sys_var |
2457 | { |
2458 | public: |
2459 | Sys_var_gtid_slave_pos(const char *name_arg, |
2460 | const char *, int flag_args, ptrdiff_t off, size_t size, |
2461 | CMD_LINE getopt) |
2462 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
2463 | getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG, |
2464 | NULL, NULL, NULL) |
2465 | { |
2466 | option.var_type|= GET_STR; |
2467 | } |
2468 | bool do_check(THD *thd, set_var *var); |
2469 | bool session_update(THD *thd, set_var *var) |
2470 | { |
2471 | DBUG_ASSERT(false); |
2472 | return true; |
2473 | } |
2474 | bool global_update(THD *thd, set_var *var); |
2475 | void session_save_default(THD *thd, set_var *var) |
2476 | { |
2477 | DBUG_ASSERT(false); |
2478 | } |
2479 | void global_save_default(THD *thd, set_var *var) |
2480 | { |
2481 | /* Record the attempt to use default so we can error. */ |
2482 | var->value= 0; |
2483 | } |
2484 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
2485 | { |
2486 | DBUG_ASSERT(false); |
2487 | return NULL; |
2488 | } |
2489 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base); |
2490 | uchar *default_value_ptr(THD *thd) |
2491 | { return 0; } |
2492 | }; |
2493 | |
2494 | |
2495 | /** |
2496 | Class for @@global.gtid_binlog_state. |
2497 | */ |
2498 | class Sys_var_gtid_binlog_state: public sys_var |
2499 | { |
2500 | public: |
2501 | Sys_var_gtid_binlog_state(const char *name_arg, |
2502 | const char *, int flag_args, ptrdiff_t off, size_t size, |
2503 | CMD_LINE getopt) |
2504 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |
2505 | getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG, |
2506 | NULL, NULL, NULL) |
2507 | { |
2508 | option.var_type|= GET_STR; |
2509 | } |
2510 | bool do_check(THD *thd, set_var *var); |
2511 | bool session_update(THD *thd, set_var *var) |
2512 | { |
2513 | DBUG_ASSERT(false); |
2514 | return true; |
2515 | } |
2516 | bool global_update(THD *thd, set_var *var); |
2517 | void session_save_default(THD *thd, set_var *var) |
2518 | { |
2519 | DBUG_ASSERT(false); |
2520 | } |
2521 | void global_save_default(THD *thd, set_var *var) |
2522 | { |
2523 | /* Record the attempt to use default so we can error. */ |
2524 | var->value= 0; |
2525 | } |
2526 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
2527 | { |
2528 | DBUG_ASSERT(false); |
2529 | return NULL; |
2530 | } |
2531 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base); |
2532 | uchar *default_value_ptr(THD *thd) |
2533 | { return 0; } |
2534 | }; |
2535 | |
2536 | |
2537 | /** |
2538 | Class for @@session.last_gtid. |
2539 | */ |
2540 | class Sys_var_last_gtid: public sys_var |
2541 | { |
2542 | public: |
2543 | Sys_var_last_gtid(const char *name_arg, |
2544 | const char *, int flag_args, CMD_LINE getopt) |
2545 | : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id, |
2546 | getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG, |
2547 | NULL, NULL, NULL) |
2548 | { |
2549 | SYSVAR_ASSERT(getopt.id < 0); |
2550 | SYSVAR_ASSERT(is_readonly()); |
2551 | option.var_type|= GET_STR; |
2552 | } |
2553 | bool do_check(THD *thd, set_var *var) |
2554 | { |
2555 | DBUG_ASSERT(false); |
2556 | return true; |
2557 | } |
2558 | bool session_update(THD *thd, set_var *var) |
2559 | { |
2560 | DBUG_ASSERT(false); |
2561 | return true; |
2562 | } |
2563 | bool global_update(THD *thd, set_var *var) |
2564 | { |
2565 | DBUG_ASSERT(false); |
2566 | return true; |
2567 | } |
2568 | void session_save_default(THD *thd, set_var *var) |
2569 | { |
2570 | DBUG_ASSERT(false); |
2571 | } |
2572 | void global_save_default(THD *thd, set_var *var) |
2573 | { |
2574 | DBUG_ASSERT(false); |
2575 | } |
2576 | uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base); |
2577 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
2578 | { |
2579 | DBUG_ASSERT(false); |
2580 | return NULL; |
2581 | } |
2582 | }; |
2583 | |
2584 | |
2585 | /** |
2586 | Class for connection_name.slave_parallel_mode. |
2587 | */ |
2588 | class Sys_var_slave_parallel_mode: public Sys_var_enum |
2589 | { |
2590 | public: |
2591 | Sys_var_slave_parallel_mode(const char *name_arg, |
2592 | const char *, int flag_args, ptrdiff_t off, size_t size, |
2593 | CMD_LINE getopt, const char *values[], |
2594 | enum_slave_parallel_mode def_val) |
2595 | : Sys_var_enum(name_arg, comment, flag_args, off, size, |
2596 | getopt, values, def_val) |
2597 | { |
2598 | option.var_type|= GET_ASK_ADDR; |
2599 | option.value= (uchar**)1; // crash me, please |
2600 | SYSVAR_ASSERT(scope() == GLOBAL); |
2601 | } |
2602 | bool global_update(THD *thd, set_var *var); |
2603 | uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base); |
2604 | }; |
2605 | |
2606 | |
2607 | class Sys_var_vers_asof: public Sys_var_enum |
2608 | { |
2609 | public: |
2610 | static const char *asof_keywords[]; |
2611 | |
2612 | public: |
2613 | Sys_var_vers_asof(const char *name_arg, |
2614 | const char *, int flag_args, ptrdiff_t off, size_t size, |
2615 | CMD_LINE getopt, const char *values[], |
2616 | uint def_val) |
2617 | : Sys_var_enum(name_arg, comment, flag_args, off, size, |
2618 | getopt, values, def_val) |
2619 | { |
2620 | // setval() accepts string rather enum |
2621 | option.var_type= GET_STR; |
2622 | } |
2623 | virtual bool do_check(THD *thd, set_var *var) |
2624 | { |
2625 | if (!Sys_var_enum::do_check(thd, var)) |
2626 | return false; |
2627 | MYSQL_TIME ltime; |
2628 | bool res= var->value->get_date(<ime, 0); |
2629 | if (!res) |
2630 | { |
2631 | var->save_result.ulonglong_value= SYSTEM_TIME_AS_OF; |
2632 | } |
2633 | return res; |
2634 | } |
2635 | |
2636 | private: |
2637 | bool update(set_var *var, vers_asof_timestamp_t &out) |
2638 | { |
2639 | bool res= false; |
2640 | out.type= static_cast<enum_var_type>(var->save_result.ulonglong_value); |
2641 | if (out.type == SYSTEM_TIME_AS_OF) |
2642 | { |
2643 | if (var->value) |
2644 | { |
2645 | res= var->value->get_date(&out.ltime, 0); |
2646 | } |
2647 | else // set DEFAULT from global var |
2648 | { |
2649 | out= global_var(vers_asof_timestamp_t); |
2650 | res= false; |
2651 | } |
2652 | } |
2653 | return res; |
2654 | } |
2655 | |
2656 | public: |
2657 | virtual bool global_update(THD *thd, set_var *var) |
2658 | { |
2659 | return update(var, global_var(vers_asof_timestamp_t)); |
2660 | } |
2661 | virtual bool session_update(THD *thd, set_var *var) |
2662 | { |
2663 | return update(var, session_var(thd, vers_asof_timestamp_t)); |
2664 | } |
2665 | |
2666 | private: |
2667 | uchar *value_ptr(THD *thd, vers_asof_timestamp_t &val) |
2668 | { |
2669 | switch (val.type) |
2670 | { |
2671 | case SYSTEM_TIME_UNSPECIFIED: |
2672 | case SYSTEM_TIME_ALL: |
2673 | return (uchar*) thd->strdup(asof_keywords[val.type]); |
2674 | case SYSTEM_TIME_AS_OF: |
2675 | { |
2676 | uchar *buf= (uchar*) thd->alloc(MAX_DATE_STRING_REP_LENGTH); |
2677 | if (buf &&!my_datetime_to_str(&val.ltime, (char*) buf, 6)) |
2678 | { |
2679 | // TODO: figure out variable name |
2680 | my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "system_versioning_asof_timestamp" , "NULL (wrong datetime)" ); |
2681 | return (uchar*) thd->strdup("Error: wrong datetime" ); |
2682 | } |
2683 | return buf; |
2684 | } |
2685 | default: |
2686 | break; |
2687 | } |
2688 | my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "system_versioning_asof_timestamp" , "NULL (wrong range type)" ); |
2689 | return (uchar*) thd->strdup("Error: wrong range type" ); |
2690 | } |
2691 | |
2692 | public: |
2693 | virtual uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) |
2694 | { return value_ptr(thd, session_var(thd, vers_asof_timestamp_t)); } |
2695 | virtual uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) |
2696 | { return value_ptr(thd, global_var(vers_asof_timestamp_t)); } |
2697 | }; |
2698 | |