sql_udf.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:14k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* This implements 'user defined functions' */
  14. /*
  15. ** Known bugs:
  16. **
  17. ** Memory for functions are never freed!
  18. ** Shared libraries are not closed before mysqld exists;
  19. **   - This is because we can't be sure if some threads is using
  20. **     a functions.
  21. **
  22. ** The buggs only affects applications that creates and frees a lot of
  23. ** dynamic functions, so this shouldn't be a real problem.
  24. */
  25. #ifdef USE_PRAGMA_IMPLEMENTATION
  26. #pragma implementation // gcc: Class implementation
  27. #endif
  28. #include "mysql_priv.h"
  29. #include <my_pthread.h>
  30. #ifdef HAVE_DLOPEN
  31. extern "C"
  32. {
  33. #if defined(__WIN__)
  34.   void* dlsym(void* lib,const char* name)
  35.   {
  36.     return GetProcAddress((HMODULE)lib,name);
  37.   }
  38.   void* dlopen(const char* libname,int unused)
  39.   {
  40.     return LoadLibraryEx(libname,NULL,0);
  41.   }
  42.   void dlclose(void* lib)
  43.   {
  44.     FreeLibrary((HMODULE)lib);
  45.   }
  46. #elif !defined(OS2)
  47. #include <dlfcn.h>
  48. #endif
  49. #include <stdarg.h>
  50. #include <hash.h>
  51. }
  52. #ifndef RTLD_NOW
  53. #define RTLD_NOW 1 // For FreeBSD 2.2.2
  54. #endif
  55. #ifndef HAVE_DLERROR
  56. #define dlerror() ""
  57. #endif
  58. static bool initialized = 0;
  59. static MEM_ROOT mem;
  60. static HASH udf_hash;
  61. static rw_lock_t THR_LOCK_udf;
  62. static udf_func *add_udf(LEX_STRING *name, Item_result ret,
  63.                          char *dl, Item_udftype typ);
  64. static void del_udf(udf_func *udf);
  65. static void *find_udf_dl(const char *dl);
  66. static char *init_syms(udf_func *tmp, char *nm)
  67. {
  68.   char *end;
  69.   if (!((tmp->func= dlsym(tmp->dlhandle, tmp->name.str))))
  70.     return tmp->name.str;
  71.   end=strmov(nm,tmp->name.str);
  72.   if (tmp->type == UDFTYPE_AGGREGATE)
  73.   {
  74.     (void)strmov(end, "_clear");
  75.     if (!((tmp->func_clear= dlsym(tmp->dlhandle, nm))))
  76.       return nm;
  77.     (void)strmov(end, "_add");
  78.     if (!((tmp->func_add= dlsym(tmp->dlhandle, nm))))
  79.       return nm;
  80.   }
  81.   (void) strmov(end,"_deinit");
  82.   tmp->func_deinit= dlsym(tmp->dlhandle, nm);
  83.   (void) strmov(end,"_init");
  84.   tmp->func_init= dlsym(tmp->dlhandle, nm);
  85.   /*
  86.     to prefent loading "udf" from, e.g. libc.so
  87.     let's ensure that at least one auxiliary symbol is defined
  88.   */
  89.   if (!tmp->func_init && !tmp->func_deinit && tmp->type != UDFTYPE_AGGREGATE)
  90.   {
  91.     if (opt_allow_suspicious_udfs)
  92.       sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), nm);
  93.     else
  94.       return nm;
  95.   }
  96.   return 0;
  97. }
  98. extern "C" byte* get_hash_key(const byte *buff,uint *length,
  99.       my_bool not_used __attribute__((unused)))
  100. {
  101.   udf_func *udf=(udf_func*) buff;
  102.   *length=(uint) udf->name.length;
  103.   return (byte*) udf->name.str;
  104. }
  105. /*
  106. ** Read all predeclared functions from mysql.func and accept all that
  107. ** can be used.
  108. */
  109. void udf_init()
  110. {
  111.   udf_func *tmp;
  112.   TABLE_LIST tables;
  113.   READ_RECORD read_record_info;
  114.   TABLE *table;
  115.   int error;
  116.   DBUG_ENTER("ufd_init");
  117.   if (initialized)
  118.     DBUG_VOID_RETURN;
  119.   my_rwlock_init(&THR_LOCK_udf,NULL);
  120.   
  121.   init_sql_alloc(&mem, UDF_ALLOC_BLOCK_SIZE, 0);
  122.   THD *new_thd = new THD;
  123.   if (!new_thd ||
  124.       hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
  125.   {
  126.     sql_print_error("Can't allocate memory for udf structures");
  127.     hash_free(&udf_hash);
  128.     free_root(&mem,MYF(0));
  129.     delete new_thd;
  130.     DBUG_VOID_RETURN;
  131.   }
  132.   initialized = 1;
  133.   new_thd->store_globals();
  134.   new_thd->db= my_strdup("mysql", MYF(0));
  135.   new_thd->db_length=5;
  136.   bzero((gptr) &tables,sizeof(tables));
  137.   tables.alias= tables.real_name= (char*) "func";
  138.   tables.lock_type = TL_READ;
  139.   tables.db=new_thd->db;
  140.   if (simple_open_n_lock_tables(new_thd, &tables))
  141.   {
  142.     DBUG_PRINT("error",("Can't open udf table"));
  143.     sql_print_error("Can't open the mysql.func table. Please run the mysql_install_db script to create it.");
  144.     goto end;
  145.   }
  146.   table= tables.table;
  147.   init_read_record(&read_record_info, new_thd, table, NULL,1,0);
  148.   while (!(error = read_record_info.read_record(&read_record_info)))
  149.   {
  150.     DBUG_PRINT("info",("init udf record"));
  151.     LEX_STRING name;
  152.     name.str=get_field(&mem, table->field[0]);
  153.     name.length = strlen(name.str);
  154.     char *dl_name= get_field(&mem, table->field[2]);
  155.     bool new_dl=0;
  156.     Item_udftype udftype=UDFTYPE_FUNCTION;
  157.     if (table->fields >= 4) // New func table
  158.       udftype=(Item_udftype) table->field[3]->val_int();
  159.     /*
  160.       Ensure that the .dll doesn't have a path
  161.       This is done to ensure that only approved dll from the system
  162.       directories are used (to make this even remotely secure).
  163.     */
  164.     if (strchr(dl_name, '/') ||
  165.         IF_WIN(strchr(dl_name, '\'),0) ||
  166.         strlen(name.str) > NAME_LEN)
  167.     {
  168.       sql_print_error("Invalid row in mysql.func table for function '%.64s'",
  169.                       name.str);
  170.       continue;
  171.     }
  172.     if (!(tmp= add_udf(&name,(Item_result) table->field[1]->val_int(),
  173.                        dl_name, udftype)))
  174.     {
  175.       sql_print_error("Can't alloc memory for udf function: '%.64s'", name.str);
  176.       continue;
  177.     }
  178.     void *dl = find_udf_dl(tmp->dl);
  179.     if (dl == NULL)
  180.     {
  181.       if (!(dl = dlopen(tmp->dl, RTLD_NOW)))
  182.       {
  183. /* Print warning to log */
  184. sql_print_error(ER(ER_CANT_OPEN_LIBRARY), tmp->dl,errno,dlerror());
  185. /* Keep the udf in the hash so that we can remove it later */
  186. continue;
  187.       }
  188.       new_dl=1;
  189.     }
  190.     tmp->dlhandle = dl;
  191.     {
  192.       char buf[NAME_LEN+16], *missing;
  193.       if ((missing= init_syms(tmp, buf)))
  194.       {
  195.         sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), missing);
  196.         del_udf(tmp);
  197.         if (new_dl)
  198.           dlclose(dl);
  199.       }
  200.     }
  201.   }
  202.   if (error > 0)
  203.     sql_print_error(ER(ER_GET_ERRNO), my_errno);
  204.   end_read_record(&read_record_info);
  205.   new_thd->version--; // Force close to free memory
  206. end:
  207.   close_thread_tables(new_thd);
  208.   delete new_thd;
  209.   /* Remember that we don't have a THD */
  210.   my_pthread_setspecific_ptr(THR_THD,  0);
  211.   DBUG_VOID_RETURN;
  212. }
  213. void udf_free()
  214. {
  215.   /* close all shared libraries */
  216.   DBUG_ENTER("udf_free");
  217.   for (uint idx=0 ; idx < udf_hash.records ; idx++)
  218.   {
  219.     udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
  220.     if (udf->dlhandle) // Not closed before
  221.     {
  222.       /* Mark all versions using the same handler as closed */
  223.       for (uint j=idx+1 ;  j < udf_hash.records ; j++)
  224.       {
  225. udf_func *tmp=(udf_func*) hash_element(&udf_hash,j);
  226. if (udf->dlhandle == tmp->dlhandle)
  227.   tmp->dlhandle=0; // Already closed
  228.       }
  229.       dlclose(udf->dlhandle);
  230.     }
  231.   }
  232.   hash_free(&udf_hash);
  233.   free_root(&mem,MYF(0));
  234.   if (initialized)
  235.   {
  236.     initialized= 0;
  237.     rwlock_destroy(&THR_LOCK_udf);
  238.   }
  239.   DBUG_VOID_RETURN;
  240. }
  241. static void del_udf(udf_func *udf)
  242. {
  243.   DBUG_ENTER("del_udf");
  244.   if (!--udf->usage_count)
  245.   {
  246.     hash_delete(&udf_hash,(byte*) udf);
  247.     using_udf_functions=udf_hash.records != 0;
  248.   }
  249.   else
  250.   {
  251.     /*
  252.       The functions is in use ; Rename the functions instead of removing it.
  253.       The functions will be automaticly removed when the least threads
  254.       doesn't use it anymore
  255.     */
  256.     char *name= udf->name.str;
  257.     uint name_length=udf->name.length;
  258.     udf->name.str=(char*) "*";
  259.     udf->name.length=1;
  260.     hash_update(&udf_hash,(byte*) udf,(byte*) name,name_length);
  261.   }
  262.   DBUG_VOID_RETURN;
  263. }
  264. void free_udf(udf_func *udf)
  265. {
  266.   DBUG_ENTER("free_udf");
  267.   rw_wrlock(&THR_LOCK_udf);
  268.   if (!--udf->usage_count)
  269.   {
  270.     /*
  271.       We come here when someone has deleted the udf function
  272.       while another thread still was using the udf
  273.     */
  274.     hash_delete(&udf_hash,(byte*) udf);
  275.     using_udf_functions=udf_hash.records != 0;
  276.     if (!find_udf_dl(udf->dl))
  277.       dlclose(udf->dlhandle);
  278.   }
  279.   rw_unlock(&THR_LOCK_udf);
  280.   DBUG_VOID_RETURN;
  281. }
  282. /* This is only called if using_udf_functions != 0 */
  283. udf_func *find_udf(const char *name,uint length,bool mark_used)
  284. {
  285.   udf_func *udf=0;
  286.   DBUG_ENTER("find_udf");
  287.   /* TODO: This should be changed to reader locks someday! */
  288.   if (mark_used)
  289.     rw_wrlock(&THR_LOCK_udf);  /* Called during fix_fields */
  290.   else
  291.     rw_rdlock(&THR_LOCK_udf);  /* Called during parsing */
  292.   if ((udf=(udf_func*) hash_search(&udf_hash,(byte*) name,
  293.    length ? length : (uint) strlen(name))))
  294.   {
  295.     if (!udf->dlhandle)
  296.       udf=0; // Could not be opened
  297.     else if (mark_used)
  298.       udf->usage_count++;
  299.   }
  300.   rw_unlock(&THR_LOCK_udf);
  301.   DBUG_RETURN(udf);
  302. }
  303. static void *find_udf_dl(const char *dl)
  304. {
  305.   DBUG_ENTER("find_udf_dl");
  306.   /*
  307.     Because only the function name is hashed, we have to search trough
  308.     all rows to find the dl.
  309.   */
  310.   for (uint idx=0 ; idx < udf_hash.records ; idx++)
  311.   {
  312.     udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
  313.     if (!strcmp(dl, udf->dl) && udf->dlhandle != NULL)
  314.       DBUG_RETURN(udf->dlhandle);
  315.   }
  316.   DBUG_RETURN(0);
  317. }
  318. /* Assume that name && dl is already allocated */
  319. static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
  320.  Item_udftype type)
  321. {
  322.   if (!name || !dl || !(uint) type || (uint) type > (uint) UDFTYPE_AGGREGATE)
  323.     return 0;
  324.   udf_func *tmp= (udf_func*) alloc_root(&mem, sizeof(udf_func));
  325.   if (!tmp)
  326.     return 0;
  327.   bzero((char*) tmp,sizeof(*tmp));
  328.   tmp->name = *name; //dup !!
  329.   tmp->dl = dl;
  330.   tmp->returns = ret;
  331.   tmp->type = type;
  332.   tmp->usage_count=1;
  333.   if (my_hash_insert(&udf_hash,(byte*)  tmp))
  334.     return 0;
  335.   using_udf_functions=1;
  336.   return tmp;
  337. }
  338. int mysql_create_function(THD *thd,udf_func *udf)
  339. {
  340.   int error;
  341.   void *dl=0;
  342.   bool new_dl=0;
  343.   TABLE *table;
  344.   TABLE_LIST tables;
  345.   udf_func *u_d;
  346.   DBUG_ENTER("mysql_create_function");
  347.   if (!initialized)
  348.   {
  349.     send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
  350.     DBUG_RETURN(1);
  351.   }
  352.   /*
  353.     Ensure that the .dll doesn't have a path
  354.     This is done to ensure that only approved dll from the system
  355.     directories are used (to make this even remotely secure).
  356.   */
  357.   if (strchr(udf->dl, '/') || IF_WIN(strchr(udf->dl, '\'),0))
  358.   {
  359.     send_error(thd, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS));
  360.     DBUG_RETURN(1);
  361.   }
  362.   if (udf->name.length > NAME_LEN)
  363.   {
  364.     net_printf(thd, ER_TOO_LONG_IDENT,udf->name);
  365.     DBUG_RETURN(1);
  366.   }
  367.   rw_wrlock(&THR_LOCK_udf);
  368.   if ((hash_search(&udf_hash,(byte*) udf->name.str, udf->name.length)))
  369.   {
  370.     net_printf(thd, ER_UDF_EXISTS, udf->name);
  371.     goto err;
  372.   }
  373.   if (!(dl = find_udf_dl(udf->dl)))
  374.   {
  375.     if (!(dl = dlopen(udf->dl, RTLD_NOW)))
  376.     {
  377.       DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)",
  378.   udf->dl,errno,dlerror()));
  379.       net_printf(thd, ER_CANT_OPEN_LIBRARY, udf->dl, errno, dlerror());
  380.       goto err;
  381.     }
  382.     new_dl=1;
  383.   }
  384.   udf->dlhandle=dl;
  385.   {
  386.     char buf[NAME_LEN+16], *missing;
  387.     if ((missing= init_syms(udf, buf)))
  388.     {
  389.       net_printf(thd, ER_CANT_FIND_DL_ENTRY, missing);
  390.       goto err;
  391.     }
  392.   }
  393.   udf->name.str=strdup_root(&mem,udf->name.str);
  394.   udf->dl=strdup_root(&mem,udf->dl);
  395.   if (!(u_d=add_udf(&udf->name,udf->returns,udf->dl,udf->type)))
  396.   {
  397.     send_error(thd,0); // End of memory
  398.     goto err;
  399.   }
  400.   u_d->dlhandle = dl;
  401.   u_d->func=udf->func;
  402.   u_d->func_init=udf->func_init;
  403.   u_d->func_deinit=udf->func_deinit;
  404.   u_d->func_clear=udf->func_clear;
  405.   u_d->func_add=udf->func_add;
  406.   /* create entry in mysql.func table */
  407.   bzero((char*) &tables,sizeof(tables));
  408.   tables.db= (char*) "mysql";
  409.   tables.real_name= tables.alias= (char*) "func";
  410.   /* Allow creation of functions even if we can't open func table */
  411.   if (!(table = open_ltable(thd,&tables,TL_WRITE)))
  412.     goto err;
  413.   restore_record(table,default_values); // Default values for fields
  414.   table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info);
  415.   table->field[1]->store((longlong) u_d->returns);
  416.   table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info);
  417.   if (table->fields >= 4) // If not old func format
  418.     table->field[3]->store((longlong) u_d->type);
  419.   error = table->file->write_row(table->record[0]);
  420.   close_thread_tables(thd);
  421.   if (error)
  422.   {
  423.     net_printf(thd, ER_ERROR_ON_WRITE, "mysql.func",error);
  424.     del_udf(u_d);
  425.     goto err;
  426.   }
  427.   rw_unlock(&THR_LOCK_udf);
  428.   DBUG_RETURN(0);
  429.  err:
  430.   if (new_dl)
  431.     dlclose(dl);
  432.   rw_unlock(&THR_LOCK_udf);
  433.   DBUG_RETURN(1);
  434. }
  435. int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
  436. {
  437.   TABLE *table;
  438.   TABLE_LIST tables;
  439.   udf_func *udf;
  440.   DBUG_ENTER("mysql_drop_function");
  441.   if (!initialized)
  442.   {
  443.     send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
  444.     DBUG_RETURN(1);
  445.   }
  446.   rw_wrlock(&THR_LOCK_udf);  
  447.   if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name->str,
  448.     (uint) udf_name->length)))
  449.   {
  450.     net_printf(thd, ER_FUNCTION_NOT_DEFINED, udf_name->str);
  451.     goto err;
  452.   }
  453.   del_udf(udf);
  454.   /*
  455.     Close the handle if this was function that was found during boot or
  456.     CREATE FUNCTION and it's not in use by any other udf function
  457.   */
  458.   if (udf->dlhandle && !find_udf_dl(udf->dl))
  459.     dlclose(udf->dlhandle);
  460.   bzero((char*) &tables,sizeof(tables));
  461.   tables.db=(char*) "mysql";
  462.   tables.real_name= tables.alias= (char*) "func";
  463.   if (!(table = open_ltable(thd,&tables,TL_WRITE)))
  464.     goto err;
  465.   table->field[0]->store(udf_name->str, udf_name->length, system_charset_info);
  466.   table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  467.   if (!table->file->index_read_idx(table->record[0], 0,
  468.    (byte*) table->field[0]->ptr,
  469.    table->key_info[0].key_length,
  470.    HA_READ_KEY_EXACT))
  471.   {
  472.     int error;
  473.     if ((error = table->file->delete_row(table->record[0])))
  474.       table->file->print_error(error, MYF(0));
  475.   }
  476.   close_thread_tables(thd);
  477.   rw_unlock(&THR_LOCK_udf);  
  478.   DBUG_RETURN(0);
  479.  err:
  480.   rw_unlock(&THR_LOCK_udf);
  481.   DBUG_RETURN(1);
  482. }
  483. #endif /* HAVE_DLOPEN */