~stewart/drizzle/embedded-innodb-create-select-transaction-arrgh

« back to all changes in this revision

Viewing changes to sql/sql_plugin.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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;
 
2689
        if (!(opt->flags & PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY))
 
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
 
 
2794
  for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2);
 
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