Commit 8b39abe2 authored by Kristofer Pettersson's avatar Kristofer Pettersson

Bug#19027 MySQL 5.0 starts even with Fatal InnoDB errors

It is not possible to prevent the server from starting if a mandatory
built-in plugin fails to start. This can in some cases lead to data
corruption when the old table name space suddenly is used by a different
storage engine.

A boolean command line option in the form of --foobar is automatically
created for every existing plugin "foobar". By changing this command line
option from a boolean to a tristate { OFF, ON, FORCE } it is possible to
specify the plugin loading policy for each plugin.

The behavior is specified as follows:
   OFF   = Disable the plugin and start the server
   ON    = Enable the plugin and start the server even if an error occurrs
           during plugin initialization.
   FORCE = Enable the plugin but don't start the server if an error occurrs
           during plugin initialization.
parent 4edc43b7
...@@ -887,7 +887,7 @@ sub collect_one_test_case { ...@@ -887,7 +887,7 @@ sub collect_one_test_case {
if ( $tinfo->{'innodb_test'} ) if ( $tinfo->{'innodb_test'} )
{ {
# This is a test that need innodb # This is a test that need innodb
if ( $::mysqld_variables{'innodb'} ne "TRUE" ) if ( $::mysqld_variables{'innodb'} eq "OFF" )
{ {
# innodb is not supported, skip it # innodb is not supported, skip it
$tinfo->{'skip'}= 1; $tinfo->{'skip'}= 1;
......
...@@ -410,7 +410,8 @@ invalid value '%s'", ...@@ -410,7 +410,8 @@ invalid value '%s'",
argument= optend; argument= optend;
} }
else if (optp->arg_type == OPT_ARG && else if (optp->arg_type == OPT_ARG &&
(optp->var_type & GET_TYPE_MASK) == GET_BOOL) (((optp->var_type & GET_TYPE_MASK) == GET_BOOL) ||
(optp->var_type & GET_TYPE_MASK) == GET_ENUM))
{ {
if (optend == disabled_my_option) if (optend == disabled_my_option)
*((my_bool*) value)= (my_bool) 0; *((my_bool*) value)= (my_bool) 0;
......
...@@ -29,6 +29,18 @@ ...@@ -29,6 +29,18 @@
extern struct st_mysql_plugin *mysqld_builtins[]; extern struct st_mysql_plugin *mysqld_builtins[];
/**
@note The order of the enumeration is critical.
@see construct_options
*/
static const char *global_plugin_typelib_names[]=
{ "OFF", "ON", "FORCE", NULL };
enum enum_plugin_load_policy {PLUGIN_OFF, PLUGIN_ON, PLUGIN_FORCE};
static TYPELIB global_plugin_typelib=
{ array_elements(global_plugin_typelib_names)-1,
"", global_plugin_typelib_names, NULL };
char *opt_plugin_load= NULL; char *opt_plugin_load= NULL;
char *opt_plugin_dir_ptr; char *opt_plugin_dir_ptr;
char opt_plugin_dir[FN_REFLEN]; char opt_plugin_dir[FN_REFLEN];
...@@ -192,7 +204,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv); ...@@ -192,7 +204,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv);
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
const char *list); const char *list);
static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *, static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *,
int *, char **, my_bool); int *, char **);
static bool register_builtin(struct st_mysql_plugin *, struct st_plugin_int *, static bool register_builtin(struct st_mysql_plugin *, struct st_plugin_int *,
struct st_plugin_int **); struct st_plugin_int **);
static void unlock_variables(THD *thd, struct system_variables *vars); static void unlock_variables(THD *thd, struct system_variables *vars);
...@@ -751,7 +763,7 @@ static bool plugin_add(MEM_ROOT *tmp_root, ...@@ -751,7 +763,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
tmp.name.length= name_len; tmp.name.length= name_len;
tmp.ref_count= 0; tmp.ref_count= 0;
tmp.state= PLUGIN_IS_UNINITIALIZED; tmp.state= PLUGIN_IS_UNINITIALIZED;
if (test_plugin_options(tmp_root, &tmp, argc, argv, true)) if (test_plugin_options(tmp_root, &tmp, argc, argv))
tmp.state= PLUGIN_IS_DISABLED; tmp.state= PLUGIN_IS_DISABLED;
if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp))) if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
...@@ -997,7 +1009,6 @@ static int plugin_initialize(struct st_plugin_int *plugin) ...@@ -997,7 +1009,6 @@ static int plugin_initialize(struct st_plugin_int *plugin)
DBUG_ENTER("plugin_initialize"); DBUG_ENTER("plugin_initialize");
safe_mutex_assert_owner(&LOCK_plugin); safe_mutex_assert_owner(&LOCK_plugin);
if (plugin_type_initialize[plugin->plugin->type]) if (plugin_type_initialize[plugin->plugin->type])
{ {
if ((*plugin_type_initialize[plugin->plugin->type])(plugin)) if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
...@@ -1083,6 +1094,20 @@ uchar *get_bookmark_hash_key(const uchar *buff, size_t *length, ...@@ -1083,6 +1094,20 @@ uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
return (uchar*) var->key; return (uchar*) var->key;
} }
static inline void convert_dash_to_underscore(char *str, int len)
{
for (char *p= str; p <= str+len; p++)
if (*p == '-')
*p= '_';
}
static inline void convert_underscore_to_dash(char *str, int len)
{
for (char *p= str; p <= str+len; p++)
if (*p == '_')
*p= '-';
}
/* /*
The logic is that we first load and initialize all compiled in plugins. The logic is that we first load and initialize all compiled in plugins.
...@@ -1094,11 +1119,12 @@ uchar *get_bookmark_hash_key(const uchar *buff, size_t *length, ...@@ -1094,11 +1119,12 @@ uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
int plugin_init(int *argc, char **argv, int flags) int plugin_init(int *argc, char **argv, int flags)
{ {
uint i; uint i;
bool def_enabled, is_myisam; bool is_myisam;
struct st_mysql_plugin **builtins; struct st_mysql_plugin **builtins;
struct st_mysql_plugin *plugin; struct st_mysql_plugin *plugin;
struct st_plugin_int tmp, *plugin_ptr, **reap; struct st_plugin_int tmp, *plugin_ptr, **reap;
MEM_ROOT tmp_root; MEM_ROOT tmp_root;
bool reaped_mandatory_plugin= FALSE;
DBUG_ENTER("plugin_init"); DBUG_ENTER("plugin_init");
if (initialized) if (initialized)
...@@ -1142,17 +1168,13 @@ int plugin_init(int *argc, char **argv, int flags) ...@@ -1142,17 +1168,13 @@ int plugin_init(int *argc, char **argv, int flags)
!my_strnncoll(&my_charset_latin1, (const uchar*) plugin->name, !my_strnncoll(&my_charset_latin1, (const uchar*) plugin->name,
6, (const uchar*) "InnoDB", 6)) 6, (const uchar*) "InnoDB", 6))
continue; continue;
/* by default, ndbcluster and federated are disabled */
def_enabled=
my_strcasecmp(&my_charset_latin1, plugin->name, "NDBCLUSTER") != 0 &&
my_strcasecmp(&my_charset_latin1, plugin->name, "FEDERATED") != 0;
bzero(&tmp, sizeof(tmp)); bzero(&tmp, sizeof(tmp));
tmp.plugin= plugin; tmp.plugin= plugin;
tmp.name.str= (char *)plugin->name; tmp.name.str= (char *)plugin->name;
tmp.name.length= strlen(plugin->name); tmp.name.length= strlen(plugin->name);
tmp.state= 0; tmp.state= 0;
free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE)); free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
if (test_plugin_options(&tmp_root, &tmp, argc, argv, def_enabled)) if (test_plugin_options(&tmp_root, &tmp, argc, argv))
tmp.state= PLUGIN_IS_DISABLED; tmp.state= PLUGIN_IS_DISABLED;
else else
tmp.state= PLUGIN_IS_UNINITIALIZED; tmp.state= PLUGIN_IS_UNINITIALIZED;
...@@ -1227,6 +1249,8 @@ int plugin_init(int *argc, char **argv, int flags) ...@@ -1227,6 +1249,8 @@ int plugin_init(int *argc, char **argv, int flags)
while ((plugin_ptr= *(--reap))) while ((plugin_ptr= *(--reap)))
{ {
pthread_mutex_unlock(&LOCK_plugin); pthread_mutex_unlock(&LOCK_plugin);
if (plugin_ptr->is_mandatory)
reaped_mandatory_plugin= TRUE;
plugin_deinitialize(plugin_ptr, true); plugin_deinitialize(plugin_ptr, true);
pthread_mutex_lock(&LOCK_plugin); pthread_mutex_lock(&LOCK_plugin);
plugin_del(plugin_ptr); plugin_del(plugin_ptr);
...@@ -1234,6 +1258,8 @@ int plugin_init(int *argc, char **argv, int flags) ...@@ -1234,6 +1258,8 @@ int plugin_init(int *argc, char **argv, int flags)
pthread_mutex_unlock(&LOCK_plugin); pthread_mutex_unlock(&LOCK_plugin);
my_afree(reap); my_afree(reap);
if (reaped_mandatory_plugin)
goto err;
end: end:
free_root(&tmp_root, MYF(0)); free_root(&tmp_root, MYF(0));
...@@ -1299,7 +1325,7 @@ bool plugin_register_builtin(THD *thd, struct st_mysql_plugin *plugin) ...@@ -1299,7 +1325,7 @@ bool plugin_register_builtin(THD *thd, struct st_mysql_plugin *plugin)
pthread_mutex_lock(&LOCK_plugin); pthread_mutex_lock(&LOCK_plugin);
rw_wrlock(&LOCK_system_variables_hash); rw_wrlock(&LOCK_system_variables_hash);
if (test_plugin_options(thd->mem_root, &tmp, &dummy_argc, NULL, true)) if (test_plugin_options(thd->mem_root, &tmp, &dummy_argc, NULL))
goto end; goto end;
tmp.state= PLUGIN_IS_UNINITIALIZED; tmp.state= PLUGIN_IS_UNINITIALIZED;
if ((result= register_builtin(plugin, &tmp, &ptr))) if ((result= register_builtin(plugin, &tmp, &ptr)))
...@@ -2889,59 +2915,78 @@ my_bool get_one_plugin_option(int optid __attribute__((unused)), ...@@ -2889,59 +2915,78 @@ my_bool get_one_plugin_option(int optid __attribute__((unused)),
} }
/**
Creates a set of my_option objects associated with a specified plugin-
handle.
@param mem_root Memory allocator to be used.
@param tmp A pointer to a plugin handle
@param[out] options A pointer to a pre-allocated static array
The set is stored in the pre-allocated static array supplied to the function.
The size of the array is calculated as (number_of_plugin_varaibles*2+3). The
reason is that each option can have a prefix '--plugin-' in addtion to the
shorter form '--&lt;plugin-name&gt;'. There is also space allocated for
terminating NULL pointers.
@return
@retval -1 An error occurred
@retval 0 Success
*/
static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
my_option *options, my_bool **enabled, my_option *options)
bool can_disable)
{ {
const char *plugin_name= tmp->plugin->name; const char *plugin_name= tmp->plugin->name;
uint namelen= strlen(plugin_name), optnamelen; const LEX_STRING plugin_dash = { C_STRING_WITH_LEN("plugin-") };
uint buffer_length= namelen * 4 + (can_disable ? 75 : 10); uint plugin_name_len= strlen(plugin_name);
char *name= (char*) alloc_root(mem_root, buffer_length) + 1; uint optnamelen;
char *optname, *p; const int max_comment_len= 180;
char *comment= (char *) alloc_root(mem_root, max_comment_len + 1);
char *optname;
int index= 0, offset= 0; int index= 0, offset= 0;
st_mysql_sys_var *opt, **plugin_option; st_mysql_sys_var *opt, **plugin_option;
st_bookmark *v; st_bookmark *v;
/** Used to circumvent the const attribute on my_option::name */
char *plugin_name_ptr, *plugin_name_with_prefix_ptr;
DBUG_ENTER("construct_options"); DBUG_ENTER("construct_options");
DBUG_PRINT("plugin", ("plugin: '%s' enabled: %d can_disable: %d",
plugin_name, **enabled, can_disable));
options[0].name= plugin_name_ptr= (char*) alloc_root(mem_root,
plugin_name_len + 1);
strcpy(plugin_name_ptr, plugin_name);
my_casedn_str(&my_charset_latin1, plugin_name_ptr);
convert_underscore_to_dash(plugin_name_ptr, plugin_name_len);
/* support --skip-plugin-foo syntax */ /* support --skip-plugin-foo syntax */
memcpy(name, plugin_name, namelen + 1); options[1].name= plugin_name_with_prefix_ptr= (char*) alloc_root(mem_root,
my_casedn_str(&my_charset_latin1, name); plugin_name_len +
strxmov(name + namelen + 1, "plugin-", name, NullS); plugin_dash.length + 1);
/* Now we have namelen + 1 + 7 + namelen + 1 == namelen * 2 + 9. */ strxmov(plugin_name_with_prefix_ptr, plugin_dash.str, options[0].name, NullS);
for (p= name + namelen*2 + 8; p > name; p--)
if (*p == '_')
*p= '-';
if (can_disable) options[0].id= options[1].id= 256; /* must be >255. dup id ok */
{ options[0].var_type= options[1].var_type= GET_ENUM;
strxmov(name + namelen*2 + 10, "Enable ", plugin_name, " plugin. " options[0].arg_type= options[1].arg_type= OPT_ARG;
"Disable with --skip-", name," (will save memory).", NullS); options[0].def_value= options[1].def_value= 1; /* ON */
/* options[0].typelib= options[1].typelib= &global_plugin_typelib;
Now we have namelen * 2 + 10 (one char unused) + 7 + namelen + 9 +
20 + namelen + 20 + 1 == namelen * 4 + 67.
*/
options[0].comment= name + namelen*2 + 10; strxnmov(comment, max_comment_len, "Enable or disable ", plugin_name,
} " plugin. Possible values are ON, OFF, FORCE (don't start "
"if the plugin fails to load).", NullS);
options[0].comment= comment;
/* /*
NOTE: 'name' is one char above the allocated buffer! Allocate temporary space for the value of the tristate.
NOTE: This code assumes that 'my_bool' and 'char' are of same size. This option will have a limited lifetime and is not used beyond
server initialization.
GET_ENUM value is an integer.
*/ */
*((my_bool *)(name -1))= **enabled; options[0].value= options[1].value= (uchar **)alloc_root(mem_root,
*enabled= (my_bool *)(name - 1); sizeof(int));
*((uint*) options[0].value)= *((uint*) options[1].value)=
(uint) options[0].def_value;
options[1].name= (options[0].name= name) + namelen + 1;
options[0].id= options[1].id= 256; /* must be >255. dup id ok */
options[0].var_type= options[1].var_type= GET_BOOL;
options[0].arg_type= options[1].arg_type= NO_ARG;
options[0].def_value= options[1].def_value= **enabled;
options[0].value= options[0].u_max_value=
options[1].value= options[1].u_max_value= (uchar**) (name - 1);
options+= 2; options+= 2;
/* /*
...@@ -2955,7 +3000,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, ...@@ -2955,7 +3000,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
opt= *plugin_option; opt= *plugin_option;
if (!(opt->flags & PLUGIN_VAR_THDLOCAL)) if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
continue; continue;
if (!(register_var(name, opt->name, opt->flags))) if (!(register_var(plugin_name_ptr, opt->name, opt->flags)))
continue; continue;
switch (opt->flags & PLUGIN_VAR_TYPEMASK) { switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
case PLUGIN_VAR_BOOL: case PLUGIN_VAR_BOOL:
...@@ -3020,7 +3065,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, ...@@ -3020,7 +3065,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
if (!opt->update) if (!opt->update)
{ {
opt->update= update_func_str; opt->update= update_func_str;
if (!(opt->flags & PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY)) if (!(opt->flags & (PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY)))
{ {
opt->flags|= PLUGIN_VAR_READONLY; opt->flags|= PLUGIN_VAR_READONLY;
sql_print_warning("Server variable %s of plugin %s was forced " sql_print_warning("Server variable %s of plugin %s was forced "
...@@ -3062,14 +3107,14 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, ...@@ -3062,14 +3107,14 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
if (!(opt->flags & PLUGIN_VAR_THDLOCAL)) if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
{ {
optnamelen= strlen(opt->name); optnamelen= strlen(opt->name);
optname= (char*) alloc_root(mem_root, namelen + optnamelen + 2); optname= (char*) alloc_root(mem_root, plugin_name_len + optnamelen + 2);
strxmov(optname, name, "-", opt->name, NullS); strxmov(optname, plugin_name_ptr, "-", opt->name, NullS);
optnamelen= namelen + optnamelen + 1; optnamelen= plugin_name_len + optnamelen + 1;
} }
else else
{ {
/* this should not fail because register_var should create entry */ /* this should not fail because register_var should create entry */
if (!(v= find_bookmark(name, opt->name, opt->flags))) if (!(v= find_bookmark(plugin_name_ptr, opt->name, opt->flags)))
{ {
sql_print_error("Thread local variable '%s' not allocated " sql_print_error("Thread local variable '%s' not allocated "
"in plugin '%s'.", opt->name, plugin_name); "in plugin '%s'.", opt->name, plugin_name);
...@@ -3085,10 +3130,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, ...@@ -3085,10 +3130,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
(optnamelen= v->name_len) + 1); (optnamelen= v->name_len) + 1);
} }
/* convert '_' to '-' */ convert_underscore_to_dash(optname, optnamelen);
for (p= optname; *p; p++)
if (*p == '_')
*p= '-';
options->name= optname; options->name= optname;
options->comment= opt->comment; options->comment= opt->comment;
...@@ -3103,10 +3145,13 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, ...@@ -3103,10 +3145,13 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
else else
options->value= options->u_max_value= *(uchar***) (opt + 1); options->value= options->u_max_value= *(uchar***) (opt + 1);
char *option_name_ptr;
options[1]= options[0]; options[1]= options[0];
options[1].name= p= (char*) alloc_root(mem_root, optnamelen + 8); options[1].name= option_name_ptr= (char*) alloc_root(mem_root,
options[1].comment= 0; // hidden plugin_dash.length +
strxmov(p, "plugin-", optname, NullS); optnamelen + 1);
options[1].comment= 0; /* Hidden from the help text */
strxmov(option_name_ptr, plugin_dash.str, optname, NullS);
options+= 2; options+= 2;
} }
...@@ -3120,55 +3165,57 @@ static my_option *construct_help_options(MEM_ROOT *mem_root, ...@@ -3120,55 +3165,57 @@ static my_option *construct_help_options(MEM_ROOT *mem_root,
{ {
st_mysql_sys_var **opt; st_mysql_sys_var **opt;
my_option *opts; my_option *opts;
my_bool dummy, can_disable;
my_bool *dummy2= &dummy;
uint count= EXTRA_OPTIONS; uint count= EXTRA_OPTIONS;
DBUG_ENTER("construct_help_options"); DBUG_ENTER("construct_help_options");
for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2); for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2)
;
if (!(opts= (my_option*) alloc_root(mem_root, sizeof(my_option) * count))) if (!(opts= (my_option*) alloc_root(mem_root, sizeof(my_option) * count)))
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
bzero(opts, sizeof(my_option) * count); bzero(opts, sizeof(my_option) * count);
dummy= TRUE; /* plugin is enabled. */ if (construct_options(mem_root, p, opts))
can_disable=
my_strcasecmp(&my_charset_latin1, p->name.str, "MyISAM") &&
my_strcasecmp(&my_charset_latin1, p->name.str, "MEMORY");
if (construct_options(mem_root, p, opts, &dummy2, can_disable))
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
DBUG_RETURN(opts); DBUG_RETURN(opts);
} }
/* /**
SYNOPSIS Create and register system variables supplied from the plugin and
test_plugin_options() assigns initial values from corresponding command line arguments.
tmp_root temporary scratch space
plugin internal plugin structure @param tmp_root Temporary scratch space
argc user supplied arguments @param[out] plugin Internal plugin structure
argv user supplied arguments @param argc Number of command line arguments
default_enabled default plugin enable status @param argv Command line argument vector
RETURNS:
0 SUCCESS - plugin should be enabled/loaded The plugin will be updated with a policy on how to handle errors during
NOTE: initialization.
Requires that a write-lock is held on LOCK_system_variables_hash
@note Requires that a write-lock is held on LOCK_system_variables_hash
@return How initialization of the plugin should be handled.
@retval 0 Initialization should proceed.
@retval 1 Plugin is disabled.
@retval -1 An error has occurred.
*/ */
static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
int *argc, char **argv, my_bool default_enabled) int *argc, char **argv)
{ {
struct sys_var_chain chain= { NULL, NULL }; struct sys_var_chain chain= { NULL, NULL };
my_bool enabled_saved= default_enabled, can_disable; my_bool can_disable;
my_bool *enabled= &default_enabled; bool disable_plugin;
enum_plugin_load_policy plugin_load_policy= PLUGIN_ON;
MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ? MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ?
&tmp->mem_root : &plugin_mem_root; &tmp->mem_root : &plugin_mem_root;
st_mysql_sys_var **opt; st_mysql_sys_var **opt;
my_option *opts= NULL; my_option *opts= NULL;
char *p, *varname; char *varname;
int error; int error;
st_mysql_sys_var *o; st_mysql_sys_var *o;
sys_var *v; sys_var *v;
...@@ -3177,13 +3224,17 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, ...@@ -3177,13 +3224,17 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
DBUG_ENTER("test_plugin_options"); DBUG_ENTER("test_plugin_options");
DBUG_ASSERT(tmp->plugin && tmp->name.str); DBUG_ASSERT(tmp->plugin && tmp->name.str);
/*
The 'federated' and 'ndbcluster' storage engines are always disabled by
default.
*/
if (!(my_strcasecmp(&my_charset_latin1, tmp->name.str, "federated") &&
my_strcasecmp(&my_charset_latin1, tmp->name.str, "ndbcluster")))
plugin_load_policy= PLUGIN_OFF;
for (opt= tmp->plugin->system_vars; opt && *opt; opt++) for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */ count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
can_disable=
my_strcasecmp(&my_charset_latin1, tmp->name.str, "MyISAM") &&
my_strcasecmp(&my_charset_latin1, tmp->name.str, "MEMORY");
if (count > EXTRA_OPTIONS || (*argc > 1)) if (count > EXTRA_OPTIONS || (*argc > 1))
{ {
if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count))) if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count)))
...@@ -3193,12 +3244,18 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, ...@@ -3193,12 +3244,18 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
} }
bzero(opts, sizeof(my_option) * count); bzero(opts, sizeof(my_option) * count);
if (construct_options(tmp_root, tmp, opts, &enabled, can_disable)) if (construct_options(tmp_root, tmp, opts))
{ {
sql_print_error("Bad options for plugin '%s'.", tmp->name.str); sql_print_error("Bad options for plugin '%s'.", tmp->name.str);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
/*
We adjust the default value to account for the hardcoded exceptions
we have set for the federated and ndbcluster storage engines.
*/
opts[0].def_value= opts[1].def_value= (int)plugin_load_policy;
error= handle_options(argc, &argv, opts, get_one_plugin_option); error= handle_options(argc, &argv, opts, get_one_plugin_option);
(*argc)++; /* add back one for the program name */ (*argc)++; /* add back one for the program name */
...@@ -3208,64 +3265,79 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, ...@@ -3208,64 +3265,79 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
tmp->name.str); tmp->name.str);
goto err; goto err;
} }
/*
Set plugin loading policy from option value. First element in the option
list is always the <plugin name> option value.
*/
plugin_load_policy= (enum_plugin_load_policy)*(uint*)opts[0].value;
} }
if (!*enabled && !can_disable) disable_plugin= (plugin_load_policy == PLUGIN_OFF);
/*
The 'MyISAM' and 'Memory' storage engines currently can't be disabled.
*/
can_disable=
my_strcasecmp(&my_charset_latin1, tmp->name.str, "MyISAM") &&
my_strcasecmp(&my_charset_latin1, tmp->name.str, "MEMORY");
tmp->is_mandatory= (plugin_load_policy == PLUGIN_FORCE) || !can_disable;
if (disable_plugin && !can_disable)
{ {
sql_print_warning("Plugin '%s' cannot be disabled", tmp->name.str); sql_print_warning("Plugin '%s' cannot be disabled", tmp->name.str);
*enabled= TRUE; disable_plugin= FALSE;
} }
error= 1; /*
If the plugin is disabled it should not be initialized.
*/
if (disable_plugin)
{
if (global_system_variables.log_warnings)
sql_print_information("Plugin '%s' is disabled.",
tmp->name.str);
if (opts)
my_cleanup_options(opts);
DBUG_RETURN(1);
}
if (*enabled) error= 1;
for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
{ {
for (opt= tmp->plugin->system_vars; opt && *opt; opt++) if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
continue;
if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
v= new (mem_root) sys_var_pluginvar(var->key + 1, o);
else
{ {
if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR)) len= tmp->name.length + strlen(o->name) + 2;
continue; varname= (char*) alloc_root(mem_root, len);
strxmov(varname, tmp->name.str, "-", o->name, NullS);
if ((var= find_bookmark(tmp->name.str, o->name, o->flags))) my_casedn_str(&my_charset_latin1, varname);
v= new (mem_root) sys_var_pluginvar(var->key + 1, o); convert_dash_to_underscore(varname, len);
else v= new (mem_root) sys_var_pluginvar(varname, o);
{
len= tmp->name.length + strlen(o->name) + 2;
varname= (char*) alloc_root(mem_root, len);
strxmov(varname, tmp->name.str, "-", o->name, NullS);
my_casedn_str(&my_charset_latin1, varname);
for (p= varname; *p; p++)
if (*p == '-')
*p= '_';
v= new (mem_root) sys_var_pluginvar(varname, o);
}
DBUG_ASSERT(v); /* check that an object was actually constructed */
/*
Add to the chain of variables.
Done like this for easier debugging so that the
pointer to v is not lost on optimized builds.
*/
v->chain_sys_var(&chain);
} }
if (chain.first) DBUG_ASSERT(v); /* check that an object was actually constructed */
/*
Add to the chain of variables.
Done like this for easier debugging so that the
pointer to v is not lost on optimized builds.
*/
v->chain_sys_var(&chain);
} /* end for */
if (chain.first)
{
chain.last->next = NULL;
if (mysql_add_sys_var_chain(chain.first, NULL))
{ {
chain.last->next = NULL; sql_print_error("Plugin '%s' has conflicting system variables",
if (mysql_add_sys_var_chain(chain.first, NULL)) tmp->name.str);
{ goto err;
sql_print_error("Plugin '%s' has conflicting system variables",
tmp->name.str);
goto err;
}
tmp->system_vars= chain.first;
} }
DBUG_RETURN(0); tmp->system_vars= chain.first;
} }
DBUG_RETURN(0);
if (enabled_saved && global_system_variables.log_warnings)
sql_print_information("Plugin '%s' disabled by command line option",
tmp->name.str);
err: err:
if (opts) if (opts)
my_cleanup_options(opts); my_cleanup_options(opts);
......
...@@ -79,6 +79,7 @@ struct st_plugin_int ...@@ -79,6 +79,7 @@ struct st_plugin_int
void *data; /* plugin type specific, e.g. handlerton */ void *data; /* plugin type specific, e.g. handlerton */
MEM_ROOT mem_root; /* memory for dynamic plugin structures */ MEM_ROOT mem_root; /* memory for dynamic plugin structures */
sys_var *system_vars; /* server variables for this plugin */ sys_var *system_vars; /* server variables for this plugin */
bool is_mandatory; /* If true then plugin must not fail to load */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment