~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/module/loader.cc

  • Committer: Andrew Hutchings
  • Date: 2010-09-26 08:33:47 UTC
  • mto: (1795.1.1 build)
  • mto: This revision was merged to the branch mainline in revision 1796.
  • Revision ID: andrew@linuxjedi.co.uk-20100926083347-fzsc9e7w0j4u7bj1
Disable boost:po allow_guessing which was making some wrong assumptions

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