summaryrefslogtreecommitdiff
path: root/sql/set_var.h
blob: 70f2cb8ead2792fd78195b5d9303780e54506090 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
#ifndef SET_VAR_INCLUDED
#define SET_VAR_INCLUDED
/* Copyright (c) 2002, 2013, Oracle and/or its affiliates.
   Copyright (c) 2009, 2020, MariaDB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA */

/**
  @file
  "public" interface to sys_var - server configuration variables.
*/

#ifdef USE_PRAGMA_INTERFACE
#pragma interface                       /* gcc class implementation */
#endif

#include <my_getopt.h>

class sys_var;
class set_var;
class sys_var_pluginvar;
class PolyLock;
class Item_func_set_user_var;

// This include needs to be here since item.h requires enum_var_type :-P
#include "item.h"                          /* Item */
#include "sql_class.h"                     /* THD  */

extern TYPELIB bool_typelib;

struct sys_var_chain
{
  sys_var *first;
  sys_var *last;
};

int mysql_add_sys_var_chain(sys_var *chain);
int mysql_del_sys_var_chain(sys_var *chain);


/**
  A class representing one system variable - that is something
  that can be accessed as @@global.variable_name or @@session.variable_name,
  visible in SHOW xxx VARIABLES and in INFORMATION_SCHEMA.xxx_VARIABLES,
  optionally it can be assigned to, optionally it can have a command-line
  counterpart with the same name.
*/
class sys_var: protected Value_source // for double_from_string_with_check
{
public:
  sys_var *next;
  LEX_CSTRING name;
  bool *test_load;
  enum flag_enum { GLOBAL, SESSION, ONLY_SESSION, SCOPE_MASK=1023,
                   READONLY=1024, ALLOCATED=2048, PARSE_EARLY=4096,
                   NO_SET_STATEMENT=8192, AUTO_SET=16384};
  enum { NO_GETOPT=-1, GETOPT_ONLY_HELP=-2 };
  enum where { CONFIG, COMMAND_LINE, AUTO, SQL, COMPILE_TIME, ENV };

  /**
    Enumeration type to indicate for a system variable whether
    it will be written to the binlog or not.
  */    
  enum binlog_status_enum { VARIABLE_NOT_IN_BINLOG,
                            SESSION_VARIABLE_IN_BINLOG } binlog_status;

  my_option option;     ///< min, max, default values are stored here
  enum where value_origin;
  const char *origin_filename;

protected:
  typedef bool (*on_check_function)(sys_var *self, THD *thd, set_var *var);
  typedef bool (*on_update_function)(sys_var *self, THD *thd, enum_var_type type);

  int flags;            ///< or'ed flag_enum values
  SHOW_TYPE show_val_type; ///< what value_ptr() returns for sql_show.cc
  PolyLock *guard;      ///< *second* lock that protects the variable
  ptrdiff_t offset;     ///< offset to the value from global_system_variables
  on_check_function on_check;
  on_update_function on_update;
  const char *const deprecation_substitute;

public:
  sys_var(sys_var_chain *chain, const char *name_arg, const char *comment,
          int flag_args, ptrdiff_t off, int getopt_id,
          enum get_opt_arg_type getopt_arg_type, SHOW_TYPE show_val_type_arg,
          longlong def_val, PolyLock *lock, enum binlog_status_enum binlog_status_arg,
          on_check_function on_check_func, on_update_function on_update_func,
          const char *substitute);

  virtual ~sys_var() = default;

  /**
    All the cleanup procedures should be performed here
  */
  virtual void cleanup() {}
  /**
    downcast for sys_var_pluginvar. Returns this if it's an instance
    of sys_var_pluginvar, and 0 otherwise.
  */
  virtual sys_var_pluginvar *cast_pluginvar() { return 0; }

  bool check(THD *thd, set_var *var);
  const uchar *value_ptr(THD *thd, enum_var_type type, const LEX_CSTRING *base) const;

  /**
     Update the system variable with the default value from either
     session or global scope.  The default value is stored in the
     'var' argument. Return false when successful.
  */
  bool set_default(THD *thd, set_var *var);
  bool update(THD *thd, set_var *var);

  String *val_str_nolock(String *str, THD *thd, const uchar *value);
  longlong val_int(bool *is_null, THD *thd, enum_var_type type, const LEX_CSTRING *base);
  String *val_str(String *str, THD *thd, enum_var_type type, const LEX_CSTRING *base);
  double val_real(bool *is_null, THD *thd, enum_var_type type, const LEX_CSTRING *base);

  SHOW_TYPE show_type() const { return show_val_type; }
  int scope() const { return flags & SCOPE_MASK; }
  virtual CHARSET_INFO *charset(THD *thd) const
  {
    return system_charset_info;
  }
  bool is_readonly() const { return flags & READONLY; }
  void update_flags(int new_flags) { flags = new_flags; }
  int get_flags() const { return flags; }
  /**
    the following is only true for keycache variables,
    that support the syntax @@keycache_name.variable_name
  */
  bool is_struct() { return option.var_type & GET_ASK_ADDR; }
  bool is_set_stmt_ok() const { return !(flags & NO_SET_STATEMENT); }
  bool is_written_to_binlog(enum_var_type type)
  { return type != OPT_GLOBAL && binlog_status == SESSION_VARIABLE_IN_BINLOG; }
  bool check_update_type(const Item *item)
  {
    Item_result type= item->result_type();
    switch (option.var_type & GET_TYPE_MASK) {
    case GET_INT:
    case GET_UINT:
    case GET_LONG:
    case GET_ULONG:
    case GET_LL:
    case GET_ULL:
      return type != INT_RESULT &&
             (type != DECIMAL_RESULT || item->decimals != 0);
    case GET_STR:
    case GET_STR_ALLOC:
      return type != STRING_RESULT;
    case GET_ENUM:
    case GET_BOOL:
    case GET_SET:
    case GET_FLAGSET:
    case GET_BIT:
      return type != STRING_RESULT && type != INT_RESULT;
    case GET_DOUBLE:
      return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT;
    default:
      return true;
    }
  }

  bool check_type(enum_var_type type)
  {
    switch (scope())
    {
    case GLOBAL:       return type != OPT_GLOBAL;
    case SESSION:      return false; // always ok
    case ONLY_SESSION: return type == OPT_GLOBAL;
    }
    return true; // keep gcc happy
  }
  bool register_option(DYNAMIC_ARRAY *array, int parse_flags)
  {
    DBUG_ASSERT(parse_flags == GETOPT_ONLY_HELP ||
                parse_flags == PARSE_EARLY || parse_flags == 0);
    if (option.id == NO_GETOPT)
      return 0;
    if (parse_flags == GETOPT_ONLY_HELP)
    {
      if (option.id != GETOPT_ONLY_HELP)
        return 0;
    }
    else
    {
      if (option.id == GETOPT_ONLY_HELP)
        return 0;
      if ((flags & PARSE_EARLY) != parse_flags)
        return 0;
    }
    return insert_dynamic(array, (uchar*)&option);
  }
  void do_deprecated_warning(THD *thd);
  /**
    whether session value of a sysvar is a default one.

    in this simple implementation we don't distinguish between default
    and non-default values. for most variables it's ok, they don't treat
    default values specially. this method is overwritten in descendant
    classes as necessary.
  */
  virtual bool session_is_default(THD *thd) { return false; }

  virtual const uchar *default_value_ptr(THD *thd) const
  { return (uchar*)&option.def_value; }

  virtual bool on_check_access_global(THD *thd) const;
  virtual bool on_check_access_session(THD *thd) const
  {
    return false;
  }

private:
  virtual bool do_check(THD *thd, set_var *var) = 0;
  /**
    save the session default value of the variable in var
  */
  virtual void session_save_default(THD *thd, set_var *var) = 0;
  /**
    save the global default value of the variable in var
  */
  virtual void global_save_default(THD *thd, set_var *var) = 0;
  virtual bool session_update(THD *thd, set_var *var) = 0;
  virtual bool global_update(THD *thd, set_var *var) = 0;

protected:
  /**
    A pointer to a value of the variable for SHOW.
    It must be of show_val_type type (my_bool for SHOW_MY_BOOL,
    int for SHOW_INT, longlong for SHOW_LONGLONG, etc).
  */
  virtual const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const;
  virtual const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;

  /**
    A pointer to a storage area of the variable, to the raw data.
    Typically it's the same as session_value_ptr(), but it's different,
    for example, for ENUM, that is printed as a string, but stored as a number.
  */
  uchar *session_var_ptr(THD *thd) const
  { return ((uchar*)&(thd->variables)) + offset; }

  uchar *global_var_ptr() const
  { return ((uchar*)&global_system_variables) + offset; }

  void *max_var_ptr()
  {
    return scope() == SESSION ? (((uchar*)&max_system_variables) + offset) :
                                0;
  }

  friend class Session_sysvars_tracker;
  friend class Session_tracker;
};

#include "sql_plugin.h"                    /* SHOW_HA_ROWS, SHOW_MY_BOOL */


/****************************************************************************
  Classes for parsing of the SET command
****************************************************************************/

/**
  A base class for everything that can be set with SET command.
  It's similar to Items, an instance of this is created by the parser
  for every assigmnent in SET (or elsewhere, e.g. in SELECT).
*/
class set_var_base :public Sql_alloc
{
public:
  set_var_base() = default;
  virtual ~set_var_base() = default;
  virtual int check(THD *thd)=0;           /* To check privileges etc. */
  virtual int update(THD *thd)=0;                  /* To set the value */
  virtual int light_check(THD *thd) { return check(thd); }   /* for PS */
  virtual bool is_system() { return FALSE; }
  /**
    @returns whether this variable is @@@@optimizer_trace.
  */
  virtual bool is_var_optimizer_trace() const { return false; }
};


/**
  Structure for holding unix timestamp and high precision second part.
 */
typedef struct my_time_t_hires
{
  my_time_t unix_time;
  ulong second_part;
} my_time_t_hires;


/**
  set_var_base descendant for assignments to the system variables.
*/
class set_var :public set_var_base
{
public:
  sys_var *var; ///< system variable to be updated
  Item *value;  ///< the expression that provides the new value of the variable
  enum_var_type type;
  union ///< temp storage to hold a value between sys_var::check and ::update
  {
    ulonglong ulonglong_value;          ///< for unsigned integer, set, enum sysvars
    longlong longlong_value;            ///< for signed integer
    double double_value;                ///< for Sys_var_double
    plugin_ref plugin;                  ///< for Sys_var_plugin
    plugin_ref *plugins;                ///< for Sys_var_pluginlist
    Time_zone *time_zone;               ///< for Sys_var_tz
    LEX_STRING string_value;            ///< for Sys_var_charptr and others
    my_time_t_hires timestamp;          ///< for Sys_var_vers_asof
    const void *ptr;                    ///< for Sys_var_struct
  } save_result;
  LEX_CSTRING base; /**< for structured variables, like keycache_name.variable_name */

  set_var(THD *thd, enum_var_type type_arg, sys_var *var_arg,
          const LEX_CSTRING *base_name_arg, Item *value_arg);
  virtual bool is_system() { return 1; }
  int check(THD *thd);
  int update(THD *thd);
  int light_check(THD *thd);
  virtual bool is_var_optimizer_trace() const
  {
    extern sys_var *Sys_optimizer_trace_ptr;
    return var == Sys_optimizer_trace_ptr;
  }
};


/* User variables like @my_own_variable */
class set_var_user: public set_var_base
{
  Item_func_set_user_var *user_var_item;
public:
  set_var_user(Item_func_set_user_var *item)
    :user_var_item(item)
  {}
  int check(THD *thd);
  int update(THD *thd);
  int light_check(THD *thd);
};

/* For SET PASSWORD */

class set_var_password: public set_var_base
{
  LEX_USER *user;
public:
  set_var_password(LEX_USER *user_arg) :user(user_arg)
  {}
  int check(THD *thd);
  int update(THD *thd);
};

/* For SET ROLE */

class set_var_role: public set_var_base
{
  LEX_CSTRING role;
  privilege_t access;
public:
  set_var_role(LEX_CSTRING role_arg) : role(role_arg), access(NO_ACL) {}
  int check(THD *thd);
  int update(THD *thd);
};

/* For SET DEFAULT ROLE */

class set_var_default_role: public set_var_base
{
  LEX_USER *user, *real_user;
  LEX_CSTRING role;
  const char *real_role;
public:
  set_var_default_role(LEX_USER *user_arg, LEX_CSTRING role_arg) :
    user(user_arg), role(role_arg) {}
  int check(THD *thd);
  int update(THD *thd);
};

/* For SET NAMES and SET CHARACTER SET */

class set_var_collation_client: public set_var_base
{
  CHARSET_INFO *character_set_client;
  CHARSET_INFO *character_set_results;
  CHARSET_INFO *collation_connection;
public:
  set_var_collation_client(CHARSET_INFO *client_coll_arg,
                           CHARSET_INFO *connection_coll_arg,
                           CHARSET_INFO *result_coll_arg)
    :character_set_client(client_coll_arg),
     character_set_results(result_coll_arg),
     collation_connection(connection_coll_arg)
  {}
  int check(THD *thd);
  int update(THD *thd);
};


/* optional things, have_* variables */
extern SHOW_COMP_OPTION have_csv, have_innodb;
extern SHOW_COMP_OPTION have_ndbcluster, have_partitioning;
extern SHOW_COMP_OPTION have_profiling;

extern SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen;
extern SHOW_COMP_OPTION have_query_cache;
extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
extern SHOW_COMP_OPTION have_crypt;
extern SHOW_COMP_OPTION have_compress;
extern SHOW_COMP_OPTION have_openssl;

/*
  Prototypes for helper functions
*/
ulong get_system_variable_hash_records(void);
ulonglong get_system_variable_hash_version(void);

SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type);
int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond);

sys_var *find_sys_var(THD *thd, const char *str, size_t length= 0,
                      bool throw_error= false);
int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free);

#define SYSVAR_AUTOSIZE(VAR,VAL)                        \
  do {                                                  \
    VAR= (VAL);                                         \
    set_sys_var_value_origin(&VAR, sys_var::AUTO);      \
  } while(0)

#define SYSVAR_AUTOSIZE_IF_CHANGED(VAR,VAL,TYPE)        \
  do {                                                  \
    TYPE tmp= (VAL);                                    \
    if (VAR != tmp)                                     \
    {                                                   \
      VAR= (VAL);                                       \
      set_sys_var_value_origin(&VAR, sys_var::AUTO);    \
    }                                                   \
  } while(0)

void set_sys_var_value_origin(void *ptr, enum sys_var::where here,
                              const char *filename= NULL);

enum sys_var::where get_sys_var_value_origin(void *ptr);
inline bool IS_SYSVAR_AUTOSIZE(void *ptr)
{
  enum sys_var::where res= get_sys_var_value_origin(ptr);
  return (res == sys_var::AUTO || res == sys_var::COMPILE_TIME);
}

bool fix_delay_key_write(sys_var *self, THD *thd, enum_var_type type);

sql_mode_t expand_sql_mode(sql_mode_t sql_mode);
const char *sql_mode_string_representation(uint bit_number);
bool sql_mode_string_representation(THD *thd, sql_mode_t sql_mode,
                                    LEX_CSTRING *ls);
int default_regex_flags_pcre(THD *thd);

extern sys_var *Sys_autocommit_ptr, *Sys_last_gtid_ptr,
  *Sys_character_set_client_ptr, *Sys_character_set_connection_ptr,
  *Sys_character_set_results_ptr;

CHARSET_INFO *get_old_charset_by_name(const char *old_name);

int sys_var_init();
uint sys_var_elements();
int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags);
void sys_var_end(void);
bool check_has_super(sys_var *self, THD *thd, set_var *var);
plugin_ref *resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len,
                                bool error_on_unknown_engine, bool temp_copy);
void free_engine_list(plugin_ref *list);
plugin_ref *copy_engine_list(plugin_ref *list);
plugin_ref *temp_copy_engine_list(THD *thd, plugin_ref *list);
char *pretty_print_engine_list(THD *thd, plugin_ref *list);
#endif