diff --git a/include/my_global.h b/include/my_global.h index a7e7d50054b..3acb204de6c 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -462,8 +462,6 @@ extern "C" int madvise(void *addr, size_t len, int behav); #ifndef SO_EXT #ifdef _WIN32 #define SO_EXT ".dll" -#elif defined(__APPLE__) -#define SO_EXT ".dylib" #else #define SO_EXT ".so" #endif diff --git a/mysql-test/r/plugin.result b/mysql-test/r/plugin.result index 7c89beb9725..5ccd64b5c30 100644 --- a/mysql-test/r/plugin.result +++ b/mysql-test/r/plugin.result @@ -3,15 +3,41 @@ Warnings: Warning 1286 Unknown storage engine 'EXAMPLE' Warning 1266 Using storage engine MyISAM for table 't1' DROP TABLE t1; -INSTALL PLUGIN example SONAME 'ha_example.so'; -INSTALL PLUGIN EXAMPLE SONAME 'ha_example.so'; +INSTALL PLUGIN example SONAME 'ha_example'; +INSTALL PLUGIN EXAMPLE SONAME 'ha_example'; ERROR HY000: Function 'EXAMPLE' already exists UNINSTALL PLUGIN example; -INSTALL PLUGIN example SONAME 'ha_example.so'; +INSTALL SONAME 'ha_example'; +select * from information_schema.plugins where plugin_library like 'ha_example%'; +PLUGIN_NAME EXAMPLE +PLUGIN_VERSION 0.1 +PLUGIN_STATUS ACTIVE +PLUGIN_TYPE STORAGE ENGINE +PLUGIN_TYPE_VERSION # +PLUGIN_LIBRARY ha_example.so +PLUGIN_LIBRARY_VERSION 1.1 +PLUGIN_AUTHOR Brian Aker, MySQL AB +PLUGIN_DESCRIPTION Example storage engine +PLUGIN_LICENSE GPL +LOAD_OPTION ON +PLUGIN_MATURITY Experimental +PLUGIN_AUTH_VERSION 0.1 +PLUGIN_NAME UNUSABLE +PLUGIN_VERSION 3.14 +PLUGIN_STATUS ACTIVE +PLUGIN_TYPE DAEMON +PLUGIN_TYPE_VERSION # +PLUGIN_LIBRARY ha_example.so +PLUGIN_LIBRARY_VERSION 1.1 +PLUGIN_AUTHOR Sergei Golubchik +PLUGIN_DESCRIPTION Unusable Daemon +PLUGIN_LICENSE GPL +LOAD_OPTION ON +PLUGIN_MATURITY Experimental +PLUGIN_AUTH_VERSION 3.14.15.926 CREATE TABLE t1(a int) ENGINE=EXAMPLE; SELECT * FROM t1; a -DROP TABLE t1; set global example_ulong_var=500; set global example_enum_var= e1; show status like 'example%'; @@ -21,7 +47,24 @@ show variables like 'example%'; Variable_name Value example_enum_var e1 example_ulong_var 500 -UNINSTALL PLUGIN example; +UNINSTALL SONAME 'ha_example'; +Warnings: +Warning 1620 Plugin is busy and will be uninstalled on shutdown +select * from information_schema.plugins where plugin_library like 'ha_example%'; +PLUGIN_NAME EXAMPLE +PLUGIN_VERSION 0.1 +PLUGIN_STATUS DELETED +PLUGIN_TYPE STORAGE ENGINE +PLUGIN_TYPE_VERSION # +PLUGIN_LIBRARY ha_example.so +PLUGIN_LIBRARY_VERSION 1.1 +PLUGIN_AUTHOR Brian Aker, MySQL AB +PLUGIN_DESCRIPTION Example storage engine +PLUGIN_LICENSE GPL +LOAD_OPTION ON +PLUGIN_MATURITY Experimental +PLUGIN_AUTH_VERSION 0.1 +DROP TABLE t1; UNINSTALL PLUGIN EXAMPLE; ERROR 42000: PLUGIN EXAMPLE does not exist UNINSTALL PLUGIN non_exist; @@ -30,13 +73,13 @@ ERROR 42000: PLUGIN non_exist does not exist # Bug#32034: check_func_enum() does not check correct values but set it # to impossible int val # -INSTALL PLUGIN example SONAME 'ha_example.so'; +INSTALL PLUGIN example SONAME 'ha_example'; SET GLOBAL example_enum_var= e1; SET GLOBAL example_enum_var= e2; SET GLOBAL example_enum_var= impossible; ERROR 42000: Variable 'example_enum_var' can't be set to the value of 'impossible' UNINSTALL PLUGIN example; -INSTALL PLUGIN example SONAME 'ha_example.so'; +INSTALL PLUGIN example SONAME 'ha_example'; select @@session.sql_mode into @old_sql_mode; set session sql_mode=''; set global example_ulong_var=500; diff --git a/mysql-test/r/plugin_maturity.result b/mysql-test/r/plugin_maturity.result index 97147459f6f..3249ea9b3c1 100644 --- a/mysql-test/r/plugin_maturity.result +++ b/mysql-test/r/plugin_maturity.result @@ -1,2 +1,8 @@ INSTALL PLUGIN example SONAME 'ha_example.so'; -ERROR HY000: Can't open shared library 'ha_example.so' (errno: 0 Loading of experimental plugins is prohibited by --plugin-maturity=stable) +ERROR HY000: Can't open shared library 'ha_example.so' (errno: 0 Loading of experimental plugin EXAMPLE is prohibited by --plugin-maturity=stable) +INSTALL SONAME 'ha_example.so'; +ERROR HY000: Can't open shared library 'ha_example.so' (errno: 0 Loading of experimental plugin EXAMPLE is prohibited by --plugin-maturity=stable) +show warnings; +Level Code Message +Error 1126 Can't open shared library 'ha_example.so' (errno: 0 Loading of experimental plugin EXAMPLE is prohibited by --plugin-maturity=stable) +Error 1126 Can't open shared library 'ha_example.so' (errno: 0 Loading of experimental plugin UNUSABLE is prohibited by --plugin-maturity=stable) diff --git a/mysql-test/t/plugin.test b/mysql-test/t/plugin.test index 6b0308cfc32..2b234b64047 100644 --- a/mysql-test/t/plugin.test +++ b/mysql-test/t/plugin.test @@ -4,23 +4,23 @@ CREATE TABLE t1(a int) ENGINE=EXAMPLE; DROP TABLE t1; ---replace_regex /\.dll/.so/ -eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO'; +eval INSTALL PLUGIN example SONAME 'ha_example'; --replace_regex /\.dll/.so/ --error 1125 -eval INSTALL PLUGIN EXAMPLE SONAME '$HA_EXAMPLE_SO'; +eval INSTALL PLUGIN EXAMPLE SONAME 'ha_example'; UNINSTALL PLUGIN example; +eval INSTALL SONAME 'ha_example'; +--replace_column 5 # --replace_regex /\.dll/.so/ -eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO'; +--query_vertical select * from information_schema.plugins where plugin_library like 'ha_example%' CREATE TABLE t1(a int) ENGINE=EXAMPLE; # Let's do some advanced ops with the example engine :) SELECT * FROM t1; -DROP TABLE t1; # a couple of tests for variables set global example_ulong_var=500; @@ -28,7 +28,13 @@ set global example_enum_var= e1; show status like 'example%'; show variables like 'example%'; -UNINSTALL PLUGIN example; +eval UNINSTALL SONAME 'ha_example'; +--replace_column 5 # +--replace_regex /\.dll/.so/ +--query_vertical select * from information_schema.plugins where plugin_library like 'ha_example%' + +DROP TABLE t1; + --error 1305 UNINSTALL PLUGIN EXAMPLE; @@ -40,8 +46,7 @@ UNINSTALL PLUGIN non_exist; --echo # Bug#32034: check_func_enum() does not check correct values but set it --echo # to impossible int val --echo # ---replace_regex /\.dll/.so/ -eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO'; +eval INSTALL PLUGIN example SONAME 'ha_example'; SET GLOBAL example_enum_var= e1; SET GLOBAL example_enum_var= e2; @@ -55,8 +60,7 @@ UNINSTALL PLUGIN example; # # Bug #32757 hang with sql_mode set when setting some global variables # ---replace_regex /\.dll/.so/ -eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO'; +eval INSTALL PLUGIN example SONAME 'ha_example'; select @@session.sql_mode into @old_sql_mode; diff --git a/mysql-test/t/plugin_maturity.test b/mysql-test/t/plugin_maturity.test index fe95f19b803..e1e4941492e 100644 --- a/mysql-test/t/plugin_maturity.test +++ b/mysql-test/t/plugin_maturity.test @@ -4,3 +4,9 @@ --replace_regex /\.dll/.so/ --error 1126 eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO'; + +--replace_regex /\.dll/.so/ +--error 1126 +eval INSTALL SONAME '$HA_EXAMPLE_SO'; +--replace_regex /\.dll/.so/ +show warnings; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index ce7c498133c..58e85c7a3a1 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -2594,13 +2594,10 @@ drop table t1; create procedure proc_1() install plugin my_plug soname 'some_plugin.so'; ---replace_regex /(Can\'t open shared library).*$/\1/ --error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED call proc_1(); ---replace_regex /(Can\'t open shared library).*$/\1/ --error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED call proc_1(); ---replace_regex /(Can\'t open shared library).*$/\1/ --error ER_CANT_OPEN_LIBRARY,ER_FEATURE_DISABLED call proc_1(); drop procedure proc_1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7dcd392b36a..b6c8751cd3a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4363,7 +4363,8 @@ create_sp_error: my_ok(thd); break; case SQLCOM_UNINSTALL_PLUGIN: - if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment))) + if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment, + &thd->lex->ident))) my_ok(thd); break; case SQLCOM_BINLOG_BASE64_EVENT: diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index fdd6b6e75bd..edeae8aa9c8 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -297,8 +297,7 @@ public: /* prototypes */ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv); -static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, - const char *list); +static bool plugin_load_list(MEM_ROOT *, int *, char **, const char *); static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *, int *, char **); static bool register_builtin(struct st_maria_plugin *, struct st_plugin_int *, @@ -318,6 +317,7 @@ static void reap_plugins(void); static void report_error(int where_to, uint error, ...) { va_list args; + DBUG_ASSERT(where_to & (REPORT_TO_USER | REPORT_TO_LOG)); if (where_to & REPORT_TO_USER) { va_start(args, error); @@ -351,6 +351,20 @@ bool check_valid_path(const char *path, size_t len) return prefix < len; } +static void fix_dl_name(MEM_ROOT *root, LEX_STRING *dl) +{ + const size_t so_ext_len= sizeof(SO_EXT) - 1; + if (my_strcasecmp(&my_charset_latin1, dl->str + dl->length - so_ext_len, + SO_EXT)) + { + char *s= (char*)alloc_root(root, dl->length + so_ext_len + 1); + memcpy(s, dl->str, dl->length); + strcpy(s + dl->length, SO_EXT); + dl->str= s; + dl->length+= so_ext_len; + } +} + /**************************************************************************** Value type thunks, allows the C world to play in the C++ world @@ -1017,31 +1031,40 @@ static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin) Requires that a write-lock is held on LOCK_system_variables_hash */ static bool plugin_add(MEM_ROOT *tmp_root, - const LEX_STRING *name, const LEX_STRING *dl, + const LEX_STRING *name, LEX_STRING *dl, int *argc, char **argv, int report) { struct st_plugin_int tmp; struct st_maria_plugin *plugin; + uint oks= 0, errs= 0; DBUG_ENTER("plugin_add"); - if (plugin_find_internal(name, MYSQL_ANY_PLUGIN)) + if (name->str && plugin_find_internal(name, MYSQL_ANY_PLUGIN)) { report_error(report, ER_UDF_EXISTS, name->str); DBUG_RETURN(TRUE); } /* 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, report))) DBUG_RETURN(TRUE); /* Find plugin by name */ for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++) { - uint name_len= strlen(plugin->name); - if (plugin->type >= 0 && plugin->type < MYSQL_MAX_PLUGIN_TYPE_NUM && - ! my_strnncoll(system_charset_info, - (const uchar *)name->str, name->length, - (const uchar *)plugin->name, - name_len)) - { + tmp.name.str= (char *)plugin->name; + tmp.name.length= strlen(plugin->name); + + if (plugin->type < 0 || plugin->type >= MYSQL_MAX_PLUGIN_TYPE_NUM) + continue; // invalid plugin + + if (name->str && my_strnncoll(system_charset_info, + (const uchar *)name->str, name->length, + (const uchar *)tmp.name.str, tmp.name.length)) + continue; // plugin name doesn't match + + if (!name->str && plugin_find_internal(&tmp.name, MYSQL_ANY_PLUGIN)) + continue; // already installed + struct st_plugin_int *tmp_plugin_ptr; if (*(int*)plugin->info < min_plugin_info_interface_version[plugin->type] || @@ -1051,7 +1074,8 @@ static bool plugin_add(MEM_ROOT *tmp_root, char buf[256]; strxnmov(buf, sizeof(buf) - 1, "API version for ", plugin_type_names[plugin->type].str, - " plugin is too different", NullS); + " plugin ", tmp.name.str, + " not supported by this version of the server", NullS); report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, 0, buf); goto err; } @@ -1060,40 +1084,49 @@ static bool plugin_add(MEM_ROOT *tmp_root, char buf[256]; strxnmov(buf, sizeof(buf) - 1, "Loading of ", plugin_maturity_names[plugin->maturity], - " plugins is prohibited by --plugin-maturity=", + " plugin ", tmp.name.str, + " is prohibited by --plugin-maturity=", plugin_maturity_names[plugin_maturity], 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; tmp.ref_count= 0; tmp.state= PLUGIN_IS_UNINITIALIZED; tmp.load_option= PLUGIN_ON; if (test_plugin_options(tmp_root, &tmp, argc, argv)) tmp.state= PLUGIN_IS_DISABLED; - if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp))) + if (!(tmp_plugin_ptr= plugin_insert_or_reuse(&tmp))) { - plugin_array_version++; - if (!my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr)) - { - init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096); - DBUG_RETURN(FALSE); - } - tmp_plugin_ptr->state= PLUGIN_IS_FREED; + mysql_del_sys_var_chain(tmp.system_vars); + restore_pluginvar_names(tmp.system_vars); + goto err; } - mysql_del_sys_var_chain(tmp.system_vars); - restore_pluginvar_names(tmp.system_vars); - goto err; - } - } - report_error(report, ER_CANT_FIND_DL_ENTRY, name->str); + plugin_array_version++; + 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); + + if (name->str) + DBUG_RETURN(FALSE); // all done + + oks++; + tmp.plugin_dl->ref_count++; + continue; // otherwise - go on + err: + errs++; + if (name->str) + break; + } + + if (errs == 0 && oks == 0) // no plugin was found + report_error(report, ER_CANT_FIND_DL_ENTRY, name->str); + plugin_dl_del(dl); - DBUG_RETURN(TRUE); + DBUG_RETURN(errs > 0 || oks == 0); } @@ -1760,8 +1793,6 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, { char buffer[FN_REFLEN]; LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name; - struct st_plugin_dl *plugin_dl; - struct st_maria_plugin *plugin; char *p= buffer; DBUG_ENTER("plugin_load_list"); while (list) @@ -1791,19 +1822,10 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, dl= name; mysql_mutex_lock(&LOCK_plugin); - if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG))) - { - for (plugin= plugin_dl->plugins; plugin->info; plugin++) - { - name.str= (char *) plugin->name; - name.length= strlen(name.str); - - free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE)); - if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG)) - goto error; - } - plugin_dl_del(&dl); // reduce ref count - } + free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE)); + name.str= 0; // load everything + if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG)) + goto error; } else { @@ -1970,14 +1992,68 @@ void plugin_shutdown(void) DBUG_VOID_RETURN; } +/** + complete plugin installation (after plugin_add). -bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl) + That is, initialize it, and update mysql.plugin table +*/ +static bool finalize_install(THD *thd, TABLE *table, const LEX_STRING *name) +{ + struct st_plugin_int *tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN); + int error; + DBUG_ASSERT(tmp); + mysql_mutex_assert_owner(&LOCK_plugin); + + if (tmp->state == PLUGIN_IS_DISABLED) + { + if (global_system_variables.log_warnings) + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_INITIALIZE_UDF, ER(ER_CANT_INITIALIZE_UDF), + name->str, "Plugin is disabled"); + } + else + { + DBUG_ASSERT(tmp->state == PLUGIN_IS_UNINITIALIZED); + if (plugin_initialize(tmp)) + { + report_error(REPORT_TO_USER, ER_CANT_INITIALIZE_UDF, name->str, + "Plugin initialization function failed."); + tmp->state= PLUGIN_IS_DELETED; + return 1; + } + } + + /* + We do not replicate the INSTALL PLUGIN statement. Disable binlogging + of the insert into the plugin table, so that it is not replicated in + row based mode. + */ + tmp_disable_binlog(thd); + table->use_all_columns(); + restore_record(table, s->default_values); + table->field[0]->store(name->str, name->length, system_charset_info); + table->field[1]->store(tmp->plugin_dl->dl.str, tmp->plugin_dl->dl.length, + files_charset_info); + error= table->file->ha_write_row(table->record[0]); + reenable_binlog(thd); + if (error) + { + table->file->print_error(error, MYF(0)); + tmp->state= PLUGIN_IS_DELETED; + return 1; + } + return 0; +} + +bool mysql_install_plugin(THD *thd, const LEX_STRING *name, + const LEX_STRING *dl_arg) { TABLE_LIST tables; TABLE *table; - int error, argc=orig_argc; + LEX_STRING dl= *dl_arg; + bool error; + int argc=orig_argc; char **argv=orig_argv; - struct st_plugin_int *tmp; DBUG_ENTER("mysql_install_plugin"); if (opt_noacl) @@ -2024,53 +2100,34 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl report_error(REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str); goto err; } - error= plugin_add(thd->mem_root, name, dl, &argc, argv, REPORT_TO_USER); + error= plugin_add(thd->mem_root, name, &dl, &argc, argv, REPORT_TO_USER); if (argv) free_defaults(argv); mysql_rwlock_unlock(&LOCK_system_variables_hash); - if (error || !(tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN))) + if (error) goto err; - if (tmp->state == PLUGIN_IS_DISABLED) - { - if (global_system_variables.log_warnings) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_CANT_INITIALIZE_UDF, ER(ER_CANT_INITIALIZE_UDF), - name->str, "Plugin is disabled"); - } + if (name->str) + error= finalize_install(thd, table, name); else { - if (plugin_initialize(tmp)) + st_plugin_dl *plugin_dl= plugin_dl_find(&dl); + struct st_maria_plugin *plugin; + for (plugin= plugin_dl->plugins; plugin->info; plugin++) { - my_error(ER_CANT_INITIALIZE_UDF, MYF(0), name->str, - "Plugin initialization function failed."); - goto deinit; + LEX_STRING str= { const_cast(plugin->name), strlen(plugin->name) }; + error|= finalize_install(thd, table, &str); } } - /* - We do not replicate the INSTALL PLUGIN statement. Disable binlogging - of the insert into the plugin table, so that it is not replicated in - row based mode. - */ - tmp_disable_binlog(thd); - table->use_all_columns(); - restore_record(table, s->default_values); - table->field[0]->store(name->str, name->length, system_charset_info); - table->field[1]->store(dl->str, dl->length, files_charset_info); - error= table->file->ha_write_row(table->record[0]); - reenable_binlog(thd); if (error) - { - table->file->print_error(error, MYF(0)); goto deinit; - } mysql_mutex_unlock(&LOCK_plugin); DBUG_RETURN(FALSE); + deinit: - tmp->state= PLUGIN_IS_DELETED; reap_needed= true; reap_plugins(); err: @@ -2079,11 +2136,70 @@ err: } -bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) +static bool do_uninstall(THD *thd, TABLE *table, const LEX_STRING *name) +{ + struct st_plugin_int *plugin; + mysql_mutex_assert_owner(&LOCK_plugin); + + if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN))) + { + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str); + return 1; + } + if (!plugin->plugin_dl) + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_PLUGIN_DELETE_BUILTIN, ER(WARN_PLUGIN_DELETE_BUILTIN)); + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str); + return 1; + } + if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT) + { + my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); + return 1; + } + + plugin->state= PLUGIN_IS_DELETED; + if (plugin->ref_count) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_PLUGIN_BUSY, ER(WARN_PLUGIN_BUSY)); + else + reap_needed= true; + + uchar user_key[MAX_KEY_LENGTH]; + table->use_all_columns(); + 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->ha_index_read_idx_map(table->record[0], 0, user_key, + HA_WHOLE_KEY, HA_READ_KEY_EXACT)) + { + int error; + /* + We do not replicate the UNINSTALL PLUGIN statement. Disable binlogging + of the delete from the plugin table, so that it is not replicated in + row based mode. + */ + tmp_disable_binlog(thd); + error= table->file->ha_delete_row(table->record[0]); + reenable_binlog(thd); + if (error) + { + table->file->print_error(error, MYF(0)); + return 1; + } + } + return 0; +} + + +bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name, + const LEX_STRING *dl_arg) { TABLE *table; TABLE_LIST tables; - struct st_plugin_int *plugin; + LEX_STRING dl= *dl_arg; + bool error= false; DBUG_ENTER("mysql_uninstall_plugin"); if (opt_noacl) @@ -2116,67 +2232,28 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) When audit event is triggered during [UN]INSTALL PLUGIN, plugin list iterator acquires the same lock (within the same thread) second time. - - This hack should be removed when LOCK_plugin is fixed so it - protects only what it supposed to protect. */ mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS); mysql_mutex_lock(&LOCK_plugin); - if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN))) - { - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str); - goto err; - } - if (!plugin->plugin_dl) - { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - WARN_PLUGIN_DELETE_BUILTIN, ER(WARN_PLUGIN_DELETE_BUILTIN)); - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str); - goto err; - } - if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT) - { - my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); - goto err; - } - plugin->state= PLUGIN_IS_DELETED; - if (plugin->ref_count) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - WARN_PLUGIN_BUSY, ER(WARN_PLUGIN_BUSY)); + if (name->str) + error= do_uninstall(thd, table, name); else - reap_needed= true; - reap_plugins(); - mysql_mutex_unlock(&LOCK_plugin); - - uchar user_key[MAX_KEY_LENGTH]; - table->use_all_columns(); - 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->ha_index_read_idx_map(table->record[0], 0, user_key, - HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { - int error; - /* - We do not replicate the UNINSTALL PLUGIN statement. Disable binlogging - of the delete from the plugin table, so that it is not replicated in - row based mode. - */ - tmp_disable_binlog(thd); - error= table->file->ha_delete_row(table->record[0]); - reenable_binlog(thd); - if (error) + fix_dl_name(thd->mem_root, &dl); + st_plugin_dl *plugin_dl= plugin_dl_find(&dl); + struct st_maria_plugin *plugin; + for (plugin= plugin_dl->plugins; plugin->info; plugin++) { - table->file->print_error(error, MYF(0)); - DBUG_RETURN(TRUE); + LEX_STRING str= { const_cast(plugin->name), strlen(plugin->name) }; + error|= do_uninstall(thd, table, &str); } } - DBUG_RETURN(FALSE); -err: + reap_plugins(); + mysql_mutex_unlock(&LOCK_plugin); - DBUG_RETURN(TRUE); + DBUG_RETURN(error); } diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index aee04de7be4..fc059142e24 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -159,7 +159,8 @@ extern void plugin_unlock(THD *thd, plugin_ref plugin); extern void plugin_unlock_list(THD *thd, plugin_ref *list, uint count); extern bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl); -extern bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name); +extern bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name, + const LEX_STRING *dl); extern bool plugin_register_builtin(struct st_mysql_plugin *plugin); extern void plugin_thdvar_init(THD *thd); extern void plugin_thdvar_cleanup(THD *thd); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ddb2a81cc2d..54e2f3012ff 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -15141,6 +15141,13 @@ install: lex->comment= $3; lex->ident= $5; } + | INSTALL_SYM SONAME_SYM TEXT_STRING_sys + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_INSTALL_PLUGIN; + lex->comment= null_lex_str; + lex->ident= $3; + } ; uninstall: @@ -15150,6 +15157,13 @@ uninstall: lex->sql_command= SQLCOM_UNINSTALL_PLUGIN; lex->comment= $3; } + | UNINSTALL_SYM SONAME_SYM TEXT_STRING_sys + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_UNINSTALL_PLUGIN; + lex->comment= null_lex_str; + lex->ident= $3; + } ; /* Avoid compiler warning from sql_yacc.cc where yyerrlab1 is not used */ diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index 5101d73d23c..dcbfb176c6a 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -19,17 +19,23 @@ @brief The ha_example engine is a stubbed storage engine for example purposes only; - it does nothing at this point. Its purpose is to provide a source + it does almost nothing at this point. Its purpose is to provide a source code illustration of how to begin writing new storage engines; see also - /storage/example/ha_example.h. + storage/example/ha_example.h. + + Additionally, this file includes an example of a daemon plugin which does + nothing at all - absolutely nothing, even less than example storage engine. + But it shows that one dll/so can contain more than one plugin. @details ha_example will let you create/open/delete tables, but nothing further (for example, indexes are not supported nor can data - be stored in the table). Use this example as a template for - implementing the same functionality in your own storage engine. You - can enable the example storage engine in your build by doing the - following during your build process:
./configure + be stored in the table). It also provides new status (example_func_example) + and system (example_ulong_var and example_enum_var) variables. + + Use this example as a template for implementing the same functionality in + your own storage engine. You can enable the example storage engine in your + build by doing the following during your build process:
./configure --with-example-storage-engine Once this is done, MySQL will let you create tables with:
@@ -1111,6 +1117,9 @@ static struct st_mysql_show_var func_status[]= {0,0,SHOW_UNDEF} }; +struct st_mysql_daemon unusable_example= +{ MYSQL_DAEMON_INTERFACE_VERSION }; + mysql_declare_plugin(example) { MYSQL_STORAGE_ENGINE_PLUGIN, @@ -1138,10 +1147,25 @@ maria_declare_plugin(example) PLUGIN_LICENSE_GPL, example_init_func, /* Plugin Init */ example_done_func, /* Plugin Deinit */ - 0x0001 /* 0.1 */, + 0x0001, /* version number (0.1) */ func_status, /* status variables */ example_system_variables, /* system variables */ "0.1", /* string version */ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */ +}, +{ + MYSQL_DAEMON_PLUGIN, + &unusable_example, + "UNUSABLE", + "Sergei Golubchik", + "Unusable Daemon", + PLUGIN_LICENSE_GPL, + NULL, /* Plugin Init */ + NULL, /* Plugin Deinit */ + 0x030E, /* version number (3.14) */ + NULL, /* status variables */ + NULL, /* system variables */ + "3.14.15.926" , /* version, as a string */ + MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */ } maria_declare_plugin_end;