~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_plugin.cc

  • Committer: Monty Taylor
  • Date: 2008-08-05 19:01:20 UTC
  • mto: (266.1.1 codestyle)
  • mto: This revision was merged to the branch mainline in revision 266.
  • Revision ID: monty@inaugust.com-20080805190120-tsuziqz2mfqcw7pe
Removed libmysyslt.la, made mysys a noinst_ and made everything use it. It's
not a standalone lib, there's no reason to pretend otherwise.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
   along with this program; if not, write to the Free Software
14
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
 
#include "config.h"
17
 
 
18
 
#include <dlfcn.h>
19
 
 
20
 
#include <cstdio>
21
 
#include <string>
22
 
#include <vector>
23
 
#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
 
/* FreeBSD 2.2.2 does not define RTLD_NOW) */
51
 
#ifndef RTLD_NOW
52
 
#define RTLD_NOW 1
53
 
#endif
54
 
 
55
 
namespace po=boost::program_options;
56
 
 
57
 
using namespace std;
58
 
 
59
 
/** These exist just to prevent symbols from being optimized out */
60
 
typedef drizzled::module::Manifest drizzled_builtin_list[];
61
 
extern drizzled_builtin_list PANDORA_BUILTIN_SYMBOLS_LIST;
62
 
drizzled::module::Manifest *drizzled_builtins[]=
63
 
{
64
 
  PANDORA_BUILTIN_SYMBOLS_LIST, NULL
65
 
};
66
 
 
67
 
namespace drizzled
68
 
{
69
 
 
70
 
 
71
 
class sys_var_pluginvar;
72
 
static vector<sys_var_pluginvar *> plugin_sysvar_vec;
73
 
 
74
 
typedef vector<string> PluginOptions;
75
 
static PluginOptions opt_plugin_load;
76
 
static PluginOptions opt_plugin_add;
77
 
static PluginOptions opt_plugin_remove;
 
16
#include "mysql_priv.h"
 
17
#include <mysys/my_pthread.h>
 
18
#include <mysys/my_getopt.h>
 
19
#include <authentication.h>
 
20
#include <drizzled/drizzled_error_messages.h>
 
21
#define REPORT_TO_LOG  1
 
22
#define REPORT_TO_USER 2
 
23
 
 
24
#define plugin_ref_to_int(A) (A ? A[0] : NULL)
 
25
#define plugin_int_to_ref(A) &(A)
 
26
 
 
27
extern struct st_mysql_plugin *mysqld_builtins[];
 
28
 
 
29
char *opt_plugin_load= NULL;
78
30
char *opt_plugin_dir_ptr;
79
31
char opt_plugin_dir[FN_REFLEN];
80
 
const char *builtin_plugins= PANDORA_BUILTIN_LIST;
 
32
/*
 
33
  When you ad a new plugin type, add both a string and make sure that the
 
34
  init and deinit array are correctly updated.
 
35
*/
 
36
const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
 
37
{
 
38
  { C_STRING_WITH_LEN("DAEMON") },
 
39
  { C_STRING_WITH_LEN("STORAGE ENGINE") },
 
40
  { C_STRING_WITH_LEN("INFORMATION SCHEMA") },
 
41
  { C_STRING_WITH_LEN("UDF") },
 
42
  { C_STRING_WITH_LEN("UDA") },
 
43
  { C_STRING_WITH_LEN("AUDIT") },
 
44
  { C_STRING_WITH_LEN("LOGGER") },
 
45
  { C_STRING_WITH_LEN("AUTH") }
 
46
};
 
47
 
 
48
extern int initialize_schema_table(st_plugin_int *plugin);
 
49
extern int finalize_schema_table(st_plugin_int *plugin);
 
50
 
 
51
extern int initialize_udf(st_plugin_int *plugin);
 
52
extern int finalize_udf(st_plugin_int *plugin);
 
53
 
 
54
/*
 
55
  The number of elements in both plugin_type_initialize and
 
56
  plugin_type_deinitialize should equal to the number of plugins
 
57
  defined.
 
58
*/
 
59
plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
 
60
{
 
61
  0,  /* Daemon */
 
62
  ha_initialize_handlerton,  /* Storage Engine */
 
63
  initialize_schema_table,  /* Information Schema */
 
64
  initialize_udf,  /* UDF */
 
65
  0,  /* UDA */
 
66
  0,  /* Audit */
 
67
  0,  /* Logger */
 
68
  authentication_initializer  /* Auth */
 
69
};
 
70
 
 
71
plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
 
72
{
 
73
  0,  /* Daemon */
 
74
  ha_finalize_handlerton,  /* Storage Engine */
 
75
  finalize_schema_table,  /* Information Schema */
 
76
  finalize_udf,  /* UDF */
 
77
  0,  /* UDA */
 
78
  0,  /* Audit */
 
79
  0,  /* Logger */
 
80
  authentication_finalizer  /* Auth */
 
81
};
 
82
 
 
83
static const char *plugin_declarations_sym= "_mysql_plugin_declarations_";
81
84
 
82
85
/* Note that 'int version' must be the first field of every plugin
83
86
   sub-structure (plugin->info).
84
87
*/
85
88
 
86
 
static bool initialized= false;
87
 
 
88
 
 
 
89
static bool initialized= 0;
 
90
 
 
91
static DYNAMIC_ARRAY plugin_dl_array;
 
92
static DYNAMIC_ARRAY plugin_array;
 
93
static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
89
94
static bool reap_needed= false;
 
95
static int plugin_array_version=0;
90
96
 
91
97
/*
92
98
  write-lock on LOCK_system_variables_hash is required before modifying
93
99
  the following variables/structures
94
100
*/
95
 
static memory::Root plugin_mem_root(4096);
96
 
static uint32_t global_variables_dynamic_size= 0;
 
101
static MEM_ROOT plugin_mem_root;
 
102
static uint global_variables_dynamic_size= 0;
 
103
static HASH bookmark_hash;
97
104
 
98
105
 
99
106
/*
100
107
  hidden part of opaque value passed to variable check functions.
101
108
  Used to provide a object-like structure to non C++ consumers.
102
109
*/
103
 
struct st_item_value_holder : public drizzle_value
 
110
struct st_item_value_holder : public st_mysql_value
104
111
{
105
112
  Item *item;
106
113
};
107
114
 
108
 
class Bookmark
 
115
 
 
116
/*
 
117
  stored in bookmark_hash, this structure is never removed from the
 
118
  hash and is used to mark a single offset for a thd local variable
 
119
  even if plugins have been uninstalled and reinstalled, repeatedly.
 
120
  This structure is allocated from plugin_mem_root.
 
121
 
 
122
  The key format is as follows:
 
123
    1 byte         - variable type code
 
124
    name_len bytes - variable name
 
125
    '\0'           - end of key
 
126
*/
 
127
struct st_bookmark
109
128
{
110
 
public:
111
 
  Bookmark() :
112
 
    type_code(0),
113
 
    offset(0),
114
 
    version(0),
115
 
    key("")
116
 
  {}
117
 
  uint8_t type_code;
 
129
  uint name_len;
118
130
  int offset;
119
 
  uint32_t version;
120
 
  string key;
121
 
};
122
 
 
123
 
typedef boost::unordered_map<string, Bookmark> bookmark_unordered_map;
124
 
static bookmark_unordered_map bookmark_hash;
 
131
  uint version;
 
132
  char key[1];
 
133
};
 
134
 
 
135
 
 
136
/*
 
137
  skeleton of a plugin variable - portion of structure common to all.
 
138
*/
 
139
struct st_mysql_sys_var
 
140
{
 
141
  MYSQL_PLUGIN_VAR_HEADER;
 
142
};
125
143
 
126
144
 
127
145
/*
130
148
class sys_var_pluginvar: public sys_var
131
149
{
132
150
public:
133
 
  module::Module *plugin;
134
 
  drizzle_sys_var *plugin_var;
135
 
 
136
 
  sys_var_pluginvar(const std::string name_arg,
137
 
                    drizzle_sys_var *plugin_var_arg)
 
151
  struct st_plugin_int *plugin;
 
152
  struct st_mysql_sys_var *plugin_var;
 
153
 
 
154
  static void *operator new(size_t size, MEM_ROOT *mem_root)
 
155
  { return (void*) alloc_root(mem_root, (uint) size); }
 
156
  static void operator delete(void *ptr_arg __attribute__((unused)),
 
157
                              size_t size __attribute__((unused)))
 
158
  { TRASH(ptr_arg, size); }
 
159
 
 
160
  sys_var_pluginvar(const char *name_arg,
 
161
                    struct st_mysql_sys_var *plugin_var_arg)
138
162
    :sys_var(name_arg), plugin_var(plugin_var_arg) {}
139
163
  sys_var_pluginvar *cast_pluginvar() { return this; }
140
164
  bool is_readonly() const { return plugin_var->flags & PLUGIN_VAR_READONLY; }
141
 
  bool check_type(sql_var_t type)
142
 
  { return !(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) && type != OPT_GLOBAL; }
 
165
  bool check_type(enum_var_type type)
 
166
  { return !(plugin_var->flags & PLUGIN_VAR_THDLOCAL) && type != OPT_GLOBAL; }
143
167
  bool check_update_type(Item_result type);
144
168
  SHOW_TYPE show_type();
145
 
  unsigned char* real_value_ptr(Session *session, sql_var_t type);
 
169
  uchar* real_value_ptr(THD *thd, enum_var_type type);
146
170
  TYPELIB* plugin_var_typelib(void);
147
 
  unsigned char* value_ptr(Session *session, sql_var_t type,
148
 
                           const LEX_STRING *base);
149
 
  bool check(Session *session, set_var *var);
150
 
  bool check_default(sql_var_t)
 
171
  uchar* value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
 
172
  bool check(THD *thd, set_var *var);
 
173
  bool check_default(enum_var_type type __attribute__((unused)))
151
174
    { return is_readonly(); }
152
 
  void set_default(Session *session, sql_var_t);
153
 
  bool update(Session *session, set_var *var);
 
175
  void set_default(THD *thd,
 
176
                   enum_var_type type __attribute__((unused)));
 
177
  bool update(THD *thd, set_var *var);
154
178
};
155
179
 
156
180
 
157
181
/* prototypes */
158
 
static void plugin_prune_list(vector<string> &plugin_list,
159
 
                              const vector<string> &plugins_to_remove);
160
 
static bool plugin_load_list(module::Registry &registry,
161
 
                             memory::Root *tmp_root,
162
 
                             const set<string> &plugin_list,
163
 
                             po::options_description &long_options,
164
 
                             bool builtin= false);
165
 
static int test_plugin_options(memory::Root *, module::Module *,
166
 
                               po::options_description &long_options);
167
 
static void unlock_variables(Session *session, struct system_variables *vars);
168
 
static void cleanup_variables(Session *session, struct system_variables *vars);
 
182
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
 
183
                             const char *list);
 
184
static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *,
 
185
                               int *, char **);
 
186
static bool register_builtin(struct st_mysql_plugin *, struct st_plugin_int *,
 
187
                             struct st_plugin_int **);
 
188
static void unlock_variables(THD *thd, struct system_variables *vars);
 
189
static void cleanup_variables(THD *thd, struct system_variables *vars);
169
190
static void plugin_vars_free_values(sys_var *vars);
 
191
static void plugin_opt_set_limits(struct my_option *options,
 
192
                                  const struct st_mysql_sys_var *opt);
 
193
#define my_intern_plugin_lock(A,B) intern_plugin_lock(A,B CALLER_INFO)
 
194
#define my_intern_plugin_lock_ci(A,B) intern_plugin_lock(A,B ORIG_CALLER_INFO)
 
195
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin
 
196
                                     CALLER_INFO_PROTO);
 
197
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
 
198
static void reap_plugins(void);
 
199
 
170
200
 
171
201
/* declared in set_var.cc */
172
 
extern sys_var *intern_find_sys_var(const char *str, uint32_t length, bool no_error);
173
 
extern bool throw_bounds_warning(Session *session, bool fixed, bool unsignd,
174
 
                                 const std::string &name, int64_t val);
175
 
 
176
 
static bool throw_bounds_warning(Session *session, bool fixed, bool unsignd,
177
 
                                 const char *name, int64_t val)
178
 
{
179
 
  const std::string name_str(name);
180
 
  return throw_bounds_warning(session, fixed, unsignd, name_str, val);
181
 
}
 
202
extern sys_var *intern_find_sys_var(const char *str, uint length, bool no_error);
 
203
extern bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd,
 
204
                                 const char *name, int64_t val);
182
205
 
183
206
/****************************************************************************
184
207
  Value type thunks, allows the C world to play in the C++ world
185
208
****************************************************************************/
186
209
 
187
 
static int item_value_type(drizzle_value *value)
 
210
static int item_value_type(struct st_mysql_value *value)
188
211
{
189
212
  switch (((st_item_value_holder*)value)->item->result_type()) {
190
213
  case INT_RESULT:
191
 
    return DRIZZLE_VALUE_TYPE_INT;
 
214
    return MYSQL_VALUE_TYPE_INT;
192
215
  case REAL_RESULT:
193
 
    return DRIZZLE_VALUE_TYPE_REAL;
 
216
    return MYSQL_VALUE_TYPE_REAL;
194
217
  default:
195
 
    return DRIZZLE_VALUE_TYPE_STRING;
 
218
    return MYSQL_VALUE_TYPE_STRING;
196
219
  }
197
220
}
198
221
 
199
 
static const char *item_val_str(drizzle_value *value,
 
222
static const char *item_val_str(struct st_mysql_value *value,
200
223
                                char *buffer, int *length)
201
224
{
202
225
  String str(buffer, *length, system_charset_info), *res;
210
233
    Lets be nice and create a temporary string since the
211
234
    buffer was too small
212
235
  */
213
 
  return current_session->strmake(res->c_ptr_quick(), res->length());
 
236
  return current_thd->strmake(res->c_ptr_quick(), res->length());
214
237
}
215
238
 
216
239
 
217
 
static int item_val_int(drizzle_value *value, int64_t *buf)
 
240
static int item_val_int(struct st_mysql_value *value, int64_t *buf)
218
241
{
219
242
  Item *item= ((st_item_value_holder*)value)->item;
220
243
  *buf= item->val_int();
224
247
}
225
248
 
226
249
 
227
 
static int item_val_real(drizzle_value *value, double *buf)
 
250
static int item_val_real(struct st_mysql_value *value, double *buf)
228
251
{
229
252
  Item *item= ((st_item_value_holder*)value)->item;
230
253
  *buf= item->val_real();
238
261
  Plugin support code
239
262
****************************************************************************/
240
263
 
241
 
 
 
264
static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl)
 
265
{
 
266
  uint i;
 
267
  struct st_plugin_dl *tmp;
 
268
  for (i= 0; i < plugin_dl_array.elements; i++)
 
269
  {
 
270
    tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
 
271
    if (tmp->ref_count &&
 
272
        ! my_strnncoll(files_charset_info,
 
273
                       (const uchar *)dl->str, dl->length,
 
274
                       (const uchar *)tmp->dl.str, tmp->dl.length))
 
275
      return(tmp);
 
276
  }
 
277
  return(0);
 
278
}
 
279
 
 
280
static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
 
281
{
 
282
  uint i;
 
283
  struct st_plugin_dl *tmp;
 
284
  for (i= 0; i < plugin_dl_array.elements; i++)
 
285
  {
 
286
    tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
 
287
    if (! tmp->ref_count)
 
288
    {
 
289
      memcpy(tmp, plugin_dl, sizeof(struct st_plugin_dl));
 
290
      return(tmp);
 
291
    }
 
292
  }
 
293
  if (insert_dynamic(&plugin_dl_array, (uchar*)&plugin_dl))
 
294
    return(0);
 
295
  tmp= *dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
 
296
                        struct st_plugin_dl **)=
 
297
      (struct st_plugin_dl *) memdup_root(&plugin_mem_root, (uchar*)plugin_dl,
 
298
                                           sizeof(struct st_plugin_dl));
 
299
  return(tmp);
 
300
}
 
301
 
 
302
static inline void free_plugin_mem(struct st_plugin_dl *p)
 
303
{
 
304
  if (p->handle)
 
305
    dlclose(p->handle);
 
306
  my_free(p->dl.str, MYF(MY_ALLOW_ZERO_PTR));
 
307
}
 
308
 
 
309
 
 
310
static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
 
311
{
 
312
  char dlpath[FN_REFLEN];
 
313
  uint plugin_dir_len, dummy_errors, dlpathlen;
 
314
  struct st_plugin_dl *tmp, plugin_dl;
 
315
  void *sym;
 
316
  plugin_dir_len= strlen(opt_plugin_dir);
 
317
  /*
 
318
    Ensure that the dll doesn't have a path.
 
319
    This is done to ensure that only approved libraries from the
 
320
    plugin directory are used (to make this even remotely secure).
 
321
  */
 
322
  if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, FN_LIBCHAR) ||
 
323
      check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN,
 
324
                               system_charset_info, 1) ||
 
325
      plugin_dir_len + dl->length + 1 >= FN_REFLEN)
 
326
  {
 
327
    if (report & REPORT_TO_USER)
 
328
      my_error(ER_UDF_NO_PATHS, MYF(0));
 
329
    if (report & REPORT_TO_LOG)
 
330
      sql_print_error(ER(ER_UDF_NO_PATHS));
 
331
    return(0);
 
332
  }
 
333
  /* If this dll is already loaded just increase ref_count. */
 
334
  if ((tmp= plugin_dl_find(dl)))
 
335
  {
 
336
    tmp->ref_count++;
 
337
    return(tmp);
 
338
  }
 
339
  memset(&plugin_dl, 0, sizeof(plugin_dl));
 
340
  /* Compile dll path */
 
341
  dlpathlen=
 
342
    strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS) -
 
343
    dlpath;
 
344
  plugin_dl.ref_count= 1;
 
345
  /* Open new dll handle */
 
346
  if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW)))
 
347
  {
 
348
    const char *errmsg=dlerror();
 
349
    if (!strncmp(dlpath, errmsg, dlpathlen))
 
350
    { // if errmsg starts from dlpath, trim this prefix.
 
351
      errmsg+=dlpathlen;
 
352
      if (*errmsg == ':') errmsg++;
 
353
      if (*errmsg == ' ') errmsg++;
 
354
    }
 
355
    if (report & REPORT_TO_USER)
 
356
      my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, errno, errmsg);
 
357
    if (report & REPORT_TO_LOG)
 
358
      sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, errno, errmsg);
 
359
    return(0);
 
360
  }
 
361
 
 
362
  /* Find plugin declarations */
 
363
  if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))
 
364
  {
 
365
    free_plugin_mem(&plugin_dl);
 
366
    if (report & REPORT_TO_USER)
 
367
      my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_declarations_sym);
 
368
    if (report & REPORT_TO_LOG)
 
369
      sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_declarations_sym);
 
370
    return(0);
 
371
  }
 
372
 
 
373
  plugin_dl.plugins= (struct st_mysql_plugin *)sym;
 
374
 
 
375
  /* Duplicate and convert dll name */
 
376
  plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
 
377
  if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
 
378
  {
 
379
    free_plugin_mem(&plugin_dl);
 
380
    if (report & REPORT_TO_USER)
 
381
      my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length);
 
382
    if (report & REPORT_TO_LOG)
 
383
      sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
 
384
    return(0);
 
385
  }
 
386
  plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length,
 
387
    files_charset_info, dl->str, dl->length, system_charset_info,
 
388
    &dummy_errors);
 
389
  plugin_dl.dl.str[plugin_dl.dl.length]= 0;
 
390
  /* Add this dll to array */
 
391
  if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl)))
 
392
  {
 
393
    free_plugin_mem(&plugin_dl);
 
394
    if (report & REPORT_TO_USER)
 
395
      my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_dl));
 
396
    if (report & REPORT_TO_LOG)
 
397
      sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_dl));
 
398
    return(0);
 
399
  }
 
400
  return(tmp);
 
401
}
 
402
 
 
403
 
 
404
static void plugin_dl_del(const LEX_STRING *dl)
 
405
{
 
406
  uint i;
 
407
 
 
408
  for (i= 0; i < plugin_dl_array.elements; i++)
 
409
  {
 
410
    struct st_plugin_dl *tmp= *dynamic_element(&plugin_dl_array, i,
 
411
                                               struct st_plugin_dl **);
 
412
    if (tmp->ref_count &&
 
413
        ! my_strnncoll(files_charset_info,
 
414
                       (const uchar *)dl->str, dl->length,
 
415
                       (const uchar *)tmp->dl.str, tmp->dl.length))
 
416
    {
 
417
      /* Do not remove this element, unless no other plugin uses this dll. */
 
418
      if (! --tmp->ref_count)
 
419
      {
 
420
        free_plugin_mem(tmp);
 
421
        memset(tmp, 0, sizeof(struct st_plugin_dl));
 
422
      }
 
423
      break;
 
424
    }
 
425
  }
 
426
  return;
 
427
}
 
428
 
 
429
 
 
430
static struct st_plugin_int *plugin_find_internal(const LEX_STRING *name, int type)
 
431
{
 
432
  uint i;
 
433
  if (! initialized)
 
434
    return(0);
 
435
 
 
436
  if (type == MYSQL_ANY_PLUGIN)
 
437
  {
 
438
    for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
 
439
    {
 
440
      struct st_plugin_int *plugin= (st_plugin_int *)
 
441
        hash_search(&plugin_hash[i], (const uchar *)name->str, name->length);
 
442
      if (plugin)
 
443
        return(plugin);
 
444
    }
 
445
  }
 
446
  else
 
447
    return((st_plugin_int *)
 
448
        hash_search(&plugin_hash[type], (const uchar *)name->str, name->length));
 
449
  return(0);
 
450
}
 
451
 
 
452
 
 
453
static SHOW_COMP_OPTION plugin_status(const LEX_STRING *name, int type)
 
454
{
 
455
  SHOW_COMP_OPTION rc= SHOW_OPTION_NO;
 
456
  struct st_plugin_int *plugin;
 
457
  if ((plugin= plugin_find_internal(name, type)))
 
458
  {
 
459
    rc= SHOW_OPTION_DISABLED;
 
460
    if (plugin->state == PLUGIN_IS_READY)
 
461
      rc= SHOW_OPTION_YES;
 
462
  }
 
463
  return(rc);
 
464
}
 
465
 
 
466
 
 
467
bool plugin_is_ready(const LEX_STRING *name, int type)
 
468
{
 
469
  bool rc= false;
 
470
  if (plugin_status(name, type) == SHOW_OPTION_YES)
 
471
    rc= true;
 
472
  return rc;
 
473
}
 
474
 
 
475
 
 
476
SHOW_COMP_OPTION sys_var_have_plugin::get_option()
 
477
{
 
478
  LEX_STRING plugin_name= { (char *) plugin_name_str, plugin_name_len };
 
479
  return plugin_status(&plugin_name, plugin_type);
 
480
}
 
481
 
 
482
 
 
483
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc CALLER_INFO_PROTO)
 
484
{
 
485
  st_plugin_int *pi= plugin_ref_to_int(rc);
 
486
 
 
487
  if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
 
488
  {
 
489
    plugin_ref plugin;
 
490
    /*
 
491
      For debugging, we do an additional malloc which allows the
 
492
      memory manager and/or valgrind to track locked references and
 
493
      double unlocks to aid resolving reference counting.problems.
 
494
    */
 
495
    if (!(plugin= (plugin_ref) my_malloc_ci(sizeof(pi), MYF(MY_WME))))
 
496
      return(NULL);
 
497
 
 
498
    *plugin= pi;
 
499
    pi->ref_count++;
 
500
 
 
501
    if (lex)
 
502
      insert_dynamic(&lex->plugins, (uchar*)&plugin);
 
503
    return(plugin);
 
504
  }
 
505
  return(NULL);
 
506
}
 
507
 
 
508
 
 
509
plugin_ref plugin_lock(THD *thd, plugin_ref *ptr CALLER_INFO_PROTO)
 
510
{
 
511
  LEX *lex= thd ? thd->lex : 0;
 
512
  plugin_ref rc;
 
513
  rc= my_intern_plugin_lock_ci(lex, *ptr);
 
514
  return(rc);
 
515
}
 
516
 
 
517
 
 
518
plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name, int type
 
519
                               CALLER_INFO_PROTO)
 
520
{
 
521
  LEX *lex= thd ? thd->lex : 0;
 
522
  plugin_ref rc= NULL;
 
523
  st_plugin_int *plugin;
 
524
  if ((plugin= plugin_find_internal(name, type)))
 
525
    rc= my_intern_plugin_lock_ci(lex, plugin_int_to_ref(plugin));
 
526
  return(rc);
 
527
}
 
528
 
 
529
 
 
530
static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
 
531
{
 
532
  uint i;
 
533
  struct st_plugin_int *tmp;
 
534
  for (i= 0; i < plugin_array.elements; i++)
 
535
  {
 
536
    tmp= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
 
537
    if (tmp->state == PLUGIN_IS_FREED)
 
538
    {
 
539
      memcpy(tmp, plugin, sizeof(struct st_plugin_int));
 
540
      return(tmp);
 
541
    }
 
542
  }
 
543
  if (insert_dynamic(&plugin_array, (uchar*)&plugin))
 
544
    return(0);
 
545
  tmp= *dynamic_element(&plugin_array, plugin_array.elements - 1,
 
546
                        struct st_plugin_int **)=
 
547
       (struct st_plugin_int *) memdup_root(&plugin_mem_root, (uchar*)plugin,
 
548
                                            sizeof(struct st_plugin_int));
 
549
  return(tmp);
 
550
}
242
551
 
243
552
 
244
553
/*
245
554
  NOTE
246
555
    Requires that a write-lock is held on LOCK_system_variables_hash
247
556
*/
248
 
static bool plugin_add(module::Registry &registry, memory::Root *tmp_root,
249
 
                       module::Library *library,
250
 
                       po::options_description &long_options)
 
557
static bool plugin_add(MEM_ROOT *tmp_root,
 
558
                       const LEX_STRING *name, const LEX_STRING *dl,
 
559
                       int *argc, char **argv, int report)
251
560
{
252
 
  if (! initialized)
253
 
    return true;
254
 
 
255
 
  if (registry.find(library->getName()))
 
561
  struct st_plugin_int tmp;
 
562
  struct st_mysql_plugin *plugin;
 
563
  if (plugin_find_internal(name, MYSQL_ANY_PLUGIN))
256
564
  {
257
 
    errmsg_printf(ERRMSG_LVL_WARN, ER(ER_PLUGIN_EXISTS),
258
 
                  library->getName().c_str());
259
 
    return false;
 
565
    if (report & REPORT_TO_USER)
 
566
      my_error(ER_UDF_EXISTS, MYF(0), name->str);
 
567
    if (report & REPORT_TO_LOG)
 
568
      sql_print_error(ER(ER_UDF_EXISTS), name->str);
 
569
    return(true);
260
570
  }
261
 
 
262
 
  module::Module *tmp= NULL;
 
571
  /* Clear the whole struct to catch future extensions. */
 
572
  memset(&tmp, 0, sizeof(tmp));
 
573
  if (! (tmp.plugin_dl= plugin_dl_add(dl, report)))
 
574
    return(true);
263
575
  /* Find plugin by name */
264
 
  const module::Manifest *manifest= library->getManifest();
265
 
 
266
 
  if (registry.find(manifest->name))
267
 
  {
268
 
    errmsg_printf(ERRMSG_LVL_ERROR, 
269
 
                  _("Plugin '%s' contains the name '%s' in its manifest, which "
270
 
                    "has already been registered.\n"),
271
 
                  library->getName().c_str(),
272
 
                  manifest->name);
273
 
    return true;
274
 
  }
275
 
 
276
 
  tmp= new (std::nothrow) module::Module(manifest, library);
277
 
  if (tmp == NULL)
278
 
    return true;
279
 
 
280
 
  if (!test_plugin_options(tmp_root, tmp, long_options))
281
 
  {
282
 
    registry.add(tmp);
283
 
    return false;
284
 
  }
285
 
  errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_CANT_FIND_DL_ENTRY),
286
 
                library->getName().c_str());
287
 
  return true;
288
 
}
289
 
 
290
 
 
291
 
static void delete_module(module::Module *module)
 
576
  for (plugin= tmp.plugin_dl->plugins; plugin->name; plugin++)
 
577
  {
 
578
    uint name_len= strlen(plugin->name);
 
579
    if (plugin->type >= 0 && plugin->type < MYSQL_MAX_PLUGIN_TYPE_NUM &&
 
580
        ! my_strnncoll(system_charset_info,
 
581
                       (const uchar *)name->str, name->length,
 
582
                       (const uchar *)plugin->name,
 
583
                       name_len))
 
584
    {
 
585
      struct st_plugin_int *tmp_plugin_ptr;
 
586
 
 
587
      tmp.plugin= plugin;
 
588
      tmp.name.str= (char *)plugin->name;
 
589
      tmp.name.length= name_len;
 
590
      tmp.ref_count= 0;
 
591
      tmp.state= PLUGIN_IS_UNINITIALIZED;
 
592
      if (!test_plugin_options(tmp_root, &tmp, argc, argv))
 
593
      {
 
594
        if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
 
595
        {
 
596
          plugin_array_version++;
 
597
          if (!my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
 
598
          {
 
599
            init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096);
 
600
            return(false);
 
601
          }
 
602
          tmp_plugin_ptr->state= PLUGIN_IS_FREED;
 
603
        }
 
604
        mysql_del_sys_var_chain(tmp.system_vars);
 
605
        goto err;
 
606
      }
 
607
      /* plugin was disabled */
 
608
      plugin_dl_del(dl);
 
609
      return(false);
 
610
    }
 
611
  }
 
612
  if (report & REPORT_TO_USER)
 
613
    my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), name->str);
 
614
  if (report & REPORT_TO_LOG)
 
615
    sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name->str);
 
616
err:
 
617
  plugin_dl_del(dl);
 
618
  return(true);
 
619
}
 
620
 
 
621
 
 
622
static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
 
623
{
 
624
  if (plugin->plugin->status_vars)
 
625
  {
 
626
#ifdef FIX_LATER
 
627
    /*
 
628
      We have a problem right now where we can not prepend without
 
629
      breaking backwards compatibility. We will fix this shortly so
 
630
      that engines have "use names" and we wil use those for
 
631
      CREATE TABLE, and use the plugin name then for adding automatic
 
632
      variable names.
 
633
    */
 
634
    SHOW_VAR array[2]= {
 
635
      {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
 
636
      {0, 0, SHOW_UNDEF}
 
637
    };
 
638
    remove_status_vars(array);
 
639
#else
 
640
    remove_status_vars(plugin->plugin->status_vars);
 
641
#endif /* FIX_LATER */
 
642
  }
 
643
 
 
644
  if (plugin_type_deinitialize[plugin->plugin->type])
 
645
  {
 
646
    if ((*plugin_type_deinitialize[plugin->plugin->type])(plugin))
 
647
    {
 
648
      sql_print_error("Plugin '%s' of type %s failed deinitialization",
 
649
                      plugin->name.str, plugin_type_names[plugin->plugin->type].str);
 
650
    }
 
651
  }
 
652
  else if (plugin->plugin->deinit)
 
653
    plugin->plugin->deinit(plugin);
 
654
 
 
655
  plugin->state= PLUGIN_IS_UNINITIALIZED;
 
656
 
 
657
  /*
 
658
    We do the check here because NDB has a worker THD which doesn't
 
659
    exit until NDB is shut down.
 
660
  */
 
661
  if (ref_check && plugin->ref_count)
 
662
    sql_print_error("Plugin '%s' has ref_count=%d after deinitialization.",
 
663
                    plugin->name.str, plugin->ref_count);
 
664
}
 
665
 
 
666
 
 
667
static void plugin_del(struct st_plugin_int *plugin)
292
668
{
293
669
  /* Free allocated strings before deleting the plugin. */
294
 
  plugin_vars_free_values(module->system_vars);
295
 
  module->isInited= false;
296
 
  mysql_del_sys_var_chain(module->system_vars);
297
 
  delete module;
298
 
}
299
 
 
300
 
 
301
 
static void reap_plugins(module::Registry &registry)
302
 
{
303
 
  std::map<std::string, module::Module *>::const_iterator modules=
304
 
    registry.getModulesMap().begin();
305
 
 
306
 
  while (modules != registry.getModulesMap().end())
307
 
  {
308
 
    module::Module *module= (*modules).second;
309
 
    delete_module(module);
310
 
    ++modules;
311
 
  }
312
 
 
313
 
  drizzle_del_plugin_sysvar();
314
 
}
315
 
 
316
 
 
317
 
static void plugin_initialize_vars(module::Module *module)
318
 
{
 
670
  plugin_vars_free_values(plugin->system_vars);
 
671
  hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
 
672
  if (plugin->plugin_dl)
 
673
    plugin_dl_del(&plugin->plugin_dl->dl);
 
674
  plugin->state= PLUGIN_IS_FREED;
 
675
  plugin_array_version++;
 
676
  rw_wrlock(&LOCK_system_variables_hash);
 
677
  mysql_del_sys_var_chain(plugin->system_vars);
 
678
  rw_unlock(&LOCK_system_variables_hash);
 
679
  free_root(&plugin->mem_root, MYF(0));
 
680
  return;
 
681
}
 
682
 
 
683
static void reap_plugins(void)
 
684
{
 
685
  uint count, idx;
 
686
  struct st_plugin_int *plugin, **reap, **list;
 
687
 
 
688
  if (!reap_needed)
 
689
    return;
 
690
 
 
691
  reap_needed= false;
 
692
  count= plugin_array.elements;
 
693
  reap= (struct st_plugin_int **)my_alloca(sizeof(plugin)*(count+1));
 
694
  *(reap++)= NULL;
 
695
 
 
696
  for (idx= 0; idx < count; idx++)
 
697
  {
 
698
    plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
 
699
    if (plugin->state == PLUGIN_IS_DELETED && !plugin->ref_count)
 
700
    {
 
701
      /* change the status flag to prevent reaping by another thread */
 
702
      plugin->state= PLUGIN_IS_DYING;
 
703
      *(reap++)= plugin;
 
704
    }
 
705
  }
 
706
 
 
707
  list= reap;
 
708
  while ((plugin= *(--list)))
 
709
    plugin_deinitialize(plugin, true);
 
710
 
 
711
  while ((plugin= *(--reap)))
 
712
    plugin_del(plugin);
 
713
 
 
714
  my_afree(reap);
 
715
}
 
716
 
 
717
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin)
 
718
{
 
719
  int i;
 
720
  st_plugin_int *pi;
 
721
 
 
722
  if (!plugin)
 
723
    return;
 
724
 
 
725
  pi= plugin_ref_to_int(plugin);
 
726
 
 
727
  my_free((uchar*) plugin, MYF(MY_WME));
 
728
 
 
729
  if (lex)
 
730
  {
 
731
    /*
 
732
      Remove one instance of this plugin from the use list.
 
733
      We are searching backwards so that plugins locked last
 
734
      could be unlocked faster - optimizing for LIFO semantics.
 
735
    */
 
736
    for (i= lex->plugins.elements - 1; i >= 0; i--)
 
737
      if (plugin == *dynamic_element(&lex->plugins, i, plugin_ref*))
 
738
      {
 
739
        delete_dynamic_element(&lex->plugins, i);
 
740
        break;
 
741
      }
 
742
    assert(i >= 0);
 
743
  }
 
744
 
 
745
  assert(pi->ref_count);
 
746
  pi->ref_count--;
 
747
 
 
748
  if (pi->state == PLUGIN_IS_DELETED && !pi->ref_count)
 
749
    reap_needed= true;
 
750
 
 
751
  return;
 
752
}
 
753
 
 
754
 
 
755
void plugin_unlock(THD *thd, plugin_ref plugin)
 
756
{
 
757
  LEX *lex= thd ? thd->lex : 0;
 
758
  if (!plugin)
 
759
    return;
 
760
  intern_plugin_unlock(lex, plugin);
 
761
  return;
 
762
}
 
763
 
 
764
 
 
765
void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
 
766
{
 
767
  LEX *lex= thd ? thd->lex : 0;
 
768
  assert(list);
 
769
  while (count--)
 
770
    intern_plugin_unlock(lex, *list++);
 
771
  return;
 
772
}
 
773
 
 
774
 
 
775
static int plugin_initialize(struct st_plugin_int *plugin)
 
776
{
 
777
 
 
778
  if (plugin_type_initialize[plugin->plugin->type])
 
779
  {
 
780
    if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
 
781
    {
 
782
      sql_print_error("Plugin '%s' registration as a %s failed.",
 
783
                      plugin->name.str, plugin_type_names[plugin->plugin->type].str);
 
784
      goto err;
 
785
    }
 
786
  }
 
787
  else if (plugin->plugin->init)
 
788
  {
 
789
    if (plugin->plugin->init(plugin))
 
790
    {
 
791
      sql_print_error("Plugin '%s' init function returned error.",
 
792
                      plugin->name.str);
 
793
      goto err;
 
794
    }
 
795
  }
 
796
 
 
797
  plugin->state= PLUGIN_IS_READY;
 
798
 
 
799
  if (plugin->plugin->status_vars)
 
800
  {
 
801
#ifdef FIX_LATER
 
802
    /*
 
803
      We have a problem right now where we can not prepend without
 
804
      breaking backwards compatibility. We will fix this shortly so
 
805
      that engines have "use names" and we wil use those for
 
806
      CREATE TABLE, and use the plugin name then for adding automatic
 
807
      variable names.
 
808
    */
 
809
    SHOW_VAR array[2]= {
 
810
      {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
 
811
      {0, 0, SHOW_UNDEF}
 
812
    };
 
813
    if (add_status_vars(array)) // add_status_vars makes a copy
 
814
      goto err;
 
815
#else
 
816
    add_status_vars(plugin->plugin->status_vars); // add_status_vars makes a copy
 
817
#endif /* FIX_LATER */
 
818
  }
 
819
 
319
820
  /*
320
821
    set the plugin attribute of plugin's sys vars so they are pointing
321
822
    to the active plugin
322
823
  */
323
 
  if (module->system_vars)
 
824
  if (plugin->system_vars)
324
825
  {
325
 
    sys_var_pluginvar *var= module->system_vars->cast_pluginvar();
 
826
    sys_var_pluginvar *var= plugin->system_vars->cast_pluginvar();
326
827
    for (;;)
327
828
    {
328
 
      var->plugin= module;
329
 
      if (! var->getNext())
 
829
      var->plugin= plugin;
 
830
      if (!var->next)
330
831
        break;
331
 
      var= var->getNext()->cast_pluginvar();
332
 
    }
333
 
  }
334
 
}
335
 
 
336
 
 
337
 
static bool plugin_initialize(module::Registry &registry,
338
 
                              module::Module *module)
339
 
{
340
 
  assert(module->isInited == false);
341
 
 
342
 
  module::Context loading_context(registry, module);
343
 
  if (module->getManifest().init)
344
 
  {
345
 
    if (module->getManifest().init(loading_context))
346
 
    {
347
 
      errmsg_printf(ERRMSG_LVL_ERROR,
348
 
                    _("Plugin '%s' init function returned error.\n"),
349
 
                    module->getName().c_str());
350
 
      return true;
351
 
    }
352
 
  }
353
 
  module->isInited= true;
354
 
 
355
 
 
356
 
  return false;
357
 
}
358
 
 
359
 
static void compose_plugin_options(vector<string> &target,
360
 
                                   vector<string> options)
361
 
{
362
 
  for (vector<string>::iterator it= options.begin();
363
 
       it != options.end();
364
 
       ++it)
365
 
  {
366
 
    tokenize(*it, target, ",", true);
367
 
  }
368
 
}
369
 
 
370
 
void compose_plugin_add(vector<string> options)
371
 
{
372
 
  compose_plugin_options(opt_plugin_add, options);
373
 
}
374
 
 
375
 
void compose_plugin_remove(vector<string> options)
376
 
{
377
 
  compose_plugin_options(opt_plugin_remove, options);
378
 
}
379
 
 
380
 
void notify_plugin_load(string in_plugin_load)
381
 
{
382
 
  tokenize(in_plugin_load, opt_plugin_load, ",", true);
383
 
}
 
832
      var= var->next->cast_pluginvar();
 
833
    }
 
834
  }
 
835
 
 
836
  return(0);
 
837
err:
 
838
  return(1);
 
839
}
 
840
 
 
841
 
 
842
extern "C" uchar *get_plugin_hash_key(const uchar *, size_t *, bool);
 
843
extern "C" uchar *get_bookmark_hash_key(const uchar *, size_t *, bool);
 
844
 
 
845
 
 
846
uchar *get_plugin_hash_key(const uchar *buff, size_t *length,
 
847
                           bool not_used __attribute__((unused)))
 
848
{
 
849
  struct st_plugin_int *plugin= (st_plugin_int *)buff;
 
850
  *length= (uint)plugin->name.length;
 
851
  return((uchar *)plugin->name.str);
 
852
}
 
853
 
 
854
 
 
855
uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
 
856
                             bool not_used __attribute__((unused)))
 
857
{
 
858
  struct st_bookmark *var= (st_bookmark *)buff;
 
859
  *length= var->name_len + 1;
 
860
  return (uchar*) var->key;
 
861
}
 
862
 
384
863
 
385
864
/*
386
865
  The logic is that we first load and initialize all compiled in plugins.
389
868
 
390
869
  Finally we initialize everything, aka the dynamic that have yet to initialize.
391
870
*/
392
 
bool plugin_init(module::Registry &registry,
393
 
                 po::options_description &long_options)
 
871
int plugin_init(int *argc, char **argv, int flags)
394
872
{
395
 
  memory::Root tmp_root(4096);
 
873
  uint i;
 
874
  struct st_mysql_plugin **builtins;
 
875
  struct st_mysql_plugin *plugin;
 
876
  struct st_plugin_int tmp, *plugin_ptr, **reap;
 
877
  MEM_ROOT tmp_root;
396
878
 
397
879
  if (initialized)
398
 
    return false;
 
880
    return(0);
 
881
 
 
882
  init_alloc_root(&plugin_mem_root, 4096, 4096);
 
883
  init_alloc_root(&tmp_root, 4096, 4096);
 
884
 
 
885
  if (hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
 
886
                  get_bookmark_hash_key, NULL, HASH_UNIQUE))
 
887
      goto err;
 
888
 
 
889
 
 
890
  if (my_init_dynamic_array(&plugin_dl_array,
 
891
                            sizeof(struct st_plugin_dl *),16,16) ||
 
892
      my_init_dynamic_array(&plugin_array,
 
893
                            sizeof(struct st_plugin_int *),16,16))
 
894
    goto err;
 
895
 
 
896
  for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
 
897
  {
 
898
    if (hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
 
899
                  get_plugin_hash_key, NULL, HASH_UNIQUE))
 
900
      goto err;
 
901
  }
399
902
 
400
903
  initialized= 1;
401
904
 
402
 
  PluginOptions builtin_list;
403
 
  tokenize(builtin_plugins, builtin_list, ",", true);
404
 
 
405
 
  bool load_failed= false;
406
 
 
407
 
  if (opt_plugin_add.size() > 0)
408
 
  {
409
 
    opt_plugin_load.insert(opt_plugin_load.end(),
410
 
                           opt_plugin_add.begin(),
411
 
                           opt_plugin_add.end());
412
 
  }
413
 
 
414
 
  if (opt_plugin_remove.size() > 0)
415
 
  {
416
 
    plugin_prune_list(opt_plugin_load, opt_plugin_remove);
417
 
    plugin_prune_list(builtin_list, opt_plugin_remove);
418
 
  }
419
 
 
420
 
 
421
905
  /*
422
906
    First we register builtin plugins
423
907
  */
424
 
  const set<string> builtin_list_set(builtin_list.begin(), builtin_list.end());
425
 
  load_failed= plugin_load_list(registry, &tmp_root,
426
 
                                builtin_list_set, long_options, true);
427
 
  if (load_failed)
 
908
  for (builtins= mysqld_builtins; *builtins; builtins++)
428
909
  {
429
 
    tmp_root.free_root(MYF(0));
430
 
    return true;
 
910
    for (plugin= *builtins; plugin->name; plugin++)
 
911
    {
 
912
      memset(&tmp, 0, sizeof(tmp));
 
913
      tmp.plugin= plugin;
 
914
      tmp.name.str= (char *)plugin->name;
 
915
      tmp.name.length= strlen(plugin->name);
 
916
 
 
917
      free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
 
918
      if (test_plugin_options(&tmp_root, &tmp, argc, argv))
 
919
        continue;
 
920
 
 
921
      if (register_builtin(plugin, &tmp, &plugin_ptr))
 
922
        goto err_unlock;
 
923
 
 
924
      if (plugin_initialize(plugin_ptr))
 
925
        goto err_unlock;
 
926
 
 
927
      /*
 
928
        initialize the global default storage engine so that it may
 
929
        not be null in any child thread.
 
930
      */
 
931
      if (my_strcasecmp(&my_charset_latin1, plugin->name, "MyISAM") == 0)
 
932
      {
 
933
        assert(!global_system_variables.table_plugin);
 
934
        global_system_variables.table_plugin=
 
935
          my_intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr));
 
936
        assert(plugin_ptr->ref_count == 1);
 
937
      }
 
938
    }
431
939
  }
432
940
 
433
 
  /* Uniquify the list */
434
 
  const set<string> plugin_list_set(opt_plugin_load.begin(),
435
 
                                    opt_plugin_load.end());
436
 
  
 
941
  /* should now be set to MyISAM storage engine */
 
942
  assert(global_system_variables.table_plugin);
 
943
 
437
944
  /* Register all dynamic plugins */
438
 
  load_failed= plugin_load_list(registry, &tmp_root,
439
 
                                plugin_list_set, long_options);
440
 
  if (load_failed)
 
945
  if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
441
946
  {
442
 
    tmp_root.free_root(MYF(0));
443
 
    return true;
 
947
    if (opt_plugin_load)
 
948
      plugin_load_list(&tmp_root, argc, argv, opt_plugin_load);
444
949
  }
445
950
 
446
 
  tmp_root.free_root(MYF(0));
447
 
 
448
 
  return false;
449
 
}
450
 
 
451
 
void plugin_finalize(module::Registry &registry)
452
 
{
 
951
  if (flags & PLUGIN_INIT_SKIP_INITIALIZATION)
 
952
    goto end;
453
953
 
454
954
  /*
455
955
    Now we initialize all remaining plugins
456
956
  */
457
 
  std::map<std::string, module::Module *>::const_iterator modules=
458
 
    registry.getModulesMap().begin();
459
 
    
460
 
  while (modules != registry.getModulesMap().end())
 
957
 
 
958
  reap= (st_plugin_int **) my_alloca((plugin_array.elements+1) * sizeof(void*));
 
959
  *(reap++)= NULL;
 
960
 
 
961
  for (i= 0; i < plugin_array.elements; i++)
461
962
  {
462
 
    module::Module *module= (*modules).second;
463
 
    ++modules;
464
 
    if (module->isInited == false)
 
963
    plugin_ptr= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
 
964
    if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED)
465
965
    {
466
 
      plugin_initialize_vars(module);
467
 
 
468
 
      if (plugin_initialize(registry, module))
 
966
      if (plugin_initialize(plugin_ptr))
469
967
      {
470
 
        registry.remove(module);
471
 
        delete_module(module);
 
968
        plugin_ptr->state= PLUGIN_IS_DYING;
 
969
        *(reap++)= plugin_ptr;
472
970
      }
473
971
    }
474
972
  }
475
 
}
476
 
 
477
 
class PrunePlugin :
478
 
  public unary_function<string, bool>
479
 
{
480
 
  const string to_match;
481
 
  PrunePlugin();
482
 
  PrunePlugin& operator=(const PrunePlugin&);
483
 
public:
484
 
  explicit PrunePlugin(const string &match_in) :
485
 
    to_match(match_in)
486
 
  { }
487
 
 
488
 
  result_type operator()(const string &match_against)
489
 
  {
490
 
    return match_against == to_match;
491
 
  }
492
 
};
493
 
 
494
 
static void plugin_prune_list(vector<string> &plugin_list,
495
 
                              const vector<string> &plugins_to_remove)
496
 
{
497
 
  for (vector<string>::const_iterator iter= plugins_to_remove.begin();
498
 
       iter != plugins_to_remove.end();
499
 
       ++iter)
500
 
  {
501
 
    plugin_list.erase(remove_if(plugin_list.begin(),
502
 
                                plugin_list.end(),
503
 
                                PrunePlugin(*iter)),
504
 
                      plugin_list.end());
505
 
  }
506
 
}
 
973
 
 
974
  /*
 
975
    Check if any plugins have to be reaped
 
976
  */
 
977
  while ((plugin_ptr= *(--reap)))
 
978
  {
 
979
    plugin_deinitialize(plugin_ptr, true);
 
980
    plugin_del(plugin_ptr);
 
981
  }
 
982
 
 
983
  my_afree(reap);
 
984
 
 
985
end:
 
986
  free_root(&tmp_root, MYF(0));
 
987
 
 
988
  return(0);
 
989
 
 
990
err_unlock:
 
991
err:
 
992
  free_root(&tmp_root, MYF(0));
 
993
  return(1);
 
994
}
 
995
 
 
996
 
 
997
static bool register_builtin(struct st_mysql_plugin *plugin,
 
998
                             struct st_plugin_int *tmp,
 
999
                             struct st_plugin_int **ptr)
 
1000
{
 
1001
 
 
1002
  tmp->state= PLUGIN_IS_UNINITIALIZED;
 
1003
  tmp->ref_count= 0;
 
1004
  tmp->plugin_dl= 0;
 
1005
 
 
1006
  if (insert_dynamic(&plugin_array, (uchar*)&tmp))
 
1007
    return(1);
 
1008
 
 
1009
  *ptr= *dynamic_element(&plugin_array, plugin_array.elements - 1,
 
1010
                         struct st_plugin_int **)=
 
1011
        (struct st_plugin_int *) memdup_root(&plugin_mem_root, (uchar*)tmp,
 
1012
                                             sizeof(struct st_plugin_int));
 
1013
 
 
1014
  if (my_hash_insert(&plugin_hash[plugin->type],(uchar*) *ptr))
 
1015
    return(1);
 
1016
 
 
1017
  return(0);
 
1018
}
 
1019
 
507
1020
 
508
1021
/*
509
1022
  called only by plugin_init()
510
1023
*/
511
 
static bool plugin_load_list(module::Registry &registry,
512
 
                             memory::Root *tmp_root,
513
 
                             const set<string> &plugin_list,
514
 
                             po::options_description &long_options,
515
 
                             bool builtin)
 
1024
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
 
1025
                             const char *list)
516
1026
{
517
 
  module::Library *library= NULL;
518
 
 
519
 
  for (set<string>::const_iterator iter= plugin_list.begin();
520
 
       iter != plugin_list.end();
521
 
       ++iter)
 
1027
  char buffer[FN_REFLEN];
 
1028
  LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
 
1029
  struct st_plugin_dl *plugin_dl;
 
1030
  struct st_mysql_plugin *plugin;
 
1031
  char *p= buffer;
 
1032
  while (list)
522
1033
  {
523
 
    const string plugin_name(*iter);
524
 
 
525
 
    library= registry.addLibrary(plugin_name, builtin);
526
 
    if (library == NULL)
 
1034
    if (p == buffer + sizeof(buffer) - 1)
527
1035
    {
528
 
      errmsg_printf(ERRMSG_LVL_ERROR,
529
 
                    _("Couldn't load plugin library named '%s'.\n"),
530
 
                    plugin_name.c_str());
531
 
      return true;
 
1036
      sql_print_error("plugin-load parameter too long");
 
1037
      return(true);
532
1038
    }
533
1039
 
534
 
    tmp_root->free_root(MYF(memory::MARK_BLOCKS_FREE));
535
 
    if (plugin_add(registry, tmp_root, library, long_options))
536
 
    {
537
 
      registry.removeLibrary(plugin_name);
538
 
      errmsg_printf(ERRMSG_LVL_ERROR,
539
 
                    _("Couldn't load plugin named '%s'.\n"),
540
 
                    plugin_name.c_str());
541
 
      return true;
542
 
 
 
1040
    switch ((*(p++)= *(list++))) {
 
1041
    case '\0':
 
1042
      list= NULL; /* terminate the loop */
 
1043
      /* fall through */
 
1044
    case ':':     /* can't use this as delimiter as it may be drive letter */
 
1045
    case ';':
 
1046
      str->str[str->length]= '\0';
 
1047
      if (str == &name)  // load all plugins in named module
 
1048
      {
 
1049
        if (!name.length)
 
1050
        {
 
1051
          p--;    /* reset pointer */
 
1052
          continue;
 
1053
        }
 
1054
 
 
1055
        dl= name;
 
1056
        if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG)))
 
1057
        {
 
1058
          for (plugin= plugin_dl->plugins; plugin->name; plugin++)
 
1059
          {
 
1060
            name.str= (char *) plugin->name;
 
1061
            name.length= strlen(name.str);
 
1062
 
 
1063
            free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
 
1064
            if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
 
1065
              goto error;
 
1066
          }
 
1067
          plugin_dl_del(&dl); // reduce ref count
 
1068
        }
 
1069
      }
 
1070
      else
 
1071
      {
 
1072
        free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
 
1073
        if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
 
1074
          goto error;
 
1075
      }
 
1076
      name.length= dl.length= 0;
 
1077
      dl.str= NULL; name.str= p= buffer;
 
1078
      str= &name;
 
1079
      continue;
 
1080
    case '=':
 
1081
    case '#':
 
1082
      if (str == &name)
 
1083
      {
 
1084
        name.str[name.length]= '\0';
 
1085
        str= &dl;
 
1086
        str->str= p;
 
1087
        continue;
 
1088
      }
 
1089
    default:
 
1090
      str->length++;
 
1091
      continue;
543
1092
    }
544
1093
  }
545
 
  return false;
 
1094
  return(false);
 
1095
error:
 
1096
  sql_print_error("Couldn't load plugin named '%s' with soname '%s'.",
 
1097
                  name.str, dl.str);
 
1098
  return(true);
546
1099
}
547
1100
 
548
1101
 
549
 
void module_shutdown(module::Registry &registry)
 
1102
void plugin_shutdown(void)
550
1103
{
 
1104
  uint i, count= plugin_array.elements, free_slots= 0;
 
1105
  struct st_plugin_int **plugins, *plugin;
 
1106
  struct st_plugin_dl **dl;
551
1107
 
552
1108
  if (initialized)
553
1109
  {
554
1110
    reap_needed= true;
555
1111
 
556
 
    reap_plugins(registry);
557
 
    unlock_variables(NULL, &global_system_variables);
558
 
    unlock_variables(NULL, &max_system_variables);
 
1112
    /*
 
1113
      We want to shut down plugins in a reasonable order, this will
 
1114
      become important when we have plugins which depend upon each other.
 
1115
      Circular references cannot be reaped so they are forced afterwards.
 
1116
      TODO: Have an additional step here to notify all active plugins that
 
1117
      shutdown is requested to allow plugins to deinitialize in parallel.
 
1118
    */
 
1119
    while (reap_needed && (count= plugin_array.elements))
 
1120
    {
 
1121
      reap_plugins();
 
1122
      for (i= free_slots= 0; i < count; i++)
 
1123
      {
 
1124
        plugin= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
 
1125
        switch (plugin->state) {
 
1126
        case PLUGIN_IS_READY:
 
1127
          plugin->state= PLUGIN_IS_DELETED;
 
1128
          reap_needed= true;
 
1129
          break;
 
1130
        case PLUGIN_IS_FREED:
 
1131
        case PLUGIN_IS_UNINITIALIZED:
 
1132
          free_slots++;
 
1133
          break;
 
1134
        }
 
1135
      }
 
1136
      if (!reap_needed)
 
1137
      {
 
1138
        /*
 
1139
          release any plugin references held.
 
1140
        */
 
1141
        unlock_variables(NULL, &global_system_variables);
 
1142
        unlock_variables(NULL, &max_system_variables);
 
1143
      }
 
1144
    }
 
1145
 
 
1146
    if (count > free_slots)
 
1147
      sql_print_warning("Forcing shutdown of %d plugins", count - free_slots);
 
1148
 
 
1149
    plugins= (struct st_plugin_int **) my_alloca(sizeof(void*) * (count+1));
 
1150
 
 
1151
    /*
 
1152
      If we have any plugins which did not die cleanly, we force shutdown
 
1153
    */
 
1154
    for (i= 0; i < count; i++)
 
1155
    {
 
1156
      plugins[i]= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
 
1157
      /* change the state to ensure no reaping races */
 
1158
      if (plugins[i]->state == PLUGIN_IS_DELETED)
 
1159
        plugins[i]->state= PLUGIN_IS_DYING;
 
1160
    }
 
1161
 
 
1162
    /*
 
1163
      We loop through all plugins and call deinit() if they have one.
 
1164
    */
 
1165
    for (i= 0; i < count; i++)
 
1166
      if (!(plugins[i]->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_FREED)))
 
1167
      {
 
1168
        sql_print_information("Plugin '%s' will be forced to shutdown",
 
1169
                              plugins[i]->name.str);
 
1170
        /*
 
1171
          We are forcing deinit on plugins so we don't want to do a ref_count
 
1172
          check until we have processed all the plugins.
 
1173
        */
 
1174
        plugin_deinitialize(plugins[i], false);
 
1175
      }
 
1176
 
 
1177
    /*
 
1178
      We defer checking ref_counts until after all plugins are deinitialized
 
1179
      as some may have worker threads holding on to plugin references.
 
1180
    */
 
1181
    for (i= 0; i < count; i++)
 
1182
    {
 
1183
      if (plugins[i]->ref_count)
 
1184
        sql_print_error("Plugin '%s' has ref_count=%d after shutdown.",
 
1185
                        plugins[i]->name.str, plugins[i]->ref_count);
 
1186
      if (plugins[i]->state & PLUGIN_IS_UNINITIALIZED)
 
1187
        plugin_del(plugins[i]);
 
1188
    }
 
1189
 
 
1190
    /*
 
1191
      Now we can deallocate all memory.
 
1192
    */
559
1193
 
560
1194
    cleanup_variables(NULL, &global_system_variables);
561
1195
    cleanup_variables(NULL, &max_system_variables);
562
1196
 
563
1197
    initialized= 0;
 
1198
 
 
1199
    my_afree(plugins);
564
1200
  }
565
1201
 
566
1202
  /* Dispose of the memory */
567
 
  plugin_mem_root.free_root(MYF(0));
 
1203
 
 
1204
  for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
 
1205
    hash_free(&plugin_hash[i]);
 
1206
  delete_dynamic(&plugin_array);
 
1207
 
 
1208
  count= plugin_dl_array.elements;
 
1209
  dl= (struct st_plugin_dl **)my_alloca(sizeof(void*) * count);
 
1210
  for (i= 0; i < count; i++)
 
1211
    dl[i]= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
 
1212
  for (i= 0; i < plugin_dl_array.elements; i++)
 
1213
    free_plugin_mem(dl[i]);
 
1214
  my_afree(dl);
 
1215
  delete_dynamic(&plugin_dl_array);
 
1216
 
 
1217
  hash_free(&bookmark_hash);
 
1218
  free_root(&plugin_mem_root, MYF(0));
568
1219
 
569
1220
  global_variables_dynamic_size= 0;
570
 
}
 
1221
 
 
1222
  return;
 
1223
}
 
1224
 
 
1225
 
 
1226
bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
 
1227
                       int type, uint state_mask, void *arg)
 
1228
{
 
1229
  uint idx, total;
 
1230
  struct st_plugin_int *plugin, **plugins;
 
1231
  int version=plugin_array_version;
 
1232
 
 
1233
  if (!initialized)
 
1234
    return(false);
 
1235
 
 
1236
  state_mask= ~state_mask; // do it only once
 
1237
 
 
1238
  total= type == MYSQL_ANY_PLUGIN ? plugin_array.elements
 
1239
                                  : plugin_hash[type].records;
 
1240
  /*
 
1241
    Do the alloca out here in case we do have a working alloca:
 
1242
        leaving the nested stack frame invalidates alloca allocation.
 
1243
  */
 
1244
  plugins=(struct st_plugin_int **)my_alloca(total*sizeof(plugin));
 
1245
  if (type == MYSQL_ANY_PLUGIN)
 
1246
  {
 
1247
    for (idx= 0; idx < total; idx++)
 
1248
    {
 
1249
      plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
 
1250
      plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
 
1251
    }
 
1252
  }
 
1253
  else
 
1254
  {
 
1255
    HASH *hash= plugin_hash + type;
 
1256
    for (idx= 0; idx < total; idx++)
 
1257
    {
 
1258
      plugin= (struct st_plugin_int *) hash_element(hash, idx);
 
1259
      plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
 
1260
    }
 
1261
  }
 
1262
  for (idx= 0; idx < total; idx++)
 
1263
  {
 
1264
    if (unlikely(version != plugin_array_version))
 
1265
    {
 
1266
      for (uint i=idx; i < total; i++)
 
1267
        if (plugins[i] && plugins[i]->state & state_mask)
 
1268
          plugins[i]=0;
 
1269
    }
 
1270
    plugin= plugins[idx];
 
1271
    /* It will stop iterating on first engine error when "func" returns true */
 
1272
    if (plugin && func(thd, plugin_int_to_ref(plugin), arg))
 
1273
        goto err;
 
1274
  }
 
1275
 
 
1276
  my_afree(plugins);
 
1277
  return(false);
 
1278
err:
 
1279
  my_afree(plugins);
 
1280
  return(true);
 
1281
}
 
1282
 
571
1283
 
572
1284
/****************************************************************************
573
1285
  Internal type declarations for variables support
574
1286
****************************************************************************/
575
1287
 
576
 
#undef DRIZZLE_SYSVAR_NAME
577
 
#define DRIZZLE_SYSVAR_NAME(name) name
 
1288
#undef MYSQL_SYSVAR_NAME
 
1289
#define MYSQL_SYSVAR_NAME(name) name
578
1290
#define PLUGIN_VAR_TYPEMASK 0x007f
579
1291
 
580
 
static const uint32_t EXTRA_OPTIONS= 1; /* handle the NULL option */
581
 
 
582
 
typedef DECLARE_DRIZZLE_SYSVAR_BASIC(sysvar_bool_t, bool);
583
 
typedef DECLARE_DRIZZLE_SessionVAR_BASIC(sessionvar_bool_t, bool);
584
 
typedef DECLARE_DRIZZLE_SYSVAR_BASIC(sysvar_str_t, char *);
585
 
typedef DECLARE_DRIZZLE_SessionVAR_BASIC(sessionvar_str_t, char *);
586
 
 
587
 
typedef DECLARE_DRIZZLE_SessionVAR_TYPELIB(sessionvar_enum_t, unsigned long);
588
 
typedef DECLARE_DRIZZLE_SessionVAR_TYPELIB(sessionvar_set_t, uint64_t);
589
 
 
590
 
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_int_t, int);
591
 
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_long_t, long);
592
 
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_int64_t_t, int64_t);
593
 
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_uint_t, uint);
594
 
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_ulong_t, ulong);
595
 
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_uint64_t_t, uint64_t);
596
 
 
597
 
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_int_t, int);
598
 
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_long_t, long);
599
 
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_int64_t_t, int64_t);
600
 
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_uint_t, uint);
601
 
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_ulong_t, ulong);
602
 
typedef DECLARE_DRIZZLE_SessionVAR_SIMPLE(sessionvar_uint64_t_t, uint64_t);
603
 
 
604
 
typedef bool *(*mysql_sys_var_ptr_p)(Session* a_session, int offset);
 
1292
#define EXTRA_OPTIONS 3 /* options for: 'foo', 'plugin-foo' and NULL */
 
1293
 
 
1294
typedef DECLARE_MYSQL_SYSVAR_BASIC(sysvar_bool_t, bool);
 
1295
typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_bool_t, bool);
 
1296
typedef DECLARE_MYSQL_SYSVAR_BASIC(sysvar_str_t, char *);
 
1297
typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_str_t, char *);
 
1298
 
 
1299
typedef DECLARE_MYSQL_SYSVAR_TYPELIB(sysvar_enum_t, unsigned long);
 
1300
typedef DECLARE_MYSQL_THDVAR_TYPELIB(thdvar_enum_t, unsigned long);
 
1301
typedef DECLARE_MYSQL_SYSVAR_TYPELIB(sysvar_set_t, uint64_t);
 
1302
typedef DECLARE_MYSQL_THDVAR_TYPELIB(thdvar_set_t, uint64_t);
 
1303
 
 
1304
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_int_t, int);
 
1305
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_long_t, long);
 
1306
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_int64_t_t, int64_t);
 
1307
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_uint_t, uint);
 
1308
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulong_t, ulong);
 
1309
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_uint64_t_t, uint64_t);
 
1310
 
 
1311
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_int_t, int);
 
1312
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_long_t, long);
 
1313
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_int64_t_t, int64_t);
 
1314
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_uint_t, uint);
 
1315
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulong_t, ulong);
 
1316
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_uint64_t_t, uint64_t);
 
1317
 
 
1318
typedef bool *(*mysql_sys_var_ptr_p)(THD* a_thd, int offset);
605
1319
 
606
1320
 
607
1321
/****************************************************************************
608
1322
  default variable data check and update functions
609
1323
****************************************************************************/
610
1324
 
611
 
static int check_func_bool(Session *, drizzle_sys_var *var,
612
 
                           void *save, drizzle_value *value)
 
1325
static int check_func_bool(THD *thd __attribute__((unused)),
 
1326
                           struct st_mysql_sys_var *var,
 
1327
                           void *save, st_mysql_value *value)
613
1328
{
614
1329
  char buff[STRING_BUFFER_USUAL_SIZE];
615
1330
  const char *strvalue= "NULL", *str;
616
1331
  int result, length;
617
1332
  int64_t tmp;
618
1333
 
619
 
  if (value->value_type(value) == DRIZZLE_VALUE_TYPE_STRING)
 
1334
  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
620
1335
  {
621
1336
    length= sizeof(buff);
622
1337
    if (!(str= value->val_str(value, buff, &length)) ||
633
1348
      goto err;
634
1349
    if (tmp > 1)
635
1350
    {
636
 
      internal::llstr(tmp, buff);
 
1351
      llstr(tmp, buff);
637
1352
      strvalue= buff;
638
1353
      goto err;
639
1354
    }
647
1362
}
648
1363
 
649
1364
 
650
 
static int check_func_int(Session *session, drizzle_sys_var *var,
651
 
                          void *save, drizzle_value *value)
 
1365
static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
 
1366
                          void *save, st_mysql_value *value)
652
1367
{
653
1368
  bool fixed;
654
1369
  int64_t tmp;
655
 
  struct option options;
 
1370
  struct my_option options;
656
1371
  value->val_int(value, &tmp);
657
1372
  plugin_opt_set_limits(&options, var);
658
1373
 
659
1374
  if (var->flags & PLUGIN_VAR_UNSIGNED)
660
 
    *(uint32_t *)save= (uint32_t) getopt_ull_limit_value((uint64_t) tmp, &options,
 
1375
    *(uint *)save= (uint) getopt_ull_limit_value((uint64_t) tmp, &options,
661
1376
                                                   &fixed);
662
1377
  else
663
1378
    *(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed);
664
1379
 
665
 
  return throw_bounds_warning(session, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
1380
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
666
1381
                              var->name, (int64_t) tmp);
667
1382
}
668
1383
 
669
1384
 
670
 
static int check_func_long(Session *session, drizzle_sys_var *var,
671
 
                          void *save, drizzle_value *value)
 
1385
static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
 
1386
                          void *save, st_mysql_value *value)
672
1387
{
673
1388
  bool fixed;
674
1389
  int64_t tmp;
675
 
  struct option options;
 
1390
  struct my_option options;
676
1391
  value->val_int(value, &tmp);
677
1392
  plugin_opt_set_limits(&options, var);
678
1393
 
682
1397
  else
683
1398
    *(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed);
684
1399
 
685
 
  return throw_bounds_warning(session, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
1400
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
686
1401
                              var->name, (int64_t) tmp);
687
1402
}
688
1403
 
689
1404
 
690
 
static int check_func_int64_t(Session *session, drizzle_sys_var *var,
691
 
                               void *save, drizzle_value *value)
 
1405
static int check_func_int64_t(THD *thd, struct st_mysql_sys_var *var,
 
1406
                               void *save, st_mysql_value *value)
692
1407
{
693
1408
  bool fixed;
694
1409
  int64_t tmp;
695
 
  struct option options;
 
1410
  struct my_option options;
696
1411
  value->val_int(value, &tmp);
697
1412
  plugin_opt_set_limits(&options, var);
698
1413
 
702
1417
  else
703
1418
    *(int64_t *)save= getopt_ll_limit_value(tmp, &options, &fixed);
704
1419
 
705
 
  return throw_bounds_warning(session, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
1420
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
706
1421
                              var->name, (int64_t) tmp);
707
1422
}
708
1423
 
709
 
static int check_func_str(Session *session, drizzle_sys_var *,
710
 
                          void *save, drizzle_value *value)
 
1424
static int check_func_str(THD *thd,
 
1425
                          struct st_mysql_sys_var *var __attribute__((unused)),
 
1426
                          void *save, st_mysql_value *value)
711
1427
{
712
1428
  char buff[STRING_BUFFER_USUAL_SIZE];
713
1429
  const char *str;
715
1431
 
716
1432
  length= sizeof(buff);
717
1433
  if ((str= value->val_str(value, buff, &length)))
718
 
    str= session->strmake(str, length);
 
1434
    str= thd->strmake(str, length);
719
1435
  *(const char**)save= str;
720
1436
  return 0;
721
1437
}
722
1438
 
723
1439
 
724
 
static void update_func_bool(Session *, drizzle_sys_var *,
 
1440
static int check_func_enum(THD *thd __attribute__((unused)),
 
1441
                           struct st_mysql_sys_var *var,
 
1442
                           void *save, st_mysql_value *value)
 
1443
{
 
1444
  char buff[STRING_BUFFER_USUAL_SIZE];
 
1445
  const char *strvalue= "NULL", *str;
 
1446
  TYPELIB *typelib;
 
1447
  int64_t tmp;
 
1448
  long result;
 
1449
  int length;
 
1450
 
 
1451
  if (var->flags & PLUGIN_VAR_THDLOCAL)
 
1452
    typelib= ((thdvar_enum_t*) var)->typelib;
 
1453
  else
 
1454
    typelib= ((sysvar_enum_t*) var)->typelib;
 
1455
 
 
1456
  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
 
1457
  {
 
1458
    length= sizeof(buff);
 
1459
    if (!(str= value->val_str(value, buff, &length)))
 
1460
      goto err;
 
1461
    if ((result= (long)find_type(typelib, str, length, 1)-1) < 0)
 
1462
    {
 
1463
      strvalue= str;
 
1464
      goto err;
 
1465
    }
 
1466
  }
 
1467
  else
 
1468
  {
 
1469
    if (value->val_int(value, &tmp))
 
1470
      goto err;
 
1471
    if (tmp >= typelib->count)
 
1472
    {
 
1473
      llstr(tmp, buff);
 
1474
      strvalue= buff;
 
1475
      goto err;
 
1476
    }
 
1477
    result= (long) tmp;
 
1478
  }
 
1479
  *(long*)save= result;
 
1480
  return 0;
 
1481
err:
 
1482
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
 
1483
  return 1;
 
1484
}
 
1485
 
 
1486
 
 
1487
static int check_func_set(THD *thd __attribute__((unused)),
 
1488
                          struct st_mysql_sys_var *var,
 
1489
                          void *save, st_mysql_value *value)
 
1490
{
 
1491
  char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
 
1492
  const char *strvalue= "NULL", *str;
 
1493
  TYPELIB *typelib;
 
1494
  uint64_t result;
 
1495
  uint error_len;
 
1496
  bool not_used;
 
1497
  int length;
 
1498
 
 
1499
  if (var->flags & PLUGIN_VAR_THDLOCAL)
 
1500
    typelib= ((thdvar_set_t*) var)->typelib;
 
1501
  else
 
1502
    typelib= ((sysvar_set_t*)var)->typelib;
 
1503
 
 
1504
  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
 
1505
  {
 
1506
    length= sizeof(buff);
 
1507
    if (!(str= value->val_str(value, buff, &length)))
 
1508
      goto err;
 
1509
    result= find_set(typelib, str, length, NULL,
 
1510
                     &error, &error_len, &not_used);
 
1511
    if (error_len)
 
1512
    {
 
1513
      strmake(buff, error, min(sizeof(buff), error_len));
 
1514
      strvalue= buff;
 
1515
      goto err;
 
1516
    }
 
1517
  }
 
1518
  else
 
1519
  {
 
1520
    if (value->val_int(value, (int64_t *)&result))
 
1521
      goto err;
 
1522
    if (unlikely((result >= (1ULL << typelib->count)) &&
 
1523
                 (typelib->count < sizeof(long)*8)))
 
1524
    {
 
1525
      llstr(result, buff);
 
1526
      strvalue= buff;
 
1527
      goto err;
 
1528
    }
 
1529
  }
 
1530
  *(uint64_t*)save= result;
 
1531
  return 0;
 
1532
err:
 
1533
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
 
1534
  return 1;
 
1535
}
 
1536
 
 
1537
 
 
1538
static void update_func_bool(THD *thd __attribute__((unused)),
 
1539
                             struct st_mysql_sys_var *var __attribute__((unused)),
725
1540
                             void *tgt, const void *save)
726
1541
{
727
1542
  *(bool *) tgt= *(int *) save ? 1 : 0;
728
1543
}
729
1544
 
730
1545
 
731
 
static void update_func_int(Session *, drizzle_sys_var *,
 
1546
static void update_func_int(THD *thd __attribute__((unused)),
 
1547
                            struct st_mysql_sys_var *var __attribute__((unused)),
732
1548
                             void *tgt, const void *save)
733
1549
{
734
1550
  *(int *)tgt= *(int *) save;
735
1551
}
736
1552
 
737
1553
 
738
 
static void update_func_long(Session *, drizzle_sys_var *,
 
1554
static void update_func_long(THD *thd __attribute__((unused)),
 
1555
                             struct st_mysql_sys_var *var __attribute__((unused)),
739
1556
                             void *tgt, const void *save)
740
1557
{
741
1558
  *(long *)tgt= *(long *) save;
742
1559
}
743
1560
 
744
1561
 
745
 
static void update_func_int64_t(Session *, drizzle_sys_var *,
 
1562
static void update_func_int64_t(THD *thd __attribute__((unused)),
 
1563
                                 struct st_mysql_sys_var *var __attribute__((unused)),
746
1564
                                 void *tgt, const void *save)
747
1565
{
748
1566
  *(int64_t *)tgt= *(uint64_t *) save;
749
1567
}
750
1568
 
751
1569
 
752
 
static void update_func_str(Session *, drizzle_sys_var *var,
 
1570
static void update_func_str(THD *thd __attribute__((unused)), struct st_mysql_sys_var *var,
753
1571
                             void *tgt, const void *save)
754
1572
{
755
1573
  char *old= *(char **) tgt;
756
1574
  *(char **)tgt= *(char **) save;
757
1575
  if (var->flags & PLUGIN_VAR_MEMALLOC)
758
1576
  {
759
 
    *(char **)tgt= strdup(*(char **) save);
760
 
    free(old);
761
 
    /*
762
 
     * There isn't a _really_ good thing to do here until this whole set_var
763
 
     * mess gets redesigned
764
 
     */
765
 
    if (tgt == NULL)
766
 
      errmsg_printf(ERRMSG_LVL_ERROR, _("Out of memory."));
767
 
 
 
1577
    *(char **)tgt= my_strdup(*(char **) save, MYF(0));
 
1578
    my_free(old, MYF(0));
768
1579
  }
769
1580
}
770
1581
 
774
1585
****************************************************************************/
775
1586
 
776
1587
 
777
 
sys_var *find_sys_var(Session *, const char *str, uint32_t length)
 
1588
sys_var *find_sys_var(THD *thd, const char *str, uint length)
778
1589
{
779
1590
  sys_var *var;
780
1591
  sys_var_pluginvar *pi= NULL;
781
 
  module::Module *module;
 
1592
  plugin_ref plugin;
782
1593
 
 
1594
  rw_rdlock(&LOCK_system_variables_hash);
783
1595
  if ((var= intern_find_sys_var(str, length, false)) &&
784
1596
      (pi= var->cast_pluginvar()))
785
1597
  {
786
 
    if (!(module= pi->plugin))
 
1598
    rw_unlock(&LOCK_system_variables_hash);
 
1599
    LEX *lex= thd ? thd->lex : 0;
 
1600
    if (!(plugin= my_intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
787
1601
      var= NULL; /* failed to lock it, it must be uninstalling */
788
 
    else if (module->isInited == false)
 
1602
    else
 
1603
    if (!(plugin_state(plugin) & PLUGIN_IS_READY))
789
1604
    {
 
1605
      /* initialization not completed */
790
1606
      var= NULL;
 
1607
      intern_plugin_unlock(lex, plugin);
791
1608
    }
792
1609
  }
 
1610
  else
 
1611
    rw_unlock(&LOCK_system_variables_hash);
793
1612
 
794
1613
  /*
795
1614
    If the variable exists but the plugin it is associated with is not ready
800
1619
  return(var);
801
1620
}
802
1621
 
803
 
static const string make_bookmark_name(const string &plugin, const char *name)
804
 
{
805
 
  string varname(plugin);
806
 
  varname.push_back('_');
807
 
  varname.append(name);
808
 
 
809
 
  for (string::iterator p= varname.begin() + 1; p != varname.end(); ++p)
810
 
  {
811
 
    if (*p == '-')
812
 
    {
813
 
      *p= '_';
814
 
    }
815
 
  }
816
 
  return varname;
817
 
}
818
1622
 
819
1623
/*
820
1624
  called by register_var, construct_options and test_plugin_options.
821
1625
  Returns the 'bookmark' for the named variable.
822
1626
  LOCK_system_variables_hash should be at least read locked
823
1627
*/
824
 
static Bookmark *find_bookmark(const string &plugin, const char *name, int flags)
 
1628
static st_bookmark *find_bookmark(const char *plugin, const char *name, int flags)
825
1629
{
826
 
  if (!(flags & PLUGIN_VAR_SessionLOCAL))
 
1630
  st_bookmark *result= NULL;
 
1631
  uint namelen, length, pluginlen= 0;
 
1632
  char *varname, *p;
 
1633
 
 
1634
  if (!(flags & PLUGIN_VAR_THDLOCAL))
827
1635
    return NULL;
828
1636
 
829
 
  const string varname(make_bookmark_name(plugin, name));
 
1637
  namelen= strlen(name);
 
1638
  if (plugin)
 
1639
    pluginlen= strlen(plugin) + 1;
 
1640
  length= namelen + pluginlen + 2;
 
1641
  varname= (char*) my_alloca(length);
830
1642
 
831
 
  bookmark_unordered_map::iterator iter= bookmark_hash.find(varname);
832
 
  if (iter != bookmark_hash.end())
 
1643
  if (plugin)
833
1644
  {
834
 
    return &((*iter).second);
 
1645
    strxmov(varname + 1, plugin, "_", name, NullS);
 
1646
    for (p= varname + 1; *p; p++)
 
1647
      if (*p == '-')
 
1648
        *p= '_';
835
1649
  }
836
 
  return NULL;
 
1650
  else
 
1651
    memcpy(varname + 1, name, namelen + 1);
 
1652
 
 
1653
  varname[0]= flags & PLUGIN_VAR_TYPEMASK;
 
1654
 
 
1655
  result= (st_bookmark*) hash_search(&bookmark_hash,
 
1656
                                     (const uchar*) varname, length - 1);
 
1657
 
 
1658
  my_afree(varname);
 
1659
  return result;
837
1660
}
838
1661
 
839
1662
 
840
1663
/*
841
 
  returns a bookmark for session-local variables, creating if neccessary.
842
 
  returns null for non session-local variables.
 
1664
  returns a bookmark for thd-local variables, creating if neccessary.
 
1665
  returns null for non thd-local variables.
843
1666
  Requires that a write lock is obtained on LOCK_system_variables_hash
844
1667
*/
845
 
static Bookmark *register_var(const string &plugin, const char *name,
 
1668
static st_bookmark *register_var(const char *plugin, const char *name,
846
1669
                                 int flags)
847
1670
{
848
 
  if (!(flags & PLUGIN_VAR_SessionLOCAL))
 
1671
  uint length= strlen(plugin) + strlen(name) + 3, size= 0, offset, new_size;
 
1672
  st_bookmark *result;
 
1673
  char *varname, *p;
 
1674
 
 
1675
  if (!(flags & PLUGIN_VAR_THDLOCAL))
849
1676
    return NULL;
850
1677
 
851
 
  uint32_t size= 0, offset, new_size;
852
 
  Bookmark *result= NULL;
853
 
 
854
1678
  switch (flags & PLUGIN_VAR_TYPEMASK) {
855
1679
  case PLUGIN_VAR_BOOL:
856
 
    size= ALIGN_SIZE(sizeof(bool));
 
1680
    size= sizeof(bool);
857
1681
    break;
858
1682
  case PLUGIN_VAR_INT:
859
 
    size= ALIGN_SIZE(sizeof(int));
 
1683
    size= sizeof(int);
860
1684
    break;
861
1685
  case PLUGIN_VAR_LONG:
862
 
    size= ALIGN_SIZE(sizeof(long));
 
1686
  case PLUGIN_VAR_ENUM:
 
1687
    size= sizeof(long);
863
1688
    break;
864
1689
  case PLUGIN_VAR_LONGLONG:
865
 
    size= ALIGN_SIZE(sizeof(uint64_t));
 
1690
  case PLUGIN_VAR_SET:
 
1691
    size= sizeof(uint64_t);
866
1692
    break;
867
1693
  case PLUGIN_VAR_STR:
868
 
    size= ALIGN_SIZE(sizeof(char*));
 
1694
    size= sizeof(char*);
869
1695
    break;
870
1696
  default:
871
1697
    assert(0);
872
1698
    return NULL;
873
1699
  };
874
1700
 
 
1701
  varname= ((char*) my_alloca(length));
 
1702
  strxmov(varname + 1, plugin, "_", name, NullS);
 
1703
  for (p= varname + 1; *p; p++)
 
1704
    if (*p == '-')
 
1705
      *p= '_';
875
1706
 
876
 
  if (!(result= find_bookmark(plugin, name, flags)))
 
1707
  if (!(result= find_bookmark(NULL, varname + 1, flags)))
877
1708
  {
878
 
    const string varname(make_bookmark_name(plugin, name));
879
 
 
880
 
    Bookmark new_bookmark;
881
 
    new_bookmark.key= varname;
882
 
    new_bookmark.offset= -1;
 
1709
    result= (st_bookmark*) alloc_root(&plugin_mem_root,
 
1710
                                      sizeof(struct st_bookmark) + length-1);
 
1711
    varname[0]= flags & PLUGIN_VAR_TYPEMASK;
 
1712
    memcpy(result->key, varname, length);
 
1713
    result->name_len= length - 2;
 
1714
    result->offset= -1;
883
1715
 
884
1716
    assert(size && !(size & (size-1))); /* must be power of 2 */
885
1717
 
886
1718
    offset= global_system_variables.dynamic_variables_size;
887
1719
    offset= (offset + size - 1) & ~(size - 1);
888
 
    new_bookmark.offset= (int) offset;
 
1720
    result->offset= (int) offset;
889
1721
 
890
1722
    new_size= (offset + size + 63) & ~63;
891
1723
 
892
1724
    if (new_size > global_variables_dynamic_size)
893
1725
    {
894
 
      char* tmpptr= NULL;
895
 
      if (!(tmpptr=
896
 
              (char *)realloc(global_system_variables.dynamic_variables_ptr,
897
 
                              new_size)))
898
 
        return NULL;
899
 
      global_system_variables.dynamic_variables_ptr= tmpptr;
900
 
      tmpptr= NULL;
901
 
      if (!(tmpptr=
902
 
              (char *)realloc(max_system_variables.dynamic_variables_ptr,
903
 
                              new_size)))
904
 
        return NULL;
905
 
      max_system_variables.dynamic_variables_ptr= tmpptr;
906
 
           
 
1726
      global_system_variables.dynamic_variables_ptr= (char*)
 
1727
        my_realloc(global_system_variables.dynamic_variables_ptr, new_size,
 
1728
                   MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
 
1729
      max_system_variables.dynamic_variables_ptr= (char*)
 
1730
        my_realloc(max_system_variables.dynamic_variables_ptr, new_size,
 
1731
                   MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
907
1732
      /*
908
1733
        Clear the new variable value space. This is required for string
909
1734
        variables. If their value is non-NULL, it must point to a valid
913
1738
             global_variables_dynamic_size, 0,
914
1739
             new_size - global_variables_dynamic_size);
915
1740
      memset(max_system_variables.dynamic_variables_ptr +
916
 
             global_variables_dynamic_size, 0,
 
1741
             global_variables_dynamic_size, 0, 
917
1742
             new_size - global_variables_dynamic_size);
918
1743
      global_variables_dynamic_size= new_size;
919
1744
    }
925
1750
    global_system_variables.dynamic_variables_version++;
926
1751
    max_system_variables.dynamic_variables_version++;
927
1752
 
928
 
    new_bookmark.version= global_system_variables.dynamic_variables_version;
929
 
    new_bookmark.type_code= flags;
 
1753
    result->version= global_system_variables.dynamic_variables_version;
930
1754
 
931
1755
    /* this should succeed because we have already checked if a dup exists */
932
 
    bookmark_hash.insert(make_pair(varname, new_bookmark));
933
 
    result= find_bookmark(plugin, name, flags);
 
1756
    if (my_hash_insert(&bookmark_hash, (uchar*) result))
 
1757
    {
 
1758
      fprintf(stderr, "failed to add placeholder to hash");
 
1759
      assert(0);
 
1760
    }
934
1761
  }
 
1762
  my_afree(varname);
935
1763
  return result;
936
1764
}
937
1765
 
938
1766
 
939
1767
/*
940
 
  returns a pointer to the memory which holds the session-local variable or
941
 
  a pointer to the global variable if session==null.
 
1768
  returns a pointer to the memory which holds the thd-local variable or
 
1769
  a pointer to the global variable if thd==null.
942
1770
  If required, will sync with global variables if the requested variable
943
1771
  has not yet been allocated in the current thread.
944
1772
*/
945
 
static unsigned char *intern_sys_var_ptr(Session* session, int offset, bool global_lock)
 
1773
static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
946
1774
{
947
1775
  assert(offset >= 0);
948
 
  assert((uint32_t)offset <= global_system_variables.dynamic_variables_head);
 
1776
  assert((uint)offset <= global_system_variables.dynamic_variables_head);
949
1777
 
950
 
  if (!session)
951
 
    return (unsigned char*) global_system_variables.dynamic_variables_ptr + offset;
 
1778
  if (!thd)
 
1779
    return (uchar*) global_system_variables.dynamic_variables_ptr + offset;
952
1780
 
953
1781
  /*
954
1782
    dynamic_variables_head points to the largest valid offset
955
1783
  */
956
 
  if (!session->variables.dynamic_variables_ptr ||
957
 
      (uint32_t)offset > session->variables.dynamic_variables_head)
 
1784
  if (!thd->variables.dynamic_variables_ptr ||
 
1785
      (uint)offset > thd->variables.dynamic_variables_head)
958
1786
  {
959
 
    char *tmpptr= NULL;
960
 
    if (!(tmpptr= (char *)realloc(session->variables.dynamic_variables_ptr,
961
 
                                  global_variables_dynamic_size)))
962
 
      return NULL;
963
 
    session->variables.dynamic_variables_ptr= tmpptr;
 
1787
    uint idx;
 
1788
 
 
1789
    rw_rdlock(&LOCK_system_variables_hash);
 
1790
 
 
1791
    thd->variables.dynamic_variables_ptr= (char*)
 
1792
      my_realloc(thd->variables.dynamic_variables_ptr,
 
1793
                 global_variables_dynamic_size,
 
1794
                 MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
964
1795
 
965
1796
    if (global_lock)
966
 
      LOCK_global_system_variables.lock();
967
 
 
968
 
    //safe_mutex_assert_owner(&LOCK_global_system_variables);
969
 
 
970
 
    memcpy(session->variables.dynamic_variables_ptr +
971
 
             session->variables.dynamic_variables_size,
 
1797
      pthread_mutex_lock(&LOCK_global_system_variables);
 
1798
 
 
1799
    safe_mutex_assert_owner(&LOCK_global_system_variables);
 
1800
 
 
1801
    memcpy(thd->variables.dynamic_variables_ptr +
 
1802
             thd->variables.dynamic_variables_size,
972
1803
           global_system_variables.dynamic_variables_ptr +
973
 
             session->variables.dynamic_variables_size,
 
1804
             thd->variables.dynamic_variables_size,
974
1805
           global_system_variables.dynamic_variables_size -
975
 
             session->variables.dynamic_variables_size);
 
1806
             thd->variables.dynamic_variables_size);
976
1807
 
977
1808
    /*
978
1809
      now we need to iterate through any newly copied 'defaults'
979
1810
      and if it is a string type with MEMALLOC flag, we need to strdup
980
1811
    */
981
 
    bookmark_unordered_map::iterator iter= bookmark_hash.begin();
982
 
    for (; iter != bookmark_hash.end() ; ++iter)
 
1812
    for (idx= 0; idx < bookmark_hash.records; idx++)
983
1813
    {
984
1814
      sys_var_pluginvar *pi;
985
1815
      sys_var *var;
986
 
      const Bookmark &v= (*iter).second;
987
 
      const string var_name((*iter).first);
 
1816
      st_bookmark *v= (st_bookmark*) hash_element(&bookmark_hash,idx);
988
1817
 
989
 
      if (v.version <= session->variables.dynamic_variables_version ||
990
 
          !(var= intern_find_sys_var(var_name.c_str(), var_name.size(), true)) ||
 
1818
      if (v->version <= thd->variables.dynamic_variables_version ||
 
1819
          !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
991
1820
          !(pi= var->cast_pluginvar()) ||
992
 
          v.type_code != (pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
 
1821
          v->key[0] != (pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
993
1822
        continue;
994
1823
 
995
1824
      /* Here we do anything special that may be required of the data types */
997
1826
      if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
998
1827
          pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
999
1828
      {
1000
 
         char **pp= (char**) (session->variables.dynamic_variables_ptr +
 
1829
         char **pp= (char**) (thd->variables.dynamic_variables_ptr +
1001
1830
                             *(int*)(pi->plugin_var + 1));
1002
1831
         if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr +
1003
1832
                             *(int*)(pi->plugin_var + 1))))
1004
 
           *pp= strdup(*pp);
1005
 
         if (*pp == NULL)
1006
 
           return NULL;
 
1833
           *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
1007
1834
      }
1008
1835
    }
1009
1836
 
1010
1837
    if (global_lock)
1011
 
      LOCK_global_system_variables.unlock();
 
1838
      pthread_mutex_unlock(&LOCK_global_system_variables);
1012
1839
 
1013
 
    session->variables.dynamic_variables_version=
 
1840
    thd->variables.dynamic_variables_version=
1014
1841
           global_system_variables.dynamic_variables_version;
1015
 
    session->variables.dynamic_variables_head=
 
1842
    thd->variables.dynamic_variables_head=
1016
1843
           global_system_variables.dynamic_variables_head;
1017
 
    session->variables.dynamic_variables_size=
 
1844
    thd->variables.dynamic_variables_size=
1018
1845
           global_system_variables.dynamic_variables_size;
 
1846
 
 
1847
    rw_unlock(&LOCK_system_variables_hash);
1019
1848
  }
1020
 
  return (unsigned char*)session->variables.dynamic_variables_ptr + offset;
1021
 
}
1022
 
 
1023
 
static bool *mysql_sys_var_ptr_bool(Session* a_session, int offset)
1024
 
{
1025
 
  return (bool *)intern_sys_var_ptr(a_session, offset, true);
1026
 
}
1027
 
 
1028
 
static int *mysql_sys_var_ptr_int(Session* a_session, int offset)
1029
 
{
1030
 
  return (int *)intern_sys_var_ptr(a_session, offset, true);
1031
 
}
1032
 
 
1033
 
static long *mysql_sys_var_ptr_long(Session* a_session, int offset)
1034
 
{
1035
 
  return (long *)intern_sys_var_ptr(a_session, offset, true);
1036
 
}
1037
 
 
1038
 
static int64_t *mysql_sys_var_ptr_int64_t(Session* a_session, int offset)
1039
 
{
1040
 
  return (int64_t *)intern_sys_var_ptr(a_session, offset, true);
1041
 
}
1042
 
 
1043
 
static char **mysql_sys_var_ptr_str(Session* a_session, int offset)
1044
 
{
1045
 
  return (char **)intern_sys_var_ptr(a_session, offset, true);
1046
 
}
1047
 
 
1048
 
void plugin_sessionvar_init(Session *session)
1049
 
{
1050
 
  session->variables.storage_engine= NULL;
1051
 
  cleanup_variables(session, &session->variables);
1052
 
 
1053
 
  session->variables= global_system_variables;
1054
 
  session->variables.storage_engine= NULL;
 
1849
  return (uchar*)thd->variables.dynamic_variables_ptr + offset;
 
1850
}
 
1851
 
 
1852
static bool *mysql_sys_var_ptr_bool(THD* a_thd, int offset)
 
1853
{
 
1854
  return (bool *)intern_sys_var_ptr(a_thd, offset, true);
 
1855
}
 
1856
 
 
1857
static int *mysql_sys_var_ptr_int(THD* a_thd, int offset)
 
1858
{
 
1859
  return (int *)intern_sys_var_ptr(a_thd, offset, true);
 
1860
}
 
1861
 
 
1862
static long *mysql_sys_var_ptr_long(THD* a_thd, int offset)
 
1863
{
 
1864
  return (long *)intern_sys_var_ptr(a_thd, offset, true);
 
1865
}
 
1866
 
 
1867
static int64_t *mysql_sys_var_ptr_int64_t(THD* a_thd, int offset)
 
1868
{
 
1869
  return (int64_t *)intern_sys_var_ptr(a_thd, offset, true);
 
1870
}
 
1871
 
 
1872
static char **mysql_sys_var_ptr_str(THD* a_thd, int offset)
 
1873
{
 
1874
  return (char **)intern_sys_var_ptr(a_thd, offset, true);
 
1875
}
 
1876
 
 
1877
static uint64_t *mysql_sys_var_ptr_set(THD* a_thd, int offset)
 
1878
{
 
1879
  return (uint64_t *)intern_sys_var_ptr(a_thd, offset, true);
 
1880
}
 
1881
 
 
1882
static unsigned long *mysql_sys_var_ptr_enum(THD* a_thd, int offset)
 
1883
{
 
1884
  return (unsigned long *)intern_sys_var_ptr(a_thd, offset, true);
 
1885
}
 
1886
 
 
1887
 
 
1888
void plugin_thdvar_init(THD *thd)
 
1889
{
 
1890
  plugin_ref old_table_plugin= thd->variables.table_plugin;
 
1891
  
 
1892
  thd->variables.table_plugin= NULL;
 
1893
  cleanup_variables(thd, &thd->variables);
 
1894
  
 
1895
  thd->variables= global_system_variables;
 
1896
  thd->variables.table_plugin= NULL;
1055
1897
 
1056
1898
  /* we are going to allocate these lazily */
1057
 
  session->variables.dynamic_variables_version= 0;
1058
 
  session->variables.dynamic_variables_size= 0;
1059
 
  session->variables.dynamic_variables_ptr= 0;
 
1899
  thd->variables.dynamic_variables_version= 0;
 
1900
  thd->variables.dynamic_variables_size= 0;
 
1901
  thd->variables.dynamic_variables_ptr= 0;
1060
1902
 
1061
 
  session->variables.storage_engine= global_system_variables.storage_engine;
 
1903
  thd->variables.table_plugin=
 
1904
        my_intern_plugin_lock(NULL, global_system_variables.table_plugin);
 
1905
  intern_plugin_unlock(NULL, old_table_plugin);
 
1906
  return;
1062
1907
}
1063
1908
 
1064
1909
 
1065
1910
/*
1066
1911
  Unlocks all system variables which hold a reference
1067
1912
*/
1068
 
static void unlock_variables(Session *, struct system_variables *vars)
 
1913
static void unlock_variables(THD *thd __attribute__((unused)),
 
1914
                             struct system_variables *vars)
1069
1915
{
1070
 
  vars->storage_engine= NULL;
 
1916
  intern_plugin_unlock(NULL, vars->table_plugin);
 
1917
  vars->table_plugin= NULL;
1071
1918
}
1072
1919
 
1073
1920
 
1077
1924
  Unlike plugin_vars_free_values() it frees all variables of all plugins,
1078
1925
  it's used on shutdown.
1079
1926
*/
1080
 
static void cleanup_variables(Session *session, struct system_variables *vars)
 
1927
static void cleanup_variables(THD *thd, struct system_variables *vars)
1081
1928
{
 
1929
  st_bookmark *v;
1082
1930
  sys_var_pluginvar *pivar;
1083
1931
  sys_var *var;
1084
1932
  int flags;
 
1933
  uint idx;
1085
1934
 
1086
 
  bookmark_unordered_map::iterator iter= bookmark_hash.begin();
1087
 
  for (; iter != bookmark_hash.end() ; ++iter)
 
1935
  rw_rdlock(&LOCK_system_variables_hash);
 
1936
  for (idx= 0; idx < bookmark_hash.records; idx++)
1088
1937
  {
1089
 
    const Bookmark &v= (*iter).second;
1090
 
    const string key_name((*iter).first);
1091
 
    if (v.version > vars->dynamic_variables_version ||
1092
 
        !(var= intern_find_sys_var(key_name.c_str(), key_name.size(), true)) ||
 
1938
    v= (st_bookmark*) hash_element(&bookmark_hash, idx);
 
1939
    if (v->version > vars->dynamic_variables_version ||
 
1940
        !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
1093
1941
        !(pivar= var->cast_pluginvar()) ||
1094
 
        v.type_code != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
 
1942
        v->key[0] != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
1095
1943
      continue;
1096
1944
 
1097
1945
    flags= pivar->plugin_var->flags;
1098
1946
 
1099
1947
    if ((flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
1100
 
        flags & PLUGIN_VAR_SessionLOCAL && flags & PLUGIN_VAR_MEMALLOC)
 
1948
        flags & PLUGIN_VAR_THDLOCAL && flags & PLUGIN_VAR_MEMALLOC)
1101
1949
    {
1102
 
      char **ptr= (char**) pivar->real_value_ptr(session, OPT_SESSION);
1103
 
      free(*ptr);
 
1950
      char **ptr= (char**) pivar->real_value_ptr(thd, OPT_SESSION);
 
1951
      my_free(*ptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
1104
1952
      *ptr= NULL;
1105
1953
    }
1106
1954
  }
1107
 
 
1108
 
  assert(vars->storage_engine == NULL);
1109
 
 
1110
 
  free(vars->dynamic_variables_ptr);
 
1955
  rw_unlock(&LOCK_system_variables_hash);
 
1956
 
 
1957
  assert(vars->table_plugin == NULL);
 
1958
 
 
1959
  my_free(vars->dynamic_variables_ptr, MYF(MY_ALLOW_ZERO_PTR));
1111
1960
  vars->dynamic_variables_ptr= NULL;
1112
1961
  vars->dynamic_variables_size= 0;
1113
1962
  vars->dynamic_variables_version= 0;
1114
1963
}
1115
1964
 
1116
1965
 
1117
 
void plugin_sessionvar_cleanup(Session *session)
 
1966
void plugin_thdvar_cleanup(THD *thd)
1118
1967
{
1119
 
  unlock_variables(session, &session->variables);
1120
 
  cleanup_variables(session, &session->variables);
 
1968
  uint idx;
 
1969
  plugin_ref *list;
 
1970
 
 
1971
  unlock_variables(thd, &thd->variables);
 
1972
  cleanup_variables(thd, &thd->variables);
 
1973
 
 
1974
  if ((idx= thd->lex->plugins.elements))
 
1975
  {
 
1976
    list= ((plugin_ref*) thd->lex->plugins.buffer) + idx - 1;
 
1977
    while ((uchar*) list >= thd->lex->plugins.buffer)
 
1978
      intern_plugin_unlock(NULL, *list--);
 
1979
  }
 
1980
 
 
1981
  reset_dynamic(&thd->lex->plugins);
 
1982
 
 
1983
  return;
1121
1984
}
1122
1985
 
1123
1986
 
1135
1998
static void plugin_vars_free_values(sys_var *vars)
1136
1999
{
1137
2000
 
1138
 
  for (sys_var *var= vars; var; var= var->getNext())
 
2001
  for (sys_var *var= vars; var; var= var->next)
1139
2002
  {
1140
2003
    sys_var_pluginvar *piv= var->cast_pluginvar();
1141
2004
    if (piv &&
1144
2007
    {
1145
2008
      /* Free the string from global_system_variables. */
1146
2009
      char **valptr= (char**) piv->real_value_ptr(NULL, OPT_GLOBAL);
1147
 
      free(*valptr);
 
2010
      my_free(*valptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
1148
2011
      *valptr= NULL;
1149
2012
    }
1150
2013
  }
1182
2045
    return SHOW_LONGLONG;
1183
2046
  case PLUGIN_VAR_STR:
1184
2047
    return SHOW_CHAR_PTR;
 
2048
  case PLUGIN_VAR_ENUM:
 
2049
  case PLUGIN_VAR_SET:
 
2050
    return SHOW_CHAR;
1185
2051
  default:
1186
2052
    assert(0);
1187
2053
    return SHOW_UNDEF;
1189
2055
}
1190
2056
 
1191
2057
 
1192
 
unsigned char* sys_var_pluginvar::real_value_ptr(Session *session, sql_var_t type)
 
2058
uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type)
1193
2059
{
1194
 
  assert(session || (type == OPT_GLOBAL));
1195
 
  if (plugin_var->flags & PLUGIN_VAR_SessionLOCAL)
 
2060
  assert(thd || (type == OPT_GLOBAL));
 
2061
  if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
1196
2062
  {
1197
2063
    if (type == OPT_GLOBAL)
1198
 
      session= NULL;
 
2064
      thd= NULL;
1199
2065
 
1200
 
    return intern_sys_var_ptr(session, *(int*) (plugin_var+1), false);
 
2066
    return intern_sys_var_ptr(thd, *(int*) (plugin_var+1), false);
1201
2067
  }
1202
 
  return *(unsigned char**) (plugin_var+1);
 
2068
  return *(uchar**) (plugin_var+1);
1203
2069
}
1204
2070
 
1205
2071
 
1206
2072
TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
1207
2073
{
1208
 
  switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_SessionLOCAL)) {
1209
 
  case PLUGIN_VAR_SessionLOCAL:
1210
 
    return ((sessionvar_enum_t *)plugin_var)->typelib;
 
2074
  switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) {
 
2075
  case PLUGIN_VAR_ENUM:
 
2076
    return ((sysvar_enum_t *)plugin_var)->typelib;
 
2077
  case PLUGIN_VAR_SET:
 
2078
    return ((sysvar_set_t *)plugin_var)->typelib;
 
2079
  case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
 
2080
    return ((thdvar_enum_t *)plugin_var)->typelib;
 
2081
  case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
 
2082
    return ((thdvar_set_t *)plugin_var)->typelib;
1211
2083
  default:
1212
2084
    return NULL;
1213
2085
  }
1215
2087
}
1216
2088
 
1217
2089
 
1218
 
unsigned char* sys_var_pluginvar::value_ptr(Session *session, sql_var_t type, const LEX_STRING *)
 
2090
uchar* sys_var_pluginvar::value_ptr(THD *thd, enum_var_type type,
 
2091
                                    LEX_STRING *base __attribute__((unused)))
1219
2092
{
1220
 
  unsigned char* result;
1221
 
 
1222
 
  result= real_value_ptr(session, type);
1223
 
 
 
2093
  uchar* result;
 
2094
 
 
2095
  result= real_value_ptr(thd, type);
 
2096
 
 
2097
  if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_ENUM)
 
2098
    result= (uchar*) get_type(plugin_var_typelib(), *(ulong*)result);
 
2099
  else if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_SET)
 
2100
  {
 
2101
    char buffer[STRING_BUFFER_USUAL_SIZE];
 
2102
    String str(buffer, sizeof(buffer), system_charset_info);
 
2103
    TYPELIB *typelib= plugin_var_typelib();
 
2104
    uint64_t mask= 1, value= *(uint64_t*) result;
 
2105
    uint i;
 
2106
 
 
2107
    str.length(0);
 
2108
    for (i= 0; i < typelib->count; i++, mask<<=1)
 
2109
    {
 
2110
      if (!(value & mask))
 
2111
        continue;
 
2112
      str.append(typelib->type_names[i], typelib->type_lengths[i]);
 
2113
      str.append(',');
 
2114
    }
 
2115
 
 
2116
    result= (uchar*) "";
 
2117
    if (str.length())
 
2118
      result= (uchar*) thd->strmake(str.ptr(), str.length()-1);
 
2119
  }
1224
2120
  return result;
1225
2121
}
1226
2122
 
1227
2123
 
1228
 
bool sys_var_pluginvar::check(Session *session, set_var *var)
 
2124
bool sys_var_pluginvar::check(THD *thd, set_var *var)
1229
2125
{
1230
2126
  st_item_value_holder value;
1231
2127
  assert(is_readonly() || plugin_var->check);
1237
2133
  value.item= var->value;
1238
2134
 
1239
2135
  return is_readonly() ||
1240
 
         plugin_var->check(session, plugin_var, &var->save_result, &value);
 
2136
         plugin_var->check(thd, plugin_var, &var->save_result, &value);
1241
2137
}
1242
2138
 
1243
2139
 
1244
 
void sys_var_pluginvar::set_default(Session *session, sql_var_t type)
 
2140
void sys_var_pluginvar::set_default(THD *thd, enum_var_type type)
1245
2141
{
1246
2142
  const void *src;
1247
2143
  void *tgt;
1251
2147
  if (is_readonly())
1252
2148
    return;
1253
2149
 
1254
 
  LOCK_global_system_variables.lock();
1255
 
  tgt= real_value_ptr(session, type);
 
2150
  pthread_mutex_lock(&LOCK_global_system_variables);
 
2151
  tgt= real_value_ptr(thd, type);
1256
2152
  src= ((void **) (plugin_var + 1) + 1);
1257
2153
 
1258
 
  if (plugin_var->flags & PLUGIN_VAR_SessionLOCAL)
 
2154
  if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
1259
2155
  {
1260
2156
    if (type != OPT_GLOBAL)
1261
 
      src= real_value_ptr(session, OPT_GLOBAL);
 
2157
      src= real_value_ptr(thd, OPT_GLOBAL);
1262
2158
    else
1263
2159
    switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
1264
2160
        case PLUGIN_VAR_INT:
1265
 
          src= &((sessionvar_uint_t*) plugin_var)->def_val;
 
2161
          src= &((thdvar_uint_t*) plugin_var)->def_val;
1266
2162
          break;
1267
2163
        case PLUGIN_VAR_LONG:
1268
 
          src= &((sessionvar_ulong_t*) plugin_var)->def_val;
 
2164
          src= &((thdvar_ulong_t*) plugin_var)->def_val;
1269
2165
          break;
1270
2166
        case PLUGIN_VAR_LONGLONG:
1271
 
          src= &((sessionvar_uint64_t_t*) plugin_var)->def_val;
 
2167
          src= &((thdvar_uint64_t_t*) plugin_var)->def_val;
 
2168
          break;
 
2169
        case PLUGIN_VAR_ENUM:
 
2170
          src= &((thdvar_enum_t*) plugin_var)->def_val;
 
2171
          break;
 
2172
        case PLUGIN_VAR_SET:
 
2173
          src= &((thdvar_set_t*) plugin_var)->def_val;
1272
2174
          break;
1273
2175
        case PLUGIN_VAR_BOOL:
1274
 
          src= &((sessionvar_bool_t*) plugin_var)->def_val;
 
2176
          src= &((thdvar_bool_t*) plugin_var)->def_val;
1275
2177
          break;
1276
2178
        case PLUGIN_VAR_STR:
1277
 
          src= &((sessionvar_str_t*) plugin_var)->def_val;
 
2179
          src= &((thdvar_str_t*) plugin_var)->def_val;
1278
2180
          break;
1279
2181
        default:
1280
2182
          assert(0);
1281
2183
        }
1282
2184
  }
1283
2185
 
1284
 
  /* session must equal current_session if PLUGIN_VAR_SessionLOCAL flag is set */
1285
 
  assert(!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) ||
1286
 
              session == current_session);
 
2186
  /* thd must equal current_thd if PLUGIN_VAR_THDLOCAL flag is set */
 
2187
  assert(!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ||
 
2188
              thd == current_thd);
1287
2189
 
1288
 
  if (!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) || type == OPT_GLOBAL)
 
2190
  if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || type == OPT_GLOBAL)
1289
2191
  {
1290
 
    plugin_var->update(session, plugin_var, tgt, src);
1291
 
    LOCK_global_system_variables.unlock();
 
2192
    plugin_var->update(thd, plugin_var, tgt, src);
 
2193
    pthread_mutex_unlock(&LOCK_global_system_variables);
1292
2194
  }
1293
2195
  else
1294
2196
  {
1295
 
    LOCK_global_system_variables.unlock();
1296
 
    plugin_var->update(session, plugin_var, tgt, src);
 
2197
    pthread_mutex_unlock(&LOCK_global_system_variables);
 
2198
    plugin_var->update(thd, plugin_var, tgt, src);
1297
2199
  }
1298
2200
}
1299
2201
 
1300
2202
 
1301
 
bool sys_var_pluginvar::update(Session *session, set_var *var)
 
2203
bool sys_var_pluginvar::update(THD *thd, set_var *var)
1302
2204
{
1303
2205
  void *tgt;
1304
2206
 
1305
2207
  assert(is_readonly() || plugin_var->update);
1306
2208
 
1307
 
  /* session must equal current_session if PLUGIN_VAR_SessionLOCAL flag is set */
1308
 
  assert(!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) ||
1309
 
              session == current_session);
 
2209
  /* thd must equal current_thd if PLUGIN_VAR_THDLOCAL flag is set */
 
2210
  assert(!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ||
 
2211
              thd == current_thd);
1310
2212
 
1311
2213
  if (is_readonly())
1312
2214
    return 1;
1313
2215
 
1314
 
  LOCK_global_system_variables.lock();
1315
 
  tgt= real_value_ptr(session, var->type);
 
2216
  pthread_mutex_lock(&LOCK_global_system_variables);
 
2217
  tgt= real_value_ptr(thd, var->type);
1316
2218
 
1317
 
  if (!(plugin_var->flags & PLUGIN_VAR_SessionLOCAL) || var->type == OPT_GLOBAL)
 
2219
  if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || var->type == OPT_GLOBAL)
1318
2220
  {
1319
2221
    /* variable we are updating has global scope, so we unlock after updating */
1320
 
    plugin_var->update(session, plugin_var, tgt, &var->save_result);
1321
 
    LOCK_global_system_variables.unlock();
 
2222
    plugin_var->update(thd, plugin_var, tgt, &var->save_result);
 
2223
    pthread_mutex_unlock(&LOCK_global_system_variables);
1322
2224
  }
1323
2225
  else
1324
2226
  {
1325
 
    LOCK_global_system_variables.unlock();
1326
 
    plugin_var->update(session, plugin_var, tgt, &var->save_result);
 
2227
    pthread_mutex_unlock(&LOCK_global_system_variables);
 
2228
    plugin_var->update(thd, plugin_var, tgt, &var->save_result);
1327
2229
  }
1328
2230
 return 0;
1329
2231
}
1330
2232
 
1331
2233
 
1332
2234
#define OPTION_SET_LIMITS(type, options, opt) \
1333
 
  options->var_type= type;                    \
1334
 
  options->def_value= (opt)->def_val;         \
1335
 
  options->min_value= (opt)->min_val;         \
1336
 
  options->max_value= (opt)->max_val;         \
 
2235
  options->var_type= type; \
 
2236
  options->def_value= (opt)->def_val; \
 
2237
  options->min_value= (opt)->min_val; \
 
2238
  options->max_value= (opt)->max_val; \
1337
2239
  options->block_size= (long) (opt)->blk_sz
1338
2240
 
1339
2241
 
1340
 
void plugin_opt_set_limits(struct option *options,
1341
 
                                                                                                         const drizzle_sys_var *opt)
 
2242
static void plugin_opt_set_limits(struct my_option *options,
 
2243
                                  const struct st_mysql_sys_var *opt)
1342
2244
{
1343
2245
  options->sub_size= 0;
1344
2246
 
1345
2247
  switch (opt->flags & (PLUGIN_VAR_TYPEMASK |
1346
 
                        PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL)) {
 
2248
                        PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL)) {
1347
2249
  /* global system variables */
1348
2250
  case PLUGIN_VAR_INT:
1349
2251
    OPTION_SET_LIMITS(GET_INT, options, (sysvar_int_t*) opt);
1355
2257
    OPTION_SET_LIMITS(GET_LONG, options, (sysvar_long_t*) opt);
1356
2258
    break;
1357
2259
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
1358
 
    OPTION_SET_LIMITS(GET_ULONG_IS_FAIL, options, (sysvar_ulong_t*) opt);
 
2260
    OPTION_SET_LIMITS(GET_ULONG, options, (sysvar_ulong_t*) opt);
1359
2261
    break;
1360
2262
  case PLUGIN_VAR_LONGLONG:
1361
2263
    OPTION_SET_LIMITS(GET_LL, options, (sysvar_int64_t_t*) opt);
1363
2265
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
1364
2266
    OPTION_SET_LIMITS(GET_ULL, options, (sysvar_uint64_t_t*) opt);
1365
2267
    break;
 
2268
  case PLUGIN_VAR_ENUM:
 
2269
    options->var_type= GET_ENUM;
 
2270
    options->typelib= ((sysvar_enum_t*) opt)->typelib;
 
2271
    options->def_value= ((sysvar_enum_t*) opt)->def_val;
 
2272
    options->min_value= options->block_size= 0;
 
2273
    options->max_value= options->typelib->count - 1;
 
2274
    break;
 
2275
  case PLUGIN_VAR_SET:
 
2276
    options->var_type= GET_SET;
 
2277
    options->typelib= ((sysvar_set_t*) opt)->typelib;
 
2278
    options->def_value= ((sysvar_set_t*) opt)->def_val;
 
2279
    options->min_value= options->block_size= 0;
 
2280
    options->max_value= (1ULL << options->typelib->count) - 1;
 
2281
    break;
1366
2282
  case PLUGIN_VAR_BOOL:
1367
2283
    options->var_type= GET_BOOL;
1368
2284
    options->def_value= ((sysvar_bool_t*) opt)->def_val;
1373
2289
    options->def_value= (intptr_t) ((sysvar_str_t*) opt)->def_val;
1374
2290
    break;
1375
2291
  /* threadlocal variables */
1376
 
  case PLUGIN_VAR_INT | PLUGIN_VAR_SessionLOCAL:
1377
 
    OPTION_SET_LIMITS(GET_INT, options, (sessionvar_int_t*) opt);
1378
 
    break;
1379
 
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL:
1380
 
    OPTION_SET_LIMITS(GET_UINT, options, (sessionvar_uint_t*) opt);
1381
 
    break;
1382
 
  case PLUGIN_VAR_LONG | PLUGIN_VAR_SessionLOCAL:
1383
 
    OPTION_SET_LIMITS(GET_LONG, options, (sessionvar_long_t*) opt);
1384
 
    break;
1385
 
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL:
1386
 
    OPTION_SET_LIMITS(GET_ULONG_IS_FAIL, options, (sessionvar_ulong_t*) opt);
1387
 
    break;
1388
 
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_SessionLOCAL:
1389
 
    OPTION_SET_LIMITS(GET_LL, options, (sessionvar_int64_t_t*) opt);
1390
 
    break;
1391
 
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_SessionLOCAL:
1392
 
    OPTION_SET_LIMITS(GET_ULL, options, (sessionvar_uint64_t_t*) opt);
1393
 
    break;
1394
 
  case PLUGIN_VAR_BOOL | PLUGIN_VAR_SessionLOCAL:
 
2292
  case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
 
2293
    OPTION_SET_LIMITS(GET_INT, options, (thdvar_int_t*) opt);
 
2294
    break;
 
2295
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
 
2296
    OPTION_SET_LIMITS(GET_UINT, options, (thdvar_uint_t*) opt);
 
2297
    break;
 
2298
  case PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL:
 
2299
    OPTION_SET_LIMITS(GET_LONG, options, (thdvar_long_t*) opt);
 
2300
    break;
 
2301
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
 
2302
    OPTION_SET_LIMITS(GET_ULONG, options, (thdvar_ulong_t*) opt);
 
2303
    break;
 
2304
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL:
 
2305
    OPTION_SET_LIMITS(GET_LL, options, (thdvar_int64_t_t*) opt);
 
2306
    break;
 
2307
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
 
2308
    OPTION_SET_LIMITS(GET_ULL, options, (thdvar_uint64_t_t*) opt);
 
2309
    break;
 
2310
  case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
 
2311
    options->var_type= GET_ENUM;
 
2312
    options->typelib= ((thdvar_enum_t*) opt)->typelib;
 
2313
    options->def_value= ((thdvar_enum_t*) opt)->def_val;
 
2314
    options->min_value= options->block_size= 0;
 
2315
    options->max_value= options->typelib->count - 1;
 
2316
    break;
 
2317
  case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
 
2318
    options->var_type= GET_SET;
 
2319
    options->typelib= ((thdvar_set_t*) opt)->typelib;
 
2320
    options->def_value= ((thdvar_set_t*) opt)->def_val;
 
2321
    options->min_value= options->block_size= 0;
 
2322
    options->max_value= (1ULL << options->typelib->count) - 1;
 
2323
    break;
 
2324
  case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL:
1395
2325
    options->var_type= GET_BOOL;
1396
 
    options->def_value= ((sessionvar_bool_t*) opt)->def_val;
 
2326
    options->def_value= ((thdvar_bool_t*) opt)->def_val;
1397
2327
    break;
1398
 
  case PLUGIN_VAR_STR | PLUGIN_VAR_SessionLOCAL:
 
2328
  case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL:
1399
2329
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
1400
2330
                        GET_STR_ALLOC : GET_STR);
1401
 
    options->def_value= (intptr_t) ((sessionvar_str_t*) opt)->def_val;
 
2331
    options->def_value= (intptr_t) ((thdvar_str_t*) opt)->def_val;
1402
2332
    break;
1403
2333
  default:
1404
2334
    assert(0);
1410
2340
    options->arg_type= OPT_ARG;
1411
2341
}
1412
2342
 
1413
 
static int construct_options(memory::Root *mem_root, module::Module *tmp,
1414
 
                             option *options)
1415
 
{
1416
 
  
1417
 
  int localoptionid= 256;
1418
 
  const string plugin_name(tmp->getManifest().name);
1419
 
 
1420
 
  size_t namelen= plugin_name.size(), optnamelen;
1421
 
 
 
2343
extern "C" bool get_one_plugin_option(int optid, const struct my_option *,
 
2344
                                         char *);
 
2345
 
 
2346
bool get_one_plugin_option(int optid __attribute__((unused)),
 
2347
                              const struct my_option *opt __attribute__((unused)),
 
2348
                              char *argument __attribute__((unused)))
 
2349
{
 
2350
  return 0;
 
2351
}
 
2352
 
 
2353
 
 
2354
static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
 
2355
                             my_option *options, bool can_disable)
 
2356
{
 
2357
  const char *plugin_name= tmp->plugin->name;
 
2358
  uint namelen= strlen(plugin_name), optnamelen;
 
2359
  uint buffer_length= namelen * 4 + (can_disable ? 75 : 10);
 
2360
  char *name= (char*) alloc_root(mem_root, buffer_length) + 1;
1422
2361
  char *optname, *p;
1423
2362
  int index= 0, offset= 0;
1424
 
  drizzle_sys_var *opt, **plugin_option;
1425
 
  Bookmark *v;
1426
 
 
1427
 
  string name(plugin_name);
1428
 
  transform(name.begin(), name.end(), name.begin(), ::tolower);
1429
 
 
1430
 
  for (string::iterator iter= name.begin(); iter != name.end(); ++iter)
 
2363
  st_mysql_sys_var *opt, **plugin_option;
 
2364
  st_bookmark *v;
 
2365
 
 
2366
  /* support --skip-plugin-foo syntax */
 
2367
  memcpy(name, plugin_name, namelen + 1);
 
2368
  my_casedn_str(&my_charset_latin1, name);
 
2369
  strxmov(name + namelen + 1, "plugin-", name, NullS);
 
2370
  /* Now we have namelen + 1 + 7 + namelen + 1 == namelen * 2 + 9. */
 
2371
 
 
2372
  for (p= name + namelen*2 + 8; p > name; p--)
 
2373
    if (*p == '_')
 
2374
      *p= '-';
 
2375
 
 
2376
  if (can_disable)
1431
2377
  {
1432
 
    if (*iter == '_')
1433
 
      *iter= '-';
 
2378
    strxmov(name + namelen*2 + 10, "Enable ", plugin_name, " plugin. "
 
2379
            "Disable with --skip-", name," (will save memory).", NullS);
 
2380
    /*
 
2381
      Now we have namelen * 2 + 10 (one char unused) + 7 + namelen + 9 +
 
2382
      20 + namelen + 20 + 1 == namelen * 4 + 67.
 
2383
    */
 
2384
 
 
2385
    options[0].comment= name + namelen*2 + 10;
1434
2386
  }
1435
2387
 
 
2388
  options[1].name= (options[0].name= name) + namelen + 1;
 
2389
  options[0].id= options[1].id= 256; /* must be >255. dup id ok */
 
2390
  options[0].var_type= options[1].var_type= GET_BOOL;
 
2391
  options[0].arg_type= options[1].arg_type= NO_ARG;
 
2392
  options[0].def_value= options[1].def_value= true;
 
2393
  options[0].value= options[0].u_max_value=
 
2394
  options[1].value= options[1].u_max_value= (char**) (name - 1);
 
2395
  options+= 2;
 
2396
 
1436
2397
  /*
1437
2398
    Two passes as the 2nd pass will take pointer addresses for use
1438
2399
    by my_getopt and register_var() in the first pass uses realloc
1439
2400
  */
1440
2401
 
1441
 
  for (plugin_option= tmp->getManifest().system_vars;
 
2402
  for (plugin_option= tmp->plugin->system_vars;
1442
2403
       plugin_option && *plugin_option; plugin_option++, index++)
1443
2404
  {
1444
2405
    opt= *plugin_option;
1445
 
    if (!(opt->flags & PLUGIN_VAR_SessionLOCAL))
 
2406
    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
1446
2407
      continue;
1447
2408
    if (!(register_var(name, opt->name, opt->flags)))
1448
2409
      continue;
1449
2410
    switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
1450
2411
    case PLUGIN_VAR_BOOL:
1451
 
      (((sessionvar_bool_t *)opt)->resolve)= mysql_sys_var_ptr_bool;
 
2412
      (((thdvar_bool_t *)opt)->resolve)= mysql_sys_var_ptr_bool;
1452
2413
      break;
1453
2414
    case PLUGIN_VAR_INT:
1454
 
      (((sessionvar_int_t *)opt)->resolve)= mysql_sys_var_ptr_int;
 
2415
      (((thdvar_int_t *)opt)->resolve)= mysql_sys_var_ptr_int;
1455
2416
      break;
1456
2417
    case PLUGIN_VAR_LONG:
1457
 
      (((sessionvar_long_t *)opt)->resolve)= mysql_sys_var_ptr_long;
 
2418
      (((thdvar_long_t *)opt)->resolve)= mysql_sys_var_ptr_long;
1458
2419
      break;
1459
2420
    case PLUGIN_VAR_LONGLONG:
1460
 
      (((sessionvar_int64_t_t *)opt)->resolve)= mysql_sys_var_ptr_int64_t;
 
2421
      (((thdvar_int64_t_t *)opt)->resolve)= mysql_sys_var_ptr_int64_t;
1461
2422
      break;
1462
2423
    case PLUGIN_VAR_STR:
1463
 
      (((sessionvar_str_t *)opt)->resolve)= mysql_sys_var_ptr_str;
 
2424
      (((thdvar_str_t *)opt)->resolve)= mysql_sys_var_ptr_str;
 
2425
      break;
 
2426
    case PLUGIN_VAR_ENUM:
 
2427
      (((thdvar_enum_t *)opt)->resolve)= mysql_sys_var_ptr_enum;
 
2428
      break;
 
2429
    case PLUGIN_VAR_SET:
 
2430
      (((thdvar_set_t *)opt)->resolve)= mysql_sys_var_ptr_set;
1464
2431
      break;
1465
2432
    default:
1466
 
      errmsg_printf(ERRMSG_LVL_ERROR, _("Unknown variable type code 0x%x in plugin '%s'."),
1467
 
                      opt->flags, plugin_name.c_str());
 
2433
      sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
 
2434
                      opt->flags, plugin_name);
1468
2435
      return(-1);
1469
2436
    };
1470
2437
  }
1471
2438
 
1472
 
  for (plugin_option= tmp->getManifest().system_vars;
 
2439
  for (plugin_option= tmp->plugin->system_vars;
1473
2440
       plugin_option && *plugin_option; plugin_option++, index++)
1474
2441
  {
1475
2442
    switch ((opt= *plugin_option)->flags & PLUGIN_VAR_TYPEMASK) {
1506
2473
        if ((opt->flags & (PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY)) == false)
1507
2474
        {
1508
2475
          opt->flags|= PLUGIN_VAR_READONLY;
1509
 
          errmsg_printf(ERRMSG_LVL_WARN, _("Server variable %s of plugin %s was forced "
 
2476
          sql_print_warning("Server variable %s of plugin %s was forced "
1510
2477
                            "to be read-only: string variable without "
1511
 
                            "update_func and PLUGIN_VAR_MEMALLOC flag"),
1512
 
                            opt->name, plugin_name.c_str());
 
2478
                            "update_func and PLUGIN_VAR_MEMALLOC flag",
 
2479
                            opt->name, plugin_name);
1513
2480
        }
1514
2481
      }
1515
2482
      break;
 
2483
    case PLUGIN_VAR_ENUM:
 
2484
      if (!opt->check)
 
2485
        opt->check= check_func_enum;
 
2486
      if (!opt->update)
 
2487
        opt->update= update_func_long;
 
2488
      break;
 
2489
    case PLUGIN_VAR_SET:
 
2490
      if (!opt->check)
 
2491
        opt->check= check_func_set;
 
2492
      if (!opt->update)
 
2493
        opt->update= update_func_int64_t;
 
2494
      break;
1516
2495
    default:
1517
 
      errmsg_printf(ERRMSG_LVL_ERROR, _("Unknown variable type code 0x%x in plugin '%s'."),
1518
 
                      opt->flags, plugin_name.c_str());
 
2496
      sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
 
2497
                      opt->flags, plugin_name);
1519
2498
      return(-1);
1520
2499
    }
1521
2500
 
1522
 
    if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_SessionLOCAL))
 
2501
    if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_THDLOCAL))
1523
2502
                    == PLUGIN_VAR_NOCMDOPT)
1524
2503
      continue;
1525
2504
 
1526
2505
    if (!opt->name)
1527
2506
    {
1528
 
      errmsg_printf(ERRMSG_LVL_ERROR, _("Missing variable name in plugin '%s'."),
1529
 
                    plugin_name.c_str());
 
2507
      sql_print_error("Missing variable name in plugin '%s'.",
 
2508
                      plugin_name);
1530
2509
      return(-1);
1531
2510
    }
1532
2511
 
1533
 
    if (!(opt->flags & PLUGIN_VAR_SessionLOCAL))
 
2512
    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
1534
2513
    {
1535
2514
      optnamelen= strlen(opt->name);
1536
 
      optname= (char*) mem_root->alloc_root(namelen + optnamelen + 2);
1537
 
      sprintf(optname, "%s-%s", name.c_str(), opt->name);
 
2515
      optname= (char*) alloc_root(mem_root, namelen + optnamelen + 2);
 
2516
      strxmov(optname, name, "-", opt->name, NullS);
1538
2517
      optnamelen= namelen + optnamelen + 1;
1539
2518
    }
1540
2519
    else
1542
2521
      /* this should not fail because register_var should create entry */
1543
2522
      if (!(v= find_bookmark(name, opt->name, opt->flags)))
1544
2523
      {
1545
 
        errmsg_printf(ERRMSG_LVL_ERROR, _("Thread local variable '%s' not allocated "
1546
 
                      "in plugin '%s'."), opt->name, plugin_name.c_str());
 
2524
        sql_print_error("Thread local variable '%s' not allocated "
 
2525
                        "in plugin '%s'.", opt->name, plugin_name);
1547
2526
        return(-1);
1548
2527
      }
1549
2528
 
1552
2531
      if (opt->flags & PLUGIN_VAR_NOCMDOPT)
1553
2532
        continue;
1554
2533
 
1555
 
      optname= (char*) mem_root->memdup_root(v->key.c_str(), (optnamelen= v->key.size()) + 1);
 
2534
      optname= (char*) memdup_root(mem_root, v->key + 1, 
 
2535
                                   (optnamelen= v->name_len) + 1);
1556
2536
    }
1557
2537
 
1558
2538
    /* convert '_' to '-' */
1563
2543
    options->name= optname;
1564
2544
    options->comment= opt->comment;
1565
2545
    options->app_type= opt;
1566
 
    options->id= localoptionid++;
 
2546
    options->id= (options-1)->id + 1;
1567
2547
 
1568
2548
    plugin_opt_set_limits(options, opt);
1569
2549
 
1570
 
    if (opt->flags & PLUGIN_VAR_SessionLOCAL)
 
2550
    if (opt->flags & PLUGIN_VAR_THDLOCAL)
1571
2551
      options->value= options->u_max_value= (char**)
1572
2552
        (global_system_variables.dynamic_variables_ptr + offset);
1573
2553
    else
1574
2554
      options->value= options->u_max_value= *(char***) (opt + 1);
1575
2555
 
1576
 
    options++;
 
2556
    options[1]= options[0];
 
2557
    options[1].name= p= (char*) alloc_root(mem_root, optnamelen + 8);
 
2558
    options[1].comment= 0; // hidden
 
2559
    strxmov(p, "plugin-", optname, NullS);
 
2560
 
 
2561
    options+= 2;
1577
2562
  }
1578
2563
 
1579
2564
  return(0);
1580
2565
}
1581
2566
 
1582
2567
 
1583
 
static option *construct_help_options(memory::Root *mem_root, module::Module *p)
 
2568
static my_option *construct_help_options(MEM_ROOT *mem_root,
 
2569
                                         struct st_plugin_int *p)
1584
2570
{
1585
 
  drizzle_sys_var **opt;
1586
 
  option *opts;
1587
 
  uint32_t count= EXTRA_OPTIONS;
1588
 
 
1589
 
  for (opt= p->getManifest().system_vars; opt && *opt; opt++, count++) {};
1590
 
 
1591
 
  opts= (option*)mem_root->alloc_root((sizeof(option) * count));
1592
 
  if (opts == NULL)
1593
 
    return NULL;
1594
 
 
1595
 
  memset(opts, 0, sizeof(option) * count);
1596
 
 
1597
 
  if (construct_options(mem_root, p, opts))
1598
 
    return NULL;
 
2571
  st_mysql_sys_var **opt;
 
2572
  my_option *opts;
 
2573
  bool can_disable;
 
2574
  uint count= EXTRA_OPTIONS;
 
2575
 
 
2576
  for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2) {};
 
2577
 
 
2578
  if (!(opts= (my_option*) alloc_root(mem_root, sizeof(my_option) * count)))
 
2579
    return(NULL);
 
2580
 
 
2581
  memset(opts, 0, sizeof(my_option) * count);
 
2582
 
 
2583
  if ((my_strcasecmp(&my_charset_latin1, p->name.str, "MyISAM") == 0))
 
2584
    can_disable= false;
 
2585
  else if ((my_strcasecmp(&my_charset_latin1, p->name.str, "MEMORY") == 0))
 
2586
    can_disable= false;
 
2587
  else
 
2588
    can_disable= true;
 
2589
 
 
2590
 
 
2591
  if (construct_options(mem_root, p, opts, can_disable))
 
2592
    return(NULL);
1599
2593
 
1600
2594
  return(opts);
1601
2595
}
1602
2596
 
1603
 
void drizzle_add_plugin_sysvar(sys_var_pluginvar *var)
1604
 
{
1605
 
  plugin_sysvar_vec.push_back(var);
1606
 
}
1607
 
 
1608
 
void drizzle_del_plugin_sysvar()
1609
 
{
1610
 
  vector<sys_var_pluginvar *>::iterator iter= plugin_sysvar_vec.begin();
1611
 
  while(iter != plugin_sysvar_vec.end())
1612
 
  {
1613
 
    delete *iter;
1614
 
    ++iter;
1615
 
  }
1616
 
  plugin_sysvar_vec.clear();
1617
 
}
1618
2597
 
1619
2598
/*
1620
2599
  SYNOPSIS
1621
2600
    test_plugin_options()
1622
2601
    tmp_root                    temporary scratch space
1623
2602
    plugin                      internal plugin structure
 
2603
    argc                        user supplied arguments
 
2604
    argv                        user supplied arguments
1624
2605
    default_enabled             default plugin enable status
1625
2606
  RETURNS:
1626
2607
    0 SUCCESS - plugin should be enabled/loaded
1627
2608
  NOTE:
1628
2609
    Requires that a write-lock is held on LOCK_system_variables_hash
1629
2610
*/
1630
 
static int test_plugin_options(memory::Root *module_root,
1631
 
                               module::Module *test_module,
1632
 
                               po::options_description &long_options)
 
2611
static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
 
2612
                               int *argc, char **argv)
1633
2613
{
1634
2614
  struct sys_var_chain chain= { NULL, NULL };
1635
 
  drizzle_sys_var **opt;
1636
 
  option *opts= NULL;
 
2615
  bool enabled_saved= true;
 
2616
  bool can_disable;
 
2617
  MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ?
 
2618
                      &tmp->mem_root : &plugin_mem_root;
 
2619
  st_mysql_sys_var **opt;
 
2620
  my_option *opts= NULL;
 
2621
  char *p, *varname;
1637
2622
  int error;
1638
 
  drizzle_sys_var *o;
1639
 
  Bookmark *var;
1640
 
  uint32_t len, count= EXTRA_OPTIONS;
1641
 
 
1642
 
  if (test_module->getManifest().init_options != NULL)
1643
 
  {
1644
 
    string plugin_section_title("Options used by ");
1645
 
    plugin_section_title.append(test_module->getName());
1646
 
    po::options_description module_options(plugin_section_title);
1647
 
    module::option_context opt_ctx(test_module->getName(),
1648
 
                                   module_options.add_options());
1649
 
    test_module->getManifest().init_options(opt_ctx);
1650
 
    long_options.add(module_options);
1651
 
 
1652
 
  }
1653
 
 
1654
 
  for (opt= test_module->getManifest().system_vars; opt && *opt; opt++)
1655
 
  {
1656
 
    count++;
1657
 
  }
1658
 
 
1659
 
  if (count > EXTRA_OPTIONS)
1660
 
  {
1661
 
    if (!(opts= (option*) module_root->alloc_root(sizeof(option) * count)))
1662
 
    {
1663
 
      errmsg_printf(ERRMSG_LVL_ERROR,
1664
 
                    _("Out of memory for plugin '%s'."),
1665
 
                    test_module->getName().c_str());
1666
 
      return(-1);
1667
 
    }
1668
 
    memset(opts, 0, sizeof(option) * count);
1669
 
 
1670
 
    if (construct_options(module_root, test_module, opts))
1671
 
    {
1672
 
      errmsg_printf(ERRMSG_LVL_ERROR,
1673
 
                    _("Bad options for plugin '%s'."),
1674
 
                    test_module->getName().c_str());
1675
 
      return(-1);
1676
 
    }
1677
 
 
 
2623
  st_mysql_sys_var *o;
 
2624
  sys_var *v;
 
2625
  struct st_bookmark *var;
 
2626
  uint len, count= EXTRA_OPTIONS;
 
2627
  assert(tmp->plugin && tmp->name.str);
 
2628
 
 
2629
  for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
 
2630
    count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
 
2631
 
 
2632
  if ((my_strcasecmp(&my_charset_latin1, tmp->name.str, "MyISAM") == 0))
 
2633
    can_disable= false;
 
2634
  else if ((my_strcasecmp(&my_charset_latin1, tmp->name.str, "MEMORY") == 0))
 
2635
    can_disable= false;
 
2636
  else
 
2637
    can_disable= true;
 
2638
 
 
2639
  if (count > EXTRA_OPTIONS || (*argc > 1))
 
2640
  {
 
2641
    if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count)))
 
2642
    {
 
2643
      sql_print_error("Out of memory for plugin '%s'.", tmp->name.str);
 
2644
      return(-1);
 
2645
    }
 
2646
    memset(opts, 0, sizeof(my_option) * count);
 
2647
 
 
2648
    if (construct_options(tmp_root, tmp, opts, can_disable))
 
2649
    {
 
2650
      sql_print_error("Bad options for plugin '%s'.", tmp->name.str);
 
2651
      return(-1);
 
2652
    }
 
2653
 
 
2654
    error= handle_options(argc, &argv, opts, get_one_plugin_option);
 
2655
    (*argc)++; /* add back one for the program name */
 
2656
 
 
2657
    if (error)
 
2658
    {
 
2659
       sql_print_error("Parsing options for plugin '%s' failed.",
 
2660
                       tmp->name.str);
 
2661
       goto err;
 
2662
    }
1678
2663
  }
1679
2664
 
1680
2665
  error= 1;
1681
2666
 
1682
2667
  {
1683
 
    for (opt= test_module->getManifest().system_vars; opt && *opt; opt++)
 
2668
    for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
1684
2669
    {
1685
 
      sys_var *v;
1686
2670
      if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
1687
2671
        continue;
1688
2672
 
1689
 
      if ((var= find_bookmark(test_module->getName(), o->name, o->flags)))
1690
 
      {
1691
 
        v= new sys_var_pluginvar(var->key.c_str(), o);
1692
 
      }
 
2673
      if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
 
2674
        v= new (mem_root) sys_var_pluginvar(var->key + 1, o);
1693
2675
      else
1694
2676
      {
1695
 
        len= test_module->getName().length() + strlen(o->name) + 2;
1696
 
        string vname(test_module->getName());
1697
 
        vname.push_back('-');
1698
 
        vname.append(o->name);
1699
 
        transform(vname.begin(), vname.end(), vname.begin(), ::tolower);
1700
 
        string::iterator p= vname.begin();      
1701
 
        while  (p != vname.end())
1702
 
        {
 
2677
        len= tmp->name.length + strlen(o->name) + 2;
 
2678
        varname= (char*) alloc_root(mem_root, len);
 
2679
        strxmov(varname, tmp->name.str, "-", o->name, NullS);
 
2680
        my_casedn_str(&my_charset_latin1, varname);
 
2681
 
 
2682
        for (p= varname; *p; p++)
1703
2683
          if (*p == '-')
1704
2684
            *p= '_';
1705
 
          ++p;
1706
 
        }
1707
2685
 
1708
 
        v= new sys_var_pluginvar(vname, o);
 
2686
        v= new (mem_root) sys_var_pluginvar(varname, o);
1709
2687
      }
1710
2688
      assert(v); /* check that an object was actually constructed */
1711
2689
 
1712
 
      drizzle_add_plugin_sysvar(static_cast<sys_var_pluginvar *>(v));
1713
2690
      /*
1714
2691
        Add to the chain of variables.
1715
2692
        Done like this for easier debugging so that the
1719
2696
    }
1720
2697
    if (chain.first)
1721
2698
    {
1722
 
      chain.last->setNext(NULL);
 
2699
      chain.last->next = NULL;
1723
2700
      if (mysql_add_sys_var_chain(chain.first, NULL))
1724
2701
      {
1725
 
        errmsg_printf(ERRMSG_LVL_ERROR,
1726
 
                      _("Plugin '%s' has conflicting system variables"),
1727
 
                      test_module->getName().c_str());
 
2702
        sql_print_error("Plugin '%s' has conflicting system variables",
 
2703
                        tmp->name.str);
1728
2704
        goto err;
1729
2705
      }
1730
 
      test_module->system_vars= chain.first;
 
2706
      tmp->system_vars= chain.first;
1731
2707
    }
1732
2708
    return(0);
1733
2709
  }
1734
2710
 
 
2711
  if (enabled_saved && global_system_variables.log_warnings)
 
2712
    sql_print_information("Plugin '%s' disabled by command line option",
 
2713
                          tmp->name.str);
1735
2714
err:
1736
2715
  if (opts)
1737
2716
    my_cleanup_options(opts);
1743
2722
  Help Verbose text with Plugin System Variables
1744
2723
****************************************************************************/
1745
2724
 
1746
 
class OptionCmp
1747
 
{
1748
 
public:
1749
 
  bool operator() (const option &a, const option &b)
1750
 
  {
1751
 
    return my_strcasecmp(&my_charset_utf8_general_ci, a.name, b.name);
1752
 
  }
1753
 
};
1754
 
 
1755
 
 
1756
 
void my_print_help_inc_plugins(option *main_options)
1757
 
{
1758
 
  module::Registry &registry= module::Registry::singleton();
1759
 
  vector<option> all_options;
1760
 
  memory::Root mem_root(4096);
1761
 
  option *opt= NULL;
1762
 
 
 
2725
static int option_cmp(my_option *a, my_option *b)
 
2726
{
 
2727
  return my_strcasecmp(&my_charset_latin1, a->name, b->name);
 
2728
}
 
2729
 
 
2730
 
 
2731
void my_print_help_inc_plugins(my_option *main_options, uint size)
 
2732
{
 
2733
  DYNAMIC_ARRAY all_options;
 
2734
  struct st_plugin_int *p;
 
2735
  MEM_ROOT mem_root;
 
2736
  my_option *opt;
 
2737
 
 
2738
  init_alloc_root(&mem_root, 4096, 4096);
 
2739
  my_init_dynamic_array(&all_options, sizeof(my_option), size, size/4);
1763
2740
 
1764
2741
  if (initialized)
1765
 
  {
1766
 
    std::map<std::string, module::Module *>::const_iterator modules=
1767
 
      registry.getModulesMap().begin();
1768
 
    
1769
 
    while (modules != registry.getModulesMap().end())
 
2742
    for (uint idx= 0; idx < plugin_array.elements; idx++)
1770
2743
    {
1771
 
      module::Module *p= (*modules).second;
1772
 
      ++modules;
1773
 
 
1774
 
      /* If we have an init_options function, we are registering
1775
 
         commmand line options that way, so don't do them this way */
1776
 
      if (p->getManifest().init_options != NULL)
1777
 
        continue;
1778
 
 
1779
 
      if (p->getManifest().system_vars == NULL)
1780
 
        continue;
1781
 
 
1782
 
      opt= construct_help_options(&mem_root, p);
1783
 
      if (opt == NULL)
 
2744
      p= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
 
2745
 
 
2746
      if (!p->plugin->system_vars ||
 
2747
          !(opt= construct_help_options(&mem_root, p)))
1784
2748
        continue;
1785
2749
 
1786
2750
      /* Only options with a non-NULL comment are displayed in help text */
1787
2751
      for (;opt->id; opt++)
1788
 
      {
1789
2752
        if (opt->comment)
1790
 
        {
1791
 
          all_options.push_back(*opt);
1792
 
          
1793
 
        }
1794
 
      }
 
2753
          insert_dynamic(&all_options, (uchar*) opt);
1795
2754
    }
1796
 
  }
1797
2755
 
1798
2756
  for (;main_options->id; main_options++)
1799
 
  {
1800
 
    if (main_options->comment)
1801
 
    {
1802
 
      all_options.push_back(*main_options);
1803
 
    }
1804
 
  }
 
2757
    insert_dynamic(&all_options, (uchar*) main_options);
1805
2758
 
1806
 
  /** 
1807
 
   * @TODO: Fix the option building so that it doens't break sort
1808
 
   *
1809
 
   * sort(all_options.begin(), all_options.end(), OptionCmp());
1810
 
   */
 
2759
  sort_dynamic(&all_options, (qsort_cmp) option_cmp);
1811
2760
 
1812
2761
  /* main_options now points to the empty option terminator */
1813
 
  all_options.push_back(*main_options);
1814
 
 
1815
 
  my_print_help(&*(all_options.begin()));
1816
 
 
1817
 
  mem_root.free_root(MYF(0));
 
2762
  insert_dynamic(&all_options, (uchar*) main_options);
 
2763
 
 
2764
  my_print_help((my_option*) all_options.buffer);
 
2765
  my_print_variables((my_option*) all_options.buffer);
 
2766
 
 
2767
  delete_dynamic(&all_options);
 
2768
  free_root(&mem_root, MYF(0));
1818
2769
}
1819
2770
 
1820
 
} /* namespace drizzled */
1821
 
 
1822