~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/module/loader.cc

  • Committer: Brian Aker
  • Date: 2010-06-02 17:48:07 UTC
  • mto: (1578.6.10 explain-drizzle)
  • mto: This revision was merged to the branch mainline in revision 1589.
  • Revision ID: brian@gir-2.local-20100602174807-9unmrwp18ewkwol5
Modify merge-buffer to use std::vector in one location (just curious to see
if this shows up on benchmarks).

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