~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/loader.cc

  • Committer: Monty Taylor
  • Date: 2009-10-06 19:20:36 UTC
  • mto: This revision was merged to the branch mainline in revision 1184.
  • Revision ID: mordred@inaugust.com-20091006192036-3n7cu7gumica4bkz
Added missing include guards. Removed server_includes.h from header.

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