6060**
6161** Function 'myfunc_argument_name' returns name of argument.
6262**
63+ ** Aggregate function 'avgcost' returns the weighted average cost from
64+ ** (quantity, price) pairs: sum of (price * quantity) divided by total
65+ ** quantity across all rows.
66+ **
67+ ** Aggregate function 'avg2' returns sum/count given (count, sum) pairs;
68+ ** demonstrates an aggregate that also supports the remove operation
69+ ** (usable as a window function).
70+ **
71+ ** Function 'is_const' returns "const" if its argument is a constant
72+ ** expression (known at query parse time), and "not const" otherwise.
73+ **
74+ ** Function 'check_const_len' verifies that strlen() of its argument matches
75+ ** the length reported by the server, returning "Correct length",
76+ ** "Wrong length", or "Not constant".
77+ **
6378** On the end is a couple of functions that converts hostnames to ip and
6479** vice versa.
6580**
85100** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
86101** CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
87102** CREATE FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so";
103+ ** CREATE AGGREGATE FUNCTION avg2 RETURNS REAL SONAME "udf_example.so";
104+ ** CREATE FUNCTION is_const RETURNS STRING SONAME "udf_example.so";
105+ ** CREATE FUNCTION check_const_len RETURNS STRING SONAME "udf_example.so";
88106**
89107** After this the functions will work exactly like native MySQL functions.
90108** Functions should be created only once.
98116** DROP FUNCTION reverse_lookup;
99117** DROP FUNCTION avgcost;
100118** DROP FUNCTION myfunc_argument_name;
119+ ** DROP FUNCTION udf_sequence;
120+ ** DROP FUNCTION avg2;
121+ ** DROP FUNCTION is_const;
122+ ** DROP FUNCTION check_const_len;
101123**
102124** The CREATE FUNCTION and DROP FUNCTION update the func@mysql table. All
103125** Active function will be reloaded on every restart of server
117139#define _WINSOCK_DEPRECATED_NO_WARNINGS
118140#endif
119141
120- #ifdef STANDARD
121- /* STANDARD is defined, don't use any mysql functions */
142+ #include <my_global.h>
143+ #include <my_pthread.h>
122144#include <stdlib.h>
123145#include <stdio.h>
124146#include <string.h>
125- #ifdef _WIN32
126- typedef unsigned __int64 ulonglong ; /* Microsofts 64 bit types */
127- typedef __int64 longlong ;
128- #else
129- typedef unsigned long long ulonglong ;
130- typedef long long longlong ;
131- #endif /*_WIN32*/
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>
145147#include <ctype.h>
148+ #include <assert.h>
149+ #include <mysql.h>
146150
147151
148152#ifdef HAVE_DLOPEN
@@ -654,18 +658,18 @@ my_bool udf_sequence_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
654658{
655659 if (args -> arg_count > 1 )
656660 {
657- strmov (message ,"This function takes none or 1 argument" );
661+ strcpy (message ,"This function takes none or 1 argument" );
658662 return 1 ;
659663 }
660664 if (args -> arg_count )
661665 args -> arg_type [0 ]= INT_RESULT ; /* Force argument to int */
662666
663667 if (!(initid -> ptr = (char * ) malloc (sizeof (longlong ))))
664668 {
665- strmov (message ,"Couldn't allocate memory" );
669+ strcpy (message ,"Couldn't allocate memory" );
666670 return 1 ;
667671 }
668- bzero (initid -> ptr ,sizeof (longlong ));
672+ memset (initid -> ptr , 0 ,sizeof (longlong ));
669673 /*
670674 udf_sequence() is a non-deterministic function : it has different value
671675 even if called with the same arguments.
@@ -731,10 +735,10 @@ my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
731735{
732736 if (args -> arg_count != 1 || args -> arg_type [0 ] != STRING_RESULT )
733737 {
734- strmov (message ,"Wrong arguments to lookup; Use the source" );
738+ strcpy (message ,"Wrong arguments to lookup; Use the source" );
735739 return 1 ;
736740 }
737- initid -> max_length = 11 ;
741+ initid -> max_length = 15 ; /* "xxx.xxx.xxx.xxx" */
738742 initid -> maybe_null = 1 ;
739743#if !defined(HAVE_GETHOSTBYADDR_R ) || !defined(HAVE_SOLARIS_STYLE_GETHOST )
740744 (void ) pthread_mutex_init (& LOCK_hostname ,MY_MUTEX_INIT_SLOW );
@@ -749,7 +753,7 @@ void lookup_deinit(UDF_INIT *initid __attribute__((unused)))
749753#endif
750754}
751755
752- char * lookup (UDF_INIT * initid __attribute__(( unused )) , UDF_ARGS * args ,
756+ char * lookup (UDF_INIT * initid , UDF_ARGS * args ,
753757 char * result , unsigned long * res_length , uchar * null_value ,
754758 uchar * error __attribute__((unused )))
755759{
@@ -762,6 +766,7 @@ char *lookup(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
762766 struct hostent tmp_hostent ;
763767#endif
764768 struct in_addr in ;
769+ const char * ip_str ;
765770
766771 if (!args -> args [0 ] || !(length = args -> lengths [0 ]))
767772 {
@@ -790,7 +795,12 @@ char *lookup(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
790795 pthread_mutex_unlock (& LOCK_hostname );
791796#endif
792797 memcpy (& in , * hostent -> h_addr_list , sizeof (in .s_addr ));
793- * res_length = (ulong ) (strmov (result , inet_ntoa (in )) - result );
798+ ip_str = inet_ntoa (in );
799+ * res_length = (ulong ) strlen (ip_str );
800+ if (* res_length > initid -> max_length )
801+ * res_length = initid -> max_length ;
802+ memcpy (result , ip_str , * res_length );
803+ result [* res_length ]= 0 ;
794804 return result ;
795805}
796806
@@ -810,11 +820,11 @@ my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
810820 INT_RESULT ;
811821 else
812822 {
813- strmov (message ,
823+ strcpy (message ,
814824 "Wrong number of arguments to reverse_lookup; Use the source" );
815825 return 1 ;
816826 }
817- initid -> max_length = 32 ;
827+ initid -> max_length = 255 ; /* POSIX host name maximum */
818828 initid -> maybe_null = 1 ;
819829#if !defined(HAVE_GETHOSTBYADDR_R ) || !defined(HAVE_SOLARIS_STYLE_GETHOST )
820830 (void ) pthread_mutex_init (& LOCK_hostname ,MY_MUTEX_INIT_SLOW );
@@ -829,7 +839,7 @@ void reverse_lookup_deinit(UDF_INIT *initid __attribute__((unused)))
829839#endif
830840}
831841
832- char * reverse_lookup (UDF_INIT * initid __attribute__(( unused )) , UDF_ARGS * args ,
842+ char * reverse_lookup (UDF_INIT * initid , UDF_ARGS * args ,
833843 char * result , unsigned long * res_length ,
834844 uchar * null_value , uchar * error __attribute__((unused )))
835845{
@@ -849,7 +859,7 @@ char *reverse_lookup(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
849859 * null_value = 1 ;
850860 return 0 ;
851861 }
852- sprintf (result ,"%d.%d.%d.%d" ,
862+ snprintf (result , sizeof ( "xxx.xxx.xxx.xxx" ), "%d.%d.%d.%d" ,
853863 (int ) * ((longlong * ) args -> args [0 ]),
854864 (int ) * ((longlong * ) args -> args [1 ]),
855865 (int ) * ((longlong * ) args -> args [2 ]),
@@ -893,7 +903,12 @@ char *reverse_lookup(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
893903 }
894904 pthread_mutex_unlock (& LOCK_hostname );
895905#endif
896- * res_length = (ulong ) (strmov (result ,hp -> h_name ) - result );
906+ length = (uint ) strlen (hp -> h_name );
907+ if (length >= initid -> max_length ) /* leave room for NUL */
908+ length = initid -> max_length - 1 ;
909+ memcpy (result , hp -> h_name , length );
910+ result [length ]= 0 ;
911+ * res_length = (ulong ) length ;
897912 return result ;
898913}
899914
@@ -954,7 +969,7 @@ avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message )
954969
955970 if (!(data = (struct avgcost_data * ) malloc (sizeof (struct avgcost_data ))))
956971 {
957- strmov (message ,"Couldn't allocate memory" );
972+ strcpy (message ,"Couldn't allocate memory" );
958973 return 1 ;
959974 }
960975 data -> totalquantity = 0 ;
@@ -1101,7 +1116,7 @@ avg2_init( UDF_INIT* initid, UDF_ARGS* args, char* message )
11011116
11021117 if (!(data = (struct avg2_data * ) malloc (sizeof (struct avg2_data ))))
11031118 {
1104- strmov (message ,"Couldn't allocate memory" );
1119+ strcpy (message ,"Couldn't allocate memory" );
11051120 return 1 ;
11061121 }
11071122 data -> count = 0 ;
@@ -1200,7 +1215,7 @@ my_bool myfunc_argument_name_init(UDF_INIT *initid, UDF_ARGS *args,
12001215{
12011216 if (args -> arg_count != 1 )
12021217 {
1203- strmov (message ,"myfunc_argument_name_init accepts only one argument" );
1218+ strcpy (message ,"myfunc_argument_name_init accepts only one argument" );
12041219 return 1 ;
12051220 }
12061221 initid -> max_length = args -> attribute_lengths [0 ];
@@ -1233,7 +1248,7 @@ my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
12331248{
12341249 if (args -> arg_count != 1 )
12351250 {
1236- strmov (message , "IS_CONST accepts only one argument" );
1251+ strcpy (message , "IS_CONST accepts only one argument" );
12371252 return 1 ;
12381253 }
12391254 initid -> ptr = (char * )((args -> args [0 ] != NULL ) ? (size_t )1 : (size_t )0 );
@@ -1260,7 +1275,7 @@ my_bool check_const_len_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
12601275{
12611276 if (args -> arg_count != 1 )
12621277 {
1263- strmov (message , "CHECK_CONST_LEN accepts only one argument" );
1278+ strcpy (message , "CHECK_CONST_LEN accepts only one argument" );
12641279 return 1 ;
12651280 }
12661281 if (args -> args [0 ] == 0 )
@@ -1283,7 +1298,7 @@ char * check_const_len(UDF_INIT *initid, UDF_ARGS *args __attribute__((unused)),
12831298 char * result , unsigned long * length ,
12841299 uchar * is_null ,uchar * error __attribute__((unused )))
12851300{
1286- strmov (result , initid -> ptr );
1301+ strcpy (result , initid -> ptr );
12871302 * length = (uint ) strlen (result );
12881303 * is_null = 0 ;
12891304 return result ;
0 commit comments