~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/module/loader.cc

  • Committer: Mark Atwood
  • Date: 2011-12-28 02:50:31 UTC
  • Revision ID: me@mark.atwood.name-20111228025031-eh4h1zwv4ig88g0i
fix tests/r/basic.result

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