~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/module/loader.cc

  • Committer: Padraig O'Sullivan
  • Date: 2010-12-03 19:16:09 UTC
  • mto: (1975.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 1976.
  • Revision ID: osullivan.padraig@gmail.com-20101203191609-7s81iwt33vrgmz9v
Some re-factoring based on feedback from Monty on IRC.

Show diffs side-by-side

added added

removed removed

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