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); ...@@ -462,8 +462,6 @@ extern "C" int madvise(void *addr, size_t len, int behav);
#ifndef SO_EXT #ifndef SO_EXT
#ifdef _WIN32 #ifdef _WIN32
#define SO_EXT ".dll" #define SO_EXT ".dll"
#elif defined(__APPLE__)
#define SO_EXT ".dylib"
#else #else
#define SO_EXT ".so" #define SO_EXT ".so"
#endif #endif
......
...@@ -3,15 +3,41 @@ Warnings: ...@@ -3,15 +3,41 @@ Warnings:
Warning 1286 Unknown storage engine 'EXAMPLE' Warning 1286 Unknown storage engine 'EXAMPLE'
Warning 1266 Using storage engine MyISAM for table 't1' Warning 1266 Using storage engine MyISAM for table 't1'
DROP TABLE t1; DROP TABLE t1;
INSTALL PLUGIN example SONAME 'ha_example.so'; INSTALL PLUGIN example SONAME 'ha_example';
INSTALL PLUGIN EXAMPLE SONAME 'ha_example.so'; INSTALL PLUGIN EXAMPLE SONAME 'ha_example';
ERROR HY000: Function 'EXAMPLE' already exists ERROR HY000: Function 'EXAMPLE' already exists
UNINSTALL PLUGIN example; 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; CREATE TABLE t1(a int) ENGINE=EXAMPLE;
SELECT * FROM t1; SELECT * FROM t1;
a a
DROP TABLE t1;
set global example_ulong_var=500; set global example_ulong_var=500;
set global example_enum_var= e1; set global example_enum_var= e1;
show status like 'example%'; show status like 'example%';
...@@ -21,7 +47,24 @@ show variables like 'example%'; ...@@ -21,7 +47,24 @@ show variables like 'example%';
Variable_name Value Variable_name Value
example_enum_var e1 example_enum_var e1
example_ulong_var 500 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; UNINSTALL PLUGIN EXAMPLE;
ERROR 42000: PLUGIN EXAMPLE does not exist ERROR 42000: PLUGIN EXAMPLE does not exist
UNINSTALL PLUGIN non_exist; UNINSTALL PLUGIN non_exist;
...@@ -30,13 +73,13 @@ ERROR 42000: PLUGIN non_exist does not 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 # Bug#32034: check_func_enum() does not check correct values but set it
# to impossible int val # 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= e1;
SET GLOBAL example_enum_var= e2; SET GLOBAL example_enum_var= e2;
SET GLOBAL example_enum_var= impossible; SET GLOBAL example_enum_var= impossible;
ERROR 42000: Variable 'example_enum_var' can't be set to the value of 'impossible' ERROR 42000: Variable 'example_enum_var' can't be set to the value of 'impossible'
UNINSTALL PLUGIN example; UNINSTALL PLUGIN example;
INSTALL PLUGIN example SONAME 'ha_example.so'; INSTALL PLUGIN example SONAME 'ha_example';
select @@session.sql_mode into @old_sql_mode; select @@session.sql_mode into @old_sql_mode;
set session sql_mode=''; set session sql_mode='';
set global example_ulong_var=500; set global example_ulong_var=500;
......
INSTALL PLUGIN example SONAME 'ha_example.so'; 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 @@ ...@@ -4,23 +4,23 @@
CREATE TABLE t1(a int) ENGINE=EXAMPLE; CREATE TABLE t1(a int) ENGINE=EXAMPLE;
DROP TABLE t1; DROP TABLE t1;
--replace_regex /\.dll/.so/ eval INSTALL PLUGIN example SONAME 'ha_example';
eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO';
--replace_regex /\.dll/.so/ --replace_regex /\.dll/.so/
--error 1125 --error 1125
eval INSTALL PLUGIN EXAMPLE SONAME '$HA_EXAMPLE_SO'; eval INSTALL PLUGIN EXAMPLE SONAME 'ha_example';
UNINSTALL PLUGIN example; UNINSTALL PLUGIN example;
eval INSTALL SONAME 'ha_example';
--replace_column 5 #
--replace_regex /\.dll/.so/ --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; CREATE TABLE t1(a int) ENGINE=EXAMPLE;
# Let's do some advanced ops with the example engine :) # Let's do some advanced ops with the example engine :)
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE t1;
# a couple of tests for variables # a couple of tests for variables
set global example_ulong_var=500; set global example_ulong_var=500;
...@@ -28,7 +28,13 @@ set global example_enum_var= e1; ...@@ -28,7 +28,13 @@ set global example_enum_var= e1;
show status like 'example%'; show status like 'example%';
show variables 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 --error 1305
UNINSTALL PLUGIN EXAMPLE; UNINSTALL PLUGIN EXAMPLE;
...@@ -40,8 +46,7 @@ UNINSTALL PLUGIN non_exist; ...@@ -40,8 +46,7 @@ UNINSTALL PLUGIN non_exist;
--echo # Bug#32034: check_func_enum() does not check correct values but set it --echo # Bug#32034: check_func_enum() does not check correct values but set it
--echo # to impossible int val --echo # to impossible int val
--echo # --echo #
--replace_regex /\.dll/.so/ eval INSTALL PLUGIN example SONAME 'ha_example';
eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO';
SET GLOBAL example_enum_var= e1; SET GLOBAL example_enum_var= e1;
SET GLOBAL example_enum_var= e2; SET GLOBAL example_enum_var= e2;
...@@ -55,8 +60,7 @@ UNINSTALL PLUGIN example; ...@@ -55,8 +60,7 @@ UNINSTALL PLUGIN example;
# #
# Bug #32757 hang with sql_mode set when setting some global variables # Bug #32757 hang with sql_mode set when setting some global variables
# #
--replace_regex /\.dll/.so/ eval INSTALL PLUGIN example SONAME 'ha_example';
eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO';
select @@session.sql_mode into @old_sql_mode; select @@session.sql_mode into @old_sql_mode;
......
...@@ -4,3 +4,9 @@ ...@@ -4,3 +4,9 @@
--replace_regex /\.dll/.so/ --replace_regex /\.dll/.so/
--error 1126 --error 1126
eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO'; 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; ...@@ -2594,13 +2594,10 @@ drop table t1;
create procedure proc_1() install plugin my_plug soname 'some_plugin.so'; 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 --error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED
call proc_1(); call proc_1();
--replace_regex /(Can\'t open shared library).*$/\1/
--error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED --error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED
call proc_1(); call proc_1();
--replace_regex /(Can\'t open shared library).*$/\1/
--error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED --error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED
call proc_1(); call proc_1();
drop procedure proc_1; drop procedure proc_1;
......
...@@ -4363,7 +4363,8 @@ case SQLCOM_PREPARE: ...@@ -4363,7 +4363,8 @@ case SQLCOM_PREPARE:
my_ok(thd); my_ok(thd);
break; break;
case SQLCOM_UNINSTALL_PLUGIN: 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); my_ok(thd);
break; break;
case SQLCOM_BINLOG_BASE64_EVENT: case SQLCOM_BINLOG_BASE64_EVENT:
......
...@@ -297,8 +297,7 @@ class sys_var_pluginvar: public sys_var ...@@ -297,8 +297,7 @@ class sys_var_pluginvar: public sys_var
/* prototypes */ /* prototypes */
static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv); 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 *, int *, char **, const char *);
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 **); int *, char **);
static bool register_builtin(struct st_maria_plugin *, struct st_plugin_int *, static bool register_builtin(struct st_maria_plugin *, struct st_plugin_int *,
...@@ -318,6 +317,7 @@ static void reap_plugins(void); ...@@ -318,6 +317,7 @@ static void reap_plugins(void);
static void report_error(int where_to, uint error, ...) static void report_error(int where_to, uint error, ...)
{ {
va_list args; va_list args;
DBUG_ASSERT(where_to & (REPORT_TO_USER | REPORT_TO_LOG));
if (where_to & REPORT_TO_USER) if (where_to & REPORT_TO_USER)
{ {
va_start(args, error); va_start(args, error);
...@@ -351,6 +351,20 @@ bool check_valid_path(const char *path, size_t len) ...@@ -351,6 +351,20 @@ bool check_valid_path(const char *path, size_t len)
return prefix < 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 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) ...@@ -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 Requires that a write-lock is held on LOCK_system_variables_hash
*/ */
static bool plugin_add(MEM_ROOT *tmp_root, 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) int *argc, char **argv, int report)
{ {
struct st_plugin_int tmp; struct st_plugin_int tmp;
struct st_maria_plugin *plugin; struct st_maria_plugin *plugin;
uint oks= 0, errs= 0;
DBUG_ENTER("plugin_add"); 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); report_error(report, ER_UDF_EXISTS, name->str);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
/* Clear the whole struct to catch future extensions. */ /* Clear the whole struct to catch future extensions. */
bzero((char*) &tmp, sizeof(tmp)); bzero((char*) &tmp, sizeof(tmp));
fix_dl_name(tmp_root, dl);
if (! (tmp.plugin_dl= plugin_dl_add(dl, report))) if (! (tmp.plugin_dl= plugin_dl_add(dl, report)))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
/* Find plugin by name */ /* Find plugin by name */
for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++) for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++)
{ {
uint name_len= strlen(plugin->name); tmp.name.str= (char *)plugin->name;
if (plugin->type >= 0 && plugin->type < MYSQL_MAX_PLUGIN_TYPE_NUM && tmp.name.length= strlen(plugin->name);
! my_strnncoll(system_charset_info,
(const uchar *)name->str, name->length, if (plugin->type < 0 || plugin->type >= MYSQL_MAX_PLUGIN_TYPE_NUM)
(const uchar *)plugin->name, continue; // invalid plugin
name_len))
{ 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; struct st_plugin_int *tmp_plugin_ptr;
if (*(int*)plugin->info < if (*(int*)plugin->info <
min_plugin_info_interface_version[plugin->type] || min_plugin_info_interface_version[plugin->type] ||
...@@ -1051,7 +1074,8 @@ static bool plugin_add(MEM_ROOT *tmp_root, ...@@ -1051,7 +1074,8 @@ static bool plugin_add(MEM_ROOT *tmp_root,
char buf[256]; char buf[256];
strxnmov(buf, sizeof(buf) - 1, "API version for ", strxnmov(buf, sizeof(buf) - 1, "API version for ",
plugin_type_names[plugin->type].str, 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); report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf);
goto err; goto err;
} }
...@@ -1060,40 +1084,49 @@ static bool plugin_add(MEM_ROOT *tmp_root, ...@@ -1060,40 +1084,49 @@ static bool plugin_add(MEM_ROOT *tmp_root,
char buf[256]; char buf[256];
strxnmov(buf, sizeof(buf) - 1, "Loading of ", strxnmov(buf, sizeof(buf) - 1, "Loading of ",
plugin_maturity_names[plugin->maturity], 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], plugin_maturity_names[plugin_maturity],
NullS); NullS);
report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf); report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf);
goto err; goto err;
} }
tmp.plugin= plugin; tmp.plugin= plugin;
tmp.name.str= (char *)plugin->name;
tmp.name.length= name_len;
tmp.ref_count= 0; tmp.ref_count= 0;
tmp.state= PLUGIN_IS_UNINITIALIZED; tmp.state= PLUGIN_IS_UNINITIALIZED;
tmp.load_option= PLUGIN_ON; tmp.load_option= PLUGIN_ON;
if (test_plugin_options(tmp_root, &tmp, argc, argv)) 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)))
{ {
plugin_array_version++; mysql_del_sys_var_chain(tmp.system_vars);
if (!my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr)) restore_pluginvar_names(tmp.system_vars);
{ goto err;
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); plugin_array_version++;
restore_pluginvar_names(tmp.system_vars); if (my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
goto err; tmp_plugin_ptr->state= PLUGIN_IS_FREED;
} init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096);
}
report_error(report, ER_CANT_FIND_DL_ENTRY, name->str); if (name->str)
DBUG_RETURN(FALSE); // all done
oks++;
tmp.plugin_dl->ref_count++;
continue; // otherwise - go on
err: 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); 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, ...@@ -1760,8 +1793,6 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
{ {
char buffer[FN_REFLEN]; char buffer[FN_REFLEN];
LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name; LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
struct st_plugin_dl *plugin_dl;
struct st_maria_plugin *plugin;
char *p= buffer; char *p= buffer;
DBUG_ENTER("plugin_load_list"); DBUG_ENTER("plugin_load_list");
while (list) while (list)
...@@ -1791,19 +1822,10 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, ...@@ -1791,19 +1822,10 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
dl= name; dl= name;
mysql_mutex_lock(&LOCK_plugin); mysql_mutex_lock(&LOCK_plugin);
if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG))) free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
{ name.str= 0; // load everything
for (plugin= plugin_dl->plugins; plugin->info; plugin++) if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
{ goto error;
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
}
} }
else else
{ {
...@@ -1970,14 +1992,68 @@ void plugin_shutdown(void) ...@@ -1970,14 +1992,68 @@ void plugin_shutdown(void)
DBUG_VOID_RETURN; 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_LIST tables;
TABLE *table; TABLE *table;
int error, argc=orig_argc; LEX_STRING dl= *dl_arg;
bool error;
int argc=orig_argc;
char **argv=orig_argv; char **argv=orig_argv;
struct st_plugin_int *tmp;
DBUG_ENTER("mysql_install_plugin"); DBUG_ENTER("mysql_install_plugin");
if (opt_noacl) if (opt_noacl)
...@@ -2024,53 +2100,34 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl ...@@ -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); report_error(REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str);
goto err; 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) if (argv)
free_defaults(argv); free_defaults(argv);
mysql_rwlock_unlock(&LOCK_system_variables_hash); mysql_rwlock_unlock(&LOCK_system_variables_hash);
if (error || !(tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN))) if (error)
goto err; goto err;
if (tmp->state == PLUGIN_IS_DISABLED) if (name->str)
{ error= finalize_install(thd, table, name);
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 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, LEX_STRING str= { const_cast<char*>(plugin->name), strlen(plugin->name) };
"Plugin initialization function failed."); error|= finalize_install(thd, table, &str);
goto deinit;
} }
} }
/*
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) if (error)
{
table->file->print_error(error, MYF(0));
goto deinit; goto deinit;
}
mysql_mutex_unlock(&LOCK_plugin); mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
deinit: deinit:
tmp->state= PLUGIN_IS_DELETED;
reap_needed= true; reap_needed= true;
reap_plugins(); reap_plugins();
err: err:
...@@ -2079,66 +2136,27 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl ...@@ -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; struct st_plugin_int *plugin;
DBUG_ENTER("mysql_uninstall_plugin"); mysql_mutex_assert_owner(&LOCK_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_lock(&LOCK_plugin);
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN))) if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
{ {
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str); my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
goto err; return 1;
} }
if (!plugin->plugin_dl) if (!plugin->plugin_dl)
{ {
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
WARN_PLUGIN_DELETE_BUILTIN, ER(WARN_PLUGIN_DELETE_BUILTIN)); WARN_PLUGIN_DELETE_BUILTIN, ER(WARN_PLUGIN_DELETE_BUILTIN));
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str); my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
goto err; return 1;
} }
if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT) if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
{ {
my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str);
goto err; return 1;
} }
plugin->state= PLUGIN_IS_DELETED; plugin->state= PLUGIN_IS_DELETED;
...@@ -2147,8 +2165,6 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) ...@@ -2147,8 +2165,6 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
WARN_PLUGIN_BUSY, ER(WARN_PLUGIN_BUSY)); WARN_PLUGIN_BUSY, ER(WARN_PLUGIN_BUSY));
else else
reap_needed= true; reap_needed= true;
reap_plugins();
mysql_mutex_unlock(&LOCK_plugin);
uchar user_key[MAX_KEY_LENGTH]; uchar user_key[MAX_KEY_LENGTH];
table->use_all_columns(); table->use_all_columns();
...@@ -2170,13 +2186,74 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) ...@@ -2170,13 +2186,74 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
if (error) if (error)
{ {
table->file->print_error(error, MYF(0)); table->file->print_error(error, MYF(0));
DBUG_RETURN(TRUE); return 1;
} }
} }
DBUG_RETURN(FALSE); return 0;
err: }
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); mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(TRUE); DBUG_RETURN(error);
} }
......
...@@ -159,7 +159,8 @@ extern void plugin_unlock(THD *thd, plugin_ref plugin); ...@@ -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 void plugin_unlock_list(THD *thd, plugin_ref *list, uint count);
extern bool mysql_install_plugin(THD *thd, const LEX_STRING *name, extern bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
const LEX_STRING *dl); 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 bool plugin_register_builtin(struct st_mysql_plugin *plugin);
extern void plugin_thdvar_init(THD *thd); extern void plugin_thdvar_init(THD *thd);
extern void plugin_thdvar_cleanup(THD *thd); extern void plugin_thdvar_cleanup(THD *thd);
......
...@@ -15141,6 +15141,13 @@ install: ...@@ -15141,6 +15141,13 @@ install:
lex->comment= $3; lex->comment= $3;
lex->ident= $5; 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: uninstall:
...@@ -15150,6 +15157,13 @@ uninstall: ...@@ -15150,6 +15157,13 @@ uninstall:
lex->sql_command= SQLCOM_UNINSTALL_PLUGIN; lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
lex->comment= $3; 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 */ /* Avoid compiler warning from sql_yacc.cc where yyerrlab1 is not used */
......
...@@ -19,17 +19,23 @@ ...@@ -19,17 +19,23 @@
@brief @brief
The ha_example engine is a stubbed storage engine for example purposes only; 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 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 @details
ha_example will let you create/open/delete tables, but ha_example will let you create/open/delete tables, but
nothing further (for example, indexes are not supported nor can data nothing further (for example, indexes are not supported nor can data
be stored in the table). Use this example as a template for be stored in the table). It also provides new status (example_func_example)
implementing the same functionality in your own storage engine. You and system (example_ulong_var and example_enum_var) variables.
can enable the example storage engine in your build by doing the
following during your build process:<br> ./configure 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 --with-example-storage-engine
Once this is done, MySQL will let you create tables with:<br> Once this is done, MySQL will let you create tables with:<br>
...@@ -1111,6 +1117,9 @@ static struct st_mysql_show_var func_status[]= ...@@ -1111,6 +1117,9 @@ static struct st_mysql_show_var func_status[]=
{0,0,SHOW_UNDEF} {0,0,SHOW_UNDEF}
}; };
struct st_mysql_daemon unusable_example=
{ MYSQL_DAEMON_INTERFACE_VERSION };
mysql_declare_plugin(example) mysql_declare_plugin(example)
{ {
MYSQL_STORAGE_ENGINE_PLUGIN, MYSQL_STORAGE_ENGINE_PLUGIN,
...@@ -1138,10 +1147,25 @@ maria_declare_plugin(example) ...@@ -1138,10 +1147,25 @@ maria_declare_plugin(example)
PLUGIN_LICENSE_GPL, PLUGIN_LICENSE_GPL,
example_init_func, /* Plugin Init */ example_init_func, /* Plugin Init */
example_done_func, /* Plugin Deinit */ example_done_func, /* Plugin Deinit */
0x0001 /* 0.1 */, 0x0001, /* version number (0.1) */
func_status, /* status variables */ func_status, /* status variables */
example_system_variables, /* system variables */ example_system_variables, /* system variables */
"0.1", /* string version */ "0.1", /* string version */
MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */ 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; 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