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.cc147
1 files changed, 92 insertions, 55 deletions
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index ffb7d747537..981420f03ae 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 Corporation
+ Copyright (c) 2010, 2020, 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
@@ -281,6 +281,7 @@ struct st_mysql_sys_var
MYSQL_PLUGIN_VAR_HEADER;
};
+enum install_status { INSTALL_GOOD, INSTALL_FAIL_WARN_OK, INSTALL_FAIL_NOT_OK };
/*
sys_var class for access to all plugin variables visible to the user
*/
@@ -1078,7 +1079,7 @@ static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
NOTE
Requires that a write-lock is held on LOCK_system_variables_hash
*/
-static bool plugin_add(MEM_ROOT *tmp_root,
+static enum install_status plugin_add(MEM_ROOT *tmp_root, bool if_not_exists,
const LEX_CSTRING *name, LEX_CSTRING *dl, myf MyFlags)
{
struct st_plugin_int tmp, *maybe_dupe;
@@ -1089,14 +1090,16 @@ static bool plugin_add(MEM_ROOT *tmp_root,
if (name->str && plugin_find_internal(name, MYSQL_ANY_PLUGIN))
{
+ if (if_not_exists)
+ MyFlags|= ME_NOTE;
my_error(ER_PLUGIN_INSTALLED, MyFlags, name->str);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(if_not_exists ? INSTALL_FAIL_WARN_OK : INSTALL_FAIL_NOT_OK);
}
/* 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, MyFlags)))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(INSTALL_FAIL_NOT_OK);
/* Find plugin by name */
for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++)
{
@@ -1122,7 +1125,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
if (plugin->name != maybe_dupe->plugin->name)
{
my_error(ER_UDF_EXISTS, MyFlags, plugin->name);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(INSTALL_FAIL_NOT_OK);
}
dupes++;
continue; // already installed
@@ -1174,7 +1177,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
init_alloc_root(&tmp_plugin_ptr->mem_root, "plugin", 4096, 4096, MYF(0));
if (name->str)
- DBUG_RETURN(FALSE); // all done
+ DBUG_RETURN(INSTALL_GOOD); // all done
oks++;
tmp.plugin_dl->ref_count++;
@@ -1192,7 +1195,9 @@ err:
my_error(ER_CANT_FIND_DL_ENTRY, MyFlags, name->str);
plugin_dl_del(tmp.plugin_dl);
- DBUG_RETURN(errs > 0 || oks + dupes == 0);
+ if (errs > 0 || oks + dupes == 0)
+ DBUG_RETURN(INSTALL_FAIL_NOT_OK);
+ DBUG_RETURN(INSTALL_GOOD);
}
static void plugin_variables_deinit(struct st_plugin_int *plugin)
@@ -1796,6 +1801,8 @@ static void plugin_load(MEM_ROOT *tmp_root)
int error;
THD *new_thd= new THD(0);
bool result;
+ unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] =
+ { MYSQL_AUDIT_GENERAL_CLASSMASK };
DBUG_ENTER("plugin_load");
if (global_system_variables.log_warnings >= 9)
@@ -1845,13 +1852,38 @@ static void plugin_load(MEM_ROOT *tmp_root)
continue;
/*
+ 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 plugin_load is acquiring LOCK_plugin
+ rather for a long time.
+
+ When audit event is triggered during plugin_load 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.
+
+ See also mysql_install_plugin(), mysql_uninstall_plugin() and
+ initialize_audit_plugin()
+ */
+ if (mysql_audit_general_enabled())
+ mysql_audit_acquire_plugins(new_thd, event_class_mask);
+
+ /*
there're no other threads running yet, so we don't need a mutex.
but plugin_add() before is designed to work in multi-threaded
environment, and it uses mysql_mutex_assert_owner(), so we lock
the mutex here to satisfy the assert
*/
mysql_mutex_lock(&LOCK_plugin);
- plugin_add(tmp_root, &name, &dl, MYF(ME_ERROR_LOG));
+ plugin_add(tmp_root, false, &name, &dl, MYF(ME_ERROR_LOG));
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
mysql_mutex_unlock(&LOCK_plugin);
}
@@ -1874,7 +1906,7 @@ end:
static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
{
char buffer[FN_REFLEN];
- LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
+ LEX_CSTRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
char *p= buffer;
DBUG_ENTER("plugin_load_list");
while (list)
@@ -1893,7 +1925,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
#ifndef __WIN__
case ':': /* can't use this as delimiter as it may be drive letter */
#endif
- str->str[str->length]= '\0';
+ p[-1]= 0;
if (str == &name) // load all plugins in named module
{
if (!name.length)
@@ -1906,16 +1938,16 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
mysql_mutex_lock(&LOCK_plugin);
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
name.str= 0; // load everything
- if (plugin_add(tmp_root, (LEX_CSTRING*) &name, (LEX_CSTRING*) &dl,
- MYF(ME_ERROR_LOG)))
+ if (plugin_add(tmp_root, false, &name, &dl,
+ MYF(ME_ERROR_LOG)) != INSTALL_GOOD)
goto error;
}
else
{
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
mysql_mutex_lock(&LOCK_plugin);
- if (plugin_add(tmp_root, (LEX_CSTRING*) &name, (LEX_CSTRING*) &dl,
- MYF(ME_ERROR_LOG)))
+ if (plugin_add(tmp_root, false, &name, &dl,
+ MYF(ME_ERROR_LOG)) != INSTALL_GOOD)
goto error;
}
mysql_mutex_unlock(&LOCK_plugin);
@@ -1927,7 +1959,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
case '#':
if (str == &name)
{
- name.str[name.length]= '\0';
+ p[-1]= 0;
str= &dl;
str->str= p;
continue;
@@ -2150,7 +2182,7 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
TABLE_LIST tables;
TABLE *table;
LEX_CSTRING dl= *dl_arg;
- bool error;
+ enum install_status error;
int argc=orig_argc;
char **argv=orig_argv;
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] =
@@ -2198,12 +2230,14 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
mysql_audit_acquire_plugins(thd, event_class_mask);
mysql_mutex_lock(&LOCK_plugin);
- error= plugin_add(thd->mem_root, name, &dl, MYF(0));
- if (unlikely(error))
+ error= plugin_add(thd->mem_root, thd->lex->create_info.if_not_exists(),
+ name, &dl, MYF(0));
+ if (unlikely(error != INSTALL_GOOD))
goto err;
if (name->str)
- error= finalize_install(thd, table, name, &argc, argv);
+ error= finalize_install(thd, table, name, &argc, argv)
+ ? INSTALL_FAIL_NOT_OK : INSTALL_GOOD;
else
{
st_plugin_dl *plugin_dl= plugin_dl_find(&dl);
@@ -2211,11 +2245,12 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
for (plugin= plugin_dl->plugins; plugin->info; plugin++)
{
LEX_CSTRING str= { plugin->name, strlen(plugin->name) };
- error|= finalize_install(thd, table, &str, &argc, argv);
+ if (finalize_install(thd, table, &str, &argc, argv))
+ error= INSTALL_FAIL_NOT_OK;
}
}
- if (unlikely(error))
+ if (unlikely(error != INSTALL_GOOD))
{
reap_needed= true;
reap_plugins();
@@ -2225,10 +2260,11 @@ err:
mysql_mutex_unlock(&LOCK_plugin);
if (argv)
free_defaults(argv);
- DBUG_RETURN(error);
-
-WSREP_ERROR_LABEL:
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(error == INSTALL_FAIL_NOT_OK);
+#ifdef WITH_WSREP
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
@@ -2240,8 +2276,8 @@ static bool do_uninstall(THD *thd, TABLE *table, const LEX_CSTRING *name)
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)) ||
plugin->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_DYING))
{
- // maybe plugin is in mysql.plugin present so postpond the error
- plugin= NULL;
+ // maybe plugin is present in mysql.plugin; postpone the error
+ plugin= nullptr;
}
if (plugin)
@@ -2290,8 +2326,9 @@ static bool do_uninstall(THD *thd, TABLE *table, const LEX_CSTRING *name)
}
else if (!plugin)
{
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
- return 1;
+ const myf MyFlags= thd->lex->if_exists() ? ME_NOTE : 0;
+ my_error(ER_SP_DOES_NOT_EXIST, MyFlags, "PLUGIN", name->str);
+ return !MyFlags;
}
return 0;
}
@@ -2313,7 +2350,7 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_CSTRING *name,
if (!opt_noacl && check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
/* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
@@ -2372,8 +2409,9 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_CSTRING *name,
}
else
{
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SONAME", dl.str);
- error= true;
+ myf MyFlags= thd->lex->if_exists() ? ME_NOTE : 0;
+ my_error(ER_SP_DOES_NOT_EXIST, MyFlags, "SONAME", dl.str);
+ error|= !MyFlags;
}
}
reap_plugins();
@@ -2381,9 +2419,10 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_CSTRING *name,
global_plugin_version++;
mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(error);
-
-WSREP_ERROR_LABEL:
- DBUG_RETURN(TRUE);
+#ifdef WITH_WSREP
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
@@ -4353,33 +4392,31 @@ void wsrep_plugins_pre_init()
members of wsrep startup threads with correct values, as these value
were not available at the time these threads were created.
*/
-void wsrep_plugins_post_init()
-{
- THD *thd;
- I_List_iterator<THD> it(threads);
+my_bool post_init_callback(THD *thd, void *)
+{
DBUG_ASSERT(!current_thd);
-
- mysql_mutex_lock(&LOCK_global_system_variables);
-
- while ((thd= it++))
+ if (thd->wsrep_applier)
{
- if (thd->wsrep_applier)
- {
- // Save options_bits as it will get overwritten in
- // plugin_thdvar_init() (verified)
- ulonglong option_bits_saved= thd->variables.option_bits;
+ // Save options_bits as it will get overwritten in
+ // plugin_thdvar_init() (verified)
+ ulonglong option_bits_saved= thd->variables.option_bits;
- set_current_thd(thd);
- plugin_thdvar_init(thd);
+ set_current_thd(thd);
+ plugin_thdvar_init(thd);
- // Restore option_bits
- thd->variables.option_bits= option_bits_saved;
- }
+ // Restore option_bits
+ thd->variables.option_bits= option_bits_saved;
}
+ set_current_thd(0);
+ return 0;
+}
+
+void wsrep_plugins_post_init()
+{
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ server_threads.iterate(post_init_callback);
mysql_mutex_unlock(&LOCK_global_system_variables);
- set_current_thd(0);
- return;
}
#endif /* WITH_WSREP */