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