~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_plugin.cc

  • Committer: Mark Atwood
  • Date: 2008-10-03 01:39:40 UTC
  • mto: This revision was merged to the branch mainline in revision 437.
  • Revision ID: mark@fallenpegasus.com-20081003013940-mvefjo725dltz41h
rename logging_noop to logging_query

Show diffs side-by-side

added added

removed removed

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