~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/module/loader.cc

add test for bug600088: multibyte comments not shown correctly in SHOW CREATE TABLE 

Show diffs side-by-side

added added

removed removed

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