diff options
Diffstat (limited to 'sql/sql_plugin.cc')
-rw-r--r-- | sql/sql_plugin.cc | 555 |
1 files changed, 378 insertions, 177 deletions
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 5f5e73091ff..06ead26414c 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1,5 +1,6 @@ /* - Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2005, 2011, Oracle and/or its affiliates. + Copyright (c) 2010, 2011, Monty Program Ab 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 @@ -33,11 +34,12 @@ #include "sql_audit.h" #include <mysql/plugin_auth.h> #include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT +#include <mysql/plugin_auth.h> #define REPORT_TO_LOG 1 #define REPORT_TO_USER 2 -extern struct st_mysql_plugin *mysql_optional_plugins[]; -extern struct st_mysql_plugin *mysql_mandatory_plugins[]; +extern struct st_maria_plugin *mysql_optional_plugins[]; +extern struct st_maria_plugin *mysql_mandatory_plugins[]; /** @note The order of the enumeration is critical. @@ -53,6 +55,18 @@ static TYPELIB global_plugin_typelib= char *opt_plugin_load= NULL; char *opt_plugin_dir_ptr; char opt_plugin_dir[FN_REFLEN]; +ulong plugin_maturity; + +/* + not really needed now, this map will become essential when we add more + maturity levels. We cannot change existing maturity constants, + so the next value - even if it will be MariaDB_PLUGIN_MATURITY_VERY_BUGGY - + will inevitably be larger than MariaDB_PLUGIN_MATURITY_STABLE. + To be able to compare them we use this mapping array +*/ +uint plugin_maturity_map[]= +{ 0, 1, 2, 3, 4, 5, 6 }; + /* When you ad a new plugin type, add both a string and make sure that the init and deinit array are correctly updated. @@ -83,13 +97,13 @@ 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 + initialize_audit_plugin, 0, 0 }; 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 + finalize_audit_plugin, 0, 0 }; #ifdef HAVE_DLOPEN @@ -99,6 +113,14 @@ static const char *sizeof_st_plugin_sym= "_mysql_sizeof_struct_st_plugin_"; static const char *plugin_declarations_sym= "_mysql_plugin_declarations_"; static int min_plugin_interface_version= MYSQL_PLUGIN_INTERFACE_VERSION & ~0xFF; +static const char *maria_plugin_interface_version_sym= + "_maria_plugin_interface_version_"; +static const char *maria_sizeof_st_plugin_sym= + "_maria_sizeof_struct_st_plugin_"; +static const char *maria_plugin_declarations_sym= + "_maria_plugin_declarations_"; +static int min_maria_plugin_interface_version= + MARIA_PLUGIN_INTERFACE_VERSION & ~0xFF; #endif /* Note that 'int version' must be the first field of every plugin @@ -223,7 +245,7 @@ public: (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, 0, 0, 0, 0, PARSE_NORMAL), + VARIABLE_NOT_IN_BINLOG, 0, 0, 0, 0), plugin_var(plugin_var_arg), orig_pluginvar_name(plugin_var_arg->name) { plugin_var->name= name_arg; } sys_var_pluginvar *cast_pluginvar() { return this; } @@ -250,7 +272,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, const char *list); static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *, int *, char **); -static bool register_builtin(struct st_mysql_plugin *, 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); @@ -331,7 +353,7 @@ static const char *item_val_str(struct st_mysql_value *value, Lets be nice and create a temporary string since the buffer was too small */ - return current_thd->strmake(res->c_ptr_quick(), res->length()); + return current_thd->strmake(res->ptr(), res->length()); } @@ -416,11 +438,232 @@ static inline void free_plugin_mem(struct st_plugin_dl *p) dlclose(p->handle); #endif my_free(p->dl.str); - if (p->version != MYSQL_PLUGIN_INTERFACE_VERSION) + if (p->allocated) my_free(p->plugins); } +/** + Reads data from mysql plugin interface + + @param plugin_dl Structure where the data should be put + @param sym Reverence on version info + @param dlpath Path to the module + @param report What errors should be reported + + @retval FALSE OK + @retval TRUE ERROR +*/ + +#ifdef HAVE_DLOPEN +static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl, + void *sym, char *dlpath, + int report) +{ + DBUG_ENTER("read_maria_plugin_info"); + /* 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); + } + plugin_dl->mariaversion= 0; + plugin_dl->mysqlversion= *(int *)sym; + /* Versioning */ + 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, + "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); + } + + /* convert mysql declaration to maria one */ + { + int i; + uint sizeof_st_plugin; + struct st_mysql_plugin *old; + struct st_maria_plugin *cur; + char *ptr= (char *)sym; + + if ((sym= dlsym(plugin_dl->handle, sizeof_st_plugin_sym))) + sizeof_st_plugin= *(int *)sym; + else + { + DBUG_ASSERT(min_plugin_interface_version == 0); + sizeof_st_plugin= (int)offsetof(struct st_mysql_plugin, version); + } + + for (i= 0; + ((struct st_mysql_plugin *)(ptr + i * sizeof_st_plugin))->info; + i++) + /* no op */; + + cur= (struct st_maria_plugin*) + my_malloc((i + 1) * sizeof(struct st_maria_plugin), + 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); + } + /* + All st_plugin fields not initialized in the plugin explicitly, are + set to 0. It matches C standard behaviour for struct initializers that + have less values than the struct definition. + */ + for (i=0; + (old= (struct st_mysql_plugin *)(ptr + i * sizeof_st_plugin))->info; + i++) + { + + cur[i].type= old->type; + cur[i].info= old->info; + cur[i].name= old->name; + cur[i].author= old->author; + cur[i].descr= old->descr; + cur[i].license= old->license; + cur[i].init= old->init; + cur[i].deinit= old->deinit; + cur[i].version= old->version; + cur[i].status_vars= old->status_vars; + cur[i].system_vars= old->system_vars; + /* + Something like this should be added to process + new mysql plugin versions: + if (plugin_dl->mysqlversion > 0x0101) + { + cur[i].newfield= CONSTANT_MEANS_UNKNOWN; + } + else + { + cur[i].newfield= old->newfield; + } + */ + /* Maria only fields */ + cur[i].version_info= "Unknown"; + cur[i].maturity= MariaDB_PLUGIN_MATURITY_UNKNOWN; + } + plugin_dl->allocated= true; + plugin_dl->plugins= (struct st_maria_plugin *)cur; + } + + DBUG_RETURN(FALSE); +} + + +/** + Reads data from maria plugin interface + + @param plugin_dl Structure where the data should be put + @param sym Reverence on version info + @param dlpath Path to the module + @param report what errors should be reported + + @retval FALSE OK + @retval TRUE ERROR +*/ + +static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl, + void *sym, char *dlpath, + int report) +{ + DBUG_ENTER("read_maria_plugin_info"); + + /* Determine interface version */ + if (!(sym)) + { + /* + 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); + } + plugin_dl->mariaversion= *(int *)sym; + plugin_dl->mysqlversion= 0; + /* Versioning */ + 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, 0, + "plugin interface version mismatch"); + DBUG_RETURN(TRUE); + } + /* 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); + } + if (plugin_dl->mariaversion != MARIA_PLUGIN_INTERFACE_VERSION) + { + uint sizeof_st_plugin; + struct st_maria_plugin *old, *cur; + char *ptr= (char *)sym; + + if ((sym= dlsym(plugin_dl->handle, maria_sizeof_st_plugin_sym))) + 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); + } + + if (sizeof_st_plugin != sizeof(st_mysql_plugin)) + { + int i; + for (i= 0; + ((struct st_maria_plugin *)(ptr + i * sizeof_st_plugin))->info; + i++) + /* no op */; + + cur= (struct st_maria_plugin*) + my_malloc((i + 1) * sizeof(struct st_maria_plugin), + 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); + } + /* + All st_plugin fields not initialized in the plugin explicitly, are + set to 0. It matches C standard behaviour for struct initializers that + have less values than the struct definition. + */ + 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)); + + sym= cur; + plugin_dl->allocated= true; + } + } + plugin_dl->plugins= (struct st_maria_plugin *)sym; + + DBUG_RETURN(FALSE); +} +#endif /* HAVE_DLOPEN */ + static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) { #ifdef HAVE_DLOPEN @@ -470,22 +713,21 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, errno, errmsg); DBUG_RETURN(0); } - /* Determine interface version */ - if (!(sym= dlsym(plugin_dl.handle, plugin_interface_version_sym))) + + /* Checks which plugin interface present and reads info */ + if (!(sym= dlsym(plugin_dl.handle, maria_plugin_interface_version_sym))) { - free_plugin_mem(&plugin_dl); - report_error(report, ER_CANT_FIND_DL_ENTRY, plugin_interface_version_sym); - DBUG_RETURN(0); + if (read_mysql_plugin_info(&plugin_dl, + dlsym(plugin_dl.handle, + plugin_interface_version_sym), + dlpath, + report)) + DBUG_RETURN(0); } - plugin_dl.version= *(int *)sym; - /* Versioning */ - if (plugin_dl.version < min_plugin_interface_version || - (plugin_dl.version >> 8) > (MYSQL_PLUGIN_INTERFACE_VERSION >> 8)) + else { - free_plugin_mem(&plugin_dl); - report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, 0, - "plugin interface version mismatch"); - DBUG_RETURN(0); + if (read_maria_plugin_info(&plugin_dl, sym, dlpath, report)) + DBUG_RETURN(0); } /* link the services in */ @@ -508,87 +750,6 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) } } - /* 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(0); - } - - if (plugin_dl.version != MYSQL_PLUGIN_INTERFACE_VERSION) - { - uint sizeof_st_plugin; - struct st_mysql_plugin *old, *cur; - char *ptr= (char *)sym; - - if ((sym= dlsym(plugin_dl.handle, sizeof_st_plugin_sym))) - sizeof_st_plugin= *(int *)sym; - else - { -#ifdef ERROR_ON_NO_SIZEOF_PLUGIN_SYMBOL - report_error(report, ER_CANT_FIND_DL_ENTRY, sizeof_st_plugin_sym); - DBUG_RETURN(0); -#else - /* - When the following assert starts failing, we'll have to switch - to the upper branch of the #ifdef - */ - DBUG_ASSERT(min_plugin_interface_version == 0); - sizeof_st_plugin= (int)offsetof(struct st_mysql_plugin, version); -#endif - } - - /* - What's the purpose of this loop? If the goal is to catch a - missing 0 record at the end of a list, it will fail miserably - since the compiler is likely to optimize this away. /Matz - */ - for (i= 0; - ((struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info; - i++) - /* no op */; - - cur= (struct st_mysql_plugin*) - my_malloc((i+1)*sizeof(struct st_mysql_plugin), 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(0); - } - /* - All st_plugin fields not initialized in the plugin explicitly, are - set to 0. It matches C standard behaviour for struct initializers that - have less values than the struct definition. - */ - for (i=0; - (old=(struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info; - i++) - memcpy(cur+i, old, min(sizeof(cur[i]), sizeof_st_plugin)); - - sym= cur; - } - plugin_dl.plugins= (struct st_mysql_plugin *)sym; - - /* - If report is REPORT_TO_USER, we were called from - mysql_install_plugin. Otherwise, we are called directly or - indirectly from plugin_init. - */ - if (report == REPORT_TO_USER) - { - st_mysql_plugin *plugin= plugin_dl.plugins; - for ( ; plugin->info ; ++plugin) - if (plugin->flags & PLUGIN_OPT_NO_INSTALL) - { - report_error(report, ER_PLUGIN_NO_INSTALL, plugin->name); - free_plugin_mem(&plugin_dl); - DBUG_RETURN(0); - } - } - /* 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)))) @@ -721,7 +882,10 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc) { plugin_ref plugin; #ifdef DBUG_OFF - /* built-in plugins don't need ref counting */ + /* + In optimized builds we don't do reference counting for built-in + (plugin->plugin_dl == 0) plugins. + */ if (!pi->plugin_dl) DBUG_RETURN(pi); @@ -738,7 +902,7 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc) *plugin= pi; #endif pi->ref_count++; - DBUG_PRINT("info",("thd: 0x%lx, plugin: \"%s\", ref_count: %d", + DBUG_PRINT("lock",("thd: 0x%lx plugin: \"%s\" LOCK ref_count: %d", (long) current_thd, pi->name.str, pi->ref_count)); if (lex) @@ -749,13 +913,33 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc) } -plugin_ref plugin_lock(THD *thd, plugin_ref *ptr) +plugin_ref plugin_lock(THD *thd, plugin_ref ptr) { LEX *lex= thd ? thd->lex : 0; plugin_ref rc; DBUG_ENTER("plugin_lock"); + +#ifdef DBUG_OFF + /* + In optimized builds we don't do reference counting for built-in + (plugin->plugin_dl == 0) plugins. + + Note that we access plugin->plugin_dl outside of LOCK_plugin, and for + dynamic plugins a 'plugin' could correspond to plugin that was unloaded + meanwhile! But because st_plugin_int is always allocated on + plugin_mem_root, the pointer can never be invalid - the memory is never + freed. + Of course, the memory that 'plugin' points to can be overwritten by + another plugin being loaded, but plugin->plugin_dl can never change + from zero to non-zero or vice versa. + That is, it's always safe to check for plugin->plugin_dl==0 even + without a mutex. + */ + if (! plugin_dlib(ptr)) + DBUG_RETURN(ptr); +#endif mysql_mutex_lock(&LOCK_plugin); - rc= my_intern_plugin_lock_ci(lex, *ptr); + rc= my_intern_plugin_lock_ci(lex, ptr); mysql_mutex_unlock(&LOCK_plugin); DBUG_RETURN(rc); } @@ -808,7 +992,7 @@ static bool plugin_add(MEM_ROOT *tmp_root, int *argc, char **argv, int report) { struct st_plugin_int tmp; - struct st_mysql_plugin *plugin; + struct st_maria_plugin *plugin; DBUG_ENTER("plugin_add"); if (plugin_find_internal(name, MYSQL_ANY_PLUGIN)) { @@ -842,6 +1026,17 @@ static bool plugin_add(MEM_ROOT *tmp_root, report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf); goto err; } + if (plugin_maturity_map[plugin->maturity] < plugin_maturity) + { + char buf[256]; + strxnmov(buf, sizeof(buf) - 1, "Loading of ", + plugin_maturity_names[plugin->maturity], + " plugins is prohibited by --plugin-maturity=", + plugin_maturity_names[plugin_maturity], + NullS); + report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf); + goto err; + } tmp.plugin= plugin; tmp.name.str= (char *)plugin->name; tmp.name.length= name_len; @@ -864,10 +1059,6 @@ static bool plugin_add(MEM_ROOT *tmp_root, mysql_del_sys_var_chain(tmp.system_vars); restore_pluginvar_names(tmp.system_vars); goto err; - - /* plugin was disabled */ - plugin_dl_del(dl); - DBUG_RETURN(FALSE); } } report_error(report, ER_CANT_FIND_DL_ENTRY, name->str); @@ -936,7 +1127,7 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check) static void plugin_del(struct st_plugin_int *plugin) { - DBUG_ENTER("plugin_del(plugin)"); + DBUG_ENTER("plugin_del"); mysql_mutex_assert_owner(&LOCK_plugin); /* Free allocated strings before deleting the plugin. */ mysql_rwlock_wrlock(&LOCK_system_variables_hash); @@ -1013,8 +1204,6 @@ static void intern_plugin_unlock(LEX *lex, plugin_ref plugin) my_free(plugin); #endif - DBUG_PRINT("info",("unlocking plugin, name= %s, ref_count= %d", - pi->name.str, pi->ref_count)); if (lex) { /* @@ -1034,6 +1223,9 @@ static void intern_plugin_unlock(LEX *lex, plugin_ref plugin) DBUG_ASSERT(pi->ref_count); pi->ref_count--; + DBUG_PRINT("lock",("thd: 0x%lx plugin: \"%s\" UNLOCK ref_count: %d", + (long) current_thd, pi->name.str, pi->ref_count)); + if (pi->state == PLUGIN_IS_DELETED && !pi->ref_count) reap_needed= true; @@ -1064,6 +1256,9 @@ void plugin_unlock_list(THD *thd, plugin_ref *list, uint count) { LEX *lex= thd ? thd->lex : 0; DBUG_ENTER("plugin_unlock_list"); + if (count == 0) + DBUG_VOID_RETURN; + DBUG_ASSERT(list); mysql_mutex_lock(&LOCK_plugin); while (count--) @@ -1224,8 +1419,8 @@ int plugin_init(int *argc, char **argv, int flags) { uint i; bool is_myisam; - struct st_mysql_plugin **builtins; - struct st_mysql_plugin *plugin; + 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; @@ -1284,6 +1479,7 @@ int plugin_init(int *argc, char **argv, int flags) !my_strnncoll(&my_charset_latin1, (const uchar*) plugin->name, 6, (const uchar*) "InnoDB", 6)) continue; + bzero(&tmp, sizeof(tmp)); tmp.plugin= plugin; tmp.name.str= (char *)plugin->name; @@ -1318,15 +1514,23 @@ int plugin_init(int *argc, char **argv, int flags) if (register_builtin(plugin, &tmp, &plugin_ptr)) goto err_unlock; - /* only initialize MyISAM and CSV at this stage */ - if (!(is_myisam= - !my_strcasecmp(&my_charset_latin1, plugin->name, "MyISAM")) && - my_strcasecmp(&my_charset_latin1, plugin->name, "CSV")) - continue; + is_myisam= !my_strcasecmp(&my_charset_latin1, plugin->name, "MyISAM"); - if (plugin_ptr->state != PLUGIN_IS_UNINITIALIZED || - plugin_initialize(plugin_ptr)) - goto err_unlock; + /* + 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 (!(flags & PLUGIN_INIT_SKIP_INITIALIZATION) || is_myisam) + { + if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED && + plugin_initialize(plugin_ptr)) + goto err_unlock; + } /* initialize the global default storage engine so that it may @@ -1412,7 +1616,7 @@ err: } -static bool register_builtin(struct st_mysql_plugin *plugin, +static bool register_builtin(struct st_maria_plugin *plugin, struct st_plugin_int *tmp, struct st_plugin_int **ptr) { @@ -1478,20 +1682,21 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv) if (result) { DBUG_PRINT("error",("Can't open plugin table")); - sql_print_error("Can't open the mysql.plugin table. Please " - "run mysql_upgrade to create it."); + if (!opt_help) + sql_print_error("Can't open the mysql.plugin table. Please " + "run mysql_upgrade to create it."); + else + sql_print_warning("Could not open mysql.plugin table. Some options may be missing from the help text"); goto end; } table= tables.table; - init_read_record(&read_record_info, new_thd, table, NULL, 1, 0, FALSE); + 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 " + "loaded"); + goto end; + } table->use_all_columns(); - /* - 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); while (!(error= read_record_info.read_record(&read_record_info))) { DBUG_PRINT("info", ("init plugin record")); @@ -1502,12 +1707,19 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv) LEX_STRING name= {(char *)str_name.ptr(), str_name.length()}; LEX_STRING dl= {(char *)str_dl.ptr(), str_dl.length()}; + /* + 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); if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG)) sql_print_warning("Couldn't load plugin named '%s' with soname '%s'.", str_name.c_ptr(), str_dl.c_ptr()); free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE)); + mysql_mutex_unlock(&LOCK_plugin); } - mysql_mutex_unlock(&LOCK_plugin); if (error > 0) sql_print_error(ER(ER_GET_ERRNO), my_errno); end_read_record(&read_record_info); @@ -1529,7 +1741,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, char buffer[FN_REFLEN]; LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name; struct st_plugin_dl *plugin_dl; - struct st_mysql_plugin *plugin; + struct st_maria_plugin *plugin; char *p= buffer; DBUG_ENTER("plugin_load_list"); while (list) @@ -1696,7 +1908,8 @@ void plugin_shutdown(void) if (plugins[i]->ref_count) sql_print_error("Plugin '%s' has ref_count=%d after shutdown.", plugins[i]->name.str, plugins[i]->ref_count); - if (plugins[i]->state & PLUGIN_IS_UNINITIALIZED) + if (plugins[i]->state & PLUGIN_IS_UNINITIALIZED || + plugins[i]->state & PLUGIN_IS_DISABLED) plugin_del(plugins[i]); } @@ -1801,9 +2014,10 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl if (tmp->state == PLUGIN_IS_DISABLED) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_CANT_INITIALIZE_UDF, ER(ER_CANT_INITIALIZE_UDF), - name->str, "Plugin is disabled"); + if (global_system_variables.log_warnings) + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_INITIALIZE_UDF, ER(ER_CANT_INITIALIZE_UDF), + name->str, "Plugin is disabled"); } else { @@ -1906,16 +2120,6 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); goto err; } - /* - Error message for ER_PLUGIN_IS_PERMANENT is not suitable for - plugins marked as not dynamically uninstallable, so we have a - separate one instead of changing the old one. - */ - if (plugin->plugin->flags & PLUGIN_OPT_NO_UNINSTALL) - { - my_error(ER_PLUGIN_NO_UNINSTALL, MYF(0), plugin->plugin->name); - goto err; - } plugin->state= PLUGIN_IS_DELETED; if (plugin->ref_count) @@ -1931,8 +2135,8 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) table->field[0]->store(name->str, name->length, system_charset_info); key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - if (! table->file->index_read_idx_map(table->record[0], 0, user_key, - HA_WHOLE_KEY, HA_READ_KEY_EXACT)) + if (! table->file->ha_index_read_idx_map(table->record[0], 0, user_key, + HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { int error; /* @@ -2027,6 +2231,7 @@ err: #undef MYSQL_SYSVAR_NAME #define MYSQL_SYSVAR_NAME(name) name #define PLUGIN_VAR_TYPEMASK 0x007f +#define PLUGIN_VAR_BOOKMARK_KEY (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_MEMALLOC) #define EXTRA_OPTIONS 3 /* options for: 'foo', 'plugin-foo' and NULL */ @@ -2380,7 +2585,7 @@ static st_bookmark *find_bookmark(const char *plugin, const char *name, else memcpy(varname + 1, name, namelen + 1); - varname[0]= flags & PLUGIN_VAR_TYPEMASK; + varname[0]= flags & PLUGIN_VAR_BOOKMARK_KEY; result= (st_bookmark*) my_hash_search(&bookmark_hash, (const uchar*) varname, length - 1); @@ -2438,7 +2643,7 @@ static st_bookmark *register_var(const char *plugin, const char *name, { result= (st_bookmark*) alloc_root(&plugin_mem_root, sizeof(struct st_bookmark) + length-1); - varname[0]= flags & PLUGIN_VAR_TYPEMASK; + varname[0]= flags & PLUGIN_VAR_BOOKMARK_KEY; memcpy(result->key, varname, length); result->name_len= length - 2; result->offset= -1; @@ -2511,11 +2716,12 @@ static void restore_pluginvar_names(sys_var *first) */ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) { + DBUG_ENTER("intern_sys_var_ptr"); DBUG_ASSERT(offset >= 0); DBUG_ASSERT((uint)offset <= global_system_variables.dynamic_variables_head); if (!thd) - return (uchar*) global_system_variables.dynamic_variables_ptr + offset; + DBUG_RETURN((uchar*) global_system_variables.dynamic_variables_ptr + offset); /* dynamic_variables_head points to the largest valid offset @@ -2554,10 +2760,12 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) sys_var *var; st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx); - if (v->version <= thd->variables.dynamic_variables_version || - !(var= intern_find_sys_var(v->key + 1, v->name_len)) || + if (v->version <= thd->variables.dynamic_variables_version) + continue; /* already in thd->variables */ + + if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) || !(pi= var->cast_pluginvar()) || - v->key[0] != (pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK)) + v->key[0] != (pi->plugin_var->flags & PLUGIN_VAR_BOOKMARK_KEY)) continue; /* Here we do anything special that may be required of the data types */ @@ -2585,7 +2793,7 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) mysql_rwlock_unlock(&LOCK_system_variables_hash); } - return (uchar*)thd->variables.dynamic_variables_ptr + offset; + DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset); } @@ -2676,27 +2884,22 @@ static void unlock_variables(THD *thd, struct system_variables *vars) static void cleanup_variables(THD *thd, struct system_variables *vars) { st_bookmark *v; - sys_var_pluginvar *pivar; - sys_var *var; - int flags; uint idx; mysql_rwlock_rdlock(&LOCK_system_variables_hash); for (idx= 0; idx < bookmark_hash.records; idx++) { v= (st_bookmark*) my_hash_element(&bookmark_hash, idx); - if (v->version > vars->dynamic_variables_version || - !(var= intern_find_sys_var(v->key + 1, v->name_len)) || - !(pivar= var->cast_pluginvar()) || - v->key[0] != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK)) - continue; - flags= pivar->plugin_var->flags; + if (v->version > vars->dynamic_variables_version) + continue; /* not in vars */ + + DBUG_ASSERT((uint)v->offset <= vars->dynamic_variables_head); - if ((flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && - flags & PLUGIN_VAR_THDLOCAL && flags & PLUGIN_VAR_MEMALLOC) + if ((v->key[0] & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && + v->key[0] & PLUGIN_VAR_MEMALLOC) { - char **ptr= (char**) pivar->real_value_ptr(thd, OPT_SESSION); + char **ptr= (char**)(vars->dynamic_variables_ptr + v->offset); my_free(*ptr); *ptr= NULL; } @@ -3403,11 +3606,9 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, DBUG_ASSERT(tmp->plugin && tmp->name.str); /* - The 'federated' and 'ndbcluster' storage engines are always disabled by - default. + The 'ndbcluster' storage engines is always disabled by default. */ - if (!(my_strcasecmp(&my_charset_latin1, tmp->name.str, "federated") && - my_strcasecmp(&my_charset_latin1, tmp->name.str, "ndbcluster"))) + if (!my_strcasecmp(&my_charset_latin1, tmp->name.str, "ndbcluster")) plugin_load_option= PLUGIN_OFF; for (opt= tmp->plugin->system_vars; opt && *opt; opt++) |