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-1301 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__
126typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */
127typedef __int64 longlong;
128#else
129typedef unsigned long long ulonglong;
130typedef 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)
151static pthread_mutex_t LOCK_hostname;
152#endif
153
154/* These must be right or mysqld will not find the symbol! */
155
156my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
157void metaphon_deinit(UDF_INIT *initid);
158char *metaphon(UDF_INIT *initid, UDF_ARGS *args, char *result,
159 unsigned long *length, char *is_null, char *error);
160my_bool myfunc_double_init(UDF_INIT *, UDF_ARGS *args, char *message);
161double myfunc_double(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
162 char *error);
163my_bool myfunc_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
164longlong myfunc_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
165 char *error);
166my_bool udf_sequence_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
167 void udf_sequence_deinit(UDF_INIT *initid);
168longlong udf_sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
169 char *error);
170my_bool avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message );
171void avgcost_deinit( UDF_INIT* initid );
172void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
173void avgcost_clear( UDF_INIT* initid, char* is_null, char *error );
174void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
175double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
176my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
177char *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
221my_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
240void 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 */
264static 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
286char *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
541my_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
563double 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
602longlong 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*/
634my_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
646my_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
670void udf_sequence_deinit(UDF_INIT *initid)
671{
672 if (initid->ptr)
673 free(initid->ptr);
674}
675
676longlong 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
705my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
706void lookup_deinit(UDF_INIT *initid);
707char *lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
708 unsigned long *length, char *null_value, char *error);
709my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
710void reverse_lookup_deinit(UDF_INIT *initid);
711char *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
723my_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
738void 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
745char *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
797my_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
818void 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
825char *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
904struct avgcost_data
905{
906 ulonglong count;
907 longlong totalquantity;
908 double totalprice;
909};
910
911
912/*
913** Average Cost Aggregate Function.
914*/
915my_bool
916avgcost_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
961void
962avgcost_deinit( UDF_INIT* initid )
963{
964 free(initid->ptr);
965}
966
967
968/* This is only for MySQL 4.0 compability */
969void
970avgcost_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
978void
979avgcost_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
989void
990avgcost_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
1037double
1038avgcost( 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
1052my_bool myfunc_argument_name_init(UDF_INIT *initid, UDF_ARGS *args,
1053 char *message);
1054char *myfunc_argument_name(UDF_INIT *initid, UDF_ARGS *args, char *result,
1055 unsigned long *length, char *null_value,
1056 char *error);
1057
1058my_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
1072char *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
1092my_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
1103char * 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
1119my_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
1142char * 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