~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2005 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
#include "mysql_priv.h"
17
#include <my_pthread.h>
18
#include <my_getopt.h>
19
#define REPORT_TO_LOG  1
20
#define REPORT_TO_USER 2
21
22
#define plugin_ref_to_int(A) (A ? A[0] : NULL)
23
#define plugin_int_to_ref(A) &(A)
24
25
extern struct st_mysql_plugin *mysqld_builtins[];
26
27
char *opt_plugin_load= NULL;
28
char *opt_plugin_dir_ptr;
29
char opt_plugin_dir[FN_REFLEN];
30
/*
31
  When you ad a new plugin type, add both a string and make sure that the
32
  init and deinit array are correctly updated.
33
*/
34
const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
35
{
36
  { C_STRING_WITH_LEN("UDF") },
37
  { C_STRING_WITH_LEN("STORAGE ENGINE") },
38
  { C_STRING_WITH_LEN("FTPARSER") },
39
  { C_STRING_WITH_LEN("DAEMON") },
40
  { C_STRING_WITH_LEN("INFORMATION SCHEMA") },
41
  { C_STRING_WITH_LEN("AUDIT") }
42
};
43
44
extern int initialize_schema_table(st_plugin_int *plugin);
45
extern int finalize_schema_table(st_plugin_int *plugin);
46
47
/*
48
  The number of elements in both plugin_type_initialize and
49
  plugin_type_deinitialize should equal to the number of plugins
50
  defined.
51
*/
52
plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
53
{
54
  0,ha_initialize_handlerton,0,0,initialize_schema_table,
55
  0
56
};
57
58
plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
59
{
60
  0,ha_finalize_handlerton,0,0,finalize_schema_table,
61
  0
62
};
63
64
#ifdef HAVE_DLOPEN
65
static const char *plugin_interface_version_sym=
66
                   "_mysql_plugin_interface_version_";
67
static const char *sizeof_st_plugin_sym=
68
                   "_mysql_sizeof_struct_st_plugin_";
69
static const char *plugin_declarations_sym= "_mysql_plugin_declarations_";
70
static int min_plugin_interface_version= MYSQL_PLUGIN_INTERFACE_VERSION & ~0xFF;
71
#endif
72
73
/* Note that 'int version' must be the first field of every plugin
74
   sub-structure (plugin->info).
75
*/
76
static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
77
{
78
  0x0000,
79
  MYSQL_HANDLERTON_INTERFACE_VERSION,
80
  MYSQL_FTPARSER_INTERFACE_VERSION,
81
  MYSQL_DAEMON_INTERFACE_VERSION,
82
  MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION,
83
  MYSQL_AUDIT_INTERFACE_VERSION
84
};
85
static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
86
{
87
  0x0000, /* UDF: not implemented */
88
  MYSQL_HANDLERTON_INTERFACE_VERSION,
89
  MYSQL_FTPARSER_INTERFACE_VERSION,
90
  MYSQL_DAEMON_INTERFACE_VERSION,
91
  MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION,
92
  MYSQL_AUDIT_INTERFACE_VERSION
93
};
94
95
static bool initialized= 0;
96
97
static DYNAMIC_ARRAY plugin_dl_array;
98
static DYNAMIC_ARRAY plugin_array;
99
static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
100
static bool reap_needed= false;
101
static int plugin_array_version=0;
102
103
/*
104
  write-lock on LOCK_system_variables_hash is required before modifying
105
  the following variables/structures
106
*/
107
static MEM_ROOT plugin_mem_root;
108
static uint global_variables_dynamic_size= 0;
109
static HASH bookmark_hash;
110
111
112
/*
113
  hidden part of opaque value passed to variable check functions.
114
  Used to provide a object-like structure to non C++ consumers.
115
*/
116
struct st_item_value_holder : public st_mysql_value
117
{
118
  Item *item;
119
};
120
121
122
/*
123
  stored in bookmark_hash, this structure is never removed from the
124
  hash and is used to mark a single offset for a thd local variable
125
  even if plugins have been uninstalled and reinstalled, repeatedly.
126
  This structure is allocated from plugin_mem_root.
127
128
  The key format is as follows:
129
    1 byte         - variable type code
130
    name_len bytes - variable name
131
    '\0'           - end of key
132
*/
133
struct st_bookmark
134
{
135
  uint name_len;
136
  int offset;
137
  uint version;
138
  char key[1];
139
};
140
141
142
/*
143
  skeleton of a plugin variable - portion of structure common to all.
144
*/
145
struct st_mysql_sys_var
146
{
147
  MYSQL_PLUGIN_VAR_HEADER;
148
};
149
150
151
/*
152
  sys_var class for access to all plugin variables visible to the user
153
*/
154
class sys_var_pluginvar: public sys_var
155
{
156
public:
157
  struct st_plugin_int *plugin;
158
  struct st_mysql_sys_var *plugin_var;
159
160
  static void *operator new(size_t size, MEM_ROOT *mem_root)
161
  { return (void*) alloc_root(mem_root, (uint) size); }
77.1.46 by Monty Taylor
Finished the warnings work!
162
  static void operator delete(void *ptr_arg __attribute__((__unused__)),
163
                              size_t size __attribute__((__unused__)))
1 by brian
clean slate
164
  { TRASH(ptr_arg, size); }
165
166
  sys_var_pluginvar(const char *name_arg,
167
                    struct st_mysql_sys_var *plugin_var_arg)
168
    :sys_var(name_arg), plugin_var(plugin_var_arg) {}
169
  sys_var_pluginvar *cast_pluginvar() { return this; }
170
  bool is_readonly() const { return plugin_var->flags & PLUGIN_VAR_READONLY; }
171
  bool check_type(enum_var_type type)
172
  { return !(plugin_var->flags & PLUGIN_VAR_THDLOCAL) && type != OPT_GLOBAL; }
173
  bool check_update_type(Item_result type);
174
  SHOW_TYPE show_type();
175
  uchar* real_value_ptr(THD *thd, enum_var_type type);
176
  TYPELIB* plugin_var_typelib(void);
177
  uchar* value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
178
  bool check(THD *thd, set_var *var);
77.1.46 by Monty Taylor
Finished the warnings work!
179
  bool check_default(enum_var_type type __attribute__((__unused__)))
180
    { return is_readonly(); }
181
  void set_default(THD *thd,
182
                   enum_var_type type __attribute__((__unused__)));
1 by brian
clean slate
183
  bool update(THD *thd, set_var *var);
184
};
185
186
187
/* prototypes */
188
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
189
                             const char *list);
190
static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *,
191
                               int *, char **, my_bool);
192
static bool register_builtin(struct st_mysql_plugin *, struct st_plugin_int *,
193
                             struct st_plugin_int **);
194
static void unlock_variables(THD *thd, struct system_variables *vars);
195
static void cleanup_variables(THD *thd, struct system_variables *vars);
196
static void plugin_vars_free_values(sys_var *vars);
197
static void plugin_opt_set_limits(struct my_option *options,
198
                                  const struct st_mysql_sys_var *opt);
199
#define my_intern_plugin_lock(A,B) intern_plugin_lock(A,B CALLER_INFO)
200
#define my_intern_plugin_lock_ci(A,B) intern_plugin_lock(A,B ORIG_CALLER_INFO)
201
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin
202
                                     CALLER_INFO_PROTO);
203
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
204
static void reap_plugins(void);
205
206
207
/* declared in set_var.cc */
208
extern sys_var *intern_find_sys_var(const char *str, uint length, bool no_error);
209
extern bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd,
210
                                 const char *name, longlong val);
211
212
/****************************************************************************
213
  Value type thunks, allows the C world to play in the C++ world
214
****************************************************************************/
215
216
static int item_value_type(struct st_mysql_value *value)
217
{
218
  switch (((st_item_value_holder*)value)->item->result_type()) {
219
  case INT_RESULT:
220
    return MYSQL_VALUE_TYPE_INT;
221
  case REAL_RESULT:
222
    return MYSQL_VALUE_TYPE_REAL;
223
  default:
224
    return MYSQL_VALUE_TYPE_STRING;
225
  }
226
}
227
228
static const char *item_val_str(struct st_mysql_value *value,
229
                                char *buffer, int *length)
230
{
231
  String str(buffer, *length, system_charset_info), *res;
232
  if (!(res= ((st_item_value_holder*)value)->item->val_str(&str)))
233
    return NULL;
234
  *length= res->length();
235
  if (res->c_ptr_quick() == buffer)
236
    return buffer;
237
238
  /*
239
    Lets be nice and create a temporary string since the
240
    buffer was too small
241
  */
242
  return current_thd->strmake(res->c_ptr_quick(), res->length());
243
}
244
245
53.2.2 by Monty Taylor
Updated everything that needs updating to compile with -std=gnu99 -pedantic
246
static int item_val_int(struct st_mysql_value *value, int64_t *buf)
1 by brian
clean slate
247
{
248
  Item *item= ((st_item_value_holder*)value)->item;
249
  *buf= item->val_int();
250
  if (item->is_null())
251
    return 1;
252
  return 0;
253
}
254
255
256
static int item_val_real(struct st_mysql_value *value, double *buf)
257
{
258
  Item *item= ((st_item_value_holder*)value)->item;
259
  *buf= item->val_real();
260
  if (item->is_null())
261
    return 1;
262
  return 0;
263
}
264
265
266
/****************************************************************************
267
  Plugin support code
268
****************************************************************************/
269
270
#ifdef HAVE_DLOPEN
271
272
static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl)
273
{
274
  uint i;
275
  struct st_plugin_dl *tmp;
276
  for (i= 0; i < plugin_dl_array.elements; i++)
277
  {
278
    tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
279
    if (tmp->ref_count &&
280
        ! my_strnncoll(files_charset_info,
281
                       (const uchar *)dl->str, dl->length,
282
                       (const uchar *)tmp->dl.str, tmp->dl.length))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
283
      return(tmp);
1 by brian
clean slate
284
  }
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
285
  return(0);
1 by brian
clean slate
286
}
287
288
289
static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
290
{
291
  uint i;
292
  struct st_plugin_dl *tmp;
293
  for (i= 0; i < plugin_dl_array.elements; i++)
294
  {
295
    tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
296
    if (! tmp->ref_count)
297
    {
298
      memcpy(tmp, plugin_dl, sizeof(struct st_plugin_dl));
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
299
      return(tmp);
1 by brian
clean slate
300
    }
301
  }
302
  if (insert_dynamic(&plugin_dl_array, (uchar*)&plugin_dl))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
303
    return(0);
1 by brian
clean slate
304
  tmp= *dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
305
                        struct st_plugin_dl **)=
306
      (struct st_plugin_dl *) memdup_root(&plugin_mem_root, (uchar*)plugin_dl,
307
                                           sizeof(struct st_plugin_dl));
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
308
  return(tmp);
1 by brian
clean slate
309
}
310
#endif /* HAVE_DLOPEN */
311
312
313
static inline void free_plugin_mem(struct st_plugin_dl *p)
314
{
315
#ifdef HAVE_DLOPEN
316
  if (p->handle)
317
    dlclose(p->handle);
318
#endif
319
  my_free(p->dl.str, MYF(MY_ALLOW_ZERO_PTR));
320
  if (p->version != MYSQL_PLUGIN_INTERFACE_VERSION)
321
    my_free((uchar*)p->plugins, MYF(MY_ALLOW_ZERO_PTR));
322
}
323
324
325
static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
326
{
327
#ifdef HAVE_DLOPEN
328
  char dlpath[FN_REFLEN];
329
  uint plugin_dir_len, dummy_errors, dlpathlen;
330
  struct st_plugin_dl *tmp, plugin_dl;
331
  void *sym;
332
  plugin_dir_len= strlen(opt_plugin_dir);
333
  /*
334
    Ensure that the dll doesn't have a path.
335
    This is done to ensure that only approved libraries from the
336
    plugin directory are used (to make this even remotely secure).
337
  */
338
  if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, FN_LIBCHAR) ||
339
      check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN,
340
                               system_charset_info, 1) ||
341
      plugin_dir_len + dl->length + 1 >= FN_REFLEN)
342
  {
343
    if (report & REPORT_TO_USER)
344
      my_error(ER_UDF_NO_PATHS, MYF(0));
345
    if (report & REPORT_TO_LOG)
346
      sql_print_error(ER(ER_UDF_NO_PATHS));
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
347
    return(0);
1 by brian
clean slate
348
  }
349
  /* If this dll is already loaded just increase ref_count. */
350
  if ((tmp= plugin_dl_find(dl)))
351
  {
352
    tmp->ref_count++;
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
353
    return(tmp);
1 by brian
clean slate
354
  }
355
  bzero(&plugin_dl, sizeof(plugin_dl));
356
  /* Compile dll path */
357
  dlpathlen=
358
    strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS) -
359
    dlpath;
360
  plugin_dl.ref_count= 1;
361
  /* Open new dll handle */
362
  if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW)))
363
  {
364
    const char *errmsg=dlerror();
365
    if (!strncmp(dlpath, errmsg, dlpathlen))
366
    { // if errmsg starts from dlpath, trim this prefix.
367
      errmsg+=dlpathlen;
368
      if (*errmsg == ':') errmsg++;
369
      if (*errmsg == ' ') errmsg++;
370
    }
371
    if (report & REPORT_TO_USER)
372
      my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, errno, errmsg);
373
    if (report & REPORT_TO_LOG)
374
      sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, errno, errmsg);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
375
    return(0);
1 by brian
clean slate
376
  }
377
  /* Determine interface version */
378
  if (!(sym= dlsym(plugin_dl.handle, plugin_interface_version_sym)))
379
  {
380
    free_plugin_mem(&plugin_dl);
381
    if (report & REPORT_TO_USER)
382
      my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_interface_version_sym);
383
    if (report & REPORT_TO_LOG)
384
      sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_interface_version_sym);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
385
    return(0);
1 by brian
clean slate
386
  }
387
  plugin_dl.version= *(int *)sym;
388
  /* Versioning */
389
  if (plugin_dl.version < min_plugin_interface_version ||
390
      (plugin_dl.version >> 8) > (MYSQL_PLUGIN_INTERFACE_VERSION >> 8))
391
  {
392
    free_plugin_mem(&plugin_dl);
393
    if (report & REPORT_TO_USER)
394
      my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, 0,
395
               "plugin interface version mismatch");
396
    if (report & REPORT_TO_LOG)
397
      sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, 0,
398
                      "plugin interface version mismatch");
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
399
    return(0);
1 by brian
clean slate
400
  }
401
  /* Find plugin declarations */
402
  if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))
403
  {
404
    free_plugin_mem(&plugin_dl);
405
    if (report & REPORT_TO_USER)
406
      my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_declarations_sym);
407
    if (report & REPORT_TO_LOG)
408
      sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_declarations_sym);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
409
    return(0);
1 by brian
clean slate
410
  }
411
412
  if (plugin_dl.version != MYSQL_PLUGIN_INTERFACE_VERSION)
413
  {
414
    int i;
415
    uint sizeof_st_plugin;
416
    struct st_mysql_plugin *old, *cur;
417
    char *ptr= (char *)sym;
418
419
    if ((sym= dlsym(plugin_dl.handle, sizeof_st_plugin_sym)))
420
      sizeof_st_plugin= *(int *)sym;
421
    else
422
    {
423
#ifdef ERROR_ON_NO_SIZEOF_PLUGIN_SYMBOL
424
      free_plugin_mem(&plugin_dl);
425
      if (report & REPORT_TO_USER)
426
        my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), sizeof_st_plugin_sym);
427
      if (report & REPORT_TO_LOG)
428
        sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), sizeof_st_plugin_sym);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
429
      return(0);
1 by brian
clean slate
430
#else
431
      /*
432
        When the following assert starts failing, we'll have to switch
433
        to the upper branch of the #ifdef
434
      */
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
435
      assert(min_plugin_interface_version == 0);
1 by brian
clean slate
436
      sizeof_st_plugin= (int)offsetof(struct st_mysql_plugin, version);
437
#endif
438
    }
439
440
    for (i= 0;
441
         ((struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info;
442
         i++)
443
      /* no op */;
444
445
    cur= (struct st_mysql_plugin*)
446
          my_malloc(i*sizeof(struct st_mysql_plugin), MYF(MY_ZEROFILL|MY_WME));
447
    if (!cur)
448
    {
449
      free_plugin_mem(&plugin_dl);
450
      if (report & REPORT_TO_USER)
451
        my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length);
452
      if (report & REPORT_TO_LOG)
453
        sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
454
      return(0);
1 by brian
clean slate
455
    }
456
    /*
457
      All st_plugin fields not initialized in the plugin explicitly, are
458
      set to 0. It matches C standard behaviour for struct initializers that
459
      have less values than the struct definition.
460
    */
461
    for (i=0;
462
         (old=(struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info;
463
         i++)
464
      memcpy(cur+i, old, min(sizeof(cur[i]), sizeof_st_plugin));
465
466
    sym= cur;
467
  }
468
  plugin_dl.plugins= (struct st_mysql_plugin *)sym;
469
470
  /* Duplicate and convert dll name */
471
  plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
472
  if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
473
  {
474
    free_plugin_mem(&plugin_dl);
475
    if (report & REPORT_TO_USER)
476
      my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length);
477
    if (report & REPORT_TO_LOG)
478
      sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
479
    return(0);
1 by brian
clean slate
480
  }
481
  plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length,
482
    files_charset_info, dl->str, dl->length, system_charset_info,
483
    &dummy_errors);
484
  plugin_dl.dl.str[plugin_dl.dl.length]= 0;
485
  /* Add this dll to array */
486
  if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl)))
487
  {
488
    free_plugin_mem(&plugin_dl);
489
    if (report & REPORT_TO_USER)
490
      my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_dl));
491
    if (report & REPORT_TO_LOG)
492
      sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_dl));
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
493
    return(0);
1 by brian
clean slate
494
  }
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
495
  return(tmp);
1 by brian
clean slate
496
#else
497
  if (report & REPORT_TO_USER)
498
    my_error(ER_FEATURE_DISABLED, MYF(0), "plugin", "HAVE_DLOPEN");
499
  if (report & REPORT_TO_LOG)
500
    sql_print_error(ER(ER_FEATURE_DISABLED), "plugin", "HAVE_DLOPEN");
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
501
  return(0);
1 by brian
clean slate
502
#endif
503
}
504
505
506
static void plugin_dl_del(const LEX_STRING *dl)
507
{
508
#ifdef HAVE_DLOPEN
509
  uint i;
510
511
  for (i= 0; i < plugin_dl_array.elements; i++)
512
  {
513
    struct st_plugin_dl *tmp= *dynamic_element(&plugin_dl_array, i,
514
                                               struct st_plugin_dl **);
515
    if (tmp->ref_count &&
516
        ! my_strnncoll(files_charset_info,
517
                       (const uchar *)dl->str, dl->length,
518
                       (const uchar *)tmp->dl.str, tmp->dl.length))
519
    {
520
      /* Do not remove this element, unless no other plugin uses this dll. */
521
      if (! --tmp->ref_count)
522
      {
523
        free_plugin_mem(tmp);
524
        bzero(tmp, sizeof(struct st_plugin_dl));
525
      }
526
      break;
527
    }
528
  }
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
529
  return;
1 by brian
clean slate
530
#endif
531
}
532
533
534
static struct st_plugin_int *plugin_find_internal(const LEX_STRING *name, int type)
535
{
536
  uint i;
537
  if (! initialized)
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
538
    return(0);
1 by brian
clean slate
539
540
  if (type == MYSQL_ANY_PLUGIN)
541
  {
542
    for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
543
    {
544
      struct st_plugin_int *plugin= (st_plugin_int *)
545
        hash_search(&plugin_hash[i], (const uchar *)name->str, name->length);
546
      if (plugin)
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
547
        return(plugin);
1 by brian
clean slate
548
    }
549
  }
550
  else
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
551
    return((st_plugin_int *)
1 by brian
clean slate
552
        hash_search(&plugin_hash[type], (const uchar *)name->str, name->length));
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
553
  return(0);
1 by brian
clean slate
554
}
555
556
557
static SHOW_COMP_OPTION plugin_status(const LEX_STRING *name, int type)
558
{
559
  SHOW_COMP_OPTION rc= SHOW_OPTION_NO;
560
  struct st_plugin_int *plugin;
561
  if ((plugin= plugin_find_internal(name, type)))
562
  {
563
    rc= SHOW_OPTION_DISABLED;
564
    if (plugin->state == PLUGIN_IS_READY)
565
      rc= SHOW_OPTION_YES;
566
  }
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
567
  return(rc);
1 by brian
clean slate
568
}
569
570
571
bool plugin_is_ready(const LEX_STRING *name, int type)
572
{
573
  bool rc= FALSE;
574
  if (plugin_status(name, type) == SHOW_OPTION_YES)
575
    rc= TRUE;
576
  return rc;
577
}
578
579
580
SHOW_COMP_OPTION sys_var_have_plugin::get_option()
581
{
582
  LEX_STRING plugin_name= { (char *) plugin_name_str, plugin_name_len };
583
  return plugin_status(&plugin_name, plugin_type);
584
}
585
586
587
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc CALLER_INFO_PROTO)
588
{
589
  st_plugin_int *pi= plugin_ref_to_int(rc);
590
591
  if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
592
  {
593
    plugin_ref plugin;
594
    /*
595
      For debugging, we do an additional malloc which allows the
596
      memory manager and/or valgrind to track locked references and
597
      double unlocks to aid resolving reference counting.problems.
598
    */
599
    if (!(plugin= (plugin_ref) my_malloc_ci(sizeof(pi), MYF(MY_WME))))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
600
      return(NULL);
1 by brian
clean slate
601
602
    *plugin= pi;
603
    pi->ref_count++;
604
605
    if (lex)
606
      insert_dynamic(&lex->plugins, (uchar*)&plugin);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
607
    return(plugin);
1 by brian
clean slate
608
  }
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
609
  return(NULL);
1 by brian
clean slate
610
}
611
612
613
plugin_ref plugin_lock(THD *thd, plugin_ref *ptr CALLER_INFO_PROTO)
614
{
615
  LEX *lex= thd ? thd->lex : 0;
616
  plugin_ref rc;
617
  rc= my_intern_plugin_lock_ci(lex, *ptr);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
618
  return(rc);
1 by brian
clean slate
619
}
620
621
622
plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name, int type
623
                               CALLER_INFO_PROTO)
624
{
625
  LEX *lex= thd ? thd->lex : 0;
626
  plugin_ref rc= NULL;
627
  st_plugin_int *plugin;
628
  if ((plugin= plugin_find_internal(name, type)))
629
    rc= my_intern_plugin_lock_ci(lex, plugin_int_to_ref(plugin));
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
630
  return(rc);
1 by brian
clean slate
631
}
632
633
634
static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
635
{
636
  uint i;
637
  struct st_plugin_int *tmp;
638
  for (i= 0; i < plugin_array.elements; i++)
639
  {
640
    tmp= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
641
    if (tmp->state == PLUGIN_IS_FREED)
642
    {
643
      memcpy(tmp, plugin, sizeof(struct st_plugin_int));
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
644
      return(tmp);
1 by brian
clean slate
645
    }
646
  }
647
  if (insert_dynamic(&plugin_array, (uchar*)&plugin))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
648
    return(0);
1 by brian
clean slate
649
  tmp= *dynamic_element(&plugin_array, plugin_array.elements - 1,
650
                        struct st_plugin_int **)=
651
       (struct st_plugin_int *) memdup_root(&plugin_mem_root, (uchar*)plugin,
652
                                            sizeof(struct st_plugin_int));
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
653
  return(tmp);
1 by brian
clean slate
654
}
655
656
657
/*
658
  NOTE
659
    Requires that a write-lock is held on LOCK_system_variables_hash
660
*/
661
static bool plugin_add(MEM_ROOT *tmp_root,
662
                       const LEX_STRING *name, const LEX_STRING *dl,
663
                       int *argc, char **argv, int report)
664
{
665
  struct st_plugin_int tmp;
666
  struct st_mysql_plugin *plugin;
667
  if (plugin_find_internal(name, MYSQL_ANY_PLUGIN))
668
  {
669
    if (report & REPORT_TO_USER)
670
      my_error(ER_UDF_EXISTS, MYF(0), name->str);
671
    if (report & REPORT_TO_LOG)
672
      sql_print_error(ER(ER_UDF_EXISTS), name->str);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
673
    return(TRUE);
1 by brian
clean slate
674
  }
675
  /* Clear the whole struct to catch future extensions. */
676
  bzero((char*) &tmp, sizeof(tmp));
677
  if (! (tmp.plugin_dl= plugin_dl_add(dl, report)))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
678
    return(TRUE);
1 by brian
clean slate
679
  /* Find plugin by name */
680
  for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++)
681
  {
682
    uint name_len= strlen(plugin->name);
683
    if (plugin->type >= 0 && plugin->type < MYSQL_MAX_PLUGIN_TYPE_NUM &&
684
        ! my_strnncoll(system_charset_info,
685
                       (const uchar *)name->str, name->length,
686
                       (const uchar *)plugin->name,
687
                       name_len))
688
    {
689
      struct st_plugin_int *tmp_plugin_ptr;
690
      if (*(int*)plugin->info <
691
          min_plugin_info_interface_version[plugin->type] ||
692
          ((*(int*)plugin->info) >> 8) >
693
          (cur_plugin_info_interface_version[plugin->type] >> 8))
694
      {
695
        char buf[256];
696
        strxnmov(buf, sizeof(buf) - 1, "API version for ",
697
                 plugin_type_names[plugin->type].str,
698
                 " plugin is too different", NullS);
699
        if (report & REPORT_TO_USER)
700
          my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dl->str, 0, buf);
701
        if (report & REPORT_TO_LOG)
702
          sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dl->str, 0, buf);
703
        goto err;
704
      }
705
      tmp.plugin= plugin;
706
      tmp.name.str= (char *)plugin->name;
707
      tmp.name.length= name_len;
708
      tmp.ref_count= 0;
709
      tmp.state= PLUGIN_IS_UNINITIALIZED;
710
      if (!test_plugin_options(tmp_root, &tmp, argc, argv, true))
711
      {
712
        if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
713
        {
714
          plugin_array_version++;
715
          if (!my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
716
          {
717
            init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
718
            return(FALSE);
1 by brian
clean slate
719
          }
720
          tmp_plugin_ptr->state= PLUGIN_IS_FREED;
721
        }
722
        mysql_del_sys_var_chain(tmp.system_vars);
723
        goto err;
724
      }
725
      /* plugin was disabled */
726
      plugin_dl_del(dl);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
727
      return(FALSE);
1 by brian
clean slate
728
    }
729
  }
730
  if (report & REPORT_TO_USER)
731
    my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), name->str);
732
  if (report & REPORT_TO_LOG)
733
    sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name->str);
734
err:
735
  plugin_dl_del(dl);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
736
  return(TRUE);
1 by brian
clean slate
737
}
738
739
740
static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
741
{
742
  if (plugin->plugin->status_vars)
743
  {
744
#ifdef FIX_LATER
745
    /*
746
      We have a problem right now where we can not prepend without
747
      breaking backwards compatibility. We will fix this shortly so
748
      that engines have "use names" and we wil use those for
749
      CREATE TABLE, and use the plugin name then for adding automatic
750
      variable names.
751
    */
752
    SHOW_VAR array[2]= {
753
      {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
754
      {0, 0, SHOW_UNDEF}
755
    };
756
    remove_status_vars(array);
757
#else
758
    remove_status_vars(plugin->plugin->status_vars);
759
#endif /* FIX_LATER */
760
  }
761
762
  if (plugin_type_deinitialize[plugin->plugin->type])
763
  {
764
    if ((*plugin_type_deinitialize[plugin->plugin->type])(plugin))
765
    {
766
      sql_print_error("Plugin '%s' of type %s failed deinitialization",
767
                      plugin->name.str, plugin_type_names[plugin->plugin->type].str);
768
    }
769
  }
770
  else if (plugin->plugin->deinit)
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
771
    plugin->plugin->deinit(plugin);
772
1 by brian
clean slate
773
  plugin->state= PLUGIN_IS_UNINITIALIZED;
774
775
  /*
776
    We do the check here because NDB has a worker THD which doesn't
777
    exit until NDB is shut down.
778
  */
779
  if (ref_check && plugin->ref_count)
780
    sql_print_error("Plugin '%s' has ref_count=%d after deinitialization.",
781
                    plugin->name.str, plugin->ref_count);
782
}
783
784
785
static void plugin_del(struct st_plugin_int *plugin)
786
{
787
  /* Free allocated strings before deleting the plugin. */
788
  plugin_vars_free_values(plugin->system_vars);
789
  hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
790
  if (plugin->plugin_dl)
791
    plugin_dl_del(&plugin->plugin_dl->dl);
792
  plugin->state= PLUGIN_IS_FREED;
793
  plugin_array_version++;
794
  rw_wrlock(&LOCK_system_variables_hash);
795
  mysql_del_sys_var_chain(plugin->system_vars);
796
  rw_unlock(&LOCK_system_variables_hash);
797
  free_root(&plugin->mem_root, MYF(0));
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
798
  return;
1 by brian
clean slate
799
}
800
801
#ifdef NOT_USED
802
803
static void plugin_del(const LEX_STRING *name)
804
{
805
  struct st_plugin_int *plugin;
806
  if ((plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
807
    plugin_del(plugin);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
808
  return;
1 by brian
clean slate
809
}
810
811
#endif
812
813
static void reap_plugins(void)
814
{
815
  uint count, idx;
816
  struct st_plugin_int *plugin, **reap, **list;
817
818
  if (!reap_needed)
819
    return;
820
821
  reap_needed= false;
822
  count= plugin_array.elements;
823
  reap= (struct st_plugin_int **)my_alloca(sizeof(plugin)*(count+1));
824
  *(reap++)= NULL;
825
826
  for (idx= 0; idx < count; idx++)
827
  {
828
    plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
829
    if (plugin->state == PLUGIN_IS_DELETED && !plugin->ref_count)
830
    {
831
      /* change the status flag to prevent reaping by another thread */
832
      plugin->state= PLUGIN_IS_DYING;
833
      *(reap++)= plugin;
834
    }
835
  }
836
837
  list= reap;
838
  while ((plugin= *(--list)))
839
    plugin_deinitialize(plugin, true);
840
841
  while ((plugin= *(--reap)))
842
    plugin_del(plugin);
843
844
  my_afree(reap);
845
}
846
847
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin)
848
{
849
  int i;
850
  st_plugin_int *pi;
851
852
  if (!plugin)
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
853
    return;
1 by brian
clean slate
854
855
  pi= plugin_ref_to_int(plugin);
856
857
  my_free((uchar*) plugin, MYF(MY_WME));
858
859
  if (lex)
860
  {
861
    /*
862
      Remove one instance of this plugin from the use list.
863
      We are searching backwards so that plugins locked last
864
      could be unlocked faster - optimizing for LIFO semantics.
865
    */
866
    for (i= lex->plugins.elements - 1; i >= 0; i--)
867
      if (plugin == *dynamic_element(&lex->plugins, i, plugin_ref*))
868
      {
869
        delete_dynamic_element(&lex->plugins, i);
870
        break;
871
      }
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
872
    assert(i >= 0);
1 by brian
clean slate
873
  }
874
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
875
  assert(pi->ref_count);
1 by brian
clean slate
876
  pi->ref_count--;
877
878
  if (pi->state == PLUGIN_IS_DELETED && !pi->ref_count)
879
    reap_needed= true;
880
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
881
  return;
1 by brian
clean slate
882
}
883
884
885
void plugin_unlock(THD *thd, plugin_ref plugin)
886
{
887
  LEX *lex= thd ? thd->lex : 0;
888
  if (!plugin)
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
889
    return;
1 by brian
clean slate
890
  intern_plugin_unlock(lex, plugin);
891
  reap_plugins();
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
892
  return;
1 by brian
clean slate
893
}
894
895
896
void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
897
{
898
  LEX *lex= thd ? thd->lex : 0;
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
899
  assert(list);
1 by brian
clean slate
900
  while (count--)
901
    intern_plugin_unlock(lex, *list++);
902
  reap_plugins();
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
903
  return;
1 by brian
clean slate
904
}
905
906
907
static int plugin_initialize(struct st_plugin_int *plugin)
908
{
909
910
  if (plugin_type_initialize[plugin->plugin->type])
911
  {
912
    if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
913
    {
914
      sql_print_error("Plugin '%s' registration as a %s failed.",
915
                      plugin->name.str, plugin_type_names[plugin->plugin->type].str);
916
      goto err;
917
    }
918
  }
919
  else if (plugin->plugin->init)
920
  {
921
    if (plugin->plugin->init(plugin))
922
    {
923
      sql_print_error("Plugin '%s' init function returned error.",
924
                      plugin->name.str);
925
      goto err;
926
    }
927
  }
928
929
  plugin->state= PLUGIN_IS_READY;
930
931
  if (plugin->plugin->status_vars)
932
  {
933
#ifdef FIX_LATER
934
    /*
935
      We have a problem right now where we can not prepend without
936
      breaking backwards compatibility. We will fix this shortly so
937
      that engines have "use names" and we wil use those for
938
      CREATE TABLE, and use the plugin name then for adding automatic
939
      variable names.
940
    */
941
    SHOW_VAR array[2]= {
942
      {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
943
      {0, 0, SHOW_UNDEF}
944
    };
945
    if (add_status_vars(array)) // add_status_vars makes a copy
946
      goto err;
947
#else
948
    add_status_vars(plugin->plugin->status_vars); // add_status_vars makes a copy
949
#endif /* FIX_LATER */
950
  }
951
952
  /*
953
    set the plugin attribute of plugin's sys vars so they are pointing
954
    to the active plugin
955
  */
956
  if (plugin->system_vars)
957
  {
958
    sys_var_pluginvar *var= plugin->system_vars->cast_pluginvar();
959
    for (;;)
960
    {
961
      var->plugin= plugin;
962
      if (!var->next)
963
        break;
964
      var= var->next->cast_pluginvar();
965
    }
966
  }
967
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
968
  return(0);
1 by brian
clean slate
969
err:
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
970
  return(1);
1 by brian
clean slate
971
}
972
973
974
extern "C" uchar *get_plugin_hash_key(const uchar *, size_t *, my_bool);
975
extern "C" uchar *get_bookmark_hash_key(const uchar *, size_t *, my_bool);
976
977
978
uchar *get_plugin_hash_key(const uchar *buff, size_t *length,
979
                           my_bool not_used __attribute__((unused)))
980
{
981
  struct st_plugin_int *plugin= (st_plugin_int *)buff;
982
  *length= (uint)plugin->name.length;
983
  return((uchar *)plugin->name.str);
984
}
985
986
987
uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
988
                             my_bool not_used __attribute__((unused)))
989
{
990
  struct st_bookmark *var= (st_bookmark *)buff;
991
  *length= var->name_len + 1;
992
  return (uchar*) var->key;
993
}
994
995
996
/*
997
  The logic is that we first load and initialize all compiled in plugins.
998
  From there we load up the dynamic types (assuming we have not been told to
999
  skip this part).
1000
1001
  Finally we initialize everything, aka the dynamic that have yet to initialize.
1002
*/
1003
int plugin_init(int *argc, char **argv, int flags)
1004
{
1005
  uint i;
1006
  bool def_enabled, is_myisam;
1007
  struct st_mysql_plugin **builtins;
1008
  struct st_mysql_plugin *plugin;
1009
  struct st_plugin_int tmp, *plugin_ptr, **reap;
1010
  MEM_ROOT tmp_root;
1011
1012
  if (initialized)
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1013
    return(0);
1 by brian
clean slate
1014
1015
  init_alloc_root(&plugin_mem_root, 4096, 4096);
1016
  init_alloc_root(&tmp_root, 4096, 4096);
1017
1018
  if (hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
1019
                  get_bookmark_hash_key, NULL, HASH_UNIQUE))
1020
      goto err;
1021
1022
1023
  if (my_init_dynamic_array(&plugin_dl_array,
1024
                            sizeof(struct st_plugin_dl *),16,16) ||
1025
      my_init_dynamic_array(&plugin_array,
1026
                            sizeof(struct st_plugin_int *),16,16))
1027
    goto err;
1028
1029
  for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
1030
  {
1031
    if (hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
1032
                  get_plugin_hash_key, NULL, HASH_UNIQUE))
1033
      goto err;
1034
  }
1035
1036
  initialized= 1;
1037
1038
  /*
1039
    First we register builtin plugins
1040
  */
1041
  for (builtins= mysqld_builtins; *builtins; builtins++)
1042
  {
1043
    for (plugin= *builtins; plugin->info; plugin++)
1044
    {
1045
      /* by default, only ndbcluster is disabled */
1046
      def_enabled=
1047
        my_strcasecmp(&my_charset_latin1, plugin->name, "NDBCLUSTER") != 0;
1048
      bzero(&tmp, sizeof(tmp));
1049
      tmp.plugin= plugin;
1050
      tmp.name.str= (char *)plugin->name;
1051
      tmp.name.length= strlen(plugin->name);
1052
1053
      free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
1054
      if (test_plugin_options(&tmp_root, &tmp, argc, argv, def_enabled))
1055
        continue;
1056
1057
      if (register_builtin(plugin, &tmp, &plugin_ptr))
1058
        goto err_unlock;
1059
1060
      /* only initialize MyISAM and CSV at this stage */
1061
      if (!(is_myisam=
1062
            !my_strcasecmp(&my_charset_latin1, plugin->name, "MyISAM")) &&
1063
          my_strcasecmp(&my_charset_latin1, plugin->name, "CSV"))
1064
        continue;
1065
1066
      if (plugin_initialize(plugin_ptr))
1067
        goto err_unlock;
1068
1069
      /*
1070
        initialize the global default storage engine so that it may
1071
        not be null in any child thread.
1072
      */
1073
      if (is_myisam)
1074
      {
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
1075
        assert(!global_system_variables.table_plugin);
1 by brian
clean slate
1076
        global_system_variables.table_plugin=
1077
          my_intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr));
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
1078
        assert(plugin_ptr->ref_count == 1);
1 by brian
clean slate
1079
      }
1080
    }
1081
  }
1082
1083
  /* should now be set to MyISAM storage engine */
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
1084
  assert(global_system_variables.table_plugin);
1 by brian
clean slate
1085
1086
  /* Register all dynamic plugins */
1087
  if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
1088
  {
1089
    if (opt_plugin_load)
1090
      plugin_load_list(&tmp_root, argc, argv, opt_plugin_load);
1091
  }
1092
1093
  if (flags & PLUGIN_INIT_SKIP_INITIALIZATION)
1094
    goto end;
1095
1096
  /*
1097
    Now we initialize all remaining plugins
1098
  */
1099
1100
  reap= (st_plugin_int **) my_alloca((plugin_array.elements+1) * sizeof(void*));
1101
  *(reap++)= NULL;
1102
1103
  for (i= 0; i < plugin_array.elements; i++)
1104
  {
1105
    plugin_ptr= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
1106
    if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED)
1107
    {
1108
      if (plugin_initialize(plugin_ptr))
1109
      {
1110
        plugin_ptr->state= PLUGIN_IS_DYING;
1111
        *(reap++)= plugin_ptr;
1112
      }
1113
    }
1114
  }
1115
1116
  /*
1117
    Check if any plugins have to be reaped
1118
  */
1119
  while ((plugin_ptr= *(--reap)))
1120
  {
1121
    plugin_deinitialize(plugin_ptr, true);
1122
    plugin_del(plugin_ptr);
1123
  }
1124
1125
  my_afree(reap);
1126
1127
end:
1128
  free_root(&tmp_root, MYF(0));
1129
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1130
  return(0);
1 by brian
clean slate
1131
1132
err_unlock:
1133
err:
1134
  free_root(&tmp_root, MYF(0));
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1135
  return(1);
1 by brian
clean slate
1136
}
1137
1138
1139
static bool register_builtin(struct st_mysql_plugin *plugin,
1140
                             struct st_plugin_int *tmp,
1141
                             struct st_plugin_int **ptr)
1142
{
1143
1144
  tmp->state= PLUGIN_IS_UNINITIALIZED;
1145
  tmp->ref_count= 0;
1146
  tmp->plugin_dl= 0;
1147
1148
  if (insert_dynamic(&plugin_array, (uchar*)&tmp))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1149
    return(1);
1 by brian
clean slate
1150
1151
  *ptr= *dynamic_element(&plugin_array, plugin_array.elements - 1,
1152
                         struct st_plugin_int **)=
1153
        (struct st_plugin_int *) memdup_root(&plugin_mem_root, (uchar*)tmp,
1154
                                             sizeof(struct st_plugin_int));
1155
1156
  if (my_hash_insert(&plugin_hash[plugin->type],(uchar*) *ptr))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1157
    return(1);
1 by brian
clean slate
1158
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1159
  return(0);
1 by brian
clean slate
1160
}
1161
1162
1163
#ifdef NOT_USED_YET
1164
/*
1165
  Register a plugin at run time. (note, this doesn't initialize a plugin)
1166
  Will be useful for embedded applications.
1167
1168
  SYNOPSIS
1169
    plugin_register_builtin()
1170
    thd         current thread (used to store scratch data in mem_root)
1171
    plugin      static plugin to install
1172
1173
  RETURN
1174
    false - plugin registered successfully
1175
*/
1176
bool plugin_register_builtin(THD *thd, struct st_mysql_plugin *plugin)
1177
{
1178
  struct st_plugin_int tmp, *ptr;
1179
  bool result= true;
1180
  int dummy_argc= 0;
1181
1182
  bzero(&tmp, sizeof(tmp));
1183
  tmp.plugin= plugin;
1184
  tmp.name.str= (char *)plugin->name;
1185
  tmp.name.length= strlen(plugin->name);
1186
1187
  rw_wrlock(&LOCK_system_variables_hash);
1188
1189
  if (test_plugin_options(thd->mem_root, &tmp, &dummy_argc, NULL, true))
1190
    goto end;
1191
1192
  if ((result= register_builtin(plugin, &tmp, &ptr)))
1193
    mysql_del_sys_var_chain(tmp.system_vars);
1194
1195
end:
1196
  rw_unlock(&LOCK_system_variables_hash);
1197
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1198
  return(result);;
1 by brian
clean slate
1199
}
1200
#endif /* NOT_USED_YET */
1201
1202
1203
/*
1204
  called only by plugin_init()
1205
*/
1206
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
1207
                             const char *list)
1208
{
1209
  char buffer[FN_REFLEN];
1210
  LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
1211
  struct st_plugin_dl *plugin_dl;
1212
  struct st_mysql_plugin *plugin;
1213
  char *p= buffer;
1214
  while (list)
1215
  {
1216
    if (p == buffer + sizeof(buffer) - 1)
1217
    {
1218
      sql_print_error("plugin-load parameter too long");
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1219
      return(TRUE);
1 by brian
clean slate
1220
    }
1221
1222
    switch ((*(p++)= *(list++))) {
1223
    case '\0':
1224
      list= NULL; /* terminate the loop */
1225
      /* fall through */
1226
    case ':':     /* can't use this as delimiter as it may be drive letter */
1227
    case ';':
1228
      str->str[str->length]= '\0';
1229
      if (str == &name)  // load all plugins in named module
1230
      {
1231
        if (!name.length)
1232
        {
1233
          p--;    /* reset pointer */
1234
          continue;
1235
        }
1236
1237
        dl= name;
1238
        if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG)))
1239
        {
1240
          for (plugin= plugin_dl->plugins; plugin->info; plugin++)
1241
          {
1242
            name.str= (char *) plugin->name;
1243
            name.length= strlen(name.str);
1244
1245
            free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
1246
            if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
1247
              goto error;
1248
          }
1249
          plugin_dl_del(&dl); // reduce ref count
1250
        }
1251
      }
1252
      else
1253
      {
1254
        free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
1255
        if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
1256
          goto error;
1257
      }
1258
      name.length= dl.length= 0;
1259
      dl.str= NULL; name.str= p= buffer;
1260
      str= &name;
1261
      continue;
1262
    case '=':
1263
    case '#':
1264
      if (str == &name)
1265
      {
1266
        name.str[name.length]= '\0';
1267
        str= &dl;
1268
        str->str= p;
1269
        continue;
1270
      }
1271
    default:
1272
      str->length++;
1273
      continue;
1274
    }
1275
  }
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1276
  return(FALSE);
1 by brian
clean slate
1277
error:
1278
  sql_print_error("Couldn't load plugin named '%s' with soname '%s'.",
1279
                  name.str, dl.str);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1280
  return(TRUE);
1 by brian
clean slate
1281
}
1282
1283
1284
void plugin_shutdown(void)
1285
{
1286
  uint i, count= plugin_array.elements, free_slots= 0;
1287
  struct st_plugin_int **plugins, *plugin;
1288
  struct st_plugin_dl **dl;
1289
1290
  if (initialized)
1291
  {
1292
    reap_needed= true;
1293
1294
    /*
1295
      We want to shut down plugins in a reasonable order, this will
1296
      become important when we have plugins which depend upon each other.
1297
      Circular references cannot be reaped so they are forced afterwards.
1298
      TODO: Have an additional step here to notify all active plugins that
1299
      shutdown is requested to allow plugins to deinitialize in parallel.
1300
    */
1301
    while (reap_needed && (count= plugin_array.elements))
1302
    {
1303
      reap_plugins();
1304
      for (i= free_slots= 0; i < count; i++)
1305
      {
1306
        plugin= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
1307
        switch (plugin->state) {
1308
        case PLUGIN_IS_READY:
1309
          plugin->state= PLUGIN_IS_DELETED;
1310
          reap_needed= true;
1311
          break;
1312
        case PLUGIN_IS_FREED:
1313
        case PLUGIN_IS_UNINITIALIZED:
1314
          free_slots++;
1315
          break;
1316
        }
1317
      }
1318
      if (!reap_needed)
1319
      {
1320
        /*
1321
          release any plugin references held.
1322
        */
1323
        unlock_variables(NULL, &global_system_variables);
1324
        unlock_variables(NULL, &max_system_variables);
1325
      }
1326
    }
1327
1328
    if (count > free_slots)
1329
      sql_print_warning("Forcing shutdown of %d plugins", count - free_slots);
1330
1331
    plugins= (struct st_plugin_int **) my_alloca(sizeof(void*) * (count+1));
1332
1333
    /*
1334
      If we have any plugins which did not die cleanly, we force shutdown
1335
    */
1336
    for (i= 0; i < count; i++)
1337
    {
1338
      plugins[i]= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
1339
      /* change the state to ensure no reaping races */
1340
      if (plugins[i]->state == PLUGIN_IS_DELETED)
1341
        plugins[i]->state= PLUGIN_IS_DYING;
1342
    }
1343
1344
    /*
1345
      We loop through all plugins and call deinit() if they have one.
1346
    */
1347
    for (i= 0; i < count; i++)
1348
      if (!(plugins[i]->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_FREED)))
1349
      {
1350
        sql_print_information("Plugin '%s' will be forced to shutdown",
1351
                              plugins[i]->name.str);
1352
        /*
1353
          We are forcing deinit on plugins so we don't want to do a ref_count
1354
          check until we have processed all the plugins.
1355
        */
1356
        plugin_deinitialize(plugins[i], false);
1357
      }
1358
1359
    /*
1360
      We defer checking ref_counts until after all plugins are deinitialized
1361
      as some may have worker threads holding on to plugin references.
1362
    */
1363
    for (i= 0; i < count; i++)
1364
    {
1365
      if (plugins[i]->ref_count)
1366
        sql_print_error("Plugin '%s' has ref_count=%d after shutdown.",
1367
                        plugins[i]->name.str, plugins[i]->ref_count);
1368
      if (plugins[i]->state & PLUGIN_IS_UNINITIALIZED)
1369
        plugin_del(plugins[i]);
1370
    }
1371
1372
    /*
1373
      Now we can deallocate all memory.
1374
    */
1375
1376
    cleanup_variables(NULL, &global_system_variables);
1377
    cleanup_variables(NULL, &max_system_variables);
1378
1379
    initialized= 0;
1380
1381
    my_afree(plugins);
1382
  }
1383
1384
  /* Dispose of the memory */
1385
1386
  for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
1387
    hash_free(&plugin_hash[i]);
1388
  delete_dynamic(&plugin_array);
1389
1390
  count= plugin_dl_array.elements;
1391
  dl= (struct st_plugin_dl **)my_alloca(sizeof(void*) * count);
1392
  for (i= 0; i < count; i++)
1393
    dl[i]= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
1394
  for (i= 0; i < plugin_dl_array.elements; i++)
1395
    free_plugin_mem(dl[i]);
1396
  my_afree(dl);
1397
  delete_dynamic(&plugin_dl_array);
1398
1399
  hash_free(&bookmark_hash);
1400
  free_root(&plugin_mem_root, MYF(0));
1401
1402
  global_variables_dynamic_size= 0;
1403
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1404
  return;
1 by brian
clean slate
1405
}
1406
1407
1408
bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
1409
                       int type, uint state_mask, void *arg)
1410
{
1411
  uint idx, total;
1412
  struct st_plugin_int *plugin, **plugins;
1413
  int version=plugin_array_version;
1414
1415
  if (!initialized)
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1416
    return(FALSE);
1 by brian
clean slate
1417
1418
  state_mask= ~state_mask; // do it only once
1419
1420
  total= type == MYSQL_ANY_PLUGIN ? plugin_array.elements
1421
                                  : plugin_hash[type].records;
1422
  /*
1423
    Do the alloca out here in case we do have a working alloca:
1424
        leaving the nested stack frame invalidates alloca allocation.
1425
  */
1426
  plugins=(struct st_plugin_int **)my_alloca(total*sizeof(plugin));
1427
  if (type == MYSQL_ANY_PLUGIN)
1428
  {
1429
    for (idx= 0; idx < total; idx++)
1430
    {
1431
      plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
1432
      plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
1433
    }
1434
  }
1435
  else
1436
  {
1437
    HASH *hash= plugin_hash + type;
1438
    for (idx= 0; idx < total; idx++)
1439
    {
1440
      plugin= (struct st_plugin_int *) hash_element(hash, idx);
1441
      plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
1442
    }
1443
  }
1444
  for (idx= 0; idx < total; idx++)
1445
  {
1446
    if (unlikely(version != plugin_array_version))
1447
    {
1448
      for (uint i=idx; i < total; i++)
1449
        if (plugins[i] && plugins[i]->state & state_mask)
1450
          plugins[i]=0;
1451
    }
1452
    plugin= plugins[idx];
1453
    /* It will stop iterating on first engine error when "func" returns TRUE */
1454
    if (plugin && func(thd, plugin_int_to_ref(plugin), arg))
1455
        goto err;
1456
  }
1457
1458
  my_afree(plugins);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1459
  return(FALSE);
1 by brian
clean slate
1460
err:
1461
  my_afree(plugins);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1462
  return(TRUE);
1 by brian
clean slate
1463
}
1464
1465
1466
/****************************************************************************
1467
  Internal type declarations for variables support
1468
****************************************************************************/
1469
1470
#undef MYSQL_SYSVAR_NAME
1471
#define MYSQL_SYSVAR_NAME(name) name
1472
#define PLUGIN_VAR_TYPEMASK 0x007f
1473
1474
#define EXTRA_OPTIONS 3 /* options for: 'foo', 'plugin-foo' and NULL */
1475
1476
typedef DECLARE_MYSQL_SYSVAR_BASIC(sysvar_bool_t, my_bool);
1477
typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_bool_t, my_bool);
1478
typedef DECLARE_MYSQL_SYSVAR_BASIC(sysvar_str_t, char *);
1479
typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_str_t, char *);
1480
1481
typedef DECLARE_MYSQL_SYSVAR_TYPELIB(sysvar_enum_t, unsigned long);
1482
typedef DECLARE_MYSQL_THDVAR_TYPELIB(thdvar_enum_t, unsigned long);
1483
typedef DECLARE_MYSQL_SYSVAR_TYPELIB(sysvar_set_t, ulonglong);
1484
typedef DECLARE_MYSQL_THDVAR_TYPELIB(thdvar_set_t, ulonglong);
1485
1486
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_int_t, int);
1487
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_long_t, long);
1488
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_longlong_t, longlong);
1489
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_uint_t, uint);
1490
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulong_t, ulong);
1491
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulonglong_t, ulonglong);
1492
1493
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_int_t, int);
1494
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_long_t, long);
1495
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_longlong_t, longlong);
1496
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_uint_t, uint);
1497
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulong_t, ulong);
1498
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulonglong_t, ulonglong);
1499
1500
#define SET_PLUGIN_VAR_RESOLVE(opt)\
1501
  *(mysql_sys_var_ptr_p*)&((opt)->resolve)= mysql_sys_var_ptr
1502
typedef uchar *(*mysql_sys_var_ptr_p)(void* a_thd, int offset);
1503
1504
1505
/****************************************************************************
1506
  default variable data check and update functions
1507
****************************************************************************/
1508
77.1.46 by Monty Taylor
Finished the warnings work!
1509
static int check_func_bool(THD *thd __attribute__((__unused__)),
1510
                           struct st_mysql_sys_var *var,
1 by brian
clean slate
1511
                           void *save, st_mysql_value *value)
1512
{
1513
  char buff[STRING_BUFFER_USUAL_SIZE];
1514
  const char *strvalue= "NULL", *str;
1515
  int result, length;
53.2.2 by Monty Taylor
Updated everything that needs updating to compile with -std=gnu99 -pedantic
1516
  int64_t tmp;
1 by brian
clean slate
1517
1518
  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
1519
  {
1520
    length= sizeof(buff);
1521
    if (!(str= value->val_str(value, buff, &length)) ||
1522
        (result= find_type(&bool_typelib, str, length, 1)-1) < 0)
1523
    {
1524
      if (str)
1525
        strvalue= str;
1526
      goto err;
1527
    }
1528
  }
1529
  else
1530
  {
1531
    if (value->val_int(value, &tmp) < 0)
1532
      goto err;
1533
    if (tmp > 1)
1534
    {
1535
      llstr(tmp, buff);
1536
      strvalue= buff;
1537
      goto err;
1538
    }
1539
    result= (int) tmp;
1540
  }
1541
  *(int*)save= -result;
1542
  return 0;
1543
err:
1544
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
1545
  return 1;
1546
}
1547
1548
1549
static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
1550
                          void *save, st_mysql_value *value)
1551
{
1552
  my_bool fixed;
53.2.2 by Monty Taylor
Updated everything that needs updating to compile with -std=gnu99 -pedantic
1553
  int64_t tmp;
1 by brian
clean slate
1554
  struct my_option options;
1555
  value->val_int(value, &tmp);
1556
  plugin_opt_set_limits(&options, var);
1557
1558
  if (var->flags & PLUGIN_VAR_UNSIGNED)
1559
    *(uint *)save= (uint) getopt_ull_limit_value((ulonglong) tmp, &options,
1560
                                                   &fixed);
1561
  else
1562
    *(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed);
1563
1564
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
1565
                              var->name, (longlong) tmp);
1566
}
1567
1568
1569
static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
1570
                          void *save, st_mysql_value *value)
1571
{
1572
  my_bool fixed;
53.2.2 by Monty Taylor
Updated everything that needs updating to compile with -std=gnu99 -pedantic
1573
  int64_t tmp;
1 by brian
clean slate
1574
  struct my_option options;
1575
  value->val_int(value, &tmp);
1576
  plugin_opt_set_limits(&options, var);
1577
1578
  if (var->flags & PLUGIN_VAR_UNSIGNED)
1579
    *(ulong *)save= (ulong) getopt_ull_limit_value((ulonglong) tmp, &options,
1580
                                                   &fixed);
1581
  else
1582
    *(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed);
1583
1584
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
1585
                              var->name, (longlong) tmp);
1586
}
1587
1588
1589
static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var,
1590
                               void *save, st_mysql_value *value)
1591
{
1592
  my_bool fixed;
53.2.2 by Monty Taylor
Updated everything that needs updating to compile with -std=gnu99 -pedantic
1593
  int64_t tmp;
1 by brian
clean slate
1594
  struct my_option options;
1595
  value->val_int(value, &tmp);
1596
  plugin_opt_set_limits(&options, var);
1597
1598
  if (var->flags & PLUGIN_VAR_UNSIGNED)
1599
    *(ulonglong *)save= getopt_ull_limit_value((ulonglong) tmp, &options,
1600
                                               &fixed);
1601
  else
1602
    *(longlong *)save= getopt_ll_limit_value(tmp, &options, &fixed);
1603
1604
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
1605
                              var->name, (longlong) tmp);
1606
}
1607
77.1.46 by Monty Taylor
Finished the warnings work!
1608
static int check_func_str(THD *thd,
1609
                          struct st_mysql_sys_var *var __attribute__((__unused__)),
1 by brian
clean slate
1610
                          void *save, st_mysql_value *value)
1611
{
1612
  char buff[STRING_BUFFER_USUAL_SIZE];
1613
  const char *str;
1614
  int length;
1615
1616
  length= sizeof(buff);
1617
  if ((str= value->val_str(value, buff, &length)))
1618
    str= thd->strmake(str, length);
1619
  *(const char**)save= str;
1620
  return 0;
1621
}
1622
1623
77.1.46 by Monty Taylor
Finished the warnings work!
1624
static int check_func_enum(THD *thd __attribute__((__unused__)),
1625
                           struct st_mysql_sys_var *var,
1 by brian
clean slate
1626
                           void *save, st_mysql_value *value)
1627
{
1628
  char buff[STRING_BUFFER_USUAL_SIZE];
1629
  const char *strvalue= "NULL", *str;
1630
  TYPELIB *typelib;
53.2.2 by Monty Taylor
Updated everything that needs updating to compile with -std=gnu99 -pedantic
1631
  int64_t tmp;
1 by brian
clean slate
1632
  long result;
1633
  int length;
1634
1635
  if (var->flags & PLUGIN_VAR_THDLOCAL)
1636
    typelib= ((thdvar_enum_t*) var)->typelib;
1637
  else
1638
    typelib= ((sysvar_enum_t*) var)->typelib;
1639
1640
  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
1641
  {
1642
    length= sizeof(buff);
1643
    if (!(str= value->val_str(value, buff, &length)))
1644
      goto err;
1645
    if ((result= (long)find_type(typelib, str, length, 1)-1) < 0)
1646
    {
1647
      strvalue= str;
1648
      goto err;
1649
    }
1650
  }
1651
  else
1652
  {
1653
    if (value->val_int(value, &tmp))
1654
      goto err;
1655
    if (tmp >= typelib->count)
1656
    {
1657
      llstr(tmp, buff);
1658
      strvalue= buff;
1659
      goto err;
1660
    }
1661
    result= (long) tmp;
1662
  }
1663
  *(long*)save= result;
1664
  return 0;
1665
err:
1666
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
1667
  return 1;
1668
}
1669
1670
77.1.46 by Monty Taylor
Finished the warnings work!
1671
static int check_func_set(THD *thd __attribute__((__unused__)),
1672
                          struct st_mysql_sys_var *var,
1 by brian
clean slate
1673
                          void *save, st_mysql_value *value)
1674
{
1675
  char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
1676
  const char *strvalue= "NULL", *str;
1677
  TYPELIB *typelib;
1678
  ulonglong result;
1679
  uint error_len;
1680
  bool not_used;
1681
  int length;
1682
1683
  if (var->flags & PLUGIN_VAR_THDLOCAL)
1684
    typelib= ((thdvar_set_t*) var)->typelib;
1685
  else
1686
    typelib= ((sysvar_set_t*)var)->typelib;
1687
1688
  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
1689
  {
1690
    length= sizeof(buff);
1691
    if (!(str= value->val_str(value, buff, &length)))
1692
      goto err;
1693
    result= find_set(typelib, str, length, NULL,
1694
                     &error, &error_len, &not_used);
1695
    if (error_len)
1696
    {
1697
      strmake(buff, error, min(sizeof(buff), error_len));
1698
      strvalue= buff;
1699
      goto err;
1700
    }
1701
  }
1702
  else
1703
  {
53.2.2 by Monty Taylor
Updated everything that needs updating to compile with -std=gnu99 -pedantic
1704
    if (value->val_int(value, (int64_t *)&result))
1 by brian
clean slate
1705
      goto err;
80.1.1 by Brian Aker
LL() cleanup
1706
    if (unlikely((result >= (1ULL << typelib->count)) &&
1 by brian
clean slate
1707
                 (typelib->count < sizeof(long)*8)))
1708
    {
1709
      llstr(result, buff);
1710
      strvalue= buff;
1711
      goto err;
1712
    }
1713
  }
1714
  *(ulonglong*)save= result;
1715
  return 0;
1716
err:
1717
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
1718
  return 1;
1719
}
1720
1721
77.1.46 by Monty Taylor
Finished the warnings work!
1722
static void update_func_bool(THD *thd __attribute__((__unused__)),
1723
                             struct st_mysql_sys_var *var __attribute__((__unused__)),
1 by brian
clean slate
1724
                             void *tgt, const void *save)
1725
{
1726
  *(my_bool *) tgt= *(int *) save ? 1 : 0;
1727
}
1728
1729
77.1.46 by Monty Taylor
Finished the warnings work!
1730
static void update_func_int(THD *thd __attribute__((__unused__)),
1731
                            struct st_mysql_sys_var *var __attribute__((__unused__)),
1 by brian
clean slate
1732
                             void *tgt, const void *save)
1733
{
1734
  *(int *)tgt= *(int *) save;
1735
}
1736
1737
77.1.46 by Monty Taylor
Finished the warnings work!
1738
static void update_func_long(THD *thd __attribute__((__unused__)),
1739
                             struct st_mysql_sys_var *var __attribute__((__unused__)),
1 by brian
clean slate
1740
                             void *tgt, const void *save)
1741
{
1742
  *(long *)tgt= *(long *) save;
1743
}
1744
1745
77.1.46 by Monty Taylor
Finished the warnings work!
1746
static void update_func_longlong(THD *thd __attribute__((__unused__)),
1747
                                 struct st_mysql_sys_var *var __attribute__((__unused__)),
1748
                                 void *tgt, const void *save)
1 by brian
clean slate
1749
{
1750
  *(longlong *)tgt= *(ulonglong *) save;
1751
}
1752
1753
77.1.46 by Monty Taylor
Finished the warnings work!
1754
static void update_func_str(THD *thd __attribute__((__unused__)), struct st_mysql_sys_var *var,
1 by brian
clean slate
1755
                             void *tgt, const void *save)
1756
{
1757
  char *old= *(char **) tgt;
1758
  *(char **)tgt= *(char **) save;
1759
  if (var->flags & PLUGIN_VAR_MEMALLOC)
1760
  {
1761
    *(char **)tgt= my_strdup(*(char **) save, MYF(0));
1762
    my_free(old, MYF(0));
1763
  }
1764
}
1765
1766
1767
/****************************************************************************
1768
  System Variables support
1769
****************************************************************************/
1770
1771
1772
sys_var *find_sys_var(THD *thd, const char *str, uint length)
1773
{
1774
  sys_var *var;
1775
  sys_var_pluginvar *pi= NULL;
1776
  plugin_ref plugin;
1777
1778
  rw_rdlock(&LOCK_system_variables_hash);
1779
  if ((var= intern_find_sys_var(str, length, false)) &&
1780
      (pi= var->cast_pluginvar()))
1781
  {
1782
    rw_unlock(&LOCK_system_variables_hash);
1783
    LEX *lex= thd ? thd->lex : 0;
1784
    if (!(plugin= my_intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
1785
      var= NULL; /* failed to lock it, it must be uninstalling */
1786
    else
1787
    if (!(plugin_state(plugin) & PLUGIN_IS_READY))
1788
    {
1789
      /* initialization not completed */
1790
      var= NULL;
1791
      intern_plugin_unlock(lex, plugin);
1792
    }
1793
  }
1794
  else
1795
    rw_unlock(&LOCK_system_variables_hash);
1796
1797
  /*
1798
    If the variable exists but the plugin it is associated with is not ready
1799
    then the intern_plugin_lock did not raise an error, so we do it here.
1800
  */
1801
  if (pi && !var)
1802
    my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
1803
  return(var);
1 by brian
clean slate
1804
}
1805
1806
1807
/*
1808
  called by register_var, construct_options and test_plugin_options.
1809
  Returns the 'bookmark' for the named variable.
1810
  LOCK_system_variables_hash should be at least read locked
1811
*/
1812
static st_bookmark *find_bookmark(const char *plugin, const char *name,
1813
                                  int flags)
1814
{
1815
  st_bookmark *result= NULL;
1816
  uint namelen, length, pluginlen= 0;
1817
  char *varname, *p;
1818
1819
  if (!(flags & PLUGIN_VAR_THDLOCAL))
1820
    return NULL;
1821
1822
  namelen= strlen(name);
1823
  if (plugin)
1824
    pluginlen= strlen(plugin) + 1;
1825
  length= namelen + pluginlen + 2;
1826
  varname= (char*) my_alloca(length);
1827
1828
  if (plugin)
1829
  {
1830
    strxmov(varname + 1, plugin, "_", name, NullS);
1831
    for (p= varname + 1; *p; p++)
1832
      if (*p == '-')
1833
        *p= '_';
1834
  }
1835
  else
1836
    memcpy(varname + 1, name, namelen + 1);
1837
1838
  varname[0]= flags & PLUGIN_VAR_TYPEMASK;
1839
1840
  result= (st_bookmark*) hash_search(&bookmark_hash,
1841
                                     (const uchar*) varname, length - 1);
1842
1843
  my_afree(varname);
1844
  return result;
1845
}
1846
1847
1848
/*
1849
  returns a bookmark for thd-local variables, creating if neccessary.
1850
  returns null for non thd-local variables.
1851
  Requires that a write lock is obtained on LOCK_system_variables_hash
1852
*/
1853
static st_bookmark *register_var(const char *plugin, const char *name,
1854
                                 int flags)
1855
{
1856
  uint length= strlen(plugin) + strlen(name) + 3, size= 0, offset, new_size;
1857
  st_bookmark *result;
1858
  char *varname, *p;
1859
1860
  if (!(flags & PLUGIN_VAR_THDLOCAL))
1861
    return NULL;
1862
1863
  switch (flags & PLUGIN_VAR_TYPEMASK) {
1864
  case PLUGIN_VAR_BOOL:
1865
    size= sizeof(my_bool);
1866
    break;
1867
  case PLUGIN_VAR_INT:
1868
    size= sizeof(int);
1869
    break;
1870
  case PLUGIN_VAR_LONG:
1871
  case PLUGIN_VAR_ENUM:
1872
    size= sizeof(long);
1873
    break;
1874
  case PLUGIN_VAR_LONGLONG:
1875
  case PLUGIN_VAR_SET:
1876
    size= sizeof(ulonglong);
1877
    break;
1878
  case PLUGIN_VAR_STR:
1879
    size= sizeof(char*);
1880
    break;
1881
  default:
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
1882
    assert(0);
1 by brian
clean slate
1883
    return NULL;
1884
  };
1885
1886
  varname= ((char*) my_alloca(length));
1887
  strxmov(varname + 1, plugin, "_", name, NullS);
1888
  for (p= varname + 1; *p; p++)
1889
    if (*p == '-')
1890
      *p= '_';
1891
1892
  if (!(result= find_bookmark(NULL, varname + 1, flags)))
1893
  {
1894
    result= (st_bookmark*) alloc_root(&plugin_mem_root,
1895
                                      sizeof(struct st_bookmark) + length-1);
1896
    varname[0]= flags & PLUGIN_VAR_TYPEMASK;
1897
    memcpy(result->key, varname, length);
1898
    result->name_len= length - 2;
1899
    result->offset= -1;
1900
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
1901
    assert(size && !(size & (size-1))); /* must be power of 2 */
1 by brian
clean slate
1902
1903
    offset= global_system_variables.dynamic_variables_size;
1904
    offset= (offset + size - 1) & ~(size - 1);
1905
    result->offset= (int) offset;
1906
1907
    new_size= (offset + size + 63) & ~63;
1908
1909
    if (new_size > global_variables_dynamic_size)
1910
    {
1911
      global_system_variables.dynamic_variables_ptr= (char*)
1912
        my_realloc(global_system_variables.dynamic_variables_ptr, new_size,
1913
                   MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
1914
      max_system_variables.dynamic_variables_ptr= (char*)
1915
        my_realloc(max_system_variables.dynamic_variables_ptr, new_size,
1916
                   MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
1917
      /*
1918
        Clear the new variable value space. This is required for string
1919
        variables. If their value is non-NULL, it must point to a valid
1920
        string.
1921
      */
1922
      bzero(global_system_variables.dynamic_variables_ptr +
1923
            global_variables_dynamic_size,
1924
            new_size - global_variables_dynamic_size);
1925
      bzero(max_system_variables.dynamic_variables_ptr +
1926
            global_variables_dynamic_size,
1927
            new_size - global_variables_dynamic_size);
1928
      global_variables_dynamic_size= new_size;
1929
    }
1930
1931
    global_system_variables.dynamic_variables_head= offset;
1932
    max_system_variables.dynamic_variables_head= offset;
1933
    global_system_variables.dynamic_variables_size= offset + size;
1934
    max_system_variables.dynamic_variables_size= offset + size;
1935
    global_system_variables.dynamic_variables_version++;
1936
    max_system_variables.dynamic_variables_version++;
1937
1938
    result->version= global_system_variables.dynamic_variables_version;
1939
1940
    /* this should succeed because we have already checked if a dup exists */
1941
    if (my_hash_insert(&bookmark_hash, (uchar*) result))
1942
    {
1943
      fprintf(stderr, "failed to add placeholder to hash");
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
1944
      assert(0);
1 by brian
clean slate
1945
    }
1946
  }
1947
  my_afree(varname);
1948
  return result;
1949
}
1950
1951
1952
/*
1953
  returns a pointer to the memory which holds the thd-local variable or
1954
  a pointer to the global variable if thd==null.
1955
  If required, will sync with global variables if the requested variable
1956
  has not yet been allocated in the current thread.
1957
*/
1958
static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
1959
{
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
1960
  assert(offset >= 0);
1961
  assert((uint)offset <= global_system_variables.dynamic_variables_head);
1 by brian
clean slate
1962
1963
  if (!thd)
1964
    return (uchar*) global_system_variables.dynamic_variables_ptr + offset;
1965
1966
  /*
1967
    dynamic_variables_head points to the largest valid offset
1968
  */
1969
  if (!thd->variables.dynamic_variables_ptr ||
1970
      (uint)offset > thd->variables.dynamic_variables_head)
1971
  {
1972
    uint idx;
1973
1974
    rw_rdlock(&LOCK_system_variables_hash);
1975
1976
    thd->variables.dynamic_variables_ptr= (char*)
1977
      my_realloc(thd->variables.dynamic_variables_ptr,
1978
                 global_variables_dynamic_size,
1979
                 MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
1980
1981
    if (global_lock)
1982
      pthread_mutex_lock(&LOCK_global_system_variables);
1983
1984
    safe_mutex_assert_owner(&LOCK_global_system_variables);
1985
1986
    memcpy(thd->variables.dynamic_variables_ptr +
1987
             thd->variables.dynamic_variables_size,
1988
           global_system_variables.dynamic_variables_ptr +
1989
             thd->variables.dynamic_variables_size,
1990
           global_system_variables.dynamic_variables_size -
1991
             thd->variables.dynamic_variables_size);
1992
1993
    /*
1994
      now we need to iterate through any newly copied 'defaults'
1995
      and if it is a string type with MEMALLOC flag, we need to strdup
1996
    */
1997
    for (idx= 0; idx < bookmark_hash.records; idx++)
1998
    {
1999
      sys_var_pluginvar *pi;
2000
      sys_var *var;
2001
      st_bookmark *v= (st_bookmark*) hash_element(&bookmark_hash,idx);
2002
2003
      if (v->version <= thd->variables.dynamic_variables_version ||
2004
          !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
2005
          !(pi= var->cast_pluginvar()) ||
2006
          v->key[0] != (pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
2007
        continue;
2008
2009
      /* Here we do anything special that may be required of the data types */
2010
2011
      if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
2012
          pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
2013
      {
2014
         char **pp= (char**) (thd->variables.dynamic_variables_ptr +
2015
                             *(int*)(pi->plugin_var + 1));
2016
         if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr +
2017
                             *(int*)(pi->plugin_var + 1))))
2018
           *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
2019
      }
2020
    }
2021
2022
    if (global_lock)
2023
      pthread_mutex_unlock(&LOCK_global_system_variables);
2024
2025
    thd->variables.dynamic_variables_version=
2026
           global_system_variables.dynamic_variables_version;
2027
    thd->variables.dynamic_variables_head=
2028
           global_system_variables.dynamic_variables_head;
2029
    thd->variables.dynamic_variables_size=
2030
           global_system_variables.dynamic_variables_size;
2031
2032
    rw_unlock(&LOCK_system_variables_hash);
2033
  }
2034
  return (uchar*)thd->variables.dynamic_variables_ptr + offset;
2035
}
2036
2037
static uchar *mysql_sys_var_ptr(void* a_thd, int offset)
2038
{
2039
  return intern_sys_var_ptr((THD *)a_thd, offset, true);
2040
}
2041
2042
2043
void plugin_thdvar_init(THD *thd)
2044
{
2045
  plugin_ref old_table_plugin= thd->variables.table_plugin;
2046
  
2047
  thd->variables.table_plugin= NULL;
2048
  cleanup_variables(thd, &thd->variables);
2049
  
2050
  thd->variables= global_system_variables;
2051
  thd->variables.table_plugin= NULL;
2052
2053
  /* we are going to allocate these lazily */
2054
  thd->variables.dynamic_variables_version= 0;
2055
  thd->variables.dynamic_variables_size= 0;
2056
  thd->variables.dynamic_variables_ptr= 0;
2057
2058
  thd->variables.table_plugin=
2059
        my_intern_plugin_lock(NULL, global_system_variables.table_plugin);
2060
  intern_plugin_unlock(NULL, old_table_plugin);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2061
  return;
1 by brian
clean slate
2062
}
2063
2064
2065
/*
2066
  Unlocks all system variables which hold a reference
2067
*/
77.1.46 by Monty Taylor
Finished the warnings work!
2068
static void unlock_variables(THD *thd __attribute__((__unused__)),
2069
                             struct system_variables *vars)
1 by brian
clean slate
2070
{
2071
  intern_plugin_unlock(NULL, vars->table_plugin);
2072
  vars->table_plugin= NULL;
2073
}
2074
2075
2076
/*
2077
  Frees memory used by system variables
2078
2079
  Unlike plugin_vars_free_values() it frees all variables of all plugins,
2080
  it's used on shutdown.
2081
*/
2082
static void cleanup_variables(THD *thd, struct system_variables *vars)
2083
{
2084
  st_bookmark *v;
2085
  sys_var_pluginvar *pivar;
2086
  sys_var *var;
2087
  int flags;
2088
  uint idx;
2089
2090
  rw_rdlock(&LOCK_system_variables_hash);
2091
  for (idx= 0; idx < bookmark_hash.records; idx++)
2092
  {
2093
    v= (st_bookmark*) hash_element(&bookmark_hash, idx);
2094
    if (v->version > vars->dynamic_variables_version ||
2095
        !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
2096
        !(pivar= var->cast_pluginvar()) ||
2097
        v->key[0] != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
2098
      continue;
2099
2100
    flags= pivar->plugin_var->flags;
2101
2102
    if ((flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
2103
        flags & PLUGIN_VAR_THDLOCAL && flags & PLUGIN_VAR_MEMALLOC)
2104
    {
2105
      char **ptr= (char**) pivar->real_value_ptr(thd, OPT_SESSION);
2106
      my_free(*ptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
2107
      *ptr= NULL;
2108
    }
2109
  }
2110
  rw_unlock(&LOCK_system_variables_hash);
2111
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2112
  assert(vars->table_plugin == NULL);
1 by brian
clean slate
2113
2114
  my_free(vars->dynamic_variables_ptr, MYF(MY_ALLOW_ZERO_PTR));
2115
  vars->dynamic_variables_ptr= NULL;
2116
  vars->dynamic_variables_size= 0;
2117
  vars->dynamic_variables_version= 0;
2118
}
2119
2120
2121
void plugin_thdvar_cleanup(THD *thd)
2122
{
2123
  uint idx;
2124
  plugin_ref *list;
2125
2126
  unlock_variables(thd, &thd->variables);
2127
  cleanup_variables(thd, &thd->variables);
2128
2129
  if ((idx= thd->lex->plugins.elements))
2130
  {
2131
    list= ((plugin_ref*) thd->lex->plugins.buffer) + idx - 1;
2132
    while ((uchar*) list >= thd->lex->plugins.buffer)
2133
      intern_plugin_unlock(NULL, *list--);
2134
  }
2135
2136
  reap_plugins();
2137
2138
  reset_dynamic(&thd->lex->plugins);
2139
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2140
  return;
1 by brian
clean slate
2141
}
2142
2143
2144
/**
2145
  @brief Free values of thread variables of a plugin.
2146
2147
  This must be called before a plugin is deleted. Otherwise its
2148
  variables are no longer accessible and the value space is lost. Note
2149
  that only string values with PLUGIN_VAR_MEMALLOC are allocated and
2150
  must be freed.
2151
2152
  @param[in]        vars        Chain of system variables of a plugin
2153
*/
2154
2155
static void plugin_vars_free_values(sys_var *vars)
2156
{
2157
2158
  for (sys_var *var= vars; var; var= var->next)
2159
  {
2160
    sys_var_pluginvar *piv= var->cast_pluginvar();
2161
    if (piv &&
2162
        ((piv->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
2163
        (piv->plugin_var->flags & PLUGIN_VAR_MEMALLOC))
2164
    {
2165
      /* Free the string from global_system_variables. */
2166
      char **valptr= (char**) piv->real_value_ptr(NULL, OPT_GLOBAL);
2167
      my_free(*valptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
2168
      *valptr= NULL;
2169
    }
2170
  }
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2171
  return;
1 by brian
clean slate
2172
}
2173
2174
2175
bool sys_var_pluginvar::check_update_type(Item_result type)
2176
{
2177
  if (is_readonly())
2178
    return 1;
2179
  switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
2180
  case PLUGIN_VAR_INT:
2181
  case PLUGIN_VAR_LONG:
2182
  case PLUGIN_VAR_LONGLONG:
2183
    return type != INT_RESULT;
2184
  case PLUGIN_VAR_STR:
2185
    return type != STRING_RESULT;
2186
  default:
2187
    return 0;
2188
  }
2189
}
2190
2191
2192
SHOW_TYPE sys_var_pluginvar::show_type()
2193
{
2194
  switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
2195
  case PLUGIN_VAR_BOOL:
2196
    return SHOW_MY_BOOL;
2197
  case PLUGIN_VAR_INT:
2198
    return SHOW_INT;
2199
  case PLUGIN_VAR_LONG:
2200
    return SHOW_LONG;
2201
  case PLUGIN_VAR_LONGLONG:
2202
    return SHOW_LONGLONG;
2203
  case PLUGIN_VAR_STR:
2204
    return SHOW_CHAR_PTR;
2205
  case PLUGIN_VAR_ENUM:
2206
  case PLUGIN_VAR_SET:
2207
    return SHOW_CHAR;
2208
  default:
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2209
    assert(0);
1 by brian
clean slate
2210
    return SHOW_UNDEF;
2211
  }
2212
}
2213
2214
2215
uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type)
2216
{
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2217
  assert(thd || (type == OPT_GLOBAL));
1 by brian
clean slate
2218
  if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
2219
  {
2220
    if (type == OPT_GLOBAL)
2221
      thd= NULL;
2222
2223
    return intern_sys_var_ptr(thd, *(int*) (plugin_var+1), false);
2224
  }
2225
  return *(uchar**) (plugin_var+1);
2226
}
2227
2228
2229
TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
2230
{
2231
  switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) {
2232
  case PLUGIN_VAR_ENUM:
2233
    return ((sysvar_enum_t *)plugin_var)->typelib;
2234
  case PLUGIN_VAR_SET:
2235
    return ((sysvar_set_t *)plugin_var)->typelib;
2236
  case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
2237
    return ((thdvar_enum_t *)plugin_var)->typelib;
2238
  case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
2239
    return ((thdvar_set_t *)plugin_var)->typelib;
2240
  default:
2241
    return NULL;
2242
  }
2243
  return NULL;
2244
}
2245
2246
2247
uchar* sys_var_pluginvar::value_ptr(THD *thd, enum_var_type type,
77.1.46 by Monty Taylor
Finished the warnings work!
2248
                                    LEX_STRING *base __attribute__((__unused__)))
1 by brian
clean slate
2249
{
2250
  uchar* result;
2251
2252
  result= real_value_ptr(thd, type);
2253
2254
  if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_ENUM)
2255
    result= (uchar*) get_type(plugin_var_typelib(), *(ulong*)result);
2256
  else if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_SET)
2257
  {
2258
    char buffer[STRING_BUFFER_USUAL_SIZE];
2259
    String str(buffer, sizeof(buffer), system_charset_info);
2260
    TYPELIB *typelib= plugin_var_typelib();
2261
    ulonglong mask= 1, value= *(ulonglong*) result;
2262
    uint i;
2263
2264
    str.length(0);
2265
    for (i= 0; i < typelib->count; i++, mask<<=1)
2266
    {
2267
      if (!(value & mask))
2268
        continue;
2269
      str.append(typelib->type_names[i], typelib->type_lengths[i]);
2270
      str.append(',');
2271
    }
2272
2273
    result= (uchar*) "";
2274
    if (str.length())
2275
      result= (uchar*) thd->strmake(str.ptr(), str.length()-1);
2276
  }
2277
  return result;
2278
}
2279
2280
2281
bool sys_var_pluginvar::check(THD *thd, set_var *var)
2282
{
2283
  st_item_value_holder value;
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2284
  assert(is_readonly() || plugin_var->check);
1 by brian
clean slate
2285
2286
  value.value_type= item_value_type;
2287
  value.val_str= item_val_str;
2288
  value.val_int= item_val_int;
2289
  value.val_real= item_val_real;
2290
  value.item= var->value;
2291
2292
  return is_readonly() ||
2293
         plugin_var->check(thd, plugin_var, &var->save_result, &value);
2294
}
2295
2296
2297
void sys_var_pluginvar::set_default(THD *thd, enum_var_type type)
2298
{
2299
  const void *src;
2300
  void *tgt;
2301
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2302
  assert(is_readonly() || plugin_var->update);
1 by brian
clean slate
2303
2304
  if (is_readonly())
2305
    return;
2306
2307
  pthread_mutex_lock(&LOCK_global_system_variables);
2308
  tgt= real_value_ptr(thd, type);
2309
  src= ((void **) (plugin_var + 1) + 1);
2310
2311
  if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
2312
  {
2313
    if (type != OPT_GLOBAL)
2314
      src= real_value_ptr(thd, OPT_GLOBAL);
2315
    else
2316
    switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
2317
	case PLUGIN_VAR_INT:
2318
	  src= &((thdvar_uint_t*) plugin_var)->def_val;
2319
	  break;
2320
	case PLUGIN_VAR_LONG:
2321
	  src= &((thdvar_ulong_t*) plugin_var)->def_val;
2322
	  break;
2323
	case PLUGIN_VAR_LONGLONG:
2324
	  src= &((thdvar_ulonglong_t*) plugin_var)->def_val;
2325
	  break;
2326
	case PLUGIN_VAR_ENUM:
2327
	  src= &((thdvar_enum_t*) plugin_var)->def_val;
2328
	  break;
2329
	case PLUGIN_VAR_SET:
2330
	  src= &((thdvar_set_t*) plugin_var)->def_val;
2331
	  break;
2332
	case PLUGIN_VAR_BOOL:
2333
	  src= &((thdvar_bool_t*) plugin_var)->def_val;
2334
	  break;
2335
	case PLUGIN_VAR_STR:
2336
	  src= &((thdvar_str_t*) plugin_var)->def_val;
2337
	  break;
2338
	default:
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2339
	  assert(0);
1 by brian
clean slate
2340
	}
2341
  }
2342
2343
  /* thd must equal current_thd if PLUGIN_VAR_THDLOCAL flag is set */
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2344
  assert(!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ||
1 by brian
clean slate
2345
              thd == current_thd);
2346
2347
  if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || type == OPT_GLOBAL)
2348
  {
2349
    plugin_var->update(thd, plugin_var, tgt, src);
2350
    pthread_mutex_unlock(&LOCK_global_system_variables);
2351
  }
2352
  else
2353
  {
2354
    pthread_mutex_unlock(&LOCK_global_system_variables);
2355
    plugin_var->update(thd, plugin_var, tgt, src);
2356
  }
2357
}
2358
2359
2360
bool sys_var_pluginvar::update(THD *thd, set_var *var)
2361
{
2362
  void *tgt;
2363
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2364
  assert(is_readonly() || plugin_var->update);
1 by brian
clean slate
2365
2366
  /* thd must equal current_thd if PLUGIN_VAR_THDLOCAL flag is set */
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2367
  assert(!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ||
1 by brian
clean slate
2368
              thd == current_thd);
2369
2370
  if (is_readonly())
2371
    return 1;
2372
2373
  pthread_mutex_lock(&LOCK_global_system_variables);
2374
  tgt= real_value_ptr(thd, var->type);
2375
2376
  if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || var->type == OPT_GLOBAL)
2377
  {
2378
    /* variable we are updating has global scope, so we unlock after updating */
2379
    plugin_var->update(thd, plugin_var, tgt, &var->save_result);
2380
    pthread_mutex_unlock(&LOCK_global_system_variables);
2381
  }
2382
  else
2383
  {
2384
    pthread_mutex_unlock(&LOCK_global_system_variables);
2385
    plugin_var->update(thd, plugin_var, tgt, &var->save_result);
2386
  }
2387
 return 0;
2388
}
2389
2390
2391
#define OPTION_SET_LIMITS(type, options, opt) \
2392
  options->var_type= type; \
2393
  options->def_value= (opt)->def_val; \
2394
  options->min_value= (opt)->min_val; \
2395
  options->max_value= (opt)->max_val; \
2396
  options->block_size= (long) (opt)->blk_sz
2397
2398
2399
static void plugin_opt_set_limits(struct my_option *options,
2400
                                  const struct st_mysql_sys_var *opt)
2401
{
2402
  options->sub_size= 0;
2403
2404
  switch (opt->flags & (PLUGIN_VAR_TYPEMASK |
2405
                        PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL)) {
2406
  /* global system variables */
2407
  case PLUGIN_VAR_INT:
2408
    OPTION_SET_LIMITS(GET_INT, options, (sysvar_int_t*) opt);
2409
    break;
2410
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED:
2411
    OPTION_SET_LIMITS(GET_UINT, options, (sysvar_uint_t*) opt);
2412
    break;
2413
  case PLUGIN_VAR_LONG:
2414
    OPTION_SET_LIMITS(GET_LONG, options, (sysvar_long_t*) opt);
2415
    break;
2416
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
2417
    OPTION_SET_LIMITS(GET_ULONG, options, (sysvar_ulong_t*) opt);
2418
    break;
2419
  case PLUGIN_VAR_LONGLONG:
2420
    OPTION_SET_LIMITS(GET_LL, options, (sysvar_longlong_t*) opt);
2421
    break;
2422
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
2423
    OPTION_SET_LIMITS(GET_ULL, options, (sysvar_ulonglong_t*) opt);
2424
    break;
2425
  case PLUGIN_VAR_ENUM:
2426
    options->var_type= GET_ENUM;
2427
    options->typelib= ((sysvar_enum_t*) opt)->typelib;
2428
    options->def_value= ((sysvar_enum_t*) opt)->def_val;
2429
    options->min_value= options->block_size= 0;
2430
    options->max_value= options->typelib->count - 1;
2431
    break;
2432
  case PLUGIN_VAR_SET:
2433
    options->var_type= GET_SET;
2434
    options->typelib= ((sysvar_set_t*) opt)->typelib;
2435
    options->def_value= ((sysvar_set_t*) opt)->def_val;
2436
    options->min_value= options->block_size= 0;
80.1.1 by Brian Aker
LL() cleanup
2437
    options->max_value= (1ULL << options->typelib->count) - 1;
1 by brian
clean slate
2438
    break;
2439
  case PLUGIN_VAR_BOOL:
2440
    options->var_type= GET_BOOL;
2441
    options->def_value= ((sysvar_bool_t*) opt)->def_val;
2442
    break;
2443
  case PLUGIN_VAR_STR:
2444
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
2445
                        GET_STR_ALLOC : GET_STR);
2446
    options->def_value= (intptr) ((sysvar_str_t*) opt)->def_val;
2447
    break;
2448
  /* threadlocal variables */
2449
  case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
2450
    OPTION_SET_LIMITS(GET_INT, options, (thdvar_int_t*) opt);
2451
    break;
2452
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
2453
    OPTION_SET_LIMITS(GET_UINT, options, (thdvar_uint_t*) opt);
2454
    break;
2455
  case PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL:
2456
    OPTION_SET_LIMITS(GET_LONG, options, (thdvar_long_t*) opt);
2457
    break;
2458
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
2459
    OPTION_SET_LIMITS(GET_ULONG, options, (thdvar_ulong_t*) opt);
2460
    break;
2461
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL:
2462
    OPTION_SET_LIMITS(GET_LL, options, (thdvar_longlong_t*) opt);
2463
    break;
2464
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
2465
    OPTION_SET_LIMITS(GET_ULL, options, (thdvar_ulonglong_t*) opt);
2466
    break;
2467
  case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
2468
    options->var_type= GET_ENUM;
2469
    options->typelib= ((thdvar_enum_t*) opt)->typelib;
2470
    options->def_value= ((thdvar_enum_t*) opt)->def_val;
2471
    options->min_value= options->block_size= 0;
2472
    options->max_value= options->typelib->count - 1;
2473
    break;
2474
  case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
2475
    options->var_type= GET_SET;
2476
    options->typelib= ((thdvar_set_t*) opt)->typelib;
2477
    options->def_value= ((thdvar_set_t*) opt)->def_val;
2478
    options->min_value= options->block_size= 0;
80.1.1 by Brian Aker
LL() cleanup
2479
    options->max_value= (1ULL << options->typelib->count) - 1;
1 by brian
clean slate
2480
    break;
2481
  case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL:
2482
    options->var_type= GET_BOOL;
2483
    options->def_value= ((thdvar_bool_t*) opt)->def_val;
2484
    break;
2485
  case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL:
2486
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
2487
                        GET_STR_ALLOC : GET_STR);
2488
    options->def_value= (intptr) ((thdvar_str_t*) opt)->def_val;
2489
    break;
2490
  default:
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2491
    assert(0);
1 by brian
clean slate
2492
  }
2493
  options->arg_type= REQUIRED_ARG;
2494
  if (opt->flags & PLUGIN_VAR_NOCMDARG)
2495
    options->arg_type= NO_ARG;
2496
  if (opt->flags & PLUGIN_VAR_OPCMDARG)
2497
    options->arg_type= OPT_ARG;
2498
}
2499
2500
extern "C" my_bool get_one_plugin_option(int optid, const struct my_option *,
2501
                                         char *);
2502
2503
my_bool get_one_plugin_option(int optid __attribute__((unused)),
77.1.46 by Monty Taylor
Finished the warnings work!
2504
                              const struct my_option *opt __attribute__((__unused__)),
2505
                              char *argument __attribute__((__unused__)))
1 by brian
clean slate
2506
{
2507
  return 0;
2508
}
2509
2510
2511
static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
2512
                             my_option *options, my_bool **enabled,
2513
                             bool can_disable)
2514
{
2515
  const char *plugin_name= tmp->plugin->name;
2516
  uint namelen= strlen(plugin_name), optnamelen;
2517
  uint buffer_length= namelen * 4 + (can_disable ? 75 : 10);
2518
  char *name= (char*) alloc_root(mem_root, buffer_length) + 1;
2519
  char *optname, *p;
2520
  int index= 0, offset= 0;
2521
  st_mysql_sys_var *opt, **plugin_option;
2522
  st_bookmark *v;
2523
2524
  /* support --skip-plugin-foo syntax */
2525
  memcpy(name, plugin_name, namelen + 1);
2526
  my_casedn_str(&my_charset_latin1, name);
2527
  strxmov(name + namelen + 1, "plugin-", name, NullS);
2528
  /* Now we have namelen + 1 + 7 + namelen + 1 == namelen * 2 + 9. */
2529
2530
  for (p= name + namelen*2 + 8; p > name; p--)
2531
    if (*p == '_')
2532
      *p= '-';
2533
2534
  if (can_disable)
2535
  {
2536
    strxmov(name + namelen*2 + 10, "Enable ", plugin_name, " plugin. "
2537
            "Disable with --skip-", name," (will save memory).", NullS);
2538
    /*
2539
      Now we have namelen * 2 + 10 (one char unused) + 7 + namelen + 9 +
2540
      20 + namelen + 20 + 1 == namelen * 4 + 67.
2541
    */
2542
2543
    options[0].comment= name + namelen*2 + 10;
2544
  }
2545
2546
  /*
2547
    NOTE: 'name' is one char above the allocated buffer!
2548
    NOTE: This code assumes that 'my_bool' and 'char' are of same size.
2549
  */
2550
  *((my_bool *)(name -1))= **enabled;
2551
  *enabled= (my_bool *)(name - 1);
2552
2553
2554
  options[1].name= (options[0].name= name) + namelen + 1;
2555
  options[0].id= options[1].id= 256; /* must be >255. dup id ok */
2556
  options[0].var_type= options[1].var_type= GET_BOOL;
2557
  options[0].arg_type= options[1].arg_type= NO_ARG;
2558
  options[0].def_value= options[1].def_value= **enabled;
2559
  options[0].value= options[0].u_max_value=
77.1.78 by Monty Taylor
One last bunch of warnings edits.
2560
  options[1].value= options[1].u_max_value= (char**) (name - 1);
1 by brian
clean slate
2561
  options+= 2;
2562
2563
  /*
2564
    Two passes as the 2nd pass will take pointer addresses for use
2565
    by my_getopt and register_var() in the first pass uses realloc
2566
  */
2567
2568
  for (plugin_option= tmp->plugin->system_vars;
2569
       plugin_option && *plugin_option; plugin_option++, index++)
2570
  {
2571
    opt= *plugin_option;
2572
    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
2573
      continue;
2574
    if (!(register_var(name, opt->name, opt->flags)))
2575
      continue;
2576
    switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
2577
    case PLUGIN_VAR_BOOL:
2578
      SET_PLUGIN_VAR_RESOLVE((thdvar_bool_t *) opt);
2579
      break;
2580
    case PLUGIN_VAR_INT:
2581
      SET_PLUGIN_VAR_RESOLVE((thdvar_int_t *) opt);
2582
      break;
2583
    case PLUGIN_VAR_LONG:
2584
      SET_PLUGIN_VAR_RESOLVE((thdvar_long_t *) opt);
2585
      break;
2586
    case PLUGIN_VAR_LONGLONG:
2587
      SET_PLUGIN_VAR_RESOLVE((thdvar_longlong_t *) opt);
2588
      break;
2589
    case PLUGIN_VAR_STR:
2590
      SET_PLUGIN_VAR_RESOLVE((thdvar_str_t *) opt);
2591
      break;
2592
    case PLUGIN_VAR_ENUM:
2593
      SET_PLUGIN_VAR_RESOLVE((thdvar_enum_t *) opt);
2594
      break;
2595
    case PLUGIN_VAR_SET:
2596
      SET_PLUGIN_VAR_RESOLVE((thdvar_set_t *) opt);
2597
      break;
2598
    default:
2599
      sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
2600
                      opt->flags, plugin_name);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2601
      return(-1);
1 by brian
clean slate
2602
    };
2603
  }
2604
2605
  for (plugin_option= tmp->plugin->system_vars;
2606
       plugin_option && *plugin_option; plugin_option++, index++)
2607
  {
2608
    switch ((opt= *plugin_option)->flags & PLUGIN_VAR_TYPEMASK) {
2609
    case PLUGIN_VAR_BOOL:
2610
      if (!opt->check)
2611
        opt->check= check_func_bool;
2612
      if (!opt->update)
2613
        opt->update= update_func_bool;
2614
      break;
2615
    case PLUGIN_VAR_INT:
2616
      if (!opt->check)
2617
        opt->check= check_func_int;
2618
      if (!opt->update)
2619
        opt->update= update_func_int;
2620
      break;
2621
    case PLUGIN_VAR_LONG:
2622
      if (!opt->check)
2623
        opt->check= check_func_long;
2624
      if (!opt->update)
2625
        opt->update= update_func_long;
2626
      break;
2627
    case PLUGIN_VAR_LONGLONG:
2628
      if (!opt->check)
2629
        opt->check= check_func_longlong;
2630
      if (!opt->update)
2631
        opt->update= update_func_longlong;
2632
      break;
2633
    case PLUGIN_VAR_STR:
2634
      if (!opt->check)
2635
        opt->check= check_func_str;
2636
      if (!opt->update)
2637
      {
2638
        opt->update= update_func_str;
9 by Brian Aker
Warnings cleanup
2639
        if ((opt->flags & (PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY)) == false)
1 by brian
clean slate
2640
        {
2641
          opt->flags|= PLUGIN_VAR_READONLY;
2642
          sql_print_warning("Server variable %s of plugin %s was forced "
2643
                            "to be read-only: string variable without "
2644
                            "update_func and PLUGIN_VAR_MEMALLOC flag",
2645
                            opt->name, plugin_name);
2646
        }
2647
      }
2648
      break;
2649
    case PLUGIN_VAR_ENUM:
2650
      if (!opt->check)
2651
        opt->check= check_func_enum;
2652
      if (!opt->update)
2653
        opt->update= update_func_long;
2654
      break;
2655
    case PLUGIN_VAR_SET:
2656
      if (!opt->check)
2657
        opt->check= check_func_set;
2658
      if (!opt->update)
2659
        opt->update= update_func_longlong;
2660
      break;
2661
    default:
2662
      sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
2663
                      opt->flags, plugin_name);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2664
      return(-1);
1 by brian
clean slate
2665
    }
2666
2667
    if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_THDLOCAL))
2668
                    == PLUGIN_VAR_NOCMDOPT)
2669
      continue;
2670
2671
    if (!opt->name)
2672
    {
2673
      sql_print_error("Missing variable name in plugin '%s'.",
2674
                      plugin_name);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2675
      return(-1);
1 by brian
clean slate
2676
    }
2677
2678
    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
2679
    {
2680
      optnamelen= strlen(opt->name);
2681
      optname= (char*) alloc_root(mem_root, namelen + optnamelen + 2);
2682
      strxmov(optname, name, "-", opt->name, NullS);
2683
      optnamelen= namelen + optnamelen + 1;
2684
    }
2685
    else
2686
    {
2687
      /* this should not fail because register_var should create entry */
2688
      if (!(v= find_bookmark(name, opt->name, opt->flags)))
2689
      {
2690
        sql_print_error("Thread local variable '%s' not allocated "
2691
                        "in plugin '%s'.", opt->name, plugin_name);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2692
        return(-1);
1 by brian
clean slate
2693
      }
2694
2695
      *(int*)(opt + 1)= offset= v->offset;
2696
2697
      if (opt->flags & PLUGIN_VAR_NOCMDOPT)
2698
        continue;
2699
2700
      optname= (char*) memdup_root(mem_root, v->key + 1, 
2701
                                   (optnamelen= v->name_len) + 1);
2702
    }
2703
2704
    /* convert '_' to '-' */
2705
    for (p= optname; *p; p++)
2706
      if (*p == '_')
2707
        *p= '-';
2708
2709
    options->name= optname;
2710
    options->comment= opt->comment;
2711
    options->app_type= opt;
2712
    options->id= (options-1)->id + 1;
2713
2714
    plugin_opt_set_limits(options, opt);
2715
2716
    if (opt->flags & PLUGIN_VAR_THDLOCAL)
77.1.78 by Monty Taylor
One last bunch of warnings edits.
2717
      options->value= options->u_max_value= (char**)
1 by brian
clean slate
2718
        (global_system_variables.dynamic_variables_ptr + offset);
2719
    else
77.1.78 by Monty Taylor
One last bunch of warnings edits.
2720
      options->value= options->u_max_value= *(char***) (opt + 1);
1 by brian
clean slate
2721
2722
    options[1]= options[0];
2723
    options[1].name= p= (char*) alloc_root(mem_root, optnamelen + 8);
2724
    options[1].comment= 0; // hidden
2725
    strxmov(p, "plugin-", optname, NullS);
2726
2727
    options+= 2;
2728
  }
2729
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2730
  return(0);
1 by brian
clean slate
2731
}
2732
2733
2734
static my_option *construct_help_options(MEM_ROOT *mem_root,
2735
                                         struct st_plugin_int *p)
2736
{
2737
  st_mysql_sys_var **opt;
2738
  my_option *opts;
2739
  my_bool dummy, can_disable;
2740
  my_bool *dummy2= &dummy;
2741
  uint count= EXTRA_OPTIONS;
2742
9 by Brian Aker
Warnings cleanup
2743
  for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2) {};
1 by brian
clean slate
2744
2745
  if (!(opts= (my_option*) alloc_root(mem_root, sizeof(my_option) * count)))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2746
    return(NULL);
1 by brian
clean slate
2747
2748
  bzero(opts, sizeof(my_option) * count);
2749
2750
  dummy= TRUE; /* plugin is enabled. */
2751
2752
  can_disable=
2753
      my_strcasecmp(&my_charset_latin1, p->name.str, "MyISAM") &&
2754
      my_strcasecmp(&my_charset_latin1, p->name.str, "MEMORY");
2755
2756
  if (construct_options(mem_root, p, opts, &dummy2, can_disable))
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2757
    return(NULL);
1 by brian
clean slate
2758
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2759
  return(opts);
1 by brian
clean slate
2760
}
2761
2762
2763
/*
2764
  SYNOPSIS
2765
    test_plugin_options()
2766
    tmp_root                    temporary scratch space
2767
    plugin                      internal plugin structure
2768
    argc                        user supplied arguments
2769
    argv                        user supplied arguments
2770
    default_enabled             default plugin enable status
2771
  RETURNS:
2772
    0 SUCCESS - plugin should be enabled/loaded
2773
  NOTE:
2774
    Requires that a write-lock is held on LOCK_system_variables_hash
2775
*/
2776
static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
2777
                               int *argc, char **argv, my_bool default_enabled)
2778
{
2779
  struct sys_var_chain chain= { NULL, NULL };
2780
  my_bool enabled_saved= default_enabled, can_disable;
2781
  my_bool *enabled= &default_enabled;
2782
  MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ?
2783
                      &tmp->mem_root : &plugin_mem_root;
2784
  st_mysql_sys_var **opt;
2785
  my_option *opts= NULL;
2786
  char *p, *varname;
2787
  int error;
2788
  st_mysql_sys_var *o;
2789
  sys_var *v;
2790
  struct st_bookmark *var;
2791
  uint len, count= EXTRA_OPTIONS;
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2792
  assert(tmp->plugin && tmp->name.str);
1 by brian
clean slate
2793
2794
  for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
2795
    count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
2796
2797
  can_disable=
2798
      my_strcasecmp(&my_charset_latin1, tmp->name.str, "MyISAM") &&
2799
      my_strcasecmp(&my_charset_latin1, tmp->name.str, "MEMORY");
2800
2801
  if (count > EXTRA_OPTIONS || (*argc > 1))
2802
  {
2803
    if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count)))
2804
    {
2805
      sql_print_error("Out of memory for plugin '%s'.", tmp->name.str);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2806
      return(-1);
1 by brian
clean slate
2807
    }
2808
    bzero(opts, sizeof(my_option) * count);
2809
2810
    if (construct_options(tmp_root, tmp, opts, &enabled, can_disable))
2811
    {
2812
      sql_print_error("Bad options for plugin '%s'.", tmp->name.str);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2813
      return(-1);
1 by brian
clean slate
2814
    }
2815
2816
    error= handle_options(argc, &argv, opts, get_one_plugin_option);
2817
    (*argc)++; /* add back one for the program name */
2818
2819
    if (error)
2820
    {
2821
       sql_print_error("Parsing options for plugin '%s' failed.",
2822
                       tmp->name.str);
2823
       goto err;
2824
    }
2825
  }
2826
2827
  if (!*enabled && !can_disable)
2828
  {
2829
    sql_print_warning("Plugin '%s' cannot be disabled", tmp->name.str);
2830
    *enabled= TRUE;
2831
  }
2832
2833
  error= 1;
2834
2835
  if (*enabled)
2836
  {
2837
    for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
2838
    {
2839
      if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
2840
        continue;
2841
2842
      if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
2843
        v= new (mem_root) sys_var_pluginvar(var->key + 1, o);
2844
      else
2845
      {
2846
        len= tmp->name.length + strlen(o->name) + 2;
2847
        varname= (char*) alloc_root(mem_root, len);
2848
        strxmov(varname, tmp->name.str, "-", o->name, NullS);
2849
        my_casedn_str(&my_charset_latin1, varname);
2850
2851
        for (p= varname; *p; p++)
2852
          if (*p == '-')
2853
            *p= '_';
2854
2855
        v= new (mem_root) sys_var_pluginvar(varname, o);
2856
      }
51.1.62 by Jay Pipes
Removed/replaced BUG symbols and standardized TRUE/FALSE
2857
      assert(v); /* check that an object was actually constructed */
1 by brian
clean slate
2858
2859
      /*
2860
        Add to the chain of variables.
2861
        Done like this for easier debugging so that the
2862
        pointer to v is not lost on optimized builds.
2863
      */
2864
      v->chain_sys_var(&chain);
2865
    }
2866
    if (chain.first)
2867
    {
2868
      chain.last->next = NULL;
2869
      if (mysql_add_sys_var_chain(chain.first, NULL))
2870
      {
2871
        sql_print_error("Plugin '%s' has conflicting system variables",
2872
                        tmp->name.str);
2873
        goto err;
2874
      }
2875
      tmp->system_vars= chain.first;
2876
    }
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2877
    return(0);
1 by brian
clean slate
2878
  }
2879
2880
  if (enabled_saved && global_system_variables.log_warnings)
2881
    sql_print_information("Plugin '%s' disabled by command line option",
2882
                          tmp->name.str);
2883
err:
2884
  if (opts)
2885
    my_cleanup_options(opts);
51.1.1 by Jay Pipes
Merged PatG's removal of various DBUG stuff with still keeping DBUG_ASSERT calls since they seem to be breaking test runs
2886
  return(error);
1 by brian
clean slate
2887
}
2888
2889
2890
/****************************************************************************
2891
  Help Verbose text with Plugin System Variables
2892
****************************************************************************/
2893
2894
static int option_cmp(my_option *a, my_option *b)
2895
{
2896
  return my_strcasecmp(&my_charset_latin1, a->name, b->name);
2897
}
2898
2899
2900
void my_print_help_inc_plugins(my_option *main_options, uint size)
2901
{
2902
  DYNAMIC_ARRAY all_options;
2903
  struct st_plugin_int *p;
2904
  MEM_ROOT mem_root;
2905
  my_option *opt;
2906
2907
  init_alloc_root(&mem_root, 4096, 4096);
2908
  my_init_dynamic_array(&all_options, sizeof(my_option), size, size/4);
2909
2910
  if (initialized)
2911
    for (uint idx= 0; idx < plugin_array.elements; idx++)
2912
    {
2913
      p= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
2914
2915
      if (!p->plugin->system_vars ||
2916
          !(opt= construct_help_options(&mem_root, p)))
2917
        continue;
2918
2919
      /* Only options with a non-NULL comment are displayed in help text */
2920
      for (;opt->id; opt++)
2921
        if (opt->comment)
2922
          insert_dynamic(&all_options, (uchar*) opt);
2923
    }
2924
2925
  for (;main_options->id; main_options++)
2926
    insert_dynamic(&all_options, (uchar*) main_options);
2927
2928
  sort_dynamic(&all_options, (qsort_cmp) option_cmp);
2929
2930
  /* main_options now points to the empty option terminator */
2931
  insert_dynamic(&all_options, (uchar*) main_options);
2932
2933
  my_print_help((my_option*) all_options.buffer);
2934
  my_print_variables((my_option*) all_options.buffer);
2935
2936
  delete_dynamic(&all_options);
2937
  free_root(&mem_root, MYF(0));
2938
}
2939