~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_plugin.cc

  • Committer: Jay Pipes
  • Date: 2008-09-11 16:03:22 UTC
  • mto: (383.5.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 386.
  • Revision ID: jay@mysql.com-20080911160322-vrl0k1djo6q6ytv1
Removed SQL_MODE variances from comment_table.test and ensured correct error thrown when a comment that is too long was input.  After moving to proto buffer definition for table, the 2048 length will go away.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
 
 
16
 
#include "config.h"
17
 
 
18
 
#include <dlfcn.h>
19
 
 
20
 
#include <cstdio>
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
 
#include <boost/foreach.hpp>
51
 
 
52
 
/* FreeBSD 2.2.2 does not define RTLD_NOW) */
53
 
#ifndef RTLD_NOW
54
 
#define RTLD_NOW 1
55
 
#endif
56
 
 
57
 
namespace po=boost::program_options;
58
 
 
59
 
using namespace std;
60
 
 
61
 
/** These exist just to prevent symbols from being optimized out */
62
 
typedef drizzled::module::Manifest drizzled_builtin_list[];
63
 
extern drizzled_builtin_list PANDORA_BUILTIN_SYMBOLS_LIST;
64
 
extern drizzled_builtin_list PANDORA_BUILTIN_LOAD_SYMBOLS_LIST;
65
 
drizzled::module::Manifest *drizzled_builtins[]=
66
 
{
67
 
  PANDORA_BUILTIN_SYMBOLS_LIST, NULL
68
 
};
69
 
drizzled::module::Manifest *drizzled_load_builtins[]=
70
 
{
71
 
  PANDORA_BUILTIN_LOAD_SYMBOLS_LIST, NULL
72
 
};
73
 
 
74
 
namespace drizzled
75
 
{
76
 
 
77
 
 
78
 
typedef vector<string> PluginOptions;
79
 
static PluginOptions opt_plugin_load;
80
 
static PluginOptions opt_plugin_add;
81
 
static PluginOptions opt_plugin_remove;
82
 
const char *builtin_plugins= PANDORA_BUILTIN_LIST;
83
 
const char *builtin_load_plugins= PANDORA_BUILTIN_LOAD_LIST;
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#include <drizzled/server_includes.h>
 
17
#include <mysys/my_getopt.h>
 
18
#include <authentication.h>
 
19
#include <drizzled/drizzled_error_messages.h>
 
20
#define REPORT_TO_LOG  1
 
21
#define REPORT_TO_USER 2
 
22
 
 
23
#define plugin_ref_to_int(A) (A ? A[0] : NULL)
 
24
#define plugin_int_to_ref(A) &(A)
 
25
 
 
26
extern struct st_mysql_plugin *mysqld_builtins[];
 
27
 
 
28
char *opt_plugin_load= NULL;
 
29
char *opt_plugin_dir_ptr;
 
30
char opt_plugin_dir[FN_REFLEN];
 
31
/*
 
32
  When you ad a new plugin type, add both a string and make sure that the
 
33
  init and deinit array are correctly updated.
 
34
*/
 
35
const LEX_STRING plugin_type_names[DRIZZLE_MAX_PLUGIN_TYPE_NUM]=
 
36
{
 
37
  { C_STRING_WITH_LEN("DAEMON") },
 
38
  { C_STRING_WITH_LEN("STORAGE ENGINE") },
 
39
  { C_STRING_WITH_LEN("INFORMATION SCHEMA") },
 
40
  { C_STRING_WITH_LEN("UDF") },
 
41
  { C_STRING_WITH_LEN("UDA") },
 
42
  { C_STRING_WITH_LEN("AUDIT") },
 
43
  { C_STRING_WITH_LEN("LOGGER") },
 
44
  { C_STRING_WITH_LEN("AUTH") }
 
45
};
 
46
 
 
47
extern int initialize_schema_table(st_plugin_int *plugin);
 
48
extern int finalize_schema_table(st_plugin_int *plugin);
 
49
 
 
50
extern int initialize_udf(st_plugin_int *plugin);
 
51
extern int finalize_udf(st_plugin_int *plugin);
 
52
 
 
53
/*
 
54
  The number of elements in both plugin_type_initialize and
 
55
  plugin_type_deinitialize should equal to the number of plugins
 
56
  defined.
 
57
*/
 
58
plugin_type_init plugin_type_initialize[DRIZZLE_MAX_PLUGIN_TYPE_NUM]=
 
59
{
 
60
  0,  /* Daemon */
 
61
  ha_initialize_handlerton,  /* Storage Engine */
 
62
  initialize_schema_table,  /* Information Schema */
 
63
  initialize_udf,  /* UDF */
 
64
  0,  /* UDA */
 
65
  0,  /* Audit */
 
66
  0,  /* Logger */
 
67
  authentication_initializer  /* Auth */
 
68
};
 
69
 
 
70
plugin_type_init plugin_type_deinitialize[DRIZZLE_MAX_PLUGIN_TYPE_NUM]=
 
71
{
 
72
  0,  /* Daemon */
 
73
  ha_finalize_handlerton,  /* Storage Engine */
 
74
  finalize_schema_table,  /* Information Schema */
 
75
  finalize_udf,  /* UDF */
 
76
  0,  /* UDA */
 
77
  0,  /* Audit */
 
78
  0,  /* Logger */
 
79
  authentication_finalizer  /* Auth */
 
80
};
 
81
 
 
82
static const char *plugin_declarations_sym= "_mysql_plugin_declarations_";
84
83
 
85
84
/* Note that 'int version' must be the first field of every plugin
86
85
   sub-structure (plugin->info).
87
86
*/
88
87
 
89
 
static bool initialized= false;
90
 
 
91
 
 
 
88
static bool initialized= 0;
 
89
 
 
90
static DYNAMIC_ARRAY plugin_dl_array;
 
91
static DYNAMIC_ARRAY plugin_array;
 
92
static HASH plugin_hash[DRIZZLE_MAX_PLUGIN_TYPE_NUM];
92
93
static bool reap_needed= false;
 
94
static int plugin_array_version=0;
93
95
 
94
96
/*
95
97
  write-lock on LOCK_system_variables_hash is required before modifying
96
98
  the following variables/structures
97
99
*/
98
 
static memory::Root plugin_mem_root(4096);
99
 
static uint32_t global_variables_dynamic_size= 0;
 
100
static MEM_ROOT plugin_mem_root;
 
101
static uint global_variables_dynamic_size= 0;
 
102
static HASH bookmark_hash;
100
103
 
101
104
 
102
105
/*
103
106
  hidden part of opaque value passed to variable check functions.
104
107
  Used to provide a object-like structure to non C++ consumers.
105
108
*/
106
 
struct st_item_value_holder : public drizzle_value
 
109
struct st_item_value_holder : public st_mysql_value
107
110
{
108
111
  Item *item;
109
112
};
110
113
 
111
 
class Bookmark
 
114
 
 
115
/*
 
116
  stored in bookmark_hash, this structure is never removed from the
 
117
  hash and is used to mark a single offset for a thd local variable
 
118
  even if plugins have been uninstalled and reinstalled, repeatedly.
 
119
  This structure is allocated from plugin_mem_root.
 
120
 
 
121
  The key format is as follows:
 
122
    1 byte         - variable type code
 
123
    name_len bytes - variable name
 
124
    '\0'           - end of key
 
125
*/
 
126
struct st_bookmark
112
127
{
113
 
public:
114
 
  Bookmark() :
115
 
    type_code(0),
116
 
    offset(0),
117
 
    version(0),
118
 
    key("")
119
 
  {}
120
 
  uint8_t type_code;
 
128
  uint name_len;
121
129
  int offset;
122
 
  uint32_t version;
123
 
  string key;
124
 
};
125
 
 
126
 
typedef boost::unordered_map<string, Bookmark> bookmark_unordered_map;
127
 
static bookmark_unordered_map bookmark_hash;
128
 
 
 
130
  uint version;
 
131
  char key[1];
 
132
};
 
133
 
 
134
 
 
135
/*
 
136
  skeleton of a plugin variable - portion of structure common to all.
 
137
*/
 
138
struct st_mysql_sys_var
 
139
{
 
140
  DRIZZLE_PLUGIN_VAR_HEADER;
 
141
};
 
142
 
 
143
 
 
144
/*
 
145
  sys_var class for access to all plugin variables visible to the user
 
146
*/
 
147
class sys_var_pluginvar: public sys_var
 
148
{
 
149
public:
 
150
  struct st_plugin_int *plugin;
 
151
  struct st_mysql_sys_var *plugin_var;
 
152
 
 
153
  static void *operator new(size_t size, MEM_ROOT *mem_root)
 
154
  { return (void*) alloc_root(mem_root, (uint) size); }
 
155
  static void operator delete(void *ptr_arg __attribute__((unused)),
 
156
                              size_t size __attribute__((unused)))
 
157
  { TRASH(ptr_arg, size); }
 
158
 
 
159
  sys_var_pluginvar(const char *name_arg,
 
160
                    struct st_mysql_sys_var *plugin_var_arg)
 
161
    :sys_var(name_arg), plugin_var(plugin_var_arg) {}
 
162
  sys_var_pluginvar *cast_pluginvar() { return this; }
 
163
  bool is_readonly() const { return plugin_var->flags & PLUGIN_VAR_READONLY; }
 
164
  bool check_type(enum_var_type type)
 
165
  { return !(plugin_var->flags & PLUGIN_VAR_THDLOCAL) && type != OPT_GLOBAL; }
 
166
  bool check_update_type(Item_result type);
 
167
  SHOW_TYPE show_type();
 
168
  uchar* real_value_ptr(THD *thd, enum_var_type type);
 
169
  TYPELIB* plugin_var_typelib(void);
 
170
  uchar* value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
 
171
  bool check(THD *thd, set_var *var);
 
172
  bool check_default(enum_var_type type __attribute__((unused)))
 
173
    { return is_readonly(); }
 
174
  void set_default(THD *thd,
 
175
                   enum_var_type type __attribute__((unused)));
 
176
  bool update(THD *thd, set_var *var);
 
177
};
129
178
 
130
179
 
131
180
/* prototypes */
132
 
static void plugin_prune_list(vector<string> &plugin_list,
133
 
                              const vector<string> &plugins_to_remove);
134
 
static bool plugin_load_list(module::Registry &registry,
135
 
                             memory::Root *tmp_root,
136
 
                             const set<string> &plugin_list,
137
 
                             po::options_description &long_options,
138
 
                             bool builtin= false);
139
 
static int test_plugin_options(memory::Root *, module::Module *,
140
 
                               po::options_description &long_options);
141
 
static void unlock_variables(Session *session, drizzle_system_variables *vars);
142
 
static void cleanup_variables(drizzle_system_variables *vars);
 
181
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
 
182
                             const char *list);
 
183
static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *,
 
184
                               int *, char **);
 
185
static bool register_builtin(struct st_mysql_plugin *, struct st_plugin_int *,
 
186
                             struct st_plugin_int **);
 
187
static void unlock_variables(THD *thd, struct system_variables *vars);
 
188
static void cleanup_variables(THD *thd, struct system_variables *vars);
 
189
static void plugin_vars_free_values(sys_var *vars);
 
190
static void plugin_opt_set_limits(struct my_option *options,
 
191
                                  const struct st_mysql_sys_var *opt);
 
192
#define my_intern_plugin_lock(A,B) intern_plugin_lock(A,B CALLER_INFO)
 
193
#define my_intern_plugin_lock_ci(A,B) intern_plugin_lock(A,B ORIG_CALLER_INFO)
 
194
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin
 
195
                                     CALLER_INFO_PROTO);
 
196
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
 
197
static void reap_plugins(void);
 
198
 
143
199
 
144
200
/* declared in set_var.cc */
145
 
extern sys_var *intern_find_sys_var(const char *str, uint32_t length, bool no_error);
 
201
extern sys_var *intern_find_sys_var(const char *str, uint length, bool no_error);
 
202
extern bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd,
 
203
                                 const char *name, int64_t val);
 
204
 
 
205
/****************************************************************************
 
206
  Value type thunks, allows the C world to play in the C++ world
 
207
****************************************************************************/
 
208
 
 
209
static int item_value_type(struct st_mysql_value *value)
 
210
{
 
211
  switch (((st_item_value_holder*)value)->item->result_type()) {
 
212
  case INT_RESULT:
 
213
    return DRIZZLE_VALUE_TYPE_INT;
 
214
  case REAL_RESULT:
 
215
    return DRIZZLE_VALUE_TYPE_REAL;
 
216
  default:
 
217
    return DRIZZLE_VALUE_TYPE_STRING;
 
218
  }
 
219
}
 
220
 
 
221
static const char *item_val_str(struct st_mysql_value *value,
 
222
                                char *buffer, int *length)
 
223
{
 
224
  String str(buffer, *length, system_charset_info), *res;
 
225
  if (!(res= ((st_item_value_holder*)value)->item->val_str(&str)))
 
226
    return NULL;
 
227
  *length= res->length();
 
228
  if (res->c_ptr_quick() == buffer)
 
229
    return buffer;
 
230
 
 
231
  /*
 
232
    Lets be nice and create a temporary string since the
 
233
    buffer was too small
 
234
  */
 
235
  return current_thd->strmake(res->c_ptr_quick(), res->length());
 
236
}
 
237
 
 
238
 
 
239
static int item_val_int(struct st_mysql_value *value, int64_t *buf)
 
240
{
 
241
  Item *item= ((st_item_value_holder*)value)->item;
 
242
  *buf= item->val_int();
 
243
  if (item->is_null())
 
244
    return 1;
 
245
  return 0;
 
246
}
 
247
 
 
248
 
 
249
static int item_val_real(struct st_mysql_value *value, double *buf)
 
250
{
 
251
  Item *item= ((st_item_value_holder*)value)->item;
 
252
  *buf= item->val_real();
 
253
  if (item->is_null())
 
254
    return 1;
 
255
  return 0;
 
256
}
146
257
 
147
258
 
148
259
/****************************************************************************
149
260
  Plugin support code
150
261
****************************************************************************/
151
262
 
152
 
 
 
263
static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl)
 
264
{
 
265
  uint i;
 
266
  struct st_plugin_dl *tmp;
 
267
  for (i= 0; i < plugin_dl_array.elements; i++)
 
268
  {
 
269
    tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
 
270
    if (tmp->ref_count &&
 
271
        ! my_strnncoll(files_charset_info,
 
272
                       (const uchar *)dl->str, dl->length,
 
273
                       (const uchar *)tmp->dl.str, tmp->dl.length))
 
274
      return(tmp);
 
275
  }
 
276
  return(0);
 
277
}
 
278
 
 
279
static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
 
280
{
 
281
  uint i;
 
282
  struct st_plugin_dl *tmp;
 
283
  for (i= 0; i < plugin_dl_array.elements; i++)
 
284
  {
 
285
    tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
 
286
    if (! tmp->ref_count)
 
287
    {
 
288
      memcpy(tmp, plugin_dl, sizeof(struct st_plugin_dl));
 
289
      return(tmp);
 
290
    }
 
291
  }
 
292
  if (insert_dynamic(&plugin_dl_array, (uchar*)&plugin_dl))
 
293
    return(0);
 
294
  tmp= *dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
 
295
                        struct st_plugin_dl **)=
 
296
      (struct st_plugin_dl *) memdup_root(&plugin_mem_root, (uchar*)plugin_dl,
 
297
                                           sizeof(struct st_plugin_dl));
 
298
  return(tmp);
 
299
}
 
300
 
 
301
static inline void free_plugin_mem(struct st_plugin_dl *p)
 
302
{
 
303
  if (p->handle)
 
304
    dlclose(p->handle);
 
305
  my_free(p->dl.str, MYF(MY_ALLOW_ZERO_PTR));
 
306
}
 
307
 
 
308
 
 
309
static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
 
310
{
 
311
  char dlpath[FN_REFLEN];
 
312
  uint plugin_dir_len, dummy_errors, dlpathlen;
 
313
  struct st_plugin_dl *tmp, plugin_dl;
 
314
  void *sym;
 
315
  plugin_dir_len= strlen(opt_plugin_dir);
 
316
  /*
 
317
    Ensure that the dll doesn't have a path.
 
318
    This is done to ensure that only approved libraries from the
 
319
    plugin directory are used (to make this even remotely secure).
 
320
  */
 
321
  if (strchr(dl->str, FN_LIBCHAR) ||
 
322
      check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN,
 
323
                               system_charset_info, 1) ||
 
324
      plugin_dir_len + dl->length + 1 >= FN_REFLEN)
 
325
  {
 
326
    if (report & REPORT_TO_USER)
 
327
      my_error(ER_UDF_NO_PATHS, MYF(0));
 
328
    if (report & REPORT_TO_LOG)
 
329
      sql_print_error(ER(ER_UDF_NO_PATHS));
 
330
    return(0);
 
331
  }
 
332
  /* If this dll is already loaded just increase ref_count. */
 
333
  if ((tmp= plugin_dl_find(dl)))
 
334
  {
 
335
    tmp->ref_count++;
 
336
    return(tmp);
 
337
  }
 
338
  memset(&plugin_dl, 0, sizeof(plugin_dl));
 
339
  /* Compile dll path */
 
340
  dlpathlen=
 
341
    strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS) -
 
342
    dlpath;
 
343
  plugin_dl.ref_count= 1;
 
344
  /* Open new dll handle */
 
345
  if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW)))
 
346
  {
 
347
    const char *errmsg=dlerror();
 
348
    if (!strncmp(dlpath, errmsg, dlpathlen))
 
349
    { // if errmsg starts from dlpath, trim this prefix.
 
350
      errmsg+=dlpathlen;
 
351
      if (*errmsg == ':') errmsg++;
 
352
      if (*errmsg == ' ') errmsg++;
 
353
    }
 
354
    if (report & REPORT_TO_USER)
 
355
      my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, errno, errmsg);
 
356
    if (report & REPORT_TO_LOG)
 
357
      sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, errno, errmsg);
 
358
    return(0);
 
359
  }
 
360
 
 
361
  /* Find plugin declarations */
 
362
  if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))
 
363
  {
 
364
    free_plugin_mem(&plugin_dl);
 
365
    if (report & REPORT_TO_USER)
 
366
      my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_declarations_sym);
 
367
    if (report & REPORT_TO_LOG)
 
368
      sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_declarations_sym);
 
369
    return(0);
 
370
  }
 
371
 
 
372
  plugin_dl.plugins= (struct st_mysql_plugin *)sym;
 
373
 
 
374
  /* Duplicate and convert dll name */
 
375
  plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
 
376
  if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
 
377
  {
 
378
    free_plugin_mem(&plugin_dl);
 
379
    if (report & REPORT_TO_USER)
 
380
      my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length);
 
381
    if (report & REPORT_TO_LOG)
 
382
      sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
 
383
    return(0);
 
384
  }
 
385
  plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length,
 
386
    files_charset_info, dl->str, dl->length, system_charset_info,
 
387
    &dummy_errors);
 
388
  plugin_dl.dl.str[plugin_dl.dl.length]= 0;
 
389
  /* Add this dll to array */
 
390
  if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl)))
 
391
  {
 
392
    free_plugin_mem(&plugin_dl);
 
393
    if (report & REPORT_TO_USER)
 
394
      my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_dl));
 
395
    if (report & REPORT_TO_LOG)
 
396
      sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_dl));
 
397
    return(0);
 
398
  }
 
399
  return(tmp);
 
400
}
 
401
 
 
402
 
 
403
static void plugin_dl_del(const LEX_STRING *dl)
 
404
{
 
405
  uint i;
 
406
 
 
407
  for (i= 0; i < plugin_dl_array.elements; i++)
 
408
  {
 
409
    struct st_plugin_dl *tmp= *dynamic_element(&plugin_dl_array, i,
 
410
                                               struct st_plugin_dl **);
 
411
    if (tmp->ref_count &&
 
412
        ! my_strnncoll(files_charset_info,
 
413
                       (const uchar *)dl->str, dl->length,
 
414
                       (const uchar *)tmp->dl.str, tmp->dl.length))
 
415
    {
 
416
      /* Do not remove this element, unless no other plugin uses this dll. */
 
417
      if (! --tmp->ref_count)
 
418
      {
 
419
        free_plugin_mem(tmp);
 
420
        memset(tmp, 0, sizeof(struct st_plugin_dl));
 
421
      }
 
422
      break;
 
423
    }
 
424
  }
 
425
  return;
 
426
}
 
427
 
 
428
 
 
429
static struct st_plugin_int *plugin_find_internal(const LEX_STRING *name, int type)
 
430
{
 
431
  uint i;
 
432
  if (! initialized)
 
433
    return(0);
 
434
 
 
435
  if (type == DRIZZLE_ANY_PLUGIN)
 
436
  {
 
437
    for (i= 0; i < DRIZZLE_MAX_PLUGIN_TYPE_NUM; i++)
 
438
    {
 
439
      struct st_plugin_int *plugin= (st_plugin_int *)
 
440
        hash_search(&plugin_hash[i], (const uchar *)name->str, name->length);
 
441
      if (plugin)
 
442
        return(plugin);
 
443
    }
 
444
  }
 
445
  else
 
446
    return((st_plugin_int *)
 
447
        hash_search(&plugin_hash[type], (const uchar *)name->str, name->length));
 
448
  return(0);
 
449
}
 
450
 
 
451
 
 
452
static SHOW_COMP_OPTION plugin_status(const LEX_STRING *name, int type)
 
453
{
 
454
  SHOW_COMP_OPTION rc= SHOW_OPTION_NO;
 
455
  struct st_plugin_int *plugin;
 
456
  if ((plugin= plugin_find_internal(name, type)))
 
457
  {
 
458
    rc= SHOW_OPTION_DISABLED;
 
459
    if (plugin->state == PLUGIN_IS_READY)
 
460
      rc= SHOW_OPTION_YES;
 
461
  }
 
462
  return(rc);
 
463
}
 
464
 
 
465
 
 
466
bool plugin_is_ready(const LEX_STRING *name, int type)
 
467
{
 
468
  bool rc= false;
 
469
  if (plugin_status(name, type) == SHOW_OPTION_YES)
 
470
    rc= true;
 
471
  return rc;
 
472
}
 
473
 
 
474
 
 
475
SHOW_COMP_OPTION sys_var_have_plugin::get_option()
 
476
{
 
477
  LEX_STRING plugin_name= { (char *) plugin_name_str, plugin_name_len };
 
478
  return plugin_status(&plugin_name, plugin_type);
 
479
}
 
480
 
 
481
 
 
482
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc CALLER_INFO_PROTO)
 
483
{
 
484
  st_plugin_int *pi= plugin_ref_to_int(rc);
 
485
 
 
486
  if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
 
487
  {
 
488
    plugin_ref plugin;
 
489
    /*
 
490
      For debugging, we do an additional malloc which allows the
 
491
      memory manager and/or valgrind to track locked references and
 
492
      double unlocks to aid resolving reference counting.problems.
 
493
    */
 
494
    if (!(plugin= (plugin_ref) my_malloc_ci(sizeof(pi), MYF(MY_WME))))
 
495
      return(NULL);
 
496
 
 
497
    *plugin= pi;
 
498
    pi->ref_count++;
 
499
 
 
500
    if (lex)
 
501
      insert_dynamic(&lex->plugins, (uchar*)&plugin);
 
502
    return(plugin);
 
503
  }
 
504
  return(NULL);
 
505
}
 
506
 
 
507
 
 
508
plugin_ref plugin_lock(THD *thd, plugin_ref *ptr CALLER_INFO_PROTO)
 
509
{
 
510
  LEX *lex= thd ? thd->lex : 0;
 
511
  plugin_ref rc;
 
512
  rc= my_intern_plugin_lock_ci(lex, *ptr);
 
513
  return(rc);
 
514
}
 
515
 
 
516
 
 
517
plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name, int type
 
518
                               CALLER_INFO_PROTO)
 
519
{
 
520
  LEX *lex= thd ? thd->lex : 0;
 
521
  plugin_ref rc= NULL;
 
522
  st_plugin_int *plugin;
 
523
  if ((plugin= plugin_find_internal(name, type)))
 
524
    rc= my_intern_plugin_lock_ci(lex, plugin_int_to_ref(plugin));
 
525
  return(rc);
 
526
}
 
527
 
 
528
 
 
529
static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
 
530
{
 
531
  uint i;
 
532
  struct st_plugin_int *tmp;
 
533
  for (i= 0; i < plugin_array.elements; i++)
 
534
  {
 
535
    tmp= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
 
536
    if (tmp->state == PLUGIN_IS_FREED)
 
537
    {
 
538
      memcpy(tmp, plugin, sizeof(struct st_plugin_int));
 
539
      return(tmp);
 
540
    }
 
541
  }
 
542
  if (insert_dynamic(&plugin_array, (uchar*)&plugin))
 
543
    return(0);
 
544
  tmp= *dynamic_element(&plugin_array, plugin_array.elements - 1,
 
545
                        struct st_plugin_int **)=
 
546
       (struct st_plugin_int *) memdup_root(&plugin_mem_root, (uchar*)plugin,
 
547
                                            sizeof(struct st_plugin_int));
 
548
  return(tmp);
 
549
}
153
550
 
154
551
 
155
552
/*
156
553
  NOTE
157
554
    Requires that a write-lock is held on LOCK_system_variables_hash
158
555
*/
159
 
static bool plugin_add(module::Registry &registry, memory::Root *tmp_root,
160
 
                       module::Library *library,
161
 
                       po::options_description &long_options)
 
556
static bool plugin_add(MEM_ROOT *tmp_root,
 
557
                       const LEX_STRING *name, const LEX_STRING *dl,
 
558
                       int *argc, char **argv, int report)
162
559
{
163
 
  if (! initialized)
164
 
    return true;
165
 
 
166
 
  if (registry.find(library->getName()))
 
560
  struct st_plugin_int tmp;
 
561
  struct st_mysql_plugin *plugin;
 
562
  if (plugin_find_internal(name, DRIZZLE_ANY_PLUGIN))
167
563
  {
168
 
    errmsg_printf(ERRMSG_LVL_WARN, ER(ER_PLUGIN_EXISTS),
169
 
                  library->getName().c_str());
170
 
    return false;
 
564
    if (report & REPORT_TO_USER)
 
565
      my_error(ER_UDF_EXISTS, MYF(0), name->str);
 
566
    if (report & REPORT_TO_LOG)
 
567
      sql_print_error(ER(ER_UDF_EXISTS), name->str);
 
568
    return(true);
171
569
  }
172
 
 
173
 
  module::Module *tmp= NULL;
 
570
  /* Clear the whole struct to catch future extensions. */
 
571
  memset(&tmp, 0, sizeof(tmp));
 
572
  if (! (tmp.plugin_dl= plugin_dl_add(dl, report)))
 
573
    return(true);
174
574
  /* Find plugin by name */
175
 
  const module::Manifest *manifest= library->getManifest();
176
 
 
177
 
  if (registry.find(manifest->name))
178
 
  {
179
 
    errmsg_printf(ERRMSG_LVL_ERROR, 
180
 
                  _("Plugin '%s' contains the name '%s' in its manifest, which "
181
 
                    "has already been registered.\n"),
182
 
                  library->getName().c_str(),
183
 
                  manifest->name);
184
 
    return true;
185
 
  }
186
 
 
187
 
  tmp= new (std::nothrow) module::Module(manifest, library);
188
 
  if (tmp == NULL)
189
 
    return true;
190
 
 
191
 
  if (!test_plugin_options(tmp_root, tmp, long_options))
192
 
  {
193
 
    registry.add(tmp);
194
 
    return false;
195
 
  }
196
 
  errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_CANT_FIND_DL_ENTRY),
197
 
                library->getName().c_str());
198
 
  return true;
199
 
}
200
 
 
201
 
 
202
 
static void reap_plugins(module::Registry &registry)
203
 
{
204
 
  std::map<std::string, module::Module *>::const_iterator modules=
205
 
    registry.getModulesMap().begin();
206
 
 
207
 
  while (modules != registry.getModulesMap().end())
208
 
  {
209
 
    module::Module *module= (*modules).second;
210
 
    delete module;
211
 
    ++modules;
212
 
  }
213
 
}
214
 
 
215
 
 
216
 
static bool plugin_initialize(module::Registry &registry,
217
 
                              module::Module *module)
218
 
{
219
 
  assert(module->isInited == false);
220
 
 
221
 
  module::Context loading_context(registry, module);
222
 
  if (module->getManifest().init)
223
 
  {
224
 
    if (module->getManifest().init(loading_context))
225
 
    {
226
 
      errmsg_printf(ERRMSG_LVL_ERROR,
227
 
                    _("Plugin '%s' init function returned error.\n"),
228
 
                    module->getName().c_str());
229
 
      return true;
230
 
    }
231
 
  }
232
 
  module->isInited= true;
233
 
 
234
 
 
235
 
  return false;
236
 
}
237
 
 
238
 
 
239
 
inline static void dashes_to_underscores(std::string &name_in,
240
 
                                         char from= '-', char to= '_')
241
 
{
242
 
  for (string::iterator p= name_in.begin();
243
 
       p != name_in.end();
244
 
       ++p)
245
 
  {
246
 
    if (*p == from)
247
 
    {
248
 
      *p= to;
249
 
    }
250
 
  }
251
 
}
252
 
 
253
 
inline static void underscores_to_dashes(std::string &name_in)
254
 
{
255
 
  return dashes_to_underscores(name_in, '_', '-');
256
 
}
257
 
 
258
 
static void compose_plugin_options(vector<string> &target,
259
 
                                   vector<string> options)
260
 
{
261
 
  for (vector<string>::iterator it= options.begin();
262
 
       it != options.end();
263
 
       ++it)
264
 
  {
265
 
    tokenize(*it, target, ",", true);
266
 
  }
267
 
  for (vector<string>::iterator it= target.begin();
268
 
       it != target.end();
269
 
       ++it)
270
 
  {
271
 
    dashes_to_underscores(*it);
272
 
  }
273
 
}
274
 
 
275
 
void compose_plugin_add(vector<string> options)
276
 
{
277
 
  compose_plugin_options(opt_plugin_add, options);
278
 
}
279
 
 
280
 
void compose_plugin_remove(vector<string> options)
281
 
{
282
 
  compose_plugin_options(opt_plugin_remove, options);
283
 
}
284
 
 
285
 
void notify_plugin_load(string in_plugin_load)
286
 
{
287
 
  tokenize(in_plugin_load, opt_plugin_load, ",", true);
288
 
}
 
575
  for (plugin= tmp.plugin_dl->plugins; plugin->name; plugin++)
 
576
  {
 
577
    uint name_len= strlen(plugin->name);
 
578
    if (plugin->type >= 0 && plugin->type < DRIZZLE_MAX_PLUGIN_TYPE_NUM &&
 
579
        ! my_strnncoll(system_charset_info,
 
580
                       (const uchar *)name->str, name->length,
 
581
                       (const uchar *)plugin->name,
 
582
                       name_len))
 
583
    {
 
584
      struct st_plugin_int *tmp_plugin_ptr;
 
585
 
 
586
      tmp.plugin= plugin;
 
587
      tmp.name.str= (char *)plugin->name;
 
588
      tmp.name.length= name_len;
 
589
      tmp.ref_count= 0;
 
590
      tmp.state= PLUGIN_IS_UNINITIALIZED;
 
591
      if (!test_plugin_options(tmp_root, &tmp, argc, argv))
 
592
      {
 
593
        if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
 
594
        {
 
595
          plugin_array_version++;
 
596
          if (!my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
 
597
          {
 
598
            init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096);
 
599
            return(false);
 
600
          }
 
601
          tmp_plugin_ptr->state= PLUGIN_IS_FREED;
 
602
        }
 
603
        mysql_del_sys_var_chain(tmp.system_vars);
 
604
        goto err;
 
605
      }
 
606
      /* plugin was disabled */
 
607
      plugin_dl_del(dl);
 
608
      return(false);
 
609
    }
 
610
  }
 
611
  if (report & REPORT_TO_USER)
 
612
    my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), name->str);
 
613
  if (report & REPORT_TO_LOG)
 
614
    sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name->str);
 
615
err:
 
616
  plugin_dl_del(dl);
 
617
  return(true);
 
618
}
 
619
 
 
620
 
 
621
static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
 
622
{
 
623
  if (plugin->plugin->status_vars)
 
624
  {
 
625
#ifdef FIX_LATER
 
626
    /*
 
627
      We have a problem right now where we can not prepend without
 
628
      breaking backwards compatibility. We will fix this shortly so
 
629
      that engines have "use names" and we wil use those for
 
630
      CREATE TABLE, and use the plugin name then for adding automatic
 
631
      variable names.
 
632
    */
 
633
    SHOW_VAR array[2]= {
 
634
      {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
 
635
      {0, 0, SHOW_UNDEF}
 
636
    };
 
637
    remove_status_vars(array);
 
638
#else
 
639
    remove_status_vars(plugin->plugin->status_vars);
 
640
#endif /* FIX_LATER */
 
641
  }
 
642
 
 
643
  if (plugin_type_deinitialize[plugin->plugin->type])
 
644
  {
 
645
    if ((*plugin_type_deinitialize[plugin->plugin->type])(plugin))
 
646
    {
 
647
      sql_print_error(_("Plugin '%s' of type %s failed deinitialization"),
 
648
                      plugin->name.str, plugin_type_names[plugin->plugin->type].str);
 
649
    }
 
650
  }
 
651
  else if (plugin->plugin->deinit)
 
652
    plugin->plugin->deinit(plugin);
 
653
 
 
654
  plugin->state= PLUGIN_IS_UNINITIALIZED;
 
655
 
 
656
  /*
 
657
    We do the check here because NDB has a worker THD which doesn't
 
658
    exit until NDB is shut down.
 
659
  */
 
660
  if (ref_check && plugin->ref_count)
 
661
    sql_print_error(_("Plugin '%s' has ref_count=%d after deinitialization."),
 
662
                    plugin->name.str, plugin->ref_count);
 
663
}
 
664
 
 
665
 
 
666
static void plugin_del(struct st_plugin_int *plugin)
 
667
{
 
668
  /* Free allocated strings before deleting the plugin. */
 
669
  plugin_vars_free_values(plugin->system_vars);
 
670
  hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
 
671
  if (plugin->plugin_dl)
 
672
    plugin_dl_del(&plugin->plugin_dl->dl);
 
673
  plugin->state= PLUGIN_IS_FREED;
 
674
  plugin_array_version++;
 
675
  rw_wrlock(&LOCK_system_variables_hash);
 
676
  mysql_del_sys_var_chain(plugin->system_vars);
 
677
  rw_unlock(&LOCK_system_variables_hash);
 
678
  free_root(&plugin->mem_root, MYF(0));
 
679
  return;
 
680
}
 
681
 
 
682
static void reap_plugins(void)
 
683
{
 
684
  uint count, idx;
 
685
  struct st_plugin_int *plugin, **reap, **list;
 
686
 
 
687
  if (!reap_needed)
 
688
    return;
 
689
 
 
690
  reap_needed= false;
 
691
  count= plugin_array.elements;
 
692
  reap= (struct st_plugin_int **)my_alloca(sizeof(plugin)*(count+1));
 
693
  *(reap++)= NULL;
 
694
 
 
695
  for (idx= 0; idx < count; idx++)
 
696
  {
 
697
    plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
 
698
    if (plugin->state == PLUGIN_IS_DELETED && !plugin->ref_count)
 
699
    {
 
700
      /* change the status flag to prevent reaping by another thread */
 
701
      plugin->state= PLUGIN_IS_DYING;
 
702
      *(reap++)= plugin;
 
703
    }
 
704
  }
 
705
 
 
706
  list= reap;
 
707
  while ((plugin= *(--list)))
 
708
    plugin_deinitialize(plugin, true);
 
709
 
 
710
  while ((plugin= *(--reap)))
 
711
    plugin_del(plugin);
 
712
 
 
713
  my_afree(reap);
 
714
}
 
715
 
 
716
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin)
 
717
{
 
718
  int i;
 
719
  st_plugin_int *pi;
 
720
 
 
721
  if (!plugin)
 
722
    return;
 
723
 
 
724
  pi= plugin_ref_to_int(plugin);
 
725
 
 
726
  my_free((uchar*) plugin, MYF(MY_WME));
 
727
 
 
728
  if (lex)
 
729
  {
 
730
    /*
 
731
      Remove one instance of this plugin from the use list.
 
732
      We are searching backwards so that plugins locked last
 
733
      could be unlocked faster - optimizing for LIFO semantics.
 
734
    */
 
735
    for (i= lex->plugins.elements - 1; i >= 0; i--)
 
736
      if (plugin == *dynamic_element(&lex->plugins, i, plugin_ref*))
 
737
      {
 
738
        delete_dynamic_element(&lex->plugins, i);
 
739
        break;
 
740
      }
 
741
    assert(i >= 0);
 
742
  }
 
743
 
 
744
  assert(pi->ref_count);
 
745
  pi->ref_count--;
 
746
 
 
747
  if (pi->state == PLUGIN_IS_DELETED && !pi->ref_count)
 
748
    reap_needed= true;
 
749
 
 
750
  return;
 
751
}
 
752
 
 
753
 
 
754
void plugin_unlock(THD *thd, plugin_ref plugin)
 
755
{
 
756
  LEX *lex= thd ? thd->lex : 0;
 
757
  if (!plugin)
 
758
    return;
 
759
  intern_plugin_unlock(lex, plugin);
 
760
  return;
 
761
}
 
762
 
 
763
 
 
764
void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
 
765
{
 
766
  LEX *lex= thd ? thd->lex : 0;
 
767
  assert(list);
 
768
  while (count--)
 
769
    intern_plugin_unlock(lex, *list++);
 
770
  return;
 
771
}
 
772
 
 
773
 
 
774
static int plugin_initialize(struct st_plugin_int *plugin)
 
775
{
 
776
 
 
777
  if (plugin_type_initialize[plugin->plugin->type])
 
778
  {
 
779
    if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
 
780
    {
 
781
      sql_print_error(_("Plugin '%s' registration as a %s failed."),
 
782
                      plugin->name.str, plugin_type_names[plugin->plugin->type].str);
 
783
      goto err;
 
784
    }
 
785
  }
 
786
  else if (plugin->plugin->init)
 
787
  {
 
788
    if (plugin->plugin->init(plugin))
 
789
    {
 
790
      sql_print_error(_("Plugin '%s' init function returned error."),
 
791
                      plugin->name.str);
 
792
      goto err;
 
793
    }
 
794
  }
 
795
 
 
796
  plugin->state= PLUGIN_IS_READY;
 
797
 
 
798
  if (plugin->plugin->status_vars)
 
799
  {
 
800
#ifdef FIX_LATER
 
801
    /*
 
802
      We have a problem right now where we can not prepend without
 
803
      breaking backwards compatibility. We will fix this shortly so
 
804
      that engines have "use names" and we wil use those for
 
805
      CREATE TABLE, and use the plugin name then for adding automatic
 
806
      variable names.
 
807
    */
 
808
    SHOW_VAR array[2]= {
 
809
      {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
 
810
      {0, 0, SHOW_UNDEF}
 
811
    };
 
812
    if (add_status_vars(array)) // add_status_vars makes a copy
 
813
      goto err;
 
814
#else
 
815
    add_status_vars(plugin->plugin->status_vars); // add_status_vars makes a copy
 
816
#endif /* FIX_LATER */
 
817
  }
 
818
 
 
819
  /*
 
820
    set the plugin attribute of plugin's sys vars so they are pointing
 
821
    to the active plugin
 
822
  */
 
823
  if (plugin->system_vars)
 
824
  {
 
825
    sys_var_pluginvar *var= plugin->system_vars->cast_pluginvar();
 
826
    for (;;)
 
827
    {
 
828
      var->plugin= plugin;
 
829
      if (!var->next)
 
830
        break;
 
831
      var= var->next->cast_pluginvar();
 
832
    }
 
833
  }
 
834
 
 
835
  return(0);
 
836
err:
 
837
  return(1);
 
838
}
 
839
 
 
840
 
 
841
extern "C" uchar *get_plugin_hash_key(const uchar *, size_t *, bool);
 
842
extern "C" uchar *get_bookmark_hash_key(const uchar *, size_t *, bool);
 
843
 
 
844
 
 
845
uchar *get_plugin_hash_key(const uchar *buff, size_t *length,
 
846
                           bool not_used __attribute__((unused)))
 
847
{
 
848
  struct st_plugin_int *plugin= (st_plugin_int *)buff;
 
849
  *length= (uint)plugin->name.length;
 
850
  return((uchar *)plugin->name.str);
 
851
}
 
852
 
 
853
 
 
854
uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
 
855
                             bool not_used __attribute__((unused)))
 
856
{
 
857
  struct st_bookmark *var= (st_bookmark *)buff;
 
858
  *length= var->name_len + 1;
 
859
  return (uchar*) var->key;
 
860
}
 
861
 
289
862
 
290
863
/*
291
864
  The logic is that we first load and initialize all compiled in plugins.
294
867
 
295
868
  Finally we initialize everything, aka the dynamic that have yet to initialize.
296
869
*/
297
 
bool plugin_init(module::Registry &registry,
298
 
                 po::options_description &long_options)
 
870
int plugin_init(int *argc, char **argv, int flags)
299
871
{
300
 
  memory::Root tmp_root(4096);
 
872
  uint i;
 
873
  struct st_mysql_plugin **builtins;
 
874
  struct st_mysql_plugin *plugin;
 
875
  struct st_plugin_int tmp, *plugin_ptr, **reap;
 
876
  MEM_ROOT tmp_root;
301
877
 
302
878
  if (initialized)
303
 
    return false;
 
879
    return(0);
 
880
 
 
881
  init_alloc_root(&plugin_mem_root, 4096, 4096);
 
882
  init_alloc_root(&tmp_root, 4096, 4096);
 
883
 
 
884
  if (hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
 
885
                  get_bookmark_hash_key, NULL, HASH_UNIQUE))
 
886
      goto err;
 
887
 
 
888
 
 
889
  if (my_init_dynamic_array(&plugin_dl_array,
 
890
                            sizeof(struct st_plugin_dl *),16,16) ||
 
891
      my_init_dynamic_array(&plugin_array,
 
892
                            sizeof(struct st_plugin_int *),16,16))
 
893
    goto err;
 
894
 
 
895
  for (i= 0; i < DRIZZLE_MAX_PLUGIN_TYPE_NUM; i++)
 
896
  {
 
897
    if (hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
 
898
                  get_plugin_hash_key, NULL, HASH_UNIQUE))
 
899
      goto err;
 
900
  }
304
901
 
305
902
  initialized= 1;
306
903
 
307
 
  PluginOptions builtin_load_list;
308
 
  tokenize(builtin_load_plugins, builtin_load_list, ",", true);
309
 
 
310
 
  PluginOptions builtin_list;
311
 
  tokenize(builtin_plugins, builtin_list, ",", true);
312
 
 
313
 
  bool load_failed= false;
314
 
 
315
 
  if (opt_plugin_add.size() > 0)
316
 
  {
317
 
    for (PluginOptions::iterator iter= opt_plugin_add.begin();
318
 
         iter != opt_plugin_add.end();
319
 
         ++iter)
320
 
    {
321
 
      if (find(builtin_list.begin(),
322
 
               builtin_list.end(), *iter) != builtin_list.end())
323
 
      {
324
 
        builtin_load_list.push_back(*iter);
325
 
      }
326
 
      else
327
 
      {
328
 
        opt_plugin_load.push_back(*iter);
329
 
      }
330
 
    }
331
 
  }
332
 
 
333
 
  if (opt_plugin_remove.size() > 0)
334
 
  {
335
 
    plugin_prune_list(opt_plugin_load, opt_plugin_remove);
336
 
    plugin_prune_list(builtin_load_list, opt_plugin_remove);
337
 
  }
338
 
 
339
 
 
340
904
  /*
341
905
    First we register builtin plugins
342
906
  */
343
 
  const set<string> builtin_list_set(builtin_load_list.begin(),
344
 
                                     builtin_load_list.end());
345
 
  load_failed= plugin_load_list(registry, &tmp_root,
346
 
                                builtin_list_set, long_options, true);
347
 
  if (load_failed)
 
907
  for (builtins= mysqld_builtins; *builtins; builtins++)
348
908
  {
349
 
    tmp_root.free_root(MYF(0));
350
 
    return true;
 
909
    for (plugin= *builtins; plugin->name; plugin++)
 
910
    {
 
911
      memset(&tmp, 0, sizeof(tmp));
 
912
      tmp.plugin= plugin;
 
913
      tmp.name.str= (char *)plugin->name;
 
914
      tmp.name.length= strlen(plugin->name);
 
915
 
 
916
      free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
 
917
      if (test_plugin_options(&tmp_root, &tmp, argc, argv))
 
918
        continue;
 
919
 
 
920
      if (register_builtin(plugin, &tmp, &plugin_ptr))
 
921
        goto err_unlock;
 
922
 
 
923
      if (plugin_initialize(plugin_ptr))
 
924
        goto err_unlock;
 
925
 
 
926
      /*
 
927
        initialize the global default storage engine so that it may
 
928
        not be null in any child thread.
 
929
      */
 
930
      if (my_strcasecmp(&my_charset_utf8_general_ci, plugin->name, "MyISAM") == 0)
 
931
      {
 
932
        assert(!global_system_variables.table_plugin);
 
933
        global_system_variables.table_plugin=
 
934
          my_intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr));
 
935
        assert(plugin_ptr->ref_count == 1);
 
936
      }
 
937
    }
351
938
  }
352
939
 
353
 
  /* Uniquify the list */
354
 
  const set<string> plugin_list_set(opt_plugin_load.begin(),
355
 
                                    opt_plugin_load.end());
356
 
  
 
940
  /* should now be set to MyISAM storage engine */
 
941
  assert(global_system_variables.table_plugin);
 
942
 
357
943
  /* Register all dynamic plugins */
358
 
  load_failed= plugin_load_list(registry, &tmp_root,
359
 
                                plugin_list_set, long_options);
360
 
  if (load_failed)
 
944
  if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
361
945
  {
362
 
    tmp_root.free_root(MYF(0));
363
 
    return true;
 
946
    if (opt_plugin_load)
 
947
      plugin_load_list(&tmp_root, argc, argv, opt_plugin_load);
364
948
  }
365
949
 
366
 
  tmp_root.free_root(MYF(0));
367
 
 
368
 
  return false;
369
 
}
370
 
 
371
 
bool plugin_finalize(module::Registry &registry)
372
 
{
 
950
  if (flags & PLUGIN_INIT_SKIP_INITIALIZATION)
 
951
    goto end;
 
952
 
373
953
  /*
374
954
    Now we initialize all remaining plugins
375
955
  */
376
 
  std::map<std::string, module::Module *>::const_iterator modules=
377
 
    registry.getModulesMap().begin();
378
 
    
379
 
  while (modules != registry.getModulesMap().end())
 
956
 
 
957
  reap= (st_plugin_int **) my_alloca((plugin_array.elements+1) * sizeof(void*));
 
958
  *(reap++)= NULL;
 
959
 
 
960
  for (i= 0; i < plugin_array.elements; i++)
380
961
  {
381
 
    module::Module *module= (*modules).second;
382
 
    ++modules;
383
 
    if (module->isInited == false)
 
962
    plugin_ptr= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
 
963
    if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED)
384
964
    {
385
 
      if (plugin_initialize(registry, module))
 
965
      if (plugin_initialize(plugin_ptr))
386
966
      {
387
 
        registry.remove(module);
388
 
        delete module;
389
 
        return true;
 
967
        plugin_ptr->state= PLUGIN_IS_DYING;
 
968
        *(reap++)= plugin_ptr;
390
969
      }
391
970
    }
392
971
  }
393
972
 
394
 
  BOOST_FOREACH(plugin::Plugin::map::value_type value, registry.getPluginsMap())
395
 
  {
396
 
    value.second->prime();
397
 
  }
398
 
 
399
 
  return false;
400
 
}
401
 
 
402
 
class PrunePlugin :
403
 
  public unary_function<string, bool>
404
 
{
405
 
  const string to_match;
406
 
  PrunePlugin();
407
 
  PrunePlugin& operator=(const PrunePlugin&);
408
 
public:
409
 
  explicit PrunePlugin(const string &match_in) :
410
 
    to_match(match_in)
411
 
  { }
412
 
 
413
 
  result_type operator()(const string &match_against)
414
 
  {
415
 
    return match_against == to_match;
416
 
  }
417
 
};
418
 
 
419
 
static void plugin_prune_list(vector<string> &plugin_list,
420
 
                              const vector<string> &plugins_to_remove)
421
 
{
422
 
  for (vector<string>::const_iterator iter= plugins_to_remove.begin();
423
 
       iter != plugins_to_remove.end();
424
 
       ++iter)
425
 
  {
426
 
    plugin_list.erase(remove_if(plugin_list.begin(),
427
 
                                plugin_list.end(),
428
 
                                PrunePlugin(*iter)),
429
 
                      plugin_list.end());
430
 
  }
431
 
}
 
973
  /*
 
974
    Check if any plugins have to be reaped
 
975
  */
 
976
  while ((plugin_ptr= *(--reap)))
 
977
  {
 
978
    plugin_deinitialize(plugin_ptr, true);
 
979
    plugin_del(plugin_ptr);
 
980
  }
 
981
 
 
982
  my_afree(reap);
 
983
 
 
984
end:
 
985
  free_root(&tmp_root, MYF(0));
 
986
 
 
987
  return(0);
 
988
 
 
989
err_unlock:
 
990
err:
 
991
  free_root(&tmp_root, MYF(0));
 
992
  return(1);
 
993
}
 
994
 
 
995
 
 
996
static bool register_builtin(struct st_mysql_plugin *plugin,
 
997
                             struct st_plugin_int *tmp,
 
998
                             struct st_plugin_int **ptr)
 
999
{
 
1000
 
 
1001
  tmp->state= PLUGIN_IS_UNINITIALIZED;
 
1002
  tmp->ref_count= 0;
 
1003
  tmp->plugin_dl= 0;
 
1004
 
 
1005
  if (insert_dynamic(&plugin_array, (uchar*)&tmp))
 
1006
    return(1);
 
1007
 
 
1008
  *ptr= *dynamic_element(&plugin_array, plugin_array.elements - 1,
 
1009
                         struct st_plugin_int **)=
 
1010
        (struct st_plugin_int *) memdup_root(&plugin_mem_root, (uchar*)tmp,
 
1011
                                             sizeof(struct st_plugin_int));
 
1012
 
 
1013
  if (my_hash_insert(&plugin_hash[plugin->type],(uchar*) *ptr))
 
1014
    return(1);
 
1015
 
 
1016
  return(0);
 
1017
}
 
1018
 
432
1019
 
433
1020
/*
434
1021
  called only by plugin_init()
435
1022
*/
436
 
static bool plugin_load_list(module::Registry &registry,
437
 
                             memory::Root *tmp_root,
438
 
                             const set<string> &plugin_list,
439
 
                             po::options_description &long_options,
440
 
                             bool builtin)
 
1023
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
 
1024
                             const char *list)
441
1025
{
442
 
  module::Library *library= NULL;
443
 
 
444
 
  for (set<string>::const_iterator iter= plugin_list.begin();
445
 
       iter != plugin_list.end();
446
 
       ++iter)
 
1026
  char buffer[FN_REFLEN];
 
1027
  LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
 
1028
  struct st_plugin_dl *plugin_dl;
 
1029
  struct st_mysql_plugin *plugin;
 
1030
  char *p= buffer;
 
1031
  while (list)
447
1032
  {
448
 
    const string plugin_name(*iter);
449
 
 
450
 
    library= registry.addLibrary(plugin_name, builtin);
451
 
    if (library == NULL)
 
1033
    if (p == buffer + sizeof(buffer) - 1)
452
1034
    {
453
 
      errmsg_printf(ERRMSG_LVL_ERROR,
454
 
                    _("Couldn't load plugin library named '%s'.\n"),
455
 
                    plugin_name.c_str());
456
 
      return true;
 
1035
      sql_print_error(_("plugin-load parameter too long"));
 
1036
      return(true);
457
1037
    }
458
1038
 
459
 
    tmp_root->free_root(MYF(memory::MARK_BLOCKS_FREE));
460
 
    if (plugin_add(registry, tmp_root, library, long_options))
461
 
    {
462
 
      registry.removeLibrary(plugin_name);
463
 
      errmsg_printf(ERRMSG_LVL_ERROR,
464
 
                    _("Couldn't load plugin named '%s'.\n"),
465
 
                    plugin_name.c_str());
466
 
      return true;
467
 
 
 
1039
    switch ((*(p++)= *(list++))) {
 
1040
    case '\0':
 
1041
      list= NULL; /* terminate the loop */
 
1042
      /* fall through */
 
1043
    case ':':     /* can't use this as delimiter as it may be drive letter */
 
1044
    case ';':
 
1045
      str->str[str->length]= '\0';
 
1046
      if (str == &name)  // load all plugins in named module
 
1047
      {
 
1048
        if (!name.length)
 
1049
        {
 
1050
          p--;    /* reset pointer */
 
1051
          continue;
 
1052
        }
 
1053
 
 
1054
        dl= name;
 
1055
        if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG)))
 
1056
        {
 
1057
          for (plugin= plugin_dl->plugins; plugin->name; plugin++)
 
1058
          {
 
1059
            name.str= (char *) plugin->name;
 
1060
            name.length= strlen(name.str);
 
1061
 
 
1062
            free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
 
1063
            if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
 
1064
              goto error;
 
1065
          }
 
1066
          plugin_dl_del(&dl); // reduce ref count
 
1067
        }
 
1068
      }
 
1069
      else
 
1070
      {
 
1071
        free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
 
1072
        if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
 
1073
          goto error;
 
1074
      }
 
1075
      name.length= dl.length= 0;
 
1076
      dl.str= NULL; name.str= p= buffer;
 
1077
      str= &name;
 
1078
      continue;
 
1079
    case '=':
 
1080
    case '#':
 
1081
      if (str == &name)
 
1082
      {
 
1083
        name.str[name.length]= '\0';
 
1084
        str= &dl;
 
1085
        str->str= p;
 
1086
        continue;
 
1087
      }
 
1088
    default:
 
1089
      str->length++;
 
1090
      continue;
468
1091
    }
469
1092
  }
470
 
  return false;
 
1093
  return(false);
 
1094
error:
 
1095
  sql_print_error(_("Couldn't load plugin named '%s' with soname '%s'."),
 
1096
                  name.str, dl.str);
 
1097
  return(true);
471
1098
}
472
1099
 
473
1100
 
474
 
void module_shutdown(module::Registry &registry)
 
1101
void plugin_shutdown(void)
475
1102
{
 
1103
  uint i, count= plugin_array.elements, free_slots= 0;
 
1104
  struct st_plugin_int **plugins, *plugin;
 
1105
  struct st_plugin_dl **dl;
476
1106
 
477
1107
  if (initialized)
478
1108
  {
479
1109
    reap_needed= true;
480
1110
 
481
 
    reap_plugins(registry);
482
 
    unlock_variables(NULL, &global_system_variables);
483
 
    unlock_variables(NULL, &max_system_variables);
484
 
 
485
 
    cleanup_variables(&global_system_variables);
486
 
    cleanup_variables(&max_system_variables);
 
1111
    /*
 
1112
      We want to shut down plugins in a reasonable order, this will
 
1113
      become important when we have plugins which depend upon each other.
 
1114
      Circular references cannot be reaped so they are forced afterwards.
 
1115
      TODO: Have an additional step here to notify all active plugins that
 
1116
      shutdown is requested to allow plugins to deinitialize in parallel.
 
1117
    */
 
1118
    while (reap_needed && (count= plugin_array.elements))
 
1119
    {
 
1120
      reap_plugins();
 
1121
      for (i= free_slots= 0; i < count; i++)
 
1122
      {
 
1123
        plugin= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
 
1124
        switch (plugin->state) {
 
1125
        case PLUGIN_IS_READY:
 
1126
          plugin->state= PLUGIN_IS_DELETED;
 
1127
          reap_needed= true;
 
1128
          break;
 
1129
        case PLUGIN_IS_FREED:
 
1130
        case PLUGIN_IS_UNINITIALIZED:
 
1131
          free_slots++;
 
1132
          break;
 
1133
        }
 
1134
      }
 
1135
      if (!reap_needed)
 
1136
      {
 
1137
        /*
 
1138
          release any plugin references held.
 
1139
        */
 
1140
        unlock_variables(NULL, &global_system_variables);
 
1141
        unlock_variables(NULL, &max_system_variables);
 
1142
      }
 
1143
    }
 
1144
 
 
1145
    if (count > free_slots)
 
1146
      sql_print_warning(_("Forcing shutdown of %d plugins"),
 
1147
                        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
    */
 
1193
 
 
1194
    cleanup_variables(NULL, &global_system_variables);
 
1195
    cleanup_variables(NULL, &max_system_variables);
487
1196
 
488
1197
    initialized= 0;
 
1198
 
 
1199
    my_afree(plugins);
489
1200
  }
490
1201
 
491
1202
  /* Dispose of the memory */
492
 
  plugin_mem_root.free_root(MYF(0));
 
1203
 
 
1204
  for (i= 0; i < DRIZZLE_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));
493
1219
 
494
1220
  global_variables_dynamic_size= 0;
 
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 == DRIZZLE_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 == DRIZZLE_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
 
 
1283
 
 
1284
/****************************************************************************
 
1285
  Internal type declarations for variables support
 
1286
****************************************************************************/
 
1287
 
 
1288
#undef DRIZZLE_SYSVAR_NAME
 
1289
#define DRIZZLE_SYSVAR_NAME(name) name
 
1290
#define PLUGIN_VAR_TYPEMASK 0x007f
 
1291
 
 
1292
#define EXTRA_OPTIONS 3 /* options for: 'foo', 'plugin-foo' and NULL */
 
1293
 
 
1294
typedef DECLARE_DRIZZLE_SYSVAR_BASIC(sysvar_bool_t, bool);
 
1295
typedef DECLARE_DRIZZLE_THDVAR_BASIC(thdvar_bool_t, bool);
 
1296
typedef DECLARE_DRIZZLE_SYSVAR_BASIC(sysvar_str_t, char *);
 
1297
typedef DECLARE_DRIZZLE_THDVAR_BASIC(thdvar_str_t, char *);
 
1298
 
 
1299
typedef DECLARE_DRIZZLE_SYSVAR_TYPELIB(sysvar_enum_t, unsigned long);
 
1300
typedef DECLARE_DRIZZLE_THDVAR_TYPELIB(thdvar_enum_t, unsigned long);
 
1301
typedef DECLARE_DRIZZLE_SYSVAR_TYPELIB(sysvar_set_t, uint64_t);
 
1302
typedef DECLARE_DRIZZLE_THDVAR_TYPELIB(thdvar_set_t, uint64_t);
 
1303
 
 
1304
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_int_t, int);
 
1305
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_long_t, long);
 
1306
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_int64_t_t, int64_t);
 
1307
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_uint_t, uint);
 
1308
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_ulong_t, ulong);
 
1309
typedef DECLARE_DRIZZLE_SYSVAR_SIMPLE(sysvar_uint64_t_t, uint64_t);
 
1310
 
 
1311
typedef DECLARE_DRIZZLE_THDVAR_SIMPLE(thdvar_int_t, int);
 
1312
typedef DECLARE_DRIZZLE_THDVAR_SIMPLE(thdvar_long_t, long);
 
1313
typedef DECLARE_DRIZZLE_THDVAR_SIMPLE(thdvar_int64_t_t, int64_t);
 
1314
typedef DECLARE_DRIZZLE_THDVAR_SIMPLE(thdvar_uint_t, uint);
 
1315
typedef DECLARE_DRIZZLE_THDVAR_SIMPLE(thdvar_ulong_t, ulong);
 
1316
typedef DECLARE_DRIZZLE_THDVAR_SIMPLE(thdvar_uint64_t_t, uint64_t);
 
1317
 
 
1318
typedef bool *(*mysql_sys_var_ptr_p)(THD* a_thd, int offset);
 
1319
 
 
1320
 
 
1321
/****************************************************************************
 
1322
  default variable data check and update functions
 
1323
****************************************************************************/
 
1324
 
 
1325
static int check_func_bool(THD *thd __attribute__((unused)),
 
1326
                           struct st_mysql_sys_var *var,
 
1327
                           void *save, st_mysql_value *value)
 
1328
{
 
1329
  char buff[STRING_BUFFER_USUAL_SIZE];
 
1330
  const char *strvalue= "NULL", *str;
 
1331
  int result, length;
 
1332
  int64_t tmp;
 
1333
 
 
1334
  if (value->value_type(value) == DRIZZLE_VALUE_TYPE_STRING)
 
1335
  {
 
1336
    length= sizeof(buff);
 
1337
    if (!(str= value->val_str(value, buff, &length)) ||
 
1338
        (result= find_type(&bool_typelib, str, length, 1)-1) < 0)
 
1339
    {
 
1340
      if (str)
 
1341
        strvalue= str;
 
1342
      goto err;
 
1343
    }
 
1344
  }
 
1345
  else
 
1346
  {
 
1347
    if (value->val_int(value, &tmp) < 0)
 
1348
      goto err;
 
1349
    if (tmp > 1)
 
1350
    {
 
1351
      llstr(tmp, buff);
 
1352
      strvalue= buff;
 
1353
      goto err;
 
1354
    }
 
1355
    result= (int) tmp;
 
1356
  }
 
1357
  *(int*)save= -result;
 
1358
  return 0;
 
1359
err:
 
1360
  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
 
1361
  return 1;
 
1362
}
 
1363
 
 
1364
 
 
1365
static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
 
1366
                          void *save, st_mysql_value *value)
 
1367
{
 
1368
  bool fixed;
 
1369
  int64_t tmp;
 
1370
  struct my_option options;
 
1371
  value->val_int(value, &tmp);
 
1372
  plugin_opt_set_limits(&options, var);
 
1373
 
 
1374
  if (var->flags & PLUGIN_VAR_UNSIGNED)
 
1375
    *(uint *)save= (uint) getopt_ull_limit_value((uint64_t) tmp, &options,
 
1376
                                                   &fixed);
 
1377
  else
 
1378
    *(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed);
 
1379
 
 
1380
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
1381
                              var->name, (int64_t) tmp);
 
1382
}
 
1383
 
 
1384
 
 
1385
static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
 
1386
                          void *save, st_mysql_value *value)
 
1387
{
 
1388
  bool fixed;
 
1389
  int64_t tmp;
 
1390
  struct my_option options;
 
1391
  value->val_int(value, &tmp);
 
1392
  plugin_opt_set_limits(&options, var);
 
1393
 
 
1394
  if (var->flags & PLUGIN_VAR_UNSIGNED)
 
1395
    *(ulong *)save= (ulong) getopt_ull_limit_value((uint64_t) tmp, &options,
 
1396
                                                   &fixed);
 
1397
  else
 
1398
    *(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed);
 
1399
 
 
1400
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
1401
                              var->name, (int64_t) tmp);
 
1402
}
 
1403
 
 
1404
 
 
1405
static int check_func_int64_t(THD *thd, struct st_mysql_sys_var *var,
 
1406
                               void *save, st_mysql_value *value)
 
1407
{
 
1408
  bool fixed;
 
1409
  int64_t tmp;
 
1410
  struct my_option options;
 
1411
  value->val_int(value, &tmp);
 
1412
  plugin_opt_set_limits(&options, var);
 
1413
 
 
1414
  if (var->flags & PLUGIN_VAR_UNSIGNED)
 
1415
    *(uint64_t *)save= getopt_ull_limit_value((uint64_t) tmp, &options,
 
1416
                                               &fixed);
 
1417
  else
 
1418
    *(int64_t *)save= getopt_ll_limit_value(tmp, &options, &fixed);
 
1419
 
 
1420
  return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
 
1421
                              var->name, (int64_t) tmp);
 
1422
}
 
1423
 
 
1424
static int check_func_str(THD *thd,
 
1425
                          struct st_mysql_sys_var *var __attribute__((unused)),
 
1426
                          void *save, st_mysql_value *value)
 
1427
{
 
1428
  char buff[STRING_BUFFER_USUAL_SIZE];
 
1429
  const char *str;
 
1430
  int length;
 
1431
 
 
1432
  length= sizeof(buff);
 
1433
  if ((str= value->val_str(value, buff, &length)))
 
1434
    str= thd->strmake(str, length);
 
1435
  *(const char**)save= str;
 
1436
  return 0;
 
1437
}
 
1438
 
 
1439
 
 
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) == DRIZZLE_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) == DRIZZLE_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), (unsigned long)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)),
 
1540
                             void *tgt, const void *save)
 
1541
{
 
1542
  *(bool *) tgt= *(int *) save ? 1 : 0;
 
1543
}
 
1544
 
 
1545
 
 
1546
static void update_func_int(THD *thd __attribute__((unused)),
 
1547
                            struct st_mysql_sys_var *var __attribute__((unused)),
 
1548
                             void *tgt, const void *save)
 
1549
{
 
1550
  *(int *)tgt= *(int *) save;
 
1551
}
 
1552
 
 
1553
 
 
1554
static void update_func_long(THD *thd __attribute__((unused)),
 
1555
                             struct st_mysql_sys_var *var __attribute__((unused)),
 
1556
                             void *tgt, const void *save)
 
1557
{
 
1558
  *(long *)tgt= *(long *) save;
 
1559
}
 
1560
 
 
1561
 
 
1562
static void update_func_int64_t(THD *thd __attribute__((unused)),
 
1563
                                 struct st_mysql_sys_var *var __attribute__((unused)),
 
1564
                                 void *tgt, const void *save)
 
1565
{
 
1566
  *(int64_t *)tgt= *(uint64_t *) save;
 
1567
}
 
1568
 
 
1569
 
 
1570
static void update_func_str(THD *thd __attribute__((unused)), struct st_mysql_sys_var *var,
 
1571
                             void *tgt, const void *save)
 
1572
{
 
1573
  char *old= *(char **) tgt;
 
1574
  *(char **)tgt= *(char **) save;
 
1575
  if (var->flags & PLUGIN_VAR_MEMALLOC)
 
1576
  {
 
1577
    *(char **)tgt= my_strdup(*(char **) save, MYF(0));
 
1578
    my_free(old, MYF(0));
 
1579
  }
495
1580
}
496
1581
 
497
1582
 
500
1585
****************************************************************************/
501
1586
 
502
1587
 
503
 
sys_var *find_sys_var(const char *str, uint32_t length)
504
 
{
505
 
  return intern_find_sys_var(str, length, false);
506
 
}
507
 
 
508
 
 
509
 
void plugin_sessionvar_init(Session *session)
510
 
{
511
 
  session->variables.storage_engine= NULL;
512
 
  cleanup_variables(&session->variables);
513
 
 
514
 
  session->variables= global_system_variables;
515
 
  session->variables.storage_engine= NULL;
 
1588
sys_var *find_sys_var(THD *thd, const char *str, uint length)
 
1589
{
 
1590
  sys_var *var;
 
1591
  sys_var_pluginvar *pi= NULL;
 
1592
  plugin_ref plugin;
 
1593
 
 
1594
  rw_rdlock(&LOCK_system_variables_hash);
 
1595
  if ((var= intern_find_sys_var(str, length, false)) &&
 
1596
      (pi= var->cast_pluginvar()))
 
1597
  {
 
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))))
 
1601
      var= NULL; /* failed to lock it, it must be uninstalling */
 
1602
    else
 
1603
    if (!(plugin_state(plugin) & PLUGIN_IS_READY))
 
1604
    {
 
1605
      /* initialization not completed */
 
1606
      var= NULL;
 
1607
      intern_plugin_unlock(lex, plugin);
 
1608
    }
 
1609
  }
 
1610
  else
 
1611
    rw_unlock(&LOCK_system_variables_hash);
 
1612
 
 
1613
  /*
 
1614
    If the variable exists but the plugin it is associated with is not ready
 
1615
    then the intern_plugin_lock did not raise an error, so we do it here.
 
1616
  */
 
1617
  if (pi && !var)
 
1618
    my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
 
1619
  return(var);
 
1620
}
 
1621
 
 
1622
 
 
1623
/*
 
1624
  called by register_var, construct_options and test_plugin_options.
 
1625
  Returns the 'bookmark' for the named variable.
 
1626
  LOCK_system_variables_hash should be at least read locked
 
1627
*/
 
1628
static st_bookmark *find_bookmark(const char *plugin, const char *name, int flags)
 
1629
{
 
1630
  st_bookmark *result= NULL;
 
1631
  uint namelen, length, pluginlen= 0;
 
1632
  char *varname, *p;
 
1633
 
 
1634
  if (!(flags & PLUGIN_VAR_THDLOCAL))
 
1635
    return NULL;
 
1636
 
 
1637
  namelen= strlen(name);
 
1638
  if (plugin)
 
1639
    pluginlen= strlen(plugin) + 1;
 
1640
  length= namelen + pluginlen + 2;
 
1641
  varname= (char*) my_alloca(length);
 
1642
 
 
1643
  if (plugin)
 
1644
  {
 
1645
    strxmov(varname + 1, plugin, "_", name, NullS);
 
1646
    for (p= varname + 1; *p; p++)
 
1647
      if (*p == '-')
 
1648
        *p= '_';
 
1649
  }
 
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;
 
1660
}
 
1661
 
 
1662
 
 
1663
/*
 
1664
  returns a bookmark for thd-local variables, creating if neccessary.
 
1665
  returns null for non thd-local variables.
 
1666
  Requires that a write lock is obtained on LOCK_system_variables_hash
 
1667
*/
 
1668
static st_bookmark *register_var(const char *plugin, const char *name,
 
1669
                                 int flags)
 
1670
{
 
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))
 
1676
    return NULL;
 
1677
 
 
1678
  switch (flags & PLUGIN_VAR_TYPEMASK) {
 
1679
  case PLUGIN_VAR_BOOL:
 
1680
    size= sizeof(bool);
 
1681
    break;
 
1682
  case PLUGIN_VAR_INT:
 
1683
    size= sizeof(int);
 
1684
    break;
 
1685
  case PLUGIN_VAR_LONG:
 
1686
  case PLUGIN_VAR_ENUM:
 
1687
    size= sizeof(long);
 
1688
    break;
 
1689
  case PLUGIN_VAR_LONGLONG:
 
1690
  case PLUGIN_VAR_SET:
 
1691
    size= sizeof(uint64_t);
 
1692
    break;
 
1693
  case PLUGIN_VAR_STR:
 
1694
    size= sizeof(char*);
 
1695
    break;
 
1696
  default:
 
1697
    assert(0);
 
1698
    return NULL;
 
1699
  };
 
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= '_';
 
1706
 
 
1707
  if (!(result= find_bookmark(NULL, varname + 1, flags)))
 
1708
  {
 
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;
 
1715
 
 
1716
    assert(size && !(size & (size-1))); /* must be power of 2 */
 
1717
 
 
1718
    offset= global_system_variables.dynamic_variables_size;
 
1719
    offset= (offset + size - 1) & ~(size - 1);
 
1720
    result->offset= (int) offset;
 
1721
 
 
1722
    new_size= (offset + size + 63) & ~63;
 
1723
 
 
1724
    if (new_size > global_variables_dynamic_size)
 
1725
    {
 
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));
 
1732
      /*
 
1733
        Clear the new variable value space. This is required for string
 
1734
        variables. If their value is non-NULL, it must point to a valid
 
1735
        string.
 
1736
      */
 
1737
      memset(global_system_variables.dynamic_variables_ptr +
 
1738
             global_variables_dynamic_size, 0,
 
1739
             new_size - global_variables_dynamic_size);
 
1740
      memset(max_system_variables.dynamic_variables_ptr +
 
1741
             global_variables_dynamic_size, 0, 
 
1742
             new_size - global_variables_dynamic_size);
 
1743
      global_variables_dynamic_size= new_size;
 
1744
    }
 
1745
 
 
1746
    global_system_variables.dynamic_variables_head= offset;
 
1747
    max_system_variables.dynamic_variables_head= offset;
 
1748
    global_system_variables.dynamic_variables_size= offset + size;
 
1749
    max_system_variables.dynamic_variables_size= offset + size;
 
1750
    global_system_variables.dynamic_variables_version++;
 
1751
    max_system_variables.dynamic_variables_version++;
 
1752
 
 
1753
    result->version= global_system_variables.dynamic_variables_version;
 
1754
 
 
1755
    /* this should succeed because we have already checked if a dup exists */
 
1756
    if (my_hash_insert(&bookmark_hash, (uchar*) result))
 
1757
    {
 
1758
      fprintf(stderr, "failed to add placeholder to hash");
 
1759
      assert(0);
 
1760
    }
 
1761
  }
 
1762
  my_afree(varname);
 
1763
  return result;
 
1764
}
 
1765
 
 
1766
 
 
1767
/*
 
1768
  returns a pointer to the memory which holds the thd-local variable or
 
1769
  a pointer to the global variable if thd==null.
 
1770
  If required, will sync with global variables if the requested variable
 
1771
  has not yet been allocated in the current thread.
 
1772
*/
 
1773
static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
 
1774
{
 
1775
  assert(offset >= 0);
 
1776
  assert((uint)offset <= global_system_variables.dynamic_variables_head);
 
1777
 
 
1778
  if (!thd)
 
1779
    return (uchar*) global_system_variables.dynamic_variables_ptr + offset;
 
1780
 
 
1781
  /*
 
1782
    dynamic_variables_head points to the largest valid offset
 
1783
  */
 
1784
  if (!thd->variables.dynamic_variables_ptr ||
 
1785
      (uint)offset > thd->variables.dynamic_variables_head)
 
1786
  {
 
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));
 
1795
 
 
1796
    if (global_lock)
 
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,
 
1803
           global_system_variables.dynamic_variables_ptr +
 
1804
             thd->variables.dynamic_variables_size,
 
1805
           global_system_variables.dynamic_variables_size -
 
1806
             thd->variables.dynamic_variables_size);
 
1807
 
 
1808
    /*
 
1809
      now we need to iterate through any newly copied 'defaults'
 
1810
      and if it is a string type with MEMALLOC flag, we need to strdup
 
1811
    */
 
1812
    for (idx= 0; idx < bookmark_hash.records; idx++)
 
1813
    {
 
1814
      sys_var_pluginvar *pi;
 
1815
      sys_var *var;
 
1816
      st_bookmark *v= (st_bookmark*) hash_element(&bookmark_hash,idx);
 
1817
 
 
1818
      if (v->version <= thd->variables.dynamic_variables_version ||
 
1819
          !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
 
1820
          !(pi= var->cast_pluginvar()) ||
 
1821
          v->key[0] != (pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
 
1822
        continue;
 
1823
 
 
1824
      /* Here we do anything special that may be required of the data types */
 
1825
 
 
1826
      if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
 
1827
          pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
 
1828
      {
 
1829
         char **pp= (char**) (thd->variables.dynamic_variables_ptr +
 
1830
                             *(int*)(pi->plugin_var + 1));
 
1831
         if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr +
 
1832
                             *(int*)(pi->plugin_var + 1))))
 
1833
           *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
 
1834
      }
 
1835
    }
 
1836
 
 
1837
    if (global_lock)
 
1838
      pthread_mutex_unlock(&LOCK_global_system_variables);
 
1839
 
 
1840
    thd->variables.dynamic_variables_version=
 
1841
           global_system_variables.dynamic_variables_version;
 
1842
    thd->variables.dynamic_variables_head=
 
1843
           global_system_variables.dynamic_variables_head;
 
1844
    thd->variables.dynamic_variables_size=
 
1845
           global_system_variables.dynamic_variables_size;
 
1846
 
 
1847
    rw_unlock(&LOCK_system_variables_hash);
 
1848
  }
 
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;
516
1897
 
517
1898
  /* we are going to allocate these lazily */
518
 
  session->variables.dynamic_variables_version= 0;
519
 
  session->variables.dynamic_variables_size= 0;
520
 
  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;
521
1902
 
522
 
  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;
523
1907
}
524
1908
 
525
1909
 
526
1910
/*
527
1911
  Unlocks all system variables which hold a reference
528
1912
*/
529
 
static void unlock_variables(Session *, struct drizzle_system_variables *vars)
 
1913
static void unlock_variables(THD *thd __attribute__((unused)),
 
1914
                             struct system_variables *vars)
530
1915
{
531
 
  vars->storage_engine= NULL;
 
1916
  intern_plugin_unlock(NULL, vars->table_plugin);
 
1917
  vars->table_plugin= NULL;
532
1918
}
533
1919
 
534
1920
 
538
1924
  Unlike plugin_vars_free_values() it frees all variables of all plugins,
539
1925
  it's used on shutdown.
540
1926
*/
541
 
static void cleanup_variables(drizzle_system_variables *vars)
 
1927
static void cleanup_variables(THD *thd, struct system_variables *vars)
542
1928
{
543
 
  assert(vars->storage_engine == NULL);
544
 
 
545
 
  free(vars->dynamic_variables_ptr);
 
1929
  st_bookmark *v;
 
1930
  sys_var_pluginvar *pivar;
 
1931
  sys_var *var;
 
1932
  int flags;
 
1933
  uint idx;
 
1934
 
 
1935
  rw_rdlock(&LOCK_system_variables_hash);
 
1936
  for (idx= 0; idx < bookmark_hash.records; idx++)
 
1937
  {
 
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)) ||
 
1941
        !(pivar= var->cast_pluginvar()) ||
 
1942
        v->key[0] != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
 
1943
      continue;
 
1944
 
 
1945
    flags= pivar->plugin_var->flags;
 
1946
 
 
1947
    if ((flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
 
1948
        flags & PLUGIN_VAR_THDLOCAL && flags & PLUGIN_VAR_MEMALLOC)
 
1949
    {
 
1950
      char **ptr= (char**) pivar->real_value_ptr(thd, OPT_SESSION);
 
1951
      my_free(*ptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
 
1952
      *ptr= NULL;
 
1953
    }
 
1954
  }
 
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));
546
1960
  vars->dynamic_variables_ptr= NULL;
547
1961
  vars->dynamic_variables_size= 0;
548
1962
  vars->dynamic_variables_version= 0;
549
1963
}
550
1964
 
551
1965
 
552
 
void plugin_sessionvar_cleanup(Session *session)
553
 
{
554
 
  unlock_variables(session, &session->variables);
555
 
  cleanup_variables(&session->variables);
556
 
}
557
 
 
 
1966
void plugin_thdvar_cleanup(THD *thd)
 
1967
{
 
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;
 
1984
}
 
1985
 
 
1986
 
 
1987
/**
 
1988
  @brief Free values of thread variables of a plugin.
 
1989
 
 
1990
  This must be called before a plugin is deleted. Otherwise its
 
1991
  variables are no longer accessible and the value space is lost. Note
 
1992
  that only string values with PLUGIN_VAR_MEMALLOC are allocated and
 
1993
  must be freed.
 
1994
 
 
1995
  @param[in]        vars        Chain of system variables of a plugin
 
1996
*/
 
1997
 
 
1998
static void plugin_vars_free_values(sys_var *vars)
 
1999
{
 
2000
 
 
2001
  for (sys_var *var= vars; var; var= var->next)
 
2002
  {
 
2003
    sys_var_pluginvar *piv= var->cast_pluginvar();
 
2004
    if (piv &&
 
2005
        ((piv->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
 
2006
        (piv->plugin_var->flags & PLUGIN_VAR_MEMALLOC))
 
2007
    {
 
2008
      /* Free the string from global_system_variables. */
 
2009
      char **valptr= (char**) piv->real_value_ptr(NULL, OPT_GLOBAL);
 
2010
      my_free(*valptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
 
2011
      *valptr= NULL;
 
2012
    }
 
2013
  }
 
2014
  return;
 
2015
}
 
2016
 
 
2017
 
 
2018
bool sys_var_pluginvar::check_update_type(Item_result type)
 
2019
{
 
2020
  if (is_readonly())
 
2021
    return 1;
 
2022
  switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
 
2023
  case PLUGIN_VAR_INT:
 
2024
  case PLUGIN_VAR_LONG:
 
2025
  case PLUGIN_VAR_LONGLONG:
 
2026
    return type != INT_RESULT;
 
2027
  case PLUGIN_VAR_STR:
 
2028
    return type != STRING_RESULT;
 
2029
  default:
 
2030
    return 0;
 
2031
  }
 
2032
}
 
2033
 
 
2034
 
 
2035
SHOW_TYPE sys_var_pluginvar::show_type()
 
2036
{
 
2037
  switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
 
2038
  case PLUGIN_VAR_BOOL:
 
2039
    return SHOW_MY_BOOL;
 
2040
  case PLUGIN_VAR_INT:
 
2041
    return SHOW_INT;
 
2042
  case PLUGIN_VAR_LONG:
 
2043
    return SHOW_LONG;
 
2044
  case PLUGIN_VAR_LONGLONG:
 
2045
    return SHOW_LONGLONG;
 
2046
  case PLUGIN_VAR_STR:
 
2047
    return SHOW_CHAR_PTR;
 
2048
  case PLUGIN_VAR_ENUM:
 
2049
  case PLUGIN_VAR_SET:
 
2050
    return SHOW_CHAR;
 
2051
  default:
 
2052
    assert(0);
 
2053
    return SHOW_UNDEF;
 
2054
  }
 
2055
}
 
2056
 
 
2057
 
 
2058
uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type)
 
2059
{
 
2060
  assert(thd || (type == OPT_GLOBAL));
 
2061
  if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
 
2062
  {
 
2063
    if (type == OPT_GLOBAL)
 
2064
      thd= NULL;
 
2065
 
 
2066
    return intern_sys_var_ptr(thd, *(int*) (plugin_var+1), false);
 
2067
  }
 
2068
  return *(uchar**) (plugin_var+1);
 
2069
}
 
2070
 
 
2071
 
 
2072
TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
 
2073
{
 
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;
 
2083
  default:
 
2084
    return NULL;
 
2085
  }
 
2086
  return NULL;
 
2087
}
 
2088
 
 
2089
 
 
2090
uchar* sys_var_pluginvar::value_ptr(THD *thd, enum_var_type type,
 
2091
                                    LEX_STRING *base __attribute__((unused)))
 
2092
{
 
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
  }
 
2120
  return result;
 
2121
}
 
2122
 
 
2123
 
 
2124
bool sys_var_pluginvar::check(THD *thd, set_var *var)
 
2125
{
 
2126
  st_item_value_holder value;
 
2127
  assert(is_readonly() || plugin_var->check);
 
2128
 
 
2129
  value.value_type= item_value_type;
 
2130
  value.val_str= item_val_str;
 
2131
  value.val_int= item_val_int;
 
2132
  value.val_real= item_val_real;
 
2133
  value.item= var->value;
 
2134
 
 
2135
  return is_readonly() ||
 
2136
         plugin_var->check(thd, plugin_var, &var->save_result, &value);
 
2137
}
 
2138
 
 
2139
 
 
2140
void sys_var_pluginvar::set_default(THD *thd, enum_var_type type)
 
2141
{
 
2142
  const void *src;
 
2143
  void *tgt;
 
2144
 
 
2145
  assert(is_readonly() || plugin_var->update);
 
2146
 
 
2147
  if (is_readonly())
 
2148
    return;
 
2149
 
 
2150
  pthread_mutex_lock(&LOCK_global_system_variables);
 
2151
  tgt= real_value_ptr(thd, type);
 
2152
  src= ((void **) (plugin_var + 1) + 1);
 
2153
 
 
2154
  if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
 
2155
  {
 
2156
    if (type != OPT_GLOBAL)
 
2157
      src= real_value_ptr(thd, OPT_GLOBAL);
 
2158
    else
 
2159
    switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
 
2160
        case PLUGIN_VAR_INT:
 
2161
          src= &((thdvar_uint_t*) plugin_var)->def_val;
 
2162
          break;
 
2163
        case PLUGIN_VAR_LONG:
 
2164
          src= &((thdvar_ulong_t*) plugin_var)->def_val;
 
2165
          break;
 
2166
        case PLUGIN_VAR_LONGLONG:
 
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;
 
2174
          break;
 
2175
        case PLUGIN_VAR_BOOL:
 
2176
          src= &((thdvar_bool_t*) plugin_var)->def_val;
 
2177
          break;
 
2178
        case PLUGIN_VAR_STR:
 
2179
          src= &((thdvar_str_t*) plugin_var)->def_val;
 
2180
          break;
 
2181
        default:
 
2182
          assert(0);
 
2183
        }
 
2184
  }
 
2185
 
 
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);
 
2189
 
 
2190
  if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || type == OPT_GLOBAL)
 
2191
  {
 
2192
    plugin_var->update(thd, plugin_var, tgt, src);
 
2193
    pthread_mutex_unlock(&LOCK_global_system_variables);
 
2194
  }
 
2195
  else
 
2196
  {
 
2197
    pthread_mutex_unlock(&LOCK_global_system_variables);
 
2198
    plugin_var->update(thd, plugin_var, tgt, src);
 
2199
  }
 
2200
}
 
2201
 
 
2202
 
 
2203
bool sys_var_pluginvar::update(THD *thd, set_var *var)
 
2204
{
 
2205
  void *tgt;
 
2206
 
 
2207
  assert(is_readonly() || plugin_var->update);
 
2208
 
 
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);
 
2212
 
 
2213
  if (is_readonly())
 
2214
    return 1;
 
2215
 
 
2216
  pthread_mutex_lock(&LOCK_global_system_variables);
 
2217
  tgt= real_value_ptr(thd, var->type);
 
2218
 
 
2219
  if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || var->type == OPT_GLOBAL)
 
2220
  {
 
2221
    /* variable we are updating has global scope, so we unlock after updating */
 
2222
    plugin_var->update(thd, plugin_var, tgt, &var->save_result);
 
2223
    pthread_mutex_unlock(&LOCK_global_system_variables);
 
2224
  }
 
2225
  else
 
2226
  {
 
2227
    pthread_mutex_unlock(&LOCK_global_system_variables);
 
2228
    plugin_var->update(thd, plugin_var, tgt, &var->save_result);
 
2229
  }
 
2230
 return 0;
 
2231
}
 
2232
 
 
2233
 
 
2234
#define OPTION_SET_LIMITS(type, options, opt) \
 
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;         \
 
2239
  options->block_size= (long) (opt)->blk_sz
 
2240
 
 
2241
 
 
2242
static void plugin_opt_set_limits(struct my_option *options,
 
2243
                                  const struct st_mysql_sys_var *opt)
 
2244
{
 
2245
  options->sub_size= 0;
 
2246
 
 
2247
  switch (opt->flags & (PLUGIN_VAR_TYPEMASK |
 
2248
                        PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL)) {
 
2249
  /* global system variables */
 
2250
  case PLUGIN_VAR_INT:
 
2251
    OPTION_SET_LIMITS(GET_INT, options, (sysvar_int_t*) opt);
 
2252
    break;
 
2253
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED:
 
2254
    OPTION_SET_LIMITS(GET_UINT, options, (sysvar_uint_t*) opt);
 
2255
    break;
 
2256
  case PLUGIN_VAR_LONG:
 
2257
    OPTION_SET_LIMITS(GET_LONG, options, (sysvar_long_t*) opt);
 
2258
    break;
 
2259
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
 
2260
    OPTION_SET_LIMITS(GET_ULONG, options, (sysvar_ulong_t*) opt);
 
2261
    break;
 
2262
  case PLUGIN_VAR_LONGLONG:
 
2263
    OPTION_SET_LIMITS(GET_LL, options, (sysvar_int64_t_t*) opt);
 
2264
    break;
 
2265
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
 
2266
    OPTION_SET_LIMITS(GET_ULL, options, (sysvar_uint64_t_t*) opt);
 
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;
 
2282
  case PLUGIN_VAR_BOOL:
 
2283
    options->var_type= GET_BOOL;
 
2284
    options->def_value= ((sysvar_bool_t*) opt)->def_val;
 
2285
    break;
 
2286
  case PLUGIN_VAR_STR:
 
2287
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
 
2288
                        GET_STR_ALLOC : GET_STR);
 
2289
    options->def_value= (intptr_t) ((sysvar_str_t*) opt)->def_val;
 
2290
    break;
 
2291
  /* threadlocal variables */
 
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:
 
2325
    options->var_type= GET_BOOL;
 
2326
    options->def_value= ((thdvar_bool_t*) opt)->def_val;
 
2327
    break;
 
2328
  case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL:
 
2329
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
 
2330
                        GET_STR_ALLOC : GET_STR);
 
2331
    options->def_value= (intptr_t) ((thdvar_str_t*) opt)->def_val;
 
2332
    break;
 
2333
  default:
 
2334
    assert(0);
 
2335
  }
 
2336
  options->arg_type= REQUIRED_ARG;
 
2337
  if (opt->flags & PLUGIN_VAR_NOCMDARG)
 
2338
    options->arg_type= NO_ARG;
 
2339
  if (opt->flags & PLUGIN_VAR_OPCMDARG)
 
2340
    options->arg_type= OPT_ARG;
 
2341
}
 
2342
 
 
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;
 
2361
  char *optname, *p;
 
2362
  int index= 0, offset= 0;
 
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_utf8_general_ci, 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)
 
2377
  {
 
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;
 
2386
  }
 
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
 
 
2397
  /*
 
2398
    Two passes as the 2nd pass will take pointer addresses for use
 
2399
    by my_getopt and register_var() in the first pass uses realloc
 
2400
  */
 
2401
 
 
2402
  for (plugin_option= tmp->plugin->system_vars;
 
2403
       plugin_option && *plugin_option; plugin_option++, index++)
 
2404
  {
 
2405
    opt= *plugin_option;
 
2406
    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
 
2407
      continue;
 
2408
    if (!(register_var(name, opt->name, opt->flags)))
 
2409
      continue;
 
2410
    switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
 
2411
    case PLUGIN_VAR_BOOL:
 
2412
      (((thdvar_bool_t *)opt)->resolve)= mysql_sys_var_ptr_bool;
 
2413
      break;
 
2414
    case PLUGIN_VAR_INT:
 
2415
      (((thdvar_int_t *)opt)->resolve)= mysql_sys_var_ptr_int;
 
2416
      break;
 
2417
    case PLUGIN_VAR_LONG:
 
2418
      (((thdvar_long_t *)opt)->resolve)= mysql_sys_var_ptr_long;
 
2419
      break;
 
2420
    case PLUGIN_VAR_LONGLONG:
 
2421
      (((thdvar_int64_t_t *)opt)->resolve)= mysql_sys_var_ptr_int64_t;
 
2422
      break;
 
2423
    case PLUGIN_VAR_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;
 
2431
      break;
 
2432
    default:
 
2433
      sql_print_error(_("Unknown variable type code 0x%x in plugin '%s'."),
 
2434
                      opt->flags, plugin_name);
 
2435
      return(-1);
 
2436
    };
 
2437
  }
 
2438
 
 
2439
  for (plugin_option= tmp->plugin->system_vars;
 
2440
       plugin_option && *plugin_option; plugin_option++, index++)
 
2441
  {
 
2442
    switch ((opt= *plugin_option)->flags & PLUGIN_VAR_TYPEMASK) {
 
2443
    case PLUGIN_VAR_BOOL:
 
2444
      if (!opt->check)
 
2445
        opt->check= check_func_bool;
 
2446
      if (!opt->update)
 
2447
        opt->update= update_func_bool;
 
2448
      break;
 
2449
    case PLUGIN_VAR_INT:
 
2450
      if (!opt->check)
 
2451
        opt->check= check_func_int;
 
2452
      if (!opt->update)
 
2453
        opt->update= update_func_int;
 
2454
      break;
 
2455
    case PLUGIN_VAR_LONG:
 
2456
      if (!opt->check)
 
2457
        opt->check= check_func_long;
 
2458
      if (!opt->update)
 
2459
        opt->update= update_func_long;
 
2460
      break;
 
2461
    case PLUGIN_VAR_LONGLONG:
 
2462
      if (!opt->check)
 
2463
        opt->check= check_func_int64_t;
 
2464
      if (!opt->update)
 
2465
        opt->update= update_func_int64_t;
 
2466
      break;
 
2467
    case PLUGIN_VAR_STR:
 
2468
      if (!opt->check)
 
2469
        opt->check= check_func_str;
 
2470
      if (!opt->update)
 
2471
      {
 
2472
        opt->update= update_func_str;
 
2473
        if ((opt->flags & (PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY)) == false)
 
2474
        {
 
2475
          opt->flags|= PLUGIN_VAR_READONLY;
 
2476
          sql_print_warning(_("Server variable %s of plugin %s was forced "
 
2477
                            "to be read-only: string variable without "
 
2478
                            "update_func and PLUGIN_VAR_MEMALLOC flag"),
 
2479
                            opt->name, plugin_name);
 
2480
        }
 
2481
      }
 
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;
 
2495
    default:
 
2496
      sql_print_error(_("Unknown variable type code 0x%x in plugin '%s'."),
 
2497
                      opt->flags, plugin_name);
 
2498
      return(-1);
 
2499
    }
 
2500
 
 
2501
    if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_THDLOCAL))
 
2502
                    == PLUGIN_VAR_NOCMDOPT)
 
2503
      continue;
 
2504
 
 
2505
    if (!opt->name)
 
2506
    {
 
2507
      sql_print_error(_("Missing variable name in plugin '%s'."),
 
2508
                      plugin_name);
 
2509
      return(-1);
 
2510
    }
 
2511
 
 
2512
    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
 
2513
    {
 
2514
      optnamelen= strlen(opt->name);
 
2515
      optname= (char*) alloc_root(mem_root, namelen + optnamelen + 2);
 
2516
      strxmov(optname, name, "-", opt->name, NullS);
 
2517
      optnamelen= namelen + optnamelen + 1;
 
2518
    }
 
2519
    else
 
2520
    {
 
2521
      /* this should not fail because register_var should create entry */
 
2522
      if (!(v= find_bookmark(name, opt->name, opt->flags)))
 
2523
      {
 
2524
        sql_print_error(_("Thread local variable '%s' not allocated "
 
2525
                        "in plugin '%s'."), opt->name, plugin_name);
 
2526
        return(-1);
 
2527
      }
 
2528
 
 
2529
      *(int*)(opt + 1)= offset= v->offset;
 
2530
 
 
2531
      if (opt->flags & PLUGIN_VAR_NOCMDOPT)
 
2532
        continue;
 
2533
 
 
2534
      optname= (char*) memdup_root(mem_root, v->key + 1, 
 
2535
                                   (optnamelen= v->name_len) + 1);
 
2536
    }
 
2537
 
 
2538
    /* convert '_' to '-' */
 
2539
    for (p= optname; *p; p++)
 
2540
      if (*p == '_')
 
2541
        *p= '-';
 
2542
 
 
2543
    options->name= optname;
 
2544
    options->comment= opt->comment;
 
2545
    options->app_type= opt;
 
2546
    options->id= (options-1)->id + 1;
 
2547
 
 
2548
    plugin_opt_set_limits(options, opt);
 
2549
 
 
2550
    if (opt->flags & PLUGIN_VAR_THDLOCAL)
 
2551
      options->value= options->u_max_value= (char**)
 
2552
        (global_system_variables.dynamic_variables_ptr + offset);
 
2553
    else
 
2554
      options->value= options->u_max_value= *(char***) (opt + 1);
 
2555
 
 
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;
 
2562
  }
 
2563
 
 
2564
  return(0);
 
2565
}
 
2566
 
 
2567
 
 
2568
static my_option *construct_help_options(MEM_ROOT *mem_root,
 
2569
                                         struct st_plugin_int *p)
 
2570
{
 
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_utf8_general_ci, p->name.str, "MyISAM") == 0))
 
2584
    can_disable= false;
 
2585
  else if ((my_strcasecmp(&my_charset_utf8_general_ci, 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);
 
2593
 
 
2594
  return(opts);
 
2595
}
558
2596
 
559
2597
 
560
2598
/*
562
2600
    test_plugin_options()
563
2601
    tmp_root                    temporary scratch space
564
2602
    plugin                      internal plugin structure
 
2603
    argc                        user supplied arguments
 
2604
    argv                        user supplied arguments
565
2605
    default_enabled             default plugin enable status
566
2606
  RETURNS:
567
2607
    0 SUCCESS - plugin should be enabled/loaded
568
2608
  NOTE:
569
2609
    Requires that a write-lock is held on LOCK_system_variables_hash
570
2610
*/
571
 
static int test_plugin_options(memory::Root *,
572
 
                               module::Module *test_module,
573
 
                               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)
574
2613
{
575
 
 
576
 
  if (test_module->getManifest().init_options != NULL)
577
 
  {
578
 
    string plugin_section_title("Options used by ");
579
 
    plugin_section_title.append(test_module->getName());
580
 
    po::options_description module_options(plugin_section_title);
581
 
    module::option_context opt_ctx(test_module->getName(),
582
 
                                   module_options.add_options());
583
 
    test_module->getManifest().init_options(opt_ctx);
584
 
    long_options.add(module_options);
585
 
  }
586
 
 
587
 
  return 0;
 
2614
  struct sys_var_chain chain= { NULL, 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;
 
2622
  int error;
 
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_utf8_general_ci, tmp->name.str, "MyISAM") == 0))
 
2633
    can_disable= false;
 
2634
  else if ((my_strcasecmp(&my_charset_utf8_general_ci, 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
    }
 
2663
  }
 
2664
 
 
2665
  error= 1;
 
2666
 
 
2667
  {
 
2668
    for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
 
2669
    {
 
2670
      if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
 
2671
        continue;
 
2672
 
 
2673
      if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
 
2674
        v= new (mem_root) sys_var_pluginvar(var->key + 1, o);
 
2675
      else
 
2676
      {
 
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_utf8_general_ci, varname);
 
2681
 
 
2682
        for (p= varname; *p; p++)
 
2683
          if (*p == '-')
 
2684
            *p= '_';
 
2685
 
 
2686
        v= new (mem_root) sys_var_pluginvar(varname, o);
 
2687
      }
 
2688
      assert(v); /* check that an object was actually constructed */
 
2689
 
 
2690
      /*
 
2691
        Add to the chain of variables.
 
2692
        Done like this for easier debugging so that the
 
2693
        pointer to v is not lost on optimized builds.
 
2694
      */
 
2695
      v->chain_sys_var(&chain);
 
2696
    }
 
2697
    if (chain.first)
 
2698
    {
 
2699
      chain.last->next = NULL;
 
2700
      if (mysql_add_sys_var_chain(chain.first, NULL))
 
2701
      {
 
2702
        sql_print_error(_("Plugin '%s' has conflicting system variables"),
 
2703
                        tmp->name.str);
 
2704
        goto err;
 
2705
      }
 
2706
      tmp->system_vars= chain.first;
 
2707
    }
 
2708
    return(0);
 
2709
  }
 
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);
 
2714
err:
 
2715
  if (opts)
 
2716
    my_cleanup_options(opts);
 
2717
  return(error);
588
2718
}
589
2719
 
590
2720
 
592
2722
  Help Verbose text with Plugin System Variables
593
2723
****************************************************************************/
594
2724
 
595
 
class OptionCmp
596
 
{
597
 
public:
598
 
  bool operator() (const option &a, const option &b)
599
 
  {
600
 
    return my_strcasecmp(&my_charset_utf8_general_ci, a.name, b.name);
601
 
  }
602
 
};
603
 
 
604
 
 
605
 
void my_print_help_inc_plugins(option *main_options)
606
 
{
607
 
  module::Registry &registry= module::Registry::singleton();
608
 
  vector<option> all_options;
609
 
  memory::Root mem_root(4096);
610
 
 
 
2725
static int option_cmp(my_option *a, my_option *b)
 
2726
{
 
2727
  return my_strcasecmp(&my_charset_utf8_general_ci, 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);
611
2740
 
612
2741
  if (initialized)
613
 
  {
614
 
    std::map<std::string, module::Module *>::const_iterator modules=
615
 
      registry.getModulesMap().begin();
616
 
    
617
 
    while (modules != registry.getModulesMap().end())
 
2742
    for (uint idx= 0; idx < plugin_array.elements; idx++)
618
2743
    {
619
 
      module::Module *p= (*modules).second;
620
 
      ++modules;
 
2744
      p= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
621
2745
 
622
 
      /* If we have an init_options function, we are registering
623
 
         commmand line options that way, so don't do them this way */
624
 
      if (p->getManifest().init_options != NULL)
 
2746
      if (!p->plugin->system_vars ||
 
2747
          !(opt= construct_help_options(&mem_root, p)))
625
2748
        continue;
626
2749
 
 
2750
      /* Only options with a non-NULL comment are displayed in help text */
 
2751
      for (;opt->id; opt++)
 
2752
        if (opt->comment)
 
2753
          insert_dynamic(&all_options, (uchar*) opt);
627
2754
    }
628
 
  }
629
2755
 
630
2756
  for (;main_options->id; main_options++)
631
 
  {
632
 
    if (main_options->comment)
633
 
    {
634
 
      all_options.push_back(*main_options);
635
 
    }
636
 
  }
 
2757
    insert_dynamic(&all_options, (uchar*) main_options);
637
2758
 
638
 
  /** 
639
 
   * @TODO: Fix the option building so that it doens't break sort
640
 
   *
641
 
   * sort(all_options.begin(), all_options.end(), OptionCmp());
642
 
   */
 
2759
  sort_dynamic(&all_options, (qsort_cmp) option_cmp);
643
2760
 
644
2761
  /* main_options now points to the empty option terminator */
645
 
  all_options.push_back(*main_options);
646
 
 
647
 
  my_print_help(&*(all_options.begin()));
648
 
 
649
 
  mem_root.free_root(MYF(0));
 
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));
650
2769
}
651
2770
 
652
 
} /* namespace drizzled */
653
 
 
654