Skip to content

Commit b9bf38d

Browse files
mertbrnraghunandanbhat
authored andcommitted
MDEV-23987 Make udf_example.c portable and warning-free
Replace the bzero/strmov macro shim with direct memset()/strcpy() calls and simplify the include block: always include <my_global.h>, <my_pthread.h>, the standard C headers actually used, and <mysql.h>. This removes the "bzero" redefinition warning triggered by the previous STANDARD-vs-non-STANDARD ifdef split. Fix the result-length computation in lookup() and reverse_lookup(): strcpy() returns the destination pointer, so the original "strcpy(result, ...) - result" expression always evaluated to 0, making both functions return empty strings. Raise initid->max_length to 15 in lookup() and to 255 in reverse_lookup(), and switch the dotted-quad path to snprintf. In reverse_lookup()'s hostname copy, clamp the copy length to initid->max_length - 1 so the NUL terminator fits. Document avgcost, avg2, is_const and check_const_len in the header comment block and add their CREATE/DROP FUNCTION examples.
1 parent 9b325e1 commit b9bf38d

1 file changed

Lines changed: 55 additions & 40 deletions

File tree

sql/udf_example.c

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,21 @@
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
**
@@ -85,6 +100,9 @@
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.
@@ -98,6 +116,10 @@
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
@@ -117,32 +139,14 @@
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

Comments
 (0)