~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/module/loader.cc

  • Committer: Brian Aker
  • Date: 2010-09-09 21:45:53 UTC
  • mto: (1756.1.2 build) (1768.2.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 1757.
  • Revision ID: brian@tangent.org-20100909214553-e687rmf5zk9478on
Force unique to just use memory and let the OS handle paging.

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 */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
#include "config.h"
17
17
 
47
47
#include "drizzled/pthread_globals.h"
48
48
#include "drizzled/util/tokenize.h"
49
49
 
50
 
#include <boost/foreach.hpp>
51
 
 
52
50
/* FreeBSD 2.2.2 does not define RTLD_NOW) */
53
51
#ifndef RTLD_NOW
54
52
#define RTLD_NOW 1
61
59
/** These exist just to prevent symbols from being optimized out */
62
60
typedef drizzled::module::Manifest drizzled_builtin_list[];
63
61
extern drizzled_builtin_list PANDORA_BUILTIN_SYMBOLS_LIST;
64
 
extern drizzled_builtin_list PANDORA_BUILTIN_LOAD_SYMBOLS_LIST;
65
62
drizzled::module::Manifest *drizzled_builtins[]=
66
63
{
67
64
  PANDORA_BUILTIN_SYMBOLS_LIST, NULL
68
65
};
69
 
drizzled::module::Manifest *drizzled_load_builtins[]=
70
 
{
71
 
  PANDORA_BUILTIN_LOAD_SYMBOLS_LIST, NULL
72
 
};
73
66
 
74
67
namespace drizzled
75
68
{
76
69
 
77
70
 
78
 
typedef vector<string> PluginOptions;
79
 
static PluginOptions opt_plugin_load;
80
 
static PluginOptions opt_plugin_add;
81
 
static PluginOptions opt_plugin_remove;
 
71
class sys_var_pluginvar;
 
72
static vector<sys_var_pluginvar *> plugin_sysvar_vec;
 
73
 
 
74
char *opt_plugin_add= NULL;
 
75
char *opt_plugin_remove= NULL;
 
76
char *opt_plugin_load= NULL;
 
77
char *opt_plugin_dir_ptr;
 
78
char opt_plugin_dir[FN_REFLEN];
 
79
const char *opt_plugin_load_default= PANDORA_PLUGIN_LIST;
82
80
const char *builtin_plugins= PANDORA_BUILTIN_LIST;
83
 
const char *builtin_load_plugins= PANDORA_BUILTIN_LOAD_LIST;
 
81
 
 
82
extern bool opt_print_defaults;
84
83
 
85
84
/* Note that 'int version' must be the first field of every plugin
86
85
   sub-structure (plugin->info).
127
126
static bookmark_unordered_map bookmark_hash;
128
127
 
129
128
 
 
129
/*
 
130
  sys_var class for access to all plugin variables visible to the user
 
131
*/
 
132
class sys_var_pluginvar: public sys_var
 
133
{
 
134
public:
 
135
  module::Module *plugin;
 
136
  drizzle_sys_var *plugin_var;
 
137
 
 
138
  sys_var_pluginvar(const std::string name_arg,
 
139
                    drizzle_sys_var *plugin_var_arg)
 
140
    :sys_var(name_arg), plugin_var(plugin_var_arg) {}
 
141
  sys_var_pluginvar *cast_pluginvar() { return this; }
 
142
  bool is_readonly() const { return plugin_var->flags & PLUGIN_VAR_READONLY; }
 
143
  bool check_type(sql_var_t type)
 
144
  { return !(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) && type != OPT_GLOBAL; }
 
145
  bool check_update_type(Item_result type);
 
146
  SHOW_TYPE show_type();
 
147
  unsigned char* real_value_ptr(Session *session, sql_var_t type);
 
148
  TYPELIB* plugin_var_typelib(void);
 
149
  unsigned char* value_ptr(Session *session, sql_var_t type,
 
150
                           const LEX_STRING *base);
 
151
  bool check(Session *session, set_var *var);
 
152
  bool check_default(sql_var_t)
 
153
    { return is_readonly(); }
 
154
  void set_default(Session *session, sql_var_t);
 
155
  bool update(Session *session, set_var *var);
 
156
};
 
157
 
130
158
 
131
159
/* prototypes */
132
160
static void plugin_prune_list(vector<string> &plugin_list,
133
161
                              const vector<string> &plugins_to_remove);
134
162
static bool plugin_load_list(module::Registry &registry,
135
 
                             memory::Root *tmp_root,
 
163
                             memory::Root *tmp_root, int *argc, char **argv,
136
164
                             const set<string> &plugin_list,
137
165
                             po::options_description &long_options,
138
166
                             bool builtin= false);
139
167
static int test_plugin_options(memory::Root *, module::Module *,
 
168
                               int *, char **,
140
169
                               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);
 
170
static void unlock_variables(Session *session, struct system_variables *vars);
 
171
static void cleanup_variables(Session *session, struct system_variables *vars);
 
172
static void plugin_vars_free_values(sys_var *vars);
143
173
 
144
174
/* declared in set_var.cc */
145
175
extern sys_var *intern_find_sys_var(const char *str, uint32_t length, bool no_error);
 
176
extern bool throw_bounds_warning(Session *session, bool fixed, bool unsignd,
 
177
                                 const std::string &name, int64_t val);
 
178
 
 
179
static bool throw_bounds_warning(Session *session, bool fixed, bool unsignd,
 
180
                                 const char *name, int64_t val)
 
181
{
 
182
  const std::string name_str(name);
 
183
  return throw_bounds_warning(session, fixed, unsignd, name_str, val);
 
184
}
 
185
 
 
186
/****************************************************************************
 
187
  Value type thunks, allows the C world to play in the C++ world
 
188
****************************************************************************/
 
189
 
 
190
static int item_value_type(drizzle_value *value)
 
191
{
 
192
  switch (((st_item_value_holder*)value)->item->result_type()) {
 
193
  case INT_RESULT:
 
194
    return DRIZZLE_VALUE_TYPE_INT;
 
195
  case REAL_RESULT:
 
196
    return DRIZZLE_VALUE_TYPE_REAL;
 
197
  default:
 
198
    return DRIZZLE_VALUE_TYPE_STRING;
 
199
  }
 
200
}
 
201
 
 
202
static const char *item_val_str(drizzle_value *value,
 
203
                                char *buffer, int *length)
 
204
{
 
205
  String str(buffer, *length, system_charset_info), *res;
 
206
  if (!(res= ((st_item_value_holder*)value)->item->val_str(&str)))
 
207
    return NULL;
 
208
  *length= res->length();
 
209
  if (res->c_ptr_quick() == buffer)
 
210
    return buffer;
 
211
 
 
212
  /*
 
213
    Lets be nice and create a temporary string since the
 
214
    buffer was too small
 
215
  */
 
216
  return current_session->strmake(res->c_ptr_quick(), res->length());
 
217
}
 
218
 
 
219
 
 
220
static int item_val_int(drizzle_value *value, int64_t *buf)
 
221
{
 
222
  Item *item= ((st_item_value_holder*)value)->item;
 
223
  *buf= item->val_int();
 
224
  if (item->is_null())
 
225
    return 1;
 
226
  return 0;
 
227
}
 
228
 
 
229
 
 
230
static int item_val_real(drizzle_value *value, double *buf)
 
231
{
 
232
  Item *item= ((st_item_value_holder*)value)->item;
 
233
  *buf= item->val_real();
 
234
  if (item->is_null())
 
235
    return 1;
 
236
  return 0;
 
237
}
146
238
 
147
239
 
148
240
/****************************************************************************
158
250
*/
159
251
static bool plugin_add(module::Registry &registry, memory::Root *tmp_root,
160
252
                       module::Library *library,
 
253
                       int *argc, char **argv,
161
254
                       po::options_description &long_options)
162
255
{
163
256
  if (! initialized)
188
281
  if (tmp == NULL)
189
282
    return true;
190
283
 
191
 
  if (!test_plugin_options(tmp_root, tmp, long_options))
 
284
  if (!test_plugin_options(tmp_root, tmp, argc, argv, long_options))
192
285
  {
193
286
    registry.add(tmp);
194
287
    return false;
199
292
}
200
293
 
201
294
 
 
295
static void delete_module(module::Module *module)
 
296
{
 
297
  /* Free allocated strings before deleting the plugin. */
 
298
  plugin_vars_free_values(module->system_vars);
 
299
  module->isInited= false;
 
300
  mysql_del_sys_var_chain(module->system_vars);
 
301
  delete module;
 
302
}
 
303
 
 
304
 
202
305
static void reap_plugins(module::Registry &registry)
203
306
{
204
307
  std::map<std::string, module::Module *>::const_iterator modules=
207
310
  while (modules != registry.getModulesMap().end())
208
311
  {
209
312
    module::Module *module= (*modules).second;
210
 
    delete module;
 
313
    delete_module(module);
211
314
    ++modules;
212
315
  }
 
316
 
 
317
  drizzle_del_plugin_sysvar();
 
318
}
 
319
 
 
320
 
 
321
static void plugin_initialize_vars(module::Module *module)
 
322
{
 
323
  /*
 
324
    set the plugin attribute of plugin's sys vars so they are pointing
 
325
    to the active plugin
 
326
  */
 
327
  if (module->system_vars)
 
328
  {
 
329
    sys_var_pluginvar *var= module->system_vars->cast_pluginvar();
 
330
    for (;;)
 
331
    {
 
332
      var->plugin= module;
 
333
      if (! var->getNext())
 
334
        break;
 
335
      var= var->getNext()->cast_pluginvar();
 
336
    }
 
337
  }
213
338
}
214
339
 
215
340
 
236
361
}
237
362
 
238
363
 
239
 
inline static void dashes_to_underscores(std::string &name_in,
240
 
                                         char from= '-', char to= '_')
241
 
{
242
 
  for (string::iterator p= name_in.begin();
243
 
       p != name_in.end();
244
 
       ++p)
245
 
  {
246
 
    if (*p == from)
247
 
    {
248
 
      *p= to;
249
 
    }
250
 
  }
251
 
}
252
 
 
253
 
inline static void underscores_to_dashes(std::string &name_in)
254
 
{
255
 
  return dashes_to_underscores(name_in, '_', '-');
256
 
}
257
 
 
258
 
static void compose_plugin_options(vector<string> &target,
259
 
                                   vector<string> options)
260
 
{
261
 
  for (vector<string>::iterator it= options.begin();
262
 
       it != options.end();
263
 
       ++it)
264
 
  {
265
 
    tokenize(*it, target, ",", true);
266
 
  }
267
 
  for (vector<string>::iterator it= target.begin();
268
 
       it != target.end();
269
 
       ++it)
270
 
  {
271
 
    dashes_to_underscores(*it);
272
 
  }
273
 
}
274
 
 
275
 
void compose_plugin_add(vector<string> options)
276
 
{
277
 
  compose_plugin_options(opt_plugin_add, options);
278
 
}
279
 
 
280
 
void compose_plugin_remove(vector<string> options)
281
 
{
282
 
  compose_plugin_options(opt_plugin_remove, options);
283
 
}
284
 
 
285
 
void notify_plugin_load(string in_plugin_load)
286
 
{
287
 
  tokenize(in_plugin_load, opt_plugin_load, ",", true);
288
 
}
289
 
 
290
364
/*
291
365
  The logic is that we first load and initialize all compiled in plugins.
292
366
  From there we load up the dynamic types (assuming we have not been told to
295
369
  Finally we initialize everything, aka the dynamic that have yet to initialize.
296
370
*/
297
371
bool plugin_init(module::Registry &registry,
 
372
                 int *argc, char **argv,
298
373
                 po::options_description &long_options)
299
374
{
300
375
  memory::Root tmp_root(4096);
304
379
 
305
380
  initialized= 1;
306
381
 
307
 
  PluginOptions builtin_load_list;
308
 
  tokenize(builtin_load_plugins, builtin_load_list, ",", true);
309
 
 
310
 
  PluginOptions builtin_list;
 
382
  vector<string> builtin_list;
311
383
  tokenize(builtin_plugins, builtin_list, ",", true);
312
384
 
313
385
  bool load_failed= false;
314
 
 
315
 
  if (opt_plugin_add.size() > 0)
316
 
  {
317
 
    for (PluginOptions::iterator iter= opt_plugin_add.begin();
318
 
         iter != opt_plugin_add.end();
319
 
         ++iter)
320
 
    {
321
 
      if (find(builtin_list.begin(),
322
 
               builtin_list.end(), *iter) != builtin_list.end())
323
 
      {
324
 
        builtin_load_list.push_back(*iter);
325
 
      }
326
 
      else
327
 
      {
328
 
        opt_plugin_load.push_back(*iter);
329
 
      }
330
 
    }
331
 
  }
332
 
 
333
 
  if (opt_plugin_remove.size() > 0)
334
 
  {
335
 
    plugin_prune_list(opt_plugin_load, opt_plugin_remove);
336
 
    plugin_prune_list(builtin_load_list, opt_plugin_remove);
 
386
  vector<string> plugin_list;
 
387
  if (opt_plugin_load)
 
388
  {
 
389
    tokenize(opt_plugin_load, plugin_list, ",", true);
 
390
  }
 
391
  else
 
392
  {
 
393
    tokenize(opt_plugin_load_default, plugin_list, ",", true);
 
394
  }
 
395
  if (opt_plugin_add)
 
396
  {
 
397
    tokenize(opt_plugin_add, plugin_list, ",", true);
 
398
  }
 
399
 
 
400
  if (opt_plugin_remove)
 
401
  {
 
402
    vector<string> plugins_to_remove;
 
403
    tokenize(opt_plugin_remove, plugins_to_remove, ",", true);
 
404
    plugin_prune_list(plugin_list, plugins_to_remove);
 
405
    plugin_prune_list(builtin_list, plugins_to_remove);
337
406
  }
338
407
 
339
408
 
340
409
  /*
341
410
    First we register builtin plugins
342
411
  */
343
 
  const set<string> builtin_list_set(builtin_load_list.begin(),
344
 
                                     builtin_load_list.end());
345
 
  load_failed= plugin_load_list(registry, &tmp_root,
 
412
  const set<string> builtin_list_set(builtin_list.begin(), builtin_list.end());
 
413
  load_failed= plugin_load_list(registry, &tmp_root, argc, argv,
346
414
                                builtin_list_set, long_options, true);
347
415
  if (load_failed)
348
416
  {
351
419
  }
352
420
 
353
421
  /* Uniquify the list */
354
 
  const set<string> plugin_list_set(opt_plugin_load.begin(),
355
 
                                    opt_plugin_load.end());
 
422
  const set<string> plugin_list_set(plugin_list.begin(), plugin_list.end());
356
423
  
357
424
  /* Register all dynamic plugins */
358
 
  load_failed= plugin_load_list(registry, &tmp_root,
 
425
  load_failed= plugin_load_list(registry, &tmp_root, argc, argv,
359
426
                                plugin_list_set, long_options);
360
427
  if (load_failed)
361
428
  {
368
435
  return false;
369
436
}
370
437
 
371
 
bool plugin_finalize(module::Registry &registry)
 
438
void plugin_finalize(module::Registry &registry)
372
439
{
 
440
 
373
441
  /*
374
442
    Now we initialize all remaining plugins
375
443
  */
382
450
    ++modules;
383
451
    if (module->isInited == false)
384
452
    {
 
453
      plugin_initialize_vars(module);
 
454
 
385
455
      if (plugin_initialize(registry, module))
386
456
      {
387
457
        registry.remove(module);
388
 
        delete module;
389
 
        return true;
 
458
        delete_module(module);
390
459
      }
391
460
    }
392
461
  }
393
 
 
394
 
  BOOST_FOREACH(plugin::Plugin::map::value_type value, registry.getPluginsMap())
395
 
  {
396
 
    value.second->prime();
397
 
  }
398
 
 
399
 
  return false;
400
462
}
401
463
 
402
464
class PrunePlugin :
434
496
  called only by plugin_init()
435
497
*/
436
498
static bool plugin_load_list(module::Registry &registry,
437
 
                             memory::Root *tmp_root,
 
499
                             memory::Root *tmp_root, int *argc, char **argv,
438
500
                             const set<string> &plugin_list,
439
501
                             po::options_description &long_options,
440
502
                             bool builtin)
457
519
    }
458
520
 
459
521
    tmp_root->free_root(MYF(memory::MARK_BLOCKS_FREE));
460
 
    if (plugin_add(registry, tmp_root, library, long_options))
 
522
    if (plugin_add(registry, tmp_root, library, argc, argv, long_options))
461
523
    {
462
524
      registry.removeLibrary(plugin_name);
463
525
      errmsg_printf(ERRMSG_LVL_ERROR,
482
544
    unlock_variables(NULL, &global_system_variables);
483
545
    unlock_variables(NULL, &max_system_variables);
484
546
 
485
 
    cleanup_variables(&global_system_variables);
486
 
    cleanup_variables(&max_system_variables);
 
547
    cleanup_variables(NULL, &global_system_variables);
 
548
    cleanup_variables(NULL, &max_system_variables);
487
549
 
488
550
    initialized= 0;
489
551
  }
494
556
  global_variables_dynamic_size= 0;
495
557
}
496
558
 
 
559
/****************************************************************************
 
560
  Internal type declarations for variables support
 
561
****************************************************************************/
 
562
 
 
563
#undef DRIZZLE_SYSVAR_NAME
 
564
#define DRIZZLE_SYSVAR_NAME(name) name
 
565
#define PLUGIN_VAR_TYPEMASK 0x007f
 
566
 
 
567
static const uint32_t EXTRA_OPTIONS= 1; /* handle the NULL option */
 
568
 
 
569
typedef DECLARE_DRIZZLE_SYSVAR_BASIC(sysvar_bool_t, bool);
 
570
typedef DECLARE_DRIZZLE_SessionVAR_BASIC(sessionvar_bool_t, bool);
 
571
typedef DECLARE_DRIZZLE_SYSVAR_BASIC(sysvar_str_t, char *);
 
572
typedef DECLARE_DRIZZLE_SessionVAR_BASIC(sessionvar_str_t, char *);
 
573
 
 
574
typedef DECLARE_DRIZZLE_SessionVAR_TYPELIB(sessionvar_enum_t, unsigned long);
 
575
typedef DECLARE_DRIZZLE_SessionVAR_TYPELIB(sessionvar_set_t, uint64_t);
 
576
 
 
577
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_int_t, int);
 
578
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_long_t, long);
 
579
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_int64_t_t, int64_t);
 
580
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_uint_t, uint);
 
581
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_ulong_t, ulong);
 
582
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_uint64_t_t, uint64_t);
 
583
 
 
584
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_int_t, int);
 
585
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_long_t, long);
 
586
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_int64_t_t, int64_t);
 
587
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_uint_t, uint);
 
588
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_ulong_t, ulong);
 
589
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_uint64_t_t, uint64_t);
 
590
 
 
591
typedef bool *(*mysql_sys_var_ptr_p)(Session* a_session, int offset);
 
592
 
 
593
 
 
594
/****************************************************************************
 
595
  default variable data check and update functions
 
596
****************************************************************************/
 
597
 
 
598
static int check_func_bool(Session *, drizzle_sys_var *var,
 
599
                           void *save, drizzle_value *value)
 
600
{
 
601
  char buff[STRING_BUFFER_USUAL_SIZE];
 
602
  const char *strvalue= "NULL", *str;
 
603
  int result, length;
 
604
  int64_t tmp;
 
605
 
 
606
  if (value->value_type(value) == DRIZZLE_VALUE_TYPE_STRING)
 
607
  {
 
608
    length= sizeof(buff);
 
609
    if (!(str= value->val_str(value, buff, &length)) ||
 
610
        (result= find_type(&bool_typelib, str, length, 1)-1) < 0)
 
611
    {
 
612
      if (str)
 
613
        strvalue= str;
 
614
      goto err;
 
615
    }
 
616
  }
 
617
  else
 
618
  {
 
619
    if (value->val_int(value, &tmp) < 0)
 
620
      goto err;
 
621
    if (tmp > 1)
 
622
    {
 
623
      internal::llstr(tmp, buff);
 
624
      strvalue= buff;
 
625
      goto err;
 
626
    }
 
627
    result= (int) tmp;
 
628
  }
 
629
  *(int*)save= -result;
 
630
  return 0;
 
631
err:
 
632
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
 
633
  return 1;
 
634
}
 
635
 
 
636
 
 
637
static int check_func_int(Session *session, drizzle_sys_var *var,
 
638
                          void *save, drizzle_value *value)
 
639
{
 
640
  bool fixed;
 
641
  int64_t tmp;
 
642
  struct option options;
 
643
  value->val_int(value, &tmp);
 
644
  plugin_opt_set_limits(&options, var);
 
645
 
 
646
  if (var->flags & PLUGIN_VAR_UNSIGNED)
 
647
    *(uint32_t *)save= (uint32_t) getopt_ull_limit_value((uint64_t) tmp, &options,
 
648
                                                   &fixed);
 
649
  else
 
650
    *(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed);
 
651
 
 
652
  return throw_bounds_warning(session, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
653
                              var->name, (int64_t) tmp);
 
654
}
 
655
 
 
656
 
 
657
static int check_func_long(Session *session, drizzle_sys_var *var,
 
658
                          void *save, drizzle_value *value)
 
659
{
 
660
  bool fixed;
 
661
  int64_t tmp;
 
662
  struct option options;
 
663
  value->val_int(value, &tmp);
 
664
  plugin_opt_set_limits(&options, var);
 
665
 
 
666
  if (var->flags & PLUGIN_VAR_UNSIGNED)
 
667
    *(ulong *)save= (ulong) getopt_ull_limit_value((uint64_t) tmp, &options,
 
668
                                                   &fixed);
 
669
  else
 
670
    *(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed);
 
671
 
 
672
  return throw_bounds_warning(session, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
673
                              var->name, (int64_t) tmp);
 
674
}
 
675
 
 
676
 
 
677
static int check_func_int64_t(Session *session, drizzle_sys_var *var,
 
678
                               void *save, drizzle_value *value)
 
679
{
 
680
  bool fixed;
 
681
  int64_t tmp;
 
682
  struct option options;
 
683
  value->val_int(value, &tmp);
 
684
  plugin_opt_set_limits(&options, var);
 
685
 
 
686
  if (var->flags & PLUGIN_VAR_UNSIGNED)
 
687
    *(uint64_t *)save= getopt_ull_limit_value((uint64_t) tmp, &options,
 
688
                                               &fixed);
 
689
  else
 
690
    *(int64_t *)save= getopt_ll_limit_value(tmp, &options, &fixed);
 
691
 
 
692
  return throw_bounds_warning(session, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
693
                              var->name, (int64_t) tmp);
 
694
}
 
695
 
 
696
static int check_func_str(Session *session, drizzle_sys_var *,
 
697
                          void *save, drizzle_value *value)
 
698
{
 
699
  char buff[STRING_BUFFER_USUAL_SIZE];
 
700
  const char *str;
 
701
  int length;
 
702
 
 
703
  length= sizeof(buff);
 
704
  if ((str= value->val_str(value, buff, &length)))
 
705
    str= session->strmake(str, length);
 
706
  *(const char**)save= str;
 
707
  return 0;
 
708
}
 
709
 
 
710
 
 
711
static void update_func_bool(Session *, drizzle_sys_var *,
 
712
                             void *tgt, const void *save)
 
713
{
 
714
  *(bool *) tgt= *(int *) save ? 1 : 0;
 
715
}
 
716
 
 
717
 
 
718
static void update_func_int(Session *, drizzle_sys_var *,
 
719
                             void *tgt, const void *save)
 
720
{
 
721
  *(int *)tgt= *(int *) save;
 
722
}
 
723
 
 
724
 
 
725
static void update_func_long(Session *, drizzle_sys_var *,
 
726
                             void *tgt, const void *save)
 
727
{
 
728
  *(long *)tgt= *(long *) save;
 
729
}
 
730
 
 
731
 
 
732
static void update_func_int64_t(Session *, drizzle_sys_var *,
 
733
                                 void *tgt, const void *save)
 
734
{
 
735
  *(int64_t *)tgt= *(uint64_t *) save;
 
736
}
 
737
 
 
738
 
 
739
static void update_func_str(Session *, drizzle_sys_var *var,
 
740
                             void *tgt, const void *save)
 
741
{
 
742
  char *old= *(char **) tgt;
 
743
  *(char **)tgt= *(char **) save;
 
744
  if (var->flags & PLUGIN_VAR_MEMALLOC)
 
745
  {
 
746
    *(char **)tgt= strdup(*(char **) save);
 
747
    free(old);
 
748
    /*
 
749
     * There isn't a _really_ good thing to do here until this whole set_var
 
750
     * mess gets redesigned
 
751
     */
 
752
    if (tgt == NULL)
 
753
      errmsg_printf(ERRMSG_LVL_ERROR, _("Out of memory."));
 
754
 
 
755
  }
 
756
}
 
757
 
497
758
 
498
759
/****************************************************************************
499
760
  System Variables support
500
761
****************************************************************************/
501
762
 
502
763
 
503
 
sys_var *find_sys_var(const char *str, uint32_t length)
504
 
{
505
 
  return intern_find_sys_var(str, length, false);
506
 
}
507
 
 
 
764
sys_var *find_sys_var(Session *, const char *str, uint32_t length)
 
765
{
 
766
  sys_var *var;
 
767
  sys_var_pluginvar *pi= NULL;
 
768
  module::Module *module;
 
769
 
 
770
  if ((var= intern_find_sys_var(str, length, false)) &&
 
771
      (pi= var->cast_pluginvar()))
 
772
  {
 
773
    if (!(module= pi->plugin))
 
774
      var= NULL; /* failed to lock it, it must be uninstalling */
 
775
    else if (module->isInited == false)
 
776
    {
 
777
      var= NULL;
 
778
    }
 
779
  }
 
780
 
 
781
  /*
 
782
    If the variable exists but the plugin it is associated with is not ready
 
783
    then the intern_plugin_lock did not raise an error, so we do it here.
 
784
  */
 
785
  if (pi && !var)
 
786
    my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
 
787
  return(var);
 
788
}
 
789
 
 
790
static const string make_bookmark_name(const string &plugin, const char *name)
 
791
{
 
792
  string varname(plugin);
 
793
  varname.push_back('_');
 
794
  varname.append(name);
 
795
 
 
796
  for (string::iterator p= varname.begin() + 1; p != varname.end(); ++p)
 
797
  {
 
798
    if (*p == '-')
 
799
    {
 
800
      *p= '_';
 
801
    }
 
802
  }
 
803
  return varname;
 
804
}
 
805
 
 
806
/*
 
807
  called by register_var, construct_options and test_plugin_options.
 
808
  Returns the 'bookmark' for the named variable.
 
809
  LOCK_system_variables_hash should be at least read locked
 
810
*/
 
811
static Bookmark *find_bookmark(const string &plugin, const char *name, int flags)
 
812
{
 
813
  if (!(flags & PLUGIN_VAR_SessionLOCAL))
 
814
    return NULL;
 
815
 
 
816
  const string varname(make_bookmark_name(plugin, name));
 
817
 
 
818
  bookmark_unordered_map::iterator iter= bookmark_hash.find(varname);
 
819
  if (iter != bookmark_hash.end())
 
820
  {
 
821
    return &((*iter).second);
 
822
  }
 
823
  return NULL;
 
824
}
 
825
 
 
826
 
 
827
/*
 
828
  returns a bookmark for session-local variables, creating if neccessary.
 
829
  returns null for non session-local variables.
 
830
  Requires that a write lock is obtained on LOCK_system_variables_hash
 
831
*/
 
832
static Bookmark *register_var(const string &plugin, const char *name,
 
833
                                 int flags)
 
834
{
 
835
  if (!(flags & PLUGIN_VAR_SessionLOCAL))
 
836
    return NULL;
 
837
 
 
838
  uint32_t size= 0, offset, new_size;
 
839
  Bookmark *result= NULL;
 
840
 
 
841
  switch (flags & PLUGIN_VAR_TYPEMASK) {
 
842
  case PLUGIN_VAR_BOOL:
 
843
    size= ALIGN_SIZE(sizeof(bool));
 
844
    break;
 
845
  case PLUGIN_VAR_INT:
 
846
    size= ALIGN_SIZE(sizeof(int));
 
847
    break;
 
848
  case PLUGIN_VAR_LONG:
 
849
    size= ALIGN_SIZE(sizeof(long));
 
850
    break;
 
851
  case PLUGIN_VAR_LONGLONG:
 
852
    size= ALIGN_SIZE(sizeof(uint64_t));
 
853
    break;
 
854
  case PLUGIN_VAR_STR:
 
855
    size= ALIGN_SIZE(sizeof(char*));
 
856
    break;
 
857
  default:
 
858
    assert(0);
 
859
    return NULL;
 
860
  };
 
861
 
 
862
 
 
863
  if (!(result= find_bookmark(plugin, name, flags)))
 
864
  {
 
865
    const string varname(make_bookmark_name(plugin, name));
 
866
 
 
867
    Bookmark new_bookmark;
 
868
    new_bookmark.key= varname;
 
869
    new_bookmark.offset= -1;
 
870
 
 
871
    assert(size && !(size & (size-1))); /* must be power of 2 */
 
872
 
 
873
    offset= global_system_variables.dynamic_variables_size;
 
874
    offset= (offset + size - 1) & ~(size - 1);
 
875
    new_bookmark.offset= (int) offset;
 
876
 
 
877
    new_size= (offset + size + 63) & ~63;
 
878
 
 
879
    if (new_size > global_variables_dynamic_size)
 
880
    {
 
881
      char* tmpptr= NULL;
 
882
      if (!(tmpptr=
 
883
              (char *)realloc(global_system_variables.dynamic_variables_ptr,
 
884
                              new_size)))
 
885
        return NULL;
 
886
      global_system_variables.dynamic_variables_ptr= tmpptr;
 
887
      tmpptr= NULL;
 
888
      if (!(tmpptr=
 
889
              (char *)realloc(max_system_variables.dynamic_variables_ptr,
 
890
                              new_size)))
 
891
        return NULL;
 
892
      max_system_variables.dynamic_variables_ptr= tmpptr;
 
893
           
 
894
      /*
 
895
        Clear the new variable value space. This is required for string
 
896
        variables. If their value is non-NULL, it must point to a valid
 
897
        string.
 
898
      */
 
899
      memset(global_system_variables.dynamic_variables_ptr +
 
900
             global_variables_dynamic_size, 0,
 
901
             new_size - global_variables_dynamic_size);
 
902
      memset(max_system_variables.dynamic_variables_ptr +
 
903
             global_variables_dynamic_size, 0,
 
904
             new_size - global_variables_dynamic_size);
 
905
      global_variables_dynamic_size= new_size;
 
906
    }
 
907
 
 
908
    global_system_variables.dynamic_variables_head= offset;
 
909
    max_system_variables.dynamic_variables_head= offset;
 
910
    global_system_variables.dynamic_variables_size= offset + size;
 
911
    max_system_variables.dynamic_variables_size= offset + size;
 
912
    global_system_variables.dynamic_variables_version++;
 
913
    max_system_variables.dynamic_variables_version++;
 
914
 
 
915
    new_bookmark.version= global_system_variables.dynamic_variables_version;
 
916
    new_bookmark.type_code= flags;
 
917
 
 
918
    /* this should succeed because we have already checked if a dup exists */
 
919
    bookmark_hash.insert(make_pair(varname, new_bookmark));
 
920
    result= find_bookmark(plugin, name, flags);
 
921
  }
 
922
  return result;
 
923
}
 
924
 
 
925
 
 
926
/*
 
927
  returns a pointer to the memory which holds the session-local variable or
 
928
  a pointer to the global variable if session==null.
 
929
  If required, will sync with global variables if the requested variable
 
930
  has not yet been allocated in the current thread.
 
931
*/
 
932
static unsigned char *intern_sys_var_ptr(Session* session, int offset, bool global_lock)
 
933
{
 
934
  assert(offset >= 0);
 
935
  assert((uint32_t)offset <= global_system_variables.dynamic_variables_head);
 
936
 
 
937
  if (!session)
 
938
    return (unsigned char*) global_system_variables.dynamic_variables_ptr + offset;
 
939
 
 
940
  /*
 
941
    dynamic_variables_head points to the largest valid offset
 
942
  */
 
943
  if (!session->variables.dynamic_variables_ptr ||
 
944
      (uint32_t)offset > session->variables.dynamic_variables_head)
 
945
  {
 
946
    char *tmpptr= NULL;
 
947
    if (!(tmpptr= (char *)realloc(session->variables.dynamic_variables_ptr,
 
948
                                  global_variables_dynamic_size)))
 
949
      return NULL;
 
950
    session->variables.dynamic_variables_ptr= tmpptr;
 
951
 
 
952
    if (global_lock)
 
953
      LOCK_global_system_variables.lock();
 
954
 
 
955
    //safe_mutex_assert_owner(&LOCK_global_system_variables);
 
956
 
 
957
    memcpy(session->variables.dynamic_variables_ptr +
 
958
             session->variables.dynamic_variables_size,
 
959
           global_system_variables.dynamic_variables_ptr +
 
960
             session->variables.dynamic_variables_size,
 
961
           global_system_variables.dynamic_variables_size -
 
962
             session->variables.dynamic_variables_size);
 
963
 
 
964
    /*
 
965
      now we need to iterate through any newly copied 'defaults'
 
966
      and if it is a string type with MEMALLOC flag, we need to strdup
 
967
    */
 
968
    bookmark_unordered_map::iterator iter= bookmark_hash.begin();
 
969
    for (; iter != bookmark_hash.end() ; ++iter)
 
970
    {
 
971
      sys_var_pluginvar *pi;
 
972
      sys_var *var;
 
973
      const Bookmark &v= (*iter).second;
 
974
      const string var_name((*iter).first);
 
975
 
 
976
      if (v.version <= session->variables.dynamic_variables_version ||
 
977
          !(var= intern_find_sys_var(var_name.c_str(), var_name.size(), true)) ||
 
978
          !(pi= var->cast_pluginvar()) ||
 
979
          v.type_code != (pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
 
980
        continue;
 
981
 
 
982
      /* Here we do anything special that may be required of the data types */
 
983
 
 
984
      if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
 
985
          pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
 
986
      {
 
987
         char **pp= (char**) (session->variables.dynamic_variables_ptr +
 
988
                             *(int*)(pi->plugin_var + 1));
 
989
         if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr +
 
990
                             *(int*)(pi->plugin_var + 1))))
 
991
           *pp= strdup(*pp);
 
992
         if (*pp == NULL)
 
993
           return NULL;
 
994
      }
 
995
    }
 
996
 
 
997
    if (global_lock)
 
998
      LOCK_global_system_variables.unlock();
 
999
 
 
1000
    session->variables.dynamic_variables_version=
 
1001
           global_system_variables.dynamic_variables_version;
 
1002
    session->variables.dynamic_variables_head=
 
1003
           global_system_variables.dynamic_variables_head;
 
1004
    session->variables.dynamic_variables_size=
 
1005
           global_system_variables.dynamic_variables_size;
 
1006
  }
 
1007
  return (unsigned char*)session->variables.dynamic_variables_ptr + offset;
 
1008
}
 
1009
 
 
1010
static bool *mysql_sys_var_ptr_bool(Session* a_session, int offset)
 
1011
{
 
1012
  return (bool *)intern_sys_var_ptr(a_session, offset, true);
 
1013
}
 
1014
 
 
1015
static int *mysql_sys_var_ptr_int(Session* a_session, int offset)
 
1016
{
 
1017
  return (int *)intern_sys_var_ptr(a_session, offset, true);
 
1018
}
 
1019
 
 
1020
static long *mysql_sys_var_ptr_long(Session* a_session, int offset)
 
1021
{
 
1022
  return (long *)intern_sys_var_ptr(a_session, offset, true);
 
1023
}
 
1024
 
 
1025
static int64_t *mysql_sys_var_ptr_int64_t(Session* a_session, int offset)
 
1026
{
 
1027
  return (int64_t *)intern_sys_var_ptr(a_session, offset, true);
 
1028
}
 
1029
 
 
1030
static char **mysql_sys_var_ptr_str(Session* a_session, int offset)
 
1031
{
 
1032
  return (char **)intern_sys_var_ptr(a_session, offset, true);
 
1033
}
508
1034
 
509
1035
void plugin_sessionvar_init(Session *session)
510
1036
{
511
1037
  session->variables.storage_engine= NULL;
512
 
  cleanup_variables(&session->variables);
 
1038
  cleanup_variables(session, &session->variables);
513
1039
 
514
1040
  session->variables= global_system_variables;
515
1041
  session->variables.storage_engine= NULL;
526
1052
/*
527
1053
  Unlocks all system variables which hold a reference
528
1054
*/
529
 
static void unlock_variables(Session *, struct drizzle_system_variables *vars)
 
1055
static void unlock_variables(Session *, struct system_variables *vars)
530
1056
{
531
1057
  vars->storage_engine= NULL;
532
1058
}
538
1064
  Unlike plugin_vars_free_values() it frees all variables of all plugins,
539
1065
  it's used on shutdown.
540
1066
*/
541
 
static void cleanup_variables(drizzle_system_variables *vars)
 
1067
static void cleanup_variables(Session *session, struct system_variables *vars)
542
1068
{
 
1069
  sys_var_pluginvar *pivar;
 
1070
  sys_var *var;
 
1071
  int flags;
 
1072
 
 
1073
  bookmark_unordered_map::iterator iter= bookmark_hash.begin();
 
1074
  for (; iter != bookmark_hash.end() ; ++iter)
 
1075
  {
 
1076
    const Bookmark &v= (*iter).second;
 
1077
    const string key_name((*iter).first);
 
1078
    if (v.version > vars->dynamic_variables_version ||
 
1079
        !(var= intern_find_sys_var(key_name.c_str(), key_name.size(), true)) ||
 
1080
        !(pivar= var->cast_pluginvar()) ||
 
1081
        v.type_code != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
 
1082
      continue;
 
1083
 
 
1084
    flags= pivar->plugin_var->flags;
 
1085
 
 
1086
    if ((flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
 
1087
        flags & PLUGIN_VAR_SessionLOCAL && flags & PLUGIN_VAR_MEMALLOC)
 
1088
    {
 
1089
      char **ptr= (char**) pivar->real_value_ptr(session, OPT_SESSION);
 
1090
      free(*ptr);
 
1091
      *ptr= NULL;
 
1092
    }
 
1093
  }
 
1094
 
543
1095
  assert(vars->storage_engine == NULL);
544
1096
 
545
1097
  free(vars->dynamic_variables_ptr);
552
1104
void plugin_sessionvar_cleanup(Session *session)
553
1105
{
554
1106
  unlock_variables(session, &session->variables);
555
 
  cleanup_variables(&session->variables);
556
 
}
557
 
 
558
 
 
 
1107
  cleanup_variables(session, &session->variables);
 
1108
}
 
1109
 
 
1110
 
 
1111
/**
 
1112
  @brief Free values of thread variables of a plugin.
 
1113
 
 
1114
  This must be called before a plugin is deleted. Otherwise its
 
1115
  variables are no longer accessible and the value space is lost. Note
 
1116
  that only string values with PLUGIN_VAR_MEMALLOC are allocated and
 
1117
  must be freed.
 
1118
 
 
1119
  @param[in]        vars        Chain of system variables of a plugin
 
1120
*/
 
1121
 
 
1122
static void plugin_vars_free_values(sys_var *vars)
 
1123
{
 
1124
 
 
1125
  for (sys_var *var= vars; var; var= var->getNext())
 
1126
  {
 
1127
    sys_var_pluginvar *piv= var->cast_pluginvar();
 
1128
    if (piv &&
 
1129
        ((piv->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
 
1130
        (piv->plugin_var->flags & PLUGIN_VAR_MEMALLOC))
 
1131
    {
 
1132
      /* Free the string from global_system_variables. */
 
1133
      char **valptr= (char**) piv->real_value_ptr(NULL, OPT_GLOBAL);
 
1134
      free(*valptr);
 
1135
      *valptr= NULL;
 
1136
    }
 
1137
  }
 
1138
  return;
 
1139
}
 
1140
 
 
1141
 
 
1142
bool sys_var_pluginvar::check_update_type(Item_result type)
 
1143
{
 
1144
  if (is_readonly())
 
1145
    return 1;
 
1146
  switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
 
1147
  case PLUGIN_VAR_INT:
 
1148
  case PLUGIN_VAR_LONG:
 
1149
  case PLUGIN_VAR_LONGLONG:
 
1150
    return type != INT_RESULT;
 
1151
  case PLUGIN_VAR_STR:
 
1152
    return type != STRING_RESULT;
 
1153
  default:
 
1154
    return 0;
 
1155
  }
 
1156
}
 
1157
 
 
1158
 
 
1159
SHOW_TYPE sys_var_pluginvar::show_type()
 
1160
{
 
1161
  switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
 
1162
  case PLUGIN_VAR_BOOL:
 
1163
    return SHOW_MY_BOOL;
 
1164
  case PLUGIN_VAR_INT:
 
1165
    return SHOW_INT;
 
1166
  case PLUGIN_VAR_LONG:
 
1167
    return SHOW_LONG;
 
1168
  case PLUGIN_VAR_LONGLONG:
 
1169
    return SHOW_LONGLONG;
 
1170
  case PLUGIN_VAR_STR:
 
1171
    return SHOW_CHAR_PTR;
 
1172
  default:
 
1173
    assert(0);
 
1174
    return SHOW_UNDEF;
 
1175
  }
 
1176
}
 
1177
 
 
1178
 
 
1179
unsigned char* sys_var_pluginvar::real_value_ptr(Session *session, sql_var_t type)
 
1180
{
 
1181
  assert(session || (type == OPT_GLOBAL));
 
1182
  if (plugin_var->flags & PLUGIN_VAR_SessionLOCAL)
 
1183
  {
 
1184
    if (type == OPT_GLOBAL)
 
1185
      session= NULL;
 
1186
 
 
1187
    return intern_sys_var_ptr(session, *(int*) (plugin_var+1), false);
 
1188
  }
 
1189
  return *(unsigned char**) (plugin_var+1);
 
1190
}
 
1191
 
 
1192
 
 
1193
TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
 
1194
{
 
1195
  switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_SessionLOCAL)) {
 
1196
  case PLUGIN_VAR_SessionLOCAL:
 
1197
    return ((sessionvar_enum_t *)plugin_var)->typelib;
 
1198
  default:
 
1199
    return NULL;
 
1200
  }
 
1201
  return NULL;
 
1202
}
 
1203
 
 
1204
 
 
1205
unsigned char* sys_var_pluginvar::value_ptr(Session *session, sql_var_t type, const LEX_STRING *)
 
1206
{
 
1207
  unsigned char* result;
 
1208
 
 
1209
  result= real_value_ptr(session, type);
 
1210
 
 
1211
  return result;
 
1212
}
 
1213
 
 
1214
 
 
1215
bool sys_var_pluginvar::check(Session *session, set_var *var)
 
1216
{
 
1217
  st_item_value_holder value;
 
1218
  assert(is_readonly() || plugin_var->check);
 
1219
 
 
1220
  value.value_type= item_value_type;
 
1221
  value.val_str= item_val_str;
 
1222
  value.val_int= item_val_int;
 
1223
  value.val_real= item_val_real;
 
1224
  value.item= var->value;
 
1225
 
 
1226
  return is_readonly() ||
 
1227
         plugin_var->check(session, plugin_var, &var->save_result, &value);
 
1228
}
 
1229
 
 
1230
 
 
1231
void sys_var_pluginvar::set_default(Session *session, sql_var_t type)
 
1232
{
 
1233
  const void *src;
 
1234
  void *tgt;
 
1235
 
 
1236
  assert(is_readonly() || plugin_var->update);
 
1237
 
 
1238
  if (is_readonly())
 
1239
    return;
 
1240
 
 
1241
  LOCK_global_system_variables.lock();
 
1242
  tgt= real_value_ptr(session, type);
 
1243
  src= ((void **) (plugin_var + 1) + 1);
 
1244
 
 
1245
  if (plugin_var->flags & PLUGIN_VAR_SessionLOCAL)
 
1246
  {
 
1247
    if (type != OPT_GLOBAL)
 
1248
      src= real_value_ptr(session, OPT_GLOBAL);
 
1249
    else
 
1250
    switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
 
1251
        case PLUGIN_VAR_INT:
 
1252
          src= &((sessionvar_uint_t*) plugin_var)->def_val;
 
1253
          break;
 
1254
        case PLUGIN_VAR_LONG:
 
1255
          src= &((sessionvar_ulong_t*) plugin_var)->def_val;
 
1256
          break;
 
1257
        case PLUGIN_VAR_LONGLONG:
 
1258
          src= &((sessionvar_uint64_t_t*) plugin_var)->def_val;
 
1259
          break;
 
1260
        case PLUGIN_VAR_BOOL:
 
1261
          src= &((sessionvar_bool_t*) plugin_var)->def_val;
 
1262
          break;
 
1263
        case PLUGIN_VAR_STR:
 
1264
          src= &((sessionvar_str_t*) plugin_var)->def_val;
 
1265
          break;
 
1266
        default:
 
1267
          assert(0);
 
1268
        }
 
1269
  }
 
1270
 
 
1271
  /* session must equal current_session if PLUGIN_VAR_SessionLOCAL flag is set */
 
1272
  assert(!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) ||
 
1273
              session == current_session);
 
1274
 
 
1275
  if (!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) || type == OPT_GLOBAL)
 
1276
  {
 
1277
    plugin_var->update(session, plugin_var, tgt, src);
 
1278
    LOCK_global_system_variables.unlock();
 
1279
  }
 
1280
  else
 
1281
  {
 
1282
    LOCK_global_system_variables.unlock();
 
1283
    plugin_var->update(session, plugin_var, tgt, src);
 
1284
  }
 
1285
}
 
1286
 
 
1287
 
 
1288
bool sys_var_pluginvar::update(Session *session, set_var *var)
 
1289
{
 
1290
  void *tgt;
 
1291
 
 
1292
  assert(is_readonly() || plugin_var->update);
 
1293
 
 
1294
  /* session must equal current_session if PLUGIN_VAR_SessionLOCAL flag is set */
 
1295
  assert(!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) ||
 
1296
              session == current_session);
 
1297
 
 
1298
  if (is_readonly())
 
1299
    return 1;
 
1300
 
 
1301
  LOCK_global_system_variables.lock();
 
1302
  tgt= real_value_ptr(session, var->type);
 
1303
 
 
1304
  if (!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) || var->type == OPT_GLOBAL)
 
1305
  {
 
1306
    /* variable we are updating has global scope, so we unlock after updating */
 
1307
    plugin_var->update(session, plugin_var, tgt, &var->save_result);
 
1308
    LOCK_global_system_variables.unlock();
 
1309
  }
 
1310
  else
 
1311
  {
 
1312
    LOCK_global_system_variables.unlock();
 
1313
    plugin_var->update(session, plugin_var, tgt, &var->save_result);
 
1314
  }
 
1315
 return 0;
 
1316
}
 
1317
 
 
1318
 
 
1319
#define OPTION_SET_LIMITS(type, options, opt) \
 
1320
  options->var_type= type;                    \
 
1321
  options->def_value= (opt)->def_val;         \
 
1322
  options->min_value= (opt)->min_val;         \
 
1323
  options->max_value= (opt)->max_val;         \
 
1324
  options->block_size= (long) (opt)->blk_sz
 
1325
 
 
1326
 
 
1327
void plugin_opt_set_limits(struct option *options,
 
1328
                                                                                                         const drizzle_sys_var *opt)
 
1329
{
 
1330
  options->sub_size= 0;
 
1331
 
 
1332
  switch (opt->flags & (PLUGIN_VAR_TYPEMASK |
 
1333
                        PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL)) {
 
1334
  /* global system variables */
 
1335
  case PLUGIN_VAR_INT:
 
1336
    OPTION_SET_LIMITS(GET_INT, options, (sysvar_int_t*) opt);
 
1337
    break;
 
1338
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED:
 
1339
    OPTION_SET_LIMITS(GET_UINT, options, (sysvar_uint_t*) opt);
 
1340
    break;
 
1341
  case PLUGIN_VAR_LONG:
 
1342
    OPTION_SET_LIMITS(GET_LONG, options, (sysvar_long_t*) opt);
 
1343
    break;
 
1344
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
 
1345
    OPTION_SET_LIMITS(GET_ULONG_IS_FAIL, options, (sysvar_ulong_t*) opt);
 
1346
    break;
 
1347
  case PLUGIN_VAR_LONGLONG:
 
1348
    OPTION_SET_LIMITS(GET_LL, options, (sysvar_int64_t_t*) opt);
 
1349
    break;
 
1350
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
 
1351
    OPTION_SET_LIMITS(GET_ULL, options, (sysvar_uint64_t_t*) opt);
 
1352
    break;
 
1353
  case PLUGIN_VAR_BOOL:
 
1354
    options->var_type= GET_BOOL;
 
1355
    options->def_value= ((sysvar_bool_t*) opt)->def_val;
 
1356
    break;
 
1357
  case PLUGIN_VAR_STR:
 
1358
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
 
1359
                        GET_STR_ALLOC : GET_STR);
 
1360
    options->def_value= (intptr_t) ((sysvar_str_t*) opt)->def_val;
 
1361
    break;
 
1362
  /* threadlocal variables */
 
1363
  case PLUGIN_VAR_INT | PLUGIN_VAR_SessionLOCAL:
 
1364
    OPTION_SET_LIMITS(GET_INT, options, (sessionvar_int_t*) opt);
 
1365
    break;
 
1366
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL:
 
1367
    OPTION_SET_LIMITS(GET_UINT, options, (sessionvar_uint_t*) opt);
 
1368
    break;
 
1369
  case PLUGIN_VAR_LONG | PLUGIN_VAR_SessionLOCAL:
 
1370
    OPTION_SET_LIMITS(GET_LONG, options, (sessionvar_long_t*) opt);
 
1371
    break;
 
1372
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL:
 
1373
    OPTION_SET_LIMITS(GET_ULONG_IS_FAIL, options, (sessionvar_ulong_t*) opt);
 
1374
    break;
 
1375
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_SessionLOCAL:
 
1376
    OPTION_SET_LIMITS(GET_LL, options, (sessionvar_int64_t_t*) opt);
 
1377
    break;
 
1378
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL:
 
1379
    OPTION_SET_LIMITS(GET_ULL, options, (sessionvar_uint64_t_t*) opt);
 
1380
    break;
 
1381
  case PLUGIN_VAR_BOOL | PLUGIN_VAR_SessionLOCAL:
 
1382
    options->var_type= GET_BOOL;
 
1383
    options->def_value= ((sessionvar_bool_t*) opt)->def_val;
 
1384
    break;
 
1385
  case PLUGIN_VAR_STR | PLUGIN_VAR_SessionLOCAL:
 
1386
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
 
1387
                        GET_STR_ALLOC : GET_STR);
 
1388
    options->def_value= (intptr_t) ((sessionvar_str_t*) opt)->def_val;
 
1389
    break;
 
1390
  default:
 
1391
    assert(0);
 
1392
  }
 
1393
  options->arg_type= REQUIRED_ARG;
 
1394
  if (opt->flags & PLUGIN_VAR_NOCMDARG)
 
1395
    options->arg_type= NO_ARG;
 
1396
  if (opt->flags & PLUGIN_VAR_OPCMDARG)
 
1397
    options->arg_type= OPT_ARG;
 
1398
}
 
1399
 
 
1400
static int get_one_plugin_option(int, const struct option *, char *)
 
1401
{
 
1402
  return 0;
 
1403
}
 
1404
 
 
1405
 
 
1406
static int construct_options(memory::Root *mem_root, module::Module *tmp,
 
1407
                             option *options)
 
1408
{
 
1409
  
 
1410
  int localoptionid= 256;
 
1411
  const string plugin_name(tmp->getManifest().name);
 
1412
 
 
1413
  size_t namelen= plugin_name.size(), optnamelen;
 
1414
 
 
1415
  char *optname, *p;
 
1416
  int index= 0, offset= 0;
 
1417
  drizzle_sys_var *opt, **plugin_option;
 
1418
  Bookmark *v;
 
1419
 
 
1420
  string name(plugin_name);
 
1421
  transform(name.begin(), name.end(), name.begin(), ::tolower);
 
1422
 
 
1423
  for (string::iterator iter= name.begin(); iter != name.end(); ++iter)
 
1424
  {
 
1425
    if (*iter == '_')
 
1426
      *iter= '-';
 
1427
  }
 
1428
 
 
1429
  /*
 
1430
    Two passes as the 2nd pass will take pointer addresses for use
 
1431
    by my_getopt and register_var() in the first pass uses realloc
 
1432
  */
 
1433
 
 
1434
  for (plugin_option= tmp->getManifest().system_vars;
 
1435
       plugin_option && *plugin_option; plugin_option++, index++)
 
1436
  {
 
1437
    opt= *plugin_option;
 
1438
    if (!(opt->flags & PLUGIN_VAR_SessionLOCAL))
 
1439
      continue;
 
1440
    if (!(register_var(name, opt->name, opt->flags)))
 
1441
      continue;
 
1442
    switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
 
1443
    case PLUGIN_VAR_BOOL:
 
1444
      (((sessionvar_bool_t *)opt)->resolve)= mysql_sys_var_ptr_bool;
 
1445
      break;
 
1446
    case PLUGIN_VAR_INT:
 
1447
      (((sessionvar_int_t *)opt)->resolve)= mysql_sys_var_ptr_int;
 
1448
      break;
 
1449
    case PLUGIN_VAR_LONG:
 
1450
      (((sessionvar_long_t *)opt)->resolve)= mysql_sys_var_ptr_long;
 
1451
      break;
 
1452
    case PLUGIN_VAR_LONGLONG:
 
1453
      (((sessionvar_int64_t_t *)opt)->resolve)= mysql_sys_var_ptr_int64_t;
 
1454
      break;
 
1455
    case PLUGIN_VAR_STR:
 
1456
      (((sessionvar_str_t *)opt)->resolve)= mysql_sys_var_ptr_str;
 
1457
      break;
 
1458
    default:
 
1459
      errmsg_printf(ERRMSG_LVL_ERROR, _("Unknown variable type code 0x%x in plugin '%s'."),
 
1460
                      opt->flags, plugin_name.c_str());
 
1461
      return(-1);
 
1462
    };
 
1463
  }
 
1464
 
 
1465
  for (plugin_option= tmp->getManifest().system_vars;
 
1466
       plugin_option && *plugin_option; plugin_option++, index++)
 
1467
  {
 
1468
    switch ((opt= *plugin_option)->flags & PLUGIN_VAR_TYPEMASK) {
 
1469
    case PLUGIN_VAR_BOOL:
 
1470
      if (!opt->check)
 
1471
        opt->check= check_func_bool;
 
1472
      if (!opt->update)
 
1473
        opt->update= update_func_bool;
 
1474
      break;
 
1475
    case PLUGIN_VAR_INT:
 
1476
      if (!opt->check)
 
1477
        opt->check= check_func_int;
 
1478
      if (!opt->update)
 
1479
        opt->update= update_func_int;
 
1480
      break;
 
1481
    case PLUGIN_VAR_LONG:
 
1482
      if (!opt->check)
 
1483
        opt->check= check_func_long;
 
1484
      if (!opt->update)
 
1485
        opt->update= update_func_long;
 
1486
      break;
 
1487
    case PLUGIN_VAR_LONGLONG:
 
1488
      if (!opt->check)
 
1489
        opt->check= check_func_int64_t;
 
1490
      if (!opt->update)
 
1491
        opt->update= update_func_int64_t;
 
1492
      break;
 
1493
    case PLUGIN_VAR_STR:
 
1494
      if (!opt->check)
 
1495
        opt->check= check_func_str;
 
1496
      if (!opt->update)
 
1497
      {
 
1498
        opt->update= update_func_str;
 
1499
        if ((opt->flags & (PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY)) == false)
 
1500
        {
 
1501
          opt->flags|= PLUGIN_VAR_READONLY;
 
1502
          errmsg_printf(ERRMSG_LVL_WARN, _("Server variable %s of plugin %s was forced "
 
1503
                            "to be read-only: string variable without "
 
1504
                            "update_func and PLUGIN_VAR_MEMALLOC flag"),
 
1505
                            opt->name, plugin_name.c_str());
 
1506
        }
 
1507
      }
 
1508
      break;
 
1509
    default:
 
1510
      errmsg_printf(ERRMSG_LVL_ERROR, _("Unknown variable type code 0x%x in plugin '%s'."),
 
1511
                      opt->flags, plugin_name.c_str());
 
1512
      return(-1);
 
1513
    }
 
1514
 
 
1515
    if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_SessionLOCAL))
 
1516
                    == PLUGIN_VAR_NOCMDOPT)
 
1517
      continue;
 
1518
 
 
1519
    if (!opt->name)
 
1520
    {
 
1521
      errmsg_printf(ERRMSG_LVL_ERROR, _("Missing variable name in plugin '%s'."),
 
1522
                    plugin_name.c_str());
 
1523
      return(-1);
 
1524
    }
 
1525
 
 
1526
    if (!(opt->flags & PLUGIN_VAR_SessionLOCAL))
 
1527
    {
 
1528
      optnamelen= strlen(opt->name);
 
1529
      optname= (char*) mem_root->alloc_root(namelen + optnamelen + 2);
 
1530
      sprintf(optname, "%s-%s", name.c_str(), opt->name);
 
1531
      optnamelen= namelen + optnamelen + 1;
 
1532
    }
 
1533
    else
 
1534
    {
 
1535
      /* this should not fail because register_var should create entry */
 
1536
      if (!(v= find_bookmark(name, opt->name, opt->flags)))
 
1537
      {
 
1538
        errmsg_printf(ERRMSG_LVL_ERROR, _("Thread local variable '%s' not allocated "
 
1539
                      "in plugin '%s'."), opt->name, plugin_name.c_str());
 
1540
        return(-1);
 
1541
      }
 
1542
 
 
1543
      *(int*)(opt + 1)= offset= v->offset;
 
1544
 
 
1545
      if (opt->flags & PLUGIN_VAR_NOCMDOPT)
 
1546
        continue;
 
1547
 
 
1548
      optname= (char*) mem_root->memdup_root(v->key.c_str(), (optnamelen= v->key.size()) + 1);
 
1549
    }
 
1550
 
 
1551
    /* convert '_' to '-' */
 
1552
    for (p= optname; *p; p++)
 
1553
      if (*p == '_')
 
1554
        *p= '-';
 
1555
 
 
1556
    options->name= optname;
 
1557
    options->comment= opt->comment;
 
1558
    options->app_type= opt;
 
1559
    options->id= localoptionid++;
 
1560
 
 
1561
    plugin_opt_set_limits(options, opt);
 
1562
 
 
1563
    if (opt->flags & PLUGIN_VAR_SessionLOCAL)
 
1564
      options->value= options->u_max_value= (char**)
 
1565
        (global_system_variables.dynamic_variables_ptr + offset);
 
1566
    else
 
1567
      options->value= options->u_max_value= *(char***) (opt + 1);
 
1568
 
 
1569
    options++;
 
1570
  }
 
1571
 
 
1572
  return(0);
 
1573
}
 
1574
 
 
1575
 
 
1576
static option *construct_help_options(memory::Root *mem_root, module::Module *p)
 
1577
{
 
1578
  drizzle_sys_var **opt;
 
1579
  option *opts;
 
1580
  uint32_t count= EXTRA_OPTIONS;
 
1581
 
 
1582
  for (opt= p->getManifest().system_vars; opt && *opt; opt++, count++) {};
 
1583
 
 
1584
  opts= (option*)mem_root->alloc_root((sizeof(option) * count));
 
1585
  if (opts == NULL)
 
1586
    return NULL;
 
1587
 
 
1588
  memset(opts, 0, sizeof(option) * count);
 
1589
 
 
1590
  if (construct_options(mem_root, p, opts))
 
1591
    return NULL;
 
1592
 
 
1593
  return(opts);
 
1594
}
 
1595
 
 
1596
void drizzle_add_plugin_sysvar(sys_var_pluginvar *var)
 
1597
{
 
1598
  plugin_sysvar_vec.push_back(var);
 
1599
}
 
1600
 
 
1601
void drizzle_del_plugin_sysvar()
 
1602
{
 
1603
  vector<sys_var_pluginvar *>::iterator iter= plugin_sysvar_vec.begin();
 
1604
  while(iter != plugin_sysvar_vec.end())
 
1605
  {
 
1606
    delete *iter;
 
1607
    ++iter;
 
1608
  }
 
1609
  plugin_sysvar_vec.clear();
 
1610
}
559
1611
 
560
1612
/*
561
1613
  SYNOPSIS
562
1614
    test_plugin_options()
563
1615
    tmp_root                    temporary scratch space
564
1616
    plugin                      internal plugin structure
 
1617
    argc                        user supplied arguments
 
1618
    argv                        user supplied arguments
565
1619
    default_enabled             default plugin enable status
566
1620
  RETURNS:
567
1621
    0 SUCCESS - plugin should be enabled/loaded
568
1622
  NOTE:
569
1623
    Requires that a write-lock is held on LOCK_system_variables_hash
570
1624
*/
571
 
static int test_plugin_options(memory::Root *,
 
1625
static int test_plugin_options(memory::Root *module_root,
572
1626
                               module::Module *test_module,
 
1627
                               int *argc, char **argv,
573
1628
                               po::options_description &long_options)
574
1629
{
 
1630
  struct sys_var_chain chain= { NULL, NULL };
 
1631
  drizzle_sys_var **opt;
 
1632
  option *opts= NULL;
 
1633
  int error;
 
1634
  drizzle_sys_var *o;
 
1635
  Bookmark *var;
 
1636
  uint32_t len, count= EXTRA_OPTIONS;
575
1637
 
576
1638
  if (test_module->getManifest().init_options != NULL)
577
1639
  {
582
1644
                                   module_options.add_options());
583
1645
    test_module->getManifest().init_options(opt_ctx);
584
1646
    long_options.add(module_options);
585
 
  }
586
 
 
587
 
  return 0;
 
1647
 
 
1648
  }
 
1649
 
 
1650
  for (opt= test_module->getManifest().system_vars; opt && *opt; opt++)
 
1651
  {
 
1652
    count++;
 
1653
  }
 
1654
 
 
1655
  if (count > EXTRA_OPTIONS || (*argc > 1))
 
1656
  {
 
1657
    if (!(opts= (option*) module_root->alloc_root(sizeof(option) * count)))
 
1658
    {
 
1659
      errmsg_printf(ERRMSG_LVL_ERROR,
 
1660
                    _("Out of memory for plugin '%s'."),
 
1661
                    test_module->getName().c_str());
 
1662
      return(-1);
 
1663
    }
 
1664
    memset(opts, 0, sizeof(option) * count);
 
1665
 
 
1666
    if (construct_options(module_root, test_module, opts))
 
1667
    {
 
1668
      errmsg_printf(ERRMSG_LVL_ERROR,
 
1669
                    _("Bad options for plugin '%s'."),
 
1670
                    test_module->getName().c_str());
 
1671
      return(-1);
 
1672
    }
 
1673
 
 
1674
    if (test_module->getManifest().init_options == NULL)
 
1675
    {
 
1676
      error= handle_options(argc, &argv, opts, get_one_plugin_option);
 
1677
      (*argc)++; /* add back one for the program name */
 
1678
 
 
1679
      if (error)
 
1680
      {
 
1681
        errmsg_printf(ERRMSG_LVL_ERROR,
 
1682
                      _("Parsing options for plugin '%s' failed."),
 
1683
                      test_module->getName().c_str());
 
1684
        goto err;
 
1685
      }
 
1686
    }
 
1687
  }
 
1688
 
 
1689
  error= 1;
 
1690
 
 
1691
  {
 
1692
    for (opt= test_module->getManifest().system_vars; opt && *opt; opt++)
 
1693
    {
 
1694
      sys_var *v;
 
1695
      if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
 
1696
        continue;
 
1697
 
 
1698
      if ((var= find_bookmark(test_module->getName(), o->name, o->flags)))
 
1699
      {
 
1700
        v= new sys_var_pluginvar(var->key.c_str(), o);
 
1701
      }
 
1702
      else
 
1703
      {
 
1704
        len= test_module->getName().length() + strlen(o->name) + 2;
 
1705
        string vname(test_module->getName());
 
1706
        vname.push_back('-');
 
1707
        vname.append(o->name);
 
1708
        transform(vname.begin(), vname.end(), vname.begin(), ::tolower);
 
1709
        string::iterator p= vname.begin();      
 
1710
        while  (p != vname.end())
 
1711
        {
 
1712
          if (*p == '-')
 
1713
            *p= '_';
 
1714
          ++p;
 
1715
        }
 
1716
 
 
1717
        v= new sys_var_pluginvar(vname, o);
 
1718
      }
 
1719
      assert(v); /* check that an object was actually constructed */
 
1720
 
 
1721
      drizzle_add_plugin_sysvar(static_cast<sys_var_pluginvar *>(v));
 
1722
      /*
 
1723
        Add to the chain of variables.
 
1724
        Done like this for easier debugging so that the
 
1725
        pointer to v is not lost on optimized builds.
 
1726
      */
 
1727
      v->chain_sys_var(&chain);
 
1728
    }
 
1729
    if (chain.first)
 
1730
    {
 
1731
      chain.last->setNext(NULL);
 
1732
      if (mysql_add_sys_var_chain(chain.first, NULL))
 
1733
      {
 
1734
        errmsg_printf(ERRMSG_LVL_ERROR,
 
1735
                      _("Plugin '%s' has conflicting system variables"),
 
1736
                      test_module->getName().c_str());
 
1737
        goto err;
 
1738
      }
 
1739
      test_module->system_vars= chain.first;
 
1740
    }
 
1741
    return(0);
 
1742
  }
 
1743
 
 
1744
err:
 
1745
  if (opts)
 
1746
    my_cleanup_options(opts);
 
1747
  return(error);
588
1748
}
589
1749
 
590
1750
 
602
1762
};
603
1763
 
604
1764
 
605
 
void my_print_help_inc_plugins(option *main_options)
 
1765
void my_print_help_inc_plugins(option *main_options,
 
1766
                               po::options_description &long_options)
606
1767
{
607
1768
  module::Registry &registry= module::Registry::singleton();
608
1769
  vector<option> all_options;
609
1770
  memory::Root mem_root(4096);
 
1771
  option *opt= NULL;
610
1772
 
611
1773
 
612
1774
  if (initialized)
624
1786
      if (p->getManifest().init_options != NULL)
625
1787
        continue;
626
1788
 
 
1789
      if (p->getManifest().system_vars == NULL)
 
1790
        continue;
 
1791
 
 
1792
      opt= construct_help_options(&mem_root, p);
 
1793
      if (opt == NULL)
 
1794
        continue;
 
1795
 
 
1796
      /* Only options with a non-NULL comment are displayed in help text */
 
1797
      for (;opt->id; opt++)
 
1798
      {
 
1799
        if (opt->comment)
 
1800
        {
 
1801
          all_options.push_back(*opt);
 
1802
          
 
1803
        }
 
1804
      }
627
1805
    }
628
1806
  }
629
1807
 
644
1822
  /* main_options now points to the empty option terminator */
645
1823
  all_options.push_back(*main_options);
646
1824
 
647
 
  my_print_help(&*(all_options.begin()));
 
1825
  if (!opt_print_defaults)
 
1826
  {
 
1827
    my_print_help(&*(all_options.begin()));
 
1828
    cout << long_options << endl;
 
1829
  }
 
1830
  else
 
1831
  {
 
1832
    my_print_variables(&*(all_options.begin()));
 
1833
  }
648
1834
 
649
1835
  mem_root.free_root(MYF(0));
650
1836
}