diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-10-22 17:08:49 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-10-22 17:08:49 +0300 |
commit | 1657b7a583c62deb72267d485bfe201f43909e11 (patch) | |
tree | a750e2a44fdd296837b566623331e8a9a707d290 /sql/sql_udf.cc | |
parent | cca75c95bc3c5d0d4a2efb920d3942da3e658654 (diff) | |
parent | 9868253b32877554a2707634dc6a6fd79c491053 (diff) | |
download | mariadb-git-1657b7a583c62deb72267d485bfe201f43909e11.tar.gz |
Merge 10.4 to 10.5
Diffstat (limited to 'sql/sql_udf.cc')
-rw-r--r-- | sql/sql_udf.cc | 148 |
1 files changed, 108 insertions, 40 deletions
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 5df9e7dd47d..07dd3b1f6ca 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -58,6 +58,8 @@ static udf_func *add_udf(LEX_CSTRING *name, Item_result ret, const 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 LEX_CSTRING &name, + TABLE *table); static const char *init_syms(udf_func *tmp, char *nm) { @@ -430,6 +432,41 @@ static udf_func *add_udf(LEX_CSTRING *name, Item_result ret, const char *dl, return tmp; } +/** + Find record with the udf in the udf func table + + @param exact_name udf name + @param table table of mysql.func + + @retval TRUE found + @retral FALSE not found +*/ + +static bool find_udf_in_table(const LEX_CSTRING &exact_name, TABLE *table) +{ + table->use_all_columns(); + table->field[0]->store(exact_name.str, exact_name.length, &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 LEX_CSTRING &exact_name, TABLE *table) +{ + if (find_udf_in_table(exact_name, 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. @@ -446,8 +483,7 @@ static int mysql_drop_function_internal(THD *thd, udf_func *udf, TABLE *table) { DBUG_ENTER("mysql_drop_function_internal"); - const char *exact_name_str= udf->name.str; - size_t exact_name_len= udf->name.length; + const LEX_CSTRING exact_name= udf->name; del_udf(udf); /* @@ -460,18 +496,17 @@ 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 (unlikely((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, table); + DBUG_RETURN(ret); +} + + +static TABLE *open_udf_func_table(THD *thd) +{ + TABLE_LIST tables; + tables.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_FUNC_NAME, + &MYSQL_FUNC_NAME, TL_WRITE); + return open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT); } @@ -518,8 +553,7 @@ int mysql_create_function(THD *thd,udf_func *udf) if (check_ident_length(&udf->name)) DBUG_RETURN(1); - tables.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_FUNC_NAME, 0, 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"); @@ -620,42 +654,65 @@ err: } -int mysql_drop_function(THD *thd, const LEX_CSTRING *udf_name) +enum drop_udf_result mysql_drop_function(THD *thd, const LEX_CSTRING *udf_name) { TABLE *table; - TABLE_LIST tables; udf_func *udf; DBUG_ENTER("mysql_drop_function"); + if (thd->locked_tables_mode) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + DBUG_RETURN(UDF_DEL_RESULT_ERROR); + } + + if (!(table= open_udf_func_table(thd))) + DBUG_RETURN(UDF_DEL_RESULT_ERROR); + + // Fast pre-check + if (!mysql_rwlock_tryrdlock(&THR_LOCK_udf)) + { + bool found= find_udf_everywhere(thd, *udf_name, table); + mysql_rwlock_unlock(&THR_LOCK_udf); + if (!found) + { + close_mysql_tables(thd); + DBUG_RETURN(UDF_DEL_RESULT_ABSENT); + } + } + if (!initialized) { + close_mysql_tables(thd); 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); - } + DBUG_RETURN(UDF_DEL_RESULT_ABSENT); // SP should be checked - tables.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_FUNC_NAME, 0, TL_WRITE); - table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT); + 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, 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, table)) + goto err; + goto done; } if (mysql_drop_function_internal(thd, udf, table)) @@ -669,13 +726,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 LEX_CSTRING &name, + TABLE *table) +{ + if (initialized && my_hash_search(&udf_hash, (uchar*) name.str, name.length)) + return true; + + return find_udf_in_table(name, table); } #endif /* HAVE_DLOPEN */ |