mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / sql / sql_udf.cc
blobfd0d8391255bc10546c33f2b33471099a4a45c73
1 /*
2 Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 /* This implements 'user defined functions' */
21 Known bugs:
23 Memory for functions is never freed!
24 Shared libraries are not closed before mysqld exits;
25 - This is because we can't be sure if some threads are using
26 a function.
28 The bugs only affect applications that create and free a lot of
29 dynamic functions, so this shouldn't be a real problem.
32 #ifdef USE_PRAGMA_IMPLEMENTATION
33 #pragma implementation // gcc: Class implementation
34 #endif
36 #include "mysql_priv.h"
37 #include <my_pthread.h>
39 #ifdef HAVE_DLOPEN
40 extern "C"
42 #include <stdarg.h>
43 #include <hash.h>
46 static bool initialized = 0;
47 static MEM_ROOT mem;
48 static HASH udf_hash;
49 static rw_lock_t THR_LOCK_udf;
52 static udf_func *add_udf(LEX_STRING *name, Item_result ret,
53 char *dl, Item_udftype typ);
54 static void del_udf(udf_func *udf);
55 static void *find_udf_dl(const char *dl);
57 static char *init_syms(udf_func *tmp, char *nm)
59 char *end;
61 if (!((tmp->func= (Udf_func_any) dlsym(tmp->dlhandle, tmp->name.str))))
62 return tmp->name.str;
64 end=strmov(nm,tmp->name.str);
66 if (tmp->type == UDFTYPE_AGGREGATE)
68 (void)strmov(end, "_clear");
69 if (!((tmp->func_clear= (Udf_func_clear) dlsym(tmp->dlhandle, nm))))
70 return nm;
71 (void)strmov(end, "_add");
72 if (!((tmp->func_add= (Udf_func_add) dlsym(tmp->dlhandle, nm))))
73 return nm;
76 (void) strmov(end,"_deinit");
77 tmp->func_deinit= (Udf_func_deinit) dlsym(tmp->dlhandle, nm);
79 (void) strmov(end,"_init");
80 tmp->func_init= (Udf_func_init) dlsym(tmp->dlhandle, nm);
83 to prefent loading "udf" from, e.g. libc.so
84 let's ensure that at least one auxiliary symbol is defined
86 if (!tmp->func_init && !tmp->func_deinit && tmp->type != UDFTYPE_AGGREGATE)
88 if (!opt_allow_suspicious_udfs)
89 return nm;
90 if (current_thd->variables.log_warnings)
91 sql_print_warning(ER(ER_CANT_FIND_DL_ENTRY), nm);
93 return 0;
97 extern "C" uchar* get_hash_key(const uchar *buff, size_t *length,
98 my_bool not_used __attribute__((unused)))
100 udf_func *udf=(udf_func*) buff;
101 *length=(uint) udf->name.length;
102 return (uchar*) udf->name.str;
107 Read all predeclared functions from mysql.func and accept all that
108 can be used.
111 void udf_init()
113 udf_func *tmp;
114 TABLE_LIST tables;
115 READ_RECORD read_record_info;
116 TABLE *table;
117 int error;
118 DBUG_ENTER("ufd_init");
119 char db[]= "mysql"; /* A subject to casednstr, can't be constant */
121 if (initialized)
122 DBUG_VOID_RETURN;
124 my_rwlock_init(&THR_LOCK_udf,NULL);
126 init_sql_alloc(&mem, UDF_ALLOC_BLOCK_SIZE, 0);
127 THD *new_thd = new THD;
128 if (!new_thd ||
129 hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
131 sql_print_error("Can't allocate memory for udf structures");
132 hash_free(&udf_hash);
133 free_root(&mem,MYF(0));
134 delete new_thd;
135 DBUG_VOID_RETURN;
137 initialized = 1;
138 new_thd->thread_stack= (char*) &new_thd;
139 new_thd->store_globals();
140 lex_start(new_thd);
141 new_thd->set_db(db, sizeof(db)-1);
143 bzero((uchar*) &tables,sizeof(tables));
144 tables.alias= tables.table_name= (char*) "func";
145 tables.lock_type = TL_READ;
146 tables.db= db;
148 if (simple_open_n_lock_tables(new_thd, &tables))
150 DBUG_PRINT("error",("Can't open udf table"));
151 sql_print_error("Can't open the mysql.func table. Please "
152 "run mysql_upgrade to create it.");
153 goto end;
156 table= tables.table;
157 init_read_record(&read_record_info, new_thd, table, NULL,1,0,FALSE);
158 table->use_all_columns();
159 while (!(error= read_record_info.read_record(&read_record_info)))
161 DBUG_PRINT("info",("init udf record"));
162 LEX_STRING name;
163 name.str=get_field(&mem, table->field[0]);
164 name.length = (uint) strlen(name.str);
165 char *dl_name= get_field(&mem, table->field[2]);
166 bool new_dl=0;
167 Item_udftype udftype=UDFTYPE_FUNCTION;
168 if (table->s->fields >= 4) // New func table
169 udftype=(Item_udftype) table->field[3]->val_int();
172 Ensure that the .dll doesn't have a path
173 This is done to ensure that only approved dll from the system
174 directories are used (to make this even remotely secure).
176 On windows we must check both FN_LIBCHAR and '/'.
178 if (check_valid_path(dl_name, strlen(dl_name)) ||
179 check_string_char_length(&name, "", NAME_CHAR_LEN,
180 system_charset_info, 1))
182 sql_print_error("Invalid row in mysql.func table for function '%.64s'",
183 name.str);
184 continue;
187 if (!(tmp= add_udf(&name,(Item_result) table->field[1]->val_int(),
188 dl_name, udftype)))
190 sql_print_error("Can't alloc memory for udf function: '%.64s'", name.str);
191 continue;
194 void *dl = find_udf_dl(tmp->dl);
195 if (dl == NULL)
197 char dlpath[FN_REFLEN];
198 strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", tmp->dl,
199 NullS);
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 */
205 continue;
207 new_dl=1;
209 tmp->dlhandle = dl;
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);
215 del_udf(tmp);
216 if (new_dl)
217 dlclose(dl);
221 if (error > 0)
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
226 end:
227 close_thread_tables(new_thd);
228 delete new_thd;
229 /* Remember that we don't have a THD */
230 my_pthread_setspecific_ptr(THR_THD, 0);
231 DBUG_VOID_RETURN;
235 void udf_free()
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));
256 if (initialized)
258 initialized= 0;
259 rwlock_destroy(&THR_LOCK_udf);
261 DBUG_VOID_RETURN;
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;
273 else
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*) "*";
283 udf->name.length=1;
284 hash_update(&udf_hash,(uchar*) udf,(uchar*) name,name_length);
286 DBUG_VOID_RETURN;
290 void free_udf(udf_func *udf)
292 DBUG_ENTER("free_udf");
294 if (!initialized)
295 DBUG_VOID_RETURN;
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);
310 DBUG_VOID_RETURN;
314 /* This is only called if using_udf_functions != 0 */
316 udf_func *find_udf(const char *name,uint length,bool mark_used)
318 udf_func *udf=0;
319 DBUG_ENTER("find_udf");
321 if (!initialized)
322 DBUG_RETURN(NULL);
324 /* TODO: This should be changed to reader locks someday! */
325 if (mark_used)
326 rw_wrlock(&THR_LOCK_udf); /* Called during fix_fields */
327 else
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))))
333 if (!udf->dlhandle)
334 udf=0; // Could not be opened
335 else if (mark_used)
336 udf->usage_count++;
338 rw_unlock(&THR_LOCK_udf);
339 DBUG_RETURN(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);
357 DBUG_RETURN(0);
361 /* Assume that name && dl is already allocated */
363 static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
364 Item_udftype type)
366 if (!name || !dl || !(uint) type || (uint) type > (uint) UDFTYPE_AGGREGATE)
367 return 0;
368 udf_func *tmp= (udf_func*) alloc_root(&mem, sizeof(udf_func));
369 if (!tmp)
370 return 0;
371 bzero((char*) tmp,sizeof(*tmp));
372 tmp->name = *name; //dup !!
373 tmp->dl = dl;
374 tmp->returns = ret;
375 tmp->type = type;
376 tmp->usage_count=1;
377 if (my_hash_insert(&udf_hash,(uchar*) tmp))
378 return 0;
379 using_udf_functions=1;
380 return tmp;
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)
394 int error;
395 void *dl=0;
396 bool new_dl=0;
397 TABLE *table;
398 TABLE_LIST tables;
399 udf_func *u_d;
400 bool save_binlog_row_based;
401 DBUG_ENTER("mysql_create_function");
403 if (!initialized)
405 if (opt_noacl)
406 my_error(ER_CANT_INITIALIZE_UDF, MYF(0),
407 udf->name.str,
408 "UDFs are unavailable with the --skip-grant-tables option");
409 else
410 my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
411 DBUG_RETURN(1);
415 Ensure that the .dll doesn't have a path
416 This is done to ensure that only approved dll from the system
417 directories are used (to make this even remotely secure).
419 if (check_valid_path(udf->dl, strlen(udf->dl)))
421 my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0));
422 DBUG_RETURN(1);
424 if (check_string_char_length(&udf->name, "", NAME_CHAR_LEN,
425 system_charset_info, 1))
427 my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name.str);
428 DBUG_RETURN(1);
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 save_binlog_row_based= 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);
442 goto err;
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());
454 goto err;
456 new_dl=1;
458 udf->dlhandle=dl;
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);
464 goto err;
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)))
470 goto err;
471 u_d->dlhandle = dl;
472 u_d->func=udf->func;
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)))
485 goto err;
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]);
495 if (error)
497 my_error(ER_ERROR_ON_WRITE, MYF(0), "mysql.func", error);
498 del_udf(u_d);
499 goto err;
501 rw_unlock(&THR_LOCK_udf);
503 /* Binlog the create function. */
504 if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
506 /* Restore the state of binlog format */
507 thd->current_stmt_binlog_row_based= save_binlog_row_based;
508 DBUG_RETURN(1);
510 /* Restore the state of binlog format */
511 thd->current_stmt_binlog_row_based= save_binlog_row_based;
512 DBUG_RETURN(0);
514 err:
515 if (new_dl)
516 dlclose(dl);
517 rw_unlock(&THR_LOCK_udf);
518 /* Restore the state of binlog format */
519 thd->current_stmt_binlog_row_based= save_binlog_row_based;
520 DBUG_RETURN(1);
524 int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
526 TABLE *table;
527 TABLE_LIST tables;
528 udf_func *udf;
529 char *exact_name_str;
530 uint exact_name_len;
531 bool save_binlog_row_based;
532 DBUG_ENTER("mysql_drop_function");
534 if (!initialized)
536 if (opt_noacl)
537 my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
538 else
539 my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
540 DBUG_RETURN(1);
544 Turn off row binlogging of this statement and use statement-based
545 so that all supporting tables are updated for DROP FUNCTION command.
547 save_binlog_row_based= thd->current_stmt_binlog_row_based;
548 thd->clear_current_stmt_binlog_row_based();
550 rw_wrlock(&THR_LOCK_udf);
551 if (!(udf=(udf_func*) hash_search(&udf_hash,(uchar*) udf_name->str,
552 (uint) udf_name->length)))
554 my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
555 goto err;
557 exact_name_str= udf->name.str;
558 exact_name_len= udf->name.length;
559 del_udf(udf);
561 Close the handle if this was function that was found during boot or
562 CREATE FUNCTION and it's not in use by any other udf function
564 if (udf->dlhandle && !find_udf_dl(udf->dl))
565 dlclose(udf->dlhandle);
567 bzero((char*) &tables,sizeof(tables));
568 tables.db=(char*) "mysql";
569 tables.table_name= tables.alias= (char*) "func";
570 if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
571 goto err;
572 table->use_all_columns();
573 table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
574 if (!table->file->index_read_idx_map(table->record[0], 0,
575 (uchar*) table->field[0]->ptr,
576 HA_WHOLE_KEY,
577 HA_READ_KEY_EXACT))
579 int error;
580 if ((error = table->file->ha_delete_row(table->record[0])))
581 table->file->print_error(error, MYF(0));
583 close_thread_tables(thd);
585 rw_unlock(&THR_LOCK_udf);
587 /* Binlog the drop function. */
588 if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
590 /* Restore the state of binlog format */
591 thd->current_stmt_binlog_row_based= save_binlog_row_based;
592 DBUG_RETURN(1);
594 /* Restore the state of binlog format */
595 thd->current_stmt_binlog_row_based= save_binlog_row_based;
596 DBUG_RETURN(0);
597 err:
598 rw_unlock(&THR_LOCK_udf);
599 /* Restore the state of binlog format */
600 thd->current_stmt_binlog_row_based= save_binlog_row_based;
601 DBUG_RETURN(1);
604 #endif /* HAVE_DLOPEN */