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