~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_plugin.cc

  • Committer: Monty Taylor
  • Date: 2009-03-16 16:56:48 UTC
  • mto: This revision was merged to the branch mainline in revision 938.
  • Revision ID: mordred@inaugust.com-20090316165648-0dsce73jne0qikk0
Addd -Wshadow to PROTOSKIP warnings and turned -Wstrict-aliasing off. Jumped the gun...

Show diffs side-by-side

added added

removed removed

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