~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_plugin.cc

  • Committer: Brian Aker
  • Date: 2008-10-29 13:46:43 UTC
  • Revision ID: brian@tangent.org-20081029134643-z6jcwjvyruhk2vlu
Updates for ignore file.

Show diffs side-by-side

added added

removed removed

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