summaryrefslogtreecommitdiff
path: root/sql/sql_plugin.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_plugin.cc')
-rw-r--r--sql/sql_plugin.cc573
1 files changed, 340 insertions, 233 deletions
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index a90c7558045..6089745d85e 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2005, 2018, Oracle and/or its affiliates.
- Copyright (c) 2010, 2018, MariaDB
+ Copyright (c) 2010, 2018, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,9 +15,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+#include "sql_plugin.h" // Includes my_global.h
#include "sql_priv.h" // SHOW_MY_BOOL
#include "unireg.h"
-#include "my_global.h" // REQUIRED by m_string.h
#include "sql_class.h" // set_var.h: THD
#include "sys_vars_shared.h"
#include "sql_locale.h"
@@ -53,8 +53,8 @@ static TYPELIB global_plugin_typelib=
{ array_elements(global_plugin_typelib_names)-1,
"", global_plugin_typelib_names, NULL };
-
-char *opt_plugin_load= NULL;
+static I_List<i_string> opt_plugin_load_list;
+I_List<i_string> *opt_plugin_load_list_ptr= &opt_plugin_load_list;
char *opt_plugin_dir_ptr;
char opt_plugin_dir[FN_REFLEN];
ulong plugin_maturity;
@@ -196,6 +196,8 @@ static MEM_ROOT plugin_mem_root;
static bool reap_needed= false;
static bool initialized= 0;
+ulong dlopen_count;
+
/*
write-lock on LOCK_system_variables_hash is required before modifying
@@ -255,15 +257,6 @@ class sys_var_pluginvar: public sys_var
public:
struct st_plugin_int *plugin;
struct st_mysql_sys_var *plugin_var;
- /**
- variable name from whatever is hard-coded in the plugin source
- and doesn't have pluginname- prefix is replaced by an allocated name
- with a plugin prefix. When plugin is uninstalled we need to restore the
- pointer to point to the hard-coded value, because plugin may be
- installed/uninstalled many times without reloading the shared object.
- */
- const char *orig_pluginvar_name;
-
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, size); }
static void operator delete(void *ptr_arg,size_t size)
@@ -277,8 +270,7 @@ public:
(plugin_var_arg->flags & PLUGIN_VAR_READONLY ? READONLY : 0),
0, -1, NO_ARG, pluginvar_show_type(plugin_var_arg), 0, 0,
VARIABLE_NOT_IN_BINLOG, NULL, NULL, NULL),
- plugin(plugin_arg), plugin_var(plugin_var_arg),
- orig_pluginvar_name(plugin_var_arg->name)
+ plugin(plugin_arg), plugin_var(plugin_var_arg)
{ plugin_var->name= name_arg; }
sys_var_pluginvar *cast_pluginvar() { return this; }
bool check_update_type(Item_result type);
@@ -308,9 +300,7 @@ static bool register_builtin(struct st_maria_plugin *, struct st_plugin_int *,
static void unlock_variables(THD *thd, struct system_variables *vars);
static void cleanup_variables(THD *thd, struct system_variables *vars);
static void plugin_vars_free_values(sys_var *vars);
-static void restore_pluginvar_names(sys_var *first);
-static void plugin_opt_set_limits(struct my_option *,
- const struct st_mysql_sys_var *);
+static void restore_ptr_backup(uint n, st_ptr_backup *backup);
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
static void reap_plugins(void);
@@ -485,9 +475,16 @@ static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *)
#endif /* HAVE_DLOPEN */
-static inline void free_plugin_mem(struct st_plugin_dl *p)
+static void free_plugin_mem(struct st_plugin_dl *p)
{
#ifdef HAVE_DLOPEN
+ if (p->ptr_backup)
+ {
+ DBUG_ASSERT(p->nbackups);
+ DBUG_ASSERT(p->handle);
+ restore_ptr_backup(p->nbackups, p->ptr_backup);
+ my_free(p->ptr_backup);
+ }
if (p->handle)
dlclose(p->handle);
#endif
@@ -518,7 +515,6 @@ static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl,
/* Determine interface version */
if (!sym)
{
- free_plugin_mem(plugin_dl);
report_error(report, ER_CANT_FIND_DL_ENTRY, plugin_interface_version_sym);
DBUG_RETURN(TRUE);
}
@@ -528,15 +524,13 @@ static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl,
if (plugin_dl->mysqlversion < min_plugin_interface_version ||
(plugin_dl->mysqlversion >> 8) > (MYSQL_PLUGIN_INTERFACE_VERSION >> 8))
{
- free_plugin_mem(plugin_dl);
- report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, 0,
+ report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, ENOEXEC,
"plugin interface version mismatch");
DBUG_RETURN(TRUE);
}
/* Find plugin declarations */
if (!(sym= dlsym(plugin_dl->handle, plugin_declarations_sym)))
{
- free_plugin_mem(plugin_dl);
report_error(report, ER_CANT_FIND_DL_ENTRY, plugin_declarations_sym);
DBUG_RETURN(TRUE);
}
@@ -567,7 +561,6 @@ static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl,
MYF(MY_ZEROFILL|MY_WME));
if (!cur)
{
- free_plugin_mem(plugin_dl);
report_error(report, ER_OUTOFMEMORY,
static_cast<int>(plugin_dl->dl.length));
DBUG_RETURN(TRUE);
@@ -642,7 +635,6 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl,
Actually this branch impossible because in case of absence of maria
version we try mysql version.
*/
- free_plugin_mem(plugin_dl);
report_error(report, ER_CANT_FIND_DL_ENTRY,
maria_plugin_interface_version_sym);
DBUG_RETURN(TRUE);
@@ -653,7 +645,6 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl,
if (plugin_dl->mariaversion < min_maria_plugin_interface_version ||
(plugin_dl->mariaversion >> 8) > (MARIA_PLUGIN_INTERFACE_VERSION >> 8))
{
- free_plugin_mem(plugin_dl);
report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, ENOEXEC,
"plugin interface version mismatch");
DBUG_RETURN(TRUE);
@@ -661,7 +652,6 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl,
/* Find plugin declarations */
if (!(sym= dlsym(plugin_dl->handle, maria_plugin_declarations_sym)))
{
- free_plugin_mem(plugin_dl);
report_error(report, ER_CANT_FIND_DL_ENTRY, maria_plugin_declarations_sym);
DBUG_RETURN(TRUE);
}
@@ -675,7 +665,6 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl,
sizeof_st_plugin= *(int *)sym;
else
{
- free_plugin_mem(plugin_dl);
report_error(report, ER_CANT_FIND_DL_ENTRY, maria_sizeof_st_plugin_sym);
DBUG_RETURN(TRUE);
}
@@ -693,7 +682,6 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl,
MYF(MY_ZEROFILL|MY_WME));
if (!cur)
{
- free_plugin_mem(plugin_dl);
report_error(report, ER_OUTOFMEMORY,
static_cast<int>(plugin_dl->dl.length));
DBUG_RETURN(TRUE);
@@ -706,7 +694,7 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl,
for (i=0;
(old= (struct st_maria_plugin *)(ptr + i * sizeof_st_plugin))->info;
i++)
- memcpy(cur + i, old, min(sizeof(cur[i]), sizeof_st_plugin));
+ memcpy(cur + i, old, MY_MIN(sizeof(cur[i]), sizeof_st_plugin));
sym= cur;
plugin_dl->allocated= true;
@@ -725,11 +713,13 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
#ifdef HAVE_DLOPEN
char dlpath[FN_REFLEN];
uint plugin_dir_len, dummy_errors, dlpathlen, i;
- struct st_plugin_dl *tmp, plugin_dl;
+ struct st_plugin_dl *tmp= 0, plugin_dl;
void *sym;
+ st_ptr_backup tmp_backup[array_elements(list_of_services)];
DBUG_ENTER("plugin_dl_add");
DBUG_PRINT("enter", ("dl->str: '%s', dl->length: %d",
dl->str, (int) dl->length));
+ mysql_mutex_assert_owner(&LOCK_plugin);
plugin_dir_len= strlen(opt_plugin_dir);
/*
Ensure that the dll doesn't have a path.
@@ -767,8 +757,9 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
if (*errmsg == ' ') errmsg++;
}
report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, errno, errmsg);
- DBUG_RETURN(0);
+ goto ret;
}
+ dlopen_count++;
/* Checks which plugin interface present and reads info */
if (!(sym= dlsym(plugin_dl.handle, maria_plugin_interface_version_sym)))
@@ -778,12 +769,12 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
plugin_interface_version_sym),
dlpath,
report))
- DBUG_RETURN(0);
+ goto ret;
}
else
{
if (read_maria_plugin_info(&plugin_dl, sym, dlpath, report))
- DBUG_RETURN(0);
+ goto ret;
}
/* link the services in */
@@ -791,7 +782,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
{
if ((sym= dlsym(plugin_dl.handle, list_of_services[i].name)))
{
- uint ver= (uint)(intptr)*(void**)sym;
+ void **ptr= (void **)sym;
+ uint ver= (uint)(intptr)*ptr;
if (ver > list_of_services[i].version ||
(ver >> 8) < (list_of_services[i].version >> 8))
{
@@ -800,20 +792,33 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
"service '%s' interface version mismatch",
list_of_services[i].name);
report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, ENOEXEC, buf);
- DBUG_RETURN(0);
+ goto ret;
}
- *(void**)sym= list_of_services[i].service;
+ tmp_backup[plugin_dl.nbackups++].save(ptr);
+ *ptr= list_of_services[i].service;
}
}
+ if (plugin_dl.nbackups)
+ {
+ size_t bytes= plugin_dl.nbackups * sizeof(plugin_dl.ptr_backup[0]);
+ plugin_dl.ptr_backup= (st_ptr_backup *)my_malloc(bytes, MYF(0));
+ if (!plugin_dl.ptr_backup)
+ {
+ restore_ptr_backup(plugin_dl.nbackups, tmp_backup);
+ report_error(report, ER_OUTOFMEMORY, bytes);
+ goto ret;
+ }
+ memcpy(plugin_dl.ptr_backup, tmp_backup, bytes);
+ }
+
/* Duplicate and convert dll name */
plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
{
- free_plugin_mem(&plugin_dl);
report_error(report, ER_OUTOFMEMORY,
static_cast<int>(plugin_dl.dl.length));
- DBUG_RETURN(0);
+ goto ret;
}
plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length,
files_charset_info, dl->str, dl->length, system_charset_info,
@@ -822,12 +827,17 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
/* Add this dll to array */
if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl)))
{
- free_plugin_mem(&plugin_dl);
report_error(report, ER_OUTOFMEMORY,
static_cast<int>(sizeof(struct st_plugin_dl)));
- DBUG_RETURN(0);
+ goto ret;
}
+
+ret:
+ if (!tmp)
+ free_plugin_mem(&plugin_dl);
+
DBUG_RETURN(tmp);
+
#else
DBUG_ENTER("plugin_dl_add");
report_error(report, ER_FEATURE_DISABLED, "plugin", "HAVE_DLOPEN");
@@ -836,34 +846,23 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
}
-static void plugin_dl_del(const LEX_STRING *dl)
+static void plugin_dl_del(struct st_plugin_dl *plugin_dl)
{
-#ifdef HAVE_DLOPEN
- uint i;
DBUG_ENTER("plugin_dl_del");
+ if (!plugin_dl)
+ DBUG_VOID_RETURN;
+
mysql_mutex_assert_owner(&LOCK_plugin);
- for (i= 0; i < plugin_dl_array.elements; i++)
+ /* Do not remove this element, unless no other plugin uses this dll. */
+ if (! --plugin_dl->ref_count)
{
- struct st_plugin_dl *tmp= *dynamic_element(&plugin_dl_array, i,
- struct st_plugin_dl **);
- if (tmp->ref_count &&
- ! my_strnncoll(files_charset_info,
- (const uchar *)dl->str, dl->length,
- (const uchar *)tmp->dl.str, tmp->dl.length))
- {
- /* Do not remove this element, unless no other plugin uses this dll. */
- if (! --tmp->ref_count)
- {
- free_plugin_mem(tmp);
- bzero(tmp, sizeof(struct st_plugin_dl));
- }
- break;
- }
+ free_plugin_mem(plugin_dl);
+ bzero(plugin_dl, sizeof(struct st_plugin_dl));
}
+
DBUG_VOID_RETURN;
-#endif
}
@@ -929,7 +928,8 @@ SHOW_COMP_OPTION plugin_status(const char *name, size_t len, int type)
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc,
uint state_mask= PLUGIN_IS_READY |
- PLUGIN_IS_UNINITIALIZED)
+ PLUGIN_IS_UNINITIALIZED |
+ PLUGIN_IS_DELETED)
{
st_plugin_int *pi= plugin_ref_to_int(rc);
DBUG_ENTER("intern_plugin_lock");
@@ -1052,13 +1052,15 @@ static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
static bool plugin_add(MEM_ROOT *tmp_root,
const LEX_STRING *name, LEX_STRING *dl, int report)
{
- struct st_plugin_int tmp;
+ struct st_plugin_int tmp, *maybe_dupe;
struct st_maria_plugin *plugin;
- uint oks= 0, errs= 0;
+ uint oks= 0, errs= 0, dupes= 0;
DBUG_ENTER("plugin_add");
+ DBUG_PRINT("enter", ("name: %s dl: %s", name->str, dl->str));
+
if (name->str && plugin_find_internal(name, MYSQL_ANY_PLUGIN))
{
- report_error(report, ER_UDF_EXISTS, name->str);
+ report_error(report, ER_PLUGIN_INSTALLED, name->str);
DBUG_RETURN(TRUE);
}
/* Clear the whole struct to catch future extensions. */
@@ -1080,9 +1082,17 @@ static bool plugin_add(MEM_ROOT *tmp_root,
(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))
+ if (!name->str &&
+ (maybe_dupe= plugin_find_internal(&tmp.name, MYSQL_ANY_PLUGIN)))
+ {
+ if (plugin->name != maybe_dupe->plugin->name)
+ {
+ report_error(report, ER_UDF_EXISTS, plugin->name);
+ DBUG_RETURN(TRUE);
+ }
+ dupes++;
continue; // already installed
-
+ }
struct st_plugin_int *tmp_plugin_ptr;
if (*(int*)plugin->info <
min_plugin_info_interface_version[plugin->type] ||
@@ -1118,7 +1128,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
goto err;
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);
+ init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096, MYF(0));
if (name->str)
DBUG_RETURN(FALSE); // all done
@@ -1133,11 +1143,13 @@ err:
break;
}
- if (errs == 0 && oks == 0) // no plugin was found
+ DBUG_ASSERT(!name->str || !dupes); // dupes is ONLY for name->str == 0
+
+ if (errs == 0 && oks == 0 && !dupes) // no plugin was found
report_error(report, ER_CANT_FIND_DL_ENTRY, name->str);
- plugin_dl_del(dl);
- DBUG_RETURN(errs > 0 || oks == 0);
+ plugin_dl_del(tmp.plugin_dl);
+ DBUG_RETURN(errs > 0 || oks + dupes == 0);
}
@@ -1152,22 +1164,21 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
if (plugin->plugin->status_vars)
{
-#ifdef FIX_LATER
- /**
- @todo
- unfortunately, status variables were introduced without a
- pluginname_ namespace, that is pluginname_ was not added automatically
- to status variable names. It should be fixed together with the next
- incompatible API change.
+ /*
+ historical ndb behavior caused MySQL plugins to specify
+ status var names in full, with the plugin name prefix.
+ this was never fixed in MySQL.
+ MariaDB fixes that but support MySQL style too.
*/
- SHOW_VAR array[2]= {
+ SHOW_VAR *show_vars= plugin->plugin->status_vars;
+ SHOW_VAR tmp_array[2]= {
{plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
{0, 0, SHOW_UNDEF}
};
- remove_status_vars(array);
-#else
- remove_status_vars(plugin->plugin->status_vars);
-#endif /* FIX_LATER */
+ if (strncasecmp(show_vars->name, plugin->name.str, plugin->name.length))
+ show_vars= tmp_array;
+
+ remove_status_vars(show_vars);
}
if (plugin_type_deinitialize[plugin->plugin->type])
@@ -1189,10 +1200,6 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
}
plugin->state= PLUGIN_IS_UNINITIALIZED;
- /* maintain the obsolete @@have_innodb variable */
- if (!my_strcasecmp(&my_charset_latin1, plugin->name.str, "InnoDB"))
- have_innodb= SHOW_OPTION_DISABLED;
-
/*
We do the check here because NDB has a worker THD which doesn't
exit until NDB is shut down.
@@ -1201,7 +1208,7 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
sql_print_error("Plugin '%s' has ref_count=%d after deinitialization.",
plugin->name.str, plugin->ref_count);
- restore_pluginvar_names(plugin->system_vars);
+ mysql_del_sys_var_chain(plugin->system_vars);
}
static void plugin_del(struct st_plugin_int *plugin)
@@ -1210,9 +1217,9 @@ static void plugin_del(struct st_plugin_int *plugin)
mysql_mutex_assert_owner(&LOCK_plugin);
/* Free allocated strings before deleting the plugin. */
plugin_vars_free_values(plugin->system_vars);
+ restore_ptr_backup(plugin->nbackups, plugin->ptr_backup);
my_hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
- if (plugin->plugin_dl)
- plugin_dl_del(&plugin->plugin_dl->dl);
+ plugin_dl_del(plugin->plugin_dl);
plugin->state= PLUGIN_IS_FREED;
free_root(&plugin->mem_root, MYF(0));
DBUG_VOID_RETURN;
@@ -1398,40 +1405,33 @@ static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin,
if (plugin->plugin->status_vars)
{
-#ifdef FIX_LATER
/*
- We have a problem right now where we can not prepend without
- breaking backwards compatibility. We will fix this shortly so
- that engines have "use names" and we wil use those for
- CREATE TABLE, and use the plugin name then for adding automatic
- variable names.
+ historical ndb behavior caused MySQL plugins to specify
+ status var names in full, with the plugin name prefix.
+ this was never fixed in MySQL.
+ MariaDB fixes that, but supports MySQL style too.
*/
- SHOW_VAR array[2]= {
+ SHOW_VAR *show_vars= plugin->plugin->status_vars;
+ SHOW_VAR tmp_array[2]= {
{plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
{0, 0, SHOW_UNDEF}
};
- if (add_status_vars(array)) // add_status_vars makes a copy
- goto err;
-#else
- if (add_status_vars(plugin->plugin->status_vars))
+ if (strncasecmp(show_vars->name, plugin->name.str, plugin->name.length))
+ show_vars= tmp_array;
+
+ if (add_status_vars(show_vars))
goto err;
-#endif /* FIX_LATER */
}
ret= 0;
err:
if (ret)
- restore_pluginvar_names(plugin->system_vars);
+ mysql_del_sys_var_chain(plugin->system_vars);
mysql_mutex_lock(&LOCK_plugin);
plugin->state= state;
- /* maintain the obsolete @@have_innodb variable */
- if (!my_strcasecmp(&my_charset_latin1, plugin->name.str, "InnoDB"))
- have_innodb= state & PLUGIN_IS_READY ? SHOW_OPTION_YES
- : SHOW_OPTION_DISABLED;
-
DBUG_RETURN(ret);
}
@@ -1514,13 +1514,15 @@ int plugin_init(int *argc, char **argv, int flags)
if (initialized)
DBUG_RETURN(0);
+ dlopen_count =0;
+
#ifdef HAVE_PSI_INTERFACE
init_plugin_psi_keys();
#endif
- init_alloc_root(&plugin_mem_root, 4096, 4096);
- init_alloc_root(&plugin_vars_mem_root, 4096, 4096);
- init_alloc_root(&tmp_root, 4096, 4096);
+ init_alloc_root(&plugin_mem_root, 4096, 4096, MYF(0));
+ init_alloc_root(&plugin_vars_mem_root, 4096, 4096, MYF(0));
+ init_alloc_root(&tmp_root, 4096, 4096, MYF(0));
if (my_hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
get_bookmark_hash_key, NULL, HASH_UNIQUE))
@@ -1530,9 +1532,9 @@ int plugin_init(int *argc, char **argv, int flags)
mysql_mutex_init(key_LOCK_plugin, &LOCK_plugin, MY_MUTEX_INIT_FAST);
if (my_init_dynamic_array(&plugin_dl_array,
- sizeof(struct st_plugin_dl *),16,16) ||
+ sizeof(struct st_plugin_dl *), 16, 16, MYF(0)) ||
my_init_dynamic_array(&plugin_array,
- sizeof(struct st_plugin_int *),16,16))
+ sizeof(struct st_plugin_int *), 16, 16, MYF(0)))
goto err;
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
@@ -1543,8 +1545,8 @@ int plugin_init(int *argc, char **argv, int flags)
}
/* prepare debug_sync service */
- DBUG_ASSERT(strcmp(list_of_services[5].name, "debug_sync_service") == 0);
- list_of_services[5].service= *(void**)&debug_sync_C_callback_ptr;
+ DBUG_ASSERT(strcmp(list_of_services[4].name, "debug_sync_service") == 0);
+ list_of_services[4].service= *(void**)&debug_sync_C_callback_ptr;
mysql_mutex_lock(&LOCK_plugin);
@@ -1553,6 +1555,9 @@ int plugin_init(int *argc, char **argv, int flags)
/*
First we register builtin plugins
*/
+ if (global_system_variables.log_warnings >= 9)
+ sql_print_information("Initializing built-in plugins");
+
for (builtins= mysql_mandatory_plugins; *builtins || mandatory; builtins++)
{
if (!*builtins)
@@ -1632,10 +1637,19 @@ int plugin_init(int *argc, char **argv, int flags)
/* Register all dynamic plugins */
if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
{
- if (opt_plugin_load)
- plugin_load_list(&tmp_root, opt_plugin_load);
+ I_List_iterator<i_string> iter(opt_plugin_load_list);
+ i_string *item;
+ if (global_system_variables.log_warnings >= 9)
+ sql_print_information("Initializing plugins specified on the command line");
+ while (NULL != (item= iter++))
+ plugin_load_list(&tmp_root, item->ptr);
+
if (!(flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE))
+ {
+ if (global_system_variables.log_warnings >= 9)
+ sql_print_information("Initializing installed plugins");
plugin_load(&tmp_root);
+ }
}
/*
@@ -1718,40 +1732,27 @@ static bool register_builtin(struct st_maria_plugin *plugin,
*/
static void plugin_load(MEM_ROOT *tmp_root)
{
- THD thd;
TABLE_LIST tables;
TABLE *table;
READ_RECORD read_record_info;
int error;
- THD *new_thd= &thd;
+ THD *new_thd= new THD;
bool result;
-#ifdef EMBEDDED_LIBRARY
- No_such_table_error_handler error_handler;
-#endif /* EMBEDDED_LIBRARY */
DBUG_ENTER("plugin_load");
new_thd->thread_stack= (char*) &tables;
new_thd->store_globals();
new_thd->db= my_strdup("mysql", MYF(0));
new_thd->db_length= 5;
- bzero((char*) &thd.net, sizeof(thd.net));
+ bzero((char*) &new_thd->net, sizeof(new_thd->net));
tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_READ);
-
-#ifdef EMBEDDED_LIBRARY
- /*
- When building an embedded library, if the mysql.plugin table
- does not exist, we silently ignore the missing table
- */
- new_thd->push_internal_handler(&error_handler);
-#endif /* EMBEDDED_LIBRARY */
+ tables.open_strategy= TABLE_LIST:: IF_EMBEDDED(OPEN_IF_EXISTS, OPEN_NORMAL);
result= open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT);
-#ifdef EMBEDDED_LIBRARY
- new_thd->pop_internal_handler();
- if (error_handler.safely_trapped_errors())
+ table= tables.table;
+ if (IF_EMBEDDED(!table, false))
goto end;
-#endif /* EMBEDDED_LIBRARY */
if (result)
{
@@ -1763,7 +1764,7 @@ static void plugin_load(MEM_ROOT *tmp_root)
sql_print_warning("Could not open mysql.plugin table. Some options may be missing from the help text");
goto end;
}
- table= tables.table;
+
if (init_read_record(&read_record_info, new_thd, table, NULL, 1, 0, FALSE))
{
sql_print_error("Could not initialize init_read_record; Plugins not "
@@ -1791,20 +1792,17 @@ static void plugin_load(MEM_ROOT *tmp_root)
the mutex here to satisfy the assert
*/
mysql_mutex_lock(&LOCK_plugin);
- if (plugin_add(tmp_root, &name, &dl, REPORT_TO_LOG))
- sql_print_warning("Couldn't load plugin named '%s' with soname '%s'.",
- str_name.c_ptr(), str_dl.c_ptr());
+ plugin_add(tmp_root, &name, &dl, REPORT_TO_LOG);
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
mysql_mutex_unlock(&LOCK_plugin);
}
if (error > 0)
- sql_print_error(ER(ER_GET_ERRNO), my_errno);
+ sql_print_error(ER(ER_GET_ERRNO), my_errno, table->file->table_type());
end_read_record(&read_record_info);
table->m_needs_reopen= TRUE; // Force close to free memory
close_mysql_tables(new_thd);
end:
- /* Remember that we don't have a THD */
- my_pthread_setspecific_ptr(THR_THD, 0);
+ delete new_thd;
DBUG_VOID_RETURN;
}
@@ -2051,7 +2049,7 @@ static bool finalize_install(THD *thd, TABLE *table, const LEX_STRING *name,
if (tmp->state == PLUGIN_IS_DISABLED)
{
if (global_system_variables.log_warnings)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_CANT_INITIALIZE_UDF, ER(ER_CANT_INITIALIZE_UDF),
name->str, "Plugin is disabled");
}
@@ -2089,14 +2087,8 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
char **argv=orig_argv;
DBUG_ENTER("mysql_install_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, INSERT_ACL, &tables, FALSE, 1, FALSE))
+ if (!opt_noacl && check_table_access(thd, INSERT_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
/* need to open before acquiring LOCK_plugin or it will deadlock */
@@ -2190,7 +2182,7 @@ static bool do_uninstall(THD *thd, TABLE *table, const LEX_STRING *name)
plugin->state= PLUGIN_IS_DELETED;
if (plugin->ref_count)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
WARN_PLUGIN_BUSY, ER(WARN_PLUGIN_BUSY));
else
reap_needed= true;
@@ -2231,15 +2223,9 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name,
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))
+ if (!opt_noacl && check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
/* need to open before acquiring LOCK_plugin or it will deadlock */
@@ -2366,6 +2352,74 @@ bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
}
+static bool plugin_dl_foreach_internal(THD *thd, st_plugin_dl *plugin_dl,
+ st_maria_plugin *plug,
+ plugin_foreach_func *func, void *arg)
+{
+ for (; plug->name; plug++)
+ {
+ st_plugin_int tmp, *plugin;
+
+ tmp.name.str= const_cast<char*>(plug->name);
+ tmp.name.length= strlen(plug->name);
+ tmp.plugin= plug;
+ tmp.plugin_dl= plugin_dl;
+
+ mysql_mutex_lock(&LOCK_plugin);
+ if ((plugin= plugin_find_internal(&tmp.name, MYSQL_ANY_PLUGIN)) &&
+ plugin->plugin == plug)
+
+ {
+ tmp.state= plugin->state;
+ tmp.load_option= plugin->load_option;
+ }
+ else
+ {
+ tmp.state= PLUGIN_IS_FREED;
+ tmp.load_option= PLUGIN_OFF;
+ }
+ mysql_mutex_unlock(&LOCK_plugin);
+
+ plugin= &tmp;
+ if (func(thd, plugin_int_to_ref(plugin), arg))
+ return 1;
+ }
+ return 0;
+}
+
+bool plugin_dl_foreach(THD *thd, const LEX_STRING *dl,
+ plugin_foreach_func *func, void *arg)
+{
+ bool err= 0;
+
+ if (dl)
+ {
+ mysql_mutex_lock(&LOCK_plugin);
+ st_plugin_dl *plugin_dl= plugin_dl_add(dl, REPORT_TO_USER);
+ mysql_mutex_unlock(&LOCK_plugin);
+
+ if (!plugin_dl)
+ return 1;
+
+ err= plugin_dl_foreach_internal(thd, plugin_dl, plugin_dl->plugins,
+ func, arg);
+
+ mysql_mutex_lock(&LOCK_plugin);
+ plugin_dl_del(plugin_dl);
+ mysql_mutex_unlock(&LOCK_plugin);
+ }
+ else
+ {
+ struct st_maria_plugin **builtins;
+ for (builtins= mysql_mandatory_plugins; !err && *builtins; builtins++)
+ err= plugin_dl_foreach_internal(thd, 0, *builtins, func, arg);
+ for (builtins= mysql_optional_plugins; !err && *builtins; builtins++)
+ err= plugin_dl_foreach_internal(thd, 0, *builtins, func, arg);
+ }
+ return err;
+}
+
+
/****************************************************************************
Internal type declarations for variables support
****************************************************************************/
@@ -2865,17 +2919,6 @@ static st_bookmark *register_var(const char *plugin, const char *name,
return result;
}
-static void restore_pluginvar_names(sys_var *first)
-{
- mysql_del_sys_var_chain(first);
- for (sys_var *var= first; var; var= var->next)
- {
- sys_var_pluginvar *pv= var->cast_pluginvar();
- pv->plugin_var->name= pv->orig_pluginvar_name;
- }
-}
-
-
/*
returns a pointer to the memory which holds the thd-local variable or
a pointer to the global variable if thd==null.
@@ -2891,8 +2934,6 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
if (!thd)
DBUG_RETURN((uchar*) global_system_variables.dynamic_variables_ptr + offset);
- mysql_mutex_assert_not_owner(&LOCK_open);
-
/*
dynamic_variables_head points to the largest valid offset
*/
@@ -2959,10 +3000,10 @@ void plugin_thdvar_init(THD *thd)
{
plugin_ref old_table_plugin= thd->variables.table_plugin;
DBUG_ENTER("plugin_thdvar_init");
-
+
thd->variables.table_plugin= NULL;
cleanup_variables(thd, &thd->variables);
-
+
thd->variables= global_system_variables;
thd->variables.table_plugin= NULL;
@@ -3275,7 +3316,7 @@ bool sys_var_pluginvar::session_update(THD *thd, set_var *var)
mysql_mutex_unlock(&LOCK_global_system_variables);
plugin_var->update(thd, plugin_var, tgt, src);
-
+
return false;
}
@@ -3351,9 +3392,8 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var)
options->max_value= getopt_double2ulonglong((opt)->max_val); \
options->block_size= (long) (opt)->blk_sz;
-
-static void plugin_opt_set_limits(struct my_option *options,
- const struct st_mysql_sys_var *opt)
+void plugin_opt_set_limits(struct my_option *options,
+ const struct st_mysql_sys_var *opt)
{
options->sub_size= 0;
@@ -3459,17 +3499,6 @@ static void plugin_opt_set_limits(struct my_option *options,
options->arg_type= OPT_ARG;
}
-extern "C" my_bool get_one_plugin_option(int optid, const struct my_option *,
- char *);
-
-my_bool get_one_plugin_option(int optid __attribute__((unused)),
- const struct my_option *opt,
- char *argument)
-{
- return 0;
-}
-
-
/**
Creates a set of my_option objects associated with a specified plugin-
handle.
@@ -3709,7 +3738,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
continue;
}
- optname= (char*) memdup_root(mem_root, v->key + 1,
+ optname= (char*) memdup_root(mem_root, v->key + 1,
(optnamelen= v->name_len) + 1);
}
@@ -3765,7 +3794,7 @@ static my_option *construct_help_options(MEM_ROOT *mem_root,
to get the correct (not double-prefixed) help text.
We won't need @@sysvars anymore and don't care about their proper names.
*/
- restore_pluginvar_names(p->system_vars);
+ restore_ptr_backup(p->nbackups, p->ptr_backup);
if (construct_options(mem_root, p, opts))
DBUG_RETURN(NULL);
@@ -3810,6 +3839,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
sys_var *v __attribute__((unused));
struct st_bookmark *var;
uint len, count= EXTRA_OPTIONS;
+ st_ptr_backup *tmp_backup= 0;
DBUG_ENTER("test_plugin_options");
DBUG_ASSERT(tmp->plugin && tmp->name.str);
@@ -3880,60 +3910,87 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
plugin_name= tmp->name;
error= 1;
- for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
+
+ if (tmp->plugin->system_vars)
{
- st_mysql_sys_var *o= *opt;
+ for (len=0, opt= tmp->plugin->system_vars; *opt; len++, opt++) /* no-op */;
+ tmp_backup= (st_ptr_backup *)my_alloca(len * sizeof(tmp_backup[0]));
+ DBUG_ASSERT(tmp->nbackups == 0);
+ DBUG_ASSERT(tmp->ptr_backup == 0);
- /*
- PLUGIN_VAR_STR command-line options without PLUGIN_VAR_MEMALLOC, point
- directly to values in the argv[] array. For plugins started at the
- server startup, argv[] array is allocated with load_defaults(), and
- freed when the server is shut down. But for plugins loaded with
- INSTALL PLUGIN, the memory allocated with load_defaults() is freed with
- freed() at the end of mysql_install_plugin(). Which means we cannot
- allow any pointers into that area.
- Thus, for all plugins loaded after the server was started,
- we copy string values to a plugin's memroot.
- */
- if (mysqld_server_started &&
- ((o->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_NOCMDOPT |
- PLUGIN_VAR_MEMALLOC)) == PLUGIN_VAR_STR))
+ for (opt= tmp->plugin->system_vars; *opt; opt++)
{
- sysvar_str_t* str= (sysvar_str_t *)o;
- if (*str->value)
- *str->value= strdup_root(mem_root, *str->value);
- }
+ st_mysql_sys_var *o= *opt;
- var= find_bookmark(plugin_name.str, o->name, o->flags);
- if (o->flags & PLUGIN_VAR_NOSYSVAR)
- continue;
- if (var)
- v= new (mem_root) sys_var_pluginvar(&chain, var->key + 1, o, tmp);
- else
+ /*
+ PLUGIN_VAR_STR command-line options without PLUGIN_VAR_MEMALLOC, point
+ directly to values in the argv[] array. For plugins started at the
+ server startup, argv[] array is allocated with load_defaults(), and
+ freed when the server is shut down. But for plugins loaded with
+ INSTALL PLUGIN, the memory allocated with load_defaults() is freed with
+ freed() at the end of mysql_install_plugin(). Which means we cannot
+ allow any pointers into that area.
+ Thus, for all plugins loaded after the server was started,
+ we copy string values to a plugin's memroot.
+ */
+ if (mysqld_server_started &&
+ ((o->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_NOCMDOPT |
+ PLUGIN_VAR_MEMALLOC)) == PLUGIN_VAR_STR))
+ {
+ sysvar_str_t* str= (sysvar_str_t *)o;
+ if (*str->value)
+ *str->value= strdup_root(mem_root, *str->value);
+ }
+
+ var= find_bookmark(plugin_name.str, o->name, o->flags);
+ if (o->flags & PLUGIN_VAR_NOSYSVAR)
+ continue;
+ tmp_backup[tmp->nbackups++].save(&o->name);
+ if (var)
+ v= new (mem_root) sys_var_pluginvar(&chain, var->key + 1, o, tmp);
+ else
+ {
+ len= plugin_name.length + strlen(o->name) + 2;
+ varname= (char*) alloc_root(mem_root, len);
+ strxmov(varname, plugin_name.str, "-", o->name, NullS);
+ my_casedn_str(&my_charset_latin1, varname);
+ convert_dash_to_underscore(varname, len-1);
+ v= new (mem_root) sys_var_pluginvar(&chain, varname, o, tmp);
+ }
+ DBUG_ASSERT(v); /* check that an object was actually constructed */
+ } /* end for */
+
+ if (tmp->nbackups)
{
- len= plugin_name.length + strlen(o->name) + 2;
- varname= (char*) alloc_root(mem_root, len);
- strxmov(varname, plugin_name.str, "-", o->name, NullS);
- my_casedn_str(&my_charset_latin1, varname);
- convert_dash_to_underscore(varname, len-1);
- v= new (mem_root) sys_var_pluginvar(&chain, varname, o, tmp);
+ size_t bytes= tmp->nbackups * sizeof(tmp->ptr_backup[0]);
+ tmp->ptr_backup= (st_ptr_backup *)alloc_root(mem_root, bytes);
+ if (!tmp->ptr_backup)
+ {
+ restore_ptr_backup(tmp->nbackups, tmp_backup);
+ goto err;
+ }
+ memcpy(tmp->ptr_backup, tmp_backup, bytes);
}
- DBUG_ASSERT(v); /* check that an object was actually constructed */
- } /* end for */
- if (chain.first)
- {
- chain.last->next = NULL;
- if (mysql_add_sys_var_chain(chain.first))
+
+ if (chain.first)
{
- sql_print_error("Plugin '%s' has conflicting system variables",
- tmp->name.str);
- goto err;
+ chain.last->next = NULL;
+ if (mysql_add_sys_var_chain(chain.first))
+ {
+ sql_print_error("Plugin '%s' has conflicting system variables",
+ tmp->name.str);
+ goto err;
+ }
+ tmp->system_vars= chain.first;
}
- tmp->system_vars= chain.first;
+ my_afree(tmp_backup);
}
+
DBUG_RETURN(0);
-
+
err:
+ if (tmp_backup)
+ my_afree(tmp_backup);
if (opts)
my_cleanup_options(opts);
DBUG_RETURN(error);
@@ -3966,3 +4023,53 @@ void add_plugin_options(DYNAMIC_ARRAY *options, MEM_ROOT *mem_root)
insert_dynamic(options, (uchar*) opt);
}
}
+
+
+/**
+ Returns a sys_var corresponding to a particular MYSQL_SYSVAR(...)
+*/
+sys_var *find_plugin_sysvar(st_plugin_int *plugin, st_mysql_sys_var *plugin_var)
+{
+ for (sys_var *var= plugin->system_vars; var; var= var->next)
+ {
+ sys_var_pluginvar *pvar=var->cast_pluginvar();
+ if (pvar->plugin_var == plugin_var)
+ return var;
+ }
+ return 0;
+}
+
+/*
+ On dlclose() we need to restore values of all symbols that we've modified in
+ the DSO. The reason is - the DSO might not actually be unloaded, so on the
+ next dlopen() these symbols will have old values, they won't be
+ reinitialized.
+
+ Perhaps, there can be many reason, why a DSO won't be unloaded. Strictly
+ speaking, it's implementation defined whether to unload an unused DSO or to
+ keep it in memory.
+
+ In particular, this happens for some plugins: In 2009 a new ELF stub was
+ introduced, see Ulrich Drepper's email "Unique symbols for C++"
+ http://www.redhat.com/archives/posix-c++-wg/2009-August/msg00002.html
+
+ DSO that has objects with this stub (STB_GNU_UNIQUE) cannot be unloaded
+ (this is mentioned in the email, see the url above).
+
+ These "unique" objects are, for example, static variables in templates,
+ in inline functions, in classes. So any DSO that uses them can
+ only be loaded once. And because Boost has them, any DSO that uses Boost
+ almost certainly cannot be unloaded.
+
+ To know whether a particular DSO has these objects, one can use
+
+ readelf -s /path/to/plugin.so|grep UNIQUE
+
+ There's nothing we can do about it, but to reset the DSO to its initial
+ state before dlclose().
+*/
+static void restore_ptr_backup(uint n, st_ptr_backup *backup)
+{
+ while (n--)
+ (backup++)->restore();
+}