~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_plugin.cc

  • Committer: Brian Aker
  • Date: 2009-06-26 00:37:27 UTC
  • Revision ID: brian@gaz-20090626003727-b2y4gitpptzbvypd
Fix for CentOS

Show diffs side-by-side

added added

removed removed

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