34
27
#include "mysql_priv.h"
35
28
#include <my_pthread.h>
40
32
#include <stdarg.h>
44
static bool initialized = 0;
36
static bool udf_startup= false; /* We do not lock because startup is single threaded */
45
37
static MEM_ROOT mem;
46
38
static HASH udf_hash;
47
static rw_lock_t THR_LOCK_udf;
50
static udf_func *add_udf(LEX_STRING *name, Item_result ret,
51
char *dl, Item_udftype typ);
52
static void del_udf(udf_func *udf);
53
static void *find_udf_dl(const char *dl);
55
static char *init_syms(udf_func *tmp, char *nm)
59
if (!((tmp->func= (Udf_func_any) dlsym(tmp->dlhandle, tmp->name.str))))
62
end=strmov(nm,tmp->name.str);
64
if (tmp->type == UDFTYPE_AGGREGATE)
66
(void)strmov(end, "_clear");
67
if (!((tmp->func_clear= (Udf_func_clear) dlsym(tmp->dlhandle, nm))))
69
(void)strmov(end, "_add");
70
if (!((tmp->func_add= (Udf_func_add) dlsym(tmp->dlhandle, nm))))
74
(void) strmov(end,"_deinit");
75
tmp->func_deinit= (Udf_func_deinit) dlsym(tmp->dlhandle, nm);
77
(void) strmov(end,"_init");
78
tmp->func_init= (Udf_func_init) dlsym(tmp->dlhandle, nm);
81
to prefent loading "udf" from, e.g. libc.so
82
let's ensure that at least one auxiliary symbol is defined
84
if (!tmp->func_init && !tmp->func_deinit && tmp->type != UDFTYPE_AGGREGATE)
90
40
extern "C" uchar* get_hash_key(const uchar *buff, size_t *length,
91
my_bool not_used __attribute__((unused)))
41
bool not_used __attribute__((unused)))
93
udf_func *udf=(udf_func*) buff;
94
*length=(uint) udf->name.length;
43
udf_func *udf= (udf_func*) buff;
44
*length= (uint) udf->name.length;
95
45
return (uchar*) udf->name.str;
100
Read all predeclared functions from mysql.func and accept all that
111
my_rwlock_init(&THR_LOCK_udf,NULL);
113
51
init_sql_alloc(&mem, UDF_ALLOC_BLOCK_SIZE, 0);
114
THD *new_thd = new THD;
116
hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
53
if (hash_init(&udf_hash, system_charset_info, 32, 0, 0, get_hash_key, NULL, 0))
118
55
sql_print_error("Can't allocate memory for udf structures");
119
56
hash_free(&udf_hash);
120
free_root(&mem,MYF(0));
57
free_root(&mem, MYF(0));
126
close_thread_tables(new_thd);
128
/* Remember that we don't have a THD */
129
my_pthread_setspecific_ptr(THR_THD, 0);
62
/* called by mysqld.cc clean_up() */
136
/* close all shared libraries */
138
for (uint idx=0 ; idx < udf_hash.records ; idx++)
140
udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
141
if (udf->dlhandle) // Not closed before
143
/* Mark all versions using the same handler as closed */
144
for (uint j=idx+1 ; j < udf_hash.records ; j++)
146
udf_func *tmp=(udf_func*) hash_element(&udf_hash,j);
147
if (udf->dlhandle == tmp->dlhandle)
148
tmp->dlhandle=0; // Already closed
150
dlclose(udf->dlhandle);
153
65
hash_free(&udf_hash);
154
free_root(&mem,MYF(0));
158
rwlock_destroy(&THR_LOCK_udf);
164
static void del_udf(udf_func *udf)
167
if (!--udf->usage_count)
169
hash_delete(&udf_hash,(uchar*) udf);
170
using_udf_functions=udf_hash.records != 0;
175
The functions is in use ; Rename the functions instead of removing it.
176
The functions will be automaticly removed when the least threads
177
doesn't use it anymore
179
char *name= udf->name.str;
180
uint name_length=udf->name.length;
181
udf->name.str=(char*) "*";
183
hash_update(&udf_hash,(uchar*) udf,(uchar*) name,name_length);
189
void free_udf(udf_func *udf)
196
rw_wrlock(&THR_LOCK_udf);
197
if (!--udf->usage_count)
200
We come here when someone has deleted the udf function
201
while another thread still was using the udf
203
hash_delete(&udf_hash,(uchar*) udf);
204
using_udf_functions=udf_hash.records != 0;
205
if (!find_udf_dl(udf->dl))
206
dlclose(udf->dlhandle);
208
rw_unlock(&THR_LOCK_udf);
66
free_root(&mem, MYF(0));
213
69
/* This is only called if using_udf_functions != 0 */
215
udf_func *find_udf(const char *name,uint length,bool mark_used)
223
/* TODO: This should be changed to reader locks someday! */
225
rw_wrlock(&THR_LOCK_udf); /* Called during fix_fields */
227
rw_rdlock(&THR_LOCK_udf); /* Called during parsing */
229
if ((udf=(udf_func*) hash_search(&udf_hash,(uchar*) name,
230
length ? length : (uint) strlen(name))))
233
udf=0; // Could not be opened
237
rw_unlock(&THR_LOCK_udf);
242
static void *find_udf_dl(const char *dl)
247
Because only the function name is hashed, we have to search trough
248
all rows to find the dl.
250
for (uint idx=0 ; idx < udf_hash.records ; idx++)
252
udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
253
if (!strcmp(dl, udf->dl) && udf->dlhandle != NULL)
254
return(udf->dlhandle);
260
/* Assume that name && dl is already allocated */
262
static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
265
if (!name || !dl || !(uint) type || (uint) type > (uint) UDFTYPE_AGGREGATE)
267
udf_func *tmp= (udf_func*) alloc_root(&mem, sizeof(udf_func));
270
bzero((char*) tmp,sizeof(*tmp));
271
tmp->name = *name; //dup !!
276
if (my_hash_insert(&udf_hash,(uchar*) tmp))
278
using_udf_functions=1;
284
Create a user defined function.
286
@note Like implementations of other DDL/DML in MySQL, this function
287
relies on the caller to close the thread tables. This is done in the
288
end of dispatch_command().
291
int mysql_create_function(THD *thd,udf_func *udf)
304
my_error(ER_CANT_INITIALIZE_UDF, MYF(0),
306
"UDFs are unavailable with the --skip-grant-tables option");
308
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
313
Ensure that the .dll doesn't have a path
314
This is done to ensure that only approved dll from the system
315
directories are used (to make this even remotely secure).
317
On windows we must check both FN_LIBCHAR and '/'.
319
if (my_strchr(files_charset_info, udf->dl,
320
udf->dl + strlen(udf->dl), FN_LIBCHAR) ||
321
IF_WIN(my_strchr(files_charset_info, udf->dl,
322
udf->dl + strlen(udf->dl), '/'), 0))
324
my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0));
327
if (check_identifier_name(&udf->name, ER_TOO_LONG_IDENT))
331
Turn off row binlogging of this statement and use statement-based
332
so that all supporting tables are updated for CREATE FUNCTION command.
334
if (thd->current_stmt_binlog_row_based)
335
thd->clear_current_stmt_binlog_row_based();
337
rw_wrlock(&THR_LOCK_udf);
338
if ((hash_search(&udf_hash,(uchar*) udf->name.str, udf->name.length)))
340
my_error(ER_UDF_EXISTS, MYF(0), udf->name.str);
343
if (!(dl = find_udf_dl(udf->dl)))
345
char dlpath[FN_REFLEN];
346
strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", udf->dl, NullS);
347
if (!(dl = dlopen(dlpath, RTLD_NOW)))
349
my_error(ER_CANT_OPEN_LIBRARY, MYF(0),
350
udf->dl, errno, dlerror());
357
char buf[NAME_LEN+16], *missing;
358
if ((missing= init_syms(udf, buf)))
360
my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), missing);
364
udf->name.str=strdup_root(&mem,udf->name.str);
365
udf->dl=strdup_root(&mem,udf->dl);
366
if (!(u_d=add_udf(&udf->name,udf->returns,udf->dl,udf->type)))
370
u_d->func_init=udf->func_init;
371
u_d->func_deinit=udf->func_deinit;
372
u_d->func_clear=udf->func_clear;
373
u_d->func_add=udf->func_add;
375
/* create entry in mysql.func table */
377
bzero((char*) &tables,sizeof(tables));
378
tables.db= (char*) "mysql";
379
tables.table_name= tables.alias= (char*) "func";
380
/* Allow creation of functions even if we can't open func table */
381
if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
383
table->use_all_columns();
384
restore_record(table, s->default_values); // Default values for fields
385
table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info);
386
table->field[1]->store((longlong) u_d->returns, TRUE);
387
table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info);
388
if (table->s->fields >= 4) // If not old func format
389
table->field[3]->store((longlong) u_d->type, TRUE);
390
error = table->file->ha_write_row(table->record[0]);
394
my_error(ER_ERROR_ON_WRITE, MYF(0), "mysql.func", error);
398
rw_unlock(&THR_LOCK_udf);
400
/* Binlog the create function. */
401
write_bin_log(thd, TRUE, thd->query, thd->query_length);
408
rw_unlock(&THR_LOCK_udf);
413
int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
70
udf_func *find_udf(const char *name, uint length)
418
char *exact_name_str;
74
if (udf_startup == false)
77
udf= (udf_func*) hash_search(&udf_hash,
79
length ? length : (uint) strlen(name));
84
static bool add_udf(udf_func *udf)
86
if (my_hash_insert(&udf_hash, (uchar*) udf))
89
using_udf_functions= 1;
94
int initialize_udf(st_plugin_int *plugin)
98
if (udf_startup == false)
104
/* allocate the udf_func structure */
105
udff = (udf_func *)my_malloc(sizeof(udf_func), MYF(MY_WME | MY_ZEROFILL));
106
if (udff == NULL) return 1;
108
plugin->data= (void *)udff;
110
if (plugin->plugin->init)
112
/* todo, if the plugin doesnt have an init, bail out */
114
if (plugin->plugin->init((void *)udff))
116
sql_print_error("Plugin '%s' init function returned error.",
425
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
427
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
432
Turn off row binlogging of this statement and use statement-based
433
so that all supporting tables are updated for DROP FUNCTION command.
435
if (thd->current_stmt_binlog_row_based)
436
thd->clear_current_stmt_binlog_row_based();
438
rw_wrlock(&THR_LOCK_udf);
439
if (!(udf=(udf_func*) hash_search(&udf_hash,(uchar*) udf_name->str,
440
(uint) udf_name->length)))
442
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
445
exact_name_str= udf->name.str;
446
exact_name_len= udf->name.length;
449
Close the handle if this was function that was found during boot or
450
CREATE FUNCTION and it's not in use by any other udf function
452
if (udf->dlhandle && !find_udf_dl(udf->dl))
453
dlclose(udf->dlhandle);
455
bzero((char*) &tables,sizeof(tables));
456
tables.db=(char*) "mysql";
457
tables.table_name= tables.alias= (char*) "func";
458
if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
460
table->use_all_columns();
461
table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
462
if (!table->file->index_read_idx_map(table->record[0], 0,
463
(uchar*) table->field[0]->ptr,
468
if ((error = table->file->ha_delete_row(table->record[0])))
469
table->file->print_error(error, MYF(0));
471
close_thread_tables(thd);
473
rw_unlock(&THR_LOCK_udf);
475
/* Binlog the drop function. */
476
write_bin_log(thd, TRUE, thd->query, thd->query_length);
480
rw_unlock(&THR_LOCK_udf);
484
#endif /* HAVE_DLOPEN */
126
my_free(udff, MYF(0));
130
int finalize_udf(st_plugin_int *plugin)
132
udf_func *udff = (udf_func *)plugin->data;
134
/* TODO: Issue warning on failure */
135
if (udff && plugin->plugin->deinit)
136
(void)plugin->plugin->deinit(udff);
139
my_free(udff, MYF(0));