summaryrefslogtreecommitdiff
path: root/sql/sql_udf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_udf.cc')
-rw-r--r--sql/sql_udf.cc138
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);