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
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
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
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'.
117 /* STANDARD is defined, don't use any mysql functions */
122 typedef unsigned __int64 ulonglong
; /* Microsofts 64 bit types */
123 typedef __int64 longlong
;
125 typedef unsigned long long ulonglong
;
126 typedef long long longlong
;
129 #include <my_global.h>
131 #if defined(MYSQL_SERVER)
132 #include <m_string.h> /* To get strmov() */
134 /* when compiled as standalone */
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)
146 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
147 static pthread_mutex_t LOCK_hostname
;
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
,
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
,
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
,
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
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
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
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
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 **************************************************************************/
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");
224 initid
->max_length
=MAXMETAPH
;
228 /****************************************************************************
229 ** Deinit function. This should free all resources allocated by
232 ** initid Return value from xxxx_init
233 ****************************************************************************/
236 void metaphon_deinit(UDF_INIT
*initid
__attribute__((unused
)))
240 /***************************************************************************
241 ** UDF string function.
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
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];
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 */
299 w_end
=word
+args
->lengths
[0];
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 */
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 *----------------------------------------------------------*/
342 if ( *(n
+ 1) == 'H')
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
++ )
371 /* drop duplicates except for CC */
372 if ( *( n
- 1 ) == *n
&& *n
!= 'C' )
375 /* check for F J L M N R or first letter vowel */
376 if ( NOCHANGE ( *n
) ||
377 ( n
== n_start
&& ISVOWEL ( *n
)))
381 case 'B': /* check for -MB */
382 if ( n
< n_end
|| *( n
- 1 ) != 'M' )
386 case 'C': /* C = X ("sh" sound) in CH and CIA */
387 /* = S in CE CI and CY */
388 /* dropped in SCI SCE SCY */
390 if ( *( n
- 1 ) != 'S' ||
393 if ( n
[1] == 'I' && n
[2] == 'A' )
396 if ( MAKESOFT ( n
[1]))
400 *result
++ = (( n
== n_start
&&
402 *( n
- 1 ) == 'S' ) ?
403 (char)'K' : (char)'X';
409 case 'D': /* J before DGE, DGI, DGY, else T */
413 (char)'J' : (char)'T';
416 case 'G': /* complicated, see table in text */
417 if (( n
[1] != 'H' || ISVOWEL ( n
[2]))
434 ( MAKESOFT ( *( n
+ 1 )) &&
436 (char)'J' : (char)'K';
439 !NOGHTOF( *( n
- 3 )) &&
444 case 'H': /* H if before a vowel and not after */
447 if ( !AFFECTH ( *( n
- 1 )) &&
448 ( !ISVOWEL ( *( n
- 1 )) ||
453 case 'K': /* K = K, except dropped after C */
454 if ( *( n
- 1 ) != 'C')
458 case 'P': /* PH = F, else P = P */
459 *result
++ = *( n
+ 1 ) == 'H'
460 ? (char)'F' : (char)'P';
462 case 'Q': /* Q = K (U after Q is already gone */
466 case 'S': /* SH, SIO, SIA = X ("sh" sound) */
467 *result
++ = ( n
[1] == 'H' ||
471 (char)'X' : (char)'S';
474 case 'T': /* TIO, TIA = X ("sh" sound) */
475 /* TH = 0, ("th" sound ) */
476 if ( *( n
+ 1 ) == 'I' && ( n
[2] == 'O'
483 if ( *( n
+ 1) != 'C' || n
[2] != 'H')
487 case 'V': /* V = F */
491 case 'W': /* only exist if a vowel follows */
493 if ( ISVOWEL ( n
[1]))
497 case 'X': /* X = KS, except at start */
502 *result
++ = 'K'; /* insert K, then S */
503 KSflag
= 1; /* this flag will cause S to be
504 inserted on next pass thru loop */
514 *length
= (unsigned long) (result
- org_result
);
519 /***************************************************************************
520 ** UDF double function.
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
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
)
538 if (!args
->arg_count
)
540 strcpy(message
,"myfunc_double must have at least one argument");
544 ** As this function wants to have everything as strings, force all arguments
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 */
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;
563 for (i
= 0; i
< args
->arg_count
; i
++)
565 if (args
->args
[i
] == NULL
)
567 val
+= args
->lengths
[i
];
568 for (j
=args
->lengths
[i
] ; j
-- > 0 ;)
569 v
+= args
->args
[i
][j
];
572 return (double) v
/ (double) val
;
578 /***************************************************************************
579 ** UDF long long function.
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
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
)))
602 for (i
= 0; i
< args
->arg_count
; i
++)
604 if (args
->args
[i
] == NULL
)
606 switch (args
->arg_type
[i
]) {
607 case STRING_RESULT
: /* Add string lengths */
608 val
+= args
->lengths
[i
];
610 case INT_RESULT
: /* Add numbers */
611 val
+= *((longlong
*) args
->args
[i
]);
613 case REAL_RESULT
: /* Add numers as longlong */
614 val
+= (longlong
) *((double*) args
->args
[i
]);
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
)))
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");
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");
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;
663 void sequence_deinit(UDF_INIT
*initid
)
669 longlong
sequence(UDF_INIT
*initid
__attribute__((unused
)), UDF_ARGS
*args
,
670 char *is_null
__attribute__((unused
)),
671 char *error
__attribute__((unused
)))
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 ****************************************************************************/
690 #include <winsock2.h>
692 #include <sys/socket.h>
693 #include <netinet/in.h>
694 #include <arpa/inet.h>
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");
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
);
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
);
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
)))
744 struct hostent
*hostent
;
745 #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
747 char hostname_buff
[2048];
748 struct hostent tmp_hostent
;
752 if (!args
->args
[0] || !(length
=args
->lengths
[0]))
757 if (length
>= sizeof(name_buff
))
758 length
=sizeof(name_buff
)-1;
759 memcpy(name_buff
,args
->args
[0],length
);
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
)))
769 VOID(pthread_mutex_lock(&LOCK_hostname
));
770 if (!(hostent
= gethostbyname((char*) name_buff
)))
772 VOID(pthread_mutex_unlock(&LOCK_hostname
));
776 VOID(pthread_mutex_unlock(&LOCK_hostname
));
778 memcpy_fixed((char*) &in
,(char*) *hostent
->h_addr_list
, sizeof(in
.s_addr
));
779 *res_length
= (ulong
) (strmov(result
, inet_ntoa(in
)) - result
);
784 /****************************************************************************
785 ** return hostname for an IP number.
786 ** The functions can take as arguments a string "xxx.xxx.xxx.xxx" or
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]=
800 "Wrong number of arguments to reverse_lookup; Use the source");
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
);
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
);
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)
824 struct hostent tmp_hostent
;
831 if (args
->arg_count
== 4)
833 if (!args
->args
[0] || !args
->args
[1] ||!args
->args
[2] ||!args
->args
[3])
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]));
845 { /* string argument */
846 if (!args
->args
[0]) /* Return NULL for NULL values */
851 length
=args
->lengths
[0];
852 if (length
>= (uint
) *res_length
-1)
853 length
=(uint
) *res_length
;
854 memcpy(result
,args
->args
[0],length
);
858 taddr
= inet_addr(result
);
859 if (taddr
== (unsigned long) -1L)
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
),
873 VOID(pthread_mutex_lock(&LOCK_hostname
));
874 if (!(hp
= gethostbyaddr((char*) &taddr
, sizeof(taddr
), AF_INET
)))
876 VOID(pthread_mutex_unlock(&LOCK_hostname
));
880 VOID(pthread_mutex_unlock(&LOCK_hostname
));
882 *res_length
=(ulong
) (strmov(result
,hp
->h_name
) - 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>)
900 longlong totalquantity
;
906 ** Average Cost Aggregate Function.
909 avgcost_init( UDF_INIT
* initid
, UDF_ARGS
* args
, char* message
)
911 struct avgcost_data
* data
;
913 if (args
->arg_count
!= 2)
917 "wrong number of arguments: AVGCOST() requires two arguments"
922 if ((args
->arg_type
[0] != INT_RESULT
) || (args
->arg_type
[1] != REAL_RESULT
) )
926 "wrong argument type: AVGCOST() requires an INT and a REAL"
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");
946 data
->totalquantity
= 0;
947 data
->totalprice
= 0.0;
949 initid
->ptr
= (char*)data
;
955 avgcost_deinit( UDF_INIT
* initid
)
961 /* This is only for MySQL 4.0 compability */
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 */
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;
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]);
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
1013 price
= data
->totalprice
/ (double)data
->totalquantity
;
1014 data
->totalprice
= price
* (double)newquantity
;
1016 data
->totalquantity
= newquantity
;
1020 data
->totalquantity
+= quantity
;
1021 data
->totalprice
+= price
* (double)quantity
;
1024 if (data
->totalquantity
== 0)
1025 data
->totalprice
= 0.0;
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
)
1042 return data
->totalprice
/(double)data
->totalquantity
;
1045 my_bool
myfunc_argument_name_init(UDF_INIT
*initid
, UDF_ARGS
*args
,
1047 char *myfunc_argument_name(UDF_INIT
*initid
, UDF_ARGS
*args
, char *result
,
1048 unsigned long *length
, char *null_value
,
1051 my_bool
myfunc_argument_name_init(UDF_INIT
*initid
, UDF_ARGS
*args
,
1054 if (args
->arg_count
!= 1)
1056 strmov(message
,"myfunc_argument_name_init accepts only one argument");
1059 initid
->max_length
= args
->attribute_lengths
[0];
1060 initid
->maybe_null
= 1;
1061 initid
->const_item
= 1;
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])
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
);
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");
1092 initid
->ptr
= (char*)((args
->args
[0] != NULL
) ? 1UL : 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");
1103 sprintf(result
, "not const");
1106 *length
= (uint
) strlen(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");
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";
1129 initid
->ptr
= (char*)"Wrong length";
1131 initid
->max_length
= 100;
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
);
1146 #endif /* HAVE_DLOPEN */