mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01: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:
parent
95bb3cb886
commit
bba22543b1
5 changed files with 164 additions and 56 deletions
|
@ -479,3 +479,17 @@ myfunc_int(max(a) over (order by b) , b)
|
|||
drop view v1;
|
||||
drop function myfunc_int;
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-23327: Can't uninstall UDF if the implementation library
|
||||
# file doesn't exist
|
||||
#
|
||||
insert into mysql.func values ("unexisting_udf", 0, "soname", "function");
|
||||
select * from mysql.func WHERE name='unexisting_udf';
|
||||
name ret dl type
|
||||
unexisting_udf 0 soname function
|
||||
DROP FUNCTION unexisting_udf;
|
||||
select * from mysql.plugin WHERE name='unexisting_udf';
|
||||
name dl
|
||||
DROP FUNCTION unexisting_udf;
|
||||
ERROR 42000: FUNCTION test.unexisting_udf does not exist
|
||||
# End of 10.2 tests
|
||||
|
|
|
@ -541,3 +541,25 @@ select * from v1;
|
|||
drop view v1;
|
||||
drop function myfunc_int;
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-23327: Can't uninstall UDF if the implementation library
|
||||
--echo # file doesn't exist
|
||||
--echo #
|
||||
|
||||
# emulate brocken so/ddl udf
|
||||
insert into mysql.func values ("unexisting_udf", 0, "soname", "function");
|
||||
|
||||
# check that we have the function "installed"
|
||||
select * from mysql.func WHERE name='unexisting_udf';
|
||||
|
||||
# make attempt to drop the function
|
||||
DROP FUNCTION unexisting_udf;
|
||||
|
||||
# check that we have the plugin uninstalled
|
||||
select * from mysql.plugin WHERE name='unexisting_udf';
|
||||
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
DROP FUNCTION unexisting_udf;
|
||||
|
||||
--echo # End of 10.2 tests
|
||||
|
|
|
@ -5623,23 +5623,20 @@ mysql_execute_command(THD *thd)
|
|||
! lex->spname->m_explicit_name)
|
||||
{
|
||||
/* DROP FUNCTION <non qualified name> */
|
||||
udf_func *udf = find_udf(lex->spname->m_name.str,
|
||||
lex->spname->m_name.length);
|
||||
if (udf)
|
||||
enum drop_udf_result rc= mysql_drop_function(thd,
|
||||
&lex->spname->m_name);
|
||||
if (rc == UDF_DEL_RESULT_DELETED)
|
||||
{
|
||||
if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 0))
|
||||
goto error;
|
||||
|
||||
if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
|
||||
{
|
||||
my_ok(thd);
|
||||
break;
|
||||
}
|
||||
my_error(ER_SP_DROP_FAILED, MYF(0),
|
||||
"FUNCTION (UDF)", lex->spname->m_name.str);
|
||||
goto error;
|
||||
my_ok(thd);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == UDF_DEL_RESULT_ERROR)
|
||||
goto error;
|
||||
|
||||
DBUG_ASSERT(rc == UDF_DEL_RESULT_ABSENT);
|
||||
|
||||
// If there was no current database, so it can not be SP
|
||||
if (lex->spname->m_db.str == NULL)
|
||||
{
|
||||
if (lex->if_exists())
|
||||
|
|
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 */
|
||||
|
|
|
@ -140,7 +140,13 @@ void udf_init(void),udf_free(void);
|
|||
udf_func *find_udf(const char *name, uint len=0,bool mark_used=0);
|
||||
void free_udf(udf_func *udf);
|
||||
int mysql_create_function(THD *thd,udf_func *udf);
|
||||
int mysql_drop_function(THD *thd,const LEX_STRING *name);
|
||||
enum drop_udf_result
|
||||
{
|
||||
UDF_DEL_RESULT_ABSENT,
|
||||
UDF_DEL_RESULT_DELETED,
|
||||
UDF_DEL_RESULT_ERROR
|
||||
};
|
||||
enum drop_udf_result mysql_drop_function(THD *thd,const LEX_STRING *name);
|
||||
#else
|
||||
static inline void udf_init(void) { }
|
||||
static inline void udf_free(void) { }
|
||||
|
|
Loading…
Reference in a new issue