Commit 10543a4a authored by Georgi Kodinov's avatar Georgi Kodinov

Bug #11754014: 45549: udf plugin_dir path separator inconsistency

  and cryptic error 1126 message

The problem was that dlopen() related code was using just a subset 
of the path normalization routines used in other places.
Fixed the expansion of the pre-dlopen() behavior for plugins and UDFs
to use a platform-dependent consistent encoding of the paths.
Fixed the error dlopen() error handling to take the correct error message
and strip off the trailing newline character(s).
Fixed tests to do a platform independent replace of directories and to 
account for the traling slash.
parent a2248579
...@@ -1364,11 +1364,31 @@ do { doubleget_union _tmp; \ ...@@ -1364,11 +1364,31 @@ do { doubleget_union _tmp; \
#ifndef HAVE_DLERROR #ifndef HAVE_DLERROR
#ifdef _WIN32 #ifdef _WIN32
#define DLERROR_GENERATE(errmsg, error_number) \
char win_errormsg[2048]; \
if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, \
0, error_number, 0, win_errormsg, 2048, NULL)) \
{ \
char *ptr; \
for (ptr= &win_errormsg[0] + strlen(win_errormsg) - 1; \
ptr >= &win_errormsg[0] && strchr("\r\n\t\0x20", *ptr); \
ptr--) \
*ptr= 0; \
errmsg= win_errormsg; \
} \
else \
errmsg= ""
#define dlerror() "" #define dlerror() ""
#else #define dlopen_errno GetLastError()
#else /* _WIN32 */
#define dlerror() "No support for dynamic loading (static build?)" #define dlerror() "No support for dynamic loading (static build?)"
#endif #define DLERROR_GENERATE(errmsg, error_number) errmsg= dlerror()
#endif #define dlopen_errno errno
#endif /* _WIN32 */
#else /* HAVE_DLERROR */
#define DLERROR_GENERATE(errmsg, error_number) errmsg= dlerror()
#define dlopen_errno errno
#endif /* HAVE_DLERROR */
/* /*
......
select @@global.character_sets_dir; select @@global.character_sets_dir;
@@global.character_sets_dir @@global.character_sets_dir
MYSQL_CHARSETSDIR/ MYSQL_CHARSETSDIR
select @@session.character_sets_dir; select @@session.character_sets_dir;
ERROR HY000: Variable 'character_sets_dir' is a GLOBAL variable ERROR HY000: Variable 'character_sets_dir' is a GLOBAL variable
show global variables like 'character_sets_dir'; show global variables like 'character_sets_dir';
Variable_name Value Variable_name Value
character_sets_dir MYSQL_CHARSETSDIR/ character_sets_dir MYSQL_CHARSETSDIR
show session variables like 'character_sets_dir'; show session variables like 'character_sets_dir';
Variable_name Value Variable_name Value
character_sets_dir MYSQL_CHARSETSDIR/ character_sets_dir MYSQL_CHARSETSDIR
select * from information_schema.global_variables where variable_name='character_sets_dir'; select * from information_schema.global_variables where variable_name='character_sets_dir';
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
CHARACTER_SETS_DIR MYSQL_CHARSETSDIR/ CHARACTER_SETS_DIR MYSQL_CHARSETSDIR
select * from information_schema.session_variables where variable_name='character_sets_dir'; select * from information_schema.session_variables where variable_name='character_sets_dir';
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
CHARACTER_SETS_DIR MYSQL_CHARSETSDIR/ CHARACTER_SETS_DIR MYSQL_CHARSETSDIR
set global character_sets_dir="foo"; set global character_sets_dir="foo";
ERROR HY000: Variable 'character_sets_dir' is a read only variable ERROR HY000: Variable 'character_sets_dir' is a read only variable
set session character_sets_dir="foo"; set session character_sets_dir="foo";
......
select @@global.plugin_dir; select @@global.plugin_dir;
@@global.plugin_dir @@global.plugin_dir
MYSQL_TMP_DIR MYSQL_TMP_DIR/
select @@session.plugin_dir; select @@session.plugin_dir;
ERROR HY000: Variable 'plugin_dir' is a GLOBAL variable ERROR HY000: Variable 'plugin_dir' is a GLOBAL variable
show global variables like 'plugin_dir'; show global variables like 'plugin_dir';
Variable_name Value Variable_name Value
plugin_dir MYSQL_TMP_DIR plugin_dir MYSQL_TMP_DIR/
show session variables like 'plugin_dir'; show session variables like 'plugin_dir';
Variable_name Value Variable_name Value
plugin_dir MYSQL_TMP_DIR plugin_dir MYSQL_TMP_DIR/
select * from information_schema.global_variables where variable_name='plugin_dir'; select * from information_schema.global_variables where variable_name='plugin_dir';
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
PLUGIN_DIR MYSQL_TMP_DIR PLUGIN_DIR MYSQL_TMP_DIR/
select * from information_schema.session_variables where variable_name='plugin_dir'; select * from information_schema.session_variables where variable_name='plugin_dir';
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
PLUGIN_DIR MYSQL_TMP_DIR PLUGIN_DIR MYSQL_TMP_DIR/
set global plugin_dir=1; set global plugin_dir=1;
ERROR HY000: Variable 'plugin_dir' is a read only variable ERROR HY000: Variable 'plugin_dir' is a read only variable
set session plugin_dir=1; set session plugin_dir=1;
......
# #
# show the global and session values; # show the global and session values;
# #
--replace_result $MYSQL_CHARSETSDIR MYSQL_CHARSETSDIR
# workaround to adjust for the directory separators being different in
# different OSes : slash on unixes and backslash or slash on windows.
# TODO: fix with a proper comparison in mysqltest
let $rcd= `SELECT REPLACE('$MYSQL_CHARSETSDIR', '\\\\\', '.')`;
let $rcd= `SELECT REPLACE('$rcd', '/', '.')`;
let $regex_charsetdir= `SELECT '/$rcd[\\\\\/\\\\\]/MYSQL_CHARSETSDIR/'`;
--replace_regex $regex_charsetdir
select @@global.character_sets_dir; select @@global.character_sets_dir;
--error ER_INCORRECT_GLOBAL_LOCAL_VAR --error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@session.character_sets_dir; select @@session.character_sets_dir;
--replace_result $MYSQL_CHARSETSDIR MYSQL_CHARSETSDIR --replace_regex $regex_charsetdir
show global variables like 'character_sets_dir'; show global variables like 'character_sets_dir';
--replace_result $MYSQL_CHARSETSDIR MYSQL_CHARSETSDIR --replace_regex $regex_charsetdir
show session variables like 'character_sets_dir'; show session variables like 'character_sets_dir';
--replace_result $MYSQL_CHARSETSDIR MYSQL_CHARSETSDIR --replace_regex $regex_charsetdir
select * from information_schema.global_variables where variable_name='character_sets_dir'; select * from information_schema.global_variables where variable_name='character_sets_dir';
--replace_result $MYSQL_CHARSETSDIR MYSQL_CHARSETSDIR --replace_regex $regex_charsetdir
select * from information_schema.session_variables where variable_name='character_sets_dir'; select * from information_schema.session_variables where variable_name='character_sets_dir';
# #
......
...@@ -7608,8 +7608,10 @@ static int fix_paths(void) ...@@ -7608,8 +7608,10 @@ static int fix_paths(void)
(void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir
(void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home);
(void) my_load_path(pidfile_name, pidfile_name_ptr, mysql_real_data_home); (void) my_load_path(pidfile_name, pidfile_name_ptr, mysql_real_data_home);
(void) my_load_path(opt_plugin_dir, opt_plugin_dir_ptr ? opt_plugin_dir_ptr :
get_relative_path(PLUGINDIR), mysql_home); convert_dirname(opt_plugin_dir, opt_plugin_dir_ptr ? opt_plugin_dir_ptr :
get_relative_path(PLUGINDIR), NullS);
(void) my_load_path(opt_plugin_dir, opt_plugin_dir, mysql_home);
opt_plugin_dir_ptr= opt_plugin_dir; opt_plugin_dir_ptr= opt_plugin_dir;
my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0)); my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0));
......
...@@ -463,18 +463,22 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) ...@@ -463,18 +463,22 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
dlpathlen= dlpathlen=
strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS) - strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS) -
dlpath; dlpath;
(void) unpack_filename(dlpath, dlpath);
plugin_dl.ref_count= 1; plugin_dl.ref_count= 1;
/* Open new dll handle */ /* Open new dll handle */
if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW))) if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW)))
{ {
const char *errmsg=dlerror(); const char *errmsg;
int error_number= dlopen_errno;
DLERROR_GENERATE(errmsg, error_number);
if (!strncmp(dlpath, errmsg, dlpathlen)) if (!strncmp(dlpath, errmsg, dlpathlen))
{ // if errmsg starts from dlpath, trim this prefix. { // if errmsg starts from dlpath, trim this prefix.
errmsg+=dlpathlen; errmsg+=dlpathlen;
if (*errmsg == ':') errmsg++; if (*errmsg == ':') errmsg++;
if (*errmsg == ' ') errmsg++; if (*errmsg == ' ') errmsg++;
} }
report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, errno, errmsg); report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, error_number, errmsg);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/* Determine interface version */ /* Determine interface version */
......
...@@ -221,10 +221,15 @@ void udf_init() ...@@ -221,10 +221,15 @@ void udf_init()
char dlpath[FN_REFLEN]; char dlpath[FN_REFLEN];
strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", tmp->dl, strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", tmp->dl,
NullS); NullS);
(void) unpack_filename(dlpath, dlpath);
if (!(dl= dlopen(dlpath, RTLD_NOW))) if (!(dl= dlopen(dlpath, RTLD_NOW)))
{ {
const char *errmsg;
int error_number= dlopen_errno;
DLERROR_GENERATE(errmsg, error_number);
/* Print warning to log */ /* Print warning to log */
sql_print_error(ER(ER_CANT_OPEN_LIBRARY), tmp->dl, errno, dlerror()); sql_print_error(ER(ER_CANT_OPEN_LIBRARY), tmp->dl, error_number, errmsg);
/* Keep the udf in the hash so that we can remove it later */ /* Keep the udf in the hash so that we can remove it later */
continue; continue;
} }
...@@ -469,12 +474,18 @@ int mysql_create_function(THD *thd,udf_func *udf) ...@@ -469,12 +474,18 @@ int mysql_create_function(THD *thd,udf_func *udf)
{ {
char dlpath[FN_REFLEN]; char dlpath[FN_REFLEN];
strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", udf->dl, NullS); strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", udf->dl, NullS);
(void) unpack_filename(dlpath, dlpath);
if (!(dl = dlopen(dlpath, RTLD_NOW))) if (!(dl = dlopen(dlpath, RTLD_NOW)))
{ {
const char *errmsg;
int error_number= dlopen_errno;
DLERROR_GENERATE(errmsg, error_number);
DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)", DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)",
udf->dl, errno, dlerror())); udf->dl, error_number, errmsg));
my_error(ER_CANT_OPEN_LIBRARY, MYF(0), my_error(ER_CANT_OPEN_LIBRARY, MYF(0),
udf->dl, errno, dlerror()); udf->dl, error_number, errmsg);
goto err; goto err;
} }
new_dl=1; new_dl=1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment