Skip to content

Commit

Permalink
Bug #26173244: THE UDF INSTALL SERVICE CAN'T BE USED AT
Browse files Browse the repository at this point in the history
 PLUGIN INSTALLS

Split the UDF initialization/deinitialization into two:
1. Initialization/deinitialization of the global structures
2. Loading of the UDF definitions from the table and removing them from the global

Then kept the #2 at the place of the current initialization/deinitalization
routines and added #2 initialization very early (before component/plugin
initialization) and #2 deinitialization very late (after the plugin/compononent
deinitialization.

Added a test plugin and a regression test.
  • Loading branch information
gkodinov committed Aug 17, 2017
1 parent 69ff70a commit c10127a
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 27 deletions.
1 change: 1 addition & 0 deletions mysql-test/include/plugin.defs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ rewrite_example plugin_output_directory REWRITE_EXAMPLE
rewriter plugin_output_directory REWRITER
mysql_no_login plugin_output_directory MYSQL_NO_LOGIN mysql_no_login
test_udf_services plugin_output_directory TESTUDFSERVICES
test_udf_services plugin_output_directory TESTUDFREGISTRATION test_udf_registration
group_replication plugin_output_directory GROUP_REPLICATION
locking_service plugin_output_directory LOCKING_SERVICE
version_token plugin_output_directory VERSION_TOKEN
Expand Down
18 changes: 18 additions & 0 deletions mysql-test/suite/test_services/r/test_udf_registration.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
INSTALL PLUGIN test_udf_registration SONAME 'test_udf_services.so';
# Must work
SELECT test_udf_registration_udf();
test_udf_registration_udf()
0
UNINSTALL PLUGIN test_udf_registration;
# Must fail: no UDF
SELECT test_udf_registration_udf();
ERROR 42000: FUNCTION test.test_udf_registration_udf does not exist
INSTALL PLUGIN test_udf_registration SONAME 'test_udf_services.so';
# Restart the server
# restart
# Must work after a restart
SELECT test_udf_registration_udf();
test_udf_registration_udf()
0
# Cleanup
UNINSTALL PLUGIN test_udf_registration;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
$TESTUDFREGISTRATION_OPT
--local-infile=true
28 changes: 28 additions & 0 deletions mysql-test/suite/test_services/t/test_udf_registration.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Save the initial number of concurrent sessions
--source include/count_sessions.inc

--replace_regex /\.dll/.so/
eval INSTALL PLUGIN test_udf_registration SONAME '$TESTUDFREGISTRATION';

--echo # Must work
SELECT test_udf_registration_udf();

UNINSTALL PLUGIN test_udf_registration;

--echo # Must fail: no UDF
--error ER_SP_DOES_NOT_EXIST
SELECT test_udf_registration_udf();

--replace_regex /\.dll/.so/
eval INSTALL PLUGIN test_udf_registration SONAME '$TESTUDFREGISTRATION';


--echo # Restart the server
--source include/restart_mysqld.inc


--echo # Must work after a restart
SELECT test_udf_registration_udf();

--echo # Cleanup
UNINSTALL PLUGIN test_udf_registration;
93 changes: 92 additions & 1 deletion plugin/udf_services/test_udf_services.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#include "my_compiler.h"
#include "my_inttypes.h"

static int test_udf_registration_init(MYSQL_PLUGIN p);
static int test_udf_registration_deinit(MYSQL_PLUGIN p);

/**
@file test_udf_services.cc
Expand All @@ -36,6 +39,9 @@
static struct st_mysql_daemon test_udf_services_plugin=
{ MYSQL_DAEMON_INTERFACE_VERSION };

static struct st_mysql_daemon test_udf_registration_plugin=
{ MYSQL_DAEMON_INTERFACE_VERSION };

mysql_declare_plugin(test_udf_services)
{
MYSQL_DAEMON_PLUGIN,
Expand All @@ -52,6 +58,22 @@ mysql_declare_plugin(test_udf_services)
NULL, /* system variables */
NULL, /* config options */
0, /* flags */
},
{
MYSQL_DAEMON_PLUGIN,
&test_udf_registration_plugin,
"test_udf_registration",
"Georgi Kodinov",
"MySQL mtr test framework",
PLUGIN_LICENSE_GPL,
test_udf_registration_init, /* Plugin Init */
NULL, /* Plugin Check uninstall */
test_udf_registration_deinit, /* Plugin Deinit */
0x0100, /* Plugin version: 1.0 */
NULL, /* status variables */
NULL, /* system variables */
NULL, /* config options */
0, /* flags */
}
mysql_declare_plugin_end;

Expand All @@ -78,7 +100,7 @@ test_udf_services_udf_init(UDF_INIT *initid MY_ATTRIBUTE((unused)),
UDF_ARGS *args MY_ATTRIBUTE((unused)),
char *message MY_ATTRIBUTE((unused)))
{
return FALSE;
return false;
}


Expand All @@ -103,3 +125,72 @@ test_udf_services_udf(UDF_INIT *initid MY_ATTRIBUTE((unused)),
my_snprintf(buffer, sizeof(buffer), "test");
return 0;
}

#include <mysql/service_plugin_registry.h>
#include <mysql/components/my_service.h>
#include <mysql/components/services/udf_registration.h>

/** Sample plugin init function that registers a UDF */
static int test_udf_registration_init(MYSQL_PLUGIN /*p */)
{
SERVICE_TYPE(registry) *reg;
SERVICE_TYPE(udf_registration) *udf;
bool ret= false;

reg= mysql_plugin_registry_acquire();
if (!reg)
{
ret= true;
goto end;
}
reg->acquire("udf_registration", (my_h_service *) &udf);
if (!udf)
{
ret= true;
goto end;
}
ret= udf->udf_register("test_udf_registration_udf", INT_RESULT,
(Udf_func_any) test_udf_services_udf,
test_udf_services_udf_init,
NULL);

reg->release((my_h_service) udf);
end:
if (reg)
mysql_plugin_registry_release(reg);
return ret ? 1 : 0;
}


/** Sample plugin init function that unregisters a UDF */
static int test_udf_registration_deinit(MYSQL_PLUGIN /* p */)
{
SERVICE_TYPE(registry) *reg;
SERVICE_TYPE(udf_registration) *udf;
bool ret= false;
int was_present;

reg= mysql_plugin_registry_acquire();
if (!reg)
{
ret= true;
goto end;
}
reg->acquire("udf_registration", (my_h_service *) &udf);
if (!udf)
{
ret= true;
goto end;
}

ret= udf->udf_unregister("test_udf_registration_udf", &was_present);

end:
if (reg)
{
if (udf)
reg->release((my_h_service) udf);
mysql_plugin_registry_release(reg);
}
return ret ? 1 : 0;
}
12 changes: 10 additions & 2 deletions sql/mysqld.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1973,7 +1973,7 @@ static void clean_up(bool print_message)
lex_free(); /* Free some memory */
item_create_cleanup();
if (!opt_noacl)
udf_deinit();
udf_unload_udfs();
table_def_start_shutdown();
plugin_shutdown();
gtid_server_cleanup(); // after plugin_shutdown
Expand Down Expand Up @@ -2065,6 +2065,7 @@ static void clean_up(bool print_message)

persisted_variables_cache.cleanup();

udf_deinit_globals();
/*
The following lines may never be executed as the main thread may have
killed us
Expand Down Expand Up @@ -4587,6 +4588,13 @@ static int init_server_components()
unireg_abort(MYSQLD_ABORT_EXIT);
}

/*
We need to initialize the UDF globals early before reading the proc table
and before the server component initialization to allow other components
to register their UDFs at init time and de-register them at deinit time.
*/
udf_init_globals();

/*
Set tc_log to point to TC_LOG_DUMMY early in order to allow plugin_init()
to commit attachable transaction after reading from mysql.plugin table.
Expand Down Expand Up @@ -5796,7 +5804,7 @@ int mysqld_main(int argc, char **argv)

if (!opt_noacl)
{
udf_init();
udf_read_functions_table();
}

init_status_vars();
Expand Down
79 changes: 56 additions & 23 deletions sql/sql_udf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -173,42 +173,62 @@ static void init_udf_psi_keys(void)
}
#endif

/**
Initialize the UDF global structures.
This is done as a separate step so that the UDF registration
service can work when initalizing plugins, which happens
before reading the UDF table.
*/
void udf_init_globals()
{
DBUG_ENTER("udf_init_globals");
if (initialized)
DBUG_VOID_RETURN;

#ifdef HAVE_PSI_INTERFACE
init_udf_psi_keys();
#endif

mysql_rwlock_init(key_rwlock_THR_LOCK_udf, &THR_LOCK_udf);
init_sql_alloc(key_memory_udf_mem, &mem, UDF_ALLOC_BLOCK_SIZE, 0);

udf_hash= new collation_unordered_map<std::string, udf_func *>(
system_charset_info, key_memory_udf_mem);
initialized= 1;

DBUG_VOID_RETURN;
}


/*
Read all predeclared functions from mysql.func and accept all that
can be used.
The global structures must be initialized first.
*/

void udf_init()
void udf_read_functions_table()
{
udf_func *tmp;
TABLE_LIST tables;
READ_RECORD read_record_info;
TABLE *table;
int error;
DBUG_ENTER("ufd_init");
DBUG_ENTER("ufd_read_functions_table");
char db[]= "mysql"; /* A subject to casednstr, can't be constant */

if (initialized)
if (!initialized)
{
DBUG_ASSERT("wrong init order: trying to read the UDFs without initializaton");
DBUG_VOID_RETURN;

#ifdef HAVE_PSI_INTERFACE
init_udf_psi_keys();
#endif

mysql_rwlock_init(key_rwlock_THR_LOCK_udf, &THR_LOCK_udf);
init_sql_alloc(key_memory_udf_mem, &mem, UDF_ALLOC_BLOCK_SIZE, 0);
}

THD *new_thd = new(std::nothrow) THD;
if (new_thd == nullptr)
{
LogErr(ERROR_LEVEL, ER_UDF_CANT_ALLOC_FOR_STRUCTURES);
free_root(&mem,MYF(0));
free_root(&mem, MYF(0));
delete new_thd;
DBUG_VOID_RETURN;
}
udf_hash= new collation_unordered_map<std::string, udf_func*>(
system_charset_info, key_memory_udf_mem);
initialized = 1;
new_thd->thread_stack= (char*) &new_thd;
new_thd->store_globals();
{
Expand Down Expand Up @@ -312,16 +332,11 @@ void udf_init()
/**
Deintialize the UDF subsystem.
This function does the following:
1. Closes the shared libaries.
2. Free the UDF hash.
3. Free the memroot allocated.
4. Destroy the RW mutex object.
This function closes the shared libaries.
*/
void udf_deinit()
void udf_unload_udfs()
{
/* close all shared libraries */
DBUG_ENTER("udf_free");
DBUG_ENTER("udf_unload_udfs");
if (udf_hash != nullptr)
{
for (auto it1= udf_hash->begin(); it1 != udf_hash->end(); ++it1)
Expand All @@ -339,6 +354,24 @@ void udf_deinit()
dlclose(udf->dlhandle);
}
}
}
DBUG_VOID_RETURN;
}


/**
Deintialize the UDF subsystem.
This function does the following:
1. Free the UDF hash.
2. Free the memroot allocated.
3. Destroy the RW mutex object.
*/
void udf_deinit_globals()
{
DBUG_ENTER("udf_deinit_globals");
if (udf_hash != nullptr)
{
delete udf_hash;
udf_hash= nullptr;
}
Expand Down
5 changes: 4 additions & 1 deletion sql/sql_udf.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ class udf_handler :public Sql_alloc
};


void udf_init(void),udf_deinit(void);
void udf_init_globals();
void udf_read_functions_table();
void udf_unload_udfs();
void udf_deinit_globals();
udf_func *find_udf(const char *name, size_t len=0,bool mark_used=0);
void free_udf(udf_func *udf);
bool mysql_create_function(THD *thd, udf_func *udf);
Expand Down

0 comments on commit c10127a

Please sign in to comment.