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 "regr_avgx.h"
22 #include "bytestream.h"
23 #include "objectreader.h"
24 
25 using namespace mcsv1sdk;
26 
27 class Add_regr_avgx_ToUDAFMap
28 {
29 public:
Add_regr_avgx_ToUDAFMap()30     Add_regr_avgx_ToUDAFMap()
31     {
32         UDAFMap::getMap()["regr_avgx"] = new regr_avgx();
33     }
34 };
35 
36 static Add_regr_avgx_ToUDAFMap addToMap;
37 
38 #define DATATYPE double
39 
40 // Use the simple data model
41 struct regr_avgx_data
42 {
43     long double sum;
44     uint64_t	cnt;
45 };
46 
47 
init(mcsv1Context * context,ColumnDatum * colTypes)48 mcsv1_UDAF::ReturnCode regr_avgx::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("regr_avgx() with other than 2 arguments");
56         return mcsv1_UDAF::ERROR;
57     }
58 
59     if (!(isNumeric(colTypes[1].dataType)))
60     {
61         // The error message will be prepended with
62         // "The storage engine for the table doesn't support "
63         context->setErrorMessage("regr_avgx() with a non-numeric x argument");
64         return mcsv1_UDAF::ERROR;
65     }
66 
67     context->setUserDataSize(sizeof(regr_avgx_data));
68     context->setResultType(execplan::CalpontSystemCatalog::DOUBLE);
69     context->setColWidth(8);
70     context->setScale(colTypes[1].scale + 4);
71     context->setPrecision(19);
72     context->setRunFlag(mcsv1sdk::UDAF_IGNORE_NULLS);
73     return mcsv1_UDAF::SUCCESS;
74 
75 }
76 
reset(mcsv1Context * context)77 mcsv1_UDAF::ReturnCode regr_avgx::reset(mcsv1Context* context)
78 {
79     struct  regr_avgx_data* data = (struct regr_avgx_data*)context->getUserData()->data;
80     data->sum = 0;
81     data->cnt = 0;
82     return mcsv1_UDAF::SUCCESS;
83 }
84 
nextValue(mcsv1Context * context,ColumnDatum * valsIn)85 mcsv1_UDAF::ReturnCode regr_avgx::nextValue(mcsv1Context* context, ColumnDatum* valsIn)
86 {
87     static_any::any& valIn_x = valsIn[1].columnData;
88     struct  regr_avgx_data* data = (struct regr_avgx_data*)context->getUserData()->data;
89     DATATYPE val = convertAnyTo<double>(valIn_x);
90 
91     // For decimal types, we need to move the decimal point.
92     uint32_t scale = valsIn[1].scale;
93     if (val != 0 && scale > 0)
94     {
95         val /= pow(10.0, (double)scale);
96     }
97 
98     data->sum += val;
99     ++data->cnt;
100 
101     return mcsv1_UDAF::SUCCESS;
102 }
103 
subEvaluate(mcsv1Context * context,const UserData * userDataIn)104 mcsv1_UDAF::ReturnCode regr_avgx::subEvaluate(mcsv1Context* context, const UserData* userDataIn)
105 {
106     if (!userDataIn)
107     {
108         return mcsv1_UDAF::SUCCESS;
109     }
110 
111     struct regr_avgx_data* outData = (struct regr_avgx_data*)context->getUserData()->data;
112 
113     struct regr_avgx_data* inData = (struct regr_avgx_data*)userDataIn->data;
114 
115     outData->sum += inData->sum;
116 
117     outData->cnt += inData->cnt;
118 
119     return mcsv1_UDAF::SUCCESS;
120 }
121 
evaluate(mcsv1Context * context,static_any::any & valOut)122 mcsv1_UDAF::ReturnCode regr_avgx::evaluate(mcsv1Context* context, static_any::any& valOut)
123 {
124     struct regr_avgx_data* data = (struct regr_avgx_data*)context->getUserData()->data;
125 
126     if (data->cnt > 0)
127     {
128         valOut = static_cast<double>(data->sum / (long double)data->cnt);
129     }
130 
131     return mcsv1_UDAF::SUCCESS;
132 }
133 
dropValue(mcsv1Context * context,ColumnDatum * valsDropped)134 mcsv1_UDAF::ReturnCode regr_avgx::dropValue(mcsv1Context* context, ColumnDatum* valsDropped)
135 {
136     static_any::any& valIn_x = valsDropped[1].columnData;
137     struct regr_avgx_data* data = (struct regr_avgx_data*)context->getUserData()->data;
138     double val = convertAnyTo<double>(valIn_x);
139 
140     // For decimal types, we need to move the decimal point.
141     uint32_t scale = valsDropped[1].scale;
142     if (val != 0 && scale > 0)
143     {
144         val /= pow(10.0, (double)scale);
145     }
146 
147     data->sum -= val;
148     --data->cnt;
149 
150     return mcsv1_UDAF::SUCCESS;
151 }
152 
153