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:
151
sql/sql_udf.cc
151
sql/sql_udf.cc
@ -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 */
|
||||
|
Reference in New Issue
Block a user