~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/loader.cc

  • Committer: Jay Pipes
  • Date: 2009-11-16 22:00:02 UTC
  • mto: (1234.1.1 push) (1237.2.10 push)
  • mto: This revision was merged to the branch mainline in revision 1229.
  • Revision ID: jpipes@serialcoder-20091116220002-rdsha64utt41i8w8
Adds INFORMATION_SCHEMA views for the transaction log:

TRANSACTION_LOG
TRANSACTION_LOG_ENTRIES
TRANSACTION_LOG_TRANSACTIONS

Adds a new user-defined function:

PRINT_TRANSACTION_MESSAGE(filename, offset)

Adds tests for all of the above

Implementation notes:

An indexer now runs when transaction messages are applied
to the transaction log.  It creates a simple index of the
transaction log entries.  This index is used when the
information schema views' fillTable() method is called.

Show diffs side-by-side

added added

removed removed

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