diff options
author | Sergei Golubchik <sergii@pisem.net> | 2012-03-05 21:48:06 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2012-03-05 21:48:06 +0100 |
commit | 1c530b36d1c3a84c8022230e478da62021e6faa9 (patch) | |
tree | ea3862310bb5ee3ec8f813a4bed640db70a0ee4b /sql | |
parent | 98141ea42b5c7e1f0426372be01c9ee6fbf9046f (diff) | |
download | mariadb-git-1c530b36d1c3a84c8022230e478da62021e6faa9.tar.gz |
mdev-20: INSTALL PLUGIN SONAME
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sql_parse.cc | 3 | ||||
-rw-r--r-- | sql/sql_plugin.cc | 331 | ||||
-rw-r--r-- | sql/sql_plugin.h | 3 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 14 |
4 files changed, 222 insertions, 129 deletions
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). + + 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) +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<char*>(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,66 +2136,27 @@ err: } -bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) +static bool do_uninstall(THD *thd, TABLE *table, const LEX_STRING *name) { - TABLE *table; - TABLE_LIST tables; struct st_plugin_int *plugin; - DBUG_ENTER("mysql_uninstall_plugin"); - - if (opt_noacl) - { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); - DBUG_RETURN(TRUE); - } - - tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE); - - if (check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE)) - DBUG_RETURN(TRUE); - - /* need to open before acquiring LOCK_plugin or it will deadlock */ - if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) - DBUG_RETURN(TRUE); - - /* - Pre-acquire audit plugins for events that may potentially occur - during [UN]INSTALL PLUGIN. - - When audit event is triggered, audit subsystem acquires interested - plugins by walking through plugin list. Evidently plugin list - iterator protects plugin list by acquiring LOCK_plugin, see - plugin_foreach_with_mask(). - - On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin - rather for a long time. - - 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_assert_owner(&LOCK_plugin); - 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; + 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); - goto err; + return 1; } if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT) { my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); - goto err; + return 1; } plugin->state= PLUGIN_IS_DELETED; @@ -2147,8 +2165,6 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) WARN_PLUGIN_BUSY, ER(WARN_PLUGIN_BUSY)); else reap_needed= true; - reap_plugins(); - mysql_mutex_unlock(&LOCK_plugin); uchar user_key[MAX_KEY_LENGTH]; table->use_all_columns(); @@ -2170,13 +2186,74 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) if (error) { table->file->print_error(error, MYF(0)); - DBUG_RETURN(TRUE); + return 1; } } - DBUG_RETURN(FALSE); -err: + return 0; +} + + +bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name, + const LEX_STRING *dl_arg) +{ + TABLE *table; + TABLE_LIST tables; + LEX_STRING dl= *dl_arg; + bool error= false; + DBUG_ENTER("mysql_uninstall_plugin"); + + if (opt_noacl) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); + DBUG_RETURN(TRUE); + } + + tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE); + + if (check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE)) + DBUG_RETURN(TRUE); + + /* need to open before acquiring LOCK_plugin or it will deadlock */ + if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) + DBUG_RETURN(TRUE); + + /* + Pre-acquire audit plugins for events that may potentially occur + during [UN]INSTALL PLUGIN. + + When audit event is triggered, audit subsystem acquires interested + plugins by walking through plugin list. Evidently plugin list + iterator protects plugin list by acquiring LOCK_plugin, see + plugin_foreach_with_mask(). + + On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin + rather for a long time. + + When audit event is triggered during [UN]INSTALL PLUGIN, plugin + list iterator acquires the same lock (within the same thread) + second time. + */ + mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS); + + mysql_mutex_lock(&LOCK_plugin); + + if (name->str) + error= do_uninstall(thd, table, name); + else + { + 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++) + { + LEX_STRING str= { const_cast<char*>(plugin->name), strlen(plugin->name) }; + error|= do_uninstall(thd, table, &str); + } + } + 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 */ |