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

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2002 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. /*
  14. ** example file of UDF (user definable functions) that are dynamicly loaded
  15. ** into the standard mysqld core.
  16. **
  17. ** The functions name, type and shared library is saved in the new system
  18. ** table 'func'.  To be able to create new functions one must have write
  19. ** privilege for the database 'mysql'. If one starts MySQL with
  20. ** --skip-grant, then UDF initialization will also be skipped.
  21. **
  22. ** Syntax for the new commands are:
  23. ** create function <function_name> returns {string|real|integer}
  24. **   soname <name_of_shared_library>
  25. ** drop function <function_name>
  26. **
  27. ** Each defined function may have a xxxx_init function and a xxxx_deinit
  28. ** function.  The init function should alloc memory for the function
  29. ** and tell the main function about the max length of the result
  30. ** (for string functions), number of decimals (for double functions) and
  31. ** if the result may be a null value.
  32. **
  33. ** If a function sets the 'error' argument to 1 the function will not be
  34. ** called anymore and mysqld will return NULL for all calls to this copy
  35. ** of the function.
  36. **
  37. ** All strings arguments to functions are given as string pointer + length
  38. ** to allow handling of binary data.
  39. ** Remember that all functions must be thread safe. This means that one is not
  40. ** allowed to alloc any global or static variables that changes!
  41. ** If one needs memory one should alloc this in the init function and free
  42. ** this on the __deinit function.
  43. **
  44. ** Note that the init and __deinit functions are only called once per
  45. ** SQL statement while the value function may be called many times
  46. **
  47. ** Function 'metaphon' returns a metaphon string of the string argument.
  48. ** This is something like a soundex string, but it's more tuned for English.
  49. **
  50. ** Function 'myfunc_double' returns summary of codes of all letters
  51. ** of arguments divided by summary length of all its arguments.
  52. **
  53. ** Function 'myfunc_int' returns summary length of all its arguments.
  54. **
  55. ** Function 'sequence' returns an sequence starting from a certain number
  56. **
  57. ** On the end is a couple of functions that converts hostnames to ip and
  58. ** vice versa.
  59. **
  60. ** A dynamicly loadable file should be compiled shared.
  61. ** (something like: gcc -shared -o my_func.so myfunc.cc).
  62. ** You can easily get all switches right by doing:
  63. ** cd sql ; make udf_example.o
  64. ** Take the compile line that make writes, remove the '-c' near the end of
  65. ** the line and add -shared -o udf_example.so to the end of the compile line.
  66. ** The resulting library (udf_example.so) should be copied to some dir
  67. ** searched by ld. (/usr/lib ?)
  68. ** If you are using gcc, then you should be able to create the udf_example.so
  69. ** by simply doing 'make udf_example.so'.
  70. **
  71. ** After the library is made one must notify mysqld about the new
  72. ** functions with the commands:
  73. **
  74. ** CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
  75. ** CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
  76. ** CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
  77. ** CREATE FUNCTION sequence RETURNS INTEGER SONAME "udf_example.so";
  78. ** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
  79. ** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
  80. ** CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
  81. **
  82. ** After this the functions will work exactly like native MySQL functions.
  83. ** Functions should be created only once.
  84. **
  85. ** The functions can be deleted by:
  86. **
  87. ** DROP FUNCTION metaphon;
  88. ** DROP FUNCTION myfunc_double;
  89. ** DROP FUNCTION myfunc_int;
  90. ** DROP FUNCTION lookup;
  91. ** DROP FUNCTION reverse_lookup;
  92. ** DROP FUNCTION avgcost;
  93. **
  94. ** The CREATE FUNCTION and DROP FUNCTION update the func@mysql table. All
  95. ** Active function will be reloaded on every restart of server
  96. ** (if --skip-grant-tables is not given)
  97. **
  98. ** If you ge problems with undefined symbols when loading the shared
  99. ** library, you should verify that mysqld is compiled with the -rdynamic
  100. ** option.
  101. **
  102. ** If you can't get AGGREGATES to work, check that you have the column
  103. ** 'type' in the mysql.func table.  If not, run 'mysql_fix_privilege_tables'.
  104. **
  105. */
  106. #ifdef STANDARD
  107. #include <stdio.h>
  108. #include <string.h>
  109. #ifdef __WIN__
  110. typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */
  111. typedef __int64 longlong;
  112. #else
  113. typedef unsigned long long ulonglong;
  114. typedef long long longlong;
  115. #endif /*__WIN__*/
  116. #else
  117. #include <my_global.h>
  118. #include <my_sys.h>
  119. #endif
  120. #include <mysql.h>
  121. #include <m_ctype.h>
  122. #include <m_string.h> // To get strmov()
  123. static pthread_mutex_t LOCK_hostname;
  124. #ifdef HAVE_DLOPEN
  125. /* These must be right or mysqld will not find the symbol! */
  126. extern "C" {
  127. my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
  128. void metaphon_deinit(UDF_INIT *initid);
  129. char *metaphon(UDF_INIT *initid, UDF_ARGS *args, char *result,
  130.        unsigned long *length, char *is_null, char *error);
  131. my_bool myfunc_double_init(UDF_INIT *, UDF_ARGS *args, char *message);
  132. double myfunc_double(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
  133.      char *error);
  134. longlong myfunc_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
  135.     char *error);
  136. my_bool sequence_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
  137.  void sequence_deinit(UDF_INIT *initid);
  138. longlong sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
  139.    char *error);
  140. my_bool avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message );
  141. void avgcost_deinit( UDF_INIT* initid );
  142. void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
  143. void avgcost_clear( UDF_INIT* initid, char* is_null, char *error );
  144. void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
  145. double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
  146. }
  147. /*************************************************************************
  148. ** Example of init function
  149. ** Arguments:
  150. ** initid Points to a structure that the init function should fill.
  151. ** This argument is given to all other functions.
  152. ** my_bool maybe_null 1 if function can return NULL
  153. ** Default value is 1 if any of the arguments
  154. ** is declared maybe_null.
  155. ** unsigned int decimals Number of decimals.
  156. ** Default value is max decimals in any of the
  157. ** arguments.
  158. ** unsigned int max_length  Length of string result.
  159. ** The default value for integer functions is 21
  160. ** The default value for real functions is 13+
  161. ** default number of decimals.
  162. ** The default value for string functions is
  163. ** the longest string argument.
  164. ** char *ptr; A pointer that the function can use.
  165. **
  166. ** args Points to a structure which contains:
  167. ** unsigned int arg_count Number of arguments
  168. ** enum Item_result *arg_type Types for each argument.
  169. ** Types are STRING_RESULT, REAL_RESULT
  170. ** and INT_RESULT.
  171. ** char **args Pointer to constant arguments.
  172. ** Contains 0 for not constant argument.
  173. ** unsigned long *lengths; max string length for each argument
  174. ** char *maybe_null Information of which arguments
  175. ** may be NULL
  176. **
  177. ** message Error message that should be passed to the user on fail.
  178. ** The message buffer is MYSQL_ERRMSG_SIZE big, but one should
  179. ** try to keep the error message less than 80 bytes long!
  180. **
  181. ** This function should return 1 if something goes wrong. In this case
  182. ** message should contain something usefull!
  183. **************************************************************************/
  184. #define MAXMETAPH 8
  185. my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
  186. {
  187.   if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
  188.   {
  189.     strcpy(message,"Wrong arguments to metaphon;  Use the source");
  190.     return 1;
  191.   }
  192.   initid->max_length=MAXMETAPH;
  193.   return 0;
  194. }
  195. /****************************************************************************
  196. ** Deinit function. This should free all resources allocated by
  197. ** this function.
  198. ** Arguments:
  199. ** initid Return value from xxxx_init
  200. ****************************************************************************/
  201. void metaphon_deinit(UDF_INIT *initid)
  202. {
  203. }
  204. /***************************************************************************
  205. ** UDF string function.
  206. ** Arguments:
  207. ** initid Structure filled by xxx_init
  208. ** args The same structure as to xxx_init. This structure
  209. ** contains values for all parameters.
  210. ** Note that the functions MUST check and convert all
  211. ** to the type it wants!  Null values are represented by
  212. ** a NULL pointer
  213. ** result Possible buffer to save result. At least 255 byte long.
  214. ** length Pointer to length of the above buffer. In this the function
  215. ** should save the result length
  216. ** is_null If the result is null, one should store 1 here.
  217. ** error If something goes fatally wrong one should store 1 here.
  218. **
  219. ** This function should return a pointer to the result string.
  220. ** Normally this is 'result' but may also be an alloced string.
  221. ***************************************************************************/
  222. /* Character coding array */
  223. static char codes[26] =  {
  224.     1,16,4,16,9,2,4,16,9,2,0,2,2,2,1,4,0,2,4,4,1,0,0,0,8,0
  225.  /* A  B C  D E F G  H I J K L M N O P Q R S T U V W X Y Z*/
  226.     };
  227. /*--- Macros to access character coding array -------------*/
  228. #define ISVOWEL(x)  (codes[(x) - 'A'] & 1) /* AEIOU */
  229.     /* Following letters are not changed */
  230. #define NOCHANGE(x) (codes[(x) - 'A'] & 2) /* FJLMNR */
  231.     /* These form diphthongs when preceding H */
  232. #define AFFECTH(x) (codes[(x) - 'A'] & 4) /* CGPST */
  233.     /* These make C and G soft */
  234. #define MAKESOFT(x) (codes[(x) - 'A'] & 8) /* EIY */
  235.     /* These prevent GH from becoming F */
  236. #define NOGHTOF(x)  (codes[(x) - 'A'] & 16) /* BDH */
  237. char *metaphon(UDF_INIT *initid, UDF_ARGS *args, char *result,
  238.        unsigned long *length, char *is_null, char *error)
  239. {
  240.   const char *word=args->args[0];
  241.   if (!word) // Null argument
  242.   {
  243.     *is_null=1;
  244.     return 0;
  245.   }
  246.   const char *w_end=word+args->lengths[0];
  247.   char *org_result=result;
  248.   char *n, *n_start, *n_end; /* pointers to string */
  249.   char *metaph, *metaph_end; /* pointers to metaph */
  250.   char ntrans[32];      /* word with uppercase letters */
  251.   char newm[8];      /* new metaph for comparison */
  252.   int  KSflag;      /* state flag for X to KS */
  253.   /*--------------------------------------------------------
  254.    *  Copy word to internal buffer, dropping non-alphabetic
  255.    *  characters and converting to uppercase.
  256.    *-------------------------------------------------------*/
  257.   for (n = ntrans + 1, n_end = ntrans + sizeof(ntrans)-2;
  258. word != w_end && n < n_end; word++ )
  259.     if ( my_isalpha ( &my_charset_latin1, *word ))
  260.       *n++ = my_toupper ( &my_charset_latin1, *word );
  261.   if ( n == ntrans + 1 ) /* return empty string if 0 bytes */
  262.   {
  263.     *length=0;
  264.     return result;
  265.   }
  266.   n_end = n; /* set n_end to end of string */
  267.   ntrans[0] = 'Z'; /* ntrans[0] should be a neutral char */
  268.   n[0]=n[1]=0; /* pad with nulls */
  269.   n = ntrans + 1; /* assign pointer to start */
  270.   /*------------------------------------------------------------
  271.    *  check for all prefixes:
  272.    * PN KN GN AE WR WH and X at start.
  273.    *----------------------------------------------------------*/
  274.   switch ( *n ) {
  275.   case 'P':
  276.   case 'K':
  277.   case 'G':
  278.     if ( n[1] == 'N')
  279.       *n++ = 0;
  280.     break;
  281.   case 'A':
  282.     if ( n[1] == 'E')
  283.       *n++ = 0;
  284.     break;
  285.   case 'W':
  286.     if ( n[1] == 'R' )
  287.       *n++ = 0;
  288.     else
  289.       if ( *(n + 1) == 'H')
  290.       {
  291. n[1] = *n;
  292. *n++ = 0;
  293.       }
  294.     break;
  295.   case 'X':
  296.     *n = 'S';
  297.     break;
  298.   }
  299.   /*------------------------------------------------------------
  300.    *  Now, loop step through string, stopping at end of string
  301.    *  or when the computed metaph is MAXMETAPH characters long
  302.    *----------------------------------------------------------*/
  303.   KSflag = 0; /* state flag for KS translation */
  304.   for (metaph_end = result + MAXMETAPH, n_start = n;
  305. n <= n_end && result < metaph_end; n++ )
  306.   {
  307.     if ( KSflag )
  308.     {
  309.       KSflag = 0;
  310.       *result++ = *n;
  311.     }
  312.     else
  313.     {
  314.       /* drop duplicates except for CC */
  315.       if ( *( n - 1 ) == *n && *n != 'C' )
  316. continue;
  317.       /* check for F J L M N R or first letter vowel */
  318.       if ( NOCHANGE ( *n ) ||
  319.    ( n == n_start && ISVOWEL ( *n )))
  320. *result++ = *n;
  321.       else
  322. switch ( *n ) {
  323. case 'B':  /* check for -MB */
  324.   if ( n < n_end || *( n - 1 ) != 'M' )
  325.     *result++ = *n;
  326.   break;
  327. case 'C': /* C = X ("sh" sound) in CH and CIA */
  328.   /*   = S in CE CI and CY       */
  329.   /*  dropped in SCI SCE SCY       */
  330.   /* else K       */
  331.   if ( *( n - 1 ) != 'S' ||
  332.        !MAKESOFT ( n[1]))
  333.   {
  334.     if ( n[1] == 'I' && n[2] == 'A' )
  335.       *result++ = 'X';
  336.     else
  337.       if ( MAKESOFT ( n[1]))
  338. *result++ = 'S';
  339.       else
  340. if ( n[1] == 'H' )
  341.   *result++ = (( n == n_start &&
  342.  !ISVOWEL ( n[2])) ||
  343.        *( n - 1 ) == 'S' ) ?
  344.     (char)'K' : (char)'X';
  345. else
  346.   *result++ = 'K';
  347.   }
  348.   break;
  349. case 'D':  /* J before DGE, DGI, DGY, else T */
  350.   *result++ =
  351.     ( n[1] == 'G' &&
  352.       MAKESOFT ( n[2])) ?
  353.     (char)'J' : (char)'T';
  354.   break;
  355. case 'G':   /* complicated, see table in text */
  356.   if (( n[1] != 'H' || ISVOWEL ( n[2]))
  357.       && (
  358.   n[1] != 'N' ||
  359.   (
  360.    (n + 1) < n_end  &&
  361.    (
  362.     n[2] != 'E' ||
  363.     *( n + 3 ) != 'D'
  364.     )
  365.    )
  366.   )
  367.       && (
  368.   *( n - 1 ) != 'D' ||
  369.   !MAKESOFT ( n[1])
  370.   )
  371.       )
  372.     *result++ =
  373.       ( MAKESOFT ( *( n  + 1 )) &&
  374. n[2] != 'G' ) ?
  375.       (char)'J' : (char)'K';
  376.   else
  377.     if ( n[1] == 'H'   &&
  378. !NOGHTOF( *( n - 3 )) &&
  379. *( n - 4 ) != 'H')
  380.       *result++ = 'F';
  381.   break;
  382. case 'H':   /* H if before a vowel and not after */
  383.   /* C, G, P, S, T */
  384.   if ( !AFFECTH ( *( n - 1 )) &&
  385.        ( !ISVOWEL ( *( n - 1 )) ||
  386.  ISVOWEL ( n[1])))
  387.     *result++ = 'H';
  388.   break;
  389. case 'K':    /* K = K, except dropped after C */
  390.   if ( *( n - 1 ) != 'C')
  391.     *result++ = 'K';
  392.   break;
  393. case 'P':    /* PH = F, else P = P */
  394.   *result++ = *( n +  1 ) == 'H'
  395.     ? (char)'F' : (char)'P';
  396.   break;
  397. case 'Q':   /* Q = K (U after Q is already gone */
  398.   *result++ = 'K';
  399.   break;
  400. case 'S':   /* SH, SIO, SIA = X ("sh" sound) */
  401.   *result++ = ( n[1] == 'H' ||
  402. ( *(n  + 1) == 'I' &&
  403.   ( n[2] == 'O' ||
  404.     n[2] == 'A')))  ?
  405.     (char)'X' : (char)'S';
  406.   break;
  407. case 'T':  /* TIO, TIA = X ("sh" sound) */
  408.   /* TH = 0, ("th" sound ) */
  409.   if ( *( n  + 1 ) == 'I' && ( n[2] == 'O'
  410.       || n[2] == 'A') )
  411.     *result++ = 'X';
  412.   else
  413.     if ( n[1] == 'H' )
  414.       *result++ = '0';
  415.     else
  416.       if ( *( n + 1) != 'C' || n[2] != 'H')
  417. *result++ = 'T';
  418.   break;
  419. case 'V':     /* V = F */
  420.   *result++ = 'F';
  421.   break;
  422. case 'W':     /* only exist if a vowel follows */
  423. case 'Y':
  424.   if ( ISVOWEL ( n[1]))
  425.     *result++ = *n;
  426.   break;
  427. case 'X':     /* X = KS, except at start */
  428.   if ( n == n_start )
  429.     *result++ = 'S';
  430.   else
  431.   {
  432.     *result++ = 'K'; /* insert K, then S */
  433.     KSflag = 1; /* this flag will cause S to be
  434.    inserted on next pass thru loop */
  435.   }
  436.   break;
  437. case 'Z':
  438.   *result++ = 'S';
  439.   break;
  440. }
  441.     }
  442.   }
  443.   *length= (ulong) (result - org_result);
  444.   return org_result;
  445. }
  446. /***************************************************************************
  447. ** UDF double function.
  448. ** Arguments:
  449. ** initid Structure filled by xxx_init
  450. ** args The same structure as to xxx_init. This structure
  451. ** contains values for all parameters.
  452. ** Note that the functions MUST check and convert all
  453. ** to the type it wants!  Null values are represented by
  454. ** a NULL pointer
  455. ** is_null If the result is null, one should store 1 here.
  456. ** error If something goes fatally wrong one should store 1 here.
  457. **
  458. ** This function should return the result.
  459. ***************************************************************************/
  460. my_bool myfunc_double_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
  461. {
  462.   if (!args->arg_count)
  463.   {
  464.     strcpy(message,"myfunc_double must have at least on argument");
  465.     return 1;
  466.   }
  467.   /*
  468.   ** As this function wants to have everything as strings, force all arguments
  469.   ** to strings.
  470.   */
  471.   for (uint i=0 ; i < args->arg_count; i++)
  472.     args->arg_type[i]=STRING_RESULT;
  473.   initid->maybe_null=1; // The result may be null
  474.   initid->decimals=2; // We want 2 decimals in the result
  475.   initid->max_length=6; // 3 digits + . + 2 decimals
  476.   return 0;
  477. }
  478. double myfunc_double(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
  479.      char *error)
  480. {
  481.   unsigned long val = 0;
  482.   unsigned long v = 0;
  483.   for (uint i = 0; i < args->arg_count; i++)
  484.   {
  485.     if (args->args[i] == NULL)
  486.       continue;
  487.     val += args->lengths[i];
  488.     for (uint j=args->lengths[i] ; j-- > 0 ;)
  489.       v += args->args[i][j];
  490.   }
  491.   if (val)
  492.     return (double) v/ (double) val;
  493.   *is_null=1;
  494.   return 0.0;
  495. }
  496. /***************************************************************************
  497. ** UDF long long function.
  498. ** Arguments:
  499. ** initid Return value from xxxx_init
  500. ** args The same structure as to xxx_init. This structure
  501. ** contains values for all parameters.
  502. ** Note that the functions MUST check and convert all
  503. ** to the type it wants!  Null values are represented by
  504. ** a NULL pointer
  505. ** is_null If the result is null, one should store 1 here.
  506. ** error If something goes fatally wrong one should store 1 here.
  507. **
  508. ** This function should return the result as a long long
  509. ***************************************************************************/
  510. /* This function returns the sum of all arguments */
  511. longlong myfunc_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
  512.      char *error)
  513. {
  514.   longlong val = 0;
  515.   for (uint i = 0; i < args->arg_count; i++)
  516.   {
  517.     if (args->args[i] == NULL)
  518.       continue;
  519.     switch (args->arg_type[i]) {
  520.     case STRING_RESULT: // Add string lengths
  521.       val += args->lengths[i];
  522.       break;
  523.     case INT_RESULT: // Add numbers
  524.       val += *((longlong*) args->args[i]);
  525.       break;
  526.     case REAL_RESULT: // Add numers as longlong
  527.       val += (longlong) *((double*) args->args[i]);
  528.       break;
  529.     default:
  530.       break;
  531.     }
  532.   }
  533.   return val;
  534. }
  535. /*
  536.   Simple example of how to get a sequences starting from the first argument
  537.   or 1 if no arguments have been given
  538. */
  539. my_bool sequence_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
  540. {
  541.   if (args->arg_count > 1)
  542.   {
  543.     strmov(message,"This function takes none or 1 argument");
  544.     return 1;
  545.   }
  546.   if (args->arg_count)
  547.     args->arg_type[0]= INT_RESULT; // Force argument to int
  548.   if (!(initid->ptr=(char*) malloc(sizeof(longlong))))
  549.   {
  550.     strmov(message,"Couldn't allocate memory");
  551.     return 1;
  552.   }
  553.   bzero(initid->ptr,sizeof(longlong));
  554.   /*
  555.     Fool MySQL to think that this function is a constant
  556.     This will ensure that MySQL only evalutes the function
  557.     when the rows are sent to the client and not before any ORDER BY
  558.     clauses
  559.   */
  560.   initid->const_item=1;
  561.   return 0;
  562. }
  563. void sequence_deinit(UDF_INIT *initid)
  564. {
  565.   if (initid->ptr)
  566.     free(initid->ptr);
  567. }
  568. longlong sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
  569.    char *error)
  570. {
  571.   ulonglong val=0;
  572.   if (args->arg_count)
  573.     val= *((longlong*) args->args[0]);
  574.   return ++*((longlong*) initid->ptr) + val;
  575. }
  576. /****************************************************************************
  577. ** Some functions that handles IP and hostname conversions
  578. ** The orignal function was from Zeev Suraski.
  579. **
  580. ** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
  581. ** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
  582. **
  583. ****************************************************************************/
  584. #include <sys/socket.h>
  585. #include <netinet/in.h>
  586. #include <arpa/inet.h>
  587. #include <netdb.h>
  588. extern "C" {
  589. my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
  590. void lookup_deinit(UDF_INIT *initid);
  591. char *lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
  592.      unsigned long *length, char *null_value, char *error);
  593. my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
  594. void reverse_lookup_deinit(UDF_INIT *initid);
  595. char *reverse_lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
  596.      unsigned long *length, char *null_value, char *error);
  597. }
  598. /****************************************************************************
  599. ** lookup IP for an hostname.
  600. **
  601. ** This code assumes that gethostbyname_r exists and inet_ntoa() is thread
  602. ** safe (As it is in Solaris)
  603. ****************************************************************************/
  604. my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
  605. {
  606.   if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
  607.   {
  608.     strmov(message,"Wrong arguments to lookup;  Use the source");
  609.     return 1;
  610.   }
  611.   initid->max_length=11;
  612.   initid->maybe_null=1;
  613. #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
  614.   (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
  615. #endif
  616.   return 0;
  617. }
  618. void lookup_deinit(UDF_INIT *initid)
  619. {
  620. #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
  621.   (void) pthread_mutex_destroy(&LOCK_hostname);
  622. #endif
  623. }
  624. char *lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
  625.      unsigned long *res_length, char *null_value, char *error)
  626. {
  627.   uint length;
  628.   int tmp_errno;
  629.   char name_buff[256],hostname_buff[2048];
  630.   struct hostent tmp_hostent,*hostent;
  631.   if (!args->args[0] || !(length=args->lengths[0]))
  632.   {
  633.     *null_value=1;
  634.     return 0;
  635.   }
  636.   if (length >= sizeof(name_buff))
  637.     length=sizeof(name_buff)-1;
  638.   memcpy(name_buff,args->args[0],length);
  639.   name_buff[length]=0;
  640. #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  641.   if (!(hostent=gethostbyname_r(name_buff,&tmp_hostent,hostname_buff,
  642. sizeof(hostname_buff), &tmp_errno)))
  643.   {
  644.     *null_value=1;
  645.     return 0;
  646.   }
  647. #else
  648.   VOID(pthread_mutex_lock(&LOCK_hostname));
  649.   if (!(hostent= gethostbyname((char*) name_buff)))
  650.   {
  651.     VOID(pthread_mutex_unlock(&LOCK_hostname));
  652.     *null_value= 1;
  653.     return 0;
  654.   }
  655.   VOID(pthread_mutex_unlock(&LOCK_hostname));
  656. #endif
  657.   struct in_addr in;
  658.   memcpy_fixed((char*) &in,(char*) *hostent->h_addr_list, sizeof(in.s_addr));
  659.   *res_length= (ulong) (strmov(result, inet_ntoa(in)) - result);
  660.   return result;
  661. }
  662. /****************************************************************************
  663. ** return hostname for an IP number.
  664. ** The functions can take as arguments a string "xxx.xxx.xxx.xxx" or
  665. ** four numbers.
  666. ****************************************************************************/
  667. my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
  668. {
  669.   if (args->arg_count == 1)
  670.     args->arg_type[0]= STRING_RESULT;
  671.   else if (args->arg_count == 4)
  672.     args->arg_type[0]=args->arg_type[1]=args->arg_type[2]=args->arg_type[3]=
  673.       INT_RESULT;
  674.   else
  675.   {
  676.     strmov(message,
  677.    "Wrong number of arguments to reverse_lookup;  Use the source");
  678.     return 1;
  679.   }
  680.   initid->max_length=32;
  681.   initid->maybe_null=1;
  682. #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
  683.   (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
  684. #endif
  685.   return 0;
  686. }
  687. void reverse_lookup_deinit(UDF_INIT *initid) 
  688. {
  689. #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
  690.   (void) pthread_mutex_destroy(&LOCK_hostname);
  691. #endif
  692. }
  693. char *reverse_lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
  694.      unsigned long *res_length, char *null_value, char *error)
  695. {
  696.   char name_buff[256];
  697.   struct hostent tmp_hostent;
  698.   uint length;
  699.   if (args->arg_count == 4)
  700.   {
  701.     if (!args->args[0] || !args->args[1] ||!args->args[2] ||!args->args[3])
  702.     {
  703.       *null_value=1;
  704.       return 0;
  705.     }
  706.     sprintf(result,"%d.%d.%d.%d",
  707.     (int) *((longlong*) args->args[0]),
  708.     (int) *((longlong*) args->args[1]),
  709.     (int) *((longlong*) args->args[2]),
  710.     (int) *((longlong*) args->args[3]));
  711.   }
  712.   else
  713.   { // string argument
  714.     if (!args->args[0]) // Return NULL for NULL values
  715.     {
  716.       *null_value=1;
  717.       return 0;
  718.     }
  719.     length=args->lengths[0];
  720.     if (length >= (uint) *res_length-1)
  721.       length=(uint) *res_length;
  722.     memcpy(result,args->args[0],length);
  723.     result[length]=0;
  724.   }
  725.   unsigned long taddr = inet_addr(result);
  726.   if (taddr == (unsigned long) -1L)
  727.   {
  728.     *null_value=1;
  729.     return 0;
  730.   }
  731.   struct hostent *hp;
  732. #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  733.   int tmp_errno;
  734.   if (!(hp=gethostbyaddr_r((char*) &taddr,sizeof(taddr), AF_INET,
  735.    &tmp_hostent, name_buff,sizeof(name_buff),
  736.    &tmp_errno)))
  737.   {
  738.     *null_value=1;
  739.     return 0;
  740.   }
  741. #else
  742.   VOID(pthread_mutex_lock(&LOCK_hostname));
  743.   if (!(hp= gethostbyaddr((char*) &taddr, sizeof(taddr), AF_INET)))
  744.   {
  745.     VOID(pthread_mutex_unlock(&LOCK_hostname));
  746.     *null_value= 1;
  747.     return 0;
  748.   }
  749.   VOID(pthread_mutex_unlock(&LOCK_hostname));
  750. #endif
  751.   *res_length=(ulong) (strmov(result,hp->h_name) - result);
  752.   return result;
  753. }
  754. /*
  755. ** Syntax for the new aggregate commands are:
  756. ** create aggregate function <function_name> returns {string|real|integer}
  757. **   soname <name_of_shared_library>
  758. **
  759. ** Syntax for avgcost: avgcost( t.quantity, t.price )
  760. ** with t.quantity=integer, t.price=double
  761. ** (this example is provided by Andreas F. Bobak <bobak@relog.ch>)
  762. */
  763. struct avgcost_data
  764. {
  765.   ulonglong count;
  766.   longlong totalquantity;
  767.   double totalprice;
  768. };
  769. /*
  770. ** Average Cost Aggregate Function.
  771. */
  772. my_bool
  773. avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message )
  774. {
  775.   struct avgcost_data* data;
  776.   if (args->arg_count != 2)
  777.   {
  778.     strcpy(
  779.    message,
  780.    "wrong number of arguments: AVGCOST() requires two arguments"
  781.    );
  782.     return 1;
  783.   }
  784.   if ((args->arg_type[0] != INT_RESULT) || (args->arg_type[1] != REAL_RESULT) )
  785.   {
  786.     strcpy(
  787.    message,
  788.    "wrong argument type: AVGCOST() requires an INT and a REAL"
  789.    );
  790.     return 1;
  791.   }
  792.   /*
  793.   ** force arguments to double.
  794.   */
  795.   /*args->arg_type[0] = REAL_RESULT;
  796.     args->arg_type[1] = REAL_RESULT;*/
  797.   initid->maybe_null = 0; // The result may be null
  798.   initid->decimals = 4; // We want 4 decimals in the result
  799.   initid->max_length = 20; // 6 digits + . + 10 decimals
  800.   data = new struct avgcost_data;
  801.   data->totalquantity = 0;
  802.   data->totalprice = 0.0;
  803.   initid->ptr = (char*)data;
  804.   return 0;
  805. }
  806. void
  807. avgcost_deinit( UDF_INIT* initid )
  808. {
  809.   delete initid->ptr;
  810. }
  811. /* This is only for MySQL 4.0 compability */
  812. void
  813. avgcost_reset(UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message)
  814. {
  815.   avgcost_clear(initid, is_null, message);
  816.   avgcost_add(initid, args, is_null, message);
  817. }
  818. /* This is needed to get things to work in MySQL 4.1.1 and above */
  819. void
  820. avgcost_clear(UDF_INIT* initid, char* is_null, char* message)
  821. {
  822.   struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
  823.   data->totalprice= 0.0;
  824.   data->totalquantity= 0;
  825.   data->count= 0;
  826. }
  827. void
  828. avgcost_add(UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message)
  829. {
  830.   if (args->args[0] && args->args[1])
  831.   {
  832.     struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
  833.     longlong quantity = *((longlong*)args->args[0]);
  834.     longlong newquantity = data->totalquantity + quantity;
  835.     double price = *((double*)args->args[1]);
  836.     data->count++;
  837.     if (   ((data->totalquantity >= 0) && (quantity < 0))
  838.    || ((data->totalquantity <  0) && (quantity > 0)) )
  839.     {
  840.       /*
  841.       ** passing from + to - or from - to +
  842.       */
  843.       if (   ((quantity < 0) && (newquantity < 0))
  844.      || ((quantity > 0) && (newquantity > 0)) )
  845.       {
  846. data->totalprice = price * double(newquantity);
  847.       }
  848.       /*
  849.       ** sub q if totalq > 0
  850.       ** add q if totalq < 0
  851.       */
  852.       else
  853.       {
  854. price   = data->totalprice / double(data->totalquantity);
  855. data->totalprice  = price * double(newquantity);
  856.       }
  857.       data->totalquantity = newquantity;
  858.     }
  859.     else
  860.     {
  861.       data->totalquantity += quantity;
  862.       data->totalprice += price * double(quantity);
  863.     }
  864.     if (data->totalquantity == 0)
  865.       data->totalprice = 0.0;
  866.   }
  867. }
  868. double
  869. avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* error )
  870. {
  871.   struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
  872.   if (!data->count || !data->totalquantity)
  873.   {
  874.     *is_null = 1;
  875.     return 0.0;
  876.   }
  877.   *is_null = 0;
  878.   return data->totalprice/double(data->totalquantity);
  879. }
  880. #endif /* HAVE_DLOPEN */