1 /* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
2
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.
6
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.
11
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
15
16 /* This implements 'user defined functions' */
17
18 /*
19 Known bugs:
20
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
24 a function.
25
26 The bugs only affect applications that create and free a lot of
27 dynamic functions, so this shouldn't be a real problem.
28 */
29
30 #ifdef USE_PRAGMA_IMPLEMENTATION
31 #pragma implementation // gcc: Class implementation
32 #endif
33
34 #include "mariadb.h"
35 #include "sql_priv.h"
36 #include "unireg.h"
37 #include "sql_base.h" // close_mysql_tables
38 #include "sql_parse.h" // check_identifier_name
39 #include "sql_table.h" // write_bin_log
40 #include "records.h" // init_read_record, end_read_record
41 #include <my_pthread.h>
42 #include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
43
44 #ifdef HAVE_DLOPEN
45 extern "C"
46 {
47 #include <stdarg.h>
48 #include <hash.h>
49 }
50
51 static bool initialized = 0;
52 static MEM_ROOT mem;
53 static HASH udf_hash;
54 static mysql_rwlock_t THR_LOCK_udf;
55 static LEX_CSTRING MYSQL_FUNC_NAME= {STRING_WITH_LEN("func") };
56
57 static udf_func *add_udf(LEX_CSTRING *name, Item_result ret,
58 const char *dl, Item_udftype typ);
59 static void del_udf(udf_func *udf);
60 static void *find_udf_dl(const char *dl);
61 static bool find_udf_everywhere(THD* thd, const LEX_CSTRING &name,
62 TABLE *table);
63
init_syms(udf_func * tmp,char * nm)64 static const char *init_syms(udf_func *tmp, char *nm)
65 {
66 char *end;
67
68 if (!((tmp->func= (Udf_func_any) dlsym(tmp->dlhandle, tmp->name.str))))
69 return tmp->name.str;
70
71 end=strmov(nm,tmp->name.str);
72
73 if (tmp->type == UDFTYPE_AGGREGATE)
74 {
75 (void)strmov(end, "_clear");
76 if (!((tmp->func_clear= (Udf_func_clear) dlsym(tmp->dlhandle, nm))))
77 return nm;
78 (void)strmov(end, "_add");
79 if (!((tmp->func_add= (Udf_func_add) dlsym(tmp->dlhandle, nm))))
80 return nm;
81 }
82
83 (void) strmov(end,"_deinit");
84 tmp->func_deinit= (Udf_func_deinit) dlsym(tmp->dlhandle, nm);
85
86 (void) strmov(end,"_init");
87 tmp->func_init= (Udf_func_init) dlsym(tmp->dlhandle, nm);
88
89 /*
90 to prefent loading "udf" from, e.g. libc.so
91 let's ensure that at least one auxiliary symbol is defined
92 */
93 if (!tmp->func_init && !tmp->func_deinit && tmp->type != UDFTYPE_AGGREGATE)
94 {
95 THD *thd= current_thd;
96 if (!opt_allow_suspicious_udfs)
97 return nm;
98 if (thd->variables.log_warnings)
99 sql_print_warning(ER_THD(thd, ER_CANT_FIND_DL_ENTRY), nm);
100 }
101 return 0;
102 }
103
104
get_hash_key(const uchar * buff,size_t * length,my_bool not_used)105 extern "C" uchar* get_hash_key(const uchar *buff, size_t *length,
106 my_bool not_used __attribute__((unused)))
107 {
108 udf_func *udf=(udf_func*) buff;
109 *length=(uint) udf->name.length;
110 return (uchar*) udf->name.str;
111 }
112
113 #ifdef HAVE_PSI_INTERFACE
114 static PSI_rwlock_key key_rwlock_THR_LOCK_udf;
115
116 static PSI_rwlock_info all_udf_rwlocks[]=
117 {
118 { &key_rwlock_THR_LOCK_udf, "THR_LOCK_udf", PSI_FLAG_GLOBAL}
119 };
120
init_udf_psi_keys(void)121 static void init_udf_psi_keys(void)
122 {
123 const char* category= "sql";
124 int count;
125
126 if (PSI_server == NULL)
127 return;
128
129 count= array_elements(all_udf_rwlocks);
130 PSI_server->register_rwlock(category, all_udf_rwlocks, count);
131 }
132 #endif
133
134 /*
135 Read all predeclared functions from mysql.func and accept all that
136 can be used.
137 */
138
udf_init()139 void udf_init()
140 {
141 udf_func *tmp;
142 TABLE_LIST tables;
143 READ_RECORD read_record_info;
144 TABLE *table;
145 int error;
146 DBUG_ENTER("ufd_init");
147
148 if (initialized || opt_noacl)
149 DBUG_VOID_RETURN;
150
151 #ifdef HAVE_PSI_INTERFACE
152 init_udf_psi_keys();
153 #endif
154
155 mysql_rwlock_init(key_rwlock_THR_LOCK_udf, &THR_LOCK_udf);
156
157 init_sql_alloc(&mem, "udf", UDF_ALLOC_BLOCK_SIZE, 0, MYF(0));
158 THD *new_thd = new THD(0);
159 if (!new_thd ||
160 my_hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
161 {
162 sql_print_error("Can't allocate memory for udf structures");
163 my_hash_free(&udf_hash);
164 free_root(&mem,MYF(0));
165 delete new_thd;
166 DBUG_VOID_RETURN;
167 }
168 initialized = 1;
169 new_thd->thread_stack= (char*) &new_thd;
170 new_thd->store_globals();
171 new_thd->set_db(&MYSQL_SCHEMA_NAME);
172
173 tables.init_one_table(&new_thd->db, &MYSQL_FUNC_NAME, 0, TL_READ);
174
175 if (open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
176 {
177 DBUG_PRINT("error",("Can't open udf table"));
178 sql_print_error("Can't open the mysql.func table. Please "
179 "run mysql_upgrade to create it.");
180 goto end;
181 }
182
183 table= tables.table;
184 if (init_read_record(&read_record_info, new_thd, table, NULL, NULL, 1, 0,
185 FALSE))
186 {
187 sql_print_error("Could not initialize init_read_record; udf's not "
188 "loaded");
189 goto end;
190 }
191
192 table->use_all_columns();
193 while (!(error= read_record_info.read_record()))
194 {
195 DBUG_PRINT("info",("init udf record"));
196 LEX_CSTRING name;
197 name.str=get_field(&mem, table->field[0]);
198 name.length = (uint) safe_strlen(name.str);
199 char *dl_name= get_field(&mem, table->field[2]);
200 bool new_dl=0;
201 Item_udftype udftype=UDFTYPE_FUNCTION;
202 if (table->s->fields >= 4) // New func table
203 udftype=(Item_udftype) table->field[3]->val_int();
204
205 /*
206 Ensure that the .dll doesn't have a path
207 This is done to ensure that only approved dll from the system
208 directories are used (to make this even remotely secure).
209
210 On windows we must check both FN_LIBCHAR and '/'.
211 */
212 if (!name.str || !dl_name || check_valid_path(dl_name, strlen(dl_name)) ||
213 check_string_char_length(&name, 0, NAME_CHAR_LEN,
214 system_charset_info, 1))
215 {
216 sql_print_error("Invalid row in mysql.func table for function '%.64s'",
217 safe_str(name.str));
218 continue;
219 }
220
221 if (!(tmp= add_udf(&name,(Item_result) table->field[1]->val_int(),
222 dl_name, udftype)))
223 {
224 sql_print_error("Can't alloc memory for udf function: '%.64s'", name.str);
225 continue;
226 }
227
228 void *dl = find_udf_dl(tmp->dl);
229 if (dl == NULL)
230 {
231 char dlpath[FN_REFLEN];
232 strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", tmp->dl, NullS);
233 (void) unpack_filename(dlpath, dlpath);
234 if (!(dl= dlopen(dlpath, RTLD_NOW)))
235 {
236 /* Print warning to log */
237 sql_print_error(ER_THD(new_thd, ER_CANT_OPEN_LIBRARY),
238 tmp->dl, errno, my_dlerror(dlpath));
239 /* Keep the udf in the hash so that we can remove it later */
240 continue;
241 }
242 new_dl=1;
243 }
244 tmp->dlhandle = dl;
245 {
246 char buf[SAFE_NAME_LEN+16];
247 const char *missing;
248 if ((missing= init_syms(tmp, buf)))
249 {
250 sql_print_error(ER_THD(new_thd, ER_CANT_FIND_DL_ENTRY), missing);
251 del_udf(tmp);
252 if (new_dl)
253 dlclose(dl);
254 }
255 }
256 }
257 if (unlikely(error > 0))
258 sql_print_error("Got unknown error: %d", my_errno);
259 end_read_record(&read_record_info);
260
261 // Force close to free memory
262 table->mark_table_for_reopen();
263
264 end:
265 close_mysql_tables(new_thd);
266 delete new_thd;
267 DBUG_VOID_RETURN;
268 }
269
270
udf_free()271 void udf_free()
272 {
273 /* close all shared libraries */
274 DBUG_ENTER("udf_free");
275 if (opt_noacl)
276 DBUG_VOID_RETURN;
277 for (uint idx=0 ; idx < udf_hash.records ; idx++)
278 {
279 udf_func *udf=(udf_func*) my_hash_element(&udf_hash,idx);
280 if (udf->dlhandle) // Not closed before
281 {
282 /* Mark all versions using the same handler as closed */
283 for (uint j=idx+1 ; j < udf_hash.records ; j++)
284 {
285 udf_func *tmp=(udf_func*) my_hash_element(&udf_hash,j);
286 if (udf->dlhandle == tmp->dlhandle)
287 tmp->dlhandle=0; // Already closed
288 }
289 dlclose(udf->dlhandle);
290 }
291 }
292 my_hash_free(&udf_hash);
293 free_root(&mem,MYF(0));
294 if (initialized)
295 {
296 initialized= 0;
297 mysql_rwlock_destroy(&THR_LOCK_udf);
298 }
299 DBUG_VOID_RETURN;
300 }
301
302
del_udf(udf_func * udf)303 static void del_udf(udf_func *udf)
304 {
305 DBUG_ENTER("del_udf");
306 if (!--udf->usage_count)
307 {
308 my_hash_delete(&udf_hash,(uchar*) udf);
309 using_udf_functions=udf_hash.records != 0;
310 }
311 else
312 {
313 /*
314 The functions is in use ; Rename the functions instead of removing it.
315 The functions will be automaticly removed when the least threads
316 doesn't use it anymore
317 */
318 const char *name= udf->name.str;
319 size_t name_length=udf->name.length;
320 udf->name.str= "*";
321 udf->name.length=1;
322 my_hash_update(&udf_hash,(uchar*) udf,(uchar*) name,name_length);
323 }
324 DBUG_VOID_RETURN;
325 }
326
327
free_udf(udf_func * udf)328 void free_udf(udf_func *udf)
329 {
330 DBUG_ENTER("free_udf");
331
332 if (!initialized)
333 DBUG_VOID_RETURN;
334
335 mysql_rwlock_wrlock(&THR_LOCK_udf);
336 if (!--udf->usage_count)
337 {
338 /*
339 We come here when someone has deleted the udf function
340 while another thread still was using the udf
341 */
342 my_hash_delete(&udf_hash,(uchar*) udf);
343 using_udf_functions=udf_hash.records != 0;
344 if (!find_udf_dl(udf->dl))
345 dlclose(udf->dlhandle);
346 }
347 mysql_rwlock_unlock(&THR_LOCK_udf);
348 DBUG_VOID_RETURN;
349 }
350
351
352 /* This is only called if using_udf_functions != 0 */
353
find_udf(const char * name,size_t length,bool mark_used)354 udf_func *find_udf(const char *name,size_t length,bool mark_used)
355 {
356 udf_func *udf=0;
357 DBUG_ENTER("find_udf");
358 DBUG_ASSERT(strlen(name) == length);
359
360 if (!initialized)
361 DBUG_RETURN(NULL);
362
363 DEBUG_SYNC(current_thd, "find_udf_before_lock");
364 /* TODO: This should be changed to reader locks someday! */
365 if (mark_used)
366 mysql_rwlock_wrlock(&THR_LOCK_udf); /* Called during fix_fields */
367 else
368 mysql_rwlock_rdlock(&THR_LOCK_udf); /* Called during parsing */
369
370 if ((udf=(udf_func*) my_hash_search(&udf_hash,(uchar*) name, length)))
371 {
372 if (!udf->dlhandle)
373 udf=0; // Could not be opened
374 else if (mark_used)
375 udf->usage_count++;
376 }
377 mysql_rwlock_unlock(&THR_LOCK_udf);
378 DBUG_RETURN(udf);
379 }
380
381
find_udf_dl(const char * dl)382 static void *find_udf_dl(const char *dl)
383 {
384 DBUG_ENTER("find_udf_dl");
385
386 /*
387 Because only the function name is hashed, we have to search trough
388 all rows to find the dl.
389 */
390 for (uint idx=0 ; idx < udf_hash.records ; idx++)
391 {
392 udf_func *udf=(udf_func*) my_hash_element(&udf_hash,idx);
393 if (!strcmp(dl, udf->dl) && udf->dlhandle != NULL)
394 DBUG_RETURN(udf->dlhandle);
395 }
396 DBUG_RETURN(0);
397 }
398
399
400 /* Assume that name && dl is already allocated */
401
add_udf(LEX_CSTRING * name,Item_result ret,const char * dl,Item_udftype type)402 static udf_func *add_udf(LEX_CSTRING *name, Item_result ret, const char *dl,
403 Item_udftype type)
404 {
405 if (!name || !dl || !(uint) type || (uint) type > (uint) UDFTYPE_AGGREGATE)
406 return 0;
407 udf_func *tmp= (udf_func*) alloc_root(&mem, sizeof(udf_func));
408 if (!tmp)
409 return 0;
410 bzero((char*) tmp,sizeof(*tmp));
411 tmp->name = *name; //dup !!
412 tmp->dl = dl;
413 tmp->returns = ret;
414 tmp->type = type;
415 tmp->usage_count=1;
416 if (my_hash_insert(&udf_hash,(uchar*) tmp))
417 return 0;
418 using_udf_functions=1;
419 return tmp;
420 }
421
422 /**
423 Find record with the udf in the udf func table
424
425 @param exact_name udf name
426 @param table table of mysql.func
427
428 @retval TRUE found
429 @retral FALSE not found
430 */
431
find_udf_in_table(const LEX_CSTRING & exact_name,TABLE * table)432 static bool find_udf_in_table(const LEX_CSTRING &exact_name, TABLE *table)
433 {
434 table->use_all_columns();
435 table->field[0]->store(exact_name.str, exact_name.length, &my_charset_bin);
436 return (!table->file->ha_index_read_idx_map(table->record[0], 0,
437 (uchar*) table->field[0]->ptr,
438 HA_WHOLE_KEY,
439 HA_READ_KEY_EXACT));
440 }
441
remove_udf_in_table(const LEX_CSTRING & exact_name,TABLE * table)442 static bool remove_udf_in_table(const LEX_CSTRING &exact_name, TABLE *table)
443 {
444 if (find_udf_in_table(exact_name, table))
445 {
446 int error;
447 if ((error= table->file->ha_delete_row(table->record[0])))
448 {
449 table->file->print_error(error, MYF(0));
450 return TRUE;
451 }
452 }
453 return FALSE;
454 }
455
456
457 /*
458 Drop user defined function.
459
460 @param thd Thread handler.
461 @param udf Existing udf_func pointer which is to be deleted.
462 @param table mysql.func table reference (opened and locked)
463
464 Assumption
465
466 - udf is not null.
467 - table is already opened and locked
468 */
mysql_drop_function_internal(THD * thd,udf_func * udf,TABLE * table)469 static int mysql_drop_function_internal(THD *thd, udf_func *udf, TABLE *table)
470 {
471 DBUG_ENTER("mysql_drop_function_internal");
472
473 const LEX_CSTRING exact_name= udf->name;
474
475 del_udf(udf);
476 /*
477 Close the handle if this was function that was found during boot or
478 CREATE FUNCTION and it's not in use by any other udf function
479 */
480 if (udf->dlhandle && !find_udf_dl(udf->dl))
481 dlclose(udf->dlhandle);
482
483 if (!table)
484 DBUG_RETURN(1);
485
486 bool ret= remove_udf_in_table(exact_name, table);
487 DBUG_RETURN(ret);
488 }
489
490
open_udf_func_table(THD * thd)491 static TABLE *open_udf_func_table(THD *thd)
492 {
493 TABLE_LIST tables;
494 tables.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_FUNC_NAME,
495 &MYSQL_FUNC_NAME, TL_WRITE);
496 return open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT);
497 }
498
499
500 /**
501 Create a user defined function.
502
503 @note Like implementations of other DDL/DML in MySQL, this function
504 relies on the caller to close the thread tables. This is done in the
505 end of dispatch_command().
506 */
507
mysql_create_function(THD * thd,udf_func * udf)508 int mysql_create_function(THD *thd,udf_func *udf)
509 {
510 int error;
511 void *dl=0;
512 bool new_dl=0;
513 TABLE *table;
514 TABLE_LIST tables;
515 udf_func *u_d;
516 DBUG_ENTER("mysql_create_function");
517
518 if (!initialized)
519 {
520 if (opt_noacl)
521 my_error(ER_CANT_INITIALIZE_UDF, MYF(0),
522 udf->name.str,
523 "UDFs are unavailable with the --skip-grant-tables option");
524 else
525 my_message(ER_OUT_OF_RESOURCES, ER_THD(thd, ER_OUT_OF_RESOURCES),
526 MYF(0));
527 DBUG_RETURN(1);
528 }
529
530 /*
531 Ensure that the .dll doesn't have a path
532 This is done to ensure that only approved dll from the system
533 directories are used (to make this even remotely secure).
534 */
535 if (check_valid_path(udf->dl, strlen(udf->dl)))
536 {
537 my_message(ER_UDF_NO_PATHS, ER_THD(thd, ER_UDF_NO_PATHS), MYF(0));
538 DBUG_RETURN(1);
539 }
540 if (check_ident_length(&udf->name))
541 DBUG_RETURN(1);
542
543 table= open_udf_func_table(thd);
544
545 mysql_rwlock_wrlock(&THR_LOCK_udf);
546 DEBUG_SYNC(current_thd, "mysql_create_function_after_lock");
547 if ((u_d= (udf_func*) my_hash_search(&udf_hash, (uchar*) udf->name.str,
548 udf->name.length)))
549 {
550 if (thd->lex->create_info.or_replace())
551 {
552 if (unlikely((error= mysql_drop_function_internal(thd, u_d, table))))
553 goto err;
554 }
555 else if (thd->lex->create_info.if_not_exists())
556 {
557 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UDF_EXISTS,
558 ER_THD(thd, ER_UDF_EXISTS), udf->name.str);
559
560 goto done;
561 }
562 else
563 {
564 my_error(ER_UDF_EXISTS, MYF(0), udf->name.str);
565 goto err;
566 }
567 }
568 if (!(dl = find_udf_dl(udf->dl)))
569 {
570 char dlpath[FN_REFLEN];
571 strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", udf->dl, NullS);
572 (void) unpack_filename(dlpath, dlpath);
573
574 if (!(dl = dlopen(dlpath, RTLD_NOW)))
575 {
576 my_error(ER_CANT_OPEN_LIBRARY, MYF(0),
577 udf->dl, errno, my_dlerror(dlpath));
578 DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)",
579 udf->dl, errno, dlerror()));
580 goto err;
581 }
582 new_dl=1;
583 }
584 udf->dlhandle=dl;
585 {
586 char buf[SAFE_NAME_LEN+16];
587 const char *missing;
588 if ((missing= init_syms(udf, buf)))
589 {
590 my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), missing);
591 goto err;
592 }
593 }
594 udf->name.str= strdup_root(&mem,udf->name.str);
595 udf->dl= strdup_root(&mem,udf->dl);
596 if (!(u_d=add_udf(&udf->name,udf->returns,udf->dl,udf->type)))
597 goto err;
598 u_d->dlhandle= dl;
599 u_d->func= udf->func;
600 u_d->func_init= udf->func_init;
601 u_d->func_deinit= udf->func_deinit;
602 u_d->func_clear= udf->func_clear;
603 u_d->func_add= udf->func_add;
604
605 /* create entry in mysql.func table */
606
607 /* Allow creation of functions even if we can't open func table */
608 if (unlikely(!table))
609 goto err;
610 table->use_all_columns();
611 restore_record(table, s->default_values); // Default values for fields
612 table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info);
613 table->field[1]->store((longlong) u_d->returns, TRUE);
614 table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info);
615 if (table->s->fields >= 4) // If not old func format
616 table->field[3]->store((longlong) u_d->type, TRUE);
617 error= table->file->ha_write_row(table->record[0]);
618
619 if (unlikely(error))
620 {
621 my_error(ER_ERROR_ON_WRITE, MYF(0), "mysql.func", error);
622 del_udf(u_d);
623 goto err;
624 }
625
626 done:
627 mysql_rwlock_unlock(&THR_LOCK_udf);
628
629 /* Binlog the create function. */
630 if (unlikely(write_bin_log(thd, TRUE, thd->query(), thd->query_length())))
631 DBUG_RETURN(1);
632
633 DBUG_RETURN(0);
634
635 err:
636 if (new_dl)
637 dlclose(dl);
638 mysql_rwlock_unlock(&THR_LOCK_udf);
639 DBUG_RETURN(1);
640 }
641
642
mysql_drop_function(THD * thd,const LEX_CSTRING * udf_name)643 enum drop_udf_result mysql_drop_function(THD *thd, const LEX_CSTRING *udf_name)
644 {
645 TABLE *table;
646 udf_func *udf;
647 DBUG_ENTER("mysql_drop_function");
648
649 if (thd->locked_tables_mode)
650 {
651 my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
652 DBUG_RETURN(UDF_DEL_RESULT_ERROR);
653 }
654
655 if (!(table= open_udf_func_table(thd)))
656 DBUG_RETURN(UDF_DEL_RESULT_ERROR);
657
658 // Fast pre-check
659 if (!mysql_rwlock_tryrdlock(&THR_LOCK_udf))
660 {
661 bool found= find_udf_everywhere(thd, *udf_name, table);
662 mysql_rwlock_unlock(&THR_LOCK_udf);
663 if (!found)
664 {
665 close_mysql_tables(thd);
666 DBUG_RETURN(UDF_DEL_RESULT_ABSENT);
667 }
668 }
669
670 if (!initialized)
671 {
672 close_mysql_tables(thd);
673 if (opt_noacl)
674 DBUG_RETURN(UDF_DEL_RESULT_ABSENT); // SP should be checked
675
676 my_message(ER_OUT_OF_RESOURCES, ER_THD(thd, ER_OUT_OF_RESOURCES), MYF(0));
677 DBUG_RETURN(UDF_DEL_RESULT_ERROR);
678 }
679
680 mysql_rwlock_wrlock(&THR_LOCK_udf);
681
682 // re-check under protection
683 if (!find_udf_everywhere(thd, *udf_name, table))
684 {
685 close_mysql_tables(thd);
686 mysql_rwlock_unlock(&THR_LOCK_udf);
687 DBUG_RETURN(UDF_DEL_RESULT_ABSENT);
688 }
689
690 if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 0))
691 goto err;
692
693
694 DEBUG_SYNC(current_thd, "mysql_drop_function_after_lock");
695
696 if (!(udf= (udf_func*) my_hash_search(&udf_hash, (uchar*) udf_name->str,
697 (uint) udf_name->length)) )
698 {
699 if (remove_udf_in_table(*udf_name, table))
700 goto err;
701 goto done;
702 }
703
704 if (mysql_drop_function_internal(thd, udf, table))
705 goto err;
706
707 done:
708 mysql_rwlock_unlock(&THR_LOCK_udf);
709
710 /*
711 Binlog the drop function. Keep the table open and locked
712 while binlogging, to avoid binlog inconsistency.
713 */
714 if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
715 DBUG_RETURN(UDF_DEL_RESULT_ERROR);
716
717 close_mysql_tables(thd);
718 DBUG_RETURN(UDF_DEL_RESULT_DELETED);
719
720 err:
721 close_mysql_tables(thd);
722 mysql_rwlock_unlock(&THR_LOCK_udf);
723 DBUG_RETURN(UDF_DEL_RESULT_ERROR);
724 }
725
find_udf_everywhere(THD * thd,const LEX_CSTRING & name,TABLE * table)726 static bool find_udf_everywhere(THD* thd, const LEX_CSTRING &name,
727 TABLE *table)
728 {
729 if (initialized && my_hash_search(&udf_hash, (uchar*) name.str, name.length))
730 return true;
731
732 return find_udf_in_table(name, table);
733 }
734
735 #endif /* HAVE_DLOPEN */
736