~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/loader.cc

  • Committer: Stewart Smith
  • Date: 2010-02-22 07:44:37 UTC
  • mfrom: (1283.17.4)
  • mto: (1283.19.1)
  • mto: This revision was merged to the branch mainline in revision 1449.
  • Revision ID: stewart@flamingspork.com-20100222074437-1a9x1n030tbtv1qv
Merged embeddded-innodb-store-table-proto into embedded-innodb-write-row.

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