1 /* Copyright (C) 2017 MariaDB Corporation
2
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public License
5 as published by the Free Software Foundation; version 2 of
6 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 Street, Fifth Floor, Boston,
16 MA 02110-1301, USA. */
17
18 #include <sstream>
19 #include <cstring>
20 #include <typeinfo>
21 #include "covar_samp.h"
22 #include "bytestream.h"
23 #include "objectreader.h"
24
25 using namespace mcsv1sdk;
26
27 class Add_covar_samp_ToUDAFMap
28 {
29 public:
Add_covar_samp_ToUDAFMap()30 Add_covar_samp_ToUDAFMap()
31 {
32 UDAFMap::getMap()["covar_samp"] = new covar_samp();
33 }
34 };
35
36 static Add_covar_samp_ToUDAFMap addToMap;
37
38 // Use the simple data model
39 struct covar_samp_data
40 {
41 uint64_t cnt;
42 long double sumx;
43 long double sumy;
44 long double sumxy; // sum of x * y
45 };
46
47
init(mcsv1Context * context,ColumnDatum * colTypes)48 mcsv1_UDAF::ReturnCode covar_samp::init(mcsv1Context* context,
49 ColumnDatum* colTypes)
50 {
51 if (context->getParameterCount() != 2)
52 {
53 // The error message will be prepended with
54 // "The storage engine for the table doesn't support "
55 context->setErrorMessage("covar_samp() with other than 2 arguments");
56 return mcsv1_UDAF::ERROR;
57 }
58 if (!(isNumeric(colTypes[0].dataType) && isNumeric(colTypes[1].dataType)))
59 {
60 // The error message will be prepended with
61 // "The storage engine for the table doesn't support "
62 context->setErrorMessage("covar_samp() with non-numeric arguments");
63 return mcsv1_UDAF::ERROR;
64 }
65
66 context->setUserDataSize(sizeof(covar_samp_data));
67 context->setResultType(execplan::CalpontSystemCatalog::DOUBLE);
68 context->setColWidth(8);
69 context->setScale(DECIMAL_NOT_SPECIFIED);
70 context->setPrecision(0);
71 context->setRunFlag(mcsv1sdk::UDAF_IGNORE_NULLS);
72 return mcsv1_UDAF::SUCCESS;
73
74 }
75
reset(mcsv1Context * context)76 mcsv1_UDAF::ReturnCode covar_samp::reset(mcsv1Context* context)
77 {
78 struct covar_samp_data* data = (struct covar_samp_data*)context->getUserData()->data;
79 data->cnt = 0;
80 data->sumx = 0.0;
81 data->sumy = 0.0;
82 data->sumxy = 0.0;
83 return mcsv1_UDAF::SUCCESS;
84 }
85
nextValue(mcsv1Context * context,ColumnDatum * valsIn)86 mcsv1_UDAF::ReturnCode covar_samp::nextValue(mcsv1Context* context, ColumnDatum* valsIn)
87 {
88 static_any::any& valIn_y = valsIn[0].columnData;
89 static_any::any& valIn_x = valsIn[1].columnData;
90 struct covar_samp_data* data = (struct covar_samp_data*)context->getUserData()->data;
91 double valx = 0.0;
92 double valy = 0.0;
93
94 valx = convertAnyTo<double>(valIn_x);
95 valy = convertAnyTo<double>(valIn_y);
96
97 // For decimal types, we need to move the decimal point.
98 uint32_t scaley = valsIn[0].scale;
99
100 if (valy != 0 && scaley > 0)
101 {
102 valy /= pow(10.0, (double)scaley);
103 }
104
105 data->sumy += valy;
106
107 // For decimal types, we need to move the decimal point.
108 uint32_t scalex = valsIn[1].scale;
109
110 if (valx != 0 && scalex > 0)
111 {
112 valx /= pow(10.0, (double)scalex);
113 }
114
115 data->sumx += valx;
116
117 data->sumxy += valx*valy;
118
119 ++data->cnt;
120
121 return mcsv1_UDAF::SUCCESS;
122 }
123
subEvaluate(mcsv1Context * context,const UserData * userDataIn)124 mcsv1_UDAF::ReturnCode covar_samp::subEvaluate(mcsv1Context* context, const UserData* userDataIn)
125 {
126 if (!userDataIn)
127 {
128 return mcsv1_UDAF::SUCCESS;
129 }
130
131 struct covar_samp_data* outData = (struct covar_samp_data*)context->getUserData()->data;
132 struct covar_samp_data* inData = (struct covar_samp_data*)userDataIn->data;
133
134 outData->sumx += inData->sumx;
135 outData->sumy += inData->sumy;
136 outData->sumxy += inData->sumxy;
137 outData->cnt += inData->cnt;
138
139 return mcsv1_UDAF::SUCCESS;
140 }
141
evaluate(mcsv1Context * context,static_any::any & valOut)142 mcsv1_UDAF::ReturnCode covar_samp::evaluate(mcsv1Context* context, static_any::any& valOut)
143 {
144 struct covar_samp_data* data = (struct covar_samp_data*)context->getUserData()->data;
145 double N = data->cnt;
146 if (N > 1)
147 {
148 long double sumx = data->sumx;
149 long double sumy = data->sumy;
150 long double sumxy = data->sumxy;
151
152 long double covar_samp = (sumxy - ((sumx * sumy) / N)) / (N - 1);
153 valOut = static_cast<double>(covar_samp);
154 }
155 else
156 if (N == 1)
157 {
158 valOut = 0;
159 }
160 return mcsv1_UDAF::SUCCESS;
161 }
162
dropValue(mcsv1Context * context,ColumnDatum * valsDropped)163 mcsv1_UDAF::ReturnCode covar_samp::dropValue(mcsv1Context* context, ColumnDatum* valsDropped)
164 {
165 static_any::any& valIn_y = valsDropped[0].columnData;
166 static_any::any& valIn_x = valsDropped[1].columnData;
167 struct covar_samp_data* data = (struct covar_samp_data*)context->getUserData()->data;
168
169 double valx = 0.0;
170 double valy = 0.0;
171
172 valx = convertAnyTo<double>(valIn_x);
173 valy = convertAnyTo<double>(valIn_y);
174
175 // For decimal types, we need to move the decimal point.
176 uint32_t scaley = valsDropped[0].scale;
177
178 if (valy != 0 && scaley > 0)
179 {
180 valy /= pow(10.0, (double)scaley);
181 }
182
183 data->sumy -= valy;
184
185 // For decimal types, we need to move the decimal point.
186 uint32_t scalex = valsDropped[1].scale;
187
188 if (valx != 0 && scalex > 0)
189 {
190 valx /= pow(10.0, (double)scalex);
191 }
192
193 data->sumx -= valx;
194
195 data->sumxy -= valx*valy;
196 --data->cnt;
197
198 return mcsv1_UDAF::SUCCESS;
199 }
200
201