Commit 1c530b36 authored by Sergei Golubchik's avatar Sergei Golubchik

mdev-20: INSTALL PLUGIN SONAME

parent 98141ea4
......@@ -462,8 +462,6 @@ extern "C" int madvise(void *addr, size_t len, int behav);
#ifndef SO_EXT
#ifdef _WIN32
#define SO_EXT ".dll"
#elif defined(__APPLE__)
#define SO_EXT ".dylib"
#else
#define SO_EXT ".so"
#endif
......
......@@ -3,15 +3,41 @@ Warnings:
Warning 1286 Unknown storage engine 'EXAMPLE'
Warning 1266 Using storage engine MyISAM for table 't1'
DROP TABLE t1;
INSTALL PLUGIN example SONAME 'ha_example.so';
INSTALL PLUGIN EXAMPLE SONAME 'ha_example.so';
INSTALL PLUGIN example SONAME 'ha_example';
INSTALL PLUGIN EXAMPLE SONAME 'ha_example';
ERROR HY000: Function 'EXAMPLE' already exists
UNINSTALL PLUGIN example;
INSTALL PLUGIN example SONAME 'ha_example.so';
INSTALL SONAME 'ha_example';
select * from information_schema.plugins where plugin_library like 'ha_example%';
PLUGIN_NAME EXAMPLE
PLUGIN_VERSION 0.1
PLUGIN_STATUS ACTIVE
PLUGIN_TYPE STORAGE ENGINE
PLUGIN_TYPE_VERSION #
PLUGIN_LIBRARY ha_example.so
PLUGIN_LIBRARY_VERSION 1.1
PLUGIN_AUTHOR Brian Aker, MySQL AB
PLUGIN_DESCRIPTION Example storage engine
PLUGIN_LICENSE GPL
LOAD_OPTION ON
PLUGIN_MATURITY Experimental
PLUGIN_AUTH_VERSION 0.1
PLUGIN_NAME UNUSABLE
PLUGIN_VERSION 3.14
PLUGIN_STATUS ACTIVE
PLUGIN_TYPE DAEMON
PLUGIN_TYPE_VERSION #
PLUGIN_LIBRARY ha_example.so
PLUGIN_LIBRARY_VERSION 1.1
PLUGIN_AUTHOR Sergei Golubchik
PLUGIN_DESCRIPTION Unusable Daemon
PLUGIN_LICENSE GPL
LOAD_OPTION ON
PLUGIN_MATURITY Experimental
PLUGIN_AUTH_VERSION 3.14.15.926
CREATE TABLE t1(a int) ENGINE=EXAMPLE;
SELECT * FROM t1;
a
DROP TABLE t1;
set global example_ulong_var=500;
set global example_enum_var= e1;
show status like 'example%';
......@@ -21,7 +47,24 @@ show variables like 'example%';
Variable_name Value
example_enum_var e1
example_ulong_var 500
UNINSTALL PLUGIN example;
UNINSTALL SONAME 'ha_example';
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown
select * from information_schema.plugins where plugin_library like 'ha_example%';
PLUGIN_NAME EXAMPLE
PLUGIN_VERSION 0.1
PLUGIN_STATUS DELETED
PLUGIN_TYPE STORAGE ENGINE
PLUGIN_TYPE_VERSION #
PLUGIN_LIBRARY ha_example.so
PLUGIN_LIBRARY_VERSION 1.1
PLUGIN_AUTHOR Brian Aker, MySQL AB
PLUGIN_DESCRIPTION Example storage engine
PLUGIN_LICENSE GPL
LOAD_OPTION ON
PLUGIN_MATURITY Experimental
PLUGIN_AUTH_VERSION 0.1
DROP TABLE t1;
UNINSTALL PLUGIN EXAMPLE;
ERROR 42000: PLUGIN EXAMPLE does not exist
UNINSTALL PLUGIN non_exist;
......@@ -30,13 +73,13 @@ ERROR 42000: PLUGIN non_exist does not exist
# Bug#32034: check_func_enum() does not check correct values but set it
# to impossible int val
#
INSTALL PLUGIN example SONAME 'ha_example.so';
INSTALL PLUGIN example SONAME 'ha_example';
SET GLOBAL example_enum_var= e1;
SET GLOBAL example_enum_var= e2;
SET GLOBAL example_enum_var= impossible;
ERROR 42000: Variable 'example_enum_var' can't be set to the value of 'impossible'
UNINSTALL PLUGIN example;
INSTALL PLUGIN example SONAME 'ha_example.so';
INSTALL PLUGIN example SONAME 'ha_example';
select @@session.sql_mode into @old_sql_mode;
set session sql_mode='';
set global example_ulong_var=500;
......
INSTALL PLUGIN example SONAME 'ha_example.so';
ERROR HY000: Can't open shared library 'ha_example.so' (errno: 0 Loading of experimental plugins is prohibited by --plugin-maturity=stable)
ERROR HY000: Can't open shared library 'ha_example.so' (errno: 0 Loading of experimental plugin EXAMPLE is prohibited by --plugin-maturity=stable)
INSTALL SONAME 'ha_example.so';
ERROR HY000: Can't open shared library 'ha_example.so' (errno: 0 Loading of experimental plugin EXAMPLE is prohibited by --plugin-maturity=stable)
show warnings;
Level Code Message
Error 1126 Can't open shared library 'ha_example.so' (errno: 0 Loading of experimental plugin EXAMPLE is prohibited by --plugin-maturity=stable)
Error 1126 Can't open shared library 'ha_example.so' (errno: 0 Loading of experimental plugin UNUSABLE is prohibited by --plugin-maturity=stable)
......@@ -4,23 +4,23 @@
CREATE TABLE t1(a int) ENGINE=EXAMPLE;
DROP TABLE t1;
--replace_regex /\.dll/.so/
eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO';
eval INSTALL PLUGIN example SONAME 'ha_example';
--replace_regex /\.dll/.so/
--error 1125
eval INSTALL PLUGIN EXAMPLE SONAME '$HA_EXAMPLE_SO';
eval INSTALL PLUGIN EXAMPLE SONAME 'ha_example';
UNINSTALL PLUGIN example;
eval INSTALL SONAME 'ha_example';
--replace_column 5 #
--replace_regex /\.dll/.so/
eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO';
--query_vertical select * from information_schema.plugins where plugin_library like 'ha_example%'
CREATE TABLE t1(a int) ENGINE=EXAMPLE;
# Let's do some advanced ops with the example engine :)
SELECT * FROM t1;
DROP TABLE t1;
# a couple of tests for variables
set global example_ulong_var=500;
......@@ -28,7 +28,13 @@ set global example_enum_var= e1;
show status like 'example%';
show variables like 'example%';
UNINSTALL PLUGIN example;
eval UNINSTALL SONAME 'ha_example';
--replace_column 5 #
--replace_regex /\.dll/.so/
--query_vertical select * from information_schema.plugins where plugin_library like 'ha_example%'
DROP TABLE t1;
--error 1305
UNINSTALL PLUGIN EXAMPLE;
......@@ -40,8 +46,7 @@ UNINSTALL PLUGIN non_exist;
--echo # Bug#32034: check_func_enum() does not check correct values but set it
--echo # to impossible int val
--echo #
--replace_regex /\.dll/.so/
eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO';
eval INSTALL PLUGIN example SONAME 'ha_example';
SET GLOBAL example_enum_var= e1;
SET GLOBAL example_enum_var= e2;
......@@ -55,8 +60,7 @@ UNINSTALL PLUGIN example;
#
# Bug #32757 hang with sql_mode set when setting some global variables
#
--replace_regex /\.dll/.so/
eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO';
eval INSTALL PLUGIN example SONAME 'ha_example';
select @@session.sql_mode into @old_sql_mode;
......
......@@ -4,3 +4,9 @@
--replace_regex /\.dll/.so/
--error 1126
eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO';
--replace_regex /\.dll/.so/
--error 1126
eval INSTALL SONAME '$HA_EXAMPLE_SO';
--replace_regex /\.dll/.so/
show warnings;
......@@ -2594,13 +2594,10 @@ drop table t1;
create procedure proc_1() install plugin my_plug soname 'some_plugin.so';
--replace_regex /(Can\'t open shared library).*$/\1/
--error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED
call proc_1();
--replace_regex /(Can\'t open shared library).*$/\1/
--error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED
call proc_1();
--replace_regex /(Can\'t open shared library).*$/\1/
--error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED
call proc_1();
drop procedure proc_1;
......
......@@ -4363,7 +4363,8 @@ case SQLCOM_PREPARE:
my_ok(thd);
break;
case SQLCOM_UNINSTALL_PLUGIN:
if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment)))
if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment,
&thd->lex->ident)))
my_ok(thd);
break;
case SQLCOM_BINLOG_BASE64_EVENT:
......
......@@ -297,8 +297,7 @@ class sys_var_pluginvar: public sys_var
/* prototypes */
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,
const char *list);
static bool plugin_load_list(MEM_ROOT *, int *, char **, const char *);
static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *,
int *, char **);
static bool register_builtin(struct st_maria_plugin *, struct st_plugin_int *,
......@@ -318,6 +317,7 @@ static void reap_plugins(void);
static void report_error(int where_to, uint error, ...)
{
va_list args;
DBUG_ASSERT(where_to & (REPORT_TO_USER | REPORT_TO_LOG));
if (where_to & REPORT_TO_USER)
{
va_start(args, error);
......@@ -351,6 +351,20 @@ bool check_valid_path(const char *path, size_t len)
return prefix < len;
}
static void fix_dl_name(MEM_ROOT *root, LEX_STRING *dl)
{
const size_t so_ext_len= sizeof(SO_EXT) - 1;
if (my_strcasecmp(&my_charset_latin1, dl->str + dl->length - so_ext_len,
SO_EXT))
{
char *s= (char*)alloc_root(root, dl->length + so_ext_len + 1);
memcpy(s, dl->str, dl->length);
strcpy(s + dl->length, SO_EXT);
dl->str= s;
dl->length+= so_ext_len;
}
}
/****************************************************************************
Value type thunks, allows the C world to play in the C++ world
......@@ -1017,31 +1031,40 @@ static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
Requires that a write-lock is held on LOCK_system_variables_hash
*/
static bool plugin_add(MEM_ROOT *tmp_root,
const LEX_STRING *name, const LEX_STRING *dl,
const LEX_STRING *name, LEX_STRING *dl,
int *argc, char **argv, int report)
{
struct st_plugin_int tmp;
struct st_maria_plugin *plugin;
uint oks= 0, errs= 0;
DBUG_ENTER("plugin_add");
if (plugin_find_internal(name, MYSQL_ANY_PLUGIN))
if (name->str && plugin_find_internal(name, MYSQL_ANY_PLUGIN))
{
report_error(report, ER_UDF_EXISTS, name->str);
DBUG_RETURN(TRUE);
}
/* Clear the whole struct to catch future extensions. */
bzero((char*) &tmp, sizeof(tmp));
fix_dl_name(tmp_root, dl);
if (! (tmp.plugin_dl= plugin_dl_add(dl, report)))
DBUG_RETURN(TRUE);
/* Find plugin by name */
for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++)
{
uint name_len= strlen(plugin->name);
if (plugin->type >= 0 && plugin->type < MYSQL_MAX_PLUGIN_TYPE_NUM &&
! my_strnncoll(system_charset_info,
(const uchar *)name->str, name->length,
(const uchar *)plugin->name,
name_len))
{
tmp.name.str= (char *)plugin->name;
tmp.name.length= strlen(plugin->name);
if (plugin->type < 0 || plugin->type >= MYSQL_MAX_PLUGIN_TYPE_NUM)
continue; // invalid plugin
if (name->str && my_strnncoll(system_charset_info,
(const uchar *)name->str, name->length,
(const uchar *)tmp.name.str, tmp.name.length))
continue; // plugin name doesn't match
if (!name->str && plugin_find_internal(&tmp.name, MYSQL_ANY_PLUGIN))
continue; // already installed
struct st_plugin_int *tmp_plugin_ptr;
if (*(int*)plugin->info <
min_plugin_info_interface_version[plugin->type] ||
......@@ -1051,7 +1074,8 @@ static bool plugin_add(MEM_ROOT *tmp_root,
char buf[256];
strxnmov(buf, sizeof(buf) - 1, "API version for ",
plugin_type_names[plugin->type].str,
" plugin is too different", NullS);
" plugin ", tmp.name.str,
" not supported by this version of the server", NullS);
report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf);
goto err;
}
......@@ -1060,40 +1084,49 @@ static bool plugin_add(MEM_ROOT *tmp_root,
char buf[256];
strxnmov(buf, sizeof(buf) - 1, "Loading of ",
plugin_maturity_names[plugin->maturity],
" plugins is prohibited by --plugin-maturity=",
" plugin ", tmp.name.str,
" is prohibited by --plugin-maturity=",
plugin_maturity_names[plugin_maturity],
NullS);
report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf);
goto err;
}
tmp.plugin= plugin;
tmp.name.str= (char *)plugin->name;
tmp.name.length= name_len;
tmp.ref_count= 0;
tmp.state= PLUGIN_IS_UNINITIALIZED;
tmp.load_option= PLUGIN_ON;
if (test_plugin_options(tmp_root, &tmp, argc, argv))
tmp.state= PLUGIN_IS_DISABLED;
if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
if (!(tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
{
plugin_array_version++;
if (!my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
{
init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096);
DBUG_RETURN(FALSE);
}
tmp_plugin_ptr->state= PLUGIN_IS_FREED;
mysql_del_sys_var_chain(tmp.system_vars);
restore_pluginvar_names(tmp.system_vars);
goto err;
}
mysql_del_sys_var_chain(tmp.system_vars);
restore_pluginvar_names(tmp.system_vars);
goto err;
}
}
report_error(report, ER_CANT_FIND_DL_ENTRY, name->str);
plugin_array_version++;
if (my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
tmp_plugin_ptr->state= PLUGIN_IS_FREED;
init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096);
if (name->str)
DBUG_RETURN(FALSE); // all done
oks++;
tmp.plugin_dl->ref_count++;
continue; // otherwise - go on
err:
errs++;
if (name->str)
break;
}
if (errs == 0 && oks == 0) // no plugin was found
report_error(report, ER_CANT_FIND_DL_ENTRY, name->str);
plugin_dl_del(dl);
DBUG_RETURN(TRUE);
DBUG_RETURN(errs > 0 || oks == 0);
}
......@@ -1760,8 +1793,6 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
{
char buffer[FN_REFLEN];
LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
struct st_plugin_dl *plugin_dl;
struct st_maria_plugin *plugin;
char *p= buffer;
DBUG_ENTER("plugin_load_list");
while (list)
......@@ -1791,19 +1822,10 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
dl= name;
mysql_mutex_lock(&LOCK_plugin);
if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG)))
{
for (plugin= plugin_dl->plugins; plugin->info; plugin++)
{
name.str= (char *) plugin->name;
name.length= strlen(name.str);
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
goto error;
}
plugin_dl_del(&dl); // reduce ref count
}
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
name.str= 0; // load everything
if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
goto error;
}
else
{
......@@ -1970,14 +1992,68 @@ void plugin_shutdown(void)
DBUG_VOID_RETURN;
}
/**
complete plugin installation (after plugin_add).
That is, initialize it, and update mysql.plugin table
*/
static bool finalize_install(THD *thd, TABLE *table, const LEX_STRING *name)
{
struct st_plugin_int *tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN);
int error;
DBUG_ASSERT(tmp);
mysql_mutex_assert_owner(&LOCK_plugin);
if (tmp->state == PLUGIN_IS_DISABLED)
{
if (global_system_variables.log_warnings)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_CANT_INITIALIZE_UDF, ER(ER_CANT_INITIALIZE_UDF),
name->str, "Plugin is disabled");
}
else
{
DBUG_ASSERT(tmp->state == PLUGIN_IS_UNINITIALIZED);
if (plugin_initialize(tmp))
{
report_error(REPORT_TO_USER, ER_CANT_INITIALIZE_UDF, name->str,
"Plugin initialization function failed.");
tmp->state= PLUGIN_IS_DELETED;
return 1;
}
}
/*
We do not replicate the INSTALL PLUGIN statement. Disable binlogging
of the insert into the plugin table, so that it is not replicated in
row based mode.
*/
tmp_disable_binlog(thd);
table->use_all_columns();
restore_record(table, s->default_values);
table->field[0]->store(name->str, name->length, system_charset_info);
table->field[1]->store(tmp->plugin_dl->dl.str, tmp->plugin_dl->dl.length,
files_charset_info);
error= table->file->ha_write_row(table->record[0]);
reenable_binlog(thd);
if (error)
{
table->file->print_error(error, MYF(0));
tmp->state= PLUGIN_IS_DELETED;
return 1;
}
return 0;
}
bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl)
bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
const LEX_STRING *dl_arg)
{
TABLE_LIST tables;
TABLE *table;
int error, argc=orig_argc;
LEX_STRING dl= *dl_arg;
bool error;
int argc=orig_argc;
char **argv=orig_argv;
struct st_plugin_int *tmp;
DBUG_ENTER("mysql_install_plugin");
if (opt_noacl)
......@@ -2024,53 +2100,34 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl
report_error(REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str);
goto err;
}
error= plugin_add(thd->mem_root, name, dl, &argc, argv, REPORT_TO_USER);
error= plugin_add(thd->mem_root, name, &dl, &argc, argv, REPORT_TO_USER);
if (argv)
free_defaults(argv);
mysql_rwlock_unlock(&LOCK_system_variables_hash);
if (error || !(tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
if (error)
goto err;
if (tmp->state == PLUGIN_IS_DISABLED)
{
if (global_system_variables.log_warnings)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_CANT_INITIALIZE_UDF, ER(ER_CANT_INITIALIZE_UDF),
name->str, "Plugin is disabled");
}
if (name->str)
error= finalize_install(thd, table, name);
else
{
if (plugin_initialize(tmp))
st_plugin_dl *plugin_dl= plugin_dl_find(&dl);
struct st_maria_plugin *plugin;
for (plugin= plugin_dl->plugins; plugin->info; plugin++)
{
my_error(ER_CANT_INITIALIZE_UDF, MYF(0), name->str,
"Plugin initialization function failed.");
goto deinit;
LEX_STRING str= { const_cast<char*>(plugin->name), strlen(plugin->name) };
error|= finalize_install(thd, table, &str);
}
}
/*
We do not replicate the INSTALL PLUGIN statement. Disable binlogging
of the insert into the plugin table, so that it is not replicated in
row based mode.
*/
tmp_disable_binlog(thd);
table->use_all_columns();
restore_record(table, s->default_values);
table->field[0]->store(name->str, name->length, system_charset_info);
table->field[1]->store(dl->str, dl->length, files_charset_info);
error= table->file->ha_write_row(table->record[0]);
reenable_binlog(thd);
if (error)
{
table->file->print_error(error, MYF(0));
goto deinit;
}
mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(FALSE);
deinit:
tmp->state= PLUGIN_IS_DELETED;
reap_needed= true;
reap_plugins();
err:
......@@ -2079,66 +2136,27 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl
}
bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
static bool do_uninstall(THD *thd, TABLE *table, const LEX_STRING *name)
{
TABLE *table;
TABLE_LIST tables;
struct st_plugin_int *plugin;
DBUG_ENTER("mysql_uninstall_plugin");
if (opt_noacl)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
DBUG_RETURN(TRUE);
}
tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE);
if (check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
/* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
DBUG_RETURN(TRUE);
/*
Pre-acquire audit plugins for events that may potentially occur
during [UN]INSTALL PLUGIN.
When audit event is triggered, audit subsystem acquires interested
plugins by walking through plugin list. Evidently plugin list
iterator protects plugin list by acquiring LOCK_plugin, see
plugin_foreach_with_mask().
On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
rather for a long time.
When audit event is triggered during [UN]INSTALL PLUGIN, plugin
list iterator acquires the same lock (within the same thread)
second time.
This hack should be removed when LOCK_plugin is fixed so it
protects only what it supposed to protect.
*/
mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS);
mysql_mutex_assert_owner(&LOCK_plugin);
mysql_mutex_lock(&LOCK_plugin);
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
{
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
goto err;
return 1;
}
if (!plugin->plugin_dl)
{
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
WARN_PLUGIN_DELETE_BUILTIN, ER(WARN_PLUGIN_DELETE_BUILTIN));
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
goto err;
return 1;
}
if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
{
my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str);
goto err;
return 1;
}
plugin->state= PLUGIN_IS_DELETED;
......@@ -2147,8 +2165,6 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
WARN_PLUGIN_BUSY, ER(WARN_PLUGIN_BUSY));
else
reap_needed= true;
reap_plugins();
mysql_mutex_unlock(&LOCK_plugin);
uchar user_key[MAX_KEY_LENGTH];
table->use_all_columns();
......@@ -2170,13 +2186,74 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
if (error)
{
table->file->print_error(error, MYF(0));
DBUG_RETURN(TRUE);
return 1;
}
}
DBUG_RETURN(FALSE);
err:
return 0;
}
bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name,
const LEX_STRING *dl_arg)
{
TABLE *table;
TABLE_LIST tables;
LEX_STRING dl= *dl_arg;
bool error= false;
DBUG_ENTER("mysql_uninstall_plugin");
if (opt_noacl)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
DBUG_RETURN(TRUE);
}
tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE);
if (check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
/* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
DBUG_RETURN(TRUE);
/*
Pre-acquire audit plugins for events that may potentially occur
during [UN]INSTALL PLUGIN.
When audit event is triggered, audit subsystem acquires interested
plugins by walking through plugin list. Evidently plugin list
iterator protects plugin list by acquiring LOCK_plugin, see
plugin_foreach_with_mask().
On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
rather for a long time.
When audit event is triggered during [UN]INSTALL PLUGIN, plugin
list iterator acquires the same lock (within the same thread)
second time.
*/
mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS);
mysql_mutex_lock(&LOCK_plugin);
if (name->str)
error= do_uninstall(thd, table, name);
else
{
fix_dl_name(thd->mem_root, &dl);
st_plugin_dl *plugin_dl= plugin_dl_find(&dl);
struct st_maria_plugin *plugin;
for (plugin= plugin_dl->plugins; plugin->info; plugin++)
{
LEX_STRING str= { const_cast<char*>(plugin->name), strlen(plugin->name) };
error|= do_uninstall(thd, table, &str);
}
}
reap_plugins();
mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(TRUE);
DBUG_RETURN(error);
}
......
......@@ -159,7 +159,8 @@ extern void plugin_unlock(THD *thd, plugin_ref plugin);
extern void plugin_unlock_list(THD *thd, plugin_ref *list, uint count);
extern bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
const LEX_STRING *dl);
extern bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name);
extern bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name,
const LEX_STRING *dl);
extern bool plugin_register_builtin(struct st_mysql_plugin *plugin);
extern void plugin_thdvar_init(THD *thd);
extern void plugin_thdvar_cleanup(THD *thd);
......
......@@ -15141,6 +15141,13 @@ install:
lex->comment= $3;
lex->ident= $5;
}
| INSTALL_SYM SONAME_SYM TEXT_STRING_sys
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_INSTALL_PLUGIN;
lex->comment= null_lex_str;
lex->ident= $3;
}
;
uninstall:
......@@ -15150,6 +15157,13 @@ uninstall:
lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
lex->comment= $3;
}
| UNINSTALL_SYM SONAME_SYM TEXT_STRING_sys
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
lex->comment= null_lex_str;
lex->ident= $3;
}
;
/* Avoid compiler warning from sql_yacc.cc where yyerrlab1 is not used */
......
......@@ -19,17 +19,23 @@
@brief
The ha_example engine is a stubbed storage engine for example purposes only;
it does nothing at this point. Its purpose is to provide a source
it does almost nothing at this point. Its purpose is to provide a source
code illustration of how to begin writing new storage engines; see also
/storage/example/ha_example.h.
storage/example/ha_example.h.
Additionally, this file includes an example of a daemon plugin which does
nothing at all - absolutely nothing, even less than example storage engine.
But it shows that one dll/so can contain more than one plugin.
@details
ha_example will let you create/open/delete tables, but
nothing further (for example, indexes are not supported nor can data
be stored in the table). Use this example as a template for
implementing the same functionality in your own storage engine. You
can enable the example storage engine in your build by doing the
following during your build process:<br> ./configure
be stored in the table). It also provides new status (example_func_example)
and system (example_ulong_var and example_enum_var) variables.
Use this example as a template for implementing the same functionality in
your own storage engine. You can enable the example storage engine in your
build by doing the following during your build process:<br> ./configure
--with-example-storage-engine
Once this is done, MySQL will let you create tables with:<br>
......@@ -1111,6 +1117,9 @@ static struct st_mysql_show_var func_status[]=
{0,0,SHOW_UNDEF}
};
struct st_mysql_daemon unusable_example=
{ MYSQL_DAEMON_INTERFACE_VERSION };
mysql_declare_plugin(example)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
......@@ -1138,10 +1147,25 @@ maria_declare_plugin(example)
PLUGIN_LICENSE_GPL,
example_init_func, /* Plugin Init */
example_done_func, /* Plugin Deinit */
0x0001 /* 0.1 */,
0x0001, /* version number (0.1) */
func_status, /* status variables */
example_system_variables, /* system variables */
"0.1", /* string version */
MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
},
{
MYSQL_DAEMON_PLUGIN,
&unusable_example,
"UNUSABLE",
"Sergei Golubchik",
"Unusable Daemon",
PLUGIN_LICENSE_GPL,
NULL, /* Plugin Init */
NULL, /* Plugin Deinit */
0x030E, /* version number (3.14) */
NULL, /* status variables */
NULL, /* system variables */
"3.14.15.926" , /* version, as a string */
MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
}
maria_declare_plugin_end;
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