1 /*
2   returns the kurtosis of the values in a distribution
3 
4   input parameters:
5   data (real)
6   number of decimals in result (int, optional)
7 
8   output:
9   kurtosis of the distribution (real)
10 
11   registering the function:
12   CREATE AGGREGATE FUNCTION kurtosis RETURNS REAL SONAME 'udf_kurtosis.so';
13 
14   getting rid of the function:
15   DROP FUNCTION kurtosis;
16 
17 */
18 
19 
20 #ifdef STANDARD
21 #include <stdio.h>
22 #include <string.h>
23 #ifdef __WIN__
24 typedef unsigned __int64 ulonglong;
25 typedef __int64 longlong;
26 #else
27 typedef unsigned long long ulonglong;
28 typedef long long longlong;
29 #endif /*__WIN__*/
30 #else
31 #include <my_global.h>
32 #include <my_sys.h>
33 #endif
34 #include <mysql.h>
35 #include <m_ctype.h>
36 #include <m_string.h>
37 #include <math.h>
38 
39 #ifdef HAVE_DLOPEN
40 
41 
42 #define BUFFERSIZE 1024
43 
44 
45 
46 extern "C" {
47 my_bool kurtosis_init( UDF_INIT* initid, UDF_ARGS* args, char* message );
48 void kurtosis_deinit( UDF_INIT* initid );
49 void kurtosis_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
50 void kurtosis_clear( UDF_INIT* initid, char* is_null, char *error );
51 void kurtosis_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
52 double kurtosis( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
53 }
54 
55 
56 struct kurtosis_data
57 {
58   unsigned long count;
59   unsigned long abscount;
60   unsigned long pages;
61   double *values;
62 };
63 
64 
kurtosis_init(UDF_INIT * initid,UDF_ARGS * args,char * message)65 my_bool kurtosis_init( UDF_INIT* initid, UDF_ARGS* args, char* message )
66 {
67   if (args->arg_count < 1 || args->arg_count>2)
68   {
69     strcpy(message,"wrong number of arguments: kurtosis() requires one or two arguments");
70     return 1;
71   }
72 
73   if (args->arg_type[0]!=REAL_RESULT)
74   {
75     strcpy(message,"kurtosis() requires a real as parameter 1");
76     return 1;
77   }
78 
79   if (args->arg_count>1 && (args->arg_type[1]!=INT_RESULT))
80   {
81     strcpy(message,"kurtosis() requires an int as parameter 2");
82     return 1;
83   }
84 
85   initid->decimals=2;
86   if (args->arg_count==2 && (*((ulong*)args->args[1])<=16))
87   {
88     initid->decimals=*((ulong*)args->args[1]);
89   }
90 
91   kurtosis_data *buffer = new kurtosis_data;
92   buffer->count = 0;
93   buffer->abscount=0;
94   buffer->pages = 1;
95   buffer->values = NULL;
96 
97   initid->maybe_null	= 1;
98   initid->max_length	= 32;
99   initid->ptr = (char*)buffer;
100 
101   return 0;
102 }
103 
104 
kurtosis_deinit(UDF_INIT * initid)105 void kurtosis_deinit( UDF_INIT* initid )
106 {
107   kurtosis_data *buffer = (kurtosis_data*)initid->ptr;
108 
109   if (buffer->values != NULL)
110   {
111     free(buffer->values);
112     buffer->values=NULL;
113   }
114   delete initid->ptr;
115 }
116 
117 
118 
kurtosis_reset(UDF_INIT * initid,UDF_ARGS * args,char * is_null,char * is_error)119 void kurtosis_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* is_error )
120 {
121   kurtosis_clear( initid, is_null, is_error );
122   kurtosis_add( initid, args, is_null, is_error );
123 }
124 
125 
kurtosis_clear(UDF_INIT * initid,char * is_null,char * is_error)126 void kurtosis_clear( UDF_INIT* initid, char* is_null, char* is_error )
127 {
128   kurtosis_data *buffer = (kurtosis_data*)initid->ptr;
129   buffer->count = 0;
130   buffer->abscount=0;
131   buffer->pages = 1;
132   *is_null = 0;
133   *is_error = 0;
134 
135   if (buffer->values != NULL)
136   {
137     free(buffer->values);
138     buffer->values=NULL;
139   }
140 
141   buffer->values=(double *) malloc(BUFFERSIZE*sizeof(double));
142 
143 }
144 
145 
kurtosis_add(UDF_INIT * initid,UDF_ARGS * args,char * is_null,char * is_error)146 void kurtosis_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* is_error )
147 {
148   if (args->args[0]!=NULL)
149   {
150     kurtosis_data *buffer = (kurtosis_data*)initid->ptr;
151     if (buffer->count>=BUFFERSIZE)
152     {
153       buffer->pages++;
154       buffer->count=0;
155       buffer->values=(double *) realloc(buffer->values,BUFFERSIZE*buffer->pages*sizeof(double));
156     }
157     buffer->values[buffer->abscount++] = *((double*)args->args[0]);
158     buffer->count++;
159   }
160 }
161 
162 
163 
kurtosis(UDF_INIT * initid,UDF_ARGS * args,char * is_null,char * is_error)164 double kurtosis( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* is_error )
165 {
166   kurtosis_data* buffer = (kurtosis_data*)initid->ptr;
167 
168   *is_null=1;
169   if (buffer->abscount<2 || *is_error!=0)
170   {
171     return 0.0;
172   }
173 
174   ulong i;
175   double mean=0.0; double term=0.0; double stddev=0.0; double kurtosis=0.0;
176 
177   for (i=0;i<buffer->abscount;++i)
178   {
179     mean+=buffer->values[i];
180   }
181 
182   mean/=(double) buffer->abscount;
183 
184   for (i=0;i<buffer->abscount;++i)
185   {
186     term=buffer->values[i]-mean;
187     stddev+=term*term;
188 
189     kurtosis+=term*term*term*term;
190   }
191 
192   stddev/=(double) buffer->abscount;
193   stddev=pow(stddev,0.5);
194 
195   if (stddev==0.0)
196   {
197     return 0.0;
198   }
199 
200   *is_null=0;
201   kurtosis/=((double) buffer->abscount)*stddev*stddev*stddev*stddev;
202 
203   return kurtosis-3.0;
204 }
205 
206 #endif
207 
208