~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/loader.cc

  • Committer: Padraig O'Sullivan
  • Date: 2010-02-10 16:26:01 UTC
  • mto: This revision was merged to the branch mainline in revision 1294.
  • Revision ID: osullivan.padraig@gmail.com-20100210162601-itx2ndl397pc1wr6
Corrected an order of initialization in a few optimizer classes

Show diffs side-by-side

added added

removed removed

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