~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/loader.cc

  • Committer: Stewart Smith
  • Date: 2010-03-18 12:01:34 UTC
  • mto: (1666.2.3 build)
  • mto: This revision was merged to the branch mainline in revision 1596.
  • Revision ID: stewart@flamingspork.com-20100318120134-45fdnsw8g3j6c7oy
move RAND() into a plugin

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
44
#include "drizzled/util/tokenize.h"
49
45
 
50
 
#include <boost/foreach.hpp>
51
 
 
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
60
namespace drizzled
75
61
{
76
62
 
77
63
 
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;
 
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;
84
73
 
85
74
/* Note that 'int version' must be the first field of every plugin
86
75
   sub-structure (plugin->info).
95
84
  write-lock on LOCK_system_variables_hash is required before modifying
96
85
  the following variables/structures
97
86
*/
98
 
static memory::Root plugin_mem_root(4096);
 
87
static memory::Root plugin_mem_root;
99
88
static uint32_t global_variables_dynamic_size= 0;
 
89
static HASH bookmark_hash;
100
90
 
101
91
 
102
92
/*
108
98
  Item *item;
109
99
};
110
100
 
111
 
class Bookmark
 
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
112
114
{
113
 
public:
114
 
  Bookmark() :
115
 
    type_code(0),
116
 
    offset(0),
117
 
    version(0),
118
 
    key("")
119
 
  {}
120
 
  uint8_t type_code;
 
115
  uint32_t name_len;
121
116
  int offset;
122
117
  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
 
 
 
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
};
129
150
 
130
151
 
131
152
/* prototypes */
132
153
static void plugin_prune_list(vector<string> &plugin_list,
133
154
                              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);
 
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);
143
163
 
144
164
/* declared in set_var.cc */
145
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
}
146
228
 
147
229
 
148
230
/****************************************************************************
156
238
  NOTE
157
239
    Requires that a write-lock is held on LOCK_system_variables_hash
158
240
*/
159
 
static bool plugin_add(module::Registry &registry, memory::Root *tmp_root,
160
 
                       module::Library *library,
161
 
                       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)
162
244
{
163
245
  if (! initialized)
164
246
    return true;
170
252
    return false;
171
253
  }
172
254
 
173
 
  module::Module *tmp= NULL;
 
255
  plugin::Module *tmp= NULL;
174
256
  /* Find plugin by name */
175
 
  const module::Manifest *manifest= library->getManifest();
 
257
  const plugin::Manifest *manifest= library->getManifest();
176
258
 
177
259
  if (registry.find(manifest->name))
178
260
  {
184
266
    return true;
185
267
  }
186
268
 
187
 
  tmp= new (std::nothrow) module::Module(manifest, library);
 
269
  tmp= new (std::nothrow) plugin::Module(manifest, library);
188
270
  if (tmp == NULL)
189
271
    return true;
190
272
 
191
 
  if (!test_plugin_options(tmp_root, tmp, long_options))
 
273
  if (!test_plugin_options(tmp_root, tmp, argc, argv))
192
274
  {
193
275
    registry.add(tmp);
194
276
    return false;
199
281
}
200
282
 
201
283
 
202
 
static void reap_plugins(module::Registry &registry)
203
 
{
204
 
  std::map<std::string, module::Module *>::const_iterator modules=
 
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=
205
309
    registry.getModulesMap().begin();
206
 
 
 
310
    
207
311
  while (modules != registry.getModulesMap().end())
208
312
  {
209
 
    module::Module *module= (*modules).second;
210
 
    delete module;
 
313
    module= (*modules).second;
 
314
    delete_module(registry, module);
211
315
    ++modules;
212
316
  }
213
 
}
214
 
 
215
 
 
216
 
static bool plugin_initialize(module::Registry &registry,
217
 
                              module::Module *module)
 
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)
218
343
{
219
344
  assert(module->isInited == false);
220
345
 
221
 
  module::Context loading_context(registry, module);
 
346
  registry.setCurrentModule(module);
222
347
  if (module->getManifest().init)
223
348
  {
224
 
    if (module->getManifest().init(loading_context))
 
349
    if (module->getManifest().init(registry))
225
350
    {
226
351
      errmsg_printf(ERRMSG_LVL_ERROR,
227
352
                    _("Plugin '%s' init function returned error.\n"),
229
354
      return true;
230
355
    }
231
356
  }
 
357
  registry.clearCurrentModule();
232
358
  module->isInited= true;
233
359
 
234
360
 
236
362
}
237
363
 
238
364
 
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
 
}
 
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
 
289
373
 
290
374
/*
291
375
  The logic is that we first load and initialize all compiled in plugins.
294
378
 
295
379
  Finally we initialize everything, aka the dynamic that have yet to initialize.
296
380
*/
297
 
bool plugin_init(module::Registry &registry,
298
 
                 po::options_description &long_options)
 
381
bool plugin_init(plugin::Registry &registry,
 
382
                 int *argc, char **argv,
 
383
                 bool skip_init)
299
384
{
300
 
  memory::Root tmp_root(4096);
 
385
  plugin::Manifest **builtins;
 
386
  plugin::Manifest *manifest;
 
387
  plugin::Module *module;
 
388
  memory::Root tmp_root;
301
389
 
302
390
  if (initialized)
303
391
    return false;
304
392
 
 
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
 
305
404
  initialized= 1;
306
405
 
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);
 
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
 
312
437
 
313
438
  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());
 
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
  }
356
459
  
357
460
  /* Register all dynamic plugins */
358
 
  load_failed= plugin_load_list(registry, &tmp_root,
359
 
                                plugin_list_set, long_options);
 
461
  load_failed= plugin_load_list(registry, &tmp_root, argc, argv,
 
462
                                plugin_list);
360
463
  if (load_failed)
361
464
  {
362
 
    tmp_root.free_root(MYF(0));
 
465
    free_root(&tmp_root, MYF(0));
363
466
    return true;
364
467
  }
365
468
 
366
 
  tmp_root.free_root(MYF(0));
367
 
 
368
 
  return false;
369
 
}
370
 
 
371
 
bool plugin_finalize(module::Registry &registry)
372
 
{
 
469
  if (skip_init)
 
470
  {
 
471
    free_root(&tmp_root, MYF(0));
 
472
    return false;
 
473
  }
 
474
 
373
475
  /*
374
476
    Now we initialize all remaining plugins
375
477
  */
376
 
  std::map<std::string, module::Module *>::const_iterator modules=
 
478
  std::map<std::string, plugin::Module *>::const_iterator modules=
377
479
    registry.getModulesMap().begin();
378
480
    
379
481
  while (modules != registry.getModulesMap().end())
380
482
  {
381
 
    module::Module *module= (*modules).second;
 
483
    module= (*modules).second;
382
484
    ++modules;
383
485
    if (module->isInited == false)
384
486
    {
 
487
      plugin_initialize_vars(module);
 
488
 
385
489
      if (plugin_initialize(registry, module))
386
 
      {
387
 
        registry.remove(module);
388
 
        delete module;
389
 
        return true;
390
 
      }
 
490
        delete_module(registry, module);
391
491
    }
392
492
  }
393
493
 
394
 
  BOOST_FOREACH(plugin::Plugin::map::value_type value, registry.getPluginsMap())
395
 
  {
396
 
    value.second->prime();
397
 
  }
 
494
 
 
495
  free_root(&tmp_root, MYF(0));
398
496
 
399
497
  return false;
400
498
}
433
531
/*
434
532
  called only by plugin_init()
435
533
*/
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)
 
534
static bool plugin_load_list(plugin::Registry &registry,
 
535
                             memory::Root *tmp_root, int *argc, char **argv,
 
536
                             const vector<string> &plugin_list)
441
537
{
442
 
  module::Library *library= NULL;
 
538
  plugin::Library *library= NULL;
443
539
 
444
 
  for (set<string>::const_iterator iter= plugin_list.begin();
 
540
  for (vector<string>::const_iterator iter= plugin_list.begin();
445
541
       iter != plugin_list.end();
446
542
       ++iter)
447
543
  {
448
544
    const string plugin_name(*iter);
449
 
 
450
 
    library= registry.addLibrary(plugin_name, builtin);
 
545
    library= registry.addLibrary(plugin_name);
451
546
    if (library == NULL)
452
547
    {
453
548
      errmsg_printf(ERRMSG_LVL_ERROR,
456
551
      return true;
457
552
    }
458
553
 
459
 
    tmp_root->free_root(MYF(memory::MARK_BLOCKS_FREE));
460
 
    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))
461
556
    {
462
557
      registry.removeLibrary(plugin_name);
463
558
      errmsg_printf(ERRMSG_LVL_ERROR,
471
566
}
472
567
 
473
568
 
474
 
void module_shutdown(module::Registry &registry)
 
569
void plugin_shutdown(plugin::Registry &registry)
475
570
{
476
571
 
477
572
  if (initialized)
482
577
    unlock_variables(NULL, &global_system_variables);
483
578
    unlock_variables(NULL, &max_system_variables);
484
579
 
485
 
    cleanup_variables(&global_system_variables);
486
 
    cleanup_variables(&max_system_variables);
 
580
    cleanup_variables(NULL, &global_system_variables);
 
581
    cleanup_variables(NULL, &max_system_variables);
487
582
 
488
583
    initialized= 0;
489
584
  }
490
585
 
491
586
  /* Dispose of the memory */
492
 
  plugin_mem_root.free_root(MYF(0));
 
587
 
 
588
  hash_free(&bookmark_hash);
 
589
  free_root(&plugin_mem_root, MYF(0));
493
590
 
494
591
  global_variables_dynamic_size= 0;
495
592
}
496
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
 
497
793
 
498
794
/****************************************************************************
499
795
  System Variables support
500
796
****************************************************************************/
501
797
 
502
798
 
503
 
sys_var *find_sys_var(const char *str, uint32_t length)
504
 
{
505
 
  return intern_find_sys_var(str, length, false);
506
 
}
507
 
 
 
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
}
508
1085
 
509
1086
void plugin_sessionvar_init(Session *session)
510
1087
{
511
1088
  session->variables.storage_engine= NULL;
512
 
  cleanup_variables(&session->variables);
 
1089
  cleanup_variables(session, &session->variables);
513
1090
 
514
1091
  session->variables= global_system_variables;
515
1092
  session->variables.storage_engine= NULL;
526
1103
/*
527
1104
  Unlocks all system variables which hold a reference
528
1105
*/
529
 
static void unlock_variables(Session *, struct drizzle_system_variables *vars)
 
1106
static void unlock_variables(Session *, struct system_variables *vars)
530
1107
{
531
1108
  vars->storage_engine= NULL;
532
1109
}
538
1115
  Unlike plugin_vars_free_values() it frees all variables of all plugins,
539
1116
  it's used on shutdown.
540
1117
*/
541
 
static void cleanup_variables(drizzle_system_variables *vars)
 
1118
static void cleanup_variables(Session *session, struct system_variables *vars)
542
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
 
543
1148
  assert(vars->storage_engine == NULL);
544
1149
 
545
1150
  free(vars->dynamic_variables_ptr);
552
1157
void plugin_sessionvar_cleanup(Session *session)
553
1158
{
554
1159
  unlock_variables(session, &session->variables);
555
 
  cleanup_variables(&session->variables);
556
 
}
557
 
 
558
 
 
 
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
}
559
1665
 
560
1666
/*
561
1667
  SYNOPSIS
562
1668
    test_plugin_options()
563
1669
    tmp_root                    temporary scratch space
564
1670
    plugin                      internal plugin structure
 
1671
    argc                        user supplied arguments
 
1672
    argv                        user supplied arguments
565
1673
    default_enabled             default plugin enable status
566
1674
  RETURNS:
567
1675
    0 SUCCESS - plugin should be enabled/loaded
568
1676
  NOTE:
569
1677
    Requires that a write-lock is held on LOCK_system_variables_hash
570
1678
*/
571
 
static int test_plugin_options(memory::Root *,
572
 
                               module::Module *test_module,
573
 
                               po::options_description &long_options)
 
1679
static int test_plugin_options(memory::Root *tmp_root, plugin::Module *tmp,
 
1680
                               int *argc, char **argv)
574
1681
{
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;
 
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);
588
1776
}
589
1777
 
590
1778
 
595
1783
class OptionCmp
596
1784
{
597
1785
public:
598
 
  bool operator() (const option &a, const option &b)
 
1786
  bool operator() (const my_option &a, const my_option &b)
599
1787
  {
600
1788
    return my_strcasecmp(&my_charset_utf8_general_ci, a.name, b.name);
601
1789
  }
602
1790
};
603
1791
 
604
1792
 
605
 
void my_print_help_inc_plugins(option *main_options)
 
1793
void my_print_help_inc_plugins(my_option *main_options)
606
1794
{
607
 
  module::Registry &registry= module::Registry::singleton();
608
 
  vector<option> all_options;
609
 
  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;
610
1800
 
 
1801
  init_alloc_root(&mem_root, 4096);
611
1802
 
612
1803
  if (initialized)
613
1804
  {
614
 
    std::map<std::string, module::Module *>::const_iterator modules=
 
1805
    std::map<std::string, plugin::Module *>::const_iterator modules=
615
1806
      registry.getModulesMap().begin();
616
1807
    
617
1808
    while (modules != registry.getModulesMap().end())
618
1809
    {
619
 
      module::Module *p= (*modules).second;
 
1810
      p= (*modules).second;
620
1811
      ++modules;
621
1812
 
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
 
 
 
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
      }
627
1829
    }
628
1830
  }
629
1831
 
636
1838
  }
637
1839
 
638
1840
  /** 
639
 
   * @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
640
1842
   *
641
1843
   * sort(all_options.begin(), all_options.end(), OptionCmp());
642
1844
   */
645
1847
  all_options.push_back(*main_options);
646
1848
 
647
1849
  my_print_help(&*(all_options.begin()));
648
 
 
649
 
  mem_root.free_root(MYF(0));
 
1850
  my_print_variables(&*(all_options.begin()));
 
1851
 
 
1852
  free_root(&mem_root, MYF(0));
 
1853
 
650
1854
}
651
1855
 
652
1856
} /* namespace drizzled */
653
 
 
654