1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-23327 Can't uninstall UDF if the implementation library file doesn't exist

Made cleanup of DROP (udf) FUNCTION procedure and also check of mysql.func (not only loaded udf).
This commit is contained in:
Oleksandr Byelkin
2020-07-29 21:54:24 +02:00
parent 95bb3cb886
commit bba22543b1
5 changed files with 164 additions and 56 deletions

View File

@ -58,6 +58,8 @@ static udf_func *add_udf(LEX_STRING *name, Item_result ret,
char *dl, Item_udftype typ);
static void del_udf(udf_func *udf);
static void *find_udf_dl(const char *dl);
static bool find_udf_everywhere(THD* thd, const char *name, uint len,
TABLE *table);
static char *init_syms(udf_func *tmp, char *nm)
{
@ -417,6 +419,45 @@ static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
return tmp;
}
/**
Find record with the udf in the udf func table
@param exact_name_str udf name
@param exact_name_len udf name length
@param table table of mysql.func
@retval TRUE found
@retral FALSE not found
*/
static bool find_udf_in_table(const char *exact_name_str, uint exact_name_len,
TABLE *table)
{
table->use_all_columns();
table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
return (!table->file->ha_index_read_idx_map(table->record[0], 0,
(uchar*) table->field[0]->ptr,
HA_WHOLE_KEY,
HA_READ_KEY_EXACT));
}
static bool remove_udf_in_table(const char *exact_name_str,
uint exact_name_len,
TABLE *table)
{
if (find_udf_in_table(exact_name_str, exact_name_len, table))
{
int error;
if ((error= table->file->ha_delete_row(table->record[0])))
{
table->file->print_error(error, MYF(0));
return TRUE;
}
}
return FALSE;
}
/*
Drop user defined function.
@ -447,18 +488,21 @@ static int mysql_drop_function_internal(THD *thd, udf_func *udf, TABLE *table)
if (!table)
DBUG_RETURN(1);
table->use_all_columns();
table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
if (!table->file->ha_index_read_idx_map(table->record[0], 0,
(uchar*) table->field[0]->ptr,
HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
int error;
if ((error= table->file->ha_delete_row(table->record[0])))
table->file->print_error(error, MYF(0));
}
DBUG_RETURN(0);
bool ret= remove_udf_in_table(exact_name_str, exact_name_len, table);
DBUG_RETURN(ret);
}
static TABLE *open_udf_func_table(THD *thd)
{
TABLE_LIST tables;
TABLE *table;
tables.init_one_table(STRING_WITH_LEN("mysql"), STRING_WITH_LEN("func"),
"func", TL_WRITE);
table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT);
return table;
}
@ -505,9 +549,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
if (check_ident_length(&udf->name))
DBUG_RETURN(1);
tables.init_one_table(STRING_WITH_LEN("mysql"), STRING_WITH_LEN("func"),
"func", TL_WRITE);
table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT);
table= open_udf_func_table(thd);
mysql_rwlock_wrlock(&THR_LOCK_udf);
DEBUG_SYNC(current_thd, "mysql_create_function_after_lock");
@ -606,43 +648,59 @@ err:
}
int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
enum drop_udf_result mysql_drop_function(THD *thd, const LEX_STRING *udf_name)
{
TABLE *table;
TABLE_LIST tables;
udf_func *udf;
DBUG_ENTER("mysql_drop_function");
if (!initialized)
if (!(table= open_udf_func_table(thd)))
DBUG_RETURN(UDF_DEL_RESULT_ERROR);
// Fast pre-check
if (!mysql_rwlock_tryrdlock(&THR_LOCK_udf))
{
if (opt_noacl)
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
else
my_message(ER_OUT_OF_RESOURCES, ER_THD(thd, ER_OUT_OF_RESOURCES),
MYF(0));
DBUG_RETURN(1);
bool found=find_udf_everywhere(thd, udf_name->str, udf_name->length, table);
mysql_rwlock_unlock(&THR_LOCK_udf);
if (!found)
{
close_mysql_tables(thd);
DBUG_RETURN(UDF_DEL_RESULT_ABSENT);
}
}
tables.init_one_table(STRING_WITH_LEN("mysql"), STRING_WITH_LEN("func"),
"func", TL_WRITE);
table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT);
if (!initialized)
{
close_mysql_tables(thd);
if (opt_noacl)
DBUG_RETURN(UDF_DEL_RESULT_ABSENT); // SP should be checked
my_message(ER_OUT_OF_RESOURCES, ER_THD(thd, ER_OUT_OF_RESOURCES), MYF(0));
DBUG_RETURN(UDF_DEL_RESULT_ERROR);
}
mysql_rwlock_wrlock(&THR_LOCK_udf);
// re-check under protection
if (!find_udf_everywhere(thd, udf_name->str, udf_name->length, table))
{
close_mysql_tables(thd);
mysql_rwlock_unlock(&THR_LOCK_udf);
DBUG_RETURN(UDF_DEL_RESULT_ABSENT);
}
if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 0))
goto err;
DEBUG_SYNC(current_thd, "mysql_drop_function_after_lock");
if (!(udf= (udf_func*) my_hash_search(&udf_hash, (uchar*) udf_name->str,
(uint) udf_name->length)) )
{
if (thd->lex->check_exists)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_FUNCTION_NOT_DEFINED,
ER_THD(thd, ER_FUNCTION_NOT_DEFINED),
udf_name->str);
goto done;
}
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
goto err;
if (remove_udf_in_table(udf_name->str, (uint) udf_name->length, table))
goto err;
goto done;
}
if (mysql_drop_function_internal(thd, udf, table))
@ -656,13 +714,24 @@ done:
while binlogging, to avoid binlog inconsistency.
*/
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
DBUG_RETURN(1);
DBUG_RETURN(UDF_DEL_RESULT_ERROR);
DBUG_RETURN(0);
close_mysql_tables(thd);
DBUG_RETURN(UDF_DEL_RESULT_DELETED);
err:
close_mysql_tables(thd);
mysql_rwlock_unlock(&THR_LOCK_udf);
DBUG_RETURN(1);
DBUG_RETURN(UDF_DEL_RESULT_ERROR);
}
static bool find_udf_everywhere(THD* thd, const char *name, uint len,
TABLE *table)
{
if (initialized && my_hash_search(&udf_hash, (uchar*) name, len))
return true;
return find_udf_in_table(name, len, table);
}
#endif /* HAVE_DLOPEN */