mirror of
https://github.com/MariaDB/server.git
synced 2025-01-22 14:54:20 +01:00
09346e6e2d
This includes both code and test cases. BitKeeper/deleted/.del-ctype_ucs_binlog.result~280d136b1a0bcf17: Delete: mysql-test/r/ctype_ucs_binlog.result BitKeeper/deleted/.del-rpl_delete_all.result~7c050d592614b3f: Delete: mysql-test/r/rpl_delete_all.result BitKeeper/deleted/.del-rpl000013-slave.opt~18266ad8a2403e8d: Delete: mysql-test/t/rpl000013-slave.opt BitKeeper/deleted/.del-rpl_delete_all.test~700a1490277780e0: Delete: mysql-test/t/rpl_delete_all.test mysql-test/extra/binlog_tests/binlog.test: Import patch wl1012.patch mysql-test/extra/binlog_tests/blackhole.test: Import patch wl1012.patch mysql-test/extra/binlog_tests/ctype_cp932.test: Import patch wl1012.patch mysql-test/extra/binlog_tests/ctype_cp932_binlog.test: Import patch wl1012.patch mysql-test/extra/binlog_tests/ctype_ucs_binlog.test: Import patch wl1012.patch mysql-test/extra/binlog_tests/drop_temp_table.test: Import patch wl1012.patch mysql-test/extra/binlog_tests/insert_select-binlog.test: Import patch wl1012.patch mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_ddl.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_deadlock.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_err_ignoredtable.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_flsh_tbls.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_loaddata_m.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_log.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_max_relay_size.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_multi_query.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_reset_slave.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_stm_000001.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_stm_EE_err.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_stm_charset.test: Import patch wl1012.patch mysql-test/extra/rpl_tests/rpl_user_variables.test: Import patch wl1012.patch mysql-test/r/binlog_stm_binlog.result: Import patch wl1012.patch mysql-test/r/binlog_stm_blackhole.result: Import patch wl1012.patch mysql-test/r/binlog_stm_ctype_cp932.result: Import patch wl1012.patch mysql-test/r/binlog_stm_ctype_ucs.result: Import patch wl1012.patch mysql-test/r/binlog_stm_drop_tmp_tbl.result: Import patch wl1012.patch mysql-test/r/binlog_stm_insert_select.result: Import patch wl1012.patch mysql-test/r/binlog_stm_mix_innodb_myisam.result: Import patch wl1012.patch mysql-test/r/rpl_000012.result: Import patch wl1012.patch mysql-test/r/rpl_000015.result: Import patch wl1012.patch mysql-test/r/rpl_deadlock_innodb.result: Import patch wl1012.patch mysql-test/r/rpl_flushlog_loop.result: Import patch wl1012.patch mysql-test/r/rpl_loaddata_s.result: Import patch wl1012.patch mysql-test/r/rpl_stm_000001.result: Import patch wl1012.patch mysql-test/r/rpl_stm_EE_err.result: Import patch wl1012.patch mysql-test/r/rpl_stm_charset.result: Import patch wl1012.patch mysql-test/r/rpl_stm_ddl.result: Import patch wl1012.patch mysql-test/r/rpl_stm_err_ignoredtable.result: Import patch wl1012.patch mysql-test/r/rpl_stm_flsh_tbls.result: Import patch wl1012.patch mysql-test/r/rpl_stm_loaddata_m.result: Import patch wl1012.patch mysql-test/r/rpl_stm_log.result: Import patch wl1012.patch mysql-test/r/rpl_stm_max_relay_size.result: Import patch wl1012.patch mysql-test/r/rpl_stm_multi_query.result: Import patch wl1012.patch mysql-test/r/rpl_stm_mystery22.result: Import patch wl1012.patch mysql-test/r/rpl_stm_reset_slave.result: Import patch wl1012.patch mysql-test/r/rpl_stm_rewrt_db.result: Import patch wl1012.patch mysql-test/r/rpl_stm_sp.result: Import patch wl1012.patch mysql-test/r/rpl_stm_timezone.result: Import patch wl1012.patch mysql-test/r/rpl_stm_until.result: Import patch wl1012.patch mysql-test/r/rpl_stm_user_variables.result: Import patch wl1012.patch mysql-test/r/rpl_stm_view.result: Import patch wl1012.patch mysql-test/t/binlog_row_binlog-master.opt: Import patch wl1012.patch mysql-test/t/rpl_000012.test: Import patch wl1012.patch mysql-test/t/rpl_000015-slave.sh: Import patch wl1012.patch mysql-test/t/rpl_000015.slave-mi: Import patch wl1012.patch mysql-test/t/rpl_000015.test: Import patch wl1012.patch mysql-test/t/rpl_deadlock_innodb-slave.opt: Import patch wl1012.patch mysql-test/t/rpl_flushlog_loop-master.opt: Import patch wl1012.patch mysql-test/t/rpl_flushlog_loop-master.sh: Import patch wl1012.patch mysql-test/t/rpl_flushlog_loop-slave.opt: Import patch wl1012.patch mysql-test/t/rpl_flushlog_loop-slave.sh: Import patch wl1012.patch mysql-test/t/rpl_flushlog_loop.test: Import patch wl1012.patch mysql-test/t/rpl_loaddata_s-slave.opt: Import patch wl1012.patch mysql-test/t/rpl_loaddata_s.test: Import patch wl1012.patch mysql-test/t/rpl_stm_000001-slave.opt: Import patch wl1012.patch mysql-test/t/rpl_stm_err_ignoredtable-slave.opt: Import patch wl1012.patch mysql-test/t/rpl_stm_loaddata_m-master.opt: Import patch wl1012.patch mysql-test/t/rpl_stm_log-master.opt: Import patch wl1012.patch mysql-test/t/rpl_stm_log-slave.opt: Import patch wl1012.patch mysql-test/t/rpl_stm_mystery22.test: Import patch wl1012.patch mysql-test/t/rpl_stm_rewrt_db-slave.opt: Import patch wl1012.patch mysql-test/t/rpl_stm_rewrt_db.test: Import patch wl1012.patch mysql-test/t/rpl_stm_sp-master.opt: Import patch wl1012.patch mysql-test/t/rpl_stm_sp-slave.opt: Import patch wl1012.patch mysql-test/t/rpl_stm_sp.test: Import patch wl1012.patch mysql-test/t/rpl_stm_timezone-master.opt: Import patch wl1012.patch mysql-test/t/rpl_stm_timezone-slave.opt: Import patch wl1012.patch BUILD/SETUP.sh: Import patch wl1012.patch Makefile.am: Import patch wl1012.patch mysql-test/t/rpl_stm_timezone.test: Import patch wl1012.patch mysql-test/t/rpl_stm_until.test: Import patch wl1012.patch mysql-test/t/rpl_stm_view.test: Import patch wl1012.patch client/Makefile.am: Import patch wl1012.patch client/client_priv.h: Import patch wl1012.patch client/mysqlbinlog.cc: Import patch wl1012.patch configure.in: Import patch wl1012.patch include/Makefile.am: Import patch wl1012.patch include/base64.h: Import patch wl1012.patch include/config-win.h: Import patch wl1012.patch include/my_base.h: Import patch wl1012.patch include/my_global.h: Import patch wl1012.patch mysql-test/Makefile.am: Import patch wl1012.patch mysql-test/mysql-test-run.pl: Import patch wl1012.patch mysql-test/mysql-test-run.sh: Import patch wl1012.patch mysql-test/r/date_formats.result: Import patch wl1012.patch mysql-test/r/flush_block_commit.result: Import patch wl1012.patch mysql-test/r/innodb.result: Import patch wl1012.patch mysql-test/r/rpl000017.result: Import patch wl1012.patch mysql-test/r/rpl_change_master.result: Import patch wl1012.patch mysql-test/r/rpl_commit_after_flush.result: Import patch wl1012.patch mysql-test/r/rpl_create_database.result: Import patch wl1012.patch mysql-test/r/rpl_do_grant.result: Import patch wl1012.patch mysql-test/r/rpl_loaddata.result: Import patch wl1012.patch mysql-test/r/rpl_log_pos.result: Import patch wl1012.patch mysql-test/r/rpl_multi_delete.result: Import patch wl1012.patch mysql-test/r/rpl_multi_update.result: Import patch wl1012.patch mysql-test/r/rpl_openssl.result: Import patch wl1012.patch mysql-test/r/rpl_replicate_do.result: Import patch wl1012.patch mysql-test/r/rpl_rotate_logs.result: Import patch wl1012.patch mysql-test/r/rpl_server_id1.result: Import patch wl1012.patch mysql-test/r/rpl_server_id2.result: Import patch wl1012.patch mysql-test/r/rpl_temporary.result: Import patch wl1012.patch mysql-test/r/user_var-binlog.result: Import patch wl1012.patch mysql-test/t/create_select_tmp.test: Import patch wl1012.patch mysql-test/t/date_formats.test: Import patch wl1012.patch mysql-test/t/disabled.def: Import patch wl1012.patch mysql-test/t/innodb.test: Import patch wl1012.patch mysql-test/t/mysqlbinlog.test: Import patch wl1012.patch mysql-test/t/mysqlbinlog2.test: Import patch wl1012.patch mysql-test/t/rpl000002.test: Import patch wl1012.patch mysql-test/t/rpl000006.test: Import patch wl1012.patch mysql-test/t/rpl000013.test: Import patch wl1012.patch mysql-test/t/rpl000017.test: Import patch wl1012.patch mysql-test/t/rpl_auto_increment.test: Import patch wl1012.patch mysql-test/t/rpl_change_master.test: Import patch wl1012.patch mysql-test/t/rpl_commit_after_flush.test: Import patch wl1012.patch mysql-test/t/rpl_create_database.test: Import patch wl1012.patch mysql-test/t/rpl_do_grant.test: Import patch wl1012.patch mysql-test/t/rpl_drop.test: Import patch wl1012.patch mysql-test/t/rpl_empty_master_crash.test: Import patch wl1012.patch mysql-test/t/rpl_failed_optimize.test: Import patch wl1012.patch mysql-test/t/rpl_heap.test: Import patch wl1012.patch mysql-test/t/rpl_insert_id.test: Import patch wl1012.patch mysql-test/t/rpl_insert_ignore.test: Import patch wl1012.patch mysql-test/t/rpl_loaddata.test: Import patch wl1012.patch mysql-test/t/rpl_log_pos.test: Import patch wl1012.patch mysql-test/t/rpl_multi_delete.test: Import patch wl1012.patch mysql-test/t/rpl_multi_update.test: Import patch wl1012.patch mysql-test/t/rpl_multi_update2.test: Import patch wl1012.patch mysql-test/t/rpl_multi_update3.test: Import patch wl1012.patch mysql-test/t/rpl_openssl.test: Import patch wl1012.patch mysql-test/t/rpl_redirect.test: Import patch wl1012.patch mysql-test/t/rpl_relayrotate.test: Import patch wl1012.patch mysql-test/t/rpl_replicate_do.test: Import patch wl1012.patch mysql-test/t/rpl_rotate_logs.test: Import patch wl1012.patch mysql-test/t/rpl_server_id1.test: Import patch wl1012.patch mysql-test/t/rpl_sp_effects.test: Import patch wl1012.patch mysql-test/t/rpl_temporary.test: Import patch wl1012.patch mysql-test/t/rpl_trigger.test: Import patch wl1012.patch mysql-test/t/sp.test: Import patch wl1012.patch mysql-test/t/user_var-binlog.test: Import patch wl1012.patch mysys/Makefile.am: Import patch wl1012.patch mysys/base64.c: Import patch wl1012.patch sql/Makefile.am: Import patch wl1012.patch sql/ha_innodb.cc: Import patch wl1012.patch sql/ha_innodb.h: Import patch wl1012.patch sql/ha_partition.cc: Import patch wl1012.patch sql/handler.cc: Import patch wl1012.patch sql/handler.h: Import patch wl1012.patch sql/item_sum.cc: Import patch wl1012.patch sql/log.cc: Import patch wl1012.patch sql/log_event.cc: Import patch wl1012.patch sql/log_event.h: Import patch wl1012.patch sql/mysql_priv.h: Import patch wl1012.patch sql/mysqld.cc: Import patch wl1012.patch sql/rpl_filter.h: Import patch wl1012.patch sql/set_var.cc: Import patch wl1012.patch sql/share/errmsg.txt: Import patch wl1012.patch sql/slave.cc: Import patch wl1012.patch sql/slave.h: Import patch wl1012.patch sql/sp.cc: Import patch wl1012.patch sql/sp_head.cc: Import patch wl1012.patch sql/sql_acl.cc: Import patch wl1012.patch sql/sql_base.cc: Import patch wl1012.patch sql/sql_class.cc: Import patch wl1012.patch sql/sql_class.h: Import patch wl1012.patch sql/sql_delete.cc: Import patch wl1012.patch sql/sql_insert.cc: Import patch wl1012.patch sql/sql_lex.h: Import patch wl1012.patch sql/sql_list.h: Import patch wl1012.patch sql/sql_load.cc: Import patch wl1012.patch sql/sql_parse.cc: Import patch wl1012.patch sql/sql_plugin.cc: Import patch wl1012.patch sql/sql_rename.cc: Import patch wl1012.patch sql/sql_repl.h: Import patch wl1012.patch sql/sql_select.cc: Import patch wl1012.patch sql/sql_show.cc: Import patch wl1012.patch sql/sql_table.cc: Import patch wl1012.patch sql/sql_udf.cc: Import patch wl1012.patch sql/sql_union.cc: Import patch wl1012.patch sql/sql_update.cc: Import patch wl1012.patch sql/sql_yacc.yy: Import patch wl1012.patch sql/table.cc: Import patch wl1012.patch sql/table.h: Import patch wl1012.patch storage/innobase/include/lock0lock.h: Import patch wl1012.patch storage/innobase/include/row0mysql.h: Import patch wl1012.patch storage/innobase/include/row0vers.h: Import patch wl1012.patch storage/innobase/lock/lock0lock.c: Import patch wl1012.patch storage/innobase/row/row0mysql.c: Import patch wl1012.patch storage/innobase/row/row0sel.c: Import patch wl1012.patch storage/innobase/row/row0vers.c: Import patch wl1012.patch
749 lines
21 KiB
C++
749 lines
21 KiB
C++
/* 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], (const byte *)name->str, name->length);
|
|
if (plugin)
|
|
DBUG_RETURN(plugin);
|
|
}
|
|
}
|
|
else
|
|
DBUG_RETURN((st_plugin_int *)
|
|
hash_search(&plugin_hash[type], (const byte *)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 int plugin_initialize(struct st_plugin_int *plugin)
|
|
{
|
|
DBUG_ENTER("plugin_initialize");
|
|
|
|
if (plugin->plugin->init)
|
|
{
|
|
if (plugin->plugin->init())
|
|
{
|
|
sql_print_error("Plugin '%s' init function returned error.",
|
|
plugin->name.str);
|
|
DBUG_PRINT("warning", ("Plugin '%s' init function returned error.",
|
|
plugin->name.str))
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
switch (plugin->plugin->type)
|
|
{
|
|
case MYSQL_STORAGE_ENGINE_PLUGIN:
|
|
if (ha_initialize_handlerton((handlerton*) plugin->plugin->info))
|
|
{
|
|
sql_print_error("Plugin '%s' handlerton init returned error.",
|
|
plugin->name.str);
|
|
DBUG_PRINT("warning", ("Plugin '%s' handlerton init returned error.",
|
|
plugin->name.str))
|
|
goto err;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
err:
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (plugin_initialize(tmp))
|
|
plugin_del(&tmp->name);
|
|
else
|
|
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);
|
|
}
|
|
|
|
|
|
int plugin_init(void)
|
|
{
|
|
int i;
|
|
DBUG_ENTER("plugin_init");
|
|
|
|
if (initialized)
|
|
DBUG_RETURN(0);
|
|
|
|
my_rwlock_init(&THR_LOCK_plugin, NULL);
|
|
|
|
if (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))
|
|
goto err;
|
|
|
|
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))
|
|
goto err;
|
|
}
|
|
|
|
initialized= 1;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
err:
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
|
|
my_bool plugin_register_builtin(struct st_mysql_plugin *plugin)
|
|
{
|
|
struct st_plugin_int tmp;
|
|
DBUG_ENTER("plugin_register_builtin");
|
|
|
|
tmp.plugin= plugin;
|
|
tmp.name.str= (char *)plugin->name;
|
|
tmp.name.length= strlen(plugin->name);
|
|
tmp.state= PLUGIN_IS_UNINITIALIZED;
|
|
|
|
/* Cannot be unloaded */
|
|
tmp.ref_count= 1;
|
|
tmp.plugin_dl= 0;
|
|
|
|
if (insert_dynamic(&plugin_array, (gptr)&tmp))
|
|
DBUG_RETURN(1);
|
|
|
|
if (my_hash_insert(&plugin_hash[plugin->type],
|
|
(byte*)dynamic_element(&plugin_array,
|
|
plugin_array.elements - 1,
|
|
struct st_plugin_int *)))
|
|
DBUG_RETURN(1);
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
void plugin_load(void)
|
|
{
|
|
TABLE_LIST tables;
|
|
TABLE *table;
|
|
READ_RECORD read_record_info;
|
|
int error, i;
|
|
MEM_ROOT mem;
|
|
THD *new_thd;
|
|
DBUG_ENTER("plugin_load");
|
|
|
|
DBUG_ASSERT(initialized);
|
|
|
|
if (!(new_thd= new THD))
|
|
{
|
|
sql_print_error("Can't allocate memory for plugin structures");
|
|
delete new_thd;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
init_sql_alloc(&mem, 1024, 0);
|
|
new_thd->thread_stack= (char*) &tables;
|
|
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.");
|
|
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);
|
|
|
|
/* need to open before acquiring THR_LOCK_plugin or it will deadlock */
|
|
if (! (table = open_ltable(thd, &tables, TL_WRITE)))
|
|
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 (plugin_initialize(tmp))
|
|
{
|
|
my_error(ER_CANT_INITIALIZE_UDF, MYF(0), name->str,
|
|
"Plugin initialization function failed.");
|
|
goto err;
|
|
}
|
|
|
|
tmp->state= PLUGIN_IS_READY;
|
|
|
|
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]);
|
|
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");
|
|
|
|
bzero(&tables, sizeof(tables));
|
|
tables.db= (char *)"mysql";
|
|
tables.table_name= tables.alias= (char *)"plugin";
|
|
|
|
/* need to open before acquiring THR_LOCK_plugin or it will deadlock */
|
|
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
|
|
DBUG_RETURN(TRUE);
|
|
|
|
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->plugin_dl)
|
|
{
|
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
|
|
"Built-in plugins cannot be deleted,.");
|
|
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);
|
|
}
|
|
|
|
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->ha_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);
|
|
}
|
|
|
|
|
|
my_bool plugin_foreach(THD *thd, plugin_foreach_func *func,
|
|
int type, void *arg)
|
|
{
|
|
uint idx;
|
|
struct st_plugin_int *plugin;
|
|
DBUG_ENTER("mysql_uninstall_plugin");
|
|
rw_rdlock(&THR_LOCK_plugin);
|
|
|
|
if (type == MYSQL_ANY_PLUGIN)
|
|
{
|
|
for (idx= 0; idx < plugin_array.elements; idx++)
|
|
{
|
|
plugin= dynamic_element(&plugin_array, idx, struct st_plugin_int *);
|
|
|
|
/* FREED records may have garbage pointers */
|
|
if ((plugin->state != PLUGIN_IS_FREED) &&
|
|
func(thd, plugin, arg))
|
|
goto err;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HASH *hash= &plugin_hash[type];
|
|
for (idx= 0; idx < hash->records; idx++)
|
|
{
|
|
plugin= (struct st_plugin_int *) hash_element(hash, idx);
|
|
if ((plugin->state != PLUGIN_IS_FREED) &&
|
|
(plugin->state != PLUGIN_IS_DELETED) &&
|
|
func(thd, plugin, arg))
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
rw_unlock(&THR_LOCK_plugin);
|
|
DBUG_RETURN(FALSE);
|
|
err:
|
|
rw_unlock(&THR_LOCK_plugin);
|
|
DBUG_RETURN(TRUE);
|
|
}
|