"Fossies" - the Fresh Open Source Software Archive

Member "mysql-5.7.39/sql/udf_example.cc" (8 Jun 2022, 36110 Bytes) of package /linux/misc/mysql-5.7.39.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "udf_example.cc" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 8.0.29_vs_8.0.30.

    1 /* Copyright (c) 2000, 2022, 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, version 2.0,
    5    as published by the Free Software Foundation.
    6 
    7    This program is also distributed with certain software (including
    8    but not limited to OpenSSL) that is licensed under separate terms,
    9    as designated in a particular file or component or in included license
   10    documentation.  The authors of MySQL hereby grant you an additional
   11    permission to link the program and your derivative works with the
   12    separately licensed software that they have included with MySQL.
   13 
   14    This program is distributed in the hope that it will be useful,
   15    but WITHOUT ANY WARRANTY; without even the implied warranty of
   16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17    GNU General Public License, version 2.0, for more details.
   18 
   19    You should have received a copy of the GNU General Public License
   20    along with this program; if not, write to the Free Software
   21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
   22 
   23 /*
   24 ** example file of UDF (user definable functions) that are dynamicly loaded
   25 ** into the standard mysqld core.
   26 **
   27 ** The functions name, type and shared library is saved in the new system
   28 ** table 'func'.  To be able to create new functions one must have write
   29 ** privilege for the database 'mysql'.  If one starts MySQL with
   30 ** --skip-grant-tables, then UDF initialization will also be skipped.
   31 **
   32 ** Syntax for the new commands are:
   33 ** create function <function_name> returns {string|real|integer}
   34 **        soname <name_of_shared_library>
   35 ** drop function <function_name>
   36 **
   37 ** Each defined function may have a xxxx_init function and a xxxx_deinit
   38 ** function.  The init function should alloc memory for the function
   39 ** and tell the main function about the max length of the result
   40 ** (for string functions), number of decimals (for double functions) and
   41 ** if the result may be a null value.
   42 **
   43 ** If a function sets the 'error' argument to 1 the function will not be
   44 ** called anymore and mysqld will return NULL for all calls to this copy
   45 ** of the function.
   46 **
   47 ** All strings arguments to functions are given as string pointer + length
   48 ** to allow handling of binary data.
   49 ** Remember that all functions must be thread safe. This means that one is not
   50 ** allowed to alloc any global or static variables that changes!
   51 ** If one needs memory one should alloc this in the init function and free
   52 ** this on the __deinit function.
   53 **
   54 ** Note that the init and __deinit functions are only called once per
   55 ** SQL statement while the value function may be called many times
   56 **
   57 ** Function 'metaphon' returns a metaphon string of the string argument.
   58 ** This is something like a soundex string, but it's more tuned for English.
   59 **
   60 ** Function 'myfunc_double' returns summary of codes of all letters
   61 ** of arguments divided by summary length of all its arguments.
   62 **
   63 ** Function 'myfunc_int' returns summary length of all its arguments.
   64 **
   65 ** Function 'sequence' returns an sequence starting from a certain number.
   66 **
   67 ** Function 'myfunc_argument_name' returns name of argument.
   68 **
   69 ** On the end is a couple of functions that converts hostnames to ip and
   70 ** vice versa.
   71 **
   72 ** A dynamicly loadable file should be compiled shared.
   73 ** (something like: gcc -shared -o my_func.so myfunc.cc).
   74 ** You can easily get all switches right by doing:
   75 ** cd sql ; make udf_example.o
   76 ** Take the compile line that make writes, remove the '-c' near the end of
   77 ** the line and add -shared -o udf_example.so to the end of the compile line.
   78 ** The resulting library (udf_example.so) should be copied to some dir
   79 ** searched by ld. (/usr/lib ?)
   80 ** If you are using gcc, then you should be able to create the udf_example.so
   81 ** by simply doing 'make udf_example.so'.
   82 **
   83 ** After the library is made one must notify mysqld about the new
   84 ** functions with the commands:
   85 **
   86 ** CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
   87 ** CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
   88 ** CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
   89 ** CREATE FUNCTION sequence RETURNS INTEGER SONAME "udf_example.so";
   90 ** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
   91 ** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
   92 ** CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
   93 ** CREATE FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so";
   94 **
   95 ** After this the functions will work exactly like native MySQL functions.
   96 ** Functions should be created only once.
   97 **
   98 ** The functions can be deleted by:
   99 **
  100 ** DROP FUNCTION metaphon;
  101 ** DROP FUNCTION myfunc_double;
  102 ** DROP FUNCTION myfunc_int;
  103 ** DROP FUNCTION lookup;
  104 ** DROP FUNCTION reverse_lookup;
  105 ** DROP FUNCTION avgcost;
  106 ** DROP FUNCTION myfunc_argument_name;
  107 **
  108 ** The CREATE FUNCTION and DROP FUNCTION update the func@mysql table. All
  109 ** Active function will be reloaded on every restart of server
  110 ** (if --skip-grant-tables is not given)
  111 **
  112 ** If you ge problems with undefined symbols when loading the shared
  113 ** library, you should verify that mysqld is compiled with the -rdynamic
  114 ** option.
  115 **
  116 ** If you can't get AGGREGATES to work, check that you have the column
  117 ** 'type' in the mysql.func table.  If not, run 'mysql_upgrade'.
  118 **
  119 */
  120 
  121 #include <my_global.h>
  122 #include <my_sys.h>
  123 
  124 #include <new>
  125 #include <vector>
  126 #include <algorithm>
  127 
  128 #if defined(MYSQL_SERVER)
  129 #include <m_string.h>       /* To get my_stpcpy() */
  130 #else
  131 /* when compiled as standalone */
  132 #include <string.h>
  133 #define my_stpcpy(a,b) stpcpy(a,b)
  134 #endif
  135 
  136 #include <mysql.h>
  137 #include <ctype.h>
  138 
  139 #ifdef _WIN32
  140 /* inet_aton needs winsock library */
  141 #pragma comment(lib, "ws2_32")
  142 #endif
  143 
  144 #ifdef HAVE_DLOPEN
  145 
  146 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
  147 static native_mutex_t LOCK_hostname;
  148 #endif
  149 
  150 /* These must be right or mysqld will not find the symbol! */
  151 
  152 C_MODE_START;
  153 my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
  154 void metaphon_deinit(UDF_INIT *initid);
  155 char *metaphon(UDF_INIT *initid, UDF_ARGS *args, char *result,
  156            unsigned long *length, char *is_null, char *error);
  157 my_bool myfunc_double_init(UDF_INIT *, UDF_ARGS *args, char *message);
  158 double myfunc_double(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
  159              char *error);
  160 my_bool myfunc_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
  161 longlong myfunc_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
  162             char *error);
  163 my_bool sequence_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
  164  void sequence_deinit(UDF_INIT *initid);
  165 longlong sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
  166            char *error);
  167 my_bool avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message );
  168 void avgcost_deinit( UDF_INIT* initid );
  169 void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
  170 void avgcost_clear( UDF_INIT* initid, char* is_null, char *error );
  171 void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
  172 double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
  173 my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
  174 char *is_const(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long
  175                *length, char *is_null, char *error);
  176 C_MODE_END;
  177 
  178 /*************************************************************************
  179 ** Example of init function
  180 ** Arguments:
  181 ** initid   Points to a structure that the init function should fill.
  182 **      This argument is given to all other functions.
  183 **  my_bool maybe_null  1 if function can return NULL
  184 **              Default value is 1 if any of the arguments
  185 **              is declared maybe_null.
  186 **  unsigned int decimals   Number of decimals.
  187 **              Default value is max decimals in any of the
  188 **              arguments.
  189 **  unsigned int max_length  Length of string result.
  190 **              The default value for integer functions is 21
  191 **              The default value for real functions is 13+
  192 **              default number of decimals.
  193 **              The default value for string functions is
  194 **              the longest string argument.
  195 **  char *ptr;      A pointer that the function can use.
  196 **
  197 ** args     Points to a structure which contains:
  198 **  unsigned int arg_count      Number of arguments
  199 **  enum Item_result *arg_type  Types for each argument.
  200 **                  Types are STRING_RESULT, REAL_RESULT
  201 **                  and INT_RESULT.
  202 **  char **args         Pointer to constant arguments.
  203 **                  Contains 0 for not constant argument.
  204 **  unsigned long *lengths;     max string length for each argument
  205 **  char *maybe_null        Information of which arguments
  206 **                  may be NULL
  207 **
  208 ** message  Error message that should be passed to the user on fail.
  209 **      The message buffer is MYSQL_ERRMSG_SIZE big, but one should
  210 **      try to keep the error message less than 80 bytes long!
  211 **
  212 ** This function should return 1 if something goes wrong. In this case
  213 ** message should contain something usefull!
  214 **************************************************************************/
  215 
  216 #define MAXMETAPH 8
  217 
  218 my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
  219 {
  220   if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
  221   {
  222     strcpy(message,"Wrong arguments to metaphon;  Use the source");
  223     return 1;
  224   }
  225   initid->max_length=MAXMETAPH;
  226   return 0;
  227 }
  228 
  229 /****************************************************************************
  230 ** Deinit function. This should free all resources allocated by
  231 ** this function.
  232 ** Arguments:
  233 ** initid   Return value from xxxx_init
  234 ****************************************************************************/
  235 
  236 
  237 void metaphon_deinit(UDF_INIT *initid MY_ATTRIBUTE((unused)))
  238 {
  239 }
  240 
  241 /***************************************************************************
  242 ** UDF string function.
  243 ** Arguments:
  244 ** initid   Structure filled by xxx_init
  245 ** args     The same structure as to xxx_init. This structure
  246 **      contains values for all parameters.
  247 **      Note that the functions MUST check and convert all
  248 **      to the type it wants!  Null values are represented by
  249 **      a NULL pointer
  250 ** result   Possible buffer to save result. At least 255 byte long.
  251 ** length   Pointer to length of the above buffer.  In this the function
  252 **      should save the result length
  253 ** is_null  If the result is null, one should store 1 here.
  254 ** error    If something goes fatally wrong one should store 1 here.
  255 **
  256 ** This function should return a pointer to the result string.
  257 ** Normally this is 'result' but may also be an alloced string.
  258 ***************************************************************************/
  259 
  260 /* Character coding array */
  261 static char codes[26] =  {
  262     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
  263  /* 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*/
  264     };
  265 
  266 /*--- Macros to access character coding array -------------*/
  267 
  268 #define ISVOWEL(x)  (codes[(x) - 'A'] & 1)  /* AEIOU */
  269 
  270     /* Following letters are not changed */
  271 #define NOCHANGE(x) (codes[(x) - 'A'] & 2)  /* FJLMNR */
  272 
  273     /* These form diphthongs when preceding H */
  274 #define AFFECTH(x) (codes[(x) - 'A'] & 4)   /* CGPST */
  275 
  276     /* These make C and G soft */
  277 #define MAKESOFT(x) (codes[(x) - 'A'] & 8)  /* EIY */
  278 
  279     /* These prevent GH from becoming F */
  280 #define NOGHTOF(x)  (codes[(x) - 'A'] & 16) /* BDH */
  281 
  282 
  283 char *metaphon(UDF_INIT *initid MY_ATTRIBUTE((unused)),
  284                UDF_ARGS *args, char *result, unsigned long *length,
  285                char *is_null, char *error MY_ATTRIBUTE((unused)))
  286 {
  287   const char *word=args->args[0];
  288   const char *w_end;
  289   char *org_result;
  290   char *n, *n_start, *n_end; /* pointers to string */
  291   char *metaph_end;      /* pointers to end of metaph */
  292   char ntrans[32];       /* word with uppercase letters */
  293   int  KSflag;           /* state flag for X to KS */
  294 
  295   if (!word)                    /* Null argument */
  296   {
  297     /* The length is expected to be zero when the argument is NULL. */
  298     assert(args->lengths[0] == 0);
  299     *is_null=1;
  300     return 0;
  301   }
  302 
  303   w_end=word+args->lengths[0];
  304   org_result=result;
  305 
  306   /*--------------------------------------------------------
  307    *  Copy word to internal buffer, dropping non-alphabetic
  308    *  characters and converting to uppercase.
  309    *-------------------------------------------------------*/
  310 
  311   for (n = ntrans + 1, n_end = ntrans + sizeof(ntrans)-2;
  312     word != w_end && n < n_end; word++ )
  313     if ( isalpha ( *word ))
  314       *n++ = toupper ( *word );
  315 
  316   if ( n == ntrans + 1 )    /* return empty string if 0 bytes */
  317   {
  318     *length=0;
  319     return result;
  320   }
  321   n_end = n;            /* set n_end to end of string */
  322   ntrans[0] = 'Z';      /* ntrans[0] should be a neutral char */
  323   n[0]=n[1]=0;          /* pad with nulls */
  324   n = ntrans + 1;       /* assign pointer to start */
  325 
  326   /*------------------------------------------------------------
  327    *  check for all prefixes:
  328    *        PN KN GN AE WR WH and X at start.
  329    *----------------------------------------------------------*/
  330 
  331   switch ( *n ) {
  332   case 'P':
  333   case 'K':
  334   case 'G':
  335     if ( n[1] == 'N')
  336       *n++ = 0;
  337     break;
  338   case 'A':
  339     if ( n[1] == 'E')
  340       *n++ = 0;
  341     break;
  342   case 'W':
  343     if ( n[1] == 'R' )
  344       *n++ = 0;
  345     else
  346       if ( *(n + 1) == 'H')
  347       {
  348     n[1] = *n;
  349     *n++ = 0;
  350       }
  351     break;
  352   case 'X':
  353     *n = 'S';
  354     break;
  355   }
  356 
  357   /*------------------------------------------------------------
  358    *  Now, loop step through string, stopping at end of string
  359    *  or when the computed metaph is MAXMETAPH characters long
  360    *----------------------------------------------------------*/
  361 
  362   KSflag = 0; /* state flag for KS translation */
  363 
  364   for (metaph_end = result + MAXMETAPH, n_start = n;
  365     n < n_end && result < metaph_end; n++ )
  366   {
  367 
  368     if ( KSflag )
  369     {
  370       KSflag = 0;
  371       *result++ = *n;
  372     }
  373     else
  374     {
  375       /* drop duplicates except for CC */
  376       if ( *( n - 1 ) == *n && *n != 'C' )
  377     continue;
  378 
  379       /* check for F J L M N R or first letter vowel */
  380       if ( NOCHANGE ( *n ) ||
  381        ( n == n_start && ISVOWEL ( *n )))
  382     *result++ = *n;
  383       else
  384     switch ( *n ) {
  385     case 'B':    /* check for -MB */
  386       if ( n < n_end || *( n - 1 ) != 'M' )
  387         *result++ = *n;
  388       break;
  389 
  390     case 'C': /* C = X ("sh" sound) in CH and CIA */
  391       /*   = S in CE CI and CY        */
  392       /*     dropped in SCI SCE SCY       */
  393       /* else K               */
  394       if ( *( n - 1 ) != 'S' ||
  395            !MAKESOFT ( n[1]))
  396       {
  397         if ( n[1] == 'I' && n[2] == 'A' )
  398           *result++ = 'X';
  399         else
  400           if ( MAKESOFT ( n[1]))
  401         *result++ = 'S';
  402           else
  403         if ( n[1] == 'H' )
  404           *result++ = (( n == n_start &&
  405                  !ISVOWEL ( n[2])) ||
  406                    *( n - 1 ) == 'S' ) ?
  407             'K' : 'X';
  408         else
  409           *result++ = 'K';
  410       }
  411       break;
  412 
  413     case 'D':  /* J before DGE, DGI, DGY, else T */
  414       *result++ =
  415         ( n[1] == 'G' &&
  416           MAKESOFT ( n[2])) ?
  417         'J' : 'T';
  418       break;
  419 
  420     case 'G':   /* complicated, see table in text */
  421       if (( n[1] != 'H' || ISVOWEL ( n[2]))
  422           && (
  423           n[1] != 'N' ||
  424           (
  425            (n + 1) < n_end  &&
  426            (
  427             n[2] != 'E' ||
  428             *( n + 3 ) != 'D'
  429             )
  430            )
  431           )
  432           && (
  433           *( n - 1 ) != 'D' ||
  434           !MAKESOFT ( n[1])
  435           )
  436           )
  437         *result++ =
  438           ( MAKESOFT ( *( n  + 1 )) &&
  439         n[2] != 'G' ) ?
  440           'J' : 'K';
  441       else
  442         if ( n[1] == 'H'   &&
  443         !NOGHTOF( *( n - 3 )) &&
  444         *( n - 4 ) != 'H')
  445           *result++ = 'F';
  446       break;
  447 
  448     case 'H':   /* H if before a vowel and not after */
  449       /* C, G, P, S, T */
  450 
  451       if ( !AFFECTH ( *( n - 1 )) &&
  452            ( !ISVOWEL ( *( n - 1 )) ||
  453          ISVOWEL ( n[1])))
  454         *result++ = 'H';
  455       break;
  456 
  457     case 'K':    /* K = K, except dropped after C */
  458       if ( *( n - 1 ) != 'C')
  459         *result++ = 'K';
  460       break;
  461 
  462     case 'P':    /* PH = F, else P = P */
  463       *result++ = *( n +  1 ) == 'H'
  464         ? 'F' : 'P';
  465       break;
  466     case 'Q':   /* Q = K (U after Q is already gone */
  467       *result++ = 'K';
  468       break;
  469 
  470     case 'S':   /* SH, SIO, SIA = X ("sh" sound) */
  471       *result++ = ( n[1] == 'H' ||
  472             ( *(n  + 1) == 'I' &&
  473               ( n[2] == 'O' ||
  474                 n[2] == 'A')))  ?
  475         'X' : 'S';
  476       break;
  477 
  478     case 'T':  /* TIO, TIA = X ("sh" sound) */
  479       /* TH = 0, ("th" sound ) */
  480       if ( *( n  + 1 ) == 'I' && ( n[2] == 'O'
  481                       || n[2] == 'A') )
  482         *result++ = 'X';
  483       else
  484         if ( n[1] == 'H' )
  485           *result++ = '0';
  486         else
  487           if ( *( n + 1) != 'C' || n[2] != 'H')
  488         *result++ = 'T';
  489       break;
  490 
  491     case 'V':     /* V = F */
  492       *result++ = 'F';
  493       break;
  494 
  495     case 'W':     /* only exist if a vowel follows */
  496     case 'Y':
  497       if ( ISVOWEL ( n[1]))
  498         *result++ = *n;
  499       break;
  500 
  501     case 'X':     /* X = KS, except at start */
  502       if ( n == n_start )
  503         *result++ = 'S';
  504       else
  505       {
  506         *result++ = 'K'; /* insert K, then S */
  507         KSflag = 1; /* this flag will cause S to be
  508                inserted on next pass thru loop */
  509       }
  510       break;
  511 
  512     case 'Z':
  513       *result++ = 'S';
  514       break;
  515     }
  516     }
  517   }
  518   *length= (unsigned long) (result - org_result);
  519   return org_result;
  520 }
  521 
  522 
  523 /***************************************************************************
  524 ** UDF double function.
  525 ** Arguments:
  526 ** initid   Structure filled by xxx_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.
  536 ***************************************************************************/
  537 
  538 my_bool myfunc_double_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
  539 {
  540   uint i;
  541 
  542   if (!args->arg_count)
  543   {
  544     strcpy(message,"myfunc_double must have at least one argument");
  545     return 1;
  546   }
  547   /*
  548   ** As this function wants to have everything as strings, force all arguments
  549   ** to strings.
  550   */
  551   for (i=0 ; i < args->arg_count; i++)
  552     args->arg_type[i]=STRING_RESULT;
  553   initid->maybe_null=1;     /* The result may be null */
  554   initid->decimals=2;       /* We want 2 decimals in the result */
  555   initid->max_length=6;     /* 3 digits + . + 2 decimals */
  556   return 0;
  557 }
  558 
  559 
  560 double myfunc_double(UDF_INIT *initid MY_ATTRIBUTE((unused)), UDF_ARGS *args,
  561                      char *is_null, char *error MY_ATTRIBUTE((unused)))
  562 {
  563   unsigned long val = 0;
  564   unsigned long v = 0;
  565   uint i, j;
  566 
  567   for (i = 0; i < args->arg_count; i++)
  568   {
  569     if (args->args[i] == NULL)
  570       continue;
  571     val += args->lengths[i];
  572     for (j=args->lengths[i] ; j-- > 0 ;)
  573       v += args->args[i][j];
  574   }
  575   if (val)
  576     return (double) v/ (double) val;
  577   *is_null=1;
  578   return 0.0;
  579 }
  580 
  581 
  582 /***************************************************************************
  583 ** UDF long long function.
  584 ** Arguments:
  585 ** initid   Return value from xxxx_init
  586 ** args     The same structure as to xxx_init. This structure
  587 **      contains values for all parameters.
  588 **      Note that the functions MUST check and convert all
  589 **      to the type it wants!  Null values are represented by
  590 **      a NULL pointer
  591 ** is_null  If the result is null, one should store 1 here.
  592 ** error    If something goes fatally wrong one should store 1 here.
  593 **
  594 ** This function should return the result as a long long
  595 ***************************************************************************/
  596 
  597 /* This function returns the sum of all arguments */
  598 
  599 longlong myfunc_int(UDF_INIT *initid MY_ATTRIBUTE((unused)), UDF_ARGS *args,
  600                     char *is_null MY_ATTRIBUTE((unused)),
  601                     char *error MY_ATTRIBUTE((unused)))
  602 {
  603   longlong val = 0;
  604   uint i;
  605 
  606   for (i = 0; i < args->arg_count; i++)
  607   {
  608     if (args->args[i] == NULL)
  609       continue;
  610     switch (args->arg_type[i]) {
  611     case STRING_RESULT:         /* Add string lengths */
  612       val += args->lengths[i];
  613       break;
  614     case INT_RESULT:            /* Add numbers */
  615       val += *((longlong*) args->args[i]);
  616       break;
  617     case REAL_RESULT:           /* Add numers as longlong */
  618       val += (longlong) *((double*) args->args[i]);
  619       break;
  620     default:
  621       break;
  622     }
  623   }
  624   return val;
  625 }
  626 
  627 /*
  628   At least one of _init/_deinit is needed unless the server is started
  629   with --allow_suspicious_udfs.
  630 */
  631 my_bool myfunc_int_init(UDF_INIT *initid MY_ATTRIBUTE((unused)),
  632                         UDF_ARGS *args MY_ATTRIBUTE((unused)),
  633                         char *message MY_ATTRIBUTE((unused)))
  634 {
  635   return 0;
  636 }
  637 
  638 /*
  639   Simple example of how to get a sequences starting from the first argument
  640   or 1 if no arguments have been given
  641 */
  642 
  643 my_bool sequence_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
  644 {
  645   if (args->arg_count > 1)
  646   {
  647     my_stpcpy(message,"This function takes none or 1 argument");
  648     return 1;
  649   }
  650   if (args->arg_count)
  651     args->arg_type[0]= INT_RESULT;      /* Force argument to int */
  652 
  653   if (!(initid->ptr=(char*) malloc(sizeof(longlong))))
  654   {
  655     my_stpcpy(message,"Couldn't allocate memory");
  656     return 1;
  657   }
  658   memset(initid->ptr, 0, sizeof(longlong));
  659   /* 
  660     sequence() is a non-deterministic function : it has different value 
  661     even if called with the same arguments.
  662   */
  663   initid->const_item=0;
  664   return 0;
  665 }
  666 
  667 void sequence_deinit(UDF_INIT *initid)
  668 {
  669   if (initid->ptr)
  670     free(initid->ptr);
  671 }
  672 
  673 longlong sequence(UDF_INIT *initid MY_ATTRIBUTE((unused)), UDF_ARGS *args,
  674                   char *is_null MY_ATTRIBUTE((unused)),
  675                   char *error MY_ATTRIBUTE((unused)))
  676 {
  677   ulonglong val=0;
  678   if (args->arg_count)
  679     val= *((longlong*) args->args[0]);
  680   return ++*((longlong*) initid->ptr) + val;
  681 }
  682 
  683 
  684 /****************************************************************************
  685 ** Some functions that handles IP and hostname conversions
  686 ** The orignal function was from Zeev Suraski.
  687 **
  688 ** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
  689 ** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
  690 **
  691 ****************************************************************************/
  692 
  693 #ifndef _WIN32
  694 #include <netdb.h>
  695 #endif
  696 #ifdef HAVE_ARPA_INET_H
  697 #include <arpa/inet.h>
  698 #endif
  699 #ifdef HAVE_NETINET_IN_H
  700 #include <netinet/in.h>
  701 #endif
  702 #ifdef HAVE_SYS_SOCKET_H
  703 #include <sys/socket.h>
  704 #endif
  705 
  706 C_MODE_START;
  707 my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
  708 void lookup_deinit(UDF_INIT *initid);
  709 char *lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
  710          unsigned long *length, char *null_value, char *error);
  711 my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
  712 void reverse_lookup_deinit(UDF_INIT *initid);
  713 char *reverse_lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
  714              unsigned long *length, char *null_value, char *error);
  715 C_MODE_END;
  716 
  717 
  718 /****************************************************************************
  719 ** lookup IP for an hostname.
  720 **
  721 ** This code assumes that gethostbyname_r exists and inet_ntoa() is thread
  722 ** safe (As it is in Solaris)
  723 ****************************************************************************/
  724 
  725 
  726 my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
  727 {
  728   if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
  729   {
  730     my_stpcpy(message,"Wrong arguments to lookup;  Use the source");
  731     return 1;
  732   }
  733   initid->max_length=11;
  734   initid->maybe_null=1;
  735 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
  736   (void) native_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
  737 #endif
  738   return 0;
  739 }
  740 
  741 void lookup_deinit(UDF_INIT *initid MY_ATTRIBUTE((unused)))
  742 {
  743 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
  744   (void) native_mutex_destroy(&LOCK_hostname);
  745 #endif
  746 }
  747 
  748 char *lookup(UDF_INIT *initid MY_ATTRIBUTE((unused)), UDF_ARGS *args,
  749              char *result, unsigned long *res_length, char *null_value,
  750              char *error MY_ATTRIBUTE((unused)))
  751 {
  752   uint length;
  753   char name_buff[256];
  754   struct hostent *hostent;
  755 #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  756   int tmp_errno;
  757   char hostname_buff[2048];
  758   struct hostent tmp_hostent;
  759 #endif
  760   struct in_addr in;
  761 
  762   if (!args->args[0] || !(length=args->lengths[0]))
  763   {
  764     *null_value=1;
  765     return 0;
  766   }
  767   if (length >= sizeof(name_buff))
  768     length=sizeof(name_buff)-1;
  769   memcpy(name_buff,args->args[0],length);
  770   name_buff[length]=0;
  771 #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  772   if (!(hostent=gethostbyname_r(name_buff,&tmp_hostent,hostname_buff,
  773                 sizeof(hostname_buff), &tmp_errno)))
  774   {
  775     *null_value=1;
  776     return 0;
  777   }
  778 #else
  779   native_mutex_lock(&LOCK_hostname);
  780   if (!(hostent= gethostbyname((char*) name_buff)))
  781   {
  782     native_mutex_unlock(&LOCK_hostname);
  783     *null_value= 1;
  784     return 0;
  785   }
  786   native_mutex_unlock(&LOCK_hostname);
  787 #endif
  788   memcpy(&in, *hostent->h_addr_list, sizeof(in.s_addr));
  789   *res_length= (ulong) (my_stpcpy(result, inet_ntoa(in)) - result);
  790   return result;
  791 }
  792 
  793 
  794 /****************************************************************************
  795 ** return hostname for an IP number.
  796 ** The functions can take as arguments a string "xxx.xxx.xxx.xxx" or
  797 ** four numbers.
  798 ****************************************************************************/
  799 
  800 my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
  801 {
  802   if (args->arg_count == 1)
  803     args->arg_type[0]= STRING_RESULT;
  804   else if (args->arg_count == 4)
  805     args->arg_type[0]=args->arg_type[1]=args->arg_type[2]=args->arg_type[3]=
  806       INT_RESULT;
  807   else
  808   {
  809     my_stpcpy(message,
  810        "Wrong number of arguments to reverse_lookup;  Use the source");
  811     return 1;
  812   }
  813   initid->max_length=32;
  814   initid->maybe_null=1;
  815 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
  816   (void) native_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
  817 #endif
  818   return 0;
  819 }
  820 
  821 void reverse_lookup_deinit(UDF_INIT *initid MY_ATTRIBUTE((unused)))
  822 {
  823 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
  824   (void) native_mutex_destroy(&LOCK_hostname);
  825 #endif
  826 }
  827 
  828 char *reverse_lookup(UDF_INIT *initid MY_ATTRIBUTE((unused)), UDF_ARGS *args,
  829                      char *result, unsigned long *res_length,
  830                      char *null_value, char *error MY_ATTRIBUTE((unused)))
  831 {
  832 #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  833   char name_buff[256];
  834   struct hostent tmp_hostent;
  835   int tmp_errno;
  836 #endif
  837   struct hostent *hp;
  838   unsigned long taddr;
  839   uint length;
  840 
  841   if (args->arg_count == 4)
  842   {
  843     if (!args->args[0] || !args->args[1] ||!args->args[2] ||!args->args[3])
  844     {
  845       *null_value=1;
  846       return 0;
  847     }
  848     sprintf(result,"%d.%d.%d.%d",
  849         (int) *((longlong*) args->args[0]),
  850         (int) *((longlong*) args->args[1]),
  851         (int) *((longlong*) args->args[2]),
  852         (int) *((longlong*) args->args[3]));
  853   }
  854   else
  855   {                 /* string argument */
  856     if (!args->args[0])         /* Return NULL for NULL values */
  857     {
  858       *null_value=1;
  859       return 0;
  860     }
  861     length=args->lengths[0];
  862     if (length >= (uint) *res_length-1)
  863       length=(uint) *res_length;
  864     memcpy(result,args->args[0],length);
  865     result[length]=0;
  866   }
  867 
  868   taddr = inet_addr(result);
  869   if (taddr == (unsigned long) -1L)
  870   {
  871     *null_value=1;
  872     return 0;
  873   }
  874 #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  875   if (!(hp=gethostbyaddr_r((char*) &taddr,sizeof(taddr), AF_INET,
  876                &tmp_hostent, name_buff,sizeof(name_buff),
  877                &tmp_errno)))
  878   {
  879     *null_value=1;
  880     return 0;
  881   }
  882 #else
  883   native_mutex_lock(&LOCK_hostname);
  884   if (!(hp= gethostbyaddr((char*) &taddr, sizeof(taddr), AF_INET)))
  885   {
  886     native_mutex_unlock(&LOCK_hostname);
  887     *null_value= 1;
  888     return 0;
  889   }
  890   native_mutex_unlock(&LOCK_hostname);
  891 #endif
  892   *res_length=(ulong) (my_stpcpy(result,hp->h_name) - result);
  893   return result;
  894 }
  895 
  896 /*
  897 ** Syntax for the new aggregate commands are:
  898 ** create aggregate function <function_name> returns {string|real|integer}
  899 **        soname <name_of_shared_library>
  900 **
  901 ** Syntax for avgcost: avgcost( t.quantity, t.price )
  902 **  with t.quantity=integer, t.price=double
  903 ** (this example is provided by Andreas F. Bobak <bobak@relog.ch>)
  904 */
  905 
  906 
  907 struct avgcost_data
  908 {
  909   ulonglong count;
  910   longlong  totalquantity;
  911   double    totalprice;
  912 };
  913 
  914 
  915 /*
  916 ** Average Cost Aggregate Function.
  917 */
  918 my_bool
  919 avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message )
  920 {
  921   struct avgcost_data*  data;
  922 
  923   if (args->arg_count != 2)
  924   {
  925     strcpy(
  926        message,
  927        "wrong number of arguments: AVGCOST() requires two arguments"
  928        );
  929     return 1;
  930   }
  931 
  932   if ((args->arg_type[0] != INT_RESULT) || (args->arg_type[1] != REAL_RESULT) )
  933   {
  934     strcpy(
  935        message,
  936        "wrong argument type: AVGCOST() requires an INT and a REAL"
  937        );
  938     return 1;
  939   }
  940 
  941   /*
  942   **    force arguments to double.
  943   */
  944   /*args->arg_type[0]   = REAL_RESULT;
  945     args->arg_type[1]   = REAL_RESULT;*/
  946 
  947   initid->maybe_null    = 0;        /* The result may be null */
  948   initid->decimals  = 4;        /* We want 4 decimals in the result */
  949   initid->max_length    = 20;       /* 6 digits + . + 10 decimals */
  950 
  951   if (!(data = new (std::nothrow) avgcost_data))
  952   {
  953     my_stpcpy(message,"Couldn't allocate memory");
  954     return 1;
  955   }
  956   data->totalquantity   = 0;
  957   data->totalprice  = 0.0;
  958 
  959   initid->ptr = (char*)data;
  960 
  961   return 0;
  962 }
  963 
  964 void
  965 avgcost_deinit( UDF_INIT* initid )
  966 {
  967   void *void_ptr= initid->ptr;
  968   avgcost_data *data= static_cast<avgcost_data*>(void_ptr);
  969   delete data;
  970 }
  971 
  972 
  973 /* This is only for MySQL 4.0 compability */
  974 void
  975 avgcost_reset(UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message)
  976 {
  977   avgcost_clear(initid, is_null, message);
  978   avgcost_add(initid, args, is_null, message);
  979 }
  980 
  981 /* This is needed to get things to work in MySQL 4.1.1 and above */
  982 
  983 void
  984 avgcost_clear(UDF_INIT* initid, char* is_null MY_ATTRIBUTE((unused)),
  985               char* message MY_ATTRIBUTE((unused)))
  986 {
  987   struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
  988   data->totalprice= 0.0;
  989   data->totalquantity=  0;
  990   data->count=      0;
  991 }
  992 
  993 
  994 void
  995 avgcost_add(UDF_INIT* initid, UDF_ARGS* args,
  996             char* is_null MY_ATTRIBUTE((unused)),
  997             char* message MY_ATTRIBUTE((unused)))
  998 {
  999   if (args->args[0] && args->args[1])
 1000   {
 1001     struct avgcost_data* data   = (struct avgcost_data*)initid->ptr;
 1002     longlong quantity       = *((longlong*)args->args[0]);
 1003     longlong newquantity    = data->totalquantity + quantity;
 1004     double price        = *((double*)args->args[1]);
 1005 
 1006     data->count++;
 1007 
 1008     if (   ((data->totalquantity >= 0) && (quantity < 0))
 1009        || ((data->totalquantity <  0) && (quantity > 0)) )
 1010     {
 1011       /*
 1012       **    passing from + to - or from - to +
 1013       */
 1014       if (   ((quantity < 0) && (newquantity < 0))
 1015          || ((quantity > 0) && (newquantity > 0)) )
 1016       {
 1017     data->totalprice    = price * (double)newquantity;
 1018       }
 1019       /*
 1020       **    sub q if totalq > 0
 1021       **    add q if totalq < 0
 1022       */
 1023       else
 1024       {
 1025     price         = data->totalprice / (double)data->totalquantity;
 1026     data->totalprice  = price * (double)newquantity;
 1027       }
 1028       data->totalquantity = newquantity;
 1029     }
 1030     else
 1031     {
 1032       data->totalquantity   += quantity;
 1033       data->totalprice      += price * (double)quantity;
 1034     }
 1035 
 1036     if (data->totalquantity == 0)
 1037       data->totalprice = 0.0;
 1038   }
 1039 }
 1040 
 1041 
 1042 double
 1043 avgcost( UDF_INIT* initid, UDF_ARGS* args MY_ATTRIBUTE((unused)),
 1044          char* is_null, char* error MY_ATTRIBUTE((unused)))
 1045 {
 1046   struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
 1047   if (!data->count || !data->totalquantity)
 1048   {
 1049     *is_null = 1;
 1050     return 0.0;
 1051   }
 1052 
 1053   *is_null = 0;
 1054   return data->totalprice/(double)data->totalquantity;
 1055 }
 1056 
 1057 my_bool myfunc_argument_name_init(UDF_INIT *initid, UDF_ARGS *args,
 1058                   char *message);
 1059 char *myfunc_argument_name(UDF_INIT *initid, UDF_ARGS *args, char *result,
 1060                unsigned long *length, char *null_value,
 1061                char *error);
 1062 
 1063 my_bool myfunc_argument_name_init(UDF_INIT *initid, UDF_ARGS *args,
 1064                   char *message)
 1065 {
 1066   if (args->arg_count != 1)
 1067   {
 1068     my_stpcpy(message,"myfunc_argument_name_init accepts only one argument");
 1069     return 1;
 1070   }
 1071   initid->max_length= args->attribute_lengths[0];
 1072   initid->maybe_null= 1;
 1073   initid->const_item= 1;
 1074   return 0;
 1075 }
 1076 
 1077 char *myfunc_argument_name(UDF_INIT *initid MY_ATTRIBUTE((unused)),
 1078                            UDF_ARGS *args, char *result,
 1079                            unsigned long *length, char *null_value,
 1080                            char *error MY_ATTRIBUTE((unused)))
 1081 {
 1082   if (!args->attributes[0])
 1083   {
 1084     *null_value= 1;
 1085     return 0;
 1086   }
 1087   (*length)--; /* space for ending \0 (for debugging purposes) */
 1088   if (*length > args->attribute_lengths[0])
 1089     *length= args->attribute_lengths[0];
 1090   memcpy(result, args->attributes[0], *length);
 1091   result[*length]= 0;
 1092   return result;
 1093 }
 1094 
 1095 
 1096 
 1097 my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
 1098 {
 1099   if (args->arg_count != 1)
 1100   {
 1101     my_stpcpy(message, "IS_CONST accepts only one argument");
 1102     return 1;
 1103   }
 1104   initid->ptr= (char*)((args->args[0] != NULL) ? 1UL : 0);
 1105   return 0;
 1106 }
 1107 
 1108 char * is_const(UDF_INIT *initid, UDF_ARGS *args MY_ATTRIBUTE((unused)),
 1109                 char *result, unsigned long *length,
 1110                 char *is_null, char *error MY_ATTRIBUTE((unused)))
 1111 {
 1112   if (initid->ptr != 0) {
 1113     sprintf(result, "const");
 1114   } else {
 1115     sprintf(result, "not const");
 1116   }
 1117   *is_null= 0;
 1118   *length= (uint) strlen(result);
 1119   return result;
 1120 }
 1121 
 1122 
 1123 
 1124 extern "C"
 1125 my_bool check_const_len_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
 1126 {
 1127   if (args->arg_count != 1)
 1128   {
 1129     my_stpcpy(message, "CHECK_CONST_LEN accepts only one argument");
 1130     return 1;
 1131   }
 1132   if (args->args[0] == 0)
 1133   {
 1134     initid->ptr= (char*)"Not constant";
 1135   }
 1136   else if(strlen(args->args[0]) == args->lengths[0])
 1137   {
 1138     initid->ptr= (char*)"Correct length";
 1139   }
 1140   else
 1141   {
 1142     initid->ptr= (char*)"Wrong length";
 1143   }
 1144   initid->max_length = 100;
 1145   return 0;
 1146 }
 1147 
 1148 extern "C"
 1149 char * check_const_len(UDF_INIT *initid, UDF_ARGS *args MY_ATTRIBUTE((unused)),
 1150                 char *result, unsigned long *length,
 1151                 char *is_null, char *error MY_ATTRIBUTE((unused)))
 1152 {
 1153   my_stpcpy(result, initid->ptr);
 1154   *length= (uint) strlen(result);
 1155   *is_null= 0;
 1156   return result;
 1157 }
 1158 
 1159 
 1160 C_MODE_START;
 1161 my_bool  my_median_init  (UDF_INIT *initid, UDF_ARGS *args, char *message);
 1162 void     my_median_deinit(UDF_INIT* initid);
 1163 void     my_median_add   (UDF_INIT* initid, UDF_ARGS* args,
 1164                           char* is_null, char *error);
 1165 void     my_median_clear (UDF_INIT* initid, UDF_ARGS* args,
 1166                           char* is_null, char *error);
 1167 longlong my_median       (UDF_INIT* initid, UDF_ARGS* args,
 1168                           char* is_null, char *error);
 1169 C_MODE_END;
 1170 
 1171 struct My_median_data
 1172 {
 1173   std::vector<longlong> vec;
 1174 };
 1175 
 1176 
 1177 my_bool  my_median_init  (UDF_INIT *initid, UDF_ARGS *args, char *message)
 1178 {
 1179   My_median_data *data= new (std::nothrow) My_median_data;
 1180   if (!data)
 1181   {
 1182     my_stpcpy(message,"Could not allocate memory");
 1183     return true;
 1184   }
 1185   initid->ptr= static_cast<char*>(static_cast<void*>(data));
 1186   return false;
 1187 }
 1188 
 1189 void my_median_deinit(UDF_INIT* initid)
 1190 {
 1191   My_median_data *data=
 1192     static_cast<My_median_data*>(static_cast<void*>(initid->ptr));
 1193   delete data;
 1194 }
 1195 
 1196 void my_median_add(UDF_INIT* initid, UDF_ARGS* args,
 1197                    char* is_null MY_ATTRIBUTE((unused)),
 1198                    char* message MY_ATTRIBUTE((unused)))
 1199 {
 1200   My_median_data *data=
 1201     static_cast<My_median_data*>(static_cast<void*>(initid->ptr));
 1202   if (args->args[0])
 1203   {
 1204     void *arg0= args->args[0];
 1205     longlong number= *(static_cast<longlong*>(arg0));
 1206     data->vec.push_back(number);
 1207   }
 1208 }
 1209 
 1210 void my_median_clear(UDF_INIT* initid, UDF_ARGS* args,
 1211                      char* is_null MY_ATTRIBUTE((unused)),
 1212                      char* message MY_ATTRIBUTE((unused)))
 1213 {
 1214   My_median_data *data=
 1215     static_cast<My_median_data*>(static_cast<void*>(initid->ptr));
 1216   data->vec.clear();
 1217 }
 1218 
 1219 longlong my_median(UDF_INIT* initid, UDF_ARGS* args,
 1220                    char* is_null,
 1221                    char* message MY_ATTRIBUTE((unused)))
 1222 {
 1223   My_median_data *data=
 1224     static_cast<My_median_data*>(static_cast<void*>(initid->ptr));
 1225   if (data->vec.size() == 0)
 1226   {
 1227     *is_null= 1;
 1228     return 0;
 1229   }
 1230   const size_t ix= data->vec.size() / 2;
 1231   std::nth_element(data->vec.begin(), data->vec.begin() + ix, data->vec.end());
 1232   return data->vec[ix];
 1233 }
 1234 
 1235 #endif /* HAVE_DLOPEN */