summaryrefslogtreecommitdiff
path: root/sql/sql_plugin.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_plugin.cc')
-rw-r--r--sql/sql_plugin.cc622
1 files changed, 622 insertions, 0 deletions
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
new file mode 100644
index 00000000000..efe8f256af5
--- /dev/null
+++ b/sql/sql_plugin.cc
@@ -0,0 +1,622 @@
+/* Copyright (C) 2005 MySQL 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "mysql_priv.h"
+#include <my_pthread.h>
+#define REPORT_TO_LOG 1
+#define REPORT_TO_USER 2
+
+char *opt_plugin_dir_ptr;
+char opt_plugin_dir[FN_REFLEN];
+
+static const char *plugin_interface_version_sym=
+ "_mysql_plugin_interface_version_";
+static const char *plugin_declarations_sym= "_mysql_plugin_declarations_";
+static int min_plugin_interface_version= 0x0000;
+
+static DYNAMIC_ARRAY plugin_dl_array;
+static DYNAMIC_ARRAY plugin_array;
+static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
+static rw_lock_t THR_LOCK_plugin;
+static bool initialized= 0;
+
+
+static struct st_plugin_dl *plugin_dl_find(LEX_STRING *dl)
+{
+ uint i;
+ DBUG_ENTER("plugin_dl_find");
+ for (i= 0; i < plugin_dl_array.elements; i++)
+ {
+ struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i,
+ struct st_plugin_dl *);
+ if (tmp->ref_count &&
+ ! my_strnncoll(files_charset_info,
+ (const uchar *)dl->str, dl->length,
+ (const uchar *)tmp->dl.str, tmp->dl.length))
+ DBUG_RETURN(tmp);
+ }
+ DBUG_RETURN(0);
+}
+
+
+static st_plugin_dl *plugin_dl_add(LEX_STRING *dl, int report)
+{
+#ifdef HAVE_DLOPEN
+ char dlpath[FN_REFLEN];
+ uint plugin_dir_len, dummy_errors;
+ struct st_plugin_dl *tmp, plugin_dl;
+ void *sym;
+ DBUG_ENTER("plugin_dl_add");
+ plugin_dir_len= strlen(opt_plugin_dir);
+ /*
+ Ensure that the dll doesn't have a path.
+ This is done to ensure that only approved libraries from the
+ plugin directory are used (to make this even remotely secure).
+ */
+ if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, FN_LIBCHAR) ||
+ dl->length > NAME_LEN ||
+ plugin_dir_len + dl->length + 1 >= FN_REFLEN)
+ {
+ if (report & REPORT_TO_USER)
+ my_error(ER_UDF_NO_PATHS, MYF(0));
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_UDF_NO_PATHS));
+ DBUG_RETURN(0);
+ }
+ /* If this dll is already loaded just increase ref_count. */
+ if ((tmp= plugin_dl_find(dl)))
+ {
+ tmp->ref_count++;
+ DBUG_RETURN(tmp);
+ }
+ /* Compile dll path */
+ strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS);
+ plugin_dl.ref_count= 1;
+ /* Open new dll handle */
+ if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW)))
+ {
+ if (report & REPORT_TO_USER)
+ my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, errno, dlerror());
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, errno, dlerror());
+ DBUG_RETURN(0);
+ }
+ /* Determine interface version */
+ if (!(sym= dlsym(plugin_dl.handle, plugin_interface_version_sym)))
+ {
+ dlclose(plugin_dl.handle);
+ if (report & REPORT_TO_USER)
+ my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_interface_version_sym);
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_interface_version_sym);
+ 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))
+ {
+ dlclose(plugin_dl.handle);
+ if (report & REPORT_TO_USER)
+ my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, 0,
+ "plugin interface version mismatch");
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, 0,
+ "plugin interface version mismatch");
+ DBUG_RETURN(0);
+ }
+ /* Find plugin declarations */
+ if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))
+ {
+ dlclose(plugin_dl.handle);
+ if (report & REPORT_TO_USER)
+ my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_declarations_sym);
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_declarations_sym);
+ DBUG_RETURN(0);
+ }
+ plugin_dl.plugins= (struct st_mysql_plugin *)sym;
+ /* Duplicate and convert dll name */
+ plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
+ if (! (plugin_dl.dl.str= my_malloc(plugin_dl.dl.length, MYF(0))))
+ {
+ dlclose(plugin_dl.handle);
+ if (report & REPORT_TO_USER)
+ my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length);
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
+ DBUG_RETURN(0);
+ }
+ plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length,
+ files_charset_info, dl->str, dl->length, system_charset_info,
+ &dummy_errors);
+ plugin_dl.dl.str[plugin_dl.dl.length]= 0;
+ /* Add this dll to array */
+ if (insert_dynamic(&plugin_dl_array, (gptr)&plugin_dl))
+ {
+ dlclose(plugin_dl.handle);
+ my_free(plugin_dl.dl.str, MYF(0));
+ if (report & REPORT_TO_USER)
+ my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_dl));
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_dl));
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
+ struct st_plugin_dl *));
+#else
+ DBUG_ENTER("plugin_dl_add");
+ if (report & REPORT_TO_USER)
+ my_error(ER_FEATURE_DISABLED, MYF(0), "plugin", "HAVE_DLOPEN");
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_FEATURE_DISABLED), "plugin", "HAVE_DLOPEN");
+ DBUG_RETURN(0);
+#endif
+}
+
+
+static void plugin_dl_del(LEX_STRING *dl)
+{
+#ifdef HAVE_DLOPEN
+ uint i;
+ DBUG_ENTER("plugin_dl_del");
+ for (i= 0; i < plugin_dl_array.elements; i++)
+ {
+ struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i,
+ struct st_plugin_dl *);
+ if (tmp->ref_count &&
+ ! my_strnncoll(files_charset_info,
+ (const uchar *)dl->str, dl->length,
+ (const uchar *)tmp->dl.str, tmp->dl.length))
+ {
+ /* Do not remove this element, unless no other plugin uses this dll. */
+ if (! --tmp->ref_count)
+ {
+ dlclose(tmp->handle);
+ my_free(tmp->dl.str, MYF(0));
+ bzero(tmp, sizeof(struct st_plugin_dl));
+ }
+ break;
+ }
+ }
+ DBUG_VOID_RETURN;
+#endif
+}
+
+
+static struct st_plugin_int *plugin_find_internal(LEX_STRING *name, int type)
+{
+ uint i;
+ DBUG_ENTER("plugin_find_internal");
+ if (! initialized)
+ DBUG_RETURN(0);
+ if (type == MYSQL_ANY_PLUGIN)
+ {
+ for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
+ {
+ struct st_plugin_int *plugin= (st_plugin_int *)
+ hash_search(&plugin_hash[i], name->str, name->length);
+ if (plugin)
+ DBUG_RETURN(plugin);
+ }
+ }
+ else
+ DBUG_RETURN((st_plugin_int *)
+ hash_search(&plugin_hash[type], name->str, name->length));
+ DBUG_RETURN(0);
+}
+
+
+my_bool plugin_is_ready(LEX_STRING *name, int type)
+{
+ my_bool rc= FALSE;
+ struct st_plugin_int *plugin;
+ DBUG_ENTER("plugin_is_ready");
+ rw_rdlock(&THR_LOCK_plugin);
+ if ((plugin= plugin_find_internal(name, type)) &&
+ plugin->state == PLUGIN_IS_READY)
+ rc= TRUE;
+ rw_unlock(&THR_LOCK_plugin);
+ DBUG_RETURN(rc);
+}
+
+
+struct st_plugin_int *plugin_lock(LEX_STRING *name, int type)
+{
+ struct st_plugin_int *rc;
+ DBUG_ENTER("plugin_find");
+ rw_wrlock(&THR_LOCK_plugin);
+ if ((rc= plugin_find_internal(name, type)))
+ {
+ if (rc->state == PLUGIN_IS_READY)
+ rc->ref_count++;
+ else
+ rc= 0;
+ }
+ rw_unlock(&THR_LOCK_plugin);
+ DBUG_RETURN(rc);
+}
+
+
+static my_bool plugin_add(LEX_STRING *name, LEX_STRING *dl, int report)
+{
+ struct st_plugin_int tmp;
+ struct st_mysql_plugin *plugin;
+ DBUG_ENTER("plugin_add");
+ if (plugin_find_internal(name, MYSQL_ANY_PLUGIN))
+ {
+ if (report & REPORT_TO_USER)
+ my_error(ER_UDF_EXISTS, MYF(0), name->str);
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_UDF_EXISTS), name->str);
+ DBUG_RETURN(TRUE);
+ }
+ 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.plugin= plugin;
+ tmp.name.str= (char *)plugin->name;
+ tmp.name.length= name_len;
+ tmp.ref_count= 0;
+ tmp.state= PLUGIN_IS_UNINITIALIZED;
+ if (insert_dynamic(&plugin_array, (gptr)&tmp))
+ {
+ if (report & REPORT_TO_USER)
+ my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_int));
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_int));
+ goto err;
+ }
+ if (my_hash_insert(&plugin_hash[plugin->type],
+ (byte*)dynamic_element(&plugin_array,
+ plugin_array.elements - 1,
+ struct st_plugin_int *)))
+ {
+ struct st_plugin_int *tmp_plugin= dynamic_element(&plugin_array,
+ plugin_array.elements - 1, struct st_plugin_int *);
+ tmp_plugin->state= PLUGIN_IS_FREED;
+ if (report & REPORT_TO_USER)
+ my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_int));
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_int));
+ goto err;
+ }
+ DBUG_RETURN(FALSE);
+ }
+ }
+ if (report & REPORT_TO_USER)
+ my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), name->str);
+ if (report & REPORT_TO_LOG)
+ sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name->str);
+err:
+ plugin_dl_del(dl);
+ DBUG_RETURN(TRUE);
+}
+
+
+static void plugin_del(LEX_STRING *name)
+{
+ uint i;
+ struct st_plugin_int *plugin;
+ DBUG_ENTER("plugin_del");
+ if ((plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
+ {
+ hash_delete(&plugin_hash[plugin->plugin->type], (byte*)plugin);
+ plugin_dl_del(&plugin->plugin_dl->dl);
+ plugin->state= PLUGIN_IS_FREED;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void plugin_unlock(struct st_plugin_int *plugin)
+{
+ DBUG_ENTER("plugin_release");
+ rw_wrlock(&THR_LOCK_plugin);
+ DBUG_ASSERT(plugin && plugin->ref_count);
+ plugin->ref_count--;
+ if (plugin->state == PLUGIN_IS_DELETED && ! plugin->ref_count)
+ {
+ if (plugin->plugin->deinit)
+ plugin->plugin->deinit();
+ plugin_del(&plugin->name);
+ }
+ rw_unlock(&THR_LOCK_plugin);
+ DBUG_VOID_RETURN;
+}
+
+
+static void plugin_call_initializer(void)
+{
+ uint i;
+ DBUG_ENTER("plugin_call_initializer");
+ for (i= 0; i < plugin_array.elements; i++)
+ {
+ struct st_plugin_int *tmp= dynamic_element(&plugin_array, i,
+ struct st_plugin_int *);
+ if (tmp->state == PLUGIN_IS_UNINITIALIZED && tmp->plugin->init)
+ {
+ DBUG_PRINT("info", ("Initializing plugin: '%s'", tmp->name.str));
+ if (tmp->plugin->init())
+ {
+ sql_print_error("Plugin '%s' init function returned error.",
+ tmp->name.str);
+ DBUG_PRINT("warning", ("Plugin '%s' init function returned error.",
+ tmp->name.str))
+ plugin_del(&tmp->name);
+ }
+ }
+ if (tmp->state == PLUGIN_IS_UNINITIALIZED)
+ tmp->state= PLUGIN_IS_READY;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+static void plugin_call_deinitializer(void)
+{
+ uint i;
+ DBUG_ENTER("plugin_call_deinitializer");
+ for (i= 0; i < plugin_array.elements; i++)
+ {
+ struct st_plugin_int *tmp= dynamic_element(&plugin_array, i,
+ struct st_plugin_int *);
+ if (tmp->state == PLUGIN_IS_READY)
+ {
+ if (tmp->plugin->deinit)
+ {
+ DBUG_PRINT("info", ("Deinitializing plugin: '%s'", tmp->name.str));
+ if (tmp->plugin->deinit())
+ {
+ DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
+ tmp->name.str))
+ }
+ }
+ tmp->state= PLUGIN_IS_UNINITIALIZED;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+static byte *get_hash_key(const byte *buff, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ struct st_plugin_int *plugin= (st_plugin_int *)buff;
+ *length= (uint)plugin->name.length;
+ return((byte *)plugin->name.str);
+}
+
+
+void plugin_init(void)
+{
+ TABLE_LIST tables;
+ TABLE *table;
+ READ_RECORD read_record_info;
+ int error, i;
+ MEM_ROOT mem;
+ DBUG_ENTER("plugin_init");
+ if (initialized)
+ DBUG_VOID_RETURN;
+ my_rwlock_init(&THR_LOCK_plugin, NULL);
+ THD *new_thd = new THD;
+ if (!new_thd ||
+ my_init_dynamic_array(&plugin_dl_array,sizeof(struct st_plugin_dl),16,16) ||
+ my_init_dynamic_array(&plugin_array,sizeof(struct st_plugin_int),16,16))
+ {
+ sql_print_error("Can't allocate memory for plugin structures");
+ delete new_thd;
+ delete_dynamic(&plugin_dl_array);
+ delete_dynamic(&plugin_array);
+ DBUG_VOID_RETURN;
+ }
+ for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
+ {
+ if (hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
+ get_hash_key, NULL, 0))
+ {
+ sql_print_error("Can't allocate memory for plugin structures");
+ delete new_thd;
+ delete_dynamic(&plugin_dl_array);
+ delete_dynamic(&plugin_array);
+ DBUG_VOID_RETURN;
+ }
+ }
+ init_sql_alloc(&mem, 1024, 0);
+ initialized= 1;
+ new_thd->store_globals();
+ new_thd->db= my_strdup("mysql", MYF(0));
+ new_thd->db_length= 5;
+ bzero((gptr)&tables, sizeof(tables));
+ tables.alias= tables.table_name= (char*)"plugin";
+ tables.lock_type= TL_READ;
+ tables.db= new_thd->db;
+ if (simple_open_n_lock_tables(new_thd, &tables))
+ {
+ DBUG_PRINT("error",("Can't open plugin table"));
+ sql_print_error("Can't open the mysql.plugin table. Please run the mysql_install_db script to create it.");
+ delete_dynamic(&plugin_dl_array);
+ delete_dynamic(&plugin_array);
+ for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
+ hash_free(&plugin_hash[i]);
+ goto end;
+ }
+ table= tables.table;
+ init_read_record(&read_record_info, new_thd, table, NULL, 1, 0);
+ while (!(error= read_record_info.read_record(&read_record_info)))
+ {
+ DBUG_PRINT("info", ("init plugin record"));
+ LEX_STRING name, dl;
+ name.str= get_field(&mem, table->field[0]);
+ name.length= strlen(name.str);
+ dl.str= get_field(&mem, table->field[1]);
+ dl.length= strlen(dl.str);
+ if (plugin_add(&name, &dl, REPORT_TO_LOG))
+ DBUG_PRINT("warning", ("Couldn't load plugin named '%s' with soname '%s'.",
+ name.str, dl.str));
+ }
+ plugin_call_initializer();
+ if (error > 0)
+ sql_print_error(ER(ER_GET_ERRNO), my_errno);
+ end_read_record(&read_record_info);
+ new_thd->version--; // Force close to free memory
+end:
+ free_root(&mem, MYF(0));
+ close_thread_tables(new_thd);
+ delete new_thd;
+ /* Remember that we don't have a THD */
+ my_pthread_setspecific_ptr(THR_THD, 0);
+ DBUG_VOID_RETURN;
+}
+
+
+void plugin_free(void)
+{
+ uint i;
+ DBUG_ENTER("plugin_free");
+ plugin_call_deinitializer();
+ for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
+ hash_free(&plugin_hash[i]);
+ delete_dynamic(&plugin_array);
+ for (i= 0; i < plugin_dl_array.elements; i++)
+ {
+ struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i,
+ struct st_plugin_dl *);
+#ifdef HAVE_DLOPEN
+ if (tmp->handle)
+ {
+ dlclose(tmp->handle);
+ my_free(tmp->dl.str, MYF(0));
+ }
+#endif
+ }
+ delete_dynamic(&plugin_dl_array);
+ if (initialized)
+ {
+ initialized= 0;
+ rwlock_destroy(&THR_LOCK_plugin);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+my_bool mysql_install_plugin(THD *thd, LEX_STRING *name, LEX_STRING *dl)
+{
+ TABLE_LIST tables;
+ TABLE *table;
+ int error;
+ struct st_plugin_int *tmp;
+ DBUG_ENTER("mysql_install_plugin");
+ bzero(&tables, sizeof(tables));
+ tables.db= (char *)"mysql";
+ tables.table_name= tables.alias= (char *)"plugin";
+ if (check_table_access(thd, INSERT_ACL, &tables, 0))
+ DBUG_RETURN(TRUE);
+ rw_wrlock(&THR_LOCK_plugin);
+ if (plugin_add(name, dl, REPORT_TO_USER))
+ goto err;
+ tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN);
+ if (tmp->plugin->init)
+ {
+ if (tmp->plugin->init())
+ {
+ my_error(ER_CANT_INITIALIZE_UDF, MYF(0), name->str,
+ "Plugin initialization function failed.");
+ goto err;
+ }
+ tmp->state= PLUGIN_IS_READY;
+ }
+ if (! (table = open_ltable(thd, &tables, TL_WRITE)))
+ goto deinit;
+ 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->write_row(table->record[0]);
+ if (error)
+ {
+ table->file->print_error(error, MYF(0));
+ goto deinit;
+ }
+ rw_unlock(&THR_LOCK_plugin);
+ DBUG_RETURN(FALSE);
+deinit:
+ if (tmp->plugin->deinit)
+ tmp->plugin->deinit();
+err:
+ plugin_del(name);
+ rw_unlock(&THR_LOCK_plugin);
+ DBUG_RETURN(TRUE);
+}
+
+
+my_bool mysql_uninstall_plugin(THD *thd, LEX_STRING *name)
+{
+ TABLE *table;
+ TABLE_LIST tables;
+ struct st_plugin_int *plugin;
+ DBUG_ENTER("mysql_uninstall_plugin");
+ rw_wrlock(&THR_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->ref_count)
+ {
+ plugin->state= PLUGIN_IS_DELETED;
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
+ "Plugin is not deleted, waiting on tables.");
+ }
+ else
+ {
+ if (plugin->plugin->deinit)
+ plugin->plugin->deinit();
+ plugin_del(name);
+ }
+ bzero(&tables, sizeof(tables));
+ tables.db= (char *)"mysql";
+ tables.table_name= tables.alias= (char *)"plugin";
+ if (! (table= open_ltable(thd, &tables, TL_WRITE)))
+ goto err;
+ table->field[0]->store(name->str, name->length, system_charset_info);
+ table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
+ if (! table->file->index_read_idx(table->record[0], 0,
+ (byte *)table->field[0]->ptr,
+ table->key_info[0].key_length,
+ HA_READ_KEY_EXACT))
+ {
+ int error;
+ if ((error= table->file->delete_row(table->record[0])))
+ {
+ table->file->print_error(error, MYF(0));
+ goto err;
+ }
+ }
+ rw_unlock(&THR_LOCK_plugin);
+ DBUG_RETURN(FALSE);
+err:
+ rw_unlock(&THR_LOCK_plugin);
+ DBUG_RETURN(TRUE);
+}