1
/* Copyright (C) 2000 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/* This implements 'user defined functions' */
21
Memory for functions is never freed!
22
Shared libraries are not closed before mysqld exits;
23
- This is because we can't be sure if some threads are using
26
The bugs only affect applications that create and free a lot of
27
dynamic functions, so this shouldn't be a real problem.
30
#ifdef USE_PRAGMA_IMPLEMENTATION
31
#pragma implementation // gcc: Class implementation
34
#include "mysql_priv.h"
35
#include <my_pthread.h>
44
static bool initialized = 0;
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)
86
if (!opt_allow_suspicious_udfs)
88
if (current_thd->variables.log_warnings)
89
sql_print_warning(ER(ER_CANT_FIND_DL_ENTRY), nm);
95
extern "C" uchar* get_hash_key(const uchar *buff, size_t *length,
96
my_bool not_used __attribute__((unused)))
98
udf_func *udf=(udf_func*) buff;
99
*length=(uint) udf->name.length;
100
return (uchar*) udf->name.str;
105
Read all predeclared functions from mysql.func and accept all that
113
READ_RECORD read_record_info;
116
DBUG_ENTER("ufd_init");
117
char db[]= "mysql"; /* A subject to casednstr, can't be constant */
122
my_rwlock_init(&THR_LOCK_udf,NULL);
124
init_sql_alloc(&mem, UDF_ALLOC_BLOCK_SIZE, 0);
125
THD *new_thd = new THD;
127
hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
129
sql_print_error("Can't allocate memory for udf structures");
130
hash_free(&udf_hash);
131
free_root(&mem,MYF(0));
136
new_thd->thread_stack= (char*) &new_thd;
137
new_thd->store_globals();
139
new_thd->set_db(db, sizeof(db)-1);
141
bzero((uchar*) &tables,sizeof(tables));
142
tables.alias= tables.table_name= (char*) "func";
143
tables.lock_type = TL_READ;
146
if (simple_open_n_lock_tables(new_thd, &tables))
148
DBUG_PRINT("error",("Can't open udf table"));
149
sql_print_error("Can't open the mysql.func table. Please "
150
"run mysql_upgrade to create it.");
155
init_read_record(&read_record_info, new_thd, table, NULL,1,0);
156
table->use_all_columns();
157
while (!(error= read_record_info.read_record(&read_record_info)))
159
DBUG_PRINT("info",("init udf record"));
161
name.str=get_field(&mem, table->field[0]);
162
name.length = strlen(name.str);
163
char *dl_name= get_field(&mem, table->field[2]);
165
Item_udftype udftype=UDFTYPE_FUNCTION;
166
if (table->s->fields >= 4) // New func table
167
udftype=(Item_udftype) table->field[3]->val_int();
170
Ensure that the .dll doesn't have a path
171
This is done to ensure that only approved dll from the system
172
directories are used (to make this even remotely secure).
174
On windows we must check both FN_LIBCHAR and '/'.
176
if (my_strchr(files_charset_info, dl_name,
177
dl_name + strlen(dl_name), FN_LIBCHAR) ||
178
IF_WIN(my_strchr(files_charset_info, dl_name,
179
dl_name + strlen(dl_name), '/'), 0) ||
180
check_identifier_name(&name))
182
sql_print_error("Invalid row in mysql.func table for function '%.64s'",
187
if (!(tmp= add_udf(&name,(Item_result) table->field[1]->val_int(),
190
sql_print_error("Can't alloc memory for udf function: '%.64s'", name.str);
194
void *dl = find_udf_dl(tmp->dl);
197
char dlpath[FN_REFLEN];
198
strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", tmp->dl,
200
if (!(dl= dlopen(dlpath, RTLD_NOW)))
202
/* Print warning to log */
203
sql_print_error(ER(ER_CANT_OPEN_LIBRARY), tmp->dl, errno, dlerror());
204
/* Keep the udf in the hash so that we can remove it later */
211
char buf[NAME_LEN+16], *missing;
212
if ((missing= init_syms(tmp, buf)))
214
sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), missing);
222
sql_print_error("Got unknown error: %d", my_errno);
223
end_read_record(&read_record_info);
224
new_thd->version--; // Force close to free memory
227
close_thread_tables(new_thd);
229
/* Remember that we don't have a THD */
230
my_pthread_setspecific_ptr(THR_THD, 0);
237
/* close all shared libraries */
238
DBUG_ENTER("udf_free");
239
for (uint idx=0 ; idx < udf_hash.records ; idx++)
241
udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
242
if (udf->dlhandle) // Not closed before
244
/* Mark all versions using the same handler as closed */
245
for (uint j=idx+1 ; j < udf_hash.records ; j++)
247
udf_func *tmp=(udf_func*) hash_element(&udf_hash,j);
248
if (udf->dlhandle == tmp->dlhandle)
249
tmp->dlhandle=0; // Already closed
251
dlclose(udf->dlhandle);
254
hash_free(&udf_hash);
255
free_root(&mem,MYF(0));
259
rwlock_destroy(&THR_LOCK_udf);
265
static void del_udf(udf_func *udf)
267
DBUG_ENTER("del_udf");
268
if (!--udf->usage_count)
270
hash_delete(&udf_hash,(uchar*) udf);
271
using_udf_functions=udf_hash.records != 0;
276
The functions is in use ; Rename the functions instead of removing it.
277
The functions will be automaticly removed when the least threads
278
doesn't use it anymore
280
char *name= udf->name.str;
281
uint name_length=udf->name.length;
282
udf->name.str=(char*) "*";
284
hash_update(&udf_hash,(uchar*) udf,(uchar*) name,name_length);
290
void free_udf(udf_func *udf)
292
DBUG_ENTER("free_udf");
297
rw_wrlock(&THR_LOCK_udf);
298
if (!--udf->usage_count)
301
We come here when someone has deleted the udf function
302
while another thread still was using the udf
304
hash_delete(&udf_hash,(uchar*) udf);
305
using_udf_functions=udf_hash.records != 0;
306
if (!find_udf_dl(udf->dl))
307
dlclose(udf->dlhandle);
309
rw_unlock(&THR_LOCK_udf);
314
/* This is only called if using_udf_functions != 0 */
316
udf_func *find_udf(const char *name,uint length,bool mark_used)
319
DBUG_ENTER("find_udf");
324
/* TODO: This should be changed to reader locks someday! */
326
rw_wrlock(&THR_LOCK_udf); /* Called during fix_fields */
328
rw_rdlock(&THR_LOCK_udf); /* Called during parsing */
330
if ((udf=(udf_func*) hash_search(&udf_hash,(uchar*) name,
331
length ? length : (uint) strlen(name))))
334
udf=0; // Could not be opened
338
rw_unlock(&THR_LOCK_udf);
343
static void *find_udf_dl(const char *dl)
345
DBUG_ENTER("find_udf_dl");
348
Because only the function name is hashed, we have to search trough
349
all rows to find the dl.
351
for (uint idx=0 ; idx < udf_hash.records ; idx++)
353
udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
354
if (!strcmp(dl, udf->dl) && udf->dlhandle != NULL)
355
DBUG_RETURN(udf->dlhandle);
361
/* Assume that name && dl is already allocated */
363
static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
366
if (!name || !dl || !(uint) type || (uint) type > (uint) UDFTYPE_AGGREGATE)
368
udf_func *tmp= (udf_func*) alloc_root(&mem, sizeof(udf_func));
371
bzero((char*) tmp,sizeof(*tmp));
372
tmp->name = *name; //dup !!
377
if (my_hash_insert(&udf_hash,(uchar*) tmp))
379
using_udf_functions=1;
385
Create a user defined function.
387
@note Like implementations of other DDL/DML in MySQL, this function
388
relies on the caller to close the thread tables. This is done in the
389
end of dispatch_command().
392
int mysql_create_function(THD *thd,udf_func *udf)
400
DBUG_ENTER("mysql_create_function");
405
my_error(ER_CANT_INITIALIZE_UDF, MYF(0),
407
"UDFs are unavailable with the --skip-grant-tables option");
409
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
414
Ensure that the .dll doesn't have a path
415
This is done to ensure that only approved dll from the system
416
directories are used (to make this even remotely secure).
418
On windows we must check both FN_LIBCHAR and '/'.
420
if (my_strchr(files_charset_info, udf->dl,
421
udf->dl + strlen(udf->dl), FN_LIBCHAR) ||
422
IF_WIN(my_strchr(files_charset_info, udf->dl,
423
udf->dl + strlen(udf->dl), '/'), 0))
425
my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0));
428
if (check_identifier_name(&udf->name, ER_TOO_LONG_IDENT))
432
Turn off row binlogging of this statement and use statement-based
433
so that all supporting tables are updated for CREATE 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 ((hash_search(&udf_hash,(uchar*) udf->name.str, udf->name.length)))
441
my_error(ER_UDF_EXISTS, MYF(0), udf->name.str);
444
if (!(dl = find_udf_dl(udf->dl)))
446
char dlpath[FN_REFLEN];
447
strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", udf->dl, NullS);
448
if (!(dl = dlopen(dlpath, RTLD_NOW)))
450
DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)",
451
udf->dl, errno, dlerror()));
452
my_error(ER_CANT_OPEN_LIBRARY, MYF(0),
453
udf->dl, errno, dlerror());
460
char buf[NAME_LEN+16], *missing;
461
if ((missing= init_syms(udf, buf)))
463
my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), missing);
467
udf->name.str=strdup_root(&mem,udf->name.str);
468
udf->dl=strdup_root(&mem,udf->dl);
469
if (!(u_d=add_udf(&udf->name,udf->returns,udf->dl,udf->type)))
473
u_d->func_init=udf->func_init;
474
u_d->func_deinit=udf->func_deinit;
475
u_d->func_clear=udf->func_clear;
476
u_d->func_add=udf->func_add;
478
/* create entry in mysql.func table */
480
bzero((char*) &tables,sizeof(tables));
481
tables.db= (char*) "mysql";
482
tables.table_name= tables.alias= (char*) "func";
483
/* Allow creation of functions even if we can't open func table */
484
if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
486
table->use_all_columns();
487
restore_record(table, s->default_values); // Default values for fields
488
table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info);
489
table->field[1]->store((longlong) u_d->returns, TRUE);
490
table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info);
491
if (table->s->fields >= 4) // If not old func format
492
table->field[3]->store((longlong) u_d->type, TRUE);
493
error = table->file->ha_write_row(table->record[0]);
497
my_error(ER_ERROR_ON_WRITE, MYF(0), "mysql.func", error);
501
rw_unlock(&THR_LOCK_udf);
503
/* Binlog the create function. */
504
write_bin_log(thd, TRUE, thd->query, thd->query_length);
511
rw_unlock(&THR_LOCK_udf);
516
int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
521
char *exact_name_str;
523
DBUG_ENTER("mysql_drop_function");
528
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
530
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
535
Turn off row binlogging of this statement and use statement-based
536
so that all supporting tables are updated for DROP FUNCTION command.
538
if (thd->current_stmt_binlog_row_based)
539
thd->clear_current_stmt_binlog_row_based();
541
rw_wrlock(&THR_LOCK_udf);
542
if (!(udf=(udf_func*) hash_search(&udf_hash,(uchar*) udf_name->str,
543
(uint) udf_name->length)))
545
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
548
exact_name_str= udf->name.str;
549
exact_name_len= udf->name.length;
552
Close the handle if this was function that was found during boot or
553
CREATE FUNCTION and it's not in use by any other udf function
555
if (udf->dlhandle && !find_udf_dl(udf->dl))
556
dlclose(udf->dlhandle);
558
bzero((char*) &tables,sizeof(tables));
559
tables.db=(char*) "mysql";
560
tables.table_name= tables.alias= (char*) "func";
561
if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
563
table->use_all_columns();
564
table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
565
if (!table->file->index_read_idx_map(table->record[0], 0,
566
(uchar*) table->field[0]->ptr,
571
if ((error = table->file->ha_delete_row(table->record[0])))
572
table->file->print_error(error, MYF(0));
574
close_thread_tables(thd);
576
rw_unlock(&THR_LOCK_udf);
578
/* Binlog the drop function. */
579
write_bin_log(thd, TRUE, thd->query, thd->query_length);
583
rw_unlock(&THR_LOCK_udf);
587
#endif /* HAVE_DLOPEN */