~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2005 MySQL AB
2
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.
6
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.
11
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 */
15
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
21
22
#ifdef DBUG_OFF
23
#define plugin_ref_to_int(A) A
24
#define plugin_int_to_ref(A) A
25
#else
26
#define plugin_ref_to_int(A) (A ? A[0] : NULL)
27
#define plugin_int_to_ref(A) &(A)
28
#endif
29
30
extern struct st_mysql_plugin *mysqld_builtins[];
31
32
char *opt_plugin_load= NULL;
33
char *opt_plugin_dir_ptr;
34
char opt_plugin_dir[FN_REFLEN];
35
/*
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.
38
*/
39
const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
40
{
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") }
47
};
48
49
extern int initialize_schema_table(st_plugin_int *plugin);
50
extern int finalize_schema_table(st_plugin_int *plugin);
51
52
/*
53
  The number of elements in both plugin_type_initialize and
54
  plugin_type_deinitialize should equal to the number of plugins
55
  defined.
56
*/
57
plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
58
{
59
  0,ha_initialize_handlerton,0,0,initialize_schema_table,
60
  0
61
};
62
63
plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
64
{
65
  0,ha_finalize_handlerton,0,0,finalize_schema_table,
66
  0
67
};
68
69
#ifdef HAVE_DLOPEN
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;
76
#endif
77
78
/* Note that 'int version' must be the first field of every plugin
79
   sub-structure (plugin->info).
80
*/
81
static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
82
{
83
  0x0000,
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
89
};
90
static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
91
{
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
98
};
99
100
static bool initialized= 0;
101
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;
107
108
/*
109
  write-lock on LOCK_system_variables_hash is required before modifying
110
  the following variables/structures
111
*/
112
static MEM_ROOT plugin_mem_root;
113
static uint global_variables_dynamic_size= 0;
114
static HASH bookmark_hash;
115
116
117
/*
118
  hidden part of opaque value passed to variable check functions.
119
  Used to provide a object-like structure to non C++ consumers.
120
*/
121
struct st_item_value_holder : public st_mysql_value
122
{
123
  Item *item;
124
};
125
126
127
/*
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.
132
133
  The key format is as follows:
134
    1 byte         - variable type code
135
    name_len bytes - variable name
136
    '\0'           - end of key
137
*/
138
struct st_bookmark
139
{
140
  uint name_len;
141
  int offset;
142
  uint version;
143
  char key[1];
144
};
145
146
147
/*
148
  skeleton of a plugin variable - portion of structure common to all.
149
*/
150
struct st_mysql_sys_var
151
{
152
  MYSQL_PLUGIN_VAR_HEADER;
153
};
154
155
156
/*
157
  sys_var class for access to all plugin variables visible to the user
158
*/
159
class sys_var_pluginvar: public sys_var
160
{
161
public:
162
  struct st_plugin_int *plugin;
163
  struct st_mysql_sys_var *plugin_var;
164
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); }
169
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);
186
};
187
188
189
/* prototypes */
190
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
191
                             const char *list);
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
204
                                     CALLER_INFO_PROTO);
205
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
206
static void reap_plugins(void);
207
208
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);
213
214
/****************************************************************************
215
  Value type thunks, allows the C world to play in the C++ world
216
****************************************************************************/
217
218
static int item_value_type(struct st_mysql_value *value)
219
{
220
  switch (((st_item_value_holder*)value)->item->result_type()) {
221
  case INT_RESULT:
222
    return MYSQL_VALUE_TYPE_INT;
223
  case REAL_RESULT:
224
    return MYSQL_VALUE_TYPE_REAL;
225
  default:
226
    return MYSQL_VALUE_TYPE_STRING;
227
  }
228
}
229
230
static const char *item_val_str(struct st_mysql_value *value,
231
                                char *buffer, int *length)
232
{
233
  String str(buffer, *length, system_charset_info), *res;
234
  if (!(res= ((st_item_value_holder*)value)->item->val_str(&str)))
235
    return NULL;
236
  *length= res->length();
237
  if (res->c_ptr_quick() == buffer)
238
    return buffer;
239
240
  /*
241
    Lets be nice and create a temporary string since the
242
    buffer was too small
243
  */
244
  return current_thd->strmake(res->c_ptr_quick(), res->length());
245
}
246
247
248
static int item_val_int(struct st_mysql_value *value, long long *buf)
249
{
250
  Item *item= ((st_item_value_holder*)value)->item;
251
  *buf= item->val_int();
252
  if (item->is_null())
253
    return 1;
254
  return 0;
255
}
256
257
258
static int item_val_real(struct st_mysql_value *value, double *buf)
259
{
260
  Item *item= ((st_item_value_holder*)value)->item;
261
  *buf= item->val_real();
262
  if (item->is_null())
263
    return 1;
264
  return 0;
265
}
266
267
268
/****************************************************************************
269
  Plugin support code
270
****************************************************************************/
271
272
#ifdef HAVE_DLOPEN
273
274
static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl)
275
{
276
  uint i;
277
  struct st_plugin_dl *tmp;
278
  DBUG_ENTER("plugin_dl_find");
279
  for (i= 0; i < plugin_dl_array.elements; i++)
280
  {
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))
286
      DBUG_RETURN(tmp);
287
  }
288
  DBUG_RETURN(0);
289
}
290
291
292
static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
293
{
294
  uint i;
295
  struct st_plugin_dl *tmp;
296
  DBUG_ENTER("plugin_dl_insert_or_reuse");
297
  for (i= 0; i < plugin_dl_array.elements; i++)
298
  {
299
    tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
300
    if (! tmp->ref_count)
301
    {
302
      memcpy(tmp, plugin_dl, sizeof(struct st_plugin_dl));
303
      DBUG_RETURN(tmp);
304
    }
305
  }
306
  if (insert_dynamic(&plugin_dl_array, (uchar*)&plugin_dl))
307
    DBUG_RETURN(0);
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));
312
  DBUG_RETURN(tmp);
313
}
314
#endif /* HAVE_DLOPEN */
315
316
317
static inline void free_plugin_mem(struct st_plugin_dl *p)
318
{
319
#ifdef HAVE_DLOPEN
320
  if (p->handle)
321
    dlclose(p->handle);
322
#endif
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));
326
}
327
328
329
static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
330
{
331
#ifdef HAVE_DLOPEN
332
  char dlpath[FN_REFLEN];
333
  uint plugin_dir_len, dummy_errors, dlpathlen;
334
  struct st_plugin_dl *tmp, plugin_dl;
335
  void *sym;
336
  DBUG_ENTER("plugin_dl_add");
337
  plugin_dir_len= strlen(opt_plugin_dir);
338
  /*
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).
342
  */
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)
347
  {
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));
352
    DBUG_RETURN(0);
353
  }
354
  /* If this dll is already loaded just increase ref_count. */
355
  if ((tmp= plugin_dl_find(dl)))
356
  {
357
    tmp->ref_count++;
358
    DBUG_RETURN(tmp);
359
  }
360
  bzero(&plugin_dl, sizeof(plugin_dl));
361
  /* Compile dll path */
362
  dlpathlen=
363
    strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS) -
364
    dlpath;
365
  plugin_dl.ref_count= 1;
366
  /* Open new dll handle */
367
  if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW)))
368
  {
369
    const char *errmsg=dlerror();
370
    if (!strncmp(dlpath, errmsg, dlpathlen))
371
    { // if errmsg starts from dlpath, trim this prefix.
372
      errmsg+=dlpathlen;
373
      if (*errmsg == ':') errmsg++;
374
      if (*errmsg == ' ') errmsg++;
375
    }
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);
380
    DBUG_RETURN(0);
381
  }
382
  /* Determine interface version */
383
  if (!(sym= dlsym(plugin_dl.handle, plugin_interface_version_sym)))
384
  {
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);
390
    DBUG_RETURN(0);
391
  }
392
  plugin_dl.version= *(int *)sym;
393
  /* Versioning */
394
  if (plugin_dl.version < min_plugin_interface_version ||
395
      (plugin_dl.version >> 8) > (MYSQL_PLUGIN_INTERFACE_VERSION >> 8))
396
  {
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");
404
    DBUG_RETURN(0);
405
  }
406
  /* Find plugin declarations */
407
  if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))
408
  {
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);
414
    DBUG_RETURN(0);
415
  }
416
417
  if (plugin_dl.version != MYSQL_PLUGIN_INTERFACE_VERSION)
418
  {
419
    int i;
420
    uint sizeof_st_plugin;
421
    struct st_mysql_plugin *old, *cur;
422
    char *ptr= (char *)sym;
423
424
    if ((sym= dlsym(plugin_dl.handle, sizeof_st_plugin_sym)))
425
      sizeof_st_plugin= *(int *)sym;
426
    else
427
    {
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);
434
      DBUG_RETURN(0);
435
#else
436
      /*
437
        When the following assert starts failing, we'll have to switch
438
        to the upper branch of the #ifdef
439
      */
440
      DBUG_ASSERT(min_plugin_interface_version == 0);
441
      sizeof_st_plugin= (int)offsetof(struct st_mysql_plugin, version);
442
#endif
443
    }
444
445
    for (i= 0;
446
         ((struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info;
447
         i++)
448
      /* no op */;
449
450
    cur= (struct st_mysql_plugin*)
451
          my_malloc(i*sizeof(struct st_mysql_plugin), MYF(MY_ZEROFILL|MY_WME));
452
    if (!cur)
453
    {
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);
459
      DBUG_RETURN(0);
460
    }
461
    /*
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.
465
    */
466
    for (i=0;
467
         (old=(struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info;
468
         i++)
469
      memcpy(cur+i, old, min(sizeof(cur[i]), sizeof_st_plugin));
470
471
    sym= cur;
472
  }
473
  plugin_dl.plugins= (struct st_mysql_plugin *)sym;
474
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))))
478
  {
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);
484
    DBUG_RETURN(0);
485
  }
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,
488
    &dummy_errors);
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)))
492
  {
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));
498
    DBUG_RETURN(0);
499
  }
500
  DBUG_RETURN(tmp);
501
#else
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");
507
  DBUG_RETURN(0);
508
#endif
509
}
510
511
512
static void plugin_dl_del(const LEX_STRING *dl)
513
{
514
#ifdef HAVE_DLOPEN
515
  uint i;
516
  DBUG_ENTER("plugin_dl_del");
517
518
  for (i= 0; i < plugin_dl_array.elements; i++)
519
  {
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))
526
    {
527
      /* Do not remove this element, unless no other plugin uses this dll. */
528
      if (! --tmp->ref_count)
529
      {
530
        free_plugin_mem(tmp);
531
        bzero(tmp, sizeof(struct st_plugin_dl));
532
      }
533
      break;
534
    }
535
  }
536
  DBUG_VOID_RETURN;
537
#endif
538
}
539
540
541
static struct st_plugin_int *plugin_find_internal(const LEX_STRING *name, int type)
542
{
543
  uint i;
544
  DBUG_ENTER("plugin_find_internal");
545
  if (! initialized)
546
    DBUG_RETURN(0);
547
548
  if (type == MYSQL_ANY_PLUGIN)
549
  {
550
    for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
551
    {
552
      struct st_plugin_int *plugin= (st_plugin_int *)
553
        hash_search(&plugin_hash[i], (const uchar *)name->str, name->length);
554
      if (plugin)
555
        DBUG_RETURN(plugin);
556
    }
557
  }
558
  else
559
    DBUG_RETURN((st_plugin_int *)
560
        hash_search(&plugin_hash[type], (const uchar *)name->str, name->length));
561
  DBUG_RETURN(0);
562
}
563
564
565
static SHOW_COMP_OPTION plugin_status(const LEX_STRING *name, int type)
566
{
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)))
571
  {
572
    rc= SHOW_OPTION_DISABLED;
573
    if (plugin->state == PLUGIN_IS_READY)
574
      rc= SHOW_OPTION_YES;
575
  }
576
  DBUG_RETURN(rc);
577
}
578
579
580
bool plugin_is_ready(const LEX_STRING *name, int type)
581
{
582
  bool rc= FALSE;
583
  if (plugin_status(name, type) == SHOW_OPTION_YES)
584
    rc= TRUE;
585
  return rc;
586
}
587
588
589
SHOW_COMP_OPTION sys_var_have_plugin::get_option()
590
{
591
  LEX_STRING plugin_name= { (char *) plugin_name_str, plugin_name_len };
592
  return plugin_status(&plugin_name, plugin_type);
593
}
594
595
596
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc CALLER_INFO_PROTO)
597
{
598
  st_plugin_int *pi= plugin_ref_to_int(rc);
599
  DBUG_ENTER("intern_plugin_lock");
600
601
  if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
602
  {
603
    plugin_ref plugin;
604
#ifdef DBUG_OFF
605
    /* built-in plugins don't need ref counting */
606
    if (!pi->plugin_dl)
607
      DBUG_RETURN(pi);
608
609
    plugin= pi;
610
#else
611
    /*
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.
615
    */
616
    if (!(plugin= (plugin_ref) my_malloc_ci(sizeof(pi), MYF(MY_WME))))
617
      DBUG_RETURN(NULL);
618
619
    *plugin= pi;
620
#endif
621
    pi->ref_count++;
622
    DBUG_PRINT("info",("thd: 0x%lx, plugin: \"%s\", ref_count: %d",
623
                       (long) current_thd, pi->name.str, pi->ref_count));
624
625
    if (lex)
626
      insert_dynamic(&lex->plugins, (uchar*)&plugin);
627
    DBUG_RETURN(plugin);
628
  }
629
  DBUG_RETURN(NULL);
630
}
631
632
633
plugin_ref plugin_lock(THD *thd, plugin_ref *ptr CALLER_INFO_PROTO)
634
{
635
  LEX *lex= thd ? thd->lex : 0;
636
  plugin_ref rc;
637
  DBUG_ENTER("plugin_lock");
638
  rc= my_intern_plugin_lock_ci(lex, *ptr);
639
  DBUG_RETURN(rc);
640
}
641
642
643
plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name, int type
644
                               CALLER_INFO_PROTO)
645
{
646
  LEX *lex= thd ? thd->lex : 0;
647
  plugin_ref rc= NULL;
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));
652
  DBUG_RETURN(rc);
653
}
654
655
656
static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
657
{
658
  uint i;
659
  struct st_plugin_int *tmp;
660
  DBUG_ENTER("plugin_insert_or_reuse");
661
  for (i= 0; i < plugin_array.elements; i++)
662
  {
663
    tmp= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
664
    if (tmp->state == PLUGIN_IS_FREED)
665
    {
666
      memcpy(tmp, plugin, sizeof(struct st_plugin_int));
667
      DBUG_RETURN(tmp);
668
    }
669
  }
670
  if (insert_dynamic(&plugin_array, (uchar*)&plugin))
671
    DBUG_RETURN(0);
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));
676
  DBUG_RETURN(tmp);
677
}
678
679
680
/*
681
  NOTE
682
    Requires that a write-lock is held on LOCK_system_variables_hash
683
*/
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)
687
{
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))
692
  {
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);
697
    DBUG_RETURN(TRUE);
698
  }
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)))
702
    DBUG_RETURN(TRUE);
703
  /* Find plugin by name */
704
  for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++)
705
  {
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,
711
                       name_len))
712
    {
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))
718
      {
719
        char buf[256];
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);
727
        goto err;
728
      }
729
      tmp.plugin= plugin;
730
      tmp.name.str= (char *)plugin->name;
731
      tmp.name.length= name_len;
732
      tmp.ref_count= 0;
733
      tmp.state= PLUGIN_IS_UNINITIALIZED;
734
      if (!test_plugin_options(tmp_root, &tmp, argc, argv, true))
735
      {
736
        if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
737
        {
738
          plugin_array_version++;
739
          if (!my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
740
          {
741
            init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096);
742
            DBUG_RETURN(FALSE);
743
          }
744
          tmp_plugin_ptr->state= PLUGIN_IS_FREED;
745
        }
746
        mysql_del_sys_var_chain(tmp.system_vars);
747
        goto err;
748
      }
749
      /* plugin was disabled */
750
      plugin_dl_del(dl);
751
      DBUG_RETURN(FALSE);
752
    }
753
  }
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);
758
err:
759
  plugin_dl_del(dl);
760
  DBUG_RETURN(TRUE);
761
}
762
763
764
static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
765
{
766
  if (plugin->plugin->status_vars)
767
  {
768
#ifdef FIX_LATER
769
    /*
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
774
      variable names.
775
    */
776
    SHOW_VAR array[2]= {
777
      {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
778
      {0, 0, SHOW_UNDEF}
779
    };
780
    remove_status_vars(array);
781
#else
782
    remove_status_vars(plugin->plugin->status_vars);
783
#endif /* FIX_LATER */
784
  }
785
786
  if (plugin_type_deinitialize[plugin->plugin->type])
787
  {
788
    if ((*plugin_type_deinitialize[plugin->plugin->type])(plugin))
789
    {
790
      sql_print_error("Plugin '%s' of type %s failed deinitialization",
791
                      plugin->name.str, plugin_type_names[plugin->plugin->type].str);
792
    }
793
  }
794
  else if (plugin->plugin->deinit)
795
  {
796
    DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
797
    if (plugin->plugin->deinit(plugin))
798
    {
799
      DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
800
                             plugin->name.str));
801
    }
802
  }
803
  plugin->state= PLUGIN_IS_UNINITIALIZED;
804
805
  /*
806
    We do the check here because NDB has a worker THD which doesn't
807
    exit until NDB is shut down.
808
  */
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);
812
}
813
814
815
static void plugin_del(struct st_plugin_int *plugin)
816
{
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));
829
  DBUG_VOID_RETURN;
830
}
831
832
#ifdef NOT_USED
833
834
static void plugin_del(const LEX_STRING *name)
835
{
836
  struct st_plugin_int *plugin;
837
  DBUG_ENTER("plugin_del(name)");
838
  if ((plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
839
    plugin_del(plugin);
840
  DBUG_VOID_RETURN;
841
}
842
843
#endif
844
845
static void reap_plugins(void)
846
{
847
  uint count, idx;
848
  struct st_plugin_int *plugin, **reap, **list;
849
850
  if (!reap_needed)
851
    return;
852
853
  reap_needed= false;
854
  count= plugin_array.elements;
855
  reap= (struct st_plugin_int **)my_alloca(sizeof(plugin)*(count+1));
856
  *(reap++)= NULL;
857
858
  for (idx= 0; idx < count; idx++)
859
  {
860
    plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
861
    if (plugin->state == PLUGIN_IS_DELETED && !plugin->ref_count)
862
    {
863
      /* change the status flag to prevent reaping by another thread */
864
      plugin->state= PLUGIN_IS_DYING;
865
      *(reap++)= plugin;
866
    }
867
  }
868
869
  list= reap;
870
  while ((plugin= *(--list)))
871
    plugin_deinitialize(plugin, true);
872
873
  while ((plugin= *(--reap)))
874
    plugin_del(plugin);
875
876
  my_afree(reap);
877
}
878
879
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin)
880
{
881
  int i;
882
  st_plugin_int *pi;
883
  DBUG_ENTER("intern_plugin_unlock");
884
885
  if (!plugin)
886
    DBUG_VOID_RETURN;
887
888
  pi= plugin_ref_to_int(plugin);
889
890
#ifdef DBUG_OFF
891
  if (!pi->plugin_dl)
892
    DBUG_VOID_RETURN;
893
#else
894
  my_free((uchar*) plugin, MYF(MY_WME));
895
#endif
896
897
  DBUG_PRINT("info",("unlocking plugin, name= %s, ref_count= %d",
898
                     pi->name.str, pi->ref_count));
899
  if (lex)
900
  {
901
    /*
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.
905
    */
906
    for (i= lex->plugins.elements - 1; i >= 0; i--)
907
      if (plugin == *dynamic_element(&lex->plugins, i, plugin_ref*))
908
      {
909
        delete_dynamic_element(&lex->plugins, i);
910
        break;
911
      }
912
    DBUG_ASSERT(i >= 0);
913
  }
914
915
  DBUG_ASSERT(pi->ref_count);
916
  pi->ref_count--;
917
918
  if (pi->state == PLUGIN_IS_DELETED && !pi->ref_count)
919
    reap_needed= true;
920
921
  DBUG_VOID_RETURN;
922
}
923
924
925
void plugin_unlock(THD *thd, plugin_ref plugin)
926
{
927
  LEX *lex= thd ? thd->lex : 0;
928
  DBUG_ENTER("plugin_unlock");
929
  if (!plugin)
930
    DBUG_VOID_RETURN;
931
  intern_plugin_unlock(lex, plugin);
932
  reap_plugins();
933
  DBUG_VOID_RETURN;
934
}
935
936
937
void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
938
{
939
  LEX *lex= thd ? thd->lex : 0;
940
  DBUG_ENTER("plugin_unlock_list");
941
  DBUG_ASSERT(list);
942
  while (count--)
943
    intern_plugin_unlock(lex, *list++);
944
  reap_plugins();
945
  DBUG_VOID_RETURN;
946
}
947
948
949
static int plugin_initialize(struct st_plugin_int *plugin)
950
{
951
  DBUG_ENTER("plugin_initialize");
952
953
  if (plugin_type_initialize[plugin->plugin->type])
954
  {
955
    if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
956
    {
957
      sql_print_error("Plugin '%s' registration as a %s failed.",
958
                      plugin->name.str, plugin_type_names[plugin->plugin->type].str);
959
      goto err;
960
    }
961
  }
962
  else if (plugin->plugin->init)
963
  {
964
    if (plugin->plugin->init(plugin))
965
    {
966
      sql_print_error("Plugin '%s' init function returned error.",
967
                      plugin->name.str);
968
      goto err;
969
    }
970
  }
971
972
  plugin->state= PLUGIN_IS_READY;
973
974
  if (plugin->plugin->status_vars)
975
  {
976
#ifdef FIX_LATER
977
    /*
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
982
      variable names.
983
    */
984
    SHOW_VAR array[2]= {
985
      {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
986
      {0, 0, SHOW_UNDEF}
987
    };
988
    if (add_status_vars(array)) // add_status_vars makes a copy
989
      goto err;
990
#else
991
    add_status_vars(plugin->plugin->status_vars); // add_status_vars makes a copy
992
#endif /* FIX_LATER */
993
  }
994
995
  /*
996
    set the plugin attribute of plugin's sys vars so they are pointing
997
    to the active plugin
998
  */
999
  if (plugin->system_vars)
1000
  {
1001
    sys_var_pluginvar *var= plugin->system_vars->cast_pluginvar();
1002
    for (;;)
1003
    {
1004
      var->plugin= plugin;
1005
      if (!var->next)
1006
        break;
1007
      var= var->next->cast_pluginvar();
1008
    }
1009
  }
1010
1011
  DBUG_RETURN(0);
1012
err:
1013
  DBUG_RETURN(1);
1014
}
1015
1016
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);
1019
1020
1021
uchar *get_plugin_hash_key(const uchar *buff, size_t *length,
1022
                           my_bool not_used __attribute__((unused)))
1023
{
1024
  struct st_plugin_int *plugin= (st_plugin_int *)buff;
1025
  *length= (uint)plugin->name.length;
1026
  return((uchar *)plugin->name.str);
1027
}
1028
1029
1030
uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
1031
                             my_bool not_used __attribute__((unused)))
1032
{
1033
  struct st_bookmark *var= (st_bookmark *)buff;
1034
  *length= var->name_len + 1;
1035
  return (uchar*) var->key;
1036
}
1037
1038
1039
/*
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
1042
  skip this part).
1043
1044
  Finally we initialize everything, aka the dynamic that have yet to initialize.
1045
*/
1046
int plugin_init(int *argc, char **argv, int flags)
1047
{
1048
  uint i;
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;
1053
  MEM_ROOT tmp_root;
1054
  DBUG_ENTER("plugin_init");
1055
1056
  if (initialized)
1057
    DBUG_RETURN(0);
1058
1059
  init_alloc_root(&plugin_mem_root, 4096, 4096);
1060
  init_alloc_root(&tmp_root, 4096, 4096);
1061
1062
  if (hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
1063
                  get_bookmark_hash_key, NULL, HASH_UNIQUE))
1064
      goto err;
1065
1066
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))
1071
    goto err;
1072
1073
  for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
1074
  {
1075
    if (hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
1076
                  get_plugin_hash_key, NULL, HASH_UNIQUE))
1077
      goto err;
1078
  }
1079
1080
  initialized= 1;
1081
1082
  /*
1083
    First we register builtin plugins
1084
  */
1085
  for (builtins= mysqld_builtins; *builtins; builtins++)
1086
  {
1087
    for (plugin= *builtins; plugin->info; plugin++)
1088
    {
1089
      /* by default, only ndbcluster is disabled */
1090
      def_enabled=
1091
        my_strcasecmp(&my_charset_latin1, plugin->name, "NDBCLUSTER") != 0;
1092
      bzero(&tmp, sizeof(tmp));
1093
      tmp.plugin= plugin;
1094
      tmp.name.str= (char *)plugin->name;
1095
      tmp.name.length= strlen(plugin->name);
1096
1097
      free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
1098
      if (test_plugin_options(&tmp_root, &tmp, argc, argv, def_enabled))
1099
        continue;
1100
1101
      if (register_builtin(plugin, &tmp, &plugin_ptr))
1102
        goto err_unlock;
1103
1104
      /* only initialize MyISAM and CSV at this stage */
1105
      if (!(is_myisam=
1106
            !my_strcasecmp(&my_charset_latin1, plugin->name, "MyISAM")) &&
1107
          my_strcasecmp(&my_charset_latin1, plugin->name, "CSV"))
1108
        continue;
1109
1110
      if (plugin_initialize(plugin_ptr))
1111
        goto err_unlock;
1112
1113
      /*
1114
        initialize the global default storage engine so that it may
1115
        not be null in any child thread.
1116
      */
1117
      if (is_myisam)
1118
      {
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);
1123
      }
1124
    }
1125
  }
1126
1127
  /* should now be set to MyISAM storage engine */
1128
  DBUG_ASSERT(global_system_variables.table_plugin);
1129
1130
  /* Register all dynamic plugins */
1131
  if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
1132
  {
1133
    if (opt_plugin_load)
1134
      plugin_load_list(&tmp_root, argc, argv, opt_plugin_load);
1135
  }
1136
1137
  if (flags & PLUGIN_INIT_SKIP_INITIALIZATION)
1138
    goto end;
1139
1140
  /*
1141
    Now we initialize all remaining plugins
1142
  */
1143
1144
  reap= (st_plugin_int **) my_alloca((plugin_array.elements+1) * sizeof(void*));
1145
  *(reap++)= NULL;
1146
1147
  for (i= 0; i < plugin_array.elements; i++)
1148
  {
1149
    plugin_ptr= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
1150
    if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED)
1151
    {
1152
      if (plugin_initialize(plugin_ptr))
1153
      {
1154
        plugin_ptr->state= PLUGIN_IS_DYING;
1155
        *(reap++)= plugin_ptr;
1156
      }
1157
    }
1158
  }
1159
1160
  /*
1161
    Check if any plugins have to be reaped
1162
  */
1163
  while ((plugin_ptr= *(--reap)))
1164
  {
1165
    plugin_deinitialize(plugin_ptr, true);
1166
    plugin_del(plugin_ptr);
1167
  }
1168
1169
  my_afree(reap);
1170
1171
end:
1172
  free_root(&tmp_root, MYF(0));
1173
1174
  DBUG_RETURN(0);
1175
1176
err_unlock:
1177
err:
1178
  free_root(&tmp_root, MYF(0));
1179
  DBUG_RETURN(1);
1180
}
1181
1182
1183
static bool register_builtin(struct st_mysql_plugin *plugin,
1184
                             struct st_plugin_int *tmp,
1185
                             struct st_plugin_int **ptr)
1186
{
1187
  DBUG_ENTER("register_builtin");
1188
1189
  tmp->state= PLUGIN_IS_UNINITIALIZED;
1190
  tmp->ref_count= 0;
1191
  tmp->plugin_dl= 0;
1192
1193
  if (insert_dynamic(&plugin_array, (uchar*)&tmp))
1194
    DBUG_RETURN(1);
1195
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));
1200
1201
  if (my_hash_insert(&plugin_hash[plugin->type],(uchar*) *ptr))
1202
    DBUG_RETURN(1);
1203
1204
  DBUG_RETURN(0);
1205
}
1206
1207
1208
#ifdef NOT_USED_YET
1209
/*
1210
  Register a plugin at run time. (note, this doesn't initialize a plugin)
1211
  Will be useful for embedded applications.
1212
1213
  SYNOPSIS
1214
    plugin_register_builtin()
1215
    thd         current thread (used to store scratch data in mem_root)
1216
    plugin      static plugin to install
1217
1218
  RETURN
1219
    false - plugin registered successfully
1220
*/
1221
bool plugin_register_builtin(THD *thd, struct st_mysql_plugin *plugin)
1222
{
1223
  struct st_plugin_int tmp, *ptr;
1224
  bool result= true;
1225
  int dummy_argc= 0;
1226
  DBUG_ENTER("plugin_register_builtin");
1227
1228
  bzero(&tmp, sizeof(tmp));
1229
  tmp.plugin= plugin;
1230
  tmp.name.str= (char *)plugin->name;
1231
  tmp.name.length= strlen(plugin->name);
1232
1233
  rw_wrlock(&LOCK_system_variables_hash);
1234
1235
  if (test_plugin_options(thd->mem_root, &tmp, &dummy_argc, NULL, true))
1236
    goto end;
1237
1238
  if ((result= register_builtin(plugin, &tmp, &ptr)))
1239
    mysql_del_sys_var_chain(tmp.system_vars);
1240
1241
end:
1242
  rw_unlock(&LOCK_system_variables_hash);
1243
1244
  DBUG_RETURN(result);;
1245
}
1246
#endif /* NOT_USED_YET */
1247
1248
1249
/*
1250
  called only by plugin_init()
1251
*/
1252
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
1253
                             const char *list)
1254
{
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;
1259
  char *p= buffer;
1260
  DBUG_ENTER("plugin_load_list");
1261
  while (list)
1262
  {
1263
    if (p == buffer + sizeof(buffer) - 1)
1264
    {
1265
      sql_print_error("plugin-load parameter too long");
1266
      DBUG_RETURN(TRUE);
1267
    }
1268
1269
    switch ((*(p++)= *(list++))) {
1270
    case '\0':
1271
      list= NULL; /* terminate the loop */
1272
      /* fall through */
1273
    case ':':     /* can't use this as delimiter as it may be drive letter */
1274
    case ';':
1275
      str->str[str->length]= '\0';
1276
      if (str == &name)  // load all plugins in named module
1277
      {
1278
        if (!name.length)
1279
        {
1280
          p--;    /* reset pointer */
1281
          continue;
1282
        }
1283
1284
        dl= name;
1285
        if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG)))
1286
        {
1287
          for (plugin= plugin_dl->plugins; plugin->info; plugin++)
1288
          {
1289
            name.str= (char *) plugin->name;
1290
            name.length= strlen(name.str);
1291
1292
            free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
1293
            if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
1294
              goto error;
1295
          }
1296
          plugin_dl_del(&dl); // reduce ref count
1297
        }
1298
      }
1299
      else
1300
      {
1301
        free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
1302
        if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
1303
          goto error;
1304
      }
1305
      name.length= dl.length= 0;
1306
      dl.str= NULL; name.str= p= buffer;
1307
      str= &name;
1308
      continue;
1309
    case '=':
1310
    case '#':
1311
      if (str == &name)
1312
      {
1313
        name.str[name.length]= '\0';
1314
        str= &dl;
1315
        str->str= p;
1316
        continue;
1317
      }
1318
    default:
1319
      str->length++;
1320
      continue;
1321
    }
1322
  }
1323
  DBUG_RETURN(FALSE);
1324
error:
1325
  sql_print_error("Couldn't load plugin named '%s' with soname '%s'.",
1326
                  name.str, dl.str);
1327
  DBUG_RETURN(TRUE);
1328
}
1329
1330
1331
void plugin_shutdown(void)
1332
{
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");
1337
1338
  if (initialized)
1339
  {
1340
    reap_needed= true;
1341
1342
    /*
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.
1348
    */
1349
    while (reap_needed && (count= plugin_array.elements))
1350
    {
1351
      reap_plugins();
1352
      for (i= free_slots= 0; i < count; i++)
1353
      {
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;
1358
          reap_needed= true;
1359
          break;
1360
        case PLUGIN_IS_FREED:
1361
        case PLUGIN_IS_UNINITIALIZED:
1362
          free_slots++;
1363
          break;
1364
        }
1365
      }
1366
      if (!reap_needed)
1367
      {
1368
        /*
1369
          release any plugin references held.
1370
        */
1371
        unlock_variables(NULL, &global_system_variables);
1372
        unlock_variables(NULL, &max_system_variables);
1373
      }
1374
    }
1375
1376
    if (count > free_slots)
1377
      sql_print_warning("Forcing shutdown of %d plugins", count - free_slots);
1378
1379
    plugins= (struct st_plugin_int **) my_alloca(sizeof(void*) * (count+1));
1380
1381
    /*
1382
      If we have any plugins which did not die cleanly, we force shutdown
1383
    */
1384
    for (i= 0; i < count; i++)
1385
    {
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;
1390
    }
1391
1392
    /*
1393
      We loop through all plugins and call deinit() if they have one.
1394
    */
1395
    for (i= 0; i < count; i++)
1396
      if (!(plugins[i]->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_FREED)))
1397
      {
1398
        sql_print_information("Plugin '%s' will be forced to shutdown",
1399
                              plugins[i]->name.str);
1400
        /*
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.
1403
        */
1404
        plugin_deinitialize(plugins[i], false);
1405
      }
1406
1407
    /*
1408
      We defer checking ref_counts until after all plugins are deinitialized
1409
      as some may have worker threads holding on to plugin references.
1410
    */
1411
    for (i= 0; i < count; i++)
1412
    {
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]);
1418
    }
1419
1420
    /*
1421
      Now we can deallocate all memory.
1422
    */
1423
1424
    cleanup_variables(NULL, &global_system_variables);
1425
    cleanup_variables(NULL, &max_system_variables);
1426
1427
    initialized= 0;
1428
1429
    my_afree(plugins);
1430
  }
1431
1432
  /* Dispose of the memory */
1433
1434
  for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
1435
    hash_free(&plugin_hash[i]);
1436
  delete_dynamic(&plugin_array);
1437
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]);
1444
  my_afree(dl);
1445
  delete_dynamic(&plugin_dl_array);
1446
1447
  hash_free(&bookmark_hash);
1448
  free_root(&plugin_mem_root, MYF(0));
1449
1450
  global_variables_dynamic_size= 0;
1451
1452
  DBUG_VOID_RETURN;
1453
}
1454
1455
1456
bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
1457
                       int type, uint state_mask, void *arg)
1458
{
1459
  uint idx, total;
1460
  struct st_plugin_int *plugin, **plugins;
1461
  int version=plugin_array_version;
1462
  DBUG_ENTER("plugin_foreach_with_mask");
1463
1464
  if (!initialized)
1465
    DBUG_RETURN(FALSE);
1466
1467
  state_mask= ~state_mask; // do it only once
1468
1469
  total= type == MYSQL_ANY_PLUGIN ? plugin_array.elements
1470
                                  : plugin_hash[type].records;
1471
  /*
1472
    Do the alloca out here in case we do have a working alloca:
1473
        leaving the nested stack frame invalidates alloca allocation.
1474
  */
1475
  plugins=(struct st_plugin_int **)my_alloca(total*sizeof(plugin));
1476
  if (type == MYSQL_ANY_PLUGIN)
1477
  {
1478
    for (idx= 0; idx < total; idx++)
1479
    {
1480
      plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
1481
      plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
1482
    }
1483
  }
1484
  else
1485
  {
1486
    HASH *hash= plugin_hash + type;
1487
    for (idx= 0; idx < total; idx++)
1488
    {
1489
      plugin= (struct st_plugin_int *) hash_element(hash, idx);
1490
      plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
1491
    }
1492
  }
1493
  for (idx= 0; idx < total; idx++)
1494
  {
1495
    if (unlikely(version != plugin_array_version))
1496
    {
1497
      for (uint i=idx; i < total; i++)
1498
        if (plugins[i] && plugins[i]->state & state_mask)
1499
          plugins[i]=0;
1500
    }
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))
1504
        goto err;
1505
  }
1506
1507
  my_afree(plugins);
1508
  DBUG_RETURN(FALSE);
1509
err:
1510
  my_afree(plugins);
1511
  DBUG_RETURN(TRUE);
1512
}
1513
1514
1515
/****************************************************************************
1516
  Internal type declarations for variables support
1517
****************************************************************************/
1518
1519
#undef MYSQL_SYSVAR_NAME
1520
#define MYSQL_SYSVAR_NAME(name) name
1521
#define PLUGIN_VAR_TYPEMASK 0x007f
1522
1523
#define EXTRA_OPTIONS 3 /* options for: 'foo', 'plugin-foo' and NULL */
1524
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 *);
1529
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);
1534
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);
1541
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);
1548
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);
1552
1553
1554
/****************************************************************************
1555
  default variable data check and update functions
1556
****************************************************************************/
1557
1558
static int check_func_bool(THD *thd, struct st_mysql_sys_var *var,
1559
                           void *save, st_mysql_value *value)
1560
{
1561
  char buff[STRING_BUFFER_USUAL_SIZE];
1562
  const char *strvalue= "NULL", *str;
1563
  int result, length;
1564
  long long tmp;
1565
1566
  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
1567
  {
1568
    length= sizeof(buff);
1569
    if (!(str= value->val_str(value, buff, &length)) ||
1570
        (result= find_type(&bool_typelib, str, length, 1)-1) < 0)
1571
    {
1572
      if (str)
1573
        strvalue= str;
1574
      goto err;
1575
    }
1576
  }
1577
  else
1578
  {
1579
    if (value->val_int(value, &tmp) < 0)
1580
      goto err;
1581
    if (tmp > 1)
1582
    {
1583
      llstr(tmp, buff);
1584
      strvalue= buff;
1585
      goto err;
1586
    }
1587
    result= (int) tmp;
1588
  }
1589
  *(int*)save= -result;
1590
  return 0;
1591
err:
1592
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
1593
  return 1;
1594
}
1595
1596
1597
static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
1598
                          void *save, st_mysql_value *value)
1599
{
1600
  my_bool fixed;
1601
  long long tmp;
1602
  struct my_option options;
1603
  value->val_int(value, &tmp);
1604
  plugin_opt_set_limits(&options, var);
1605
1606
  if (var->flags & PLUGIN_VAR_UNSIGNED)
1607
    *(uint *)save= (uint) getopt_ull_limit_value((ulonglong) tmp, &options,
1608
                                                   &fixed);
1609
  else
1610
    *(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed);
1611
1612
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
1613
                              var->name, (longlong) tmp);
1614
}
1615
1616
1617
static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
1618
                          void *save, st_mysql_value *value)
1619
{
1620
  my_bool fixed;
1621
  long long tmp;
1622
  struct my_option options;
1623
  value->val_int(value, &tmp);
1624
  plugin_opt_set_limits(&options, var);
1625
1626
  if (var->flags & PLUGIN_VAR_UNSIGNED)
1627
    *(ulong *)save= (ulong) getopt_ull_limit_value((ulonglong) tmp, &options,
1628
                                                   &fixed);
1629
  else
1630
    *(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed);
1631
1632
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
1633
                              var->name, (longlong) tmp);
1634
}
1635
1636
1637
static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var,
1638
                               void *save, st_mysql_value *value)
1639
{
1640
  my_bool fixed;
1641
  long long tmp;
1642
  struct my_option options;
1643
  value->val_int(value, &tmp);
1644
  plugin_opt_set_limits(&options, var);
1645
1646
  if (var->flags & PLUGIN_VAR_UNSIGNED)
1647
    *(ulonglong *)save= getopt_ull_limit_value((ulonglong) tmp, &options,
1648
                                               &fixed);
1649
  else
1650
    *(longlong *)save= getopt_ll_limit_value(tmp, &options, &fixed);
1651
1652
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
1653
                              var->name, (longlong) tmp);
1654
}
1655
1656
static int check_func_str(THD *thd, struct st_mysql_sys_var *var,
1657
                          void *save, st_mysql_value *value)
1658
{
1659
  char buff[STRING_BUFFER_USUAL_SIZE];
1660
  const char *str;
1661
  int length;
1662
1663
  length= sizeof(buff);
1664
  if ((str= value->val_str(value, buff, &length)))
1665
    str= thd->strmake(str, length);
1666
  *(const char**)save= str;
1667
  return 0;
1668
}
1669
1670
1671
static int check_func_enum(THD *thd, struct st_mysql_sys_var *var,
1672
                           void *save, st_mysql_value *value)
1673
{
1674
  char buff[STRING_BUFFER_USUAL_SIZE];
1675
  const char *strvalue= "NULL", *str;
1676
  TYPELIB *typelib;
1677
  long long tmp;
1678
  long result;
1679
  int length;
1680
1681
  if (var->flags & PLUGIN_VAR_THDLOCAL)
1682
    typelib= ((thdvar_enum_t*) var)->typelib;
1683
  else
1684
    typelib= ((sysvar_enum_t*) var)->typelib;
1685
1686
  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
1687
  {
1688
    length= sizeof(buff);
1689
    if (!(str= value->val_str(value, buff, &length)))
1690
      goto err;
1691
    if ((result= (long)find_type(typelib, str, length, 1)-1) < 0)
1692
    {
1693
      strvalue= str;
1694
      goto err;
1695
    }
1696
  }
1697
  else
1698
  {
1699
    if (value->val_int(value, &tmp))
1700
      goto err;
1701
    if (tmp >= typelib->count)
1702
    {
1703
      llstr(tmp, buff);
1704
      strvalue= buff;
1705
      goto err;
1706
    }
1707
    result= (long) tmp;
1708
  }
1709
  *(long*)save= result;
1710
  return 0;
1711
err:
1712
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
1713
  return 1;
1714
}
1715
1716
1717
static int check_func_set(THD *thd, struct st_mysql_sys_var *var,
1718
                          void *save, st_mysql_value *value)
1719
{
1720
  char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
1721
  const char *strvalue= "NULL", *str;
1722
  TYPELIB *typelib;
1723
  ulonglong result;
1724
  uint error_len;
1725
  bool not_used;
1726
  int length;
1727
1728
  if (var->flags & PLUGIN_VAR_THDLOCAL)
1729
    typelib= ((thdvar_set_t*) var)->typelib;
1730
  else
1731
    typelib= ((sysvar_set_t*)var)->typelib;
1732
1733
  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
1734
  {
1735
    length= sizeof(buff);
1736
    if (!(str= value->val_str(value, buff, &length)))
1737
      goto err;
1738
    result= find_set(typelib, str, length, NULL,
1739
                     &error, &error_len, &not_used);
1740
    if (error_len)
1741
    {
1742
      strmake(buff, error, min(sizeof(buff), error_len));
1743
      strvalue= buff;
1744
      goto err;
1745
    }
1746
  }
1747
  else
1748
  {
1749
    if (value->val_int(value, (long long *)&result))
1750
      goto err;
1751
    if (unlikely((result >= (ULL(1) << typelib->count)) &&
1752
                 (typelib->count < sizeof(long)*8)))
1753
    {
1754
      llstr(result, buff);
1755
      strvalue= buff;
1756
      goto err;
1757
    }
1758
  }
1759
  *(ulonglong*)save= result;
1760
  return 0;
1761
err:
1762
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
1763
  return 1;
1764
}
1765
1766
1767
static void update_func_bool(THD *thd, struct st_mysql_sys_var *var,
1768
                             void *tgt, const void *save)
1769
{
1770
  *(my_bool *) tgt= *(int *) save ? 1 : 0;
1771
}
1772
1773
1774
static void update_func_int(THD *thd, struct st_mysql_sys_var *var,
1775
                             void *tgt, const void *save)
1776
{
1777
  *(int *)tgt= *(int *) save;
1778
}
1779
1780
1781
static void update_func_long(THD *thd, struct st_mysql_sys_var *var,
1782
                             void *tgt, const void *save)
1783
{
1784
  *(long *)tgt= *(long *) save;
1785
}
1786
1787
1788
static void update_func_longlong(THD *thd, struct st_mysql_sys_var *var,
1789
                             void *tgt, const void *save)
1790
{
1791
  *(longlong *)tgt= *(ulonglong *) save;
1792
}
1793
1794
1795
static void update_func_str(THD *thd, struct st_mysql_sys_var *var,
1796
                             void *tgt, const void *save)
1797
{
1798
  char *old= *(char **) tgt;
1799
  *(char **)tgt= *(char **) save;
1800
  if (var->flags & PLUGIN_VAR_MEMALLOC)
1801
  {
1802
    *(char **)tgt= my_strdup(*(char **) save, MYF(0));
1803
    my_free(old, MYF(0));
1804
  }
1805
}
1806
1807
1808
/****************************************************************************
1809
  System Variables support
1810
****************************************************************************/
1811
1812
1813
sys_var *find_sys_var(THD *thd, const char *str, uint length)
1814
{
1815
  sys_var *var;
1816
  sys_var_pluginvar *pi= NULL;
1817
  plugin_ref plugin;
1818
  DBUG_ENTER("find_sys_var");
1819
1820
  rw_rdlock(&LOCK_system_variables_hash);
1821
  if ((var= intern_find_sys_var(str, length, false)) &&
1822
      (pi= var->cast_pluginvar()))
1823
  {
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 */
1828
    else
1829
    if (!(plugin_state(plugin) & PLUGIN_IS_READY))
1830
    {
1831
      /* initialization not completed */
1832
      var= NULL;
1833
      intern_plugin_unlock(lex, plugin);
1834
    }
1835
  }
1836
  else
1837
    rw_unlock(&LOCK_system_variables_hash);
1838
1839
  /*
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.
1842
  */
1843
  if (pi && !var)
1844
    my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
1845
  DBUG_RETURN(var);
1846
}
1847
1848
1849
/*
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
1853
*/
1854
static st_bookmark *find_bookmark(const char *plugin, const char *name,
1855
                                  int flags)
1856
{
1857
  st_bookmark *result= NULL;
1858
  uint namelen, length, pluginlen= 0;
1859
  char *varname, *p;
1860
1861
  if (!(flags & PLUGIN_VAR_THDLOCAL))
1862
    return NULL;
1863
1864
  namelen= strlen(name);
1865
  if (plugin)
1866
    pluginlen= strlen(plugin) + 1;
1867
  length= namelen + pluginlen + 2;
1868
  varname= (char*) my_alloca(length);
1869
1870
  if (plugin)
1871
  {
1872
    strxmov(varname + 1, plugin, "_", name, NullS);
1873
    for (p= varname + 1; *p; p++)
1874
      if (*p == '-')
1875
        *p= '_';
1876
  }
1877
  else
1878
    memcpy(varname + 1, name, namelen + 1);
1879
1880
  varname[0]= flags & PLUGIN_VAR_TYPEMASK;
1881
1882
  result= (st_bookmark*) hash_search(&bookmark_hash,
1883
                                     (const uchar*) varname, length - 1);
1884
1885
  my_afree(varname);
1886
  return result;
1887
}
1888
1889
1890
/*
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
1894
*/
1895
static st_bookmark *register_var(const char *plugin, const char *name,
1896
                                 int flags)
1897
{
1898
  uint length= strlen(plugin) + strlen(name) + 3, size= 0, offset, new_size;
1899
  st_bookmark *result;
1900
  char *varname, *p;
1901
1902
  if (!(flags & PLUGIN_VAR_THDLOCAL))
1903
    return NULL;
1904
1905
  switch (flags & PLUGIN_VAR_TYPEMASK) {
1906
  case PLUGIN_VAR_BOOL:
1907
    size= sizeof(my_bool);
1908
    break;
1909
  case PLUGIN_VAR_INT:
1910
    size= sizeof(int);
1911
    break;
1912
  case PLUGIN_VAR_LONG:
1913
  case PLUGIN_VAR_ENUM:
1914
    size= sizeof(long);
1915
    break;
1916
  case PLUGIN_VAR_LONGLONG:
1917
  case PLUGIN_VAR_SET:
1918
    size= sizeof(ulonglong);
1919
    break;
1920
  case PLUGIN_VAR_STR:
1921
    size= sizeof(char*);
1922
    break;
1923
  default:
1924
    DBUG_ASSERT(0);
1925
    return NULL;
1926
  };
1927
1928
  varname= ((char*) my_alloca(length));
1929
  strxmov(varname + 1, plugin, "_", name, NullS);
1930
  for (p= varname + 1; *p; p++)
1931
    if (*p == '-')
1932
      *p= '_';
1933
1934
  if (!(result= find_bookmark(NULL, varname + 1, flags)))
1935
  {
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;
1941
    result->offset= -1;
1942
1943
    DBUG_ASSERT(size && !(size & (size-1))); /* must be power of 2 */
1944
1945
    offset= global_system_variables.dynamic_variables_size;
1946
    offset= (offset + size - 1) & ~(size - 1);
1947
    result->offset= (int) offset;
1948
1949
    new_size= (offset + size + 63) & ~63;
1950
1951
    if (new_size > global_variables_dynamic_size)
1952
    {
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));
1959
      /*
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
1962
        string.
1963
      */
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;
1971
    }
1972
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++;
1979
1980
    result->version= global_system_variables.dynamic_variables_version;
1981
1982
    /* this should succeed because we have already checked if a dup exists */
1983
    if (my_hash_insert(&bookmark_hash, (uchar*) result))
1984
    {
1985
      fprintf(stderr, "failed to add placeholder to hash");
1986
      DBUG_ASSERT(0);
1987
    }
1988
  }
1989
  my_afree(varname);
1990
  return result;
1991
}
1992
1993
1994
/*
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.
1999
*/
2000
static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
2001
{
2002
  DBUG_ASSERT(offset >= 0);
2003
  DBUG_ASSERT((uint)offset <= global_system_variables.dynamic_variables_head);
2004
2005
  if (!thd)
2006
    return (uchar*) global_system_variables.dynamic_variables_ptr + offset;
2007
2008
  /*
2009
    dynamic_variables_head points to the largest valid offset
2010
  */
2011
  if (!thd->variables.dynamic_variables_ptr ||
2012
      (uint)offset > thd->variables.dynamic_variables_head)
2013
  {
2014
    uint idx;
2015
2016
    rw_rdlock(&LOCK_system_variables_hash);
2017
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));
2022
2023
    if (global_lock)
2024
      pthread_mutex_lock(&LOCK_global_system_variables);
2025
2026
    safe_mutex_assert_owner(&LOCK_global_system_variables);
2027
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);
2034
2035
    /*
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
2038
    */
2039
    for (idx= 0; idx < bookmark_hash.records; idx++)
2040
    {
2041
      sys_var_pluginvar *pi;
2042
      sys_var *var;
2043
      st_bookmark *v= (st_bookmark*) hash_element(&bookmark_hash,idx);
2044
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))
2049
        continue;
2050
2051
      /* Here we do anything special that may be required of the data types */
2052
2053
      if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
2054
          pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
2055
      {
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));
2061
      }
2062
    }
2063
2064
    if (global_lock)
2065
      pthread_mutex_unlock(&LOCK_global_system_variables);
2066
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;
2073
2074
    rw_unlock(&LOCK_system_variables_hash);
2075
  }
2076
  return (uchar*)thd->variables.dynamic_variables_ptr + offset;
2077
}
2078
2079
static uchar *mysql_sys_var_ptr(void* a_thd, int offset)
2080
{
2081
  return intern_sys_var_ptr((THD *)a_thd, offset, true);
2082
}
2083
2084
2085
void plugin_thdvar_init(THD *thd)
2086
{
2087
  plugin_ref old_table_plugin= thd->variables.table_plugin;
2088
  DBUG_ENTER("plugin_thdvar_init");
2089
  
2090
  thd->variables.table_plugin= NULL;
2091
  cleanup_variables(thd, &thd->variables);
2092
  
2093
  thd->variables= global_system_variables;
2094
  thd->variables.table_plugin= NULL;
2095
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;
2100
2101
  thd->variables.table_plugin=
2102
        my_intern_plugin_lock(NULL, global_system_variables.table_plugin);
2103
  intern_plugin_unlock(NULL, old_table_plugin);
2104
  DBUG_VOID_RETURN;
2105
}
2106
2107
2108
/*
2109
  Unlocks all system variables which hold a reference
2110
*/
2111
static void unlock_variables(THD *thd, struct system_variables *vars)
2112
{
2113
  intern_plugin_unlock(NULL, vars->table_plugin);
2114
  vars->table_plugin= NULL;
2115
}
2116
2117
2118
/*
2119
  Frees memory used by system variables
2120
2121
  Unlike plugin_vars_free_values() it frees all variables of all plugins,
2122
  it's used on shutdown.
2123
*/
2124
static void cleanup_variables(THD *thd, struct system_variables *vars)
2125
{
2126
  st_bookmark *v;
2127
  sys_var_pluginvar *pivar;
2128
  sys_var *var;
2129
  int flags;
2130
  uint idx;
2131
2132
  rw_rdlock(&LOCK_system_variables_hash);
2133
  for (idx= 0; idx < bookmark_hash.records; idx++)
2134
  {
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))
2140
      continue;
2141
2142
    flags= pivar->plugin_var->flags;
2143
2144
    if ((flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
2145
        flags & PLUGIN_VAR_THDLOCAL && flags & PLUGIN_VAR_MEMALLOC)
2146
    {
2147
      char **ptr= (char**) pivar->real_value_ptr(thd, OPT_SESSION);
2148
      my_free(*ptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
2149
      *ptr= NULL;
2150
    }
2151
  }
2152
  rw_unlock(&LOCK_system_variables_hash);
2153
2154
  DBUG_ASSERT(vars->table_plugin == NULL);
2155
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;
2160
}
2161
2162
2163
void plugin_thdvar_cleanup(THD *thd)
2164
{
2165
  uint idx;
2166
  plugin_ref *list;
2167
  DBUG_ENTER("plugin_thdvar_cleanup");
2168
2169
  unlock_variables(thd, &thd->variables);
2170
  cleanup_variables(thd, &thd->variables);
2171
2172
  if ((idx= thd->lex->plugins.elements))
2173
  {
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--);
2178
  }
2179
2180
  reap_plugins();
2181
2182
  reset_dynamic(&thd->lex->plugins);
2183
2184
  DBUG_VOID_RETURN;
2185
}
2186
2187
2188
/**
2189
  @brief Free values of thread variables of a plugin.
2190
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
2194
  must be freed.
2195
2196
  @param[in]        vars        Chain of system variables of a plugin
2197
*/
2198
2199
static void plugin_vars_free_values(sys_var *vars)
2200
{
2201
  DBUG_ENTER("plugin_vars_free_values");
2202
2203
  for (sys_var *var= vars; var; var= var->next)
2204
  {
2205
    sys_var_pluginvar *piv= var->cast_pluginvar();
2206
    if (piv &&
2207
        ((piv->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
2208
        (piv->plugin_var->flags & PLUGIN_VAR_MEMALLOC))
2209
    {
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));
2215
      *valptr= NULL;
2216
    }
2217
  }
2218
  DBUG_VOID_RETURN;
2219
}
2220
2221
2222
bool sys_var_pluginvar::check_update_type(Item_result type)
2223
{
2224
  if (is_readonly())
2225
    return 1;
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;
2233
  default:
2234
    return 0;
2235
  }
2236
}
2237
2238
2239
SHOW_TYPE sys_var_pluginvar::show_type()
2240
{
2241
  switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
2242
  case PLUGIN_VAR_BOOL:
2243
    return SHOW_MY_BOOL;
2244
  case PLUGIN_VAR_INT:
2245
    return SHOW_INT;
2246
  case PLUGIN_VAR_LONG:
2247
    return SHOW_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:
2254
    return SHOW_CHAR;
2255
  default:
2256
    DBUG_ASSERT(0);
2257
    return SHOW_UNDEF;
2258
  }
2259
}
2260
2261
2262
uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type)
2263
{
2264
  DBUG_ASSERT(thd || (type == OPT_GLOBAL));
2265
  if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
2266
  {
2267
    if (type == OPT_GLOBAL)
2268
      thd= NULL;
2269
2270
    return intern_sys_var_ptr(thd, *(int*) (plugin_var+1), false);
2271
  }
2272
  return *(uchar**) (plugin_var+1);
2273
}
2274
2275
2276
TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
2277
{
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;
2287
  default:
2288
    return NULL;
2289
  }
2290
  return NULL;
2291
}
2292
2293
2294
uchar* sys_var_pluginvar::value_ptr(THD *thd, enum_var_type type,
2295
                                   LEX_STRING *base)
2296
{
2297
  uchar* result;
2298
2299
  result= real_value_ptr(thd, type);
2300
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)
2304
  {
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;
2309
    uint i;
2310
2311
    str.length(0);
2312
    for (i= 0; i < typelib->count; i++, mask<<=1)
2313
    {
2314
      if (!(value & mask))
2315
        continue;
2316
      str.append(typelib->type_names[i], typelib->type_lengths[i]);
2317
      str.append(',');
2318
    }
2319
2320
    result= (uchar*) "";
2321
    if (str.length())
2322
      result= (uchar*) thd->strmake(str.ptr(), str.length()-1);
2323
  }
2324
  return result;
2325
}
2326
2327
2328
bool sys_var_pluginvar::check(THD *thd, set_var *var)
2329
{
2330
  st_item_value_holder value;
2331
  DBUG_ASSERT(is_readonly() || plugin_var->check);
2332
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;
2338
2339
  return is_readonly() ||
2340
         plugin_var->check(thd, plugin_var, &var->save_result, &value);
2341
}
2342
2343
2344
void sys_var_pluginvar::set_default(THD *thd, enum_var_type type)
2345
{
2346
  const void *src;
2347
  void *tgt;
2348
2349
  DBUG_ASSERT(is_readonly() || plugin_var->update);
2350
2351
  if (is_readonly())
2352
    return;
2353
2354
  pthread_mutex_lock(&LOCK_global_system_variables);
2355
  tgt= real_value_ptr(thd, type);
2356
  src= ((void **) (plugin_var + 1) + 1);
2357
2358
  if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
2359
  {
2360
    if (type != OPT_GLOBAL)
2361
      src= real_value_ptr(thd, OPT_GLOBAL);
2362
    else
2363
    switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
2364
	case PLUGIN_VAR_INT:
2365
	  src= &((thdvar_uint_t*) plugin_var)->def_val;
2366
	  break;
2367
	case PLUGIN_VAR_LONG:
2368
	  src= &((thdvar_ulong_t*) plugin_var)->def_val;
2369
	  break;
2370
	case PLUGIN_VAR_LONGLONG:
2371
	  src= &((thdvar_ulonglong_t*) plugin_var)->def_val;
2372
	  break;
2373
	case PLUGIN_VAR_ENUM:
2374
	  src= &((thdvar_enum_t*) plugin_var)->def_val;
2375
	  break;
2376
	case PLUGIN_VAR_SET:
2377
	  src= &((thdvar_set_t*) plugin_var)->def_val;
2378
	  break;
2379
	case PLUGIN_VAR_BOOL:
2380
	  src= &((thdvar_bool_t*) plugin_var)->def_val;
2381
	  break;
2382
	case PLUGIN_VAR_STR:
2383
	  src= &((thdvar_str_t*) plugin_var)->def_val;
2384
	  break;
2385
	default:
2386
	  DBUG_ASSERT(0);
2387
	}
2388
  }
2389
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);
2393
2394
  if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || type == OPT_GLOBAL)
2395
  {
2396
    plugin_var->update(thd, plugin_var, tgt, src);
2397
    pthread_mutex_unlock(&LOCK_global_system_variables);
2398
  }
2399
  else
2400
  {
2401
    pthread_mutex_unlock(&LOCK_global_system_variables);
2402
    plugin_var->update(thd, plugin_var, tgt, src);
2403
  }
2404
}
2405
2406
2407
bool sys_var_pluginvar::update(THD *thd, set_var *var)
2408
{
2409
  void *tgt;
2410
2411
  DBUG_ASSERT(is_readonly() || plugin_var->update);
2412
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);
2416
2417
  if (is_readonly())
2418
    return 1;
2419
2420
  pthread_mutex_lock(&LOCK_global_system_variables);
2421
  tgt= real_value_ptr(thd, var->type);
2422
2423
  if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || var->type == OPT_GLOBAL)
2424
  {
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);
2428
  }
2429
  else
2430
  {
2431
    pthread_mutex_unlock(&LOCK_global_system_variables);
2432
    plugin_var->update(thd, plugin_var, tgt, &var->save_result);
2433
  }
2434
 return 0;
2435
}
2436
2437
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
2444
2445
2446
static void plugin_opt_set_limits(struct my_option *options,
2447
                                  const struct st_mysql_sys_var *opt)
2448
{
2449
  options->sub_size= 0;
2450
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);
2456
    break;
2457
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED:
2458
    OPTION_SET_LIMITS(GET_UINT, options, (sysvar_uint_t*) opt);
2459
    break;
2460
  case PLUGIN_VAR_LONG:
2461
    OPTION_SET_LIMITS(GET_LONG, options, (sysvar_long_t*) opt);
2462
    break;
2463
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
2464
    OPTION_SET_LIMITS(GET_ULONG, options, (sysvar_ulong_t*) opt);
2465
    break;
2466
  case PLUGIN_VAR_LONGLONG:
2467
    OPTION_SET_LIMITS(GET_LL, options, (sysvar_longlong_t*) opt);
2468
    break;
2469
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
2470
    OPTION_SET_LIMITS(GET_ULL, options, (sysvar_ulonglong_t*) opt);
2471
    break;
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;
2478
    break;
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;
2485
    break;
2486
  case PLUGIN_VAR_BOOL:
2487
    options->var_type= GET_BOOL;
2488
    options->def_value= ((sysvar_bool_t*) opt)->def_val;
2489
    break;
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;
2494
    break;
2495
  /* threadlocal variables */
2496
  case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
2497
    OPTION_SET_LIMITS(GET_INT, options, (thdvar_int_t*) opt);
2498
    break;
2499
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
2500
    OPTION_SET_LIMITS(GET_UINT, options, (thdvar_uint_t*) opt);
2501
    break;
2502
  case PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL:
2503
    OPTION_SET_LIMITS(GET_LONG, options, (thdvar_long_t*) opt);
2504
    break;
2505
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
2506
    OPTION_SET_LIMITS(GET_ULONG, options, (thdvar_ulong_t*) opt);
2507
    break;
2508
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL:
2509
    OPTION_SET_LIMITS(GET_LL, options, (thdvar_longlong_t*) opt);
2510
    break;
2511
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
2512
    OPTION_SET_LIMITS(GET_ULL, options, (thdvar_ulonglong_t*) opt);
2513
    break;
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;
2520
    break;
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;
2527
    break;
2528
  case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL:
2529
    options->var_type= GET_BOOL;
2530
    options->def_value= ((thdvar_bool_t*) opt)->def_val;
2531
    break;
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;
2536
    break;
2537
  default:
2538
    DBUG_ASSERT(0);
2539
  }
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;
2545
}
2546
2547
extern "C" my_bool get_one_plugin_option(int optid, const struct my_option *,
2548
                                         char *);
2549
2550
my_bool get_one_plugin_option(int optid __attribute__((unused)),
2551
                              const struct my_option *opt,
2552
                              char *argument)
2553
{
2554
  return 0;
2555
}
2556
2557
2558
static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
2559
                             my_option *options, my_bool **enabled,
2560
                             bool can_disable)
2561
{
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;
2566
  char *optname, *p;
2567
  int index= 0, offset= 0;
2568
  st_mysql_sys_var *opt, **plugin_option;
2569
  st_bookmark *v;
2570
  DBUG_ENTER("construct_options");
2571
  DBUG_PRINT("plugin", ("plugin: '%s'  enabled: %d  can_disable: %d",
2572
                        plugin_name, **enabled, can_disable));
2573
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. */
2579
2580
  for (p= name + namelen*2 + 8; p > name; p--)
2581
    if (*p == '_')
2582
      *p= '-';
2583
2584
  if (can_disable)
2585
  {
2586
    strxmov(name + namelen*2 + 10, "Enable ", plugin_name, " plugin. "
2587
            "Disable with --skip-", name," (will save memory).", NullS);
2588
    /*
2589
      Now we have namelen * 2 + 10 (one char unused) + 7 + namelen + 9 +
2590
      20 + namelen + 20 + 1 == namelen * 4 + 67.
2591
    */
2592
2593
    options[0].comment= name + namelen*2 + 10;
2594
  }
2595
2596
  /*
2597
    NOTE: 'name' is one char above the allocated buffer!
2598
    NOTE: This code assumes that 'my_bool' and 'char' are of same size.
2599
  */
2600
  *((my_bool *)(name -1))= **enabled;
2601
  *enabled= (my_bool *)(name - 1);
2602
2603
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);
2611
  options+= 2;
2612
2613
  /*
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
2616
  */
2617
2618
  for (plugin_option= tmp->plugin->system_vars;
2619
       plugin_option && *plugin_option; plugin_option++, index++)
2620
  {
2621
    opt= *plugin_option;
2622
    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
2623
      continue;
2624
    if (!(register_var(name, opt->name, opt->flags)))
2625
      continue;
2626
    switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
2627
    case PLUGIN_VAR_BOOL:
2628
      SET_PLUGIN_VAR_RESOLVE((thdvar_bool_t *) opt);
2629
      break;
2630
    case PLUGIN_VAR_INT:
2631
      SET_PLUGIN_VAR_RESOLVE((thdvar_int_t *) opt);
2632
      break;
2633
    case PLUGIN_VAR_LONG:
2634
      SET_PLUGIN_VAR_RESOLVE((thdvar_long_t *) opt);
2635
      break;
2636
    case PLUGIN_VAR_LONGLONG:
2637
      SET_PLUGIN_VAR_RESOLVE((thdvar_longlong_t *) opt);
2638
      break;
2639
    case PLUGIN_VAR_STR:
2640
      SET_PLUGIN_VAR_RESOLVE((thdvar_str_t *) opt);
2641
      break;
2642
    case PLUGIN_VAR_ENUM:
2643
      SET_PLUGIN_VAR_RESOLVE((thdvar_enum_t *) opt);
2644
      break;
2645
    case PLUGIN_VAR_SET:
2646
      SET_PLUGIN_VAR_RESOLVE((thdvar_set_t *) opt);
2647
      break;
2648
    default:
2649
      sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
2650
                      opt->flags, plugin_name);
2651
      DBUG_RETURN(-1);
2652
    };
2653
  }
2654
2655
  for (plugin_option= tmp->plugin->system_vars;
2656
       plugin_option && *plugin_option; plugin_option++, index++)
2657
  {
2658
    switch ((opt= *plugin_option)->flags & PLUGIN_VAR_TYPEMASK) {
2659
    case PLUGIN_VAR_BOOL:
2660
      if (!opt->check)
2661
        opt->check= check_func_bool;
2662
      if (!opt->update)
2663
        opt->update= update_func_bool;
2664
      break;
2665
    case PLUGIN_VAR_INT:
2666
      if (!opt->check)
2667
        opt->check= check_func_int;
2668
      if (!opt->update)
2669
        opt->update= update_func_int;
2670
      break;
2671
    case PLUGIN_VAR_LONG:
2672
      if (!opt->check)
2673
        opt->check= check_func_long;
2674
      if (!opt->update)
2675
        opt->update= update_func_long;
2676
      break;
2677
    case PLUGIN_VAR_LONGLONG:
2678
      if (!opt->check)
2679
        opt->check= check_func_longlong;
2680
      if (!opt->update)
2681
        opt->update= update_func_longlong;
2682
      break;
2683
    case PLUGIN_VAR_STR:
2684
      if (!opt->check)
2685
        opt->check= check_func_str;
2686
      if (!opt->update)
2687
      {
2688
        opt->update= update_func_str;
9 by Brian Aker
Warnings cleanup
2689
        if ((opt->flags & (PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY)) == false)
1 by brian
clean slate
2690
        {
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);
2696
        }
2697
      }
2698
      break;
2699
    case PLUGIN_VAR_ENUM:
2700
      if (!opt->check)
2701
        opt->check= check_func_enum;
2702
      if (!opt->update)
2703
        opt->update= update_func_long;
2704
      break;
2705
    case PLUGIN_VAR_SET:
2706
      if (!opt->check)
2707
        opt->check= check_func_set;
2708
      if (!opt->update)
2709
        opt->update= update_func_longlong;
2710
      break;
2711
    default:
2712
      sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
2713
                      opt->flags, plugin_name);
2714
      DBUG_RETURN(-1);
2715
    }
2716
2717
    if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_THDLOCAL))
2718
                    == PLUGIN_VAR_NOCMDOPT)
2719
      continue;
2720
2721
    if (!opt->name)
2722
    {
2723
      sql_print_error("Missing variable name in plugin '%s'.",
2724
                      plugin_name);
2725
      DBUG_RETURN(-1);
2726
    }
2727
2728
    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
2729
    {
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;
2734
    }
2735
    else
2736
    {
2737
      /* this should not fail because register_var should create entry */
2738
      if (!(v= find_bookmark(name, opt->name, opt->flags)))
2739
      {
2740
        sql_print_error("Thread local variable '%s' not allocated "
2741
                        "in plugin '%s'.", opt->name, plugin_name);
2742
        DBUG_RETURN(-1);
2743
      }
2744
2745
      *(int*)(opt + 1)= offset= v->offset;
2746
2747
      if (opt->flags & PLUGIN_VAR_NOCMDOPT)
2748
        continue;
2749
2750
      optname= (char*) memdup_root(mem_root, v->key + 1, 
2751
                                   (optnamelen= v->name_len) + 1);
2752
    }
2753
2754
    /* convert '_' to '-' */
2755
    for (p= optname; *p; p++)
2756
      if (*p == '_')
2757
        *p= '-';
2758
2759
    options->name= optname;
2760
    options->comment= opt->comment;
2761
    options->app_type= opt;
2762
    options->id= (options-1)->id + 1;
2763
2764
    plugin_opt_set_limits(options, opt);
2765
2766
    if (opt->flags & PLUGIN_VAR_THDLOCAL)
2767
      options->value= options->u_max_value= (uchar**)
2768
        (global_system_variables.dynamic_variables_ptr + offset);
2769
    else
2770
      options->value= options->u_max_value= *(uchar***) (opt + 1);
2771
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);
2776
2777
    options+= 2;
2778
  }
2779
2780
  DBUG_RETURN(0);
2781
}
2782
2783
2784
static my_option *construct_help_options(MEM_ROOT *mem_root,
2785
                                         struct st_plugin_int *p)
2786
{
2787
  st_mysql_sys_var **opt;
2788
  my_option *opts;
2789
  my_bool dummy, can_disable;
2790
  my_bool *dummy2= &dummy;
2791
  uint count= EXTRA_OPTIONS;
2792
  DBUG_ENTER("construct_help_options");
2793
9 by Brian Aker
Warnings cleanup
2794
  for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2) {};
1 by brian
clean slate
2795
2796
  if (!(opts= (my_option*) alloc_root(mem_root, sizeof(my_option) * count)))
2797
    DBUG_RETURN(NULL);
2798
2799
  bzero(opts, sizeof(my_option) * count);
2800
2801
  dummy= TRUE; /* plugin is enabled. */
2802
2803
  can_disable=
2804
      my_strcasecmp(&my_charset_latin1, p->name.str, "MyISAM") &&
2805
      my_strcasecmp(&my_charset_latin1, p->name.str, "MEMORY");
2806
2807
  if (construct_options(mem_root, p, opts, &dummy2, can_disable))
2808
    DBUG_RETURN(NULL);
2809
2810
  DBUG_RETURN(opts);
2811
}
2812
2813
2814
/*
2815
  SYNOPSIS
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
2822
  RETURNS:
2823
    0 SUCCESS - plugin should be enabled/loaded
2824
  NOTE:
2825
    Requires that a write-lock is held on LOCK_system_variables_hash
2826
*/
2827
static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
2828
                               int *argc, char **argv, my_bool default_enabled)
2829
{
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;
2837
  char *p, *varname;
2838
  int error;
2839
  st_mysql_sys_var *o;
2840
  sys_var *v;
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);
2845
2846
  for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
2847
    count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
2848
2849
  can_disable=
2850
      my_strcasecmp(&my_charset_latin1, tmp->name.str, "MyISAM") &&
2851
      my_strcasecmp(&my_charset_latin1, tmp->name.str, "MEMORY");
2852
2853
  if (count > EXTRA_OPTIONS || (*argc > 1))
2854
  {
2855
    if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count)))
2856
    {
2857
      sql_print_error("Out of memory for plugin '%s'.", tmp->name.str);
2858
      DBUG_RETURN(-1);
2859
    }
2860
    bzero(opts, sizeof(my_option) * count);
2861
2862
    if (construct_options(tmp_root, tmp, opts, &enabled, can_disable))
2863
    {
2864
      sql_print_error("Bad options for plugin '%s'.", tmp->name.str);
2865
      DBUG_RETURN(-1);
2866
    }
2867
2868
    error= handle_options(argc, &argv, opts, get_one_plugin_option);
2869
    (*argc)++; /* add back one for the program name */
2870
2871
    if (error)
2872
    {
2873
       sql_print_error("Parsing options for plugin '%s' failed.",
2874
                       tmp->name.str);
2875
       goto err;
2876
    }
2877
  }
2878
2879
  if (!*enabled && !can_disable)
2880
  {
2881
    sql_print_warning("Plugin '%s' cannot be disabled", tmp->name.str);
2882
    *enabled= TRUE;
2883
  }
2884
2885
  error= 1;
2886
2887
  if (*enabled)
2888
  {
2889
    for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
2890
    {
2891
      if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
2892
        continue;
2893
2894
      if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
2895
        v= new (mem_root) sys_var_pluginvar(var->key + 1, o);
2896
      else
2897
      {
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);
2902
2903
        for (p= varname; *p; p++)
2904
          if (*p == '-')
2905
            *p= '_';
2906
2907
        v= new (mem_root) sys_var_pluginvar(varname, o);
2908
      }
2909
      DBUG_ASSERT(v); /* check that an object was actually constructed */
2910
2911
      /*
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.
2915
      */
2916
      v->chain_sys_var(&chain);
2917
    }
2918
    if (chain.first)
2919
    {
2920
      chain.last->next = NULL;
2921
      if (mysql_add_sys_var_chain(chain.first, NULL))
2922
      {
2923
        sql_print_error("Plugin '%s' has conflicting system variables",
2924
                        tmp->name.str);
2925
        goto err;
2926
      }
2927
      tmp->system_vars= chain.first;
2928
    }
2929
    DBUG_RETURN(0);
2930
  }
2931
2932
  if (enabled_saved && global_system_variables.log_warnings)
2933
    sql_print_information("Plugin '%s' disabled by command line option",
2934
                          tmp->name.str);
2935
err:
2936
  if (opts)
2937
    my_cleanup_options(opts);
2938
  DBUG_RETURN(error);
2939
}
2940
2941
2942
/****************************************************************************
2943
  Help Verbose text with Plugin System Variables
2944
****************************************************************************/
2945
2946
static int option_cmp(my_option *a, my_option *b)
2947
{
2948
  return my_strcasecmp(&my_charset_latin1, a->name, b->name);
2949
}
2950
2951
2952
void my_print_help_inc_plugins(my_option *main_options, uint size)
2953
{
2954
  DYNAMIC_ARRAY all_options;
2955
  struct st_plugin_int *p;
2956
  MEM_ROOT mem_root;
2957
  my_option *opt;
2958
2959
  init_alloc_root(&mem_root, 4096, 4096);
2960
  my_init_dynamic_array(&all_options, sizeof(my_option), size, size/4);
2961
2962
  if (initialized)
2963
    for (uint idx= 0; idx < plugin_array.elements; idx++)
2964
    {
2965
      p= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
2966
2967
      if (!p->plugin->system_vars ||
2968
          !(opt= construct_help_options(&mem_root, p)))
2969
        continue;
2970
2971
      /* Only options with a non-NULL comment are displayed in help text */
2972
      for (;opt->id; opt++)
2973
        if (opt->comment)
2974
          insert_dynamic(&all_options, (uchar*) opt);
2975
    }
2976
2977
  for (;main_options->id; main_options++)
2978
    insert_dynamic(&all_options, (uchar*) main_options);
2979
2980
  sort_dynamic(&all_options, (qsort_cmp) option_cmp);
2981
2982
  /* main_options now points to the empty option terminator */
2983
  insert_dynamic(&all_options, (uchar*) main_options);
2984
2985
  my_print_help((my_option*) all_options.buffer);
2986
  my_print_variables((my_option*) all_options.buffer);
2987
2988
  delete_dynamic(&all_options);
2989
  free_root(&mem_root, MYF(0));
2990
}
2991