diff options
Diffstat (limited to 'sql/sql_plugin.cc')
-rw-r--r-- | sql/sql_plugin.cc | 845 |
1 files changed, 531 insertions, 314 deletions
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 9e016019d10..f41d1e0fdbf 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -25,6 +25,7 @@ #include "sql_parse.h" // check_table_access #include "sql_base.h" // close_mysql_tables #include "key.h" // key_copy +#include "sql_table.h" #include "sql_show.h" // remove_status_vars, add_status_vars #include "strfunc.h" // find_set #include "sql_acl.h" // *_ACL @@ -35,11 +36,17 @@ #include <mysql/plugin_auth.h> #include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT #include <mysql/plugin_auth.h> +#include <mysql/plugin_password_validation.h> +#include <mysql/plugin_encryption.h> #include "sql_plugin_compat.h" #define REPORT_TO_LOG 1 #define REPORT_TO_USER 2 +#ifdef HAVE_LINK_H +#include <link.h> +#endif + extern struct st_maria_plugin *mysql_optional_plugins[]; extern struct st_maria_plugin *mysql_mandatory_plugins[]; @@ -82,7 +89,9 @@ const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]= { C_STRING_WITH_LEN("INFORMATION SCHEMA") }, { C_STRING_WITH_LEN("AUDIT") }, { C_STRING_WITH_LEN("REPLICATION") }, - { C_STRING_WITH_LEN("AUTHENTICATION") } + { C_STRING_WITH_LEN("AUTHENTICATION") }, + { C_STRING_WITH_LEN("PASSWORD VALIDATION") }, + { C_STRING_WITH_LEN("ENCRYPTION") } }; extern int initialize_schema_table(st_plugin_int *plugin); @@ -91,6 +100,9 @@ extern int finalize_schema_table(st_plugin_int *plugin); extern int initialize_audit_plugin(st_plugin_int *plugin); extern int finalize_audit_plugin(st_plugin_int *plugin); +extern int initialize_encryption_plugin(st_plugin_int *plugin); +extern int finalize_encryption_plugin(st_plugin_int *plugin); + /* The number of elements in both plugin_type_initialize and plugin_type_deinitialize should equal to the number of plugins @@ -98,14 +110,33 @@ extern int finalize_audit_plugin(st_plugin_int *plugin); */ plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]= { - 0,ha_initialize_handlerton,0,0,initialize_schema_table, - initialize_audit_plugin, 0, 0 + 0, ha_initialize_handlerton, 0, 0,initialize_schema_table, + initialize_audit_plugin, 0, 0, 0, initialize_encryption_plugin }; plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]= { - 0,ha_finalize_handlerton,0,0,finalize_schema_table, - finalize_audit_plugin, 0, 0 + 0, ha_finalize_handlerton, 0, 0, finalize_schema_table, + finalize_audit_plugin, 0, 0, 0, finalize_encryption_plugin +}; + +/* + Defines in which order plugin types have to be initialized. + Essentially, we want to initialize MYSQL_KEY_MANAGEMENT_PLUGIN before + MYSQL_STORAGE_ENGINE_PLUGIN, and that before MYSQL_INFORMATION_SCHEMA_PLUGIN +*/ +static int plugin_type_initialization_order[MYSQL_MAX_PLUGIN_TYPE_NUM]= +{ + MYSQL_DAEMON_PLUGIN, + MariaDB_ENCRYPTION_PLUGIN, + MYSQL_STORAGE_ENGINE_PLUGIN, + MYSQL_INFORMATION_SCHEMA_PLUGIN, + MYSQL_FTPARSER_PLUGIN, + MYSQL_AUTHENTICATION_PLUGIN, + MariaDB_PASSWORD_VALIDATION_PLUGIN, + MYSQL_AUDIT_PLUGIN, + MYSQL_REPLICATION_PLUGIN, + MYSQL_UDF_PLUGIN }; #ifdef HAVE_DLOPEN @@ -137,7 +168,9 @@ static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION, MYSQL_AUDIT_INTERFACE_VERSION, MYSQL_REPLICATION_INTERFACE_VERSION, - MIN_AUTHENTICATION_INTERFACE_VERSION + MIN_AUTHENTICATION_INTERFACE_VERSION, + MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION, + MariaDB_ENCRYPTION_INTERFACE_VERSION }; static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= { @@ -148,7 +181,9 @@ static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION, MYSQL_AUDIT_INTERFACE_VERSION, MYSQL_REPLICATION_INTERFACE_VERSION, - MYSQL_AUTHENTICATION_INTERFACE_VERSION + MYSQL_AUTHENTICATION_INTERFACE_VERSION, + MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION, + MariaDB_ENCRYPTION_INTERFACE_VERSION }; static struct @@ -172,16 +207,15 @@ static struct - yet disable explicitly a component needed for the functionality to work, by using '--skip-performance-schema' (the plugin) */ - { "performance_schema", PLUGIN_FORCE }, + { "performance_schema", PLUGIN_FORCE } /* we disable few other plugins by default */ - { "ndbcluster", PLUGIN_OFF }, - { "feedback", PLUGIN_OFF } + ,{ "feedback", PLUGIN_OFF } }; /* support for Services */ -#include "sql_plugin_services.h" +#include "sql_plugin_services.ic" /* A mutex LOCK_plugin must be acquired before accessing the @@ -246,47 +280,33 @@ struct st_mysql_sys_var MYSQL_PLUGIN_VAR_HEADER; }; -static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var); - - /* sys_var class for access to all plugin variables visible to the user */ -class sys_var_pluginvar: public sys_var +class sys_var_pluginvar: public sys_var, public Sql_alloc { public: struct st_plugin_int *plugin; struct st_mysql_sys_var *plugin_var; - 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) - { TRASH(ptr_arg, size); } sys_var_pluginvar(sys_var_chain *chain, const char *name_arg, - struct st_mysql_sys_var *plugin_var_arg, - struct st_plugin_int *plugin_arg) - :sys_var(chain, name_arg, plugin_var_arg->comment, - (plugin_var_arg->flags & PLUGIN_VAR_THDLOCAL ? SESSION : GLOBAL) | - (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) - { plugin_var->name= name_arg; } + st_plugin_int *p, st_mysql_sys_var *plugin_var_arg); sys_var_pluginvar *cast_pluginvar() { return this; } - bool check_update_type(Item_result type); - SHOW_TYPE show_type(); uchar* real_value_ptr(THD *thd, enum_var_type type); TYPELIB* plugin_var_typelib(void); - uchar* do_value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); - uchar* session_value_ptr(THD *thd, LEX_STRING *base) + uchar* do_value_ptr(THD *thd, enum_var_type type, const LEX_STRING *base); + uchar* session_value_ptr(THD *thd, const LEX_STRING *base) { return do_value_ptr(thd, OPT_SESSION, base); } - uchar* global_value_ptr(THD *thd, LEX_STRING *base) + uchar* global_value_ptr(THD *thd, const LEX_STRING *base) { return do_value_ptr(thd, OPT_GLOBAL, base); } + uchar *default_value_ptr(THD *thd) + { return do_value_ptr(thd, OPT_DEFAULT, 0); } bool do_check(THD *thd, set_var *var); virtual void session_save_default(THD *thd, set_var *var) {} virtual void global_save_default(THD *thd, set_var *var) {} bool session_update(THD *thd, set_var *var); bool global_update(THD *thd, set_var *var); + bool session_is_default(THD *thd); }; @@ -298,7 +318,7 @@ static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *, static bool register_builtin(struct st_maria_plugin *, struct st_plugin_int *, 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 cleanup_variables(struct system_variables *vars); static void plugin_vars_free_values(sys_var *vars); static void restore_ptr_backup(uint n, st_ptr_backup *backup); static void intern_plugin_unlock(LEX *lex, plugin_ref plugin); @@ -707,7 +727,7 @@ 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; + uint plugin_dir_len, dummy_errors, i; struct st_plugin_dl *tmp= 0, plugin_dl; void *sym; st_ptr_backup tmp_backup[array_elements(list_of_services)]; @@ -722,7 +742,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) plugin directory are used (to make this even remotely secure). */ if (check_valid_path(dl->str, dl->length) || - check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN, + check_string_char_length((LEX_STRING *) dl, 0, NAME_CHAR_LEN, system_charset_info, 1) || plugin_dir_len + dl->length + 1 >= FN_REFLEN) { @@ -743,19 +763,19 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) /* Open new dll handle */ if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW))) { - const char *errmsg=dlerror(); - dlpathlen= strlen(dlpath); - if (!strncmp(dlpath, errmsg, dlpathlen)) - { // if errmsg starts from dlpath, trim this prefix. - errmsg+=dlpathlen; - if (*errmsg == ':') errmsg++; - if (*errmsg == ' ') errmsg++; - } - report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, errno, errmsg); + report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, errno, my_dlerror(dlpath)); goto ret; } dlopen_count++; +#ifdef HAVE_LINK_H + if (global_system_variables.log_warnings > 2) + { + struct link_map *lm = (struct link_map*) plugin_dl.handle; + sql_print_information("Loaded '%s' with offset 0x%lx", dl->str, lm->l_addr); + } +#endif + /* Checks which plugin interface present and reads info */ if (!(sym= dlsym(plugin_dl.handle, maria_plugin_interface_version_sym))) { @@ -1070,7 +1090,12 @@ static bool plugin_add(MEM_ROOT *tmp_root, tmp.name.length= strlen(plugin->name); if (plugin->type < 0 || plugin->type >= MYSQL_MAX_PLUGIN_TYPE_NUM) - continue; // invalid plugin + continue; // invalid plugin type + + if (plugin->type == MYSQL_UDF_PLUGIN || + (plugin->type == MariaDB_PASSWORD_VALIDATION_PLUGIN && + tmp.plugin_dl->mariaversion == 0)) + continue; // unsupported plugin type if (name->str && my_strnncoll(system_charset_info, (const uchar *)name->str, name->length, @@ -1163,7 +1188,7 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check) 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. + MariaDB fixes that but supports MySQL style too. */ SHOW_VAR *show_vars= plugin->plugin->status_vars; SHOW_VAR tmp_array[2]= { @@ -1195,10 +1220,6 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check) } plugin->state= PLUGIN_IS_UNINITIALIZED; - /* - We do the check here because NDB has a worker THD which doesn't - exit until NDB is shut down. - */ if (ref_check && plugin->ref_count) sql_print_error("Plugin '%s' has ref_count=%d after deinitialization.", plugin->name.str, plugin->ref_count); @@ -1213,16 +1234,21 @@ static void plugin_del(struct st_plugin_int *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); - plugin_dl_del(plugin->plugin_dl); - plugin->state= PLUGIN_IS_FREED; - free_root(&plugin->mem_root, MYF(0)); + if (plugin->plugin_dl) + { + my_hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin); + plugin_dl_del(plugin->plugin_dl); + plugin->state= PLUGIN_IS_FREED; + free_root(&plugin->mem_root, MYF(0)); + } + else + plugin->state= PLUGIN_IS_UNINITIALIZED; DBUG_VOID_RETURN; } static void reap_plugins(void) { - uint count, idx; + uint count; struct st_plugin_int *plugin, **reap, **list; mysql_mutex_assert_owner(&LOCK_plugin); @@ -1235,14 +1261,18 @@ static void reap_plugins(void) reap= (struct st_plugin_int **)my_alloca(sizeof(plugin)*(count+1)); *(reap++)= NULL; - for (idx= 0; idx < count; idx++) + for (uint i=0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++) { - plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **); - if (plugin->state == PLUGIN_IS_DELETED && !plugin->ref_count) + HASH *hash= plugin_hash + plugin_type_initialization_order[i]; + for (uint j= 0; j < hash->records; j++) { - /* change the status flag to prevent reaping by another thread */ - plugin->state= PLUGIN_IS_DYING; - *(reap++)= plugin; + plugin= (struct st_plugin_int *) my_hash_element(hash, j); + if (plugin->state == PLUGIN_IS_DELETED && !plugin->ref_count) + { + /* change the status flag to prevent reaping by another thread */ + plugin->state= PLUGIN_IS_DYING; + *(reap++)= plugin; + } } } @@ -1250,7 +1280,7 @@ static void reap_plugins(void) list= reap; while ((plugin= *(--list))) - plugin_deinitialize(plugin, true); + plugin_deinitialize(plugin, true); mysql_mutex_lock(&LOCK_plugin); @@ -1365,19 +1395,10 @@ static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin, if (options_only || state == PLUGIN_IS_DISABLED) { ret= !options_only && plugin_is_forced(plugin); + state= PLUGIN_IS_DISABLED; goto err; } - if (plugin->plugin_dl && global_system_variables.log_warnings >= 9) - { - void *sym= dlsym(plugin->plugin_dl->handle, - plugin->plugin_dl->mariaversion ? - maria_plugin_declarations_sym : plugin_declarations_sym); - DBUG_ASSERT(sym); - sql_print_information("Plugin %s loaded at %p", - plugin->name.str, sym); - } - if (plugin_type_initialize[plugin->plugin->type]) { if ((*plugin_type_initialize[plugin->plugin->type])(plugin)) @@ -1404,7 +1425,7 @@ static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin, 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. + MariaDB fixes that but supports MySQL style too. */ SHOW_VAR *show_vars= plugin->plugin->status_vars; SHOW_VAR tmp_array[2]= { @@ -1497,13 +1518,13 @@ static void init_plugin_psi_keys(void) int plugin_init(int *argc, char **argv, int flags) { uint i; - bool is_myisam; struct st_maria_plugin **builtins; struct st_maria_plugin *plugin; struct st_plugin_int tmp, *plugin_ptr, **reap; MEM_ROOT tmp_root; bool reaped_mandatory_plugin= false; bool mandatory= true; + LEX_STRING MyISAM= { C_STRING_WITH_LEN("MyISAM") }; DBUG_ENTER("plugin_init"); if (initialized) @@ -1511,10 +1532,6 @@ int plugin_init(int *argc, char **argv, int flags) dlopen_count =0; -#ifdef HAVE_PSI_INTERFACE - init_plugin_psi_keys(); -#endif - 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)); @@ -1523,9 +1540,6 @@ int plugin_init(int *argc, char **argv, int flags) get_bookmark_hash_key, NULL, HASH_UNIQUE)) goto err; - - 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, MYF(0)) || my_init_dynamic_array(&plugin_array, @@ -1540,8 +1554,11 @@ int plugin_init(int *argc, char **argv, int flags) } /* prepare debug_sync service */ - DBUG_ASSERT(strcmp(list_of_services[4].name, "debug_sync_service") == 0); - list_of_services[4].service= *(void**)&debug_sync_C_callback_ptr; + DBUG_ASSERT(strcmp(list_of_services[1].name, "debug_sync_service") == 0); + list_of_services[1].service= *(void**)&debug_sync_C_callback_ptr; + + /* prepare encryption_keys service */ + finalize_encryption_plugin(0); mysql_mutex_lock(&LOCK_plugin); @@ -1590,46 +1607,34 @@ int plugin_init(int *argc, char **argv, int flags) tmp.state= PLUGIN_IS_UNINITIALIZED; if (register_builtin(plugin, &tmp, &plugin_ptr)) goto err_unlock; - - is_myisam= !my_strcasecmp(&my_charset_latin1, plugin->name, "MyISAM"); - - /* - strictly speaking, we should to initialize all plugins, - even for mysqld --help, because important subsystems - may be disabled otherwise, and the help will be incomplete. - For example, if the mysql.plugin table is not MyISAM. - But for now it's an unlikely corner case, and to optimize - mysqld --help for all other users, we will only initialize - MyISAM here. - */ - if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv, !is_myisam && - (flags & PLUGIN_INIT_SKIP_INITIALIZATION))) - { - if (plugin_ptr->load_option == PLUGIN_FORCE) - goto err_unlock; - plugin_ptr->state= PLUGIN_IS_DISABLED; - } - - /* - initialize the global default storage engine so that it may - not be null in any child thread. - */ - if (is_myisam) - { - DBUG_ASSERT(!global_system_variables.table_plugin); - global_system_variables.table_plugin= - intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr)); - DBUG_ASSERT(plugin_ptr->ref_count == 1); - } } } - /* should now be set to MyISAM storage engine */ - DBUG_ASSERT(global_system_variables.table_plugin); + /* + First, we initialize only MyISAM - that should almost always succeed + (almost always, because plugins can be loaded outside of the server, too). + */ + plugin_ptr= plugin_find_internal(&MyISAM, MYSQL_STORAGE_ENGINE_PLUGIN); + DBUG_ASSERT(plugin_ptr || !mysql_mandatory_plugins[0]); + if (plugin_ptr) + { + DBUG_ASSERT(plugin_ptr->load_option == PLUGIN_FORCE); + + if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv, false)) + goto err_unlock; + /* + set the global default storage engine variable so that it will + not be null in any child thread. + */ + global_system_variables.table_plugin = + intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr)); + DBUG_ASSERT(plugin_ptr->ref_count == 1); + + } mysql_mutex_unlock(&LOCK_plugin); - /* Register all dynamic plugins */ + /* Register (not initialize!) all dynamic plugins */ if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING)) { I_List_iterator<i_string> iter(opt_plugin_load_list); @@ -1641,9 +1646,17 @@ int plugin_init(int *argc, char **argv, int flags) if (!(flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE)) { - if (global_system_variables.log_warnings >= 9) - sql_print_information("Initializing installed plugins"); - plugin_load(&tmp_root); + char path[FN_REFLEN + 1]; + build_table_filename(path, sizeof(path) - 1, "mysql", "plugin", reg_ext, 0); + char engine_name_buf[NAME_CHAR_LEN + 1]; + LEX_STRING maybe_myisam= { engine_name_buf, 0 }; + frm_type_enum frm_type= dd_frm_type(NULL, path, &maybe_myisam); + /* if mysql.plugin table is MyISAM - load it right away */ + if (frm_type == FRMTYPE_TABLE && !strcasecmp(maybe_myisam.str, "MyISAM")) + { + plugin_load(&tmp_root); + flags|= PLUGIN_INIT_SKIP_PLUGIN_TABLE; + } } } @@ -1655,18 +1668,34 @@ int plugin_init(int *argc, char **argv, int flags) reap= (st_plugin_int **) my_alloca((plugin_array.elements+1) * sizeof(void*)); *(reap++)= NULL; - for (i= 0; i < plugin_array.elements; i++) + for(;;) { - plugin_ptr= *dynamic_element(&plugin_array, i, struct st_plugin_int **); - if (plugin_ptr->plugin_dl && plugin_ptr->state == PLUGIN_IS_UNINITIALIZED) + for (i=0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++) { - if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv, - (flags & PLUGIN_INIT_SKIP_INITIALIZATION))) + HASH *hash= plugin_hash + plugin_type_initialization_order[i]; + for (uint idx= 0; idx < hash->records; idx++) { - plugin_ptr->state= PLUGIN_IS_DYING; - *(reap++)= plugin_ptr; + plugin_ptr= (struct st_plugin_int *) my_hash_element(hash, idx); + if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED) + { + if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv, + (flags & PLUGIN_INIT_SKIP_INITIALIZATION))) + { + plugin_ptr->state= PLUGIN_IS_DYING; + *(reap++)= plugin_ptr; + } + } } } + + /* load and init plugins from the plugin table (unless done already) */ + if (flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE) + break; + + mysql_mutex_unlock(&LOCK_plugin); + plugin_load(&tmp_root); + flags|= PLUGIN_INIT_SKIP_PLUGIN_TABLE; + mysql_mutex_lock(&LOCK_plugin); } /* @@ -1735,28 +1764,30 @@ static void plugin_load(MEM_ROOT *tmp_root) bool result; DBUG_ENTER("plugin_load"); + if (global_system_variables.log_warnings >= 9) + sql_print_information("Initializing installed plugins"); + 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*) &new_thd->net, sizeof(new_thd->net)); - tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_READ); - tables.open_strategy= TABLE_LIST:: IF_EMBEDDED(OPEN_IF_EXISTS, OPEN_NORMAL); + tables.init_one_table(STRING_WITH_LEN("mysql"), STRING_WITH_LEN("plugin"), + "plugin", TL_READ); + tables.open_strategy= TABLE_LIST::OPEN_NORMAL; result= open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT); table= tables.table; - if (IF_EMBEDDED(!table, false)) - goto end; - if (result) { DBUG_PRINT("error",("Can't open plugin table")); if (!opt_help) - sql_print_error("Can't open the mysql.plugin table. Please " - "run mysql_upgrade to create it."); + sql_print_error("Could not open mysql.plugin table. " + "Some plugins may be not loaded"); else - sql_print_warning("Could not open mysql.plugin table. Some options may be missing from the help text"); + sql_print_warning("Could not open mysql.plugin table. " + "Some options may be missing from the help text"); goto end; } @@ -1789,7 +1820,8 @@ static void plugin_load(MEM_ROOT *tmp_root) mysql_mutex_unlock(&LOCK_plugin); } if (error > 0) - sql_print_error(ER(ER_GET_ERRNO), my_errno, table->file->table_type()); + sql_print_error(ER_THD(new_thd, 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); @@ -1942,8 +1974,6 @@ void plugin_shutdown(void) if (!(plugins[i]->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_FREED | PLUGIN_IS_DISABLED))) { - sql_print_warning("Plugin '%s' will be forced to shutdown", - plugins[i]->name.str); /* We are forcing deinit on plugins so we don't want to do a ref_count check until we have processed all the plugins. @@ -1976,8 +2006,8 @@ void plugin_shutdown(void) Now we can deallocate all memory. */ - cleanup_variables(NULL, &global_system_variables); - cleanup_variables(NULL, &max_system_variables); + cleanup_variables(&global_system_variables); + cleanup_variables(&max_system_variables); mysql_mutex_unlock(&LOCK_plugin); initialized= 0; @@ -2042,7 +2072,8 @@ static bool finalize_install(THD *thd, TABLE *table, const LEX_STRING *name, { if (global_system_variables.log_warnings) push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_CANT_INITIALIZE_UDF, ER(ER_CANT_INITIALIZE_UDF), + ER_CANT_INITIALIZE_UDF, + ER_THD(thd, ER_CANT_INITIALIZE_UDF), name->str, "Plugin is disabled"); } @@ -2175,7 +2206,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, Sql_condition::WARN_LEVEL_WARN, - WARN_PLUGIN_BUSY, ER(WARN_PLUGIN_BUSY)); + WARN_PLUGIN_BUSY, ER_THD(thd, WARN_PLUGIN_BUSY)); else reap_needed= true; @@ -2901,6 +2932,62 @@ static st_bookmark *register_var(const char *plugin, const char *name, return result; } + +void sync_dynamic_session_variables(THD* thd, bool global_lock) +{ + uint idx; + + thd->variables.dynamic_variables_ptr= (char*) + my_realloc(thd->variables.dynamic_variables_ptr, + global_variables_dynamic_size, + MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); + + if (global_lock) + mysql_mutex_lock(&LOCK_global_system_variables); + + mysql_mutex_assert_owner(&LOCK_global_system_variables); + + memcpy(thd->variables.dynamic_variables_ptr + + thd->variables.dynamic_variables_size, + global_system_variables.dynamic_variables_ptr + + thd->variables.dynamic_variables_size, + global_system_variables.dynamic_variables_size - + thd->variables.dynamic_variables_size); + + /* + now we need to iterate through any newly copied 'defaults' + and if it is a string type with MEMALLOC flag, we need to strdup + */ + for (idx= 0; idx < bookmark_hash.records; idx++) + { + st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx); + + if (v->version <= thd->variables.dynamic_variables_version) + continue; /* already in thd->variables */ + + /* Here we do anything special that may be required of the data types */ + + if ((v->key[0] & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && + v->key[0] & BOOKMARK_MEMALLOC) + { + char **pp= (char**) (thd->variables.dynamic_variables_ptr + v->offset); + if (*pp) + *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE)); + } + } + + if (global_lock) + mysql_mutex_unlock(&LOCK_global_system_variables); + + thd->variables.dynamic_variables_version= + global_system_variables.dynamic_variables_version; + thd->variables.dynamic_variables_head= + global_system_variables.dynamic_variables_head; + thd->variables.dynamic_variables_size= + global_system_variables.dynamic_variables_size; +} + + /* returns a pointer to the memory which holds the thd-local variable or a pointer to the global variable if thd==null. @@ -2981,87 +3068,38 @@ static double *mysql_sys_var_double(THD* thd, int offset) void plugin_thdvar_init(THD *thd) { plugin_ref old_table_plugin= thd->variables.table_plugin; + plugin_ref old_tmp_table_plugin= thd->variables.tmp_table_plugin; + plugin_ref old_enforced_table_plugin= thd->variables.enforced_table_plugin; DBUG_ENTER("plugin_thdvar_init"); + // This function may be called many times per THD (e.g. on COM_CHANGE_USER) thd->variables.table_plugin= NULL; - cleanup_variables(thd, &thd->variables); + thd->variables.tmp_table_plugin= NULL; + thd->variables.enforced_table_plugin= NULL; + cleanup_variables(&thd->variables); thd->variables= global_system_variables; - thd->variables.table_plugin= NULL; /* we are going to allocate these lazily */ thd->variables.dynamic_variables_version= 0; thd->variables.dynamic_variables_size= 0; thd->variables.dynamic_variables_ptr= 0; -#ifdef WITH_WSREP - if (!WSREP(thd) || !thd->wsrep_applier) { -#endif mysql_mutex_lock(&LOCK_plugin); thd->variables.table_plugin= - intern_plugin_lock(NULL, global_system_variables.table_plugin); + intern_plugin_lock(NULL, global_system_variables.table_plugin); + if (global_system_variables.tmp_table_plugin) + thd->variables.tmp_table_plugin= + intern_plugin_lock(NULL, global_system_variables.tmp_table_plugin); + if (global_system_variables.enforced_table_plugin) + thd->variables.enforced_table_plugin= + intern_plugin_lock(NULL, global_system_variables.enforced_table_plugin); intern_plugin_unlock(NULL, old_table_plugin); + intern_plugin_unlock(NULL, old_tmp_table_plugin); + intern_plugin_unlock(NULL, old_enforced_table_plugin); mysql_mutex_unlock(&LOCK_plugin); -#ifdef WITH_WSREP - } -#endif - DBUG_VOID_RETURN; -} - - - -void sync_dynamic_session_variables(THD* thd, bool global_lock) -{ - uint idx; - - thd->variables.dynamic_variables_ptr= (char*) - my_realloc(thd->variables.dynamic_variables_ptr, - global_variables_dynamic_size, - MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); - - if (global_lock) - mysql_mutex_lock(&LOCK_global_system_variables); - - mysql_mutex_assert_owner(&LOCK_global_system_variables); - - memcpy(thd->variables.dynamic_variables_ptr + - thd->variables.dynamic_variables_size, - global_system_variables.dynamic_variables_ptr + - thd->variables.dynamic_variables_size, - global_system_variables.dynamic_variables_size - - thd->variables.dynamic_variables_size); - - /* - now we need to iterate through any newly copied 'defaults' - and if it is a string type with MEMALLOC flag, we need to strdup - */ - for (idx= 0; idx < bookmark_hash.records; idx++) - { - st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx); - - if (v->version <= thd->variables.dynamic_variables_version) - continue; /* already in thd->variables */ - - /* Here we do anything special that may be required of the data types */ - - if ((v->key[0] & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && - v->key[0] & BOOKMARK_MEMALLOC) - { - char **pp= (char**) (thd->variables.dynamic_variables_ptr + v->offset); - if (*pp) - *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE)); - } - } - - if (global_lock) - mysql_mutex_unlock(&LOCK_global_system_variables); - thd->variables.dynamic_variables_version= - global_system_variables.dynamic_variables_version; - thd->variables.dynamic_variables_head= - global_system_variables.dynamic_variables_head; - thd->variables.dynamic_variables_size= - global_system_variables.dynamic_variables_size; + DBUG_VOID_RETURN; } @@ -3071,7 +3109,9 @@ void sync_dynamic_session_variables(THD* thd, bool global_lock) static void unlock_variables(THD *thd, struct system_variables *vars) { intern_plugin_unlock(NULL, vars->table_plugin); - vars->table_plugin= NULL; + intern_plugin_unlock(NULL, vars->tmp_table_plugin); + intern_plugin_unlock(NULL, vars->enforced_table_plugin); + vars->table_plugin= vars->tmp_table_plugin= vars->enforced_table_plugin= NULL; } @@ -3081,7 +3121,7 @@ static void unlock_variables(THD *thd, struct system_variables *vars) Unlike plugin_vars_free_values() it frees all variables of all plugins, it's used on shutdown. */ -static void cleanup_variables(THD *thd, struct system_variables *vars) +static void cleanup_variables(struct system_variables *vars) { st_bookmark *v; uint idx; @@ -3096,6 +3136,7 @@ static void cleanup_variables(THD *thd, struct system_variables *vars) DBUG_ASSERT((uint)v->offset <= vars->dynamic_variables_head); + /* free allocated strings (PLUGIN_VAR_STR | PLUGIN_VAR_MEMALLOC) */ if ((v->key[0] & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && v->key[0] & BOOKMARK_MEMALLOC) { @@ -3107,6 +3148,8 @@ static void cleanup_variables(THD *thd, struct system_variables *vars) mysql_rwlock_unlock(&LOCK_system_variables_hash); DBUG_ASSERT(vars->table_plugin == NULL); + DBUG_ASSERT(vars->tmp_table_plugin == NULL); + DBUG_ASSERT(vars->enforced_table_plugin == NULL); my_free(vars->dynamic_variables_ptr); vars->dynamic_variables_ptr= NULL; @@ -3124,7 +3167,7 @@ void plugin_thdvar_cleanup(THD *thd) mysql_mutex_lock(&LOCK_plugin); unlock_variables(thd, &thd->variables); - cleanup_variables(thd, &thd->variables); + cleanup_variables(&thd->variables); if ((idx= thd->lex->plugins.elements)) { @@ -3176,7 +3219,7 @@ static void plugin_vars_free_values(sys_var *vars) DBUG_VOID_RETURN; } -static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var) +static SHOW_TYPE pluginvar_show_type(const st_mysql_sys_var *plugin_var) { switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_UNSIGNED)) { case PLUGIN_VAR_BOOL: @@ -3207,29 +3250,53 @@ static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var) } -bool sys_var_pluginvar::check_update_type(Item_result type) +static int pluginvar_sysvar_flags(const st_mysql_sys_var *p) { - switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) { - case PLUGIN_VAR_INT: - case PLUGIN_VAR_LONG: - case PLUGIN_VAR_LONGLONG: - return type != INT_RESULT; - case PLUGIN_VAR_STR: - return type != STRING_RESULT; - case PLUGIN_VAR_ENUM: - case PLUGIN_VAR_BOOL: - case PLUGIN_VAR_SET: - return type != STRING_RESULT && type != INT_RESULT; - case PLUGIN_VAR_DOUBLE: - return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT; - default: - return true; - } + return (p->flags & PLUGIN_VAR_THDLOCAL ? sys_var::SESSION : sys_var::GLOBAL) + | (p->flags & PLUGIN_VAR_READONLY ? sys_var::READONLY : 0); } +sys_var_pluginvar::sys_var_pluginvar(sys_var_chain *chain, const char *name_arg, + st_plugin_int *p, st_mysql_sys_var *pv) + : sys_var(chain, name_arg, pv->comment, pluginvar_sysvar_flags(pv), + 0, pv->flags & PLUGIN_VAR_NOCMDOPT ? -1 : 0, NO_ARG, + pluginvar_show_type(pv), 0, + NULL, VARIABLE_NOT_IN_BINLOG, NULL, NULL, NULL), + plugin(p), plugin_var(pv) +{ + plugin_var->name= name_arg; + plugin_opt_set_limits(&option, pv); +} uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type) { + if (type == OPT_DEFAULT) + { + switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) { + case PLUGIN_VAR_BOOL: + thd->sys_var_tmp.my_bool_value= option.def_value; + return (uchar*) &thd->sys_var_tmp.my_bool_value; + case PLUGIN_VAR_INT: + thd->sys_var_tmp.int_value= option.def_value; + return (uchar*) &thd->sys_var_tmp.int_value; + case PLUGIN_VAR_LONG: + case PLUGIN_VAR_ENUM: + thd->sys_var_tmp.long_value= option.def_value; + return (uchar*) &thd->sys_var_tmp.long_value; + case PLUGIN_VAR_LONGLONG: + case PLUGIN_VAR_SET: + return (uchar*) &option.def_value; + case PLUGIN_VAR_STR: + thd->sys_var_tmp.ptr_value= (void*) option.def_value; + return (uchar*) &thd->sys_var_tmp.ptr_value; + case PLUGIN_VAR_DOUBLE: + thd->sys_var_tmp.double_value= getopt_ulonglong2double(option.def_value); + return (uchar*) &thd->sys_var_tmp.double_value; + default: + DBUG_ASSERT(0); + } + } + DBUG_ASSERT(thd || (type == OPT_GLOBAL)); if (plugin_var->flags & PLUGIN_VAR_THDLOCAL) { @@ -3242,6 +3309,39 @@ uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type) } +bool sys_var_pluginvar::session_is_default(THD *thd) +{ + uchar *value= plugin_var->flags & PLUGIN_VAR_THDLOCAL + ? intern_sys_var_ptr(thd, *(int*) (plugin_var+1), true) + : *(uchar**) (plugin_var+1); + + real_value_ptr(thd, OPT_SESSION); + + switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) { + case PLUGIN_VAR_BOOL: + return option.def_value == *(my_bool*)value; + case PLUGIN_VAR_INT: + return option.def_value == *(int*)value; + case PLUGIN_VAR_LONG: + case PLUGIN_VAR_ENUM: + return option.def_value == *(long*)value; + case PLUGIN_VAR_LONGLONG: + case PLUGIN_VAR_SET: + return option.def_value == *(longlong*)value; + case PLUGIN_VAR_STR: + { + const char *a=(char*)option.def_value; + const char *b=(char*)value; + return (!a && !b) || (a && b && strcmp(a,b)); + } + case PLUGIN_VAR_DOUBLE: + return getopt_ulonglong2double(option.def_value) == *(double*)value; + } + DBUG_ASSERT(0); + return 0; +} + + TYPELIB* sys_var_pluginvar::plugin_var_typelib(void) { switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) { @@ -3261,7 +3361,7 @@ TYPELIB* sys_var_pluginvar::plugin_var_typelib(void) uchar* sys_var_pluginvar::do_value_ptr(THD *thd, enum_var_type type, - LEX_STRING *base) + const LEX_STRING *base) { uchar* result; @@ -3298,7 +3398,7 @@ bool sys_var_pluginvar::session_update(THD *thd, set_var *var) DBUG_ASSERT(thd == current_thd); mysql_mutex_lock(&LOCK_global_system_variables); - void *tgt= real_value_ptr(thd, var->type); + void *tgt= real_value_ptr(thd, OPT_SESSION); const void *src= var->value ? (void*)&var->save_result : (void*)real_value_ptr(thd, OPT_GLOBAL); mysql_mutex_unlock(&LOCK_global_system_variables); @@ -3355,7 +3455,7 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var) DBUG_ASSERT(!is_readonly()); mysql_mutex_assert_owner(&LOCK_global_system_variables); - void *tgt= real_value_ptr(thd, var->type); + void *tgt= real_value_ptr(thd, OPT_GLOBAL); const void *src= &var->save_result; if (!var->value) @@ -3423,6 +3523,7 @@ void plugin_opt_set_limits(struct my_option *options, case PLUGIN_VAR_BOOL: options->var_type= GET_BOOL; options->def_value= ((sysvar_bool_t*) opt)->def_val; + options->typelib= &bool_typelib; break; case PLUGIN_VAR_STR: options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ? @@ -3471,6 +3572,7 @@ void plugin_opt_set_limits(struct my_option *options, case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL: options->var_type= GET_BOOL; options->def_value= ((thdvar_bool_t*) opt)->def_val; + options->typelib= &bool_typelib; break; case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL: options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ? @@ -3517,7 +3619,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, char *comment= (char *) alloc_root(mem_root, max_comment_len + 1); char *optname; - int index= 0, offset= 0; + int index= 0, UNINIT_VAR(offset); st_mysql_sys_var *opt, **plugin_option; st_bookmark *v; @@ -3547,7 +3649,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, options[0].typelib= options[1].typelib= &global_plugin_typelib; strxnmov(comment, max_comment_len, "Enable or disable ", plugin_name, - " plugin. Possible values are ON, OFF, FORCE (don't start " + " plugin. One of: ON, OFF, FORCE (don't start " "if the plugin fails to load).", NullS); options[0].comment= comment; /* @@ -3563,12 +3665,6 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, options+= 2; } - if (!my_strcasecmp(&my_charset_latin1, plugin_name_ptr, "NDBCLUSTER")) - { - plugin_name_ptr= const_cast<char*>("ndb"); // Use legacy "ndb" prefix - plugin_name_len= 3; - } - /* Two passes as the 2nd pass will take pointer addresses for use by my_getopt and register_var() in the first pass uses realloc @@ -3578,6 +3674,14 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, plugin_option && *plugin_option; plugin_option++, index++) { opt= *plugin_option; + + if (!opt->name) + { + sql_print_error("Missing variable name in plugin '%s'.", + plugin_name); + DBUG_RETURN(-1); + } + if (!(opt->flags & PLUGIN_VAR_THDLOCAL)) continue; if (!(register_var(plugin_name_ptr, opt->name, opt->flags))) @@ -3686,13 +3790,6 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, == PLUGIN_VAR_NOCMDOPT) continue; - if (!opt->name) - { - sql_print_error("Missing variable name in plugin '%s'.", - plugin_name); - DBUG_RETURN(-1); - } - if (!(opt->flags & PLUGIN_VAR_THDLOCAL)) { optnamelen= strlen(opt->name); @@ -3734,7 +3831,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, options->name= optname; options->comment= opt->comment; - options->app_type= opt; + options->app_type= (opt->flags & PLUGIN_VAR_NOSYSVAR) ? NULL : opt; options->id= 0; plugin_opt_set_limits(options, opt); @@ -3790,6 +3887,17 @@ static my_option *construct_help_options(MEM_ROOT *mem_root, DBUG_RETURN(opts); } +extern "C" my_bool mark_changed(int, const struct my_option *, char *); +my_bool mark_changed(int, const struct my_option *opt, char *) +{ + if (opt->app_type) + { + sys_var *var= (sys_var*) opt->app_type; + var->value_origin= sys_var::CONFIG; + } + return 0; +} + /** Create and register system variables supplied from the plugin and assigns initial values from corresponding command line arguments. @@ -3821,21 +3929,22 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, &tmp->mem_root : &plugin_vars_mem_root; st_mysql_sys_var **opt; my_option *opts= NULL; - LEX_STRING plugin_name; - char *varname; - int error; - sys_var *v __attribute__((unused)); + int error= 1; struct st_bookmark *var; - uint len, count= EXTRA_OPTIONS; + uint len=0, count= EXTRA_OPTIONS; st_ptr_backup *tmp_backup= 0; DBUG_ENTER("test_plugin_options"); DBUG_ASSERT(tmp->plugin && tmp->name.str); - for (opt= tmp->plugin->system_vars; opt && *opt; opt++) - count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */ - - if (count > EXTRA_OPTIONS || (*argc > 1)) + if (tmp->plugin->system_vars || (*argc > 1)) { + for (opt= tmp->plugin->system_vars; opt && *opt; opt++) + { + len++; + if (!((*opt)->flags & PLUGIN_VAR_NOCMDOPT)) + count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */ + } + if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count))) { sql_print_error("Out of memory for plugin '%s'.", tmp->name.str); @@ -3849,6 +3958,57 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, DBUG_RETURN(-1); } + if (tmp->plugin->system_vars) + { + tmp_backup= (st_ptr_backup *)my_alloca(len * sizeof(tmp_backup[0])); + DBUG_ASSERT(tmp->nbackups == 0); + DBUG_ASSERT(tmp->ptr_backup == 0); + + for (opt= tmp->plugin->system_vars; *opt; opt++) + { + st_mysql_sys_var *o= *opt; + char *varname; + sys_var *v; + + if (o->flags & PLUGIN_VAR_NOSYSVAR) + continue; + + tmp_backup[tmp->nbackups++].save(&o->name); + if ((var= find_bookmark(tmp->name.str, o->name, o->flags))) + varname= var->key + 1; + else + { + len= tmp->name.length + strlen(o->name) + 2; + varname= (char*) alloc_root(mem_root, len); + strxmov(varname, tmp->name.str, "-", o->name, NullS); + my_casedn_str(&my_charset_latin1, varname); + convert_dash_to_underscore(varname, len-1); + } + v= new (mem_root) sys_var_pluginvar(&chain, varname, tmp, o); + if (!(o->flags & PLUGIN_VAR_NOCMDOPT)) + { + // update app_type, used for I_S.SYSTEM_VARIABLES + for (my_option *mo=opts; mo->name; mo++) + if (mo->app_type == o) + mo->app_type= v; + } + } + + if (tmp->nbackups) + { + 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); + my_afree(tmp_backup); + goto err; + } + memcpy(tmp->ptr_backup, tmp_backup, bytes); + } + my_afree(tmp_backup); + } + /* We adjust the default value to account for the hardcoded exceptions we have set for the federated and ndbcluster storage engines. @@ -3856,7 +4016,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, if (!plugin_is_forced(tmp)) opts[0].def_value= opts[1].def_value= plugin_load_option; - error= handle_options(argc, &argv, opts, NULL); + error= handle_options(argc, &argv, opts, mark_changed); (*argc)++; /* add back one for the program name */ if (error) @@ -3876,6 +4036,8 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, disable_plugin= (plugin_load_option == PLUGIN_OFF); tmp->load_option= plugin_load_option; + error= 1; + /* If the plugin is disabled it should not be initialized. */ @@ -3884,80 +4046,32 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, if (global_system_variables.log_warnings) sql_print_information("Plugin '%s' is disabled.", tmp->name.str); - if (opts) - my_cleanup_options(opts); - DBUG_RETURN(1); - } - - if (!my_strcasecmp(&my_charset_latin1, tmp->name.str, "NDBCLUSTER")) - { - plugin_name.str= const_cast<char*>("ndb"); // Use legacy "ndb" prefix - plugin_name.length= 3; + goto err; } - else - plugin_name= tmp->name; - - error= 1; if (tmp->plugin->system_vars) { - 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); - for (opt= tmp->plugin->system_vars; *opt; opt++) { - st_mysql_sys_var *o= *opt; - /* 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 + free() 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)) + (((*opt)->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_NOCMDOPT | + PLUGIN_VAR_MEMALLOC)) == PLUGIN_VAR_STR)) { - sysvar_str_t* str= (sysvar_str_t *)o; + sysvar_str_t* str= (sysvar_str_t *)*opt; 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) - { - 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); } if (chain.first) @@ -3971,14 +4085,11 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, } 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); @@ -4061,3 +4172,109 @@ static void restore_ptr_backup(uint n, st_ptr_backup *backup) while (n--) (backup++)->restore(); } + +/**************************************************************************** + thd specifics service, see include/mysql/service_thd_specifics.h +****************************************************************************/ +static const int INVALID_THD_KEY= -1; +static uint thd_key_no = 42; + +int thd_key_create(MYSQL_THD_KEY_T *key) +{ + int flags= PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_STR | + PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT; + char namebuf[256]; + snprintf(namebuf, sizeof(namebuf), "%u", thd_key_no++); + mysql_rwlock_wrlock(&LOCK_system_variables_hash); + // non-letters in the name as an extra safety + st_bookmark *bookmark= register_var("\a\v\a\t\a\r", namebuf, flags); + mysql_rwlock_unlock(&LOCK_system_variables_hash); + if (bookmark) + { + *key= bookmark->offset; + return 0; + } + return ENOMEM; +} + +void thd_key_delete(MYSQL_THD_KEY_T *key) +{ + *key= INVALID_THD_KEY; +} + +void* thd_getspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key) +{ + DBUG_ASSERT(key != INVALID_THD_KEY); + if (key == INVALID_THD_KEY || (!thd && !(thd= current_thd))) + return 0; + + return *(void**)(intern_sys_var_ptr(thd, key, true)); +} + +int thd_setspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key, void *value) +{ + DBUG_ASSERT(key != INVALID_THD_KEY); + if (key == INVALID_THD_KEY || (!thd && !(thd= current_thd))) + return EINVAL; + + memcpy(intern_sys_var_ptr(thd, key, true), &value, sizeof(void*)); + return 0; +} + +void plugin_mutex_init() +{ +#ifdef HAVE_PSI_INTERFACE + init_plugin_psi_keys(); +#endif + mysql_mutex_init(key_LOCK_plugin, &LOCK_plugin, MY_MUTEX_INIT_FAST); +} + +#ifdef WITH_WSREP + +/* + Placeholder for global_system_variables.table_plugin required during + initialization of startup wsrep threads. +*/ +static st_plugin_int wsrep_dummy_plugin; +static st_plugin_int *wsrep_dummy_plugin_ptr; + +/* + Initialize wsrep_dummy_plugin and assign it to + global_system_variables.table_plugin. +*/ +void wsrep_plugins_pre_init() +{ + wsrep_dummy_plugin_ptr= &wsrep_dummy_plugin; + wsrep_dummy_plugin.state= PLUGIN_IS_DISABLED; + global_system_variables.table_plugin= + plugin_int_to_ref(wsrep_dummy_plugin_ptr); +} + +/* + This function is intended to be called after the plugins and related + global system variables are initialized. It re-initializes some data + 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); + + while ((thd= it++)) + { + if (IF_WSREP(thd->wsrep_applier,1)) + { + // Save options_bits as it will get overwritten in plugin_thdvar_init() + ulonglong option_bits_saved= thd->variables.option_bits; + + plugin_thdvar_init(thd); + + // Restore option_bits + thd->variables.option_bits= option_bits_saved; + } + } + + return; +} +#endif /* WITH_WSREP */ |