~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_plugin.cc

  • Committer: Brian Aker
  • Date: 2009-06-05 23:10:06 UTC
  • mto: This revision was merged to the branch mainline in revision 1055.
  • Revision ID: brian@gaz-20090605231006-01nyw7pfpj2z2v8p
Remove guts in parser for LOCK TABLE.

Show diffs side-by-side

added added

removed removed

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