diff options
Diffstat (limited to 'sql/sql_udf.cc')
-rw-r--r-- | sql/sql_udf.cc | 138 |
1 files changed, 76 insertions, 62 deletions
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 077660f0bb9..19582af38f4 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -37,36 +37,10 @@ #ifdef HAVE_DLOPEN extern "C" { -#if defined(__WIN__) - void* dlsym(void* lib,const char* name) - { - return GetProcAddress((HMODULE)lib,name); - } - void* dlopen(const char* libname,int unused) - { - return LoadLibraryEx(libname,NULL,0); - } - void dlclose(void* lib) - { - FreeLibrary((HMODULE)lib); - } - -#elif !defined(OS2) -#include <dlfcn.h> -#endif - #include <stdarg.h> #include <hash.h> } -#ifndef RTLD_NOW -#define RTLD_NOW 1 // For FreeBSD 2.2.2 -#endif - -#ifndef HAVE_DLERROR -#define dlerror() "" -#endif - static bool initialized = 0; static MEM_ROOT mem; static HASH udf_hash; @@ -118,12 +92,12 @@ static char *init_syms(udf_func *tmp, char *nm) } -extern "C" byte* get_hash_key(const byte *buff,uint *length, +extern "C" uchar* get_hash_key(const uchar *buff, size_t *length, my_bool not_used __attribute__((unused))) { udf_func *udf=(udf_func*) buff; *length=(uint) udf->name.length; - return (byte*) udf->name.str; + return (uchar*) udf->name.str; } @@ -139,8 +113,8 @@ void udf_init() READ_RECORD read_record_info; TABLE *table; int error; - char db[]= "mysql"; /* A subject to casednstr, can't be constant */ DBUG_ENTER("ufd_init"); + char db[]= "mysql"; /* A subject to casednstr, can't be constant */ if (initialized) DBUG_VOID_RETURN; @@ -163,7 +137,7 @@ void udf_init() new_thd->store_globals(); new_thd->set_db(db, sizeof(db)-1); - bzero((gptr) &tables,sizeof(tables)); + bzero((uchar*) &tables,sizeof(tables)); tables.alias= tables.table_name= (char*) "func"; tables.lock_type = TL_READ; tables.db= db; @@ -171,13 +145,15 @@ void udf_init() if (simple_open_n_lock_tables(new_thd, &tables)) { DBUG_PRINT("error",("Can't open udf table")); - sql_print_error("Can't open the mysql.func table. Please run the mysql_install_db script to create it."); + sql_print_error("Can't open the mysql.func table. Please " + "run mysql_upgrade to create it."); goto end; } table= tables.table; init_read_record(&read_record_info, new_thd, table, NULL,1,0); - while (!(error = read_record_info.read_record(&read_record_info))) + table->use_all_columns(); + while (!(error= read_record_info.read_record(&read_record_info))) { DBUG_PRINT("info",("init udf record")); LEX_STRING name; @@ -193,17 +169,21 @@ void udf_init() Ensure that the .dll doesn't have a path This is done to ensure that only approved dll from the system directories are used (to make this even remotely secure). + + On windows we must check both FN_LIBCHAR and '/'. */ - if (strchr(dl_name, '/') || - IF_WIN(strchr(dl_name, '\\'),0) || - strlen(name.str) > NAME_LEN) + if (my_strchr(files_charset_info, dl_name, + dl_name + strlen(dl_name), FN_LIBCHAR) || + IF_WIN(my_strchr(files_charset_info, dl_name, + dl_name + strlen(dl_name), '/'), 0) || + check_string_char_length(&name, "", NAME_CHAR_LEN, + system_charset_info, 1)) { sql_print_error("Invalid row in mysql.func table for function '%.64s'", name.str); continue; } - if (!(tmp= add_udf(&name,(Item_result) table->field[1]->val_int(), dl_name, udftype))) { @@ -214,10 +194,13 @@ void udf_init() void *dl = find_udf_dl(tmp->dl); if (dl == NULL) { - if (!(dl = dlopen(tmp->dl, RTLD_NOW))) + char dlpath[FN_REFLEN]; + strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", tmp->dl, + NullS); + if (!(dl= dlopen(dlpath, RTLD_NOW))) { /* 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, errno, dlerror()); /* Keep the udf in the hash so that we can remove it later */ continue; } @@ -284,7 +267,7 @@ static void del_udf(udf_func *udf) DBUG_ENTER("del_udf"); if (!--udf->usage_count) { - hash_delete(&udf_hash,(byte*) udf); + hash_delete(&udf_hash,(uchar*) udf); using_udf_functions=udf_hash.records != 0; } else @@ -298,7 +281,7 @@ static void del_udf(udf_func *udf) uint name_length=udf->name.length; udf->name.str=(char*) "*"; udf->name.length=1; - hash_update(&udf_hash,(byte*) udf,(byte*) name,name_length); + hash_update(&udf_hash,(uchar*) udf,(uchar*) name,name_length); } DBUG_VOID_RETURN; } @@ -318,7 +301,7 @@ void free_udf(udf_func *udf) We come here when someone has deleted the udf function while another thread still was using the udf */ - hash_delete(&udf_hash,(byte*) udf); + hash_delete(&udf_hash,(uchar*) udf); using_udf_functions=udf_hash.records != 0; if (!find_udf_dl(udf->dl)) dlclose(udf->dlhandle); @@ -344,7 +327,7 @@ udf_func *find_udf(const char *name,uint length,bool mark_used) else rw_rdlock(&THR_LOCK_udf); /* Called during parsing */ - if ((udf=(udf_func*) hash_search(&udf_hash,(byte*) name, + if ((udf=(udf_func*) hash_search(&udf_hash,(uchar*) name, length ? length : (uint) strlen(name)))) { if (!udf->dlhandle) @@ -391,7 +374,7 @@ static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl, tmp->returns = ret; tmp->type = type; tmp->usage_count=1; - if (my_hash_insert(&udf_hash,(byte*) tmp)) + if (my_hash_insert(&udf_hash,(uchar*) tmp)) return 0; using_udf_functions=1; return tmp; @@ -418,33 +401,47 @@ int mysql_create_function(THD *thd,udf_func *udf) Ensure that the .dll doesn't have a path This is done to ensure that only approved dll from the system directories are used (to make this even remotely secure). + + On windows we must check both FN_LIBCHAR and '/'. */ - if (strchr(udf->dl, '/') || IF_WIN(strchr(udf->dl, '\\'),0)) + if (my_strchr(files_charset_info, udf->dl, + udf->dl + strlen(udf->dl), FN_LIBCHAR) || + IF_WIN(my_strchr(files_charset_info, udf->dl, + udf->dl + strlen(udf->dl), '/'), 0)) { my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0)); DBUG_RETURN(1); } - if (udf->name.length > NAME_LEN) + if (check_string_char_length(&udf->name, "", NAME_CHAR_LEN, + system_charset_info, 1)) { my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name); DBUG_RETURN(1); } + /* + Turn off row binlogging of this statement and use statement-based + so that all supporting tables are updated for CREATE FUNCTION command. + */ + if (thd->current_stmt_binlog_row_based) + thd->clear_current_stmt_binlog_row_based(); + rw_wrlock(&THR_LOCK_udf); - if ((hash_search(&udf_hash,(byte*) udf->name.str, udf->name.length))) + if ((hash_search(&udf_hash,(uchar*) udf->name.str, udf->name.length))) { my_error(ER_UDF_EXISTS, MYF(0), udf->name); goto err; } if (!(dl = find_udf_dl(udf->dl))) { - DBUG_PRINT("info", ("Calling dlopen, udf->dl: %s", udf->dl)); - if (!(dl = dlopen(udf->dl, RTLD_NOW))) + char dlpath[FN_REFLEN]; + strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", udf->dl, NullS); + if (!(dl = dlopen(dlpath, RTLD_NOW))) { DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)", - udf->dl,errno,dlerror())); + udf->dl, errno, dlerror())); my_error(ER_CANT_OPEN_LIBRARY, MYF(0), - udf->dl, errno, dlerror()); + udf->dl, errno, dlerror()); goto err; } new_dl=1; @@ -475,16 +472,16 @@ int mysql_create_function(THD *thd,udf_func *udf) tables.db= (char*) "mysql"; tables.table_name= tables.alias= (char*) "func"; /* Allow creation of functions even if we can't open func table */ - if (!(table = open_ltable(thd,&tables,TL_WRITE))) + if (!(table = open_ltable(thd, &tables, TL_WRITE, 0))) goto err; - + table->use_all_columns(); restore_record(table, s->default_values); // Default values for fields table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info); table->field[1]->store((longlong) u_d->returns, TRUE); table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info); if (table->s->fields >= 4) // If not old func format table->field[3]->store((longlong) u_d->type, TRUE); - error = table->file->write_row(table->record[0]); + error = table->file->ha_write_row(table->record[0]); close_thread_tables(thd); if (error) @@ -494,6 +491,10 @@ int mysql_create_function(THD *thd,udf_func *udf) goto err; } rw_unlock(&THR_LOCK_udf); + + /* Binlog the create function. */ + write_bin_log(thd, TRUE, thd->query, thd->query_length); + DBUG_RETURN(0); err: @@ -512,13 +513,22 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) char *exact_name_str; uint exact_name_len; DBUG_ENTER("mysql_drop_function"); + if (!initialized) { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); DBUG_RETURN(1); } + + /* + Turn off row binlogging of this statement and use statement-based + so that all supporting tables are updated for DROP FUNCTION command. + */ + if (thd->current_stmt_binlog_row_based) + thd->clear_current_stmt_binlog_row_based(); + rw_wrlock(&THR_LOCK_udf); - if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name->str, + if (!(udf=(udf_func*) hash_search(&udf_hash,(uchar*) udf_name->str, (uint) udf_name->length))) { my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str); @@ -537,22 +547,26 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) bzero((char*) &tables,sizeof(tables)); tables.db=(char*) "mysql"; tables.table_name= tables.alias= (char*) "func"; - if (!(table = open_ltable(thd,&tables,TL_WRITE))) + if (!(table = open_ltable(thd, &tables, TL_WRITE, 0))) goto err; + table->use_all_columns(); table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); - if (!table->file->index_read_idx(table->record[0], 0, - (byte*) table->field[0]->ptr, - table->key_info[0].key_length, - HA_READ_KEY_EXACT)) + if (!table->file->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->delete_row(table->record[0]))) + if ((error = table->file->ha_delete_row(table->record[0]))) table->file->print_error(error, MYF(0)); } close_thread_tables(thd); - rw_unlock(&THR_LOCK_udf); + rw_unlock(&THR_LOCK_udf); + + /* Binlog the drop function. */ + write_bin_log(thd, TRUE, thd->query, thd->query_length); + DBUG_RETURN(0); err: rw_unlock(&THR_LOCK_udf); |