home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / sql / udf_example.cpp < prev    next >
C/C++ Source or Header  |  2000-08-31  |  25KB  |  869 lines

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