~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/loader.cc

Added the testsuite location finding code to support in-plugin-dir test suites.

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 "drizzled/server_includes.h"
17
17
 
18
18
#include <dlfcn.h>
19
19
 
20
 
#include <cstdio>
21
20
#include <string>
22
21
#include <vector>
23
22
#include <map>
24
23
#include <algorithm>
25
 
#include <iostream>
26
 
 
27
 
#include <boost/program_options.hpp>
28
 
 
29
 
#include "drizzled/option.h"
30
 
#include "drizzled/internal/m_string.h"
31
 
 
32
 
#include "drizzled/plugin.h"
33
 
#include "drizzled/module/load_list.h"
34
 
#include "drizzled/module/library.h"
35
 
#include "drizzled/module/registry.h"
36
 
#include "drizzled/module/option_context.h"
 
24
 
 
25
#include "mysys/my_getopt.h"
 
26
#include "mysys/hash.h"
 
27
 
 
28
#include "drizzled/plugin/config.h"
37
29
#include "drizzled/sql_parse.h"
38
30
#include "drizzled/show.h"
39
31
#include "drizzled/cursor.h"
40
32
#include "drizzled/set_var.h"
41
33
#include "drizzled/session.h"
42
34
#include "drizzled/item/null.h"
 
35
#include "drizzled/plugin/registry.h"
43
36
#include "drizzled/error.h"
44
37
#include "drizzled/gettext.h"
45
38
#include "drizzled/errmsg_print.h"
46
 
#include "drizzled/strfunc.h"
47
 
#include "drizzled/pthread_globals.h"
48
 
#include "drizzled/util/tokenize.h"
49
39
 
50
 
#include <boost/foreach.hpp>
51
40
 
52
41
/* FreeBSD 2.2.2 does not define RTLD_NOW) */
53
42
#ifndef RTLD_NOW
54
43
#define RTLD_NOW 1
55
44
#endif
56
45
 
57
 
namespace po=boost::program_options;
58
 
 
59
46
using namespace std;
60
 
 
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
72
 
};
73
 
 
74
 
namespace drizzled
75
 
{
 
47
using namespace drizzled;
76
48
 
77
 
 
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;
 
49
typedef plugin::Manifest builtin_plugin[];
 
50
extern builtin_plugin PANDORA_BUILTIN_LIST;
 
51
static plugin::Manifest *drizzled_builtins[]=
 
52
{
 
53
  PANDORA_BUILTIN_LIST, NULL
 
54
};
 
55
 
 
56
class sys_var_pluginvar;
 
57
static vector<sys_var_pluginvar *> plugin_sysvar_vec;
 
58
 
 
59
char *opt_plugin_add= NULL;
 
60
char *opt_plugin_load= NULL;
 
61
const char *opt_plugin_load_default= PANDORA_PLUGIN_LIST;
 
62
char *opt_plugin_dir_ptr;
 
63
char opt_plugin_dir[FN_REFLEN];
 
64
static const char *plugin_declarations_sym= "_drizzled_plugin_declaration_";
84
65
 
85
66
/* Note that 'int version' must be the first field of every plugin
86
67
   sub-structure (plugin->info).
88
69
 
89
70
static bool initialized= false;
90
71
 
 
72
static DYNAMIC_ARRAY plugin_dl_array;
 
73
static DYNAMIC_ARRAY module_array;
91
74
 
92
75
static bool reap_needed= false;
93
76
 
95
78
  write-lock on LOCK_system_variables_hash is required before modifying
96
79
  the following variables/structures
97
80
*/
98
 
static memory::Root plugin_mem_root(4096);
 
81
static MEM_ROOT plugin_mem_root;
99
82
static uint32_t global_variables_dynamic_size= 0;
 
83
static HASH bookmark_hash;
100
84
 
101
85
 
102
86
/*
103
87
  hidden part of opaque value passed to variable check functions.
104
88
  Used to provide a object-like structure to non C++ consumers.
105
89
*/
106
 
struct st_item_value_holder : public drizzle_value
 
90
struct st_item_value_holder : public st_mysql_value
107
91
{
108
92
  Item *item;
109
93
};
110
94
 
111
 
class Bookmark
 
95
 
 
96
/*
 
97
  stored in bookmark_hash, this structure is never removed from the
 
98
  hash and is used to mark a single offset for a session local variable
 
99
  even if plugins have been uninstalled and reinstalled, repeatedly.
 
100
  This structure is allocated from plugin_mem_root.
 
101
 
 
102
  The key format is as follows:
 
103
    1 byte         - variable type code
 
104
    name_len bytes - variable name
 
105
    '\0'           - end of key
 
106
*/
 
107
struct st_bookmark
112
108
{
113
 
public:
114
 
  Bookmark() :
115
 
    type_code(0),
116
 
    offset(0),
117
 
    version(0),
118
 
    key("")
119
 
  {}
120
 
  uint8_t type_code;
 
109
  uint32_t name_len;
121
110
  int offset;
122
111
  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
 
 
 
112
  char key[1];
 
113
};
 
114
 
 
115
 
 
116
/*
 
117
  skeleton of a plugin variable - portion of structure common to all.
 
118
*/
 
119
struct st_mysql_sys_var
 
120
{
 
121
  DRIZZLE_PLUGIN_VAR_HEADER;
 
122
};
 
123
 
 
124
 
 
125
/*
 
126
  sys_var class for access to all plugin variables visible to the user
 
127
*/
 
128
class sys_var_pluginvar: public sys_var
 
129
{
 
130
public:
 
131
  plugin::Module *plugin;
 
132
  struct st_mysql_sys_var *plugin_var;
 
133
 
 
134
  sys_var_pluginvar(const std::string name_arg,
 
135
                    struct st_mysql_sys_var *plugin_var_arg)
 
136
    :sys_var(name_arg), plugin_var(plugin_var_arg) {}
 
137
  sys_var_pluginvar *cast_pluginvar() { return this; }
 
138
  bool is_readonly() const { return plugin_var->flags & PLUGIN_VAR_READONLY; }
 
139
  bool check_type(enum_var_type type)
 
140
  { return !(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) && type != OPT_GLOBAL; }
 
141
  bool check_update_type(Item_result type);
 
142
  SHOW_TYPE show_type();
 
143
  unsigned char* real_value_ptr(Session *session, enum_var_type type);
 
144
  TYPELIB* plugin_var_typelib(void);
 
145
  unsigned char* value_ptr(Session *session, enum_var_type type,
 
146
                           const LEX_STRING *base);
 
147
  bool check(Session *session, set_var *var);
 
148
  bool check_default(enum_var_type)
 
149
    { return is_readonly(); }
 
150
  void set_default(Session *session, enum_var_type);
 
151
  bool update(Session *session, set_var *var);
 
152
};
129
153
 
130
154
 
131
155
/* prototypes */
132
 
static void plugin_prune_list(vector<string> &plugin_list,
133
 
                              const vector<string> &plugins_to_remove);
134
 
static bool plugin_load_list(module::Registry &registry,
135
 
                             memory::Root *tmp_root,
136
 
                             const set<string> &plugin_list,
137
 
                             po::options_description &long_options,
138
 
                             bool builtin= false);
139
 
static int test_plugin_options(memory::Root *, module::Module *,
140
 
                               po::options_description &long_options);
141
 
static void unlock_variables(Session *session, drizzle_system_variables *vars);
142
 
static void cleanup_variables(drizzle_system_variables *vars);
 
156
static bool plugin_load_list(plugin::Registry &registry,
 
157
                             MEM_ROOT *tmp_root, int *argc, char **argv,
 
158
                             const char *list);
 
159
static int test_plugin_options(MEM_ROOT *, plugin::Module *,
 
160
                               int *, char **);
 
161
static bool register_builtin(plugin::Registry &registry,
 
162
                             plugin::Module *,
 
163
                             plugin::Module **);
 
164
static void unlock_variables(Session *session, struct system_variables *vars);
 
165
static void cleanup_variables(Session *session, struct system_variables *vars);
 
166
static void plugin_vars_free_values(sys_var *vars);
 
167
static void plugin_opt_set_limits(struct my_option *options,
 
168
                                  const struct st_mysql_sys_var *opt);
 
169
static void reap_plugins(plugin::Registry &plugins);
 
170
 
143
171
 
144
172
/* declared in set_var.cc */
145
173
extern sys_var *intern_find_sys_var(const char *str, uint32_t length, bool no_error);
 
174
extern bool throw_bounds_warning(Session *session, bool fixed, bool unsignd,
 
175
                                 const std::string &name, int64_t val);
 
176
 
 
177
static bool throw_bounds_warning(Session *session, bool fixed, bool unsignd,
 
178
                                 const char *name, int64_t val)
 
179
{
 
180
  const std::string name_str(name);
 
181
  return throw_bounds_warning(session, fixed, unsignd, name_str, val);
 
182
}
 
183
 
 
184
/****************************************************************************
 
185
  Value type thunks, allows the C world to play in the C++ world
 
186
****************************************************************************/
 
187
 
 
188
static int item_value_type(struct st_mysql_value *value)
 
189
{
 
190
  switch (((st_item_value_holder*)value)->item->result_type()) {
 
191
  case INT_RESULT:
 
192
    return DRIZZLE_VALUE_TYPE_INT;
 
193
  case REAL_RESULT:
 
194
    return DRIZZLE_VALUE_TYPE_REAL;
 
195
  default:
 
196
    return DRIZZLE_VALUE_TYPE_STRING;
 
197
  }
 
198
}
 
199
 
 
200
static const char *item_val_str(struct st_mysql_value *value,
 
201
                                char *buffer, int *length)
 
202
{
 
203
  String str(buffer, *length, system_charset_info), *res;
 
204
  if (!(res= ((st_item_value_holder*)value)->item->val_str(&str)))
 
205
    return NULL;
 
206
  *length= res->length();
 
207
  if (res->c_ptr_quick() == buffer)
 
208
    return buffer;
 
209
 
 
210
  /*
 
211
    Lets be nice and create a temporary string since the
 
212
    buffer was too small
 
213
  */
 
214
  return current_session->strmake(res->c_ptr_quick(), res->length());
 
215
}
 
216
 
 
217
 
 
218
static int item_val_int(struct st_mysql_value *value, int64_t *buf)
 
219
{
 
220
  Item *item= ((st_item_value_holder*)value)->item;
 
221
  *buf= item->val_int();
 
222
  if (item->is_null())
 
223
    return 1;
 
224
  return 0;
 
225
}
 
226
 
 
227
 
 
228
static int item_val_real(struct st_mysql_value *value, double *buf)
 
229
{
 
230
  Item *item= ((st_item_value_holder*)value)->item;
 
231
  *buf= item->val_real();
 
232
  if (item->is_null())
 
233
    return 1;
 
234
  return 0;
 
235
}
146
236
 
147
237
 
148
238
/****************************************************************************
149
239
  Plugin support code
150
240
****************************************************************************/
151
241
 
152
 
 
 
242
static plugin::Library *plugin_dl_find(const LEX_STRING *dl)
 
243
{
 
244
  uint32_t i;
 
245
  plugin::Library *tmp;
 
246
 
 
247
  for (i= 0; i < plugin_dl_array.elements; i++)
 
248
  {
 
249
    tmp= *dynamic_element(&plugin_dl_array, i, plugin::Library **);
 
250
    if (! my_strnncoll(files_charset_info,
 
251
                       (const unsigned char *)dl->str, dl->length,
 
252
                       (const unsigned char *)tmp->dl.str, tmp->dl.length))
 
253
      return(tmp);
 
254
  }
 
255
  return(0);
 
256
}
 
257
 
 
258
static plugin::Library *plugin_dl_insert_or_reuse(plugin::Library *plugin_dl)
 
259
{
 
260
  uint32_t i;
 
261
  plugin::Library *tmp;
 
262
 
 
263
  for (i= 0; i < plugin_dl_array.elements; i++)
 
264
  {
 
265
    tmp= *dynamic_element(&plugin_dl_array, i, plugin::Library **);
 
266
    {
 
267
      memcpy(tmp, plugin_dl, sizeof(plugin::Library));
 
268
      return(tmp);
 
269
    }
 
270
  }
 
271
  if (insert_dynamic(&plugin_dl_array, (unsigned char*)&plugin_dl))
 
272
    return(0);
 
273
  tmp= *dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
 
274
                        plugin::Library **)=
 
275
      (plugin::Library *) memdup_root(&plugin_mem_root,
 
276
                                      (unsigned char*)plugin_dl,
 
277
                                      sizeof(plugin::Library));
 
278
  return(tmp);
 
279
}
 
280
 
 
281
static inline void free_plugin_mem(plugin::Library *p)
 
282
{
 
283
  if (p->handle)
 
284
    dlclose(p->handle);
 
285
  free(p->dl.str);
 
286
}
 
287
 
 
288
 
 
289
static plugin::Library *plugin_dl_add(const LEX_STRING *dl)
 
290
{
 
291
  string dlpath;
 
292
  uint32_t plugin_dir_len;
 
293
  plugin::Library *tmp, plugin_dl;
 
294
  void *sym;
 
295
  plugin_dir_len= strlen(opt_plugin_dir);
 
296
  dlpath.reserve(FN_REFLEN);
 
297
  /*
 
298
    Ensure that the dll doesn't have a path.
 
299
    This is done to ensure that only approved libraries from the
 
300
    plugin directory are used (to make this even remotely secure).
 
301
  */
 
302
  if (strchr(dl->str, FN_LIBCHAR) ||
 
303
      check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN,
 
304
                               system_charset_info, 1) ||
 
305
      plugin_dir_len + dl->length + 1 >= FN_REFLEN)
 
306
  {
 
307
    errmsg_printf(ERRMSG_LVL_ERROR, "%s",ER(ER_UDF_NO_PATHS));
 
308
    return NULL;
 
309
  }
 
310
  /* If this dll is already loaded just increase ref_count. */
 
311
  if ((tmp= plugin_dl_find(dl)))
 
312
  {
 
313
    return(tmp);
 
314
  }
 
315
  memset(&plugin_dl, 0, sizeof(plugin_dl));
 
316
  /* Compile dll path */
 
317
  dlpath.append(opt_plugin_dir);
 
318
  dlpath.append("/");
 
319
  dlpath.append("lib");
 
320
  dlpath.append(dl->str);
 
321
  dlpath.append("_plugin.so");
 
322
  /* Open new dll handle */
 
323
  if (!(plugin_dl.handle= dlopen(dlpath.c_str(), RTLD_NOW|RTLD_GLOBAL)))
 
324
  {
 
325
    const char *errmsg=dlerror();
 
326
    uint32_t dlpathlen= dlpath.length();
 
327
    if (!dlpath.compare(0, dlpathlen, errmsg))
 
328
    { // if errmsg starts from dlpath, trim this prefix.
 
329
      errmsg+=dlpathlen;
 
330
      if (*errmsg == ':') errmsg++;
 
331
      if (*errmsg == ' ') errmsg++;
 
332
    }
 
333
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_CANT_OPEN_LIBRARY), dlpath.c_str(), errno, errmsg);
 
334
    return NULL;
 
335
  }
 
336
 
 
337
  /* Find plugin declarations */
 
338
  if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))
 
339
  {
 
340
    free_plugin_mem(&plugin_dl);
 
341
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_CANT_FIND_DL_ENTRY), plugin_declarations_sym);
 
342
    return NULL;
 
343
  }
 
344
 
 
345
  plugin_dl.plugins= static_cast<plugin::Manifest *>(sym);
 
346
 
 
347
  /* Duplicate and convert dll name */
 
348
  plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
 
349
  if (! (plugin_dl.dl.str= (char*) calloc(plugin_dl.dl.length, sizeof(char))))
 
350
  {
 
351
    free_plugin_mem(&plugin_dl);
 
352
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
 
353
    return NULL;
 
354
  }
 
355
  strcpy(plugin_dl.dl.str, dl->str);
 
356
  /* Add this dll to array */
 
357
  if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl)))
 
358
  {
 
359
    free_plugin_mem(&plugin_dl);
 
360
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY),
 
361
                  sizeof(plugin::Library));
 
362
    return NULL;
 
363
  }
 
364
  return(tmp);
 
365
}
 
366
 
 
367
 
 
368
static void plugin_dl_del(const LEX_STRING *dl)
 
369
{
 
370
  uint32_t i;
 
371
 
 
372
  for (i= 0; i < plugin_dl_array.elements; i++)
 
373
  {
 
374
    plugin::Library *tmp= *dynamic_element(&plugin_dl_array, i,
 
375
                                           plugin::Library **);
 
376
    if (! my_strnncoll(files_charset_info,
 
377
                       (const unsigned char *)dl->str, dl->length,
 
378
                       (const unsigned char *)tmp->dl.str, tmp->dl.length))
 
379
    {
 
380
      /* Do not remove this element, unless no other plugin uses this dll. */
 
381
      {
 
382
        free_plugin_mem(tmp);
 
383
        memset(tmp, 0, sizeof(plugin::Library));
 
384
      }
 
385
      break;
 
386
    }
 
387
  }
 
388
  return;
 
389
}
 
390
 
 
391
 
 
392
 
 
393
static plugin::Module *plugin_insert_or_reuse(plugin::Module *module)
 
394
{
 
395
  if (insert_dynamic(&module_array, (unsigned char*)&module))
 
396
    return NULL;
 
397
  module= *dynamic_element(&module_array, module_array.elements - 1,
 
398
                           plugin::Module **);
 
399
  return module;
 
400
}
153
401
 
154
402
 
155
403
/*
156
404
  NOTE
157
405
    Requires that a write-lock is held on LOCK_system_variables_hash
158
406
*/
159
 
static bool plugin_add(module::Registry &registry, memory::Root *tmp_root,
160
 
                       module::Library *library,
161
 
                       po::options_description &long_options)
 
407
static bool plugin_add(plugin::Registry &registry, MEM_ROOT *tmp_root,
 
408
                       const LEX_STRING *name, const LEX_STRING *dl,
 
409
                       int *argc, char **argv)
162
410
{
 
411
  plugin::Manifest *manifest;
163
412
  if (! initialized)
164
 
    return true;
 
413
    return(0);
165
414
 
166
 
  if (registry.find(library->getName()))
 
415
  if (registry.find(name))
167
416
  {
168
 
    errmsg_printf(ERRMSG_LVL_WARN, ER(ER_PLUGIN_EXISTS),
169
 
                  library->getName().c_str());
170
 
    return false;
 
417
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_UDF_EXISTS), name->str);
 
418
    return(true);
171
419
  }
 
420
  plugin::Library *library= plugin_dl_add(dl);
 
421
  if (library == NULL)
 
422
    return true;
172
423
 
173
 
  module::Module *tmp= NULL;
 
424
  plugin::Module *tmp= NULL;
174
425
  /* Find plugin by name */
175
 
  const module::Manifest *manifest= library->getManifest();
176
 
 
177
 
  if (registry.find(manifest->name))
178
 
  {
179
 
    errmsg_printf(ERRMSG_LVL_ERROR, 
180
 
                  _("Plugin '%s' contains the name '%s' in its manifest, which "
181
 
                    "has already been registered.\n"),
182
 
                  library->getName().c_str(),
183
 
                  manifest->name);
184
 
    return true;
185
 
  }
186
 
 
187
 
  tmp= new (std::nothrow) module::Module(manifest, library);
188
 
  if (tmp == NULL)
189
 
    return true;
190
 
 
191
 
  if (!test_plugin_options(tmp_root, tmp, long_options))
192
 
  {
193
 
    registry.add(tmp);
194
 
    return false;
195
 
  }
196
 
  errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_CANT_FIND_DL_ENTRY),
197
 
                library->getName().c_str());
198
 
  return true;
199
 
}
200
 
 
201
 
 
202
 
static void reap_plugins(module::Registry &registry)
203
 
{
204
 
  std::map<std::string, module::Module *>::const_iterator modules=
205
 
    registry.getModulesMap().begin();
206
 
 
207
 
  while (modules != registry.getModulesMap().end())
208
 
  {
209
 
    module::Module *module= (*modules).second;
210
 
    delete module;
211
 
    ++modules;
212
 
  }
213
 
}
214
 
 
215
 
 
216
 
static bool plugin_initialize(module::Registry &registry,
217
 
                              module::Module *module)
 
426
  for (manifest= library->plugins; manifest->name; manifest++)
 
427
  {
 
428
    if (! my_strnncoll(system_charset_info,
 
429
                       (const unsigned char *)name->str, name->length,
 
430
                       (const unsigned char *)manifest->name,
 
431
                       strlen(manifest->name)))
 
432
    {
 
433
      tmp= new (std::nothrow) plugin::Module(manifest, library);
 
434
      if (tmp == NULL)
 
435
        return true;
 
436
 
 
437
      if (!test_plugin_options(tmp_root, tmp, argc, argv))
 
438
      {
 
439
        if ((tmp= plugin_insert_or_reuse(tmp)))
 
440
        {
 
441
          registry.add(tmp);
 
442
          init_alloc_root(&tmp->mem_root, 4096, 4096);
 
443
          return(false);
 
444
        }
 
445
        mysql_del_sys_var_chain(tmp->system_vars);
 
446
        goto err;
 
447
      }
 
448
      /* plugin was disabled */
 
449
      plugin_dl_del(dl);
 
450
      return(false);
 
451
    }
 
452
  }
 
453
  errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_CANT_FIND_DL_ENTRY), name->str);
 
454
err:
 
455
  plugin_dl_del(dl);
 
456
  return(true);
 
457
}
 
458
 
 
459
 
 
460
static void delete_module(plugin::Registry &registry, plugin::Module *module)
 
461
{
 
462
  plugin::Manifest manifest= module->getManifest();
 
463
 
 
464
  if (module->isInited)
 
465
  {
 
466
    if (manifest.status_vars)
 
467
    {
 
468
      remove_status_vars(manifest.status_vars);
 
469
    }
 
470
 
 
471
    if (manifest.deinit)
 
472
      manifest.deinit(registry);
 
473
  }
 
474
 
 
475
  /* Free allocated strings before deleting the plugin. */
 
476
  plugin_vars_free_values(module->system_vars);
 
477
  if (module->plugin_dl)
 
478
    plugin_dl_del(&module->plugin_dl->dl);
 
479
  module->isInited= false;
 
480
  pthread_rwlock_wrlock(&LOCK_system_variables_hash);
 
481
  mysql_del_sys_var_chain(module->system_vars);
 
482
  pthread_rwlock_unlock(&LOCK_system_variables_hash);
 
483
  delete module;
 
484
}
 
485
 
 
486
static void reap_plugins(plugin::Registry &plugins)
 
487
{
 
488
  size_t count;
 
489
  uint32_t idx;
 
490
  plugin::Module *module;
 
491
 
 
492
  count= module_array.elements;
 
493
 
 
494
  for (idx= 0; idx < count; idx++)
 
495
  {
 
496
    module= *dynamic_element(&module_array, idx, plugin::Module **);
 
497
    delete_module(plugins, module);
 
498
  }
 
499
  drizzle_del_plugin_sysvar();
 
500
}
 
501
 
 
502
 
 
503
static void plugin_initialize_vars(plugin::Module *module)
 
504
{
 
505
  if (module->getManifest().status_vars)
 
506
  {
 
507
    add_status_vars(module->getManifest().status_vars); // add_status_vars makes a copy
 
508
  }
 
509
 
 
510
  /*
 
511
    set the plugin attribute of plugin's sys vars so they are pointing
 
512
    to the active plugin
 
513
  */
 
514
  if (module->system_vars)
 
515
  {
 
516
    sys_var_pluginvar *var= module->system_vars->cast_pluginvar();
 
517
    for (;;)
 
518
    {
 
519
      var->plugin= module;
 
520
      if (! var->getNext())
 
521
        break;
 
522
      var= var->getNext()->cast_pluginvar();
 
523
    }
 
524
  }
 
525
}
 
526
 
 
527
 
 
528
static bool plugin_initialize(plugin::Registry &registry,
 
529
                              plugin::Module *module)
218
530
{
219
531
  assert(module->isInited == false);
220
532
 
221
 
  module::Context loading_context(registry, module);
 
533
  registry.setCurrentModule(module);
222
534
  if (module->getManifest().init)
223
535
  {
224
 
    if (module->getManifest().init(loading_context))
 
536
    if (module->getManifest().init(registry))
225
537
    {
226
538
      errmsg_printf(ERRMSG_LVL_ERROR,
227
539
                    _("Plugin '%s' init function returned error.\n"),
229
541
      return true;
230
542
    }
231
543
  }
 
544
  registry.clearCurrentModule();
232
545
  module->isInited= true;
233
546
 
234
547
 
236
549
}
237
550
 
238
551
 
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
 
}
 
552
extern "C" unsigned char *get_bookmark_hash_key(const unsigned char *, size_t *, bool);
 
553
 
 
554
 
 
555
unsigned char *get_bookmark_hash_key(const unsigned char *buff, size_t *length, bool)
 
556
{
 
557
  struct st_bookmark *var= (st_bookmark *)buff;
 
558
  *length= var->name_len + 1;
 
559
  return (unsigned char*) var->key;
 
560
}
 
561
 
289
562
 
290
563
/*
291
564
  The logic is that we first load and initialize all compiled in plugins.
294
567
 
295
568
  Finally we initialize everything, aka the dynamic that have yet to initialize.
296
569
*/
297
 
bool plugin_init(module::Registry &registry,
298
 
                 po::options_description &long_options)
 
570
int plugin_init(plugin::Registry &registry, int *argc, char **argv, int flags)
299
571
{
300
 
  memory::Root tmp_root(4096);
 
572
  uint32_t idx;
 
573
  plugin::Manifest **builtins;
 
574
  plugin::Manifest *manifest;
 
575
  plugin::Module *module;
 
576
  MEM_ROOT tmp_root;
301
577
 
302
578
  if (initialized)
303
 
    return false;
 
579
    return(0);
 
580
 
 
581
  init_alloc_root(&plugin_mem_root, 4096, 4096);
 
582
  init_alloc_root(&tmp_root, 4096, 4096);
 
583
 
 
584
  if (hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
 
585
                  get_bookmark_hash_key, NULL, HASH_UNIQUE))
 
586
      goto err;
 
587
 
 
588
 
 
589
  if (my_init_dynamic_array(&plugin_dl_array,
 
590
                            sizeof(plugin::Library *),16,16) ||
 
591
      my_init_dynamic_array(&module_array,
 
592
                            sizeof(plugin::Module *),16,16))
 
593
    goto err;
304
594
 
305
595
  initialized= 1;
306
596
 
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);
312
 
 
313
 
  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
597
  /*
341
598
    First we register builtin plugins
342
599
  */
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)
 
600
  for (builtins= drizzled_builtins; *builtins; builtins++)
348
601
  {
349
 
    tmp_root.free_root(MYF(0));
350
 
    return true;
 
602
    for (manifest= *builtins; manifest->name; manifest++)
 
603
    {
 
604
      module= new (std::nothrow) plugin::Module(manifest);
 
605
      if (module == NULL)
 
606
        return true;
 
607
 
 
608
      free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
 
609
      if (test_plugin_options(&tmp_root, module, argc, argv))
 
610
        continue;
 
611
 
 
612
      if (register_builtin(registry, module, &module))
 
613
        goto err_unlock;
 
614
 
 
615
      plugin_initialize_vars(module);
 
616
 
 
617
      if (! (flags & PLUGIN_INIT_SKIP_INITIALIZATION))
 
618
      {
 
619
        if (plugin_initialize(registry, module))
 
620
          goto err_unlock;
 
621
      }
 
622
    }
351
623
  }
352
624
 
353
 
  /* Uniquify the list */
354
 
  const set<string> plugin_list_set(opt_plugin_load.begin(),
355
 
                                    opt_plugin_load.end());
356
 
  
 
625
 
357
626
  /* Register all dynamic plugins */
358
 
  load_failed= plugin_load_list(registry, &tmp_root,
359
 
                                plugin_list_set, long_options);
360
 
  if (load_failed)
 
627
  if (! (flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
361
628
  {
362
 
    tmp_root.free_root(MYF(0));
363
 
    return true;
 
629
    if (opt_plugin_load)
 
630
    {
 
631
      plugin_load_list(registry, &tmp_root, argc, argv, opt_plugin_load);
 
632
    }
 
633
    else
 
634
    {
 
635
      string tmp_plugin_list(opt_plugin_load_default);
 
636
      if (opt_plugin_add)
 
637
      {
 
638
        tmp_plugin_list.push_back(',');
 
639
        tmp_plugin_list.append(opt_plugin_add);
 
640
      }
 
641
      plugin_load_list(registry, &tmp_root, argc, argv, tmp_plugin_list.c_str());
 
642
    }
364
643
  }
365
644
 
366
 
  tmp_root.free_root(MYF(0));
367
 
 
368
 
  return false;
369
 
}
370
 
 
371
 
bool plugin_finalize(module::Registry &registry)
372
 
{
 
645
  if (flags & PLUGIN_INIT_SKIP_INITIALIZATION)
 
646
    goto end;
 
647
 
373
648
  /*
374
649
    Now we initialize all remaining plugins
375
650
  */
376
 
  std::map<std::string, module::Module *>::const_iterator modules=
377
 
    registry.getModulesMap().begin();
378
 
    
379
 
  while (modules != registry.getModulesMap().end())
 
651
  for (idx= 0; idx < module_array.elements; idx++)
380
652
  {
381
 
    module::Module *module= (*modules).second;
382
 
    ++modules;
 
653
    module= *dynamic_element(&module_array, idx, plugin::Module **);
383
654
    if (module->isInited == false)
384
655
    {
 
656
      plugin_initialize_vars(module);
 
657
 
385
658
      if (plugin_initialize(registry, module))
386
 
      {
387
 
        registry.remove(module);
388
 
        delete module;
389
 
        return true;
390
 
      }
 
659
        delete_module(registry, module);
391
660
    }
392
661
  }
393
662
 
394
 
  BOOST_FOREACH(plugin::Plugin::map::value_type value, registry.getPluginsMap())
395
 
  {
396
 
    value.second->prime();
397
 
  }
398
 
 
399
 
  return false;
400
 
}
401
 
 
402
 
class PrunePlugin :
403
 
  public unary_function<string, bool>
404
 
{
405
 
  const string to_match;
406
 
  PrunePlugin();
407
 
  PrunePlugin& operator=(const PrunePlugin&);
408
 
public:
409
 
  explicit PrunePlugin(const string &match_in) :
410
 
    to_match(match_in)
411
 
  { }
412
 
 
413
 
  result_type operator()(const string &match_against)
414
 
  {
415
 
    return match_against == to_match;
416
 
  }
417
 
};
418
 
 
419
 
static void plugin_prune_list(vector<string> &plugin_list,
420
 
                              const vector<string> &plugins_to_remove)
421
 
{
422
 
  for (vector<string>::const_iterator iter= plugins_to_remove.begin();
423
 
       iter != plugins_to_remove.end();
424
 
       ++iter)
425
 
  {
426
 
    plugin_list.erase(remove_if(plugin_list.begin(),
427
 
                                plugin_list.end(),
428
 
                                PrunePlugin(*iter)),
429
 
                      plugin_list.end());
430
 
  }
431
 
}
 
663
 
 
664
end:
 
665
  free_root(&tmp_root, MYF(0));
 
666
 
 
667
  return(0);
 
668
 
 
669
err_unlock:
 
670
err:
 
671
  free_root(&tmp_root, MYF(0));
 
672
  return(1);
 
673
}
 
674
 
 
675
 
 
676
static bool register_builtin(plugin::Registry &registry,
 
677
                             plugin::Module *tmp,
 
678
                             plugin::Module **ptr)
 
679
{
 
680
 
 
681
  tmp->isInited= false;
 
682
  tmp->plugin_dl= 0;
 
683
 
 
684
  if (insert_dynamic(&module_array, (unsigned char*)&tmp))
 
685
    return(1);
 
686
 
 
687
  *ptr= *dynamic_element(&module_array, module_array.elements - 1,
 
688
                         plugin::Module **);
 
689
 
 
690
  registry.add(*ptr);
 
691
 
 
692
  return(0);
 
693
}
 
694
 
432
695
 
433
696
/*
434
697
  called only by plugin_init()
435
698
*/
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)
 
699
static bool plugin_load_list(plugin::Registry &plugins,
 
700
                             MEM_ROOT *tmp_root, int *argc, char **argv,
 
701
                             const char *list)
441
702
{
442
 
  module::Library *library= NULL;
443
 
 
444
 
  for (set<string>::const_iterator iter= plugin_list.begin();
445
 
       iter != plugin_list.end();
446
 
       ++iter)
 
703
  char buffer[FN_REFLEN];
 
704
  LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
 
705
  plugin::Library *plugin_dl;
 
706
  plugin::Manifest *plugin;
 
707
  char *p= buffer;
 
708
  while (list)
447
709
  {
448
 
    const string plugin_name(*iter);
449
 
 
450
 
    library= registry.addLibrary(plugin_name, builtin);
451
 
    if (library == NULL)
 
710
    if (p == buffer + sizeof(buffer) - 1)
452
711
    {
453
 
      errmsg_printf(ERRMSG_LVL_ERROR,
454
 
                    _("Couldn't load plugin library named '%s'.\n"),
455
 
                    plugin_name.c_str());
456
 
      return true;
 
712
      errmsg_printf(ERRMSG_LVL_ERROR, _("plugin-load parameter too long"));
 
713
      return(true);
457
714
    }
458
715
 
459
 
    tmp_root->free_root(MYF(memory::MARK_BLOCKS_FREE));
460
 
    if (plugin_add(registry, tmp_root, library, long_options))
461
 
    {
462
 
      registry.removeLibrary(plugin_name);
463
 
      errmsg_printf(ERRMSG_LVL_ERROR,
464
 
                    _("Couldn't load plugin named '%s'.\n"),
465
 
                    plugin_name.c_str());
466
 
      return true;
467
 
 
 
716
    switch ((*(p++)= *(list++))) {
 
717
    case '\0':
 
718
      list= NULL; /* terminate the loop */
 
719
      /* fall through */
 
720
    case ':':     /* can't use this as delimiter as it may be drive letter */
 
721
    case ',':
 
722
      str->str[str->length]= '\0';
 
723
      if (str == &name)  // load all plugins in named module
 
724
      {
 
725
        if (!name.length)
 
726
        {
 
727
          p--;    /* reset pointer */
 
728
          continue;
 
729
        }
 
730
 
 
731
        dl= name;
 
732
        if ((plugin_dl= plugin_dl_add(&dl)))
 
733
        {
 
734
          for (plugin= plugin_dl->plugins; plugin->name; plugin++)
 
735
          {
 
736
            name.str= (char *) plugin->name;
 
737
            name.length= strlen(name.str);
 
738
 
 
739
            free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
 
740
            if (plugin_add(plugins, tmp_root, &name, &dl, argc, argv))
 
741
              goto error;
 
742
          }
 
743
          plugin_dl_del(&dl); // reduce ref count
 
744
        }
 
745
      }
 
746
      else
 
747
      {
 
748
        free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
 
749
        if (plugin_add(plugins, tmp_root, &name, &dl, argc, argv))
 
750
          goto error;
 
751
      }
 
752
      name.length= dl.length= 0;
 
753
      dl.str= NULL; name.str= p= buffer;
 
754
      str= &name;
 
755
      continue;
 
756
    case '=':
 
757
    case '#':
 
758
      if (str == &name)
 
759
      {
 
760
        name.str[name.length]= '\0';
 
761
        str= &dl;
 
762
        str->str= p;
 
763
        continue;
 
764
      }
 
765
    default:
 
766
      str->length++;
 
767
      continue;
468
768
    }
469
769
  }
470
 
  return false;
 
770
  return(false);
 
771
error:
 
772
  errmsg_printf(ERRMSG_LVL_ERROR, _("Couldn't load plugin named '%s' with soname '%s'."),
 
773
                  name.str, dl.str);
 
774
  return(true);
471
775
}
472
776
 
473
777
 
474
 
void module_shutdown(module::Registry &registry)
 
778
void plugin_shutdown(plugin::Registry &registry)
475
779
{
 
780
  uint32_t idx;
 
781
  size_t count= module_array.elements;
 
782
  vector<plugin::Library *> dl;
476
783
 
477
784
  if (initialized)
478
785
  {
482
789
    unlock_variables(NULL, &global_system_variables);
483
790
    unlock_variables(NULL, &max_system_variables);
484
791
 
485
 
    cleanup_variables(&global_system_variables);
486
 
    cleanup_variables(&max_system_variables);
 
792
    cleanup_variables(NULL, &global_system_variables);
 
793
    cleanup_variables(NULL, &max_system_variables);
487
794
 
488
795
    initialized= 0;
489
796
  }
490
797
 
491
798
  /* Dispose of the memory */
492
 
  plugin_mem_root.free_root(MYF(0));
 
799
 
 
800
  delete_dynamic(&module_array);
 
801
 
 
802
  count= plugin_dl_array.elements;
 
803
  dl.reserve(count);
 
804
  for (idx= 0; idx < count; idx++)
 
805
    dl.push_back(*dynamic_element(&plugin_dl_array, idx,
 
806
                 plugin::Library **));
 
807
  for (idx= 0; idx < count; idx++)
 
808
    free_plugin_mem(dl[idx]);
 
809
  delete_dynamic(&plugin_dl_array);
 
810
 
 
811
  hash_free(&bookmark_hash);
 
812
  free_root(&plugin_mem_root, MYF(0));
493
813
 
494
814
  global_variables_dynamic_size= 0;
495
815
}
496
816
 
 
817
/****************************************************************************
 
818
  Internal type declarations for variables support
 
819
****************************************************************************/
 
820
 
 
821
#undef DRIZZLE_SYSVAR_NAME
 
822
#define DRIZZLE_SYSVAR_NAME(name) name
 
823
#define PLUGIN_VAR_TYPEMASK 0x007f
 
824
 
 
825
#define EXTRA_OPTIONS 3 /* options for: 'foo', 'plugin-foo' and NULL */
 
826
 
 
827
typedef DECLARE_DRIZZLE_SYSVAR_BASIC(sysvar_bool_t, bool);
 
828
typedef DECLARE_DRIZZLE_SessionVAR_BASIC(sessionvar_bool_t, bool);
 
829
typedef DECLARE_DRIZZLE_SYSVAR_BASIC(sysvar_str_t, char *);
 
830
typedef DECLARE_DRIZZLE_SessionVAR_BASIC(sessionvar_str_t, char *);
 
831
 
 
832
typedef DECLARE_DRIZZLE_SYSVAR_TYPELIB(sysvar_enum_t, unsigned long);
 
833
typedef DECLARE_DRIZZLE_SessionVAR_TYPELIB(sessionvar_enum_t, unsigned long);
 
834
typedef DECLARE_DRIZZLE_SYSVAR_TYPELIB(sysvar_set_t, uint64_t);
 
835
typedef DECLARE_DRIZZLE_SessionVAR_TYPELIB(sessionvar_set_t, uint64_t);
 
836
 
 
837
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_int_t, int);
 
838
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_long_t, long);
 
839
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_int64_t_t, int64_t);
 
840
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_uint_t, uint);
 
841
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_ulong_t, ulong);
 
842
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_uint64_t_t, uint64_t);
 
843
 
 
844
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_int_t, int);
 
845
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_long_t, long);
 
846
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_int64_t_t, int64_t);
 
847
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_uint_t, uint);
 
848
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_ulong_t, ulong);
 
849
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_uint64_t_t, uint64_t);
 
850
 
 
851
typedef bool *(*mysql_sys_var_ptr_p)(Session* a_session, int offset);
 
852
 
 
853
 
 
854
/****************************************************************************
 
855
  default variable data check and update functions
 
856
****************************************************************************/
 
857
 
 
858
static int check_func_bool(Session *, struct st_mysql_sys_var *var,
 
859
                           void *save, st_mysql_value *value)
 
860
{
 
861
  char buff[STRING_BUFFER_USUAL_SIZE];
 
862
  const char *strvalue= "NULL", *str;
 
863
  int result, length;
 
864
  int64_t tmp;
 
865
 
 
866
  if (value->value_type(value) == DRIZZLE_VALUE_TYPE_STRING)
 
867
  {
 
868
    length= sizeof(buff);
 
869
    if (!(str= value->val_str(value, buff, &length)) ||
 
870
        (result= find_type(&bool_typelib, str, length, 1)-1) < 0)
 
871
    {
 
872
      if (str)
 
873
        strvalue= str;
 
874
      goto err;
 
875
    }
 
876
  }
 
877
  else
 
878
  {
 
879
    if (value->val_int(value, &tmp) < 0)
 
880
      goto err;
 
881
    if (tmp > 1)
 
882
    {
 
883
      llstr(tmp, buff);
 
884
      strvalue= buff;
 
885
      goto err;
 
886
    }
 
887
    result= (int) tmp;
 
888
  }
 
889
  *(int*)save= -result;
 
890
  return 0;
 
891
err:
 
892
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
 
893
  return 1;
 
894
}
 
895
 
 
896
 
 
897
static int check_func_int(Session *session, struct st_mysql_sys_var *var,
 
898
                          void *save, st_mysql_value *value)
 
899
{
 
900
  bool fixed;
 
901
  int64_t tmp;
 
902
  struct my_option options;
 
903
  value->val_int(value, &tmp);
 
904
  plugin_opt_set_limits(&options, var);
 
905
 
 
906
  if (var->flags & PLUGIN_VAR_UNSIGNED)
 
907
    *(uint32_t *)save= (uint32_t) getopt_ull_limit_value((uint64_t) tmp, &options,
 
908
                                                   &fixed);
 
909
  else
 
910
    *(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed);
 
911
 
 
912
  return throw_bounds_warning(session, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
913
                              var->name, (int64_t) tmp);
 
914
}
 
915
 
 
916
 
 
917
static int check_func_long(Session *session, struct st_mysql_sys_var *var,
 
918
                          void *save, st_mysql_value *value)
 
919
{
 
920
  bool fixed;
 
921
  int64_t tmp;
 
922
  struct my_option options;
 
923
  value->val_int(value, &tmp);
 
924
  plugin_opt_set_limits(&options, var);
 
925
 
 
926
  if (var->flags & PLUGIN_VAR_UNSIGNED)
 
927
    *(ulong *)save= (ulong) getopt_ull_limit_value((uint64_t) tmp, &options,
 
928
                                                   &fixed);
 
929
  else
 
930
    *(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed);
 
931
 
 
932
  return throw_bounds_warning(session, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
933
                              var->name, (int64_t) tmp);
 
934
}
 
935
 
 
936
 
 
937
static int check_func_int64_t(Session *session, struct st_mysql_sys_var *var,
 
938
                               void *save, st_mysql_value *value)
 
939
{
 
940
  bool fixed;
 
941
  int64_t tmp;
 
942
  struct my_option options;
 
943
  value->val_int(value, &tmp);
 
944
  plugin_opt_set_limits(&options, var);
 
945
 
 
946
  if (var->flags & PLUGIN_VAR_UNSIGNED)
 
947
    *(uint64_t *)save= getopt_ull_limit_value((uint64_t) tmp, &options,
 
948
                                               &fixed);
 
949
  else
 
950
    *(int64_t *)save= getopt_ll_limit_value(tmp, &options, &fixed);
 
951
 
 
952
  return throw_bounds_warning(session, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
953
                              var->name, (int64_t) tmp);
 
954
}
 
955
 
 
956
static int check_func_str(Session *session, struct st_mysql_sys_var *,
 
957
                          void *save, st_mysql_value *value)
 
958
{
 
959
  char buff[STRING_BUFFER_USUAL_SIZE];
 
960
  const char *str;
 
961
  int length;
 
962
 
 
963
  length= sizeof(buff);
 
964
  if ((str= value->val_str(value, buff, &length)))
 
965
    str= session->strmake(str, length);
 
966
  *(const char**)save= str;
 
967
  return 0;
 
968
}
 
969
 
 
970
 
 
971
static int check_func_enum(Session *, struct st_mysql_sys_var *var,
 
972
                           void *save, st_mysql_value *value)
 
973
{
 
974
  char buff[STRING_BUFFER_USUAL_SIZE];
 
975
  const char *strvalue= "NULL", *str;
 
976
  TYPELIB *typelib;
 
977
  int64_t tmp;
 
978
  long result;
 
979
  int length;
 
980
 
 
981
  if (var->flags & PLUGIN_VAR_SessionLOCAL)
 
982
    typelib= ((sessionvar_enum_t*) var)->typelib;
 
983
  else
 
984
    typelib= ((sysvar_enum_t*) var)->typelib;
 
985
 
 
986
  if (value->value_type(value) == DRIZZLE_VALUE_TYPE_STRING)
 
987
  {
 
988
    length= sizeof(buff);
 
989
    if (!(str= value->val_str(value, buff, &length)))
 
990
      goto err;
 
991
    if ((result= (long)find_type(typelib, str, length, 1)-1) < 0)
 
992
    {
 
993
      strvalue= str;
 
994
      goto err;
 
995
    }
 
996
  }
 
997
  else
 
998
  {
 
999
    if (value->val_int(value, &tmp))
 
1000
      goto err;
 
1001
    if (tmp >= typelib->count)
 
1002
    {
 
1003
      llstr(tmp, buff);
 
1004
      strvalue= buff;
 
1005
      goto err;
 
1006
    }
 
1007
    result= (long) tmp;
 
1008
  }
 
1009
  *(long*)save= result;
 
1010
  return 0;
 
1011
err:
 
1012
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
 
1013
  return 1;
 
1014
}
 
1015
 
 
1016
 
 
1017
static int check_func_set(Session *, struct st_mysql_sys_var *var,
 
1018
                          void *save, st_mysql_value *value)
 
1019
{
 
1020
  char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
 
1021
  const char *strvalue= "NULL", *str;
 
1022
  TYPELIB *typelib;
 
1023
  uint64_t result;
 
1024
  uint32_t error_len;
 
1025
  bool not_used;
 
1026
  int length;
 
1027
 
 
1028
  if (var->flags & PLUGIN_VAR_SessionLOCAL)
 
1029
    typelib= ((sessionvar_set_t*) var)->typelib;
 
1030
  else
 
1031
    typelib= ((sysvar_set_t*)var)->typelib;
 
1032
 
 
1033
  if (value->value_type(value) == DRIZZLE_VALUE_TYPE_STRING)
 
1034
  {
 
1035
    length= sizeof(buff);
 
1036
    if (!(str= value->val_str(value, buff, &length)))
 
1037
      goto err;
 
1038
    result= find_set(typelib, str, length, NULL,
 
1039
                     &error, &error_len, &not_used);
 
1040
    if (error_len)
 
1041
    {
 
1042
      length= min((uint32_t)sizeof(buff), error_len);
 
1043
      strncpy(buff, error, length);
 
1044
      buff[length]= '\0';
 
1045
      strvalue= buff;
 
1046
      goto err;
 
1047
    }
 
1048
  }
 
1049
  else
 
1050
  {
 
1051
    if (value->val_int(value, (int64_t *)&result))
 
1052
      goto err;
 
1053
    if (unlikely((result >= (1UL << typelib->count)) &&
 
1054
                 (typelib->count < sizeof(long)*8)))
 
1055
    {
 
1056
      llstr(result, buff);
 
1057
      strvalue= buff;
 
1058
      goto err;
 
1059
    }
 
1060
  }
 
1061
  *(uint64_t*)save= result;
 
1062
  return 0;
 
1063
err:
 
1064
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
 
1065
  return 1;
 
1066
}
 
1067
 
 
1068
 
 
1069
static void update_func_bool(Session *, struct st_mysql_sys_var *,
 
1070
                             void *tgt, const void *save)
 
1071
{
 
1072
  *(bool *) tgt= *(int *) save ? 1 : 0;
 
1073
}
 
1074
 
 
1075
 
 
1076
static void update_func_int(Session *, struct st_mysql_sys_var *,
 
1077
                             void *tgt, const void *save)
 
1078
{
 
1079
  *(int *)tgt= *(int *) save;
 
1080
}
 
1081
 
 
1082
 
 
1083
static void update_func_long(Session *, struct st_mysql_sys_var *,
 
1084
                             void *tgt, const void *save)
 
1085
{
 
1086
  *(long *)tgt= *(long *) save;
 
1087
}
 
1088
 
 
1089
 
 
1090
static void update_func_int64_t(Session *, struct st_mysql_sys_var *,
 
1091
                                 void *tgt, const void *save)
 
1092
{
 
1093
  *(int64_t *)tgt= *(uint64_t *) save;
 
1094
}
 
1095
 
 
1096
 
 
1097
static void update_func_str(Session *, struct st_mysql_sys_var *var,
 
1098
                             void *tgt, const void *save)
 
1099
{
 
1100
  char *old= *(char **) tgt;
 
1101
  *(char **)tgt= *(char **) save;
 
1102
  if (var->flags & PLUGIN_VAR_MEMALLOC)
 
1103
  {
 
1104
    *(char **)tgt= strdup(*(char **) save);
 
1105
    free(old);
 
1106
    /*
 
1107
     * There isn't a _really_ good thing to do here until this whole set_var
 
1108
     * mess gets redesigned
 
1109
     */
 
1110
    if (tgt == NULL)
 
1111
      errmsg_printf(ERRMSG_LVL_ERROR, _("Out of memory."));
 
1112
 
 
1113
  }
 
1114
}
 
1115
 
497
1116
 
498
1117
/****************************************************************************
499
1118
  System Variables support
500
1119
****************************************************************************/
501
1120
 
502
1121
 
503
 
sys_var *find_sys_var(const char *str, uint32_t length)
504
 
{
505
 
  return intern_find_sys_var(str, length, false);
 
1122
sys_var *find_sys_var(Session *, const char *str, uint32_t length)
 
1123
{
 
1124
  sys_var *var;
 
1125
  sys_var_pluginvar *pi= NULL;
 
1126
  plugin::Module *module;
 
1127
 
 
1128
  pthread_rwlock_rdlock(&LOCK_system_variables_hash);
 
1129
  if ((var= intern_find_sys_var(str, length, false)) &&
 
1130
      (pi= var->cast_pluginvar()))
 
1131
  {
 
1132
    pthread_rwlock_unlock(&LOCK_system_variables_hash);
 
1133
    if (!(module= pi->plugin))
 
1134
      var= NULL; /* failed to lock it, it must be uninstalling */
 
1135
    else if (module->isInited == false)
 
1136
    {
 
1137
      var= NULL;
 
1138
    }
 
1139
  }
 
1140
  else
 
1141
    pthread_rwlock_unlock(&LOCK_system_variables_hash);
 
1142
 
 
1143
  /*
 
1144
    If the variable exists but the plugin it is associated with is not ready
 
1145
    then the intern_plugin_lock did not raise an error, so we do it here.
 
1146
  */
 
1147
  if (pi && !var)
 
1148
    my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
 
1149
  return(var);
 
1150
}
 
1151
 
 
1152
 
 
1153
/*
 
1154
  called by register_var, construct_options and test_plugin_options.
 
1155
  Returns the 'bookmark' for the named variable.
 
1156
  LOCK_system_variables_hash should be at least read locked
 
1157
*/
 
1158
static st_bookmark *find_bookmark(const char *plugin, const char *name, int flags)
 
1159
{
 
1160
  st_bookmark *result= NULL;
 
1161
  uint32_t namelen, length, pluginlen= 0;
 
1162
  char *varname, *p;
 
1163
 
 
1164
  if (!(flags & PLUGIN_VAR_SessionLOCAL))
 
1165
    return NULL;
 
1166
 
 
1167
  namelen= strlen(name);
 
1168
  if (plugin)
 
1169
    pluginlen= strlen(plugin) + 1;
 
1170
  length= namelen + pluginlen + 2;
 
1171
  varname= (char*) malloc(length);
 
1172
 
 
1173
  if (plugin)
 
1174
  {
 
1175
    sprintf(varname+1,"%s_%s",plugin,name);
 
1176
    for (p= varname + 1; *p; p++)
 
1177
      if (*p == '-')
 
1178
        *p= '_';
 
1179
  }
 
1180
  else
 
1181
    memcpy(varname + 1, name, namelen + 1);
 
1182
 
 
1183
  varname[0]= flags & PLUGIN_VAR_TYPEMASK;
 
1184
 
 
1185
  result= (st_bookmark*) hash_search(&bookmark_hash,
 
1186
                                     (const unsigned char*) varname, length - 1);
 
1187
 
 
1188
  free(varname);
 
1189
  return result;
 
1190
}
 
1191
 
 
1192
 
 
1193
/*
 
1194
  returns a bookmark for session-local variables, creating if neccessary.
 
1195
  returns null for non session-local variables.
 
1196
  Requires that a write lock is obtained on LOCK_system_variables_hash
 
1197
*/
 
1198
static st_bookmark *register_var(const char *plugin, const char *name,
 
1199
                                 int flags)
 
1200
{
 
1201
  uint32_t length= strlen(plugin) + strlen(name) + 3, size= 0, offset, new_size;
 
1202
  st_bookmark *result;
 
1203
  char *varname, *p;
 
1204
 
 
1205
  if (!(flags & PLUGIN_VAR_SessionLOCAL))
 
1206
    return NULL;
 
1207
 
 
1208
  switch (flags & PLUGIN_VAR_TYPEMASK) {
 
1209
  case PLUGIN_VAR_BOOL:
 
1210
    size= ALIGN_SIZE(sizeof(bool));
 
1211
    break;
 
1212
  case PLUGIN_VAR_INT:
 
1213
    size= ALIGN_SIZE(sizeof(int));
 
1214
    break;
 
1215
  case PLUGIN_VAR_LONG:
 
1216
  case PLUGIN_VAR_ENUM:
 
1217
    size= ALIGN_SIZE(sizeof(long));
 
1218
    break;
 
1219
  case PLUGIN_VAR_LONGLONG:
 
1220
  case PLUGIN_VAR_SET:
 
1221
    size= ALIGN_SIZE(sizeof(uint64_t));
 
1222
    break;
 
1223
  case PLUGIN_VAR_STR:
 
1224
    size= ALIGN_SIZE(sizeof(char*));
 
1225
    break;
 
1226
  default:
 
1227
    assert(0);
 
1228
    return NULL;
 
1229
  };
 
1230
 
 
1231
  varname= ((char*) malloc(length));
 
1232
  sprintf(varname+1, "%s_%s", plugin, name);
 
1233
  for (p= varname + 1; *p; p++)
 
1234
    if (*p == '-')
 
1235
      *p= '_';
 
1236
 
 
1237
  if (!(result= find_bookmark(NULL, varname + 1, flags)))
 
1238
  {
 
1239
    result= (st_bookmark*) alloc_root(&plugin_mem_root,
 
1240
                                      sizeof(struct st_bookmark) + length-1);
 
1241
    varname[0]= flags & PLUGIN_VAR_TYPEMASK;
 
1242
    memcpy(result->key, varname, length);
 
1243
    result->name_len= length - 2;
 
1244
    result->offset= -1;
 
1245
 
 
1246
    assert(size && !(size & (size-1))); /* must be power of 2 */
 
1247
 
 
1248
    offset= global_system_variables.dynamic_variables_size;
 
1249
    offset= (offset + size - 1) & ~(size - 1);
 
1250
    result->offset= (int) offset;
 
1251
 
 
1252
    new_size= (offset + size + 63) & ~63;
 
1253
 
 
1254
    if (new_size > global_variables_dynamic_size)
 
1255
    {
 
1256
      char* tmpptr= NULL;
 
1257
      if (!(tmpptr=
 
1258
              (char *)realloc(global_system_variables.dynamic_variables_ptr,
 
1259
                              new_size)))
 
1260
        return NULL;
 
1261
      global_system_variables.dynamic_variables_ptr= tmpptr;
 
1262
      tmpptr= NULL;
 
1263
      if (!(tmpptr=
 
1264
              (char *)realloc(max_system_variables.dynamic_variables_ptr,
 
1265
                              new_size)))
 
1266
        return NULL;
 
1267
      max_system_variables.dynamic_variables_ptr= tmpptr;
 
1268
           
 
1269
      /*
 
1270
        Clear the new variable value space. This is required for string
 
1271
        variables. If their value is non-NULL, it must point to a valid
 
1272
        string.
 
1273
      */
 
1274
      memset(global_system_variables.dynamic_variables_ptr +
 
1275
             global_variables_dynamic_size, 0,
 
1276
             new_size - global_variables_dynamic_size);
 
1277
      memset(max_system_variables.dynamic_variables_ptr +
 
1278
             global_variables_dynamic_size, 0,
 
1279
             new_size - global_variables_dynamic_size);
 
1280
      global_variables_dynamic_size= new_size;
 
1281
    }
 
1282
 
 
1283
    global_system_variables.dynamic_variables_head= offset;
 
1284
    max_system_variables.dynamic_variables_head= offset;
 
1285
    global_system_variables.dynamic_variables_size= offset + size;
 
1286
    max_system_variables.dynamic_variables_size= offset + size;
 
1287
    global_system_variables.dynamic_variables_version++;
 
1288
    max_system_variables.dynamic_variables_version++;
 
1289
 
 
1290
    result->version= global_system_variables.dynamic_variables_version;
 
1291
 
 
1292
    /* this should succeed because we have already checked if a dup exists */
 
1293
    if (my_hash_insert(&bookmark_hash, (unsigned char*) result))
 
1294
    {
 
1295
      fprintf(stderr, "failed to add placeholder to hash");
 
1296
      assert(0);
 
1297
    }
 
1298
  }
 
1299
  free(varname);
 
1300
  return result;
 
1301
}
 
1302
 
 
1303
 
 
1304
/*
 
1305
  returns a pointer to the memory which holds the session-local variable or
 
1306
  a pointer to the global variable if session==null.
 
1307
  If required, will sync with global variables if the requested variable
 
1308
  has not yet been allocated in the current thread.
 
1309
*/
 
1310
static unsigned char *intern_sys_var_ptr(Session* session, int offset, bool global_lock)
 
1311
{
 
1312
  assert(offset >= 0);
 
1313
  assert((uint32_t)offset <= global_system_variables.dynamic_variables_head);
 
1314
 
 
1315
  if (!session)
 
1316
    return (unsigned char*) global_system_variables.dynamic_variables_ptr + offset;
 
1317
 
 
1318
  /*
 
1319
    dynamic_variables_head points to the largest valid offset
 
1320
  */
 
1321
  if (!session->variables.dynamic_variables_ptr ||
 
1322
      (uint32_t)offset > session->variables.dynamic_variables_head)
 
1323
  {
 
1324
    uint32_t idx;
 
1325
 
 
1326
    pthread_rwlock_rdlock(&LOCK_system_variables_hash);
 
1327
 
 
1328
    char *tmpptr= NULL;
 
1329
    if (!(tmpptr= (char *)realloc(session->variables.dynamic_variables_ptr,
 
1330
                                  global_variables_dynamic_size)))
 
1331
      return NULL;
 
1332
    session->variables.dynamic_variables_ptr= tmpptr;
 
1333
 
 
1334
    if (global_lock)
 
1335
      pthread_mutex_lock(&LOCK_global_system_variables);
 
1336
 
 
1337
    safe_mutex_assert_owner(&LOCK_global_system_variables);
 
1338
 
 
1339
    memcpy(session->variables.dynamic_variables_ptr +
 
1340
             session->variables.dynamic_variables_size,
 
1341
           global_system_variables.dynamic_variables_ptr +
 
1342
             session->variables.dynamic_variables_size,
 
1343
           global_system_variables.dynamic_variables_size -
 
1344
             session->variables.dynamic_variables_size);
 
1345
 
 
1346
    /*
 
1347
      now we need to iterate through any newly copied 'defaults'
 
1348
      and if it is a string type with MEMALLOC flag, we need to strdup
 
1349
    */
 
1350
    for (idx= 0; idx < bookmark_hash.records; idx++)
 
1351
    {
 
1352
      sys_var_pluginvar *pi;
 
1353
      sys_var *var;
 
1354
      st_bookmark *v= (st_bookmark*) hash_element(&bookmark_hash,idx);
 
1355
 
 
1356
      if (v->version <= session->variables.dynamic_variables_version ||
 
1357
          !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
 
1358
          !(pi= var->cast_pluginvar()) ||
 
1359
          v->key[0] != (pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
 
1360
        continue;
 
1361
 
 
1362
      /* Here we do anything special that may be required of the data types */
 
1363
 
 
1364
      if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
 
1365
          pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
 
1366
      {
 
1367
         char **pp= (char**) (session->variables.dynamic_variables_ptr +
 
1368
                             *(int*)(pi->plugin_var + 1));
 
1369
         if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr +
 
1370
                             *(int*)(pi->plugin_var + 1))))
 
1371
           *pp= strdup(*pp);
 
1372
         if (*pp == NULL)
 
1373
           return NULL;
 
1374
      }
 
1375
    }
 
1376
 
 
1377
    if (global_lock)
 
1378
      pthread_mutex_unlock(&LOCK_global_system_variables);
 
1379
 
 
1380
    session->variables.dynamic_variables_version=
 
1381
           global_system_variables.dynamic_variables_version;
 
1382
    session->variables.dynamic_variables_head=
 
1383
           global_system_variables.dynamic_variables_head;
 
1384
    session->variables.dynamic_variables_size=
 
1385
           global_system_variables.dynamic_variables_size;
 
1386
 
 
1387
    pthread_rwlock_unlock(&LOCK_system_variables_hash);
 
1388
  }
 
1389
  return (unsigned char*)session->variables.dynamic_variables_ptr + offset;
 
1390
}
 
1391
 
 
1392
static bool *mysql_sys_var_ptr_bool(Session* a_session, int offset)
 
1393
{
 
1394
  return (bool *)intern_sys_var_ptr(a_session, offset, true);
 
1395
}
 
1396
 
 
1397
static int *mysql_sys_var_ptr_int(Session* a_session, int offset)
 
1398
{
 
1399
  return (int *)intern_sys_var_ptr(a_session, offset, true);
 
1400
}
 
1401
 
 
1402
static long *mysql_sys_var_ptr_long(Session* a_session, int offset)
 
1403
{
 
1404
  return (long *)intern_sys_var_ptr(a_session, offset, true);
 
1405
}
 
1406
 
 
1407
static int64_t *mysql_sys_var_ptr_int64_t(Session* a_session, int offset)
 
1408
{
 
1409
  return (int64_t *)intern_sys_var_ptr(a_session, offset, true);
 
1410
}
 
1411
 
 
1412
static char **mysql_sys_var_ptr_str(Session* a_session, int offset)
 
1413
{
 
1414
  return (char **)intern_sys_var_ptr(a_session, offset, true);
 
1415
}
 
1416
 
 
1417
static uint64_t *mysql_sys_var_ptr_set(Session* a_session, int offset)
 
1418
{
 
1419
  return (uint64_t *)intern_sys_var_ptr(a_session, offset, true);
 
1420
}
 
1421
 
 
1422
static unsigned long *mysql_sys_var_ptr_enum(Session* a_session, int offset)
 
1423
{
 
1424
  return (unsigned long *)intern_sys_var_ptr(a_session, offset, true);
506
1425
}
507
1426
 
508
1427
 
509
1428
void plugin_sessionvar_init(Session *session)
510
1429
{
511
1430
  session->variables.storage_engine= NULL;
512
 
  cleanup_variables(&session->variables);
 
1431
  cleanup_variables(session, &session->variables);
513
1432
 
514
1433
  session->variables= global_system_variables;
515
1434
  session->variables.storage_engine= NULL;
526
1445
/*
527
1446
  Unlocks all system variables which hold a reference
528
1447
*/
529
 
static void unlock_variables(Session *, struct drizzle_system_variables *vars)
 
1448
static void unlock_variables(Session *, struct system_variables *vars)
530
1449
{
531
1450
  vars->storage_engine= NULL;
532
1451
}
538
1457
  Unlike plugin_vars_free_values() it frees all variables of all plugins,
539
1458
  it's used on shutdown.
540
1459
*/
541
 
static void cleanup_variables(drizzle_system_variables *vars)
 
1460
static void cleanup_variables(Session *session, struct system_variables *vars)
542
1461
{
 
1462
  st_bookmark *v;
 
1463
  sys_var_pluginvar *pivar;
 
1464
  sys_var *var;
 
1465
  int flags;
 
1466
  uint32_t idx;
 
1467
 
 
1468
  pthread_rwlock_rdlock(&LOCK_system_variables_hash);
 
1469
  for (idx= 0; idx < bookmark_hash.records; idx++)
 
1470
  {
 
1471
    v= (st_bookmark*) hash_element(&bookmark_hash, idx);
 
1472
    if (v->version > vars->dynamic_variables_version ||
 
1473
        !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
 
1474
        !(pivar= var->cast_pluginvar()) ||
 
1475
        v->key[0] != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
 
1476
      continue;
 
1477
 
 
1478
    flags= pivar->plugin_var->flags;
 
1479
 
 
1480
    if ((flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
 
1481
        flags & PLUGIN_VAR_SessionLOCAL && flags & PLUGIN_VAR_MEMALLOC)
 
1482
    {
 
1483
      char **ptr= (char**) pivar->real_value_ptr(session, OPT_SESSION);
 
1484
      free(*ptr);
 
1485
      *ptr= NULL;
 
1486
    }
 
1487
  }
 
1488
  pthread_rwlock_unlock(&LOCK_system_variables_hash);
 
1489
 
543
1490
  assert(vars->storage_engine == NULL);
544
1491
 
545
1492
  free(vars->dynamic_variables_ptr);
552
1499
void plugin_sessionvar_cleanup(Session *session)
553
1500
{
554
1501
  unlock_variables(session, &session->variables);
555
 
  cleanup_variables(&session->variables);
556
 
}
557
 
 
558
 
 
 
1502
  cleanup_variables(session, &session->variables);
 
1503
}
 
1504
 
 
1505
 
 
1506
/**
 
1507
  @brief Free values of thread variables of a plugin.
 
1508
 
 
1509
  This must be called before a plugin is deleted. Otherwise its
 
1510
  variables are no longer accessible and the value space is lost. Note
 
1511
  that only string values with PLUGIN_VAR_MEMALLOC are allocated and
 
1512
  must be freed.
 
1513
 
 
1514
  @param[in]        vars        Chain of system variables of a plugin
 
1515
*/
 
1516
 
 
1517
static void plugin_vars_free_values(sys_var *vars)
 
1518
{
 
1519
 
 
1520
  for (sys_var *var= vars; var; var= var->getNext())
 
1521
  {
 
1522
    sys_var_pluginvar *piv= var->cast_pluginvar();
 
1523
    if (piv &&
 
1524
        ((piv->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
 
1525
        (piv->plugin_var->flags & PLUGIN_VAR_MEMALLOC))
 
1526
    {
 
1527
      /* Free the string from global_system_variables. */
 
1528
      char **valptr= (char**) piv->real_value_ptr(NULL, OPT_GLOBAL);
 
1529
      free(*valptr);
 
1530
      *valptr= NULL;
 
1531
    }
 
1532
  }
 
1533
  return;
 
1534
}
 
1535
 
 
1536
 
 
1537
bool sys_var_pluginvar::check_update_type(Item_result type)
 
1538
{
 
1539
  if (is_readonly())
 
1540
    return 1;
 
1541
  switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
 
1542
  case PLUGIN_VAR_INT:
 
1543
  case PLUGIN_VAR_LONG:
 
1544
  case PLUGIN_VAR_LONGLONG:
 
1545
    return type != INT_RESULT;
 
1546
  case PLUGIN_VAR_STR:
 
1547
    return type != STRING_RESULT;
 
1548
  default:
 
1549
    return 0;
 
1550
  }
 
1551
}
 
1552
 
 
1553
 
 
1554
SHOW_TYPE sys_var_pluginvar::show_type()
 
1555
{
 
1556
  switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
 
1557
  case PLUGIN_VAR_BOOL:
 
1558
    return SHOW_MY_BOOL;
 
1559
  case PLUGIN_VAR_INT:
 
1560
    return SHOW_INT;
 
1561
  case PLUGIN_VAR_LONG:
 
1562
    return SHOW_LONG;
 
1563
  case PLUGIN_VAR_LONGLONG:
 
1564
    return SHOW_LONGLONG;
 
1565
  case PLUGIN_VAR_STR:
 
1566
    return SHOW_CHAR_PTR;
 
1567
  case PLUGIN_VAR_ENUM:
 
1568
  case PLUGIN_VAR_SET:
 
1569
    return SHOW_CHAR;
 
1570
  default:
 
1571
    assert(0);
 
1572
    return SHOW_UNDEF;
 
1573
  }
 
1574
}
 
1575
 
 
1576
 
 
1577
unsigned char* sys_var_pluginvar::real_value_ptr(Session *session, enum_var_type type)
 
1578
{
 
1579
  assert(session || (type == OPT_GLOBAL));
 
1580
  if (plugin_var->flags & PLUGIN_VAR_SessionLOCAL)
 
1581
  {
 
1582
    if (type == OPT_GLOBAL)
 
1583
      session= NULL;
 
1584
 
 
1585
    return intern_sys_var_ptr(session, *(int*) (plugin_var+1), false);
 
1586
  }
 
1587
  return *(unsigned char**) (plugin_var+1);
 
1588
}
 
1589
 
 
1590
 
 
1591
TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
 
1592
{
 
1593
  switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_SessionLOCAL)) {
 
1594
  case PLUGIN_VAR_ENUM:
 
1595
    return ((sysvar_enum_t *)plugin_var)->typelib;
 
1596
  case PLUGIN_VAR_SET:
 
1597
    return ((sysvar_set_t *)plugin_var)->typelib;
 
1598
  case PLUGIN_VAR_ENUM | PLUGIN_VAR_SessionLOCAL:
 
1599
    return ((sessionvar_enum_t *)plugin_var)->typelib;
 
1600
  case PLUGIN_VAR_SET | PLUGIN_VAR_SessionLOCAL:
 
1601
    return ((sessionvar_set_t *)plugin_var)->typelib;
 
1602
  default:
 
1603
    return NULL;
 
1604
  }
 
1605
  return NULL;
 
1606
}
 
1607
 
 
1608
 
 
1609
unsigned char* sys_var_pluginvar::value_ptr(Session *session, enum_var_type type, const LEX_STRING *)
 
1610
{
 
1611
  unsigned char* result;
 
1612
 
 
1613
  result= real_value_ptr(session, type);
 
1614
 
 
1615
  if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_ENUM)
 
1616
    result= (unsigned char*) get_type(plugin_var_typelib(), *(ulong*)result);
 
1617
  else if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_SET)
 
1618
  {
 
1619
    char buffer[STRING_BUFFER_USUAL_SIZE];
 
1620
    String str(buffer, sizeof(buffer), system_charset_info);
 
1621
    TYPELIB *typelib= plugin_var_typelib();
 
1622
    uint64_t mask= 1, value= *(uint64_t*) result;
 
1623
    uint32_t i;
 
1624
 
 
1625
    str.length(0);
 
1626
    for (i= 0; i < typelib->count; i++, mask<<=1)
 
1627
    {
 
1628
      if (!(value & mask))
 
1629
        continue;
 
1630
      str.append(typelib->type_names[i], typelib->type_lengths[i]);
 
1631
      str.append(',');
 
1632
    }
 
1633
 
 
1634
    result= (unsigned char*) "";
 
1635
    if (str.length())
 
1636
      result= (unsigned char*) session->strmake(str.ptr(), str.length()-1);
 
1637
  }
 
1638
  return result;
 
1639
}
 
1640
 
 
1641
 
 
1642
bool sys_var_pluginvar::check(Session *session, set_var *var)
 
1643
{
 
1644
  st_item_value_holder value;
 
1645
  assert(is_readonly() || plugin_var->check);
 
1646
 
 
1647
  value.value_type= item_value_type;
 
1648
  value.val_str= item_val_str;
 
1649
  value.val_int= item_val_int;
 
1650
  value.val_real= item_val_real;
 
1651
  value.item= var->value;
 
1652
 
 
1653
  return is_readonly() ||
 
1654
         plugin_var->check(session, plugin_var, &var->save_result, &value);
 
1655
}
 
1656
 
 
1657
 
 
1658
void sys_var_pluginvar::set_default(Session *session, enum_var_type type)
 
1659
{
 
1660
  const void *src;
 
1661
  void *tgt;
 
1662
 
 
1663
  assert(is_readonly() || plugin_var->update);
 
1664
 
 
1665
  if (is_readonly())
 
1666
    return;
 
1667
 
 
1668
  pthread_mutex_lock(&LOCK_global_system_variables);
 
1669
  tgt= real_value_ptr(session, type);
 
1670
  src= ((void **) (plugin_var + 1) + 1);
 
1671
 
 
1672
  if (plugin_var->flags & PLUGIN_VAR_SessionLOCAL)
 
1673
  {
 
1674
    if (type != OPT_GLOBAL)
 
1675
      src= real_value_ptr(session, OPT_GLOBAL);
 
1676
    else
 
1677
    switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
 
1678
        case PLUGIN_VAR_INT:
 
1679
          src= &((sessionvar_uint_t*) plugin_var)->def_val;
 
1680
          break;
 
1681
        case PLUGIN_VAR_LONG:
 
1682
          src= &((sessionvar_ulong_t*) plugin_var)->def_val;
 
1683
          break;
 
1684
        case PLUGIN_VAR_LONGLONG:
 
1685
          src= &((sessionvar_uint64_t_t*) plugin_var)->def_val;
 
1686
          break;
 
1687
        case PLUGIN_VAR_ENUM:
 
1688
          src= &((sessionvar_enum_t*) plugin_var)->def_val;
 
1689
          break;
 
1690
        case PLUGIN_VAR_SET:
 
1691
          src= &((sessionvar_set_t*) plugin_var)->def_val;
 
1692
          break;
 
1693
        case PLUGIN_VAR_BOOL:
 
1694
          src= &((sessionvar_bool_t*) plugin_var)->def_val;
 
1695
          break;
 
1696
        case PLUGIN_VAR_STR:
 
1697
          src= &((sessionvar_str_t*) plugin_var)->def_val;
 
1698
          break;
 
1699
        default:
 
1700
          assert(0);
 
1701
        }
 
1702
  }
 
1703
 
 
1704
  /* session must equal current_session if PLUGIN_VAR_SessionLOCAL flag is set */
 
1705
  assert(!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) ||
 
1706
              session == current_session);
 
1707
 
 
1708
  if (!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) || type == OPT_GLOBAL)
 
1709
  {
 
1710
    plugin_var->update(session, plugin_var, tgt, src);
 
1711
    pthread_mutex_unlock(&LOCK_global_system_variables);
 
1712
  }
 
1713
  else
 
1714
  {
 
1715
    pthread_mutex_unlock(&LOCK_global_system_variables);
 
1716
    plugin_var->update(session, plugin_var, tgt, src);
 
1717
  }
 
1718
}
 
1719
 
 
1720
 
 
1721
bool sys_var_pluginvar::update(Session *session, set_var *var)
 
1722
{
 
1723
  void *tgt;
 
1724
 
 
1725
  assert(is_readonly() || plugin_var->update);
 
1726
 
 
1727
  /* session must equal current_session if PLUGIN_VAR_SessionLOCAL flag is set */
 
1728
  assert(!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) ||
 
1729
              session == current_session);
 
1730
 
 
1731
  if (is_readonly())
 
1732
    return 1;
 
1733
 
 
1734
  pthread_mutex_lock(&LOCK_global_system_variables);
 
1735
  tgt= real_value_ptr(session, var->type);
 
1736
 
 
1737
  if (!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) || var->type == OPT_GLOBAL)
 
1738
  {
 
1739
    /* variable we are updating has global scope, so we unlock after updating */
 
1740
    plugin_var->update(session, plugin_var, tgt, &var->save_result);
 
1741
    pthread_mutex_unlock(&LOCK_global_system_variables);
 
1742
  }
 
1743
  else
 
1744
  {
 
1745
    pthread_mutex_unlock(&LOCK_global_system_variables);
 
1746
    plugin_var->update(session, plugin_var, tgt, &var->save_result);
 
1747
  }
 
1748
 return 0;
 
1749
}
 
1750
 
 
1751
 
 
1752
#define OPTION_SET_LIMITS(type, options, opt) \
 
1753
  options->var_type= type;                    \
 
1754
  options->def_value= (opt)->def_val;         \
 
1755
  options->min_value= (opt)->min_val;         \
 
1756
  options->max_value= (opt)->max_val;         \
 
1757
  options->block_size= (long) (opt)->blk_sz
 
1758
 
 
1759
 
 
1760
static void plugin_opt_set_limits(struct my_option *options,
 
1761
                                  const struct st_mysql_sys_var *opt)
 
1762
{
 
1763
  options->sub_size= 0;
 
1764
 
 
1765
  switch (opt->flags & (PLUGIN_VAR_TYPEMASK |
 
1766
                        PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL)) {
 
1767
  /* global system variables */
 
1768
  case PLUGIN_VAR_INT:
 
1769
    OPTION_SET_LIMITS(GET_INT, options, (sysvar_int_t*) opt);
 
1770
    break;
 
1771
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED:
 
1772
    OPTION_SET_LIMITS(GET_UINT, options, (sysvar_uint_t*) opt);
 
1773
    break;
 
1774
  case PLUGIN_VAR_LONG:
 
1775
    OPTION_SET_LIMITS(GET_LONG, options, (sysvar_long_t*) opt);
 
1776
    break;
 
1777
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
 
1778
    OPTION_SET_LIMITS(GET_ULONG_IS_FAIL, options, (sysvar_ulong_t*) opt);
 
1779
    break;
 
1780
  case PLUGIN_VAR_LONGLONG:
 
1781
    OPTION_SET_LIMITS(GET_LL, options, (sysvar_int64_t_t*) opt);
 
1782
    break;
 
1783
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
 
1784
    OPTION_SET_LIMITS(GET_ULL, options, (sysvar_uint64_t_t*) opt);
 
1785
    break;
 
1786
  case PLUGIN_VAR_ENUM:
 
1787
    options->var_type= GET_ENUM;
 
1788
    options->typelib= ((sysvar_enum_t*) opt)->typelib;
 
1789
    options->def_value= ((sysvar_enum_t*) opt)->def_val;
 
1790
    options->min_value= options->block_size= 0;
 
1791
    options->max_value= options->typelib->count - 1;
 
1792
    break;
 
1793
  case PLUGIN_VAR_SET:
 
1794
    options->var_type= GET_SET;
 
1795
    options->typelib= ((sysvar_set_t*) opt)->typelib;
 
1796
    options->def_value= ((sysvar_set_t*) opt)->def_val;
 
1797
    options->min_value= options->block_size= 0;
 
1798
    options->max_value= (1UL << options->typelib->count) - 1;
 
1799
    break;
 
1800
  case PLUGIN_VAR_BOOL:
 
1801
    options->var_type= GET_BOOL;
 
1802
    options->def_value= ((sysvar_bool_t*) opt)->def_val;
 
1803
    break;
 
1804
  case PLUGIN_VAR_STR:
 
1805
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
 
1806
                        GET_STR_ALLOC : GET_STR);
 
1807
    options->def_value= (intptr_t) ((sysvar_str_t*) opt)->def_val;
 
1808
    break;
 
1809
  /* threadlocal variables */
 
1810
  case PLUGIN_VAR_INT | PLUGIN_VAR_SessionLOCAL:
 
1811
    OPTION_SET_LIMITS(GET_INT, options, (sessionvar_int_t*) opt);
 
1812
    break;
 
1813
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL:
 
1814
    OPTION_SET_LIMITS(GET_UINT, options, (sessionvar_uint_t*) opt);
 
1815
    break;
 
1816
  case PLUGIN_VAR_LONG | PLUGIN_VAR_SessionLOCAL:
 
1817
    OPTION_SET_LIMITS(GET_LONG, options, (sessionvar_long_t*) opt);
 
1818
    break;
 
1819
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL:
 
1820
    OPTION_SET_LIMITS(GET_ULONG_IS_FAIL, options, (sessionvar_ulong_t*) opt);
 
1821
    break;
 
1822
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_SessionLOCAL:
 
1823
    OPTION_SET_LIMITS(GET_LL, options, (sessionvar_int64_t_t*) opt);
 
1824
    break;
 
1825
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL:
 
1826
    OPTION_SET_LIMITS(GET_ULL, options, (sessionvar_uint64_t_t*) opt);
 
1827
    break;
 
1828
  case PLUGIN_VAR_ENUM | PLUGIN_VAR_SessionLOCAL:
 
1829
    options->var_type= GET_ENUM;
 
1830
    options->typelib= ((sessionvar_enum_t*) opt)->typelib;
 
1831
    options->def_value= ((sessionvar_enum_t*) opt)->def_val;
 
1832
    options->min_value= options->block_size= 0;
 
1833
    options->max_value= options->typelib->count - 1;
 
1834
    break;
 
1835
  case PLUGIN_VAR_SET | PLUGIN_VAR_SessionLOCAL:
 
1836
    options->var_type= GET_SET;
 
1837
    options->typelib= ((sessionvar_set_t*) opt)->typelib;
 
1838
    options->def_value= ((sessionvar_set_t*) opt)->def_val;
 
1839
    options->min_value= options->block_size= 0;
 
1840
    options->max_value= (1UL << options->typelib->count) - 1;
 
1841
    break;
 
1842
  case PLUGIN_VAR_BOOL | PLUGIN_VAR_SessionLOCAL:
 
1843
    options->var_type= GET_BOOL;
 
1844
    options->def_value= ((sessionvar_bool_t*) opt)->def_val;
 
1845
    break;
 
1846
  case PLUGIN_VAR_STR | PLUGIN_VAR_SessionLOCAL:
 
1847
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
 
1848
                        GET_STR_ALLOC : GET_STR);
 
1849
    options->def_value= (intptr_t) ((sessionvar_str_t*) opt)->def_val;
 
1850
    break;
 
1851
  default:
 
1852
    assert(0);
 
1853
  }
 
1854
  options->arg_type= REQUIRED_ARG;
 
1855
  if (opt->flags & PLUGIN_VAR_NOCMDARG)
 
1856
    options->arg_type= NO_ARG;
 
1857
  if (opt->flags & PLUGIN_VAR_OPCMDARG)
 
1858
    options->arg_type= OPT_ARG;
 
1859
}
 
1860
 
 
1861
extern "C" bool get_one_plugin_option(int optid, const struct my_option *,
 
1862
                                         char *);
 
1863
 
 
1864
bool get_one_plugin_option(int, const struct my_option *, char *)
 
1865
{
 
1866
  return 0;
 
1867
}
 
1868
 
 
1869
 
 
1870
static int construct_options(MEM_ROOT *mem_root, plugin::Module *tmp,
 
1871
                             my_option *options, bool can_disable)
 
1872
{
 
1873
  const char *plugin_name= tmp->getManifest().name;
 
1874
  uint32_t namelen= strlen(plugin_name), optnamelen;
 
1875
  uint32_t buffer_length= namelen * 4 + (can_disable ? 75 : 10);
 
1876
  char *name= (char*) alloc_root(mem_root, buffer_length);
 
1877
  bool *enabled_value= (bool*) alloc_root(mem_root, sizeof(bool));
 
1878
  char *optname, *p;
 
1879
  int index= 0, offset= 0;
 
1880
  st_mysql_sys_var *opt, **plugin_option;
 
1881
  st_bookmark *v;
 
1882
 
 
1883
  /* support --skip-plugin-foo syntax */
 
1884
  memcpy(name, plugin_name, namelen + 1);
 
1885
  my_casedn_str(&my_charset_utf8_general_ci, name);
 
1886
  sprintf(name+namelen+1, "plugin-%s", name);
 
1887
  /* Now we have namelen + 1 + 7 + namelen + 1 == namelen * 2 + 9. */
 
1888
 
 
1889
  for (p= name + namelen*2 + 8; p > name; p--)
 
1890
    if (*p == '_')
 
1891
      *p= '-';
 
1892
 
 
1893
  if (can_disable)
 
1894
  {
 
1895
    sprintf(name+namelen*2+10,
 
1896
            "Enable %s plugin. Disable with --skip-%s (will save memory).",
 
1897
            plugin_name, name);
 
1898
    /*
 
1899
      Now we have namelen * 2 + 10 (one char unused) + 7 + namelen + 9 +
 
1900
      20 + namelen + 20 + 1 == namelen * 4 + 67.
 
1901
    */
 
1902
 
 
1903
    options[0].comment= name + namelen*2 + 10;
 
1904
  }
 
1905
 
 
1906
  /*
 
1907
    This whole code around variables and command line parameters is turd
 
1908
    soup.
 
1909
 
 
1910
    e.g. the below assignemnt of having the plugin alaways enabled is never
 
1911
    changed so that './drizzled --skip-innodb --help' shows innodb as enabled.
 
1912
 
 
1913
    But this is just as broken as it was in MySQL and properly fixing everything
 
1914
    is a decent amount of "future work"
 
1915
  */
 
1916
  *enabled_value= true; /* by default, plugin enabled */
 
1917
 
 
1918
  options[1].name= (options[0].name= name) + namelen + 1;
 
1919
  options[0].id= options[1].id= 256; /* must be >255. dup id ok */
 
1920
  options[0].var_type= options[1].var_type= GET_BOOL;
 
1921
  options[0].arg_type= options[1].arg_type= NO_ARG;
 
1922
  options[0].def_value= options[1].def_value= true;
 
1923
  options[0].value= options[0].u_max_value=
 
1924
  options[1].value= options[1].u_max_value= (char**) enabled_value;
 
1925
  options+= 2;
 
1926
 
 
1927
  /*
 
1928
    Two passes as the 2nd pass will take pointer addresses for use
 
1929
    by my_getopt and register_var() in the first pass uses realloc
 
1930
  */
 
1931
 
 
1932
  for (plugin_option= tmp->getManifest().system_vars;
 
1933
       plugin_option && *plugin_option; plugin_option++, index++)
 
1934
  {
 
1935
    opt= *plugin_option;
 
1936
    if (!(opt->flags & PLUGIN_VAR_SessionLOCAL))
 
1937
      continue;
 
1938
    if (!(register_var(name, opt->name, opt->flags)))
 
1939
      continue;
 
1940
    switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
 
1941
    case PLUGIN_VAR_BOOL:
 
1942
      (((sessionvar_bool_t *)opt)->resolve)= mysql_sys_var_ptr_bool;
 
1943
      break;
 
1944
    case PLUGIN_VAR_INT:
 
1945
      (((sessionvar_int_t *)opt)->resolve)= mysql_sys_var_ptr_int;
 
1946
      break;
 
1947
    case PLUGIN_VAR_LONG:
 
1948
      (((sessionvar_long_t *)opt)->resolve)= mysql_sys_var_ptr_long;
 
1949
      break;
 
1950
    case PLUGIN_VAR_LONGLONG:
 
1951
      (((sessionvar_int64_t_t *)opt)->resolve)= mysql_sys_var_ptr_int64_t;
 
1952
      break;
 
1953
    case PLUGIN_VAR_STR:
 
1954
      (((sessionvar_str_t *)opt)->resolve)= mysql_sys_var_ptr_str;
 
1955
      break;
 
1956
    case PLUGIN_VAR_ENUM:
 
1957
      (((sessionvar_enum_t *)opt)->resolve)= mysql_sys_var_ptr_enum;
 
1958
      break;
 
1959
    case PLUGIN_VAR_SET:
 
1960
      (((sessionvar_set_t *)opt)->resolve)= mysql_sys_var_ptr_set;
 
1961
      break;
 
1962
    default:
 
1963
      errmsg_printf(ERRMSG_LVL_ERROR, _("Unknown variable type code 0x%x in plugin '%s'."),
 
1964
                      opt->flags, plugin_name);
 
1965
      return(-1);
 
1966
    };
 
1967
  }
 
1968
 
 
1969
  for (plugin_option= tmp->getManifest().system_vars;
 
1970
       plugin_option && *plugin_option; plugin_option++, index++)
 
1971
  {
 
1972
    switch ((opt= *plugin_option)->flags & PLUGIN_VAR_TYPEMASK) {
 
1973
    case PLUGIN_VAR_BOOL:
 
1974
      if (!opt->check)
 
1975
        opt->check= check_func_bool;
 
1976
      if (!opt->update)
 
1977
        opt->update= update_func_bool;
 
1978
      break;
 
1979
    case PLUGIN_VAR_INT:
 
1980
      if (!opt->check)
 
1981
        opt->check= check_func_int;
 
1982
      if (!opt->update)
 
1983
        opt->update= update_func_int;
 
1984
      break;
 
1985
    case PLUGIN_VAR_LONG:
 
1986
      if (!opt->check)
 
1987
        opt->check= check_func_long;
 
1988
      if (!opt->update)
 
1989
        opt->update= update_func_long;
 
1990
      break;
 
1991
    case PLUGIN_VAR_LONGLONG:
 
1992
      if (!opt->check)
 
1993
        opt->check= check_func_int64_t;
 
1994
      if (!opt->update)
 
1995
        opt->update= update_func_int64_t;
 
1996
      break;
 
1997
    case PLUGIN_VAR_STR:
 
1998
      if (!opt->check)
 
1999
        opt->check= check_func_str;
 
2000
      if (!opt->update)
 
2001
      {
 
2002
        opt->update= update_func_str;
 
2003
        if ((opt->flags & (PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY)) == false)
 
2004
        {
 
2005
          opt->flags|= PLUGIN_VAR_READONLY;
 
2006
          errmsg_printf(ERRMSG_LVL_WARN, _("Server variable %s of plugin %s was forced "
 
2007
                            "to be read-only: string variable without "
 
2008
                            "update_func and PLUGIN_VAR_MEMALLOC flag"),
 
2009
                            opt->name, plugin_name);
 
2010
        }
 
2011
      }
 
2012
      break;
 
2013
    case PLUGIN_VAR_ENUM:
 
2014
      if (!opt->check)
 
2015
        opt->check= check_func_enum;
 
2016
      if (!opt->update)
 
2017
        opt->update= update_func_long;
 
2018
      break;
 
2019
    case PLUGIN_VAR_SET:
 
2020
      if (!opt->check)
 
2021
        opt->check= check_func_set;
 
2022
      if (!opt->update)
 
2023
        opt->update= update_func_int64_t;
 
2024
      break;
 
2025
    default:
 
2026
      errmsg_printf(ERRMSG_LVL_ERROR, _("Unknown variable type code 0x%x in plugin '%s'."),
 
2027
                      opt->flags, plugin_name);
 
2028
      return(-1);
 
2029
    }
 
2030
 
 
2031
    if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_SessionLOCAL))
 
2032
                    == PLUGIN_VAR_NOCMDOPT)
 
2033
      continue;
 
2034
 
 
2035
    if (!opt->name)
 
2036
    {
 
2037
      errmsg_printf(ERRMSG_LVL_ERROR, _("Missing variable name in plugin '%s'."),
 
2038
                      plugin_name);
 
2039
      return(-1);
 
2040
    }
 
2041
 
 
2042
    if (!(opt->flags & PLUGIN_VAR_SessionLOCAL))
 
2043
    {
 
2044
      optnamelen= strlen(opt->name);
 
2045
      optname= (char*) alloc_root(mem_root, namelen + optnamelen + 2);
 
2046
      sprintf(optname, "%s-%s", name, opt->name);
 
2047
      optnamelen= namelen + optnamelen + 1;
 
2048
    }
 
2049
    else
 
2050
    {
 
2051
      /* this should not fail because register_var should create entry */
 
2052
      if (!(v= find_bookmark(name, opt->name, opt->flags)))
 
2053
      {
 
2054
        errmsg_printf(ERRMSG_LVL_ERROR, _("Thread local variable '%s' not allocated "
 
2055
                        "in plugin '%s'."), opt->name, plugin_name);
 
2056
        return(-1);
 
2057
      }
 
2058
 
 
2059
      *(int*)(opt + 1)= offset= v->offset;
 
2060
 
 
2061
      if (opt->flags & PLUGIN_VAR_NOCMDOPT)
 
2062
        continue;
 
2063
 
 
2064
      optname= (char*) memdup_root(mem_root, v->key + 1,
 
2065
                                   (optnamelen= v->name_len) + 1);
 
2066
    }
 
2067
 
 
2068
    /* convert '_' to '-' */
 
2069
    for (p= optname; *p; p++)
 
2070
      if (*p == '_')
 
2071
        *p= '-';
 
2072
 
 
2073
    options->name= optname;
 
2074
    options->comment= opt->comment;
 
2075
    options->app_type= opt;
 
2076
    options->id= (options-1)->id + 1;
 
2077
 
 
2078
    plugin_opt_set_limits(options, opt);
 
2079
 
 
2080
    if (opt->flags & PLUGIN_VAR_SessionLOCAL)
 
2081
      options->value= options->u_max_value= (char**)
 
2082
        (global_system_variables.dynamic_variables_ptr + offset);
 
2083
    else
 
2084
      options->value= options->u_max_value= *(char***) (opt + 1);
 
2085
 
 
2086
    options[1]= options[0];
 
2087
    options[1].name= p= (char*) alloc_root(mem_root, optnamelen + 8);
 
2088
    options[1].comment= 0; // hidden
 
2089
    sprintf(p,"plugin-%s",optname);
 
2090
 
 
2091
    options+= 2;
 
2092
  }
 
2093
 
 
2094
  return(0);
 
2095
}
 
2096
 
 
2097
 
 
2098
static my_option *construct_help_options(MEM_ROOT *mem_root, plugin::Module *p)
 
2099
{
 
2100
  st_mysql_sys_var **opt;
 
2101
  my_option *opts;
 
2102
  bool can_disable;
 
2103
  uint32_t count= EXTRA_OPTIONS;
 
2104
 
 
2105
  for (opt= p->getManifest().system_vars; opt && *opt; opt++, count+= 2) {};
 
2106
 
 
2107
  opts= (my_option*)alloc_root(mem_root, (sizeof(my_option) * count));
 
2108
  if (opts == NULL)
 
2109
    return NULL;
 
2110
 
 
2111
  memset(opts, 0, sizeof(my_option) * count);
 
2112
 
 
2113
  if ((my_strcasecmp(&my_charset_utf8_general_ci, p->getName().c_str(), "MyISAM") == 0))
 
2114
    can_disable= false;
 
2115
  else if ((my_strcasecmp(&my_charset_utf8_general_ci, p->getName().c_str(), "MEMORY") == 0))
 
2116
    can_disable= false;
 
2117
  else
 
2118
    can_disable= true;
 
2119
 
 
2120
 
 
2121
  if (construct_options(mem_root, p, opts, can_disable))
 
2122
    return NULL;
 
2123
 
 
2124
  return(opts);
 
2125
}
 
2126
 
 
2127
void drizzle_add_plugin_sysvar(sys_var_pluginvar *var)
 
2128
{
 
2129
  plugin_sysvar_vec.push_back(var);
 
2130
}
 
2131
 
 
2132
void drizzle_del_plugin_sysvar()
 
2133
{
 
2134
  vector<sys_var_pluginvar *>::iterator iter= plugin_sysvar_vec.begin();
 
2135
  while(iter != plugin_sysvar_vec.end())
 
2136
  {
 
2137
    delete *iter;
 
2138
    ++iter;
 
2139
  }
 
2140
  plugin_sysvar_vec.clear();
 
2141
}
559
2142
 
560
2143
/*
561
2144
  SYNOPSIS
562
2145
    test_plugin_options()
563
2146
    tmp_root                    temporary scratch space
564
2147
    plugin                      internal plugin structure
 
2148
    argc                        user supplied arguments
 
2149
    argv                        user supplied arguments
565
2150
    default_enabled             default plugin enable status
566
2151
  RETURNS:
567
2152
    0 SUCCESS - plugin should be enabled/loaded
568
2153
  NOTE:
569
2154
    Requires that a write-lock is held on LOCK_system_variables_hash
570
2155
*/
571
 
static int test_plugin_options(memory::Root *,
572
 
                               module::Module *test_module,
573
 
                               po::options_description &long_options)
 
2156
static int test_plugin_options(MEM_ROOT *tmp_root, plugin::Module *tmp,
 
2157
                               int *argc, char **argv)
574
2158
{
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;
 
2159
  struct sys_var_chain chain= { NULL, NULL };
 
2160
  bool can_disable;
 
2161
  st_mysql_sys_var **opt;
 
2162
  my_option *opts= NULL;
 
2163
  int error;
 
2164
  st_mysql_sys_var *o;
 
2165
  struct st_bookmark *var;
 
2166
  uint32_t len, count= EXTRA_OPTIONS;
 
2167
 
 
2168
  for (opt= tmp->getManifest().system_vars; opt && *opt; opt++)
 
2169
    count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
 
2170
 
 
2171
  if ((my_strcasecmp(&my_charset_utf8_general_ci, tmp->getName().c_str(), "MyISAM") == 0))
 
2172
    can_disable= false;
 
2173
  else if ((my_strcasecmp(&my_charset_utf8_general_ci, tmp->getName().c_str(), "MEMORY") == 0))
 
2174
    can_disable= false;
 
2175
  else
 
2176
    can_disable= true;
 
2177
 
 
2178
  if (count > EXTRA_OPTIONS || (*argc > 1))
 
2179
  {
 
2180
    if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count)))
 
2181
    {
 
2182
      errmsg_printf(ERRMSG_LVL_ERROR, _("Out of memory for plugin '%s'."), tmp->getName().c_str());
 
2183
      return(-1);
 
2184
    }
 
2185
    memset(opts, 0, sizeof(my_option) * count);
 
2186
 
 
2187
    if (construct_options(tmp_root, tmp, opts, can_disable))
 
2188
    {
 
2189
      errmsg_printf(ERRMSG_LVL_ERROR, _("Bad options for plugin '%s'."), tmp->getName().c_str());
 
2190
      return(-1);
 
2191
    }
 
2192
 
 
2193
    error= handle_options(argc, &argv, opts, get_one_plugin_option);
 
2194
    (*argc)++; /* add back one for the program name */
 
2195
 
 
2196
    if (error)
 
2197
    {
 
2198
       errmsg_printf(ERRMSG_LVL_ERROR, _("Parsing options for plugin '%s' failed."),
 
2199
                       tmp->getName().c_str());
 
2200
       goto err;
 
2201
    }
 
2202
  }
 
2203
 
 
2204
  error= 1;
 
2205
 
 
2206
  {
 
2207
    for (opt= tmp->getManifest().system_vars; opt && *opt; opt++)
 
2208
    {
 
2209
      sys_var *v;
 
2210
      if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
 
2211
        continue;
 
2212
 
 
2213
      if ((var= find_bookmark(tmp->getName().c_str(), o->name, o->flags)))
 
2214
        v= new sys_var_pluginvar(var->key + 1, o);
 
2215
      else
 
2216
      {
 
2217
        len= tmp->getName().length() + strlen(o->name) + 2;
 
2218
        string vname(tmp->getName());
 
2219
        vname.push_back('-');
 
2220
        vname.append(o->name);
 
2221
        transform(vname.begin(), vname.end(), vname.begin(), ::tolower);
 
2222
        string::iterator p= vname.begin();      
 
2223
        while  (p != vname.end())
 
2224
        {
 
2225
          if (*p == '-')
 
2226
            *p= '_';
 
2227
          ++p;
 
2228
        }
 
2229
 
 
2230
        v= new sys_var_pluginvar(vname, o);
 
2231
      }
 
2232
      assert(v); /* check that an object was actually constructed */
 
2233
 
 
2234
      drizzle_add_plugin_sysvar(static_cast<sys_var_pluginvar *>(v));
 
2235
      /*
 
2236
        Add to the chain of variables.
 
2237
        Done like this for easier debugging so that the
 
2238
        pointer to v is not lost on optimized builds.
 
2239
      */
 
2240
      v->chain_sys_var(&chain);
 
2241
    }
 
2242
    if (chain.first)
 
2243
    {
 
2244
      chain.last->setNext(NULL);
 
2245
      if (mysql_add_sys_var_chain(chain.first, NULL))
 
2246
      {
 
2247
        errmsg_printf(ERRMSG_LVL_ERROR, _("Plugin '%s' has conflicting system variables"),
 
2248
                        tmp->getName().c_str());
 
2249
        goto err;
 
2250
      }
 
2251
      tmp->system_vars= chain.first;
 
2252
    }
 
2253
    return(0);
 
2254
  }
 
2255
 
 
2256
err:
 
2257
  if (opts)
 
2258
    my_cleanup_options(opts);
 
2259
  return(error);
588
2260
}
589
2261
 
590
2262
 
595
2267
class OptionCmp
596
2268
{
597
2269
public:
598
 
  bool operator() (const option &a, const option &b)
 
2270
  bool operator() (const my_option &a, const my_option &b)
599
2271
  {
600
2272
    return my_strcasecmp(&my_charset_utf8_general_ci, a.name, b.name);
601
2273
  }
602
2274
};
603
2275
 
604
2276
 
605
 
void my_print_help_inc_plugins(option *main_options)
 
2277
void my_print_help_inc_plugins(my_option *main_options)
606
2278
{
607
 
  module::Registry &registry= module::Registry::singleton();
608
 
  vector<option> all_options;
609
 
  memory::Root mem_root(4096);
 
2279
  vector<my_option> all_options;
 
2280
  plugin::Module *p;
 
2281
  MEM_ROOT mem_root;
 
2282
  my_option *opt= NULL;
610
2283
 
 
2284
  init_alloc_root(&mem_root, 4096, 4096);
611
2285
 
612
2286
  if (initialized)
613
 
  {
614
 
    std::map<std::string, module::Module *>::const_iterator modules=
615
 
      registry.getModulesMap().begin();
616
 
    
617
 
    while (modules != registry.getModulesMap().end())
 
2287
    for (uint32_t idx= 0; idx < module_array.elements; idx++)
618
2288
    {
619
 
      module::Module *p= (*modules).second;
620
 
      ++modules;
621
 
 
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
 
 
 
2289
      p= *dynamic_element(&module_array, idx, plugin::Module **);
 
2290
 
 
2291
      if (p->getManifest().system_vars == NULL)
 
2292
        continue;
 
2293
 
 
2294
      opt= construct_help_options(&mem_root, p);
 
2295
      if (opt == NULL)
 
2296
        continue;
 
2297
 
 
2298
      /* Only options with a non-NULL comment are displayed in help text */
 
2299
      for (;opt->id; opt++)
 
2300
      {
 
2301
        if (opt->comment)
 
2302
        {
 
2303
          all_options.push_back(*opt);
 
2304
          
 
2305
        }
 
2306
      }
627
2307
    }
628
 
  }
629
2308
 
630
2309
  for (;main_options->id; main_options++)
631
2310
  {
636
2315
  }
637
2316
 
638
2317
  /** 
639
 
   * @TODO: Fix the option building so that it doens't break sort
 
2318
   * @TODO: Fix the my_option building so that it doens't break sort
640
2319
   *
641
2320
   * sort(all_options.begin(), all_options.end(), OptionCmp());
642
2321
   */
645
2324
  all_options.push_back(*main_options);
646
2325
 
647
2326
  my_print_help(&*(all_options.begin()));
648
 
 
649
 
  mem_root.free_root(MYF(0));
 
2327
  my_print_variables(&*(all_options.begin()));
 
2328
 
 
2329
  free_root(&mem_root, MYF(0));
 
2330
 
650
2331
}
651
2332
 
652
 
} /* namespace drizzled */
653
 
 
654