1
/* Copyright (C) 2005 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include "mysql_priv.h"
17
#include <my_pthread.h>
18
#include <my_getopt.h>
19
#define REPORT_TO_LOG 1
20
#define REPORT_TO_USER 2
23
#define plugin_ref_to_int(A) A
24
#define plugin_int_to_ref(A) A
26
#define plugin_ref_to_int(A) (A ? A[0] : NULL)
27
#define plugin_int_to_ref(A) &(A)
30
extern struct st_mysql_plugin *mysqld_builtins[];
32
char *opt_plugin_load= NULL;
33
char *opt_plugin_dir_ptr;
34
char opt_plugin_dir[FN_REFLEN];
36
When you ad a new plugin type, add both a string and make sure that the
37
init and deinit array are correctly updated.
39
const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
41
{ C_STRING_WITH_LEN("UDF") },
42
{ C_STRING_WITH_LEN("STORAGE ENGINE") },
43
{ C_STRING_WITH_LEN("FTPARSER") },
44
{ C_STRING_WITH_LEN("DAEMON") },
45
{ C_STRING_WITH_LEN("INFORMATION SCHEMA") },
46
{ C_STRING_WITH_LEN("AUDIT") }
49
extern int initialize_schema_table(st_plugin_int *plugin);
50
extern int finalize_schema_table(st_plugin_int *plugin);
53
The number of elements in both plugin_type_initialize and
54
plugin_type_deinitialize should equal to the number of plugins
57
plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
59
0,ha_initialize_handlerton,0,0,initialize_schema_table,
63
plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
65
0,ha_finalize_handlerton,0,0,finalize_schema_table,
70
static const char *plugin_interface_version_sym=
71
"_mysql_plugin_interface_version_";
72
static const char *sizeof_st_plugin_sym=
73
"_mysql_sizeof_struct_st_plugin_";
74
static const char *plugin_declarations_sym= "_mysql_plugin_declarations_";
75
static int min_plugin_interface_version= MYSQL_PLUGIN_INTERFACE_VERSION & ~0xFF;
78
/* Note that 'int version' must be the first field of every plugin
79
sub-structure (plugin->info).
81
static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
84
MYSQL_HANDLERTON_INTERFACE_VERSION,
85
MYSQL_FTPARSER_INTERFACE_VERSION,
86
MYSQL_DAEMON_INTERFACE_VERSION,
87
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION,
88
MYSQL_AUDIT_INTERFACE_VERSION
90
static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
92
0x0000, /* UDF: not implemented */
93
MYSQL_HANDLERTON_INTERFACE_VERSION,
94
MYSQL_FTPARSER_INTERFACE_VERSION,
95
MYSQL_DAEMON_INTERFACE_VERSION,
96
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION,
97
MYSQL_AUDIT_INTERFACE_VERSION
100
static bool initialized= 0;
102
static DYNAMIC_ARRAY plugin_dl_array;
103
static DYNAMIC_ARRAY plugin_array;
104
static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
105
static bool reap_needed= false;
106
static int plugin_array_version=0;
109
write-lock on LOCK_system_variables_hash is required before modifying
110
the following variables/structures
112
static MEM_ROOT plugin_mem_root;
113
static uint global_variables_dynamic_size= 0;
114
static HASH bookmark_hash;
118
hidden part of opaque value passed to variable check functions.
119
Used to provide a object-like structure to non C++ consumers.
121
struct st_item_value_holder : public st_mysql_value
128
stored in bookmark_hash, this structure is never removed from the
129
hash and is used to mark a single offset for a thd local variable
130
even if plugins have been uninstalled and reinstalled, repeatedly.
131
This structure is allocated from plugin_mem_root.
133
The key format is as follows:
134
1 byte - variable type code
135
name_len bytes - variable name
148
skeleton of a plugin variable - portion of structure common to all.
150
struct st_mysql_sys_var
152
MYSQL_PLUGIN_VAR_HEADER;
157
sys_var class for access to all plugin variables visible to the user
159
class sys_var_pluginvar: public sys_var
162
struct st_plugin_int *plugin;
163
struct st_mysql_sys_var *plugin_var;
165
static void *operator new(size_t size, MEM_ROOT *mem_root)
166
{ return (void*) alloc_root(mem_root, (uint) size); }
167
static void operator delete(void *ptr_arg,size_t size)
168
{ TRASH(ptr_arg, size); }
170
sys_var_pluginvar(const char *name_arg,
171
struct st_mysql_sys_var *plugin_var_arg)
172
:sys_var(name_arg), plugin_var(plugin_var_arg) {}
173
sys_var_pluginvar *cast_pluginvar() { return this; }
174
bool is_readonly() const { return plugin_var->flags & PLUGIN_VAR_READONLY; }
175
bool check_type(enum_var_type type)
176
{ return !(plugin_var->flags & PLUGIN_VAR_THDLOCAL) && type != OPT_GLOBAL; }
177
bool check_update_type(Item_result type);
178
SHOW_TYPE show_type();
179
uchar* real_value_ptr(THD *thd, enum_var_type type);
180
TYPELIB* plugin_var_typelib(void);
181
uchar* value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
182
bool check(THD *thd, set_var *var);
183
bool check_default(enum_var_type type) { return is_readonly(); }
184
void set_default(THD *thd, enum_var_type type);
185
bool update(THD *thd, set_var *var);
190
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
192
static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *,
193
int *, char **, my_bool);
194
static bool register_builtin(struct st_mysql_plugin *, struct st_plugin_int *,
195
struct st_plugin_int **);
196
static void unlock_variables(THD *thd, struct system_variables *vars);
197
static void cleanup_variables(THD *thd, struct system_variables *vars);
198
static void plugin_vars_free_values(sys_var *vars);
199
static void plugin_opt_set_limits(struct my_option *options,
200
const struct st_mysql_sys_var *opt);
201
#define my_intern_plugin_lock(A,B) intern_plugin_lock(A,B CALLER_INFO)
202
#define my_intern_plugin_lock_ci(A,B) intern_plugin_lock(A,B ORIG_CALLER_INFO)
203
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin
205
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
206
static void reap_plugins(void);
209
/* declared in set_var.cc */
210
extern sys_var *intern_find_sys_var(const char *str, uint length, bool no_error);
211
extern bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd,
212
const char *name, longlong val);
214
/****************************************************************************
215
Value type thunks, allows the C world to play in the C++ world
216
****************************************************************************/
218
static int item_value_type(struct st_mysql_value *value)
220
switch (((st_item_value_holder*)value)->item->result_type()) {
222
return MYSQL_VALUE_TYPE_INT;
224
return MYSQL_VALUE_TYPE_REAL;
226
return MYSQL_VALUE_TYPE_STRING;
230
static const char *item_val_str(struct st_mysql_value *value,
231
char *buffer, int *length)
233
String str(buffer, *length, system_charset_info), *res;
234
if (!(res= ((st_item_value_holder*)value)->item->val_str(&str)))
236
*length= res->length();
237
if (res->c_ptr_quick() == buffer)
241
Lets be nice and create a temporary string since the
244
return current_thd->strmake(res->c_ptr_quick(), res->length());
248
static int item_val_int(struct st_mysql_value *value, long long *buf)
250
Item *item= ((st_item_value_holder*)value)->item;
251
*buf= item->val_int();
258
static int item_val_real(struct st_mysql_value *value, double *buf)
260
Item *item= ((st_item_value_holder*)value)->item;
261
*buf= item->val_real();
268
/****************************************************************************
270
****************************************************************************/
274
static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl)
277
struct st_plugin_dl *tmp;
278
DBUG_ENTER("plugin_dl_find");
279
for (i= 0; i < plugin_dl_array.elements; i++)
281
tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
282
if (tmp->ref_count &&
283
! my_strnncoll(files_charset_info,
284
(const uchar *)dl->str, dl->length,
285
(const uchar *)tmp->dl.str, tmp->dl.length))
292
static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
295
struct st_plugin_dl *tmp;
296
DBUG_ENTER("plugin_dl_insert_or_reuse");
297
for (i= 0; i < plugin_dl_array.elements; i++)
299
tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
300
if (! tmp->ref_count)
302
memcpy(tmp, plugin_dl, sizeof(struct st_plugin_dl));
306
if (insert_dynamic(&plugin_dl_array, (uchar*)&plugin_dl))
308
tmp= *dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
309
struct st_plugin_dl **)=
310
(struct st_plugin_dl *) memdup_root(&plugin_mem_root, (uchar*)plugin_dl,
311
sizeof(struct st_plugin_dl));
314
#endif /* HAVE_DLOPEN */
317
static inline void free_plugin_mem(struct st_plugin_dl *p)
323
my_free(p->dl.str, MYF(MY_ALLOW_ZERO_PTR));
324
if (p->version != MYSQL_PLUGIN_INTERFACE_VERSION)
325
my_free((uchar*)p->plugins, MYF(MY_ALLOW_ZERO_PTR));
329
static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
332
char dlpath[FN_REFLEN];
333
uint plugin_dir_len, dummy_errors, dlpathlen;
334
struct st_plugin_dl *tmp, plugin_dl;
336
DBUG_ENTER("plugin_dl_add");
337
plugin_dir_len= strlen(opt_plugin_dir);
339
Ensure that the dll doesn't have a path.
340
This is done to ensure that only approved libraries from the
341
plugin directory are used (to make this even remotely secure).
343
if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, FN_LIBCHAR) ||
344
check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN,
345
system_charset_info, 1) ||
346
plugin_dir_len + dl->length + 1 >= FN_REFLEN)
348
if (report & REPORT_TO_USER)
349
my_error(ER_UDF_NO_PATHS, MYF(0));
350
if (report & REPORT_TO_LOG)
351
sql_print_error(ER(ER_UDF_NO_PATHS));
354
/* If this dll is already loaded just increase ref_count. */
355
if ((tmp= plugin_dl_find(dl)))
360
bzero(&plugin_dl, sizeof(plugin_dl));
361
/* Compile dll path */
363
strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS) -
365
plugin_dl.ref_count= 1;
366
/* Open new dll handle */
367
if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW)))
369
const char *errmsg=dlerror();
370
if (!strncmp(dlpath, errmsg, dlpathlen))
371
{ // if errmsg starts from dlpath, trim this prefix.
373
if (*errmsg == ':') errmsg++;
374
if (*errmsg == ' ') errmsg++;
376
if (report & REPORT_TO_USER)
377
my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, errno, errmsg);
378
if (report & REPORT_TO_LOG)
379
sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, errno, errmsg);
382
/* Determine interface version */
383
if (!(sym= dlsym(plugin_dl.handle, plugin_interface_version_sym)))
385
free_plugin_mem(&plugin_dl);
386
if (report & REPORT_TO_USER)
387
my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_interface_version_sym);
388
if (report & REPORT_TO_LOG)
389
sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_interface_version_sym);
392
plugin_dl.version= *(int *)sym;
394
if (plugin_dl.version < min_plugin_interface_version ||
395
(plugin_dl.version >> 8) > (MYSQL_PLUGIN_INTERFACE_VERSION >> 8))
397
free_plugin_mem(&plugin_dl);
398
if (report & REPORT_TO_USER)
399
my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, 0,
400
"plugin interface version mismatch");
401
if (report & REPORT_TO_LOG)
402
sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, 0,
403
"plugin interface version mismatch");
406
/* Find plugin declarations */
407
if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))
409
free_plugin_mem(&plugin_dl);
410
if (report & REPORT_TO_USER)
411
my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_declarations_sym);
412
if (report & REPORT_TO_LOG)
413
sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_declarations_sym);
417
if (plugin_dl.version != MYSQL_PLUGIN_INTERFACE_VERSION)
420
uint sizeof_st_plugin;
421
struct st_mysql_plugin *old, *cur;
422
char *ptr= (char *)sym;
424
if ((sym= dlsym(plugin_dl.handle, sizeof_st_plugin_sym)))
425
sizeof_st_plugin= *(int *)sym;
428
#ifdef ERROR_ON_NO_SIZEOF_PLUGIN_SYMBOL
429
free_plugin_mem(&plugin_dl);
430
if (report & REPORT_TO_USER)
431
my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), sizeof_st_plugin_sym);
432
if (report & REPORT_TO_LOG)
433
sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), sizeof_st_plugin_sym);
437
When the following assert starts failing, we'll have to switch
438
to the upper branch of the #ifdef
440
DBUG_ASSERT(min_plugin_interface_version == 0);
441
sizeof_st_plugin= (int)offsetof(struct st_mysql_plugin, version);
446
((struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info;
450
cur= (struct st_mysql_plugin*)
451
my_malloc(i*sizeof(struct st_mysql_plugin), MYF(MY_ZEROFILL|MY_WME));
454
free_plugin_mem(&plugin_dl);
455
if (report & REPORT_TO_USER)
456
my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length);
457
if (report & REPORT_TO_LOG)
458
sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
462
All st_plugin fields not initialized in the plugin explicitly, are
463
set to 0. It matches C standard behaviour for struct initializers that
464
have less values than the struct definition.
467
(old=(struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info;
469
memcpy(cur+i, old, min(sizeof(cur[i]), sizeof_st_plugin));
473
plugin_dl.plugins= (struct st_mysql_plugin *)sym;
475
/* Duplicate and convert dll name */
476
plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
477
if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
479
free_plugin_mem(&plugin_dl);
480
if (report & REPORT_TO_USER)
481
my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length);
482
if (report & REPORT_TO_LOG)
483
sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
486
plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length,
487
files_charset_info, dl->str, dl->length, system_charset_info,
489
plugin_dl.dl.str[plugin_dl.dl.length]= 0;
490
/* Add this dll to array */
491
if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl)))
493
free_plugin_mem(&plugin_dl);
494
if (report & REPORT_TO_USER)
495
my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_dl));
496
if (report & REPORT_TO_LOG)
497
sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_dl));
502
DBUG_ENTER("plugin_dl_add");
503
if (report & REPORT_TO_USER)
504
my_error(ER_FEATURE_DISABLED, MYF(0), "plugin", "HAVE_DLOPEN");
505
if (report & REPORT_TO_LOG)
506
sql_print_error(ER(ER_FEATURE_DISABLED), "plugin", "HAVE_DLOPEN");
512
static void plugin_dl_del(const LEX_STRING *dl)
516
DBUG_ENTER("plugin_dl_del");
518
for (i= 0; i < plugin_dl_array.elements; i++)
520
struct st_plugin_dl *tmp= *dynamic_element(&plugin_dl_array, i,
521
struct st_plugin_dl **);
522
if (tmp->ref_count &&
523
! my_strnncoll(files_charset_info,
524
(const uchar *)dl->str, dl->length,
525
(const uchar *)tmp->dl.str, tmp->dl.length))
527
/* Do not remove this element, unless no other plugin uses this dll. */
528
if (! --tmp->ref_count)
530
free_plugin_mem(tmp);
531
bzero(tmp, sizeof(struct st_plugin_dl));
541
static struct st_plugin_int *plugin_find_internal(const LEX_STRING *name, int type)
544
DBUG_ENTER("plugin_find_internal");
548
if (type == MYSQL_ANY_PLUGIN)
550
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
552
struct st_plugin_int *plugin= (st_plugin_int *)
553
hash_search(&plugin_hash[i], (const uchar *)name->str, name->length);
559
DBUG_RETURN((st_plugin_int *)
560
hash_search(&plugin_hash[type], (const uchar *)name->str, name->length));
565
static SHOW_COMP_OPTION plugin_status(const LEX_STRING *name, int type)
567
SHOW_COMP_OPTION rc= SHOW_OPTION_NO;
568
struct st_plugin_int *plugin;
569
DBUG_ENTER("plugin_is_ready");
570
if ((plugin= plugin_find_internal(name, type)))
572
rc= SHOW_OPTION_DISABLED;
573
if (plugin->state == PLUGIN_IS_READY)
580
bool plugin_is_ready(const LEX_STRING *name, int type)
583
if (plugin_status(name, type) == SHOW_OPTION_YES)
589
SHOW_COMP_OPTION sys_var_have_plugin::get_option()
591
LEX_STRING plugin_name= { (char *) plugin_name_str, plugin_name_len };
592
return plugin_status(&plugin_name, plugin_type);
596
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc CALLER_INFO_PROTO)
598
st_plugin_int *pi= plugin_ref_to_int(rc);
599
DBUG_ENTER("intern_plugin_lock");
601
if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
605
/* built-in plugins don't need ref counting */
612
For debugging, we do an additional malloc which allows the
613
memory manager and/or valgrind to track locked references and
614
double unlocks to aid resolving reference counting.problems.
616
if (!(plugin= (plugin_ref) my_malloc_ci(sizeof(pi), MYF(MY_WME))))
622
DBUG_PRINT("info",("thd: 0x%lx, plugin: \"%s\", ref_count: %d",
623
(long) current_thd, pi->name.str, pi->ref_count));
626
insert_dynamic(&lex->plugins, (uchar*)&plugin);
633
plugin_ref plugin_lock(THD *thd, plugin_ref *ptr CALLER_INFO_PROTO)
635
LEX *lex= thd ? thd->lex : 0;
637
DBUG_ENTER("plugin_lock");
638
rc= my_intern_plugin_lock_ci(lex, *ptr);
643
plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name, int type
646
LEX *lex= thd ? thd->lex : 0;
648
st_plugin_int *plugin;
649
DBUG_ENTER("plugin_lock_by_name");
650
if ((plugin= plugin_find_internal(name, type)))
651
rc= my_intern_plugin_lock_ci(lex, plugin_int_to_ref(plugin));
656
static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
659
struct st_plugin_int *tmp;
660
DBUG_ENTER("plugin_insert_or_reuse");
661
for (i= 0; i < plugin_array.elements; i++)
663
tmp= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
664
if (tmp->state == PLUGIN_IS_FREED)
666
memcpy(tmp, plugin, sizeof(struct st_plugin_int));
670
if (insert_dynamic(&plugin_array, (uchar*)&plugin))
672
tmp= *dynamic_element(&plugin_array, plugin_array.elements - 1,
673
struct st_plugin_int **)=
674
(struct st_plugin_int *) memdup_root(&plugin_mem_root, (uchar*)plugin,
675
sizeof(struct st_plugin_int));
682
Requires that a write-lock is held on LOCK_system_variables_hash
684
static bool plugin_add(MEM_ROOT *tmp_root,
685
const LEX_STRING *name, const LEX_STRING *dl,
686
int *argc, char **argv, int report)
688
struct st_plugin_int tmp;
689
struct st_mysql_plugin *plugin;
690
DBUG_ENTER("plugin_add");
691
if (plugin_find_internal(name, MYSQL_ANY_PLUGIN))
693
if (report & REPORT_TO_USER)
694
my_error(ER_UDF_EXISTS, MYF(0), name->str);
695
if (report & REPORT_TO_LOG)
696
sql_print_error(ER(ER_UDF_EXISTS), name->str);
699
/* Clear the whole struct to catch future extensions. */
700
bzero((char*) &tmp, sizeof(tmp));
701
if (! (tmp.plugin_dl= plugin_dl_add(dl, report)))
703
/* Find plugin by name */
704
for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++)
706
uint name_len= strlen(plugin->name);
707
if (plugin->type >= 0 && plugin->type < MYSQL_MAX_PLUGIN_TYPE_NUM &&
708
! my_strnncoll(system_charset_info,
709
(const uchar *)name->str, name->length,
710
(const uchar *)plugin->name,
713
struct st_plugin_int *tmp_plugin_ptr;
714
if (*(int*)plugin->info <
715
min_plugin_info_interface_version[plugin->type] ||
716
((*(int*)plugin->info) >> 8) >
717
(cur_plugin_info_interface_version[plugin->type] >> 8))
720
strxnmov(buf, sizeof(buf) - 1, "API version for ",
721
plugin_type_names[plugin->type].str,
722
" plugin is too different", NullS);
723
if (report & REPORT_TO_USER)
724
my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dl->str, 0, buf);
725
if (report & REPORT_TO_LOG)
726
sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dl->str, 0, buf);
730
tmp.name.str= (char *)plugin->name;
731
tmp.name.length= name_len;
733
tmp.state= PLUGIN_IS_UNINITIALIZED;
734
if (!test_plugin_options(tmp_root, &tmp, argc, argv, true))
736
if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
738
plugin_array_version++;
739
if (!my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
741
init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096);
744
tmp_plugin_ptr->state= PLUGIN_IS_FREED;
746
mysql_del_sys_var_chain(tmp.system_vars);
749
/* plugin was disabled */
754
if (report & REPORT_TO_USER)
755
my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), name->str);
756
if (report & REPORT_TO_LOG)
757
sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name->str);
764
static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
766
if (plugin->plugin->status_vars)
770
We have a problem right now where we can not prepend without
771
breaking backwards compatibility. We will fix this shortly so
772
that engines have "use names" and we wil use those for
773
CREATE TABLE, and use the plugin name then for adding automatic
777
{plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
780
remove_status_vars(array);
782
remove_status_vars(plugin->plugin->status_vars);
783
#endif /* FIX_LATER */
786
if (plugin_type_deinitialize[plugin->plugin->type])
788
if ((*plugin_type_deinitialize[plugin->plugin->type])(plugin))
790
sql_print_error("Plugin '%s' of type %s failed deinitialization",
791
plugin->name.str, plugin_type_names[plugin->plugin->type].str);
794
else if (plugin->plugin->deinit)
796
DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
797
if (plugin->plugin->deinit(plugin))
799
DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
803
plugin->state= PLUGIN_IS_UNINITIALIZED;
806
We do the check here because NDB has a worker THD which doesn't
807
exit until NDB is shut down.
809
if (ref_check && plugin->ref_count)
810
sql_print_error("Plugin '%s' has ref_count=%d after deinitialization.",
811
plugin->name.str, plugin->ref_count);
815
static void plugin_del(struct st_plugin_int *plugin)
817
DBUG_ENTER("plugin_del(plugin)");
818
/* Free allocated strings before deleting the plugin. */
819
plugin_vars_free_values(plugin->system_vars);
820
hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
821
if (plugin->plugin_dl)
822
plugin_dl_del(&plugin->plugin_dl->dl);
823
plugin->state= PLUGIN_IS_FREED;
824
plugin_array_version++;
825
rw_wrlock(&LOCK_system_variables_hash);
826
mysql_del_sys_var_chain(plugin->system_vars);
827
rw_unlock(&LOCK_system_variables_hash);
828
free_root(&plugin->mem_root, MYF(0));
834
static void plugin_del(const LEX_STRING *name)
836
struct st_plugin_int *plugin;
837
DBUG_ENTER("plugin_del(name)");
838
if ((plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
845
static void reap_plugins(void)
848
struct st_plugin_int *plugin, **reap, **list;
854
count= plugin_array.elements;
855
reap= (struct st_plugin_int **)my_alloca(sizeof(plugin)*(count+1));
858
for (idx= 0; idx < count; idx++)
860
plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
861
if (plugin->state == PLUGIN_IS_DELETED && !plugin->ref_count)
863
/* change the status flag to prevent reaping by another thread */
864
plugin->state= PLUGIN_IS_DYING;
870
while ((plugin= *(--list)))
871
plugin_deinitialize(plugin, true);
873
while ((plugin= *(--reap)))
879
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin)
883
DBUG_ENTER("intern_plugin_unlock");
888
pi= plugin_ref_to_int(plugin);
894
my_free((uchar*) plugin, MYF(MY_WME));
897
DBUG_PRINT("info",("unlocking plugin, name= %s, ref_count= %d",
898
pi->name.str, pi->ref_count));
902
Remove one instance of this plugin from the use list.
903
We are searching backwards so that plugins locked last
904
could be unlocked faster - optimizing for LIFO semantics.
906
for (i= lex->plugins.elements - 1; i >= 0; i--)
907
if (plugin == *dynamic_element(&lex->plugins, i, plugin_ref*))
909
delete_dynamic_element(&lex->plugins, i);
915
DBUG_ASSERT(pi->ref_count);
918
if (pi->state == PLUGIN_IS_DELETED && !pi->ref_count)
925
void plugin_unlock(THD *thd, plugin_ref plugin)
927
LEX *lex= thd ? thd->lex : 0;
928
DBUG_ENTER("plugin_unlock");
931
intern_plugin_unlock(lex, plugin);
937
void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
939
LEX *lex= thd ? thd->lex : 0;
940
DBUG_ENTER("plugin_unlock_list");
943
intern_plugin_unlock(lex, *list++);
949
static int plugin_initialize(struct st_plugin_int *plugin)
951
DBUG_ENTER("plugin_initialize");
953
if (plugin_type_initialize[plugin->plugin->type])
955
if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
957
sql_print_error("Plugin '%s' registration as a %s failed.",
958
plugin->name.str, plugin_type_names[plugin->plugin->type].str);
962
else if (plugin->plugin->init)
964
if (plugin->plugin->init(plugin))
966
sql_print_error("Plugin '%s' init function returned error.",
972
plugin->state= PLUGIN_IS_READY;
974
if (plugin->plugin->status_vars)
978
We have a problem right now where we can not prepend without
979
breaking backwards compatibility. We will fix this shortly so
980
that engines have "use names" and we wil use those for
981
CREATE TABLE, and use the plugin name then for adding automatic
985
{plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
988
if (add_status_vars(array)) // add_status_vars makes a copy
991
add_status_vars(plugin->plugin->status_vars); // add_status_vars makes a copy
992
#endif /* FIX_LATER */
996
set the plugin attribute of plugin's sys vars so they are pointing
999
if (plugin->system_vars)
1001
sys_var_pluginvar *var= plugin->system_vars->cast_pluginvar();
1004
var->plugin= plugin;
1007
var= var->next->cast_pluginvar();
1017
extern "C" uchar *get_plugin_hash_key(const uchar *, size_t *, my_bool);
1018
extern "C" uchar *get_bookmark_hash_key(const uchar *, size_t *, my_bool);
1021
uchar *get_plugin_hash_key(const uchar *buff, size_t *length,
1022
my_bool not_used __attribute__((unused)))
1024
struct st_plugin_int *plugin= (st_plugin_int *)buff;
1025
*length= (uint)plugin->name.length;
1026
return((uchar *)plugin->name.str);
1030
uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
1031
my_bool not_used __attribute__((unused)))
1033
struct st_bookmark *var= (st_bookmark *)buff;
1034
*length= var->name_len + 1;
1035
return (uchar*) var->key;
1040
The logic is that we first load and initialize all compiled in plugins.
1041
From there we load up the dynamic types (assuming we have not been told to
1044
Finally we initialize everything, aka the dynamic that have yet to initialize.
1046
int plugin_init(int *argc, char **argv, int flags)
1049
bool def_enabled, is_myisam;
1050
struct st_mysql_plugin **builtins;
1051
struct st_mysql_plugin *plugin;
1052
struct st_plugin_int tmp, *plugin_ptr, **reap;
1054
DBUG_ENTER("plugin_init");
1059
init_alloc_root(&plugin_mem_root, 4096, 4096);
1060
init_alloc_root(&tmp_root, 4096, 4096);
1062
if (hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
1063
get_bookmark_hash_key, NULL, HASH_UNIQUE))
1067
if (my_init_dynamic_array(&plugin_dl_array,
1068
sizeof(struct st_plugin_dl *),16,16) ||
1069
my_init_dynamic_array(&plugin_array,
1070
sizeof(struct st_plugin_int *),16,16))
1073
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
1075
if (hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
1076
get_plugin_hash_key, NULL, HASH_UNIQUE))
1083
First we register builtin plugins
1085
for (builtins= mysqld_builtins; *builtins; builtins++)
1087
for (plugin= *builtins; plugin->info; plugin++)
1089
/* by default, only ndbcluster is disabled */
1091
my_strcasecmp(&my_charset_latin1, plugin->name, "NDBCLUSTER") != 0;
1092
bzero(&tmp, sizeof(tmp));
1094
tmp.name.str= (char *)plugin->name;
1095
tmp.name.length= strlen(plugin->name);
1097
free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
1098
if (test_plugin_options(&tmp_root, &tmp, argc, argv, def_enabled))
1101
if (register_builtin(plugin, &tmp, &plugin_ptr))
1104
/* only initialize MyISAM and CSV at this stage */
1106
!my_strcasecmp(&my_charset_latin1, plugin->name, "MyISAM")) &&
1107
my_strcasecmp(&my_charset_latin1, plugin->name, "CSV"))
1110
if (plugin_initialize(plugin_ptr))
1114
initialize the global default storage engine so that it may
1115
not be null in any child thread.
1119
DBUG_ASSERT(!global_system_variables.table_plugin);
1120
global_system_variables.table_plugin=
1121
my_intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr));
1122
DBUG_ASSERT(plugin_ptr->ref_count == 1);
1127
/* should now be set to MyISAM storage engine */
1128
DBUG_ASSERT(global_system_variables.table_plugin);
1130
/* Register all dynamic plugins */
1131
if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
1133
if (opt_plugin_load)
1134
plugin_load_list(&tmp_root, argc, argv, opt_plugin_load);
1137
if (flags & PLUGIN_INIT_SKIP_INITIALIZATION)
1141
Now we initialize all remaining plugins
1144
reap= (st_plugin_int **) my_alloca((plugin_array.elements+1) * sizeof(void*));
1147
for (i= 0; i < plugin_array.elements; i++)
1149
plugin_ptr= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
1150
if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED)
1152
if (plugin_initialize(plugin_ptr))
1154
plugin_ptr->state= PLUGIN_IS_DYING;
1155
*(reap++)= plugin_ptr;
1161
Check if any plugins have to be reaped
1163
while ((plugin_ptr= *(--reap)))
1165
plugin_deinitialize(plugin_ptr, true);
1166
plugin_del(plugin_ptr);
1172
free_root(&tmp_root, MYF(0));
1178
free_root(&tmp_root, MYF(0));
1183
static bool register_builtin(struct st_mysql_plugin *plugin,
1184
struct st_plugin_int *tmp,
1185
struct st_plugin_int **ptr)
1187
DBUG_ENTER("register_builtin");
1189
tmp->state= PLUGIN_IS_UNINITIALIZED;
1193
if (insert_dynamic(&plugin_array, (uchar*)&tmp))
1196
*ptr= *dynamic_element(&plugin_array, plugin_array.elements - 1,
1197
struct st_plugin_int **)=
1198
(struct st_plugin_int *) memdup_root(&plugin_mem_root, (uchar*)tmp,
1199
sizeof(struct st_plugin_int));
1201
if (my_hash_insert(&plugin_hash[plugin->type],(uchar*) *ptr))
1210
Register a plugin at run time. (note, this doesn't initialize a plugin)
1211
Will be useful for embedded applications.
1214
plugin_register_builtin()
1215
thd current thread (used to store scratch data in mem_root)
1216
plugin static plugin to install
1219
false - plugin registered successfully
1221
bool plugin_register_builtin(THD *thd, struct st_mysql_plugin *plugin)
1223
struct st_plugin_int tmp, *ptr;
1226
DBUG_ENTER("plugin_register_builtin");
1228
bzero(&tmp, sizeof(tmp));
1230
tmp.name.str= (char *)plugin->name;
1231
tmp.name.length= strlen(plugin->name);
1233
rw_wrlock(&LOCK_system_variables_hash);
1235
if (test_plugin_options(thd->mem_root, &tmp, &dummy_argc, NULL, true))
1238
if ((result= register_builtin(plugin, &tmp, &ptr)))
1239
mysql_del_sys_var_chain(tmp.system_vars);
1242
rw_unlock(&LOCK_system_variables_hash);
1244
DBUG_RETURN(result);;
1246
#endif /* NOT_USED_YET */
1250
called only by plugin_init()
1252
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
1255
char buffer[FN_REFLEN];
1256
LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
1257
struct st_plugin_dl *plugin_dl;
1258
struct st_mysql_plugin *plugin;
1260
DBUG_ENTER("plugin_load_list");
1263
if (p == buffer + sizeof(buffer) - 1)
1265
sql_print_error("plugin-load parameter too long");
1269
switch ((*(p++)= *(list++))) {
1271
list= NULL; /* terminate the loop */
1273
case ':': /* can't use this as delimiter as it may be drive letter */
1275
str->str[str->length]= '\0';
1276
if (str == &name) // load all plugins in named module
1280
p--; /* reset pointer */
1285
if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG)))
1287
for (plugin= plugin_dl->plugins; plugin->info; plugin++)
1289
name.str= (char *) plugin->name;
1290
name.length= strlen(name.str);
1292
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
1293
if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
1296
plugin_dl_del(&dl); // reduce ref count
1301
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
1302
if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
1305
name.length= dl.length= 0;
1306
dl.str= NULL; name.str= p= buffer;
1313
name.str[name.length]= '\0';
1325
sql_print_error("Couldn't load plugin named '%s' with soname '%s'.",
1331
void plugin_shutdown(void)
1333
uint i, count= plugin_array.elements, free_slots= 0;
1334
struct st_plugin_int **plugins, *plugin;
1335
struct st_plugin_dl **dl;
1336
DBUG_ENTER("plugin_shutdown");
1343
We want to shut down plugins in a reasonable order, this will
1344
become important when we have plugins which depend upon each other.
1345
Circular references cannot be reaped so they are forced afterwards.
1346
TODO: Have an additional step here to notify all active plugins that
1347
shutdown is requested to allow plugins to deinitialize in parallel.
1349
while (reap_needed && (count= plugin_array.elements))
1352
for (i= free_slots= 0; i < count; i++)
1354
plugin= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
1355
switch (plugin->state) {
1356
case PLUGIN_IS_READY:
1357
plugin->state= PLUGIN_IS_DELETED;
1360
case PLUGIN_IS_FREED:
1361
case PLUGIN_IS_UNINITIALIZED:
1369
release any plugin references held.
1371
unlock_variables(NULL, &global_system_variables);
1372
unlock_variables(NULL, &max_system_variables);
1376
if (count > free_slots)
1377
sql_print_warning("Forcing shutdown of %d plugins", count - free_slots);
1379
plugins= (struct st_plugin_int **) my_alloca(sizeof(void*) * (count+1));
1382
If we have any plugins which did not die cleanly, we force shutdown
1384
for (i= 0; i < count; i++)
1386
plugins[i]= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
1387
/* change the state to ensure no reaping races */
1388
if (plugins[i]->state == PLUGIN_IS_DELETED)
1389
plugins[i]->state= PLUGIN_IS_DYING;
1393
We loop through all plugins and call deinit() if they have one.
1395
for (i= 0; i < count; i++)
1396
if (!(plugins[i]->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_FREED)))
1398
sql_print_information("Plugin '%s' will be forced to shutdown",
1399
plugins[i]->name.str);
1401
We are forcing deinit on plugins so we don't want to do a ref_count
1402
check until we have processed all the plugins.
1404
plugin_deinitialize(plugins[i], false);
1408
We defer checking ref_counts until after all plugins are deinitialized
1409
as some may have worker threads holding on to plugin references.
1411
for (i= 0; i < count; i++)
1413
if (plugins[i]->ref_count)
1414
sql_print_error("Plugin '%s' has ref_count=%d after shutdown.",
1415
plugins[i]->name.str, plugins[i]->ref_count);
1416
if (plugins[i]->state & PLUGIN_IS_UNINITIALIZED)
1417
plugin_del(plugins[i]);
1421
Now we can deallocate all memory.
1424
cleanup_variables(NULL, &global_system_variables);
1425
cleanup_variables(NULL, &max_system_variables);
1432
/* Dispose of the memory */
1434
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
1435
hash_free(&plugin_hash[i]);
1436
delete_dynamic(&plugin_array);
1438
count= plugin_dl_array.elements;
1439
dl= (struct st_plugin_dl **)my_alloca(sizeof(void*) * count);
1440
for (i= 0; i < count; i++)
1441
dl[i]= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
1442
for (i= 0; i < plugin_dl_array.elements; i++)
1443
free_plugin_mem(dl[i]);
1445
delete_dynamic(&plugin_dl_array);
1447
hash_free(&bookmark_hash);
1448
free_root(&plugin_mem_root, MYF(0));
1450
global_variables_dynamic_size= 0;
1456
bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
1457
int type, uint state_mask, void *arg)
1460
struct st_plugin_int *plugin, **plugins;
1461
int version=plugin_array_version;
1462
DBUG_ENTER("plugin_foreach_with_mask");
1467
state_mask= ~state_mask; // do it only once
1469
total= type == MYSQL_ANY_PLUGIN ? plugin_array.elements
1470
: plugin_hash[type].records;
1472
Do the alloca out here in case we do have a working alloca:
1473
leaving the nested stack frame invalidates alloca allocation.
1475
plugins=(struct st_plugin_int **)my_alloca(total*sizeof(plugin));
1476
if (type == MYSQL_ANY_PLUGIN)
1478
for (idx= 0; idx < total; idx++)
1480
plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
1481
plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
1486
HASH *hash= plugin_hash + type;
1487
for (idx= 0; idx < total; idx++)
1489
plugin= (struct st_plugin_int *) hash_element(hash, idx);
1490
plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
1493
for (idx= 0; idx < total; idx++)
1495
if (unlikely(version != plugin_array_version))
1497
for (uint i=idx; i < total; i++)
1498
if (plugins[i] && plugins[i]->state & state_mask)
1501
plugin= plugins[idx];
1502
/* It will stop iterating on first engine error when "func" returns TRUE */
1503
if (plugin && func(thd, plugin_int_to_ref(plugin), arg))
1515
/****************************************************************************
1516
Internal type declarations for variables support
1517
****************************************************************************/
1519
#undef MYSQL_SYSVAR_NAME
1520
#define MYSQL_SYSVAR_NAME(name) name
1521
#define PLUGIN_VAR_TYPEMASK 0x007f
1523
#define EXTRA_OPTIONS 3 /* options for: 'foo', 'plugin-foo' and NULL */
1525
typedef DECLARE_MYSQL_SYSVAR_BASIC(sysvar_bool_t, my_bool);
1526
typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_bool_t, my_bool);
1527
typedef DECLARE_MYSQL_SYSVAR_BASIC(sysvar_str_t, char *);
1528
typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_str_t, char *);
1530
typedef DECLARE_MYSQL_SYSVAR_TYPELIB(sysvar_enum_t, unsigned long);
1531
typedef DECLARE_MYSQL_THDVAR_TYPELIB(thdvar_enum_t, unsigned long);
1532
typedef DECLARE_MYSQL_SYSVAR_TYPELIB(sysvar_set_t, ulonglong);
1533
typedef DECLARE_MYSQL_THDVAR_TYPELIB(thdvar_set_t, ulonglong);
1535
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_int_t, int);
1536
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_long_t, long);
1537
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_longlong_t, longlong);
1538
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_uint_t, uint);
1539
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulong_t, ulong);
1540
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulonglong_t, ulonglong);
1542
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_int_t, int);
1543
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_long_t, long);
1544
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_longlong_t, longlong);
1545
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_uint_t, uint);
1546
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulong_t, ulong);
1547
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulonglong_t, ulonglong);
1549
#define SET_PLUGIN_VAR_RESOLVE(opt)\
1550
*(mysql_sys_var_ptr_p*)&((opt)->resolve)= mysql_sys_var_ptr
1551
typedef uchar *(*mysql_sys_var_ptr_p)(void* a_thd, int offset);
1554
/****************************************************************************
1555
default variable data check and update functions
1556
****************************************************************************/
1558
static int check_func_bool(THD *thd, struct st_mysql_sys_var *var,
1559
void *save, st_mysql_value *value)
1561
char buff[STRING_BUFFER_USUAL_SIZE];
1562
const char *strvalue= "NULL", *str;
1566
if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
1568
length= sizeof(buff);
1569
if (!(str= value->val_str(value, buff, &length)) ||
1570
(result= find_type(&bool_typelib, str, length, 1)-1) < 0)
1579
if (value->val_int(value, &tmp) < 0)
1589
*(int*)save= -result;
1592
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
1597
static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
1598
void *save, st_mysql_value *value)
1602
struct my_option options;
1603
value->val_int(value, &tmp);
1604
plugin_opt_set_limits(&options, var);
1606
if (var->flags & PLUGIN_VAR_UNSIGNED)
1607
*(uint *)save= (uint) getopt_ull_limit_value((ulonglong) tmp, &options,
1610
*(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed);
1612
return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
1613
var->name, (longlong) tmp);
1617
static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
1618
void *save, st_mysql_value *value)
1622
struct my_option options;
1623
value->val_int(value, &tmp);
1624
plugin_opt_set_limits(&options, var);
1626
if (var->flags & PLUGIN_VAR_UNSIGNED)
1627
*(ulong *)save= (ulong) getopt_ull_limit_value((ulonglong) tmp, &options,
1630
*(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed);
1632
return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
1633
var->name, (longlong) tmp);
1637
static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var,
1638
void *save, st_mysql_value *value)
1642
struct my_option options;
1643
value->val_int(value, &tmp);
1644
plugin_opt_set_limits(&options, var);
1646
if (var->flags & PLUGIN_VAR_UNSIGNED)
1647
*(ulonglong *)save= getopt_ull_limit_value((ulonglong) tmp, &options,
1650
*(longlong *)save= getopt_ll_limit_value(tmp, &options, &fixed);
1652
return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
1653
var->name, (longlong) tmp);
1656
static int check_func_str(THD *thd, struct st_mysql_sys_var *var,
1657
void *save, st_mysql_value *value)
1659
char buff[STRING_BUFFER_USUAL_SIZE];
1663
length= sizeof(buff);
1664
if ((str= value->val_str(value, buff, &length)))
1665
str= thd->strmake(str, length);
1666
*(const char**)save= str;
1671
static int check_func_enum(THD *thd, struct st_mysql_sys_var *var,
1672
void *save, st_mysql_value *value)
1674
char buff[STRING_BUFFER_USUAL_SIZE];
1675
const char *strvalue= "NULL", *str;
1681
if (var->flags & PLUGIN_VAR_THDLOCAL)
1682
typelib= ((thdvar_enum_t*) var)->typelib;
1684
typelib= ((sysvar_enum_t*) var)->typelib;
1686
if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
1688
length= sizeof(buff);
1689
if (!(str= value->val_str(value, buff, &length)))
1691
if ((result= (long)find_type(typelib, str, length, 1)-1) < 0)
1699
if (value->val_int(value, &tmp))
1701
if (tmp >= typelib->count)
1709
*(long*)save= result;
1712
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
1717
static int check_func_set(THD *thd, struct st_mysql_sys_var *var,
1718
void *save, st_mysql_value *value)
1720
char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
1721
const char *strvalue= "NULL", *str;
1728
if (var->flags & PLUGIN_VAR_THDLOCAL)
1729
typelib= ((thdvar_set_t*) var)->typelib;
1731
typelib= ((sysvar_set_t*)var)->typelib;
1733
if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
1735
length= sizeof(buff);
1736
if (!(str= value->val_str(value, buff, &length)))
1738
result= find_set(typelib, str, length, NULL,
1739
&error, &error_len, ¬_used);
1742
strmake(buff, error, min(sizeof(buff), error_len));
1749
if (value->val_int(value, (long long *)&result))
1751
if (unlikely((result >= (ULL(1) << typelib->count)) &&
1752
(typelib->count < sizeof(long)*8)))
1754
llstr(result, buff);
1759
*(ulonglong*)save= result;
1762
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
1767
static void update_func_bool(THD *thd, struct st_mysql_sys_var *var,
1768
void *tgt, const void *save)
1770
*(my_bool *) tgt= *(int *) save ? 1 : 0;
1774
static void update_func_int(THD *thd, struct st_mysql_sys_var *var,
1775
void *tgt, const void *save)
1777
*(int *)tgt= *(int *) save;
1781
static void update_func_long(THD *thd, struct st_mysql_sys_var *var,
1782
void *tgt, const void *save)
1784
*(long *)tgt= *(long *) save;
1788
static void update_func_longlong(THD *thd, struct st_mysql_sys_var *var,
1789
void *tgt, const void *save)
1791
*(longlong *)tgt= *(ulonglong *) save;
1795
static void update_func_str(THD *thd, struct st_mysql_sys_var *var,
1796
void *tgt, const void *save)
1798
char *old= *(char **) tgt;
1799
*(char **)tgt= *(char **) save;
1800
if (var->flags & PLUGIN_VAR_MEMALLOC)
1802
*(char **)tgt= my_strdup(*(char **) save, MYF(0));
1803
my_free(old, MYF(0));
1808
/****************************************************************************
1809
System Variables support
1810
****************************************************************************/
1813
sys_var *find_sys_var(THD *thd, const char *str, uint length)
1816
sys_var_pluginvar *pi= NULL;
1818
DBUG_ENTER("find_sys_var");
1820
rw_rdlock(&LOCK_system_variables_hash);
1821
if ((var= intern_find_sys_var(str, length, false)) &&
1822
(pi= var->cast_pluginvar()))
1824
rw_unlock(&LOCK_system_variables_hash);
1825
LEX *lex= thd ? thd->lex : 0;
1826
if (!(plugin= my_intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
1827
var= NULL; /* failed to lock it, it must be uninstalling */
1829
if (!(plugin_state(plugin) & PLUGIN_IS_READY))
1831
/* initialization not completed */
1833
intern_plugin_unlock(lex, plugin);
1837
rw_unlock(&LOCK_system_variables_hash);
1840
If the variable exists but the plugin it is associated with is not ready
1841
then the intern_plugin_lock did not raise an error, so we do it here.
1844
my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
1850
called by register_var, construct_options and test_plugin_options.
1851
Returns the 'bookmark' for the named variable.
1852
LOCK_system_variables_hash should be at least read locked
1854
static st_bookmark *find_bookmark(const char *plugin, const char *name,
1857
st_bookmark *result= NULL;
1858
uint namelen, length, pluginlen= 0;
1861
if (!(flags & PLUGIN_VAR_THDLOCAL))
1864
namelen= strlen(name);
1866
pluginlen= strlen(plugin) + 1;
1867
length= namelen + pluginlen + 2;
1868
varname= (char*) my_alloca(length);
1872
strxmov(varname + 1, plugin, "_", name, NullS);
1873
for (p= varname + 1; *p; p++)
1878
memcpy(varname + 1, name, namelen + 1);
1880
varname[0]= flags & PLUGIN_VAR_TYPEMASK;
1882
result= (st_bookmark*) hash_search(&bookmark_hash,
1883
(const uchar*) varname, length - 1);
1891
returns a bookmark for thd-local variables, creating if neccessary.
1892
returns null for non thd-local variables.
1893
Requires that a write lock is obtained on LOCK_system_variables_hash
1895
static st_bookmark *register_var(const char *plugin, const char *name,
1898
uint length= strlen(plugin) + strlen(name) + 3, size= 0, offset, new_size;
1899
st_bookmark *result;
1902
if (!(flags & PLUGIN_VAR_THDLOCAL))
1905
switch (flags & PLUGIN_VAR_TYPEMASK) {
1906
case PLUGIN_VAR_BOOL:
1907
size= sizeof(my_bool);
1909
case PLUGIN_VAR_INT:
1912
case PLUGIN_VAR_LONG:
1913
case PLUGIN_VAR_ENUM:
1916
case PLUGIN_VAR_LONGLONG:
1917
case PLUGIN_VAR_SET:
1918
size= sizeof(ulonglong);
1920
case PLUGIN_VAR_STR:
1921
size= sizeof(char*);
1928
varname= ((char*) my_alloca(length));
1929
strxmov(varname + 1, plugin, "_", name, NullS);
1930
for (p= varname + 1; *p; p++)
1934
if (!(result= find_bookmark(NULL, varname + 1, flags)))
1936
result= (st_bookmark*) alloc_root(&plugin_mem_root,
1937
sizeof(struct st_bookmark) + length-1);
1938
varname[0]= flags & PLUGIN_VAR_TYPEMASK;
1939
memcpy(result->key, varname, length);
1940
result->name_len= length - 2;
1943
DBUG_ASSERT(size && !(size & (size-1))); /* must be power of 2 */
1945
offset= global_system_variables.dynamic_variables_size;
1946
offset= (offset + size - 1) & ~(size - 1);
1947
result->offset= (int) offset;
1949
new_size= (offset + size + 63) & ~63;
1951
if (new_size > global_variables_dynamic_size)
1953
global_system_variables.dynamic_variables_ptr= (char*)
1954
my_realloc(global_system_variables.dynamic_variables_ptr, new_size,
1955
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
1956
max_system_variables.dynamic_variables_ptr= (char*)
1957
my_realloc(max_system_variables.dynamic_variables_ptr, new_size,
1958
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
1960
Clear the new variable value space. This is required for string
1961
variables. If their value is non-NULL, it must point to a valid
1964
bzero(global_system_variables.dynamic_variables_ptr +
1965
global_variables_dynamic_size,
1966
new_size - global_variables_dynamic_size);
1967
bzero(max_system_variables.dynamic_variables_ptr +
1968
global_variables_dynamic_size,
1969
new_size - global_variables_dynamic_size);
1970
global_variables_dynamic_size= new_size;
1973
global_system_variables.dynamic_variables_head= offset;
1974
max_system_variables.dynamic_variables_head= offset;
1975
global_system_variables.dynamic_variables_size= offset + size;
1976
max_system_variables.dynamic_variables_size= offset + size;
1977
global_system_variables.dynamic_variables_version++;
1978
max_system_variables.dynamic_variables_version++;
1980
result->version= global_system_variables.dynamic_variables_version;
1982
/* this should succeed because we have already checked if a dup exists */
1983
if (my_hash_insert(&bookmark_hash, (uchar*) result))
1985
fprintf(stderr, "failed to add placeholder to hash");
1995
returns a pointer to the memory which holds the thd-local variable or
1996
a pointer to the global variable if thd==null.
1997
If required, will sync with global variables if the requested variable
1998
has not yet been allocated in the current thread.
2000
static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
2002
DBUG_ASSERT(offset >= 0);
2003
DBUG_ASSERT((uint)offset <= global_system_variables.dynamic_variables_head);
2006
return (uchar*) global_system_variables.dynamic_variables_ptr + offset;
2009
dynamic_variables_head points to the largest valid offset
2011
if (!thd->variables.dynamic_variables_ptr ||
2012
(uint)offset > thd->variables.dynamic_variables_head)
2016
rw_rdlock(&LOCK_system_variables_hash);
2018
thd->variables.dynamic_variables_ptr= (char*)
2019
my_realloc(thd->variables.dynamic_variables_ptr,
2020
global_variables_dynamic_size,
2021
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
2024
pthread_mutex_lock(&LOCK_global_system_variables);
2026
safe_mutex_assert_owner(&LOCK_global_system_variables);
2028
memcpy(thd->variables.dynamic_variables_ptr +
2029
thd->variables.dynamic_variables_size,
2030
global_system_variables.dynamic_variables_ptr +
2031
thd->variables.dynamic_variables_size,
2032
global_system_variables.dynamic_variables_size -
2033
thd->variables.dynamic_variables_size);
2036
now we need to iterate through any newly copied 'defaults'
2037
and if it is a string type with MEMALLOC flag, we need to strdup
2039
for (idx= 0; idx < bookmark_hash.records; idx++)
2041
sys_var_pluginvar *pi;
2043
st_bookmark *v= (st_bookmark*) hash_element(&bookmark_hash,idx);
2045
if (v->version <= thd->variables.dynamic_variables_version ||
2046
!(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
2047
!(pi= var->cast_pluginvar()) ||
2048
v->key[0] != (pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
2051
/* Here we do anything special that may be required of the data types */
2053
if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
2054
pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
2056
char **pp= (char**) (thd->variables.dynamic_variables_ptr +
2057
*(int*)(pi->plugin_var + 1));
2058
if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr +
2059
*(int*)(pi->plugin_var + 1))))
2060
*pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
2065
pthread_mutex_unlock(&LOCK_global_system_variables);
2067
thd->variables.dynamic_variables_version=
2068
global_system_variables.dynamic_variables_version;
2069
thd->variables.dynamic_variables_head=
2070
global_system_variables.dynamic_variables_head;
2071
thd->variables.dynamic_variables_size=
2072
global_system_variables.dynamic_variables_size;
2074
rw_unlock(&LOCK_system_variables_hash);
2076
return (uchar*)thd->variables.dynamic_variables_ptr + offset;
2079
static uchar *mysql_sys_var_ptr(void* a_thd, int offset)
2081
return intern_sys_var_ptr((THD *)a_thd, offset, true);
2085
void plugin_thdvar_init(THD *thd)
2087
plugin_ref old_table_plugin= thd->variables.table_plugin;
2088
DBUG_ENTER("plugin_thdvar_init");
2090
thd->variables.table_plugin= NULL;
2091
cleanup_variables(thd, &thd->variables);
2093
thd->variables= global_system_variables;
2094
thd->variables.table_plugin= NULL;
2096
/* we are going to allocate these lazily */
2097
thd->variables.dynamic_variables_version= 0;
2098
thd->variables.dynamic_variables_size= 0;
2099
thd->variables.dynamic_variables_ptr= 0;
2101
thd->variables.table_plugin=
2102
my_intern_plugin_lock(NULL, global_system_variables.table_plugin);
2103
intern_plugin_unlock(NULL, old_table_plugin);
2109
Unlocks all system variables which hold a reference
2111
static void unlock_variables(THD *thd, struct system_variables *vars)
2113
intern_plugin_unlock(NULL, vars->table_plugin);
2114
vars->table_plugin= NULL;
2119
Frees memory used by system variables
2121
Unlike plugin_vars_free_values() it frees all variables of all plugins,
2122
it's used on shutdown.
2124
static void cleanup_variables(THD *thd, struct system_variables *vars)
2127
sys_var_pluginvar *pivar;
2132
rw_rdlock(&LOCK_system_variables_hash);
2133
for (idx= 0; idx < bookmark_hash.records; idx++)
2135
v= (st_bookmark*) hash_element(&bookmark_hash, idx);
2136
if (v->version > vars->dynamic_variables_version ||
2137
!(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
2138
!(pivar= var->cast_pluginvar()) ||
2139
v->key[0] != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
2142
flags= pivar->plugin_var->flags;
2144
if ((flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
2145
flags & PLUGIN_VAR_THDLOCAL && flags & PLUGIN_VAR_MEMALLOC)
2147
char **ptr= (char**) pivar->real_value_ptr(thd, OPT_SESSION);
2148
my_free(*ptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
2152
rw_unlock(&LOCK_system_variables_hash);
2154
DBUG_ASSERT(vars->table_plugin == NULL);
2156
my_free(vars->dynamic_variables_ptr, MYF(MY_ALLOW_ZERO_PTR));
2157
vars->dynamic_variables_ptr= NULL;
2158
vars->dynamic_variables_size= 0;
2159
vars->dynamic_variables_version= 0;
2163
void plugin_thdvar_cleanup(THD *thd)
2167
DBUG_ENTER("plugin_thdvar_cleanup");
2169
unlock_variables(thd, &thd->variables);
2170
cleanup_variables(thd, &thd->variables);
2172
if ((idx= thd->lex->plugins.elements))
2174
list= ((plugin_ref*) thd->lex->plugins.buffer) + idx - 1;
2175
DBUG_PRINT("info",("unlocking %d plugins", idx));
2176
while ((uchar*) list >= thd->lex->plugins.buffer)
2177
intern_plugin_unlock(NULL, *list--);
2182
reset_dynamic(&thd->lex->plugins);
2189
@brief Free values of thread variables of a plugin.
2191
This must be called before a plugin is deleted. Otherwise its
2192
variables are no longer accessible and the value space is lost. Note
2193
that only string values with PLUGIN_VAR_MEMALLOC are allocated and
2196
@param[in] vars Chain of system variables of a plugin
2199
static void plugin_vars_free_values(sys_var *vars)
2201
DBUG_ENTER("plugin_vars_free_values");
2203
for (sys_var *var= vars; var; var= var->next)
2205
sys_var_pluginvar *piv= var->cast_pluginvar();
2207
((piv->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
2208
(piv->plugin_var->flags & PLUGIN_VAR_MEMALLOC))
2210
/* Free the string from global_system_variables. */
2211
char **valptr= (char**) piv->real_value_ptr(NULL, OPT_GLOBAL);
2212
DBUG_PRINT("plugin", ("freeing value for: '%s' addr: 0x%lx",
2213
var->name, (long) valptr));
2214
my_free(*valptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
2222
bool sys_var_pluginvar::check_update_type(Item_result type)
2226
switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
2227
case PLUGIN_VAR_INT:
2228
case PLUGIN_VAR_LONG:
2229
case PLUGIN_VAR_LONGLONG:
2230
return type != INT_RESULT;
2231
case PLUGIN_VAR_STR:
2232
return type != STRING_RESULT;
2239
SHOW_TYPE sys_var_pluginvar::show_type()
2241
switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
2242
case PLUGIN_VAR_BOOL:
2243
return SHOW_MY_BOOL;
2244
case PLUGIN_VAR_INT:
2246
case PLUGIN_VAR_LONG:
2248
case PLUGIN_VAR_LONGLONG:
2249
return SHOW_LONGLONG;
2250
case PLUGIN_VAR_STR:
2251
return SHOW_CHAR_PTR;
2252
case PLUGIN_VAR_ENUM:
2253
case PLUGIN_VAR_SET:
2262
uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type)
2264
DBUG_ASSERT(thd || (type == OPT_GLOBAL));
2265
if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
2267
if (type == OPT_GLOBAL)
2270
return intern_sys_var_ptr(thd, *(int*) (plugin_var+1), false);
2272
return *(uchar**) (plugin_var+1);
2276
TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
2278
switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) {
2279
case PLUGIN_VAR_ENUM:
2280
return ((sysvar_enum_t *)plugin_var)->typelib;
2281
case PLUGIN_VAR_SET:
2282
return ((sysvar_set_t *)plugin_var)->typelib;
2283
case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
2284
return ((thdvar_enum_t *)plugin_var)->typelib;
2285
case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
2286
return ((thdvar_set_t *)plugin_var)->typelib;
2294
uchar* sys_var_pluginvar::value_ptr(THD *thd, enum_var_type type,
2299
result= real_value_ptr(thd, type);
2301
if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_ENUM)
2302
result= (uchar*) get_type(plugin_var_typelib(), *(ulong*)result);
2303
else if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_SET)
2305
char buffer[STRING_BUFFER_USUAL_SIZE];
2306
String str(buffer, sizeof(buffer), system_charset_info);
2307
TYPELIB *typelib= plugin_var_typelib();
2308
ulonglong mask= 1, value= *(ulonglong*) result;
2312
for (i= 0; i < typelib->count; i++, mask<<=1)
2314
if (!(value & mask))
2316
str.append(typelib->type_names[i], typelib->type_lengths[i]);
2320
result= (uchar*) "";
2322
result= (uchar*) thd->strmake(str.ptr(), str.length()-1);
2328
bool sys_var_pluginvar::check(THD *thd, set_var *var)
2330
st_item_value_holder value;
2331
DBUG_ASSERT(is_readonly() || plugin_var->check);
2333
value.value_type= item_value_type;
2334
value.val_str= item_val_str;
2335
value.val_int= item_val_int;
2336
value.val_real= item_val_real;
2337
value.item= var->value;
2339
return is_readonly() ||
2340
plugin_var->check(thd, plugin_var, &var->save_result, &value);
2344
void sys_var_pluginvar::set_default(THD *thd, enum_var_type type)
2349
DBUG_ASSERT(is_readonly() || plugin_var->update);
2354
pthread_mutex_lock(&LOCK_global_system_variables);
2355
tgt= real_value_ptr(thd, type);
2356
src= ((void **) (plugin_var + 1) + 1);
2358
if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
2360
if (type != OPT_GLOBAL)
2361
src= real_value_ptr(thd, OPT_GLOBAL);
2363
switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
2364
case PLUGIN_VAR_INT:
2365
src= &((thdvar_uint_t*) plugin_var)->def_val;
2367
case PLUGIN_VAR_LONG:
2368
src= &((thdvar_ulong_t*) plugin_var)->def_val;
2370
case PLUGIN_VAR_LONGLONG:
2371
src= &((thdvar_ulonglong_t*) plugin_var)->def_val;
2373
case PLUGIN_VAR_ENUM:
2374
src= &((thdvar_enum_t*) plugin_var)->def_val;
2376
case PLUGIN_VAR_SET:
2377
src= &((thdvar_set_t*) plugin_var)->def_val;
2379
case PLUGIN_VAR_BOOL:
2380
src= &((thdvar_bool_t*) plugin_var)->def_val;
2382
case PLUGIN_VAR_STR:
2383
src= &((thdvar_str_t*) plugin_var)->def_val;
2390
/* thd must equal current_thd if PLUGIN_VAR_THDLOCAL flag is set */
2391
DBUG_ASSERT(!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ||
2392
thd == current_thd);
2394
if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || type == OPT_GLOBAL)
2396
plugin_var->update(thd, plugin_var, tgt, src);
2397
pthread_mutex_unlock(&LOCK_global_system_variables);
2401
pthread_mutex_unlock(&LOCK_global_system_variables);
2402
plugin_var->update(thd, plugin_var, tgt, src);
2407
bool sys_var_pluginvar::update(THD *thd, set_var *var)
2411
DBUG_ASSERT(is_readonly() || plugin_var->update);
2413
/* thd must equal current_thd if PLUGIN_VAR_THDLOCAL flag is set */
2414
DBUG_ASSERT(!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ||
2415
thd == current_thd);
2420
pthread_mutex_lock(&LOCK_global_system_variables);
2421
tgt= real_value_ptr(thd, var->type);
2423
if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || var->type == OPT_GLOBAL)
2425
/* variable we are updating has global scope, so we unlock after updating */
2426
plugin_var->update(thd, plugin_var, tgt, &var->save_result);
2427
pthread_mutex_unlock(&LOCK_global_system_variables);
2431
pthread_mutex_unlock(&LOCK_global_system_variables);
2432
plugin_var->update(thd, plugin_var, tgt, &var->save_result);
2438
#define OPTION_SET_LIMITS(type, options, opt) \
2439
options->var_type= type; \
2440
options->def_value= (opt)->def_val; \
2441
options->min_value= (opt)->min_val; \
2442
options->max_value= (opt)->max_val; \
2443
options->block_size= (long) (opt)->blk_sz
2446
static void plugin_opt_set_limits(struct my_option *options,
2447
const struct st_mysql_sys_var *opt)
2449
options->sub_size= 0;
2451
switch (opt->flags & (PLUGIN_VAR_TYPEMASK |
2452
PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL)) {
2453
/* global system variables */
2454
case PLUGIN_VAR_INT:
2455
OPTION_SET_LIMITS(GET_INT, options, (sysvar_int_t*) opt);
2457
case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED:
2458
OPTION_SET_LIMITS(GET_UINT, options, (sysvar_uint_t*) opt);
2460
case PLUGIN_VAR_LONG:
2461
OPTION_SET_LIMITS(GET_LONG, options, (sysvar_long_t*) opt);
2463
case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
2464
OPTION_SET_LIMITS(GET_ULONG, options, (sysvar_ulong_t*) opt);
2466
case PLUGIN_VAR_LONGLONG:
2467
OPTION_SET_LIMITS(GET_LL, options, (sysvar_longlong_t*) opt);
2469
case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
2470
OPTION_SET_LIMITS(GET_ULL, options, (sysvar_ulonglong_t*) opt);
2472
case PLUGIN_VAR_ENUM:
2473
options->var_type= GET_ENUM;
2474
options->typelib= ((sysvar_enum_t*) opt)->typelib;
2475
options->def_value= ((sysvar_enum_t*) opt)->def_val;
2476
options->min_value= options->block_size= 0;
2477
options->max_value= options->typelib->count - 1;
2479
case PLUGIN_VAR_SET:
2480
options->var_type= GET_SET;
2481
options->typelib= ((sysvar_set_t*) opt)->typelib;
2482
options->def_value= ((sysvar_set_t*) opt)->def_val;
2483
options->min_value= options->block_size= 0;
2484
options->max_value= (ULL(1) << options->typelib->count) - 1;
2486
case PLUGIN_VAR_BOOL:
2487
options->var_type= GET_BOOL;
2488
options->def_value= ((sysvar_bool_t*) opt)->def_val;
2490
case PLUGIN_VAR_STR:
2491
options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
2492
GET_STR_ALLOC : GET_STR);
2493
options->def_value= (intptr) ((sysvar_str_t*) opt)->def_val;
2495
/* threadlocal variables */
2496
case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
2497
OPTION_SET_LIMITS(GET_INT, options, (thdvar_int_t*) opt);
2499
case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
2500
OPTION_SET_LIMITS(GET_UINT, options, (thdvar_uint_t*) opt);
2502
case PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL:
2503
OPTION_SET_LIMITS(GET_LONG, options, (thdvar_long_t*) opt);
2505
case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
2506
OPTION_SET_LIMITS(GET_ULONG, options, (thdvar_ulong_t*) opt);
2508
case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL:
2509
OPTION_SET_LIMITS(GET_LL, options, (thdvar_longlong_t*) opt);
2511
case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
2512
OPTION_SET_LIMITS(GET_ULL, options, (thdvar_ulonglong_t*) opt);
2514
case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
2515
options->var_type= GET_ENUM;
2516
options->typelib= ((thdvar_enum_t*) opt)->typelib;
2517
options->def_value= ((thdvar_enum_t*) opt)->def_val;
2518
options->min_value= options->block_size= 0;
2519
options->max_value= options->typelib->count - 1;
2521
case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
2522
options->var_type= GET_SET;
2523
options->typelib= ((thdvar_set_t*) opt)->typelib;
2524
options->def_value= ((thdvar_set_t*) opt)->def_val;
2525
options->min_value= options->block_size= 0;
2526
options->max_value= (ULL(1) << options->typelib->count) - 1;
2528
case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL:
2529
options->var_type= GET_BOOL;
2530
options->def_value= ((thdvar_bool_t*) opt)->def_val;
2532
case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL:
2533
options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
2534
GET_STR_ALLOC : GET_STR);
2535
options->def_value= (intptr) ((thdvar_str_t*) opt)->def_val;
2540
options->arg_type= REQUIRED_ARG;
2541
if (opt->flags & PLUGIN_VAR_NOCMDARG)
2542
options->arg_type= NO_ARG;
2543
if (opt->flags & PLUGIN_VAR_OPCMDARG)
2544
options->arg_type= OPT_ARG;
2547
extern "C" my_bool get_one_plugin_option(int optid, const struct my_option *,
2550
my_bool get_one_plugin_option(int optid __attribute__((unused)),
2551
const struct my_option *opt,
2558
static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
2559
my_option *options, my_bool **enabled,
2562
const char *plugin_name= tmp->plugin->name;
2563
uint namelen= strlen(plugin_name), optnamelen;
2564
uint buffer_length= namelen * 4 + (can_disable ? 75 : 10);
2565
char *name= (char*) alloc_root(mem_root, buffer_length) + 1;
2567
int index= 0, offset= 0;
2568
st_mysql_sys_var *opt, **plugin_option;
2570
DBUG_ENTER("construct_options");
2571
DBUG_PRINT("plugin", ("plugin: '%s' enabled: %d can_disable: %d",
2572
plugin_name, **enabled, can_disable));
2574
/* support --skip-plugin-foo syntax */
2575
memcpy(name, plugin_name, namelen + 1);
2576
my_casedn_str(&my_charset_latin1, name);
2577
strxmov(name + namelen + 1, "plugin-", name, NullS);
2578
/* Now we have namelen + 1 + 7 + namelen + 1 == namelen * 2 + 9. */
2580
for (p= name + namelen*2 + 8; p > name; p--)
2586
strxmov(name + namelen*2 + 10, "Enable ", plugin_name, " plugin. "
2587
"Disable with --skip-", name," (will save memory).", NullS);
2589
Now we have namelen * 2 + 10 (one char unused) + 7 + namelen + 9 +
2590
20 + namelen + 20 + 1 == namelen * 4 + 67.
2593
options[0].comment= name + namelen*2 + 10;
2597
NOTE: 'name' is one char above the allocated buffer!
2598
NOTE: This code assumes that 'my_bool' and 'char' are of same size.
2600
*((my_bool *)(name -1))= **enabled;
2601
*enabled= (my_bool *)(name - 1);
2604
options[1].name= (options[0].name= name) + namelen + 1;
2605
options[0].id= options[1].id= 256; /* must be >255. dup id ok */
2606
options[0].var_type= options[1].var_type= GET_BOOL;
2607
options[0].arg_type= options[1].arg_type= NO_ARG;
2608
options[0].def_value= options[1].def_value= **enabled;
2609
options[0].value= options[0].u_max_value=
2610
options[1].value= options[1].u_max_value= (uchar**) (name - 1);
2614
Two passes as the 2nd pass will take pointer addresses for use
2615
by my_getopt and register_var() in the first pass uses realloc
2618
for (plugin_option= tmp->plugin->system_vars;
2619
plugin_option && *plugin_option; plugin_option++, index++)
2621
opt= *plugin_option;
2622
if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
2624
if (!(register_var(name, opt->name, opt->flags)))
2626
switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
2627
case PLUGIN_VAR_BOOL:
2628
SET_PLUGIN_VAR_RESOLVE((thdvar_bool_t *) opt);
2630
case PLUGIN_VAR_INT:
2631
SET_PLUGIN_VAR_RESOLVE((thdvar_int_t *) opt);
2633
case PLUGIN_VAR_LONG:
2634
SET_PLUGIN_VAR_RESOLVE((thdvar_long_t *) opt);
2636
case PLUGIN_VAR_LONGLONG:
2637
SET_PLUGIN_VAR_RESOLVE((thdvar_longlong_t *) opt);
2639
case PLUGIN_VAR_STR:
2640
SET_PLUGIN_VAR_RESOLVE((thdvar_str_t *) opt);
2642
case PLUGIN_VAR_ENUM:
2643
SET_PLUGIN_VAR_RESOLVE((thdvar_enum_t *) opt);
2645
case PLUGIN_VAR_SET:
2646
SET_PLUGIN_VAR_RESOLVE((thdvar_set_t *) opt);
2649
sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
2650
opt->flags, plugin_name);
2655
for (plugin_option= tmp->plugin->system_vars;
2656
plugin_option && *plugin_option; plugin_option++, index++)
2658
switch ((opt= *plugin_option)->flags & PLUGIN_VAR_TYPEMASK) {
2659
case PLUGIN_VAR_BOOL:
2661
opt->check= check_func_bool;
2663
opt->update= update_func_bool;
2665
case PLUGIN_VAR_INT:
2667
opt->check= check_func_int;
2669
opt->update= update_func_int;
2671
case PLUGIN_VAR_LONG:
2673
opt->check= check_func_long;
2675
opt->update= update_func_long;
2677
case PLUGIN_VAR_LONGLONG:
2679
opt->check= check_func_longlong;
2681
opt->update= update_func_longlong;
2683
case PLUGIN_VAR_STR:
2685
opt->check= check_func_str;
2688
opt->update= update_func_str;
2689
if (!(opt->flags & PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY))
2691
opt->flags|= PLUGIN_VAR_READONLY;
2692
sql_print_warning("Server variable %s of plugin %s was forced "
2693
"to be read-only: string variable without "
2694
"update_func and PLUGIN_VAR_MEMALLOC flag",
2695
opt->name, plugin_name);
2699
case PLUGIN_VAR_ENUM:
2701
opt->check= check_func_enum;
2703
opt->update= update_func_long;
2705
case PLUGIN_VAR_SET:
2707
opt->check= check_func_set;
2709
opt->update= update_func_longlong;
2712
sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
2713
opt->flags, plugin_name);
2717
if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_THDLOCAL))
2718
== PLUGIN_VAR_NOCMDOPT)
2723
sql_print_error("Missing variable name in plugin '%s'.",
2728
if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
2730
optnamelen= strlen(opt->name);
2731
optname= (char*) alloc_root(mem_root, namelen + optnamelen + 2);
2732
strxmov(optname, name, "-", opt->name, NullS);
2733
optnamelen= namelen + optnamelen + 1;
2737
/* this should not fail because register_var should create entry */
2738
if (!(v= find_bookmark(name, opt->name, opt->flags)))
2740
sql_print_error("Thread local variable '%s' not allocated "
2741
"in plugin '%s'.", opt->name, plugin_name);
2745
*(int*)(opt + 1)= offset= v->offset;
2747
if (opt->flags & PLUGIN_VAR_NOCMDOPT)
2750
optname= (char*) memdup_root(mem_root, v->key + 1,
2751
(optnamelen= v->name_len) + 1);
2754
/* convert '_' to '-' */
2755
for (p= optname; *p; p++)
2759
options->name= optname;
2760
options->comment= opt->comment;
2761
options->app_type= opt;
2762
options->id= (options-1)->id + 1;
2764
plugin_opt_set_limits(options, opt);
2766
if (opt->flags & PLUGIN_VAR_THDLOCAL)
2767
options->value= options->u_max_value= (uchar**)
2768
(global_system_variables.dynamic_variables_ptr + offset);
2770
options->value= options->u_max_value= *(uchar***) (opt + 1);
2772
options[1]= options[0];
2773
options[1].name= p= (char*) alloc_root(mem_root, optnamelen + 8);
2774
options[1].comment= 0; // hidden
2775
strxmov(p, "plugin-", optname, NullS);
2784
static my_option *construct_help_options(MEM_ROOT *mem_root,
2785
struct st_plugin_int *p)
2787
st_mysql_sys_var **opt;
2789
my_bool dummy, can_disable;
2790
my_bool *dummy2= &dummy;
2791
uint count= EXTRA_OPTIONS;
2792
DBUG_ENTER("construct_help_options");
2794
for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2);
2796
if (!(opts= (my_option*) alloc_root(mem_root, sizeof(my_option) * count)))
2799
bzero(opts, sizeof(my_option) * count);
2801
dummy= TRUE; /* plugin is enabled. */
2804
my_strcasecmp(&my_charset_latin1, p->name.str, "MyISAM") &&
2805
my_strcasecmp(&my_charset_latin1, p->name.str, "MEMORY");
2807
if (construct_options(mem_root, p, opts, &dummy2, can_disable))
2816
test_plugin_options()
2817
tmp_root temporary scratch space
2818
plugin internal plugin structure
2819
argc user supplied arguments
2820
argv user supplied arguments
2821
default_enabled default plugin enable status
2823
0 SUCCESS - plugin should be enabled/loaded
2825
Requires that a write-lock is held on LOCK_system_variables_hash
2827
static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
2828
int *argc, char **argv, my_bool default_enabled)
2830
struct sys_var_chain chain= { NULL, NULL };
2831
my_bool enabled_saved= default_enabled, can_disable;
2832
my_bool *enabled= &default_enabled;
2833
MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ?
2834
&tmp->mem_root : &plugin_mem_root;
2835
st_mysql_sys_var **opt;
2836
my_option *opts= NULL;
2839
st_mysql_sys_var *o;
2841
struct st_bookmark *var;
2842
uint len, count= EXTRA_OPTIONS;
2843
DBUG_ENTER("test_plugin_options");
2844
DBUG_ASSERT(tmp->plugin && tmp->name.str);
2846
for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
2847
count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
2850
my_strcasecmp(&my_charset_latin1, tmp->name.str, "MyISAM") &&
2851
my_strcasecmp(&my_charset_latin1, tmp->name.str, "MEMORY");
2853
if (count > EXTRA_OPTIONS || (*argc > 1))
2855
if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count)))
2857
sql_print_error("Out of memory for plugin '%s'.", tmp->name.str);
2860
bzero(opts, sizeof(my_option) * count);
2862
if (construct_options(tmp_root, tmp, opts, &enabled, can_disable))
2864
sql_print_error("Bad options for plugin '%s'.", tmp->name.str);
2868
error= handle_options(argc, &argv, opts, get_one_plugin_option);
2869
(*argc)++; /* add back one for the program name */
2873
sql_print_error("Parsing options for plugin '%s' failed.",
2879
if (!*enabled && !can_disable)
2881
sql_print_warning("Plugin '%s' cannot be disabled", tmp->name.str);
2889
for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
2891
if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
2894
if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
2895
v= new (mem_root) sys_var_pluginvar(var->key + 1, o);
2898
len= tmp->name.length + strlen(o->name) + 2;
2899
varname= (char*) alloc_root(mem_root, len);
2900
strxmov(varname, tmp->name.str, "-", o->name, NullS);
2901
my_casedn_str(&my_charset_latin1, varname);
2903
for (p= varname; *p; p++)
2907
v= new (mem_root) sys_var_pluginvar(varname, o);
2909
DBUG_ASSERT(v); /* check that an object was actually constructed */
2912
Add to the chain of variables.
2913
Done like this for easier debugging so that the
2914
pointer to v is not lost on optimized builds.
2916
v->chain_sys_var(&chain);
2920
chain.last->next = NULL;
2921
if (mysql_add_sys_var_chain(chain.first, NULL))
2923
sql_print_error("Plugin '%s' has conflicting system variables",
2927
tmp->system_vars= chain.first;
2932
if (enabled_saved && global_system_variables.log_warnings)
2933
sql_print_information("Plugin '%s' disabled by command line option",
2937
my_cleanup_options(opts);
2942
/****************************************************************************
2943
Help Verbose text with Plugin System Variables
2944
****************************************************************************/
2946
static int option_cmp(my_option *a, my_option *b)
2948
return my_strcasecmp(&my_charset_latin1, a->name, b->name);
2952
void my_print_help_inc_plugins(my_option *main_options, uint size)
2954
DYNAMIC_ARRAY all_options;
2955
struct st_plugin_int *p;
2959
init_alloc_root(&mem_root, 4096, 4096);
2960
my_init_dynamic_array(&all_options, sizeof(my_option), size, size/4);
2963
for (uint idx= 0; idx < plugin_array.elements; idx++)
2965
p= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
2967
if (!p->plugin->system_vars ||
2968
!(opt= construct_help_options(&mem_root, p)))
2971
/* Only options with a non-NULL comment are displayed in help text */
2972
for (;opt->id; opt++)
2974
insert_dynamic(&all_options, (uchar*) opt);
2977
for (;main_options->id; main_options++)
2978
insert_dynamic(&all_options, (uchar*) main_options);
2980
sort_dynamic(&all_options, (qsort_cmp) option_cmp);
2982
/* main_options now points to the empty option terminator */
2983
insert_dynamic(&all_options, (uchar*) main_options);
2985
my_print_help((my_option*) all_options.buffer);
2986
my_print_variables((my_option*) all_options.buffer);
2988
delete_dynamic(&all_options);
2989
free_root(&mem_root, MYF(0));