mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / sql / udf_example.c
blob3c58c0809745127c7b562bc108eb87fe8af616d0
1 /*
2 Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
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.
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.
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-1301 USA
19 ** example file of UDF (user definable functions) that are dynamicly loaded
20 ** into the standard mysqld core.
22 ** The functions name, type and shared library is saved in the new system
23 ** table 'func'. To be able to create new functions one must have write
24 ** privilege for the database 'mysql'. If one starts MySQL with
25 ** --skip-grant, then UDF initialization will also be skipped.
27 ** Syntax for the new commands are:
28 ** create function <function_name> returns {string|real|integer}
29 ** soname <name_of_shared_library>
30 ** drop function <function_name>
32 ** Each defined function may have a xxxx_init function and a xxxx_deinit
33 ** function. The init function should alloc memory for the function
34 ** and tell the main function about the max length of the result
35 ** (for string functions), number of decimals (for double functions) and
36 ** if the result may be a null value.
38 ** If a function sets the 'error' argument to 1 the function will not be
39 ** called anymore and mysqld will return NULL for all calls to this copy
40 ** of the function.
42 ** All strings arguments to functions are given as string pointer + length
43 ** to allow handling of binary data.
44 ** Remember that all functions must be thread safe. This means that one is not
45 ** allowed to alloc any global or static variables that changes!
46 ** If one needs memory one should alloc this in the init function and free
47 ** this on the __deinit function.
49 ** Note that the init and __deinit functions are only called once per
50 ** SQL statement while the value function may be called many times
52 ** Function 'metaphon' returns a metaphon string of the string argument.
53 ** This is something like a soundex string, but it's more tuned for English.
55 ** Function 'myfunc_double' returns summary of codes of all letters
56 ** of arguments divided by summary length of all its arguments.
58 ** Function 'myfunc_int' returns summary length of all its arguments.
60 ** Function 'sequence' returns an sequence starting from a certain number.
62 ** Function 'myfunc_argument_name' returns name of argument.
64 ** On the end is a couple of functions that converts hostnames to ip and
65 ** vice versa.
67 ** A dynamicly loadable file should be compiled shared.
68 ** (something like: gcc -shared -o my_func.so myfunc.cc).
69 ** You can easily get all switches right by doing:
70 ** cd sql ; make udf_example.o
71 ** Take the compile line that make writes, remove the '-c' near the end of
72 ** the line and add -shared -o udf_example.so to the end of the compile line.
73 ** The resulting library (udf_example.so) should be copied to some dir
74 ** searched by ld. (/usr/lib ?)
75 ** If you are using gcc, then you should be able to create the udf_example.so
76 ** by simply doing 'make udf_example.so'.
78 ** After the library is made one must notify mysqld about the new
79 ** functions with the commands:
81 ** CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
82 ** CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
83 ** CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
84 ** CREATE FUNCTION sequence RETURNS INTEGER SONAME "udf_example.so";
85 ** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
86 ** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
87 ** CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
88 ** CREATE FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so";
90 ** After this the functions will work exactly like native MySQL functions.
91 ** Functions should be created only once.
93 ** The functions can be deleted by:
95 ** DROP FUNCTION metaphon;
96 ** DROP FUNCTION myfunc_double;
97 ** DROP FUNCTION myfunc_int;
98 ** DROP FUNCTION lookup;
99 ** DROP FUNCTION reverse_lookup;
100 ** DROP FUNCTION avgcost;
101 ** DROP FUNCTION myfunc_argument_name;
103 ** The CREATE FUNCTION and DROP FUNCTION update the func@mysql table. All
104 ** Active function will be reloaded on every restart of server
105 ** (if --skip-grant-tables is not given)
107 ** If you ge problems with undefined symbols when loading the shared
108 ** library, you should verify that mysqld is compiled with the -rdynamic
109 ** option.
111 ** If you can't get AGGREGATES to work, check that you have the column
112 ** 'type' in the mysql.func table. If not, run 'mysql_fix_privilege_tables'.
116 #ifdef STANDARD
117 /* STANDARD is defined, don't use any mysql functions */
118 #include <stdlib.h>
119 #include <stdio.h>
120 #include <string.h>
121 #ifdef __WIN__
122 typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */
123 typedef __int64 longlong;
124 #else
125 typedef unsigned long long ulonglong;
126 typedef long long longlong;
127 #endif /*__WIN__*/
128 #else
129 #include <my_global.h>
130 #include <my_sys.h>
131 #if defined(MYSQL_SERVER)
132 #include <m_string.h> /* To get strmov() */
133 #else
134 /* when compiled as standalone */
135 #include <string.h>
136 #define strmov(a,b) stpcpy(a,b)
137 #define bzero(a,b) memset(a,0,b)
138 #define memcpy_fixed(a,b,c) memcpy(a,b,c)
139 #endif
140 #endif
141 #include <mysql.h>
142 #include <ctype.h>
144 #ifdef HAVE_DLOPEN
146 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
147 static pthread_mutex_t LOCK_hostname;
148 #endif
150 /* These must be right or mysqld will not find the symbol! */
152 my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
153 void metaphon_deinit(UDF_INIT *initid);
154 char *metaphon(UDF_INIT *initid, UDF_ARGS *args, char *result,
155 unsigned long *length, char *is_null, char *error);
156 my_bool myfunc_double_init(UDF_INIT *, UDF_ARGS *args, char *message);
157 double myfunc_double(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
158 char *error);
159 my_bool myfunc_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
160 longlong myfunc_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
161 char *error);
162 my_bool sequence_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
163 void sequence_deinit(UDF_INIT *initid);
164 longlong sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
165 char *error);
166 my_bool avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message );
167 void avgcost_deinit( UDF_INIT* initid );
168 void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
169 void avgcost_clear( UDF_INIT* initid, char* is_null, char *error );
170 void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
171 double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
172 my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
173 char *is_const(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long
174 *length, char *is_null, char *error);
177 /*************************************************************************
178 ** Example of init function
179 ** Arguments:
180 ** initid Points to a structure that the init function should fill.
181 ** This argument is given to all other functions.
182 ** my_bool maybe_null 1 if function can return NULL
183 ** Default value is 1 if any of the arguments
184 ** is declared maybe_null.
185 ** unsigned int decimals Number of decimals.
186 ** Default value is max decimals in any of the
187 ** arguments.
188 ** unsigned int max_length Length of string result.
189 ** The default value for integer functions is 21
190 ** The default value for real functions is 13+
191 ** default number of decimals.
192 ** The default value for string functions is
193 ** the longest string argument.
194 ** char *ptr; A pointer that the function can use.
196 ** args Points to a structure which contains:
197 ** unsigned int arg_count Number of arguments
198 ** enum Item_result *arg_type Types for each argument.
199 ** Types are STRING_RESULT, REAL_RESULT
200 ** and INT_RESULT.
201 ** char **args Pointer to constant arguments.
202 ** Contains 0 for not constant argument.
203 ** unsigned long *lengths; max string length for each argument
204 ** char *maybe_null Information of which arguments
205 ** may be NULL
207 ** message Error message that should be passed to the user on fail.
208 ** The message buffer is MYSQL_ERRMSG_SIZE big, but one should
209 ** try to keep the error message less than 80 bytes long!
211 ** This function should return 1 if something goes wrong. In this case
212 ** message should contain something usefull!
213 **************************************************************************/
215 #define MAXMETAPH 8
217 my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
219 if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
221 strcpy(message,"Wrong arguments to metaphon; Use the source");
222 return 1;
224 initid->max_length=MAXMETAPH;
225 return 0;
228 /****************************************************************************
229 ** Deinit function. This should free all resources allocated by
230 ** this function.
231 ** Arguments:
232 ** initid Return value from xxxx_init
233 ****************************************************************************/
236 void metaphon_deinit(UDF_INIT *initid __attribute__((unused)))
240 /***************************************************************************
241 ** UDF string function.
242 ** Arguments:
243 ** initid Structure filled by xxx_init
244 ** args The same structure as to xxx_init. This structure
245 ** contains values for all parameters.
246 ** Note that the functions MUST check and convert all
247 ** to the type it wants! Null values are represented by
248 ** a NULL pointer
249 ** result Possible buffer to save result. At least 255 byte long.
250 ** length Pointer to length of the above buffer. In this the function
251 ** should save the result length
252 ** is_null If the result is null, one should store 1 here.
253 ** error If something goes fatally wrong one should store 1 here.
255 ** This function should return a pointer to the result string.
256 ** Normally this is 'result' but may also be an alloced string.
257 ***************************************************************************/
259 /* Character coding array */
260 static char codes[26] = {
261 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
262 /* 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*/
265 /*--- Macros to access character coding array -------------*/
267 #define ISVOWEL(x) (codes[(x) - 'A'] & 1) /* AEIOU */
269 /* Following letters are not changed */
270 #define NOCHANGE(x) (codes[(x) - 'A'] & 2) /* FJLMNR */
272 /* These form diphthongs when preceding H */
273 #define AFFECTH(x) (codes[(x) - 'A'] & 4) /* CGPST */
275 /* These make C and G soft */
276 #define MAKESOFT(x) (codes[(x) - 'A'] & 8) /* EIY */
278 /* These prevent GH from becoming F */
279 #define NOGHTOF(x) (codes[(x) - 'A'] & 16) /* BDH */
282 char *metaphon(UDF_INIT *initid __attribute__((unused)),
283 UDF_ARGS *args, char *result, unsigned long *length,
284 char *is_null, char *error __attribute__((unused)))
286 const char *word=args->args[0];
287 const char *w_end;
288 char *org_result;
289 char *n, *n_start, *n_end; /* pointers to string */
290 char *metaph_end; /* pointers to end of metaph */
291 char ntrans[32]; /* word with uppercase letters */
292 int KSflag; /* state flag for X to KS */
294 if (!word) /* Null argument */
296 *is_null=1;
297 return 0;
299 w_end=word+args->lengths[0];
300 org_result=result;
302 /*--------------------------------------------------------
303 * Copy word to internal buffer, dropping non-alphabetic
304 * characters and converting to uppercase.
305 *-------------------------------------------------------*/
307 for (n = ntrans + 1, n_end = ntrans + sizeof(ntrans)-2;
308 word != w_end && n < n_end; word++ )
309 if ( isalpha ( *word ))
310 *n++ = toupper ( *word );
312 if ( n == ntrans + 1 ) /* return empty string if 0 bytes */
314 *length=0;
315 return result;
317 n_end = n; /* set n_end to end of string */
318 ntrans[0] = 'Z'; /* ntrans[0] should be a neutral char */
319 n[0]=n[1]=0; /* pad with nulls */
320 n = ntrans + 1; /* assign pointer to start */
322 /*------------------------------------------------------------
323 * check for all prefixes:
324 * PN KN GN AE WR WH and X at start.
325 *----------------------------------------------------------*/
327 switch ( *n ) {
328 case 'P':
329 case 'K':
330 case 'G':
331 if ( n[1] == 'N')
332 *n++ = 0;
333 break;
334 case 'A':
335 if ( n[1] == 'E')
336 *n++ = 0;
337 break;
338 case 'W':
339 if ( n[1] == 'R' )
340 *n++ = 0;
341 else
342 if ( *(n + 1) == 'H')
344 n[1] = *n;
345 *n++ = 0;
347 break;
348 case 'X':
349 *n = 'S';
350 break;
353 /*------------------------------------------------------------
354 * Now, loop step through string, stopping at end of string
355 * or when the computed metaph is MAXMETAPH characters long
356 *----------------------------------------------------------*/
358 KSflag = 0; /* state flag for KS translation */
360 for (metaph_end = result + MAXMETAPH, n_start = n;
361 n < n_end && result < metaph_end; n++ )
364 if ( KSflag )
366 KSflag = 0;
367 *result++ = *n;
369 else
371 /* drop duplicates except for CC */
372 if ( *( n - 1 ) == *n && *n != 'C' )
373 continue;
375 /* check for F J L M N R or first letter vowel */
376 if ( NOCHANGE ( *n ) ||
377 ( n == n_start && ISVOWEL ( *n )))
378 *result++ = *n;
379 else
380 switch ( *n ) {
381 case 'B': /* check for -MB */
382 if ( n < n_end || *( n - 1 ) != 'M' )
383 *result++ = *n;
384 break;
386 case 'C': /* C = X ("sh" sound) in CH and CIA */
387 /* = S in CE CI and CY */
388 /* dropped in SCI SCE SCY */
389 /* else K */
390 if ( *( n - 1 ) != 'S' ||
391 !MAKESOFT ( n[1]))
393 if ( n[1] == 'I' && n[2] == 'A' )
394 *result++ = 'X';
395 else
396 if ( MAKESOFT ( n[1]))
397 *result++ = 'S';
398 else
399 if ( n[1] == 'H' )
400 *result++ = (( n == n_start &&
401 !ISVOWEL ( n[2])) ||
402 *( n - 1 ) == 'S' ) ?
403 (char)'K' : (char)'X';
404 else
405 *result++ = 'K';
407 break;
409 case 'D': /* J before DGE, DGI, DGY, else T */
410 *result++ =
411 ( n[1] == 'G' &&
412 MAKESOFT ( n[2])) ?
413 (char)'J' : (char)'T';
414 break;
416 case 'G': /* complicated, see table in text */
417 if (( n[1] != 'H' || ISVOWEL ( n[2]))
418 && (
419 n[1] != 'N' ||
421 (n + 1) < n_end &&
423 n[2] != 'E' ||
424 *( n + 3 ) != 'D'
428 && (
429 *( n - 1 ) != 'D' ||
430 !MAKESOFT ( n[1])
433 *result++ =
434 ( MAKESOFT ( *( n + 1 )) &&
435 n[2] != 'G' ) ?
436 (char)'J' : (char)'K';
437 else
438 if ( n[1] == 'H' &&
439 !NOGHTOF( *( n - 3 )) &&
440 *( n - 4 ) != 'H')
441 *result++ = 'F';
442 break;
444 case 'H': /* H if before a vowel and not after */
445 /* C, G, P, S, T */
447 if ( !AFFECTH ( *( n - 1 )) &&
448 ( !ISVOWEL ( *( n - 1 )) ||
449 ISVOWEL ( n[1])))
450 *result++ = 'H';
451 break;
453 case 'K': /* K = K, except dropped after C */
454 if ( *( n - 1 ) != 'C')
455 *result++ = 'K';
456 break;
458 case 'P': /* PH = F, else P = P */
459 *result++ = *( n + 1 ) == 'H'
460 ? (char)'F' : (char)'P';
461 break;
462 case 'Q': /* Q = K (U after Q is already gone */
463 *result++ = 'K';
464 break;
466 case 'S': /* SH, SIO, SIA = X ("sh" sound) */
467 *result++ = ( n[1] == 'H' ||
468 ( *(n + 1) == 'I' &&
469 ( n[2] == 'O' ||
470 n[2] == 'A'))) ?
471 (char)'X' : (char)'S';
472 break;
474 case 'T': /* TIO, TIA = X ("sh" sound) */
475 /* TH = 0, ("th" sound ) */
476 if ( *( n + 1 ) == 'I' && ( n[2] == 'O'
477 || n[2] == 'A') )
478 *result++ = 'X';
479 else
480 if ( n[1] == 'H' )
481 *result++ = '0';
482 else
483 if ( *( n + 1) != 'C' || n[2] != 'H')
484 *result++ = 'T';
485 break;
487 case 'V': /* V = F */
488 *result++ = 'F';
489 break;
491 case 'W': /* only exist if a vowel follows */
492 case 'Y':
493 if ( ISVOWEL ( n[1]))
494 *result++ = *n;
495 break;
497 case 'X': /* X = KS, except at start */
498 if ( n == n_start )
499 *result++ = 'S';
500 else
502 *result++ = 'K'; /* insert K, then S */
503 KSflag = 1; /* this flag will cause S to be
504 inserted on next pass thru loop */
506 break;
508 case 'Z':
509 *result++ = 'S';
510 break;
514 *length= (unsigned long) (result - org_result);
515 return org_result;
519 /***************************************************************************
520 ** UDF double function.
521 ** Arguments:
522 ** initid Structure filled by xxx_init
523 ** args The same structure as to xxx_init. This structure
524 ** contains values for all parameters.
525 ** Note that the functions MUST check and convert all
526 ** to the type it wants! Null values are represented by
527 ** a NULL pointer
528 ** is_null If the result is null, one should store 1 here.
529 ** error If something goes fatally wrong one should store 1 here.
531 ** This function should return the result.
532 ***************************************************************************/
534 my_bool myfunc_double_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
536 uint i;
538 if (!args->arg_count)
540 strcpy(message,"myfunc_double must have at least one argument");
541 return 1;
544 ** As this function wants to have everything as strings, force all arguments
545 ** to strings.
547 for (i=0 ; i < args->arg_count; i++)
548 args->arg_type[i]=STRING_RESULT;
549 initid->maybe_null=1; /* The result may be null */
550 initid->decimals=2; /* We want 2 decimals in the result */
551 initid->max_length=6; /* 3 digits + . + 2 decimals */
552 return 0;
556 double myfunc_double(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
557 char *is_null, char *error __attribute__((unused)))
559 unsigned long val = 0;
560 unsigned long v = 0;
561 uint i, j;
563 for (i = 0; i < args->arg_count; i++)
565 if (args->args[i] == NULL)
566 continue;
567 val += args->lengths[i];
568 for (j=args->lengths[i] ; j-- > 0 ;)
569 v += args->args[i][j];
571 if (val)
572 return (double) v/ (double) val;
573 *is_null=1;
574 return 0.0;
578 /***************************************************************************
579 ** UDF long long function.
580 ** Arguments:
581 ** initid Return value from xxxx_init
582 ** args The same structure as to xxx_init. This structure
583 ** contains values for all parameters.
584 ** Note that the functions MUST check and convert all
585 ** to the type it wants! Null values are represented by
586 ** a NULL pointer
587 ** is_null If the result is null, one should store 1 here.
588 ** error If something goes fatally wrong one should store 1 here.
590 ** This function should return the result as a long long
591 ***************************************************************************/
593 /* This function returns the sum of all arguments */
595 longlong myfunc_int(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
596 char *is_null __attribute__((unused)),
597 char *error __attribute__((unused)))
599 longlong val = 0;
600 uint i;
602 for (i = 0; i < args->arg_count; i++)
604 if (args->args[i] == NULL)
605 continue;
606 switch (args->arg_type[i]) {
607 case STRING_RESULT: /* Add string lengths */
608 val += args->lengths[i];
609 break;
610 case INT_RESULT: /* Add numbers */
611 val += *((longlong*) args->args[i]);
612 break;
613 case REAL_RESULT: /* Add numers as longlong */
614 val += (longlong) *((double*) args->args[i]);
615 break;
616 default:
617 break;
620 return val;
624 At least one of _init/_deinit is needed unless the server is started
625 with --allow_suspicious_udfs.
627 my_bool myfunc_int_init(UDF_INIT *initid __attribute__((unused)),
628 UDF_ARGS *args __attribute__((unused)),
629 char *message __attribute__((unused)))
631 return 0;
635 Simple example of how to get a sequences starting from the first argument
636 or 1 if no arguments have been given
639 my_bool sequence_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
641 if (args->arg_count > 1)
643 strmov(message,"This function takes none or 1 argument");
644 return 1;
646 if (args->arg_count)
647 args->arg_type[0]= INT_RESULT; /* Force argument to int */
649 if (!(initid->ptr=(char*) malloc(sizeof(longlong))))
651 strmov(message,"Couldn't allocate memory");
652 return 1;
654 bzero(initid->ptr,sizeof(longlong));
656 sequence() is a non-deterministic function : it has different value
657 even if called with the same arguments.
659 initid->const_item=0;
660 return 0;
663 void sequence_deinit(UDF_INIT *initid)
665 if (initid->ptr)
666 free(initid->ptr);
669 longlong sequence(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
670 char *is_null __attribute__((unused)),
671 char *error __attribute__((unused)))
673 ulonglong val=0;
674 if (args->arg_count)
675 val= *((longlong*) args->args[0]);
676 return ++*((longlong*) initid->ptr) + val;
680 /****************************************************************************
681 ** Some functions that handles IP and hostname conversions
682 ** The orignal function was from Zeev Suraski.
684 ** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
685 ** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
687 ****************************************************************************/
689 #ifdef __WIN__
690 #include <winsock2.h>
691 #else
692 #include <sys/socket.h>
693 #include <netinet/in.h>
694 #include <arpa/inet.h>
695 #include <netdb.h>
696 #endif
698 my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
699 void lookup_deinit(UDF_INIT *initid);
700 char *lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
701 unsigned long *length, char *null_value, char *error);
702 my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
703 void reverse_lookup_deinit(UDF_INIT *initid);
704 char *reverse_lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
705 unsigned long *length, char *null_value, char *error);
708 /****************************************************************************
709 ** lookup IP for an hostname.
711 ** This code assumes that gethostbyname_r exists and inet_ntoa() is thread
712 ** safe (As it is in Solaris)
713 ****************************************************************************/
716 my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
718 if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
720 strmov(message,"Wrong arguments to lookup; Use the source");
721 return 1;
723 initid->max_length=11;
724 initid->maybe_null=1;
725 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
726 (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
727 #endif
728 return 0;
731 void lookup_deinit(UDF_INIT *initid __attribute__((unused)))
733 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
734 (void) pthread_mutex_destroy(&LOCK_hostname);
735 #endif
738 char *lookup(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
739 char *result, unsigned long *res_length, char *null_value,
740 char *error __attribute__((unused)))
742 uint length;
743 char name_buff[256];
744 struct hostent *hostent;
745 #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
746 int tmp_errno;
747 char hostname_buff[2048];
748 struct hostent tmp_hostent;
749 #endif
750 struct in_addr in;
752 if (!args->args[0] || !(length=args->lengths[0]))
754 *null_value=1;
755 return 0;
757 if (length >= sizeof(name_buff))
758 length=sizeof(name_buff)-1;
759 memcpy(name_buff,args->args[0],length);
760 name_buff[length]=0;
761 #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
762 if (!(hostent=gethostbyname_r(name_buff,&tmp_hostent,hostname_buff,
763 sizeof(hostname_buff), &tmp_errno)))
765 *null_value=1;
766 return 0;
768 #else
769 VOID(pthread_mutex_lock(&LOCK_hostname));
770 if (!(hostent= gethostbyname((char*) name_buff)))
772 VOID(pthread_mutex_unlock(&LOCK_hostname));
773 *null_value= 1;
774 return 0;
776 VOID(pthread_mutex_unlock(&LOCK_hostname));
777 #endif
778 memcpy_fixed((char*) &in,(char*) *hostent->h_addr_list, sizeof(in.s_addr));
779 *res_length= (ulong) (strmov(result, inet_ntoa(in)) - result);
780 return result;
784 /****************************************************************************
785 ** return hostname for an IP number.
786 ** The functions can take as arguments a string "xxx.xxx.xxx.xxx" or
787 ** four numbers.
788 ****************************************************************************/
790 my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
792 if (args->arg_count == 1)
793 args->arg_type[0]= STRING_RESULT;
794 else if (args->arg_count == 4)
795 args->arg_type[0]=args->arg_type[1]=args->arg_type[2]=args->arg_type[3]=
796 INT_RESULT;
797 else
799 strmov(message,
800 "Wrong number of arguments to reverse_lookup; Use the source");
801 return 1;
803 initid->max_length=32;
804 initid->maybe_null=1;
805 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
806 (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
807 #endif
808 return 0;
811 void reverse_lookup_deinit(UDF_INIT *initid __attribute__((unused)))
813 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
814 (void) pthread_mutex_destroy(&LOCK_hostname);
815 #endif
818 char *reverse_lookup(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
819 char *result, unsigned long *res_length,
820 char *null_value, char *error __attribute__((unused)))
822 #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
823 char name_buff[256];
824 struct hostent tmp_hostent;
825 int tmp_errno;
826 #endif
827 struct hostent *hp;
828 unsigned long taddr;
829 uint length;
831 if (args->arg_count == 4)
833 if (!args->args[0] || !args->args[1] ||!args->args[2] ||!args->args[3])
835 *null_value=1;
836 return 0;
838 sprintf(result,"%d.%d.%d.%d",
839 (int) *((longlong*) args->args[0]),
840 (int) *((longlong*) args->args[1]),
841 (int) *((longlong*) args->args[2]),
842 (int) *((longlong*) args->args[3]));
844 else
845 { /* string argument */
846 if (!args->args[0]) /* Return NULL for NULL values */
848 *null_value=1;
849 return 0;
851 length=args->lengths[0];
852 if (length >= (uint) *res_length-1)
853 length=(uint) *res_length;
854 memcpy(result,args->args[0],length);
855 result[length]=0;
858 taddr = inet_addr(result);
859 if (taddr == (unsigned long) -1L)
861 *null_value=1;
862 return 0;
864 #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
865 if (!(hp=gethostbyaddr_r((char*) &taddr,sizeof(taddr), AF_INET,
866 &tmp_hostent, name_buff,sizeof(name_buff),
867 &tmp_errno)))
869 *null_value=1;
870 return 0;
872 #else
873 VOID(pthread_mutex_lock(&LOCK_hostname));
874 if (!(hp= gethostbyaddr((char*) &taddr, sizeof(taddr), AF_INET)))
876 VOID(pthread_mutex_unlock(&LOCK_hostname));
877 *null_value= 1;
878 return 0;
880 VOID(pthread_mutex_unlock(&LOCK_hostname));
881 #endif
882 *res_length=(ulong) (strmov(result,hp->h_name) - result);
883 return result;
887 ** Syntax for the new aggregate commands are:
888 ** create aggregate function <function_name> returns {string|real|integer}
889 ** soname <name_of_shared_library>
891 ** Syntax for avgcost: avgcost( t.quantity, t.price )
892 ** with t.quantity=integer, t.price=double
893 ** (this example is provided by Andreas F. Bobak <bobak@relog.ch>)
897 struct avgcost_data
899 ulonglong count;
900 longlong totalquantity;
901 double totalprice;
906 ** Average Cost Aggregate Function.
908 my_bool
909 avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message )
911 struct avgcost_data* data;
913 if (args->arg_count != 2)
915 strcpy(
916 message,
917 "wrong number of arguments: AVGCOST() requires two arguments"
919 return 1;
922 if ((args->arg_type[0] != INT_RESULT) || (args->arg_type[1] != REAL_RESULT) )
924 strcpy(
925 message,
926 "wrong argument type: AVGCOST() requires an INT and a REAL"
928 return 1;
932 ** force arguments to double.
934 /*args->arg_type[0] = REAL_RESULT;
935 args->arg_type[1] = REAL_RESULT;*/
937 initid->maybe_null = 0; /* The result may be null */
938 initid->decimals = 4; /* We want 4 decimals in the result */
939 initid->max_length = 20; /* 6 digits + . + 10 decimals */
941 if (!(data = (struct avgcost_data*) malloc(sizeof(struct avgcost_data))))
943 strmov(message,"Couldn't allocate memory");
944 return 1;
946 data->totalquantity = 0;
947 data->totalprice = 0.0;
949 initid->ptr = (char*)data;
951 return 0;
954 void
955 avgcost_deinit( UDF_INIT* initid )
957 free(initid->ptr);
961 /* This is only for MySQL 4.0 compability */
962 void
963 avgcost_reset(UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message)
965 avgcost_clear(initid, is_null, message);
966 avgcost_add(initid, args, is_null, message);
969 /* This is needed to get things to work in MySQL 4.1.1 and above */
971 void
972 avgcost_clear(UDF_INIT* initid, char* is_null __attribute__((unused)),
973 char* message __attribute__((unused)))
975 struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
976 data->totalprice= 0.0;
977 data->totalquantity= 0;
978 data->count= 0;
982 void
983 avgcost_add(UDF_INIT* initid, UDF_ARGS* args,
984 char* is_null __attribute__((unused)),
985 char* message __attribute__((unused)))
987 if (args->args[0] && args->args[1])
989 struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
990 longlong quantity = *((longlong*)args->args[0]);
991 longlong newquantity = data->totalquantity + quantity;
992 double price = *((double*)args->args[1]);
994 data->count++;
996 if ( ((data->totalquantity >= 0) && (quantity < 0))
997 || ((data->totalquantity < 0) && (quantity > 0)) )
1000 ** passing from + to - or from - to +
1002 if ( ((quantity < 0) && (newquantity < 0))
1003 || ((quantity > 0) && (newquantity > 0)) )
1005 data->totalprice = price * (double)newquantity;
1008 ** sub q if totalq > 0
1009 ** add q if totalq < 0
1011 else
1013 price = data->totalprice / (double)data->totalquantity;
1014 data->totalprice = price * (double)newquantity;
1016 data->totalquantity = newquantity;
1018 else
1020 data->totalquantity += quantity;
1021 data->totalprice += price * (double)quantity;
1024 if (data->totalquantity == 0)
1025 data->totalprice = 0.0;
1030 double
1031 avgcost( UDF_INIT* initid, UDF_ARGS* args __attribute__((unused)),
1032 char* is_null, char* error __attribute__((unused)))
1034 struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
1035 if (!data->count || !data->totalquantity)
1037 *is_null = 1;
1038 return 0.0;
1041 *is_null = 0;
1042 return data->totalprice/(double)data->totalquantity;
1045 my_bool myfunc_argument_name_init(UDF_INIT *initid, UDF_ARGS *args,
1046 char *message);
1047 char *myfunc_argument_name(UDF_INIT *initid, UDF_ARGS *args, char *result,
1048 unsigned long *length, char *null_value,
1049 char *error);
1051 my_bool myfunc_argument_name_init(UDF_INIT *initid, UDF_ARGS *args,
1052 char *message)
1054 if (args->arg_count != 1)
1056 strmov(message,"myfunc_argument_name_init accepts only one argument");
1057 return 1;
1059 initid->max_length= args->attribute_lengths[0];
1060 initid->maybe_null= 1;
1061 initid->const_item= 1;
1062 return 0;
1065 char *myfunc_argument_name(UDF_INIT *initid __attribute__((unused)),
1066 UDF_ARGS *args, char *result,
1067 unsigned long *length, char *null_value,
1068 char *error __attribute__((unused)))
1070 if (!args->attributes[0])
1072 *null_value= 1;
1073 return 0;
1075 (*length)--; /* space for ending \0 (for debugging purposes) */
1076 if (*length > args->attribute_lengths[0])
1077 *length= args->attribute_lengths[0];
1078 memcpy(result, args->attributes[0], *length);
1079 result[*length]= 0;
1080 return result;
1085 my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
1087 if (args->arg_count != 1)
1089 strmov(message, "IS_CONST accepts only one argument");
1090 return 1;
1092 initid->ptr= (char*)((args->args[0] != NULL) ? 1UL : 0);
1093 return 0;
1096 char * is_const(UDF_INIT *initid, UDF_ARGS *args __attribute__((unused)),
1097 char *result, unsigned long *length,
1098 char *is_null, char *error __attribute__((unused)))
1100 if (initid->ptr != 0) {
1101 sprintf(result, "const");
1102 } else {
1103 sprintf(result, "not const");
1105 *is_null= 0;
1106 *length= (uint) strlen(result);
1107 return result;
1112 my_bool check_const_len_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
1114 if (args->arg_count != 1)
1116 strmov(message, "CHECK_CONST_LEN accepts only one argument");
1117 return 1;
1119 if (args->args[0] == 0)
1121 initid->ptr= (char*)"Not constant";
1123 else if(strlen(args->args[0]) == args->lengths[0])
1125 initid->ptr= (char*)"Correct length";
1127 else
1129 initid->ptr= (char*)"Wrong length";
1131 initid->max_length = 100;
1132 return 0;
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)))
1139 strmov(result, initid->ptr);
1140 *length= (uint) strlen(result);
1141 *is_null= 0;
1142 return result;
1146 #endif /* HAVE_DLOPEN */