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