diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index dba39fe86..c4486ddd5 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -25,3 +25,5 @@ add_subdirectory(thrift) add_subdirectory(querytele) add_subdirectory(clusterTester) add_subdirectory(libmysql_client) +add_subdirectory(regr) + diff --git a/utils/regr/regr.vpj b/utils/regr/regr.vpj new file mode 100644 index 000000000..d99a1d436 --- /dev/null +++ b/utils/regr/regr.vpj @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/udfsdk/regr_avgx.cpp b/utils/regr/regr_avgx.cpp similarity index 95% rename from utils/udfsdk/regr_avgx.cpp rename to utils/regr/regr_avgx.cpp index e99871f97..1230df84c 100644 --- a/utils/udfsdk/regr_avgx.cpp +++ b/utils/regr/regr_avgx.cpp @@ -24,6 +24,17 @@ using namespace mcsv1sdk; +class Add_regr_avgx_ToUDAFMap +{ +public: + Add_regr_avgx_ToUDAFMap() + { + UDAFMap::getMap()["regr_avgx"] = new regr_avgx(); + } +}; + +static Add_regr_avgx_ToUDAFMap addToMap; + #define DATATYPE double // Use the simple data model @@ -196,6 +207,10 @@ mcsv1_UDAF::ReturnCode regr_avgx::dropValue(mcsv1Context* context, ColumnDatum* struct regr_avgx_data* data = (struct regr_avgx_data*)context->getUserData()->data; DATATYPE val = 0.0; + if (context->isParamNull(0) || context->isParamNull(1)) + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } if (valIn_x.empty() || valIn_y.empty()) { return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. diff --git a/utils/udfsdk/regr_avgx.h b/utils/regr/regr_avgx.h similarity index 99% rename from utils/udfsdk/regr_avgx.h rename to utils/regr/regr_avgx.h index 27b8708f7..75791f769 100644 --- a/utils/udfsdk/regr_avgx.h +++ b/utils/regr/regr_avgx.h @@ -26,7 +26,7 @@ * * * CREATE AGGREGATE FUNCTION regr_avgx returns REAL soname - * 'libudf_mysql.so'; + * 'libregr_mysql.so'; * */ #ifndef HEADER_regr_avgx diff --git a/utils/regr/regr_avgy.cpp b/utils/regr/regr_avgy.cpp new file mode 100644 index 000000000..667019a33 --- /dev/null +++ b/utils/regr/regr_avgy.cpp @@ -0,0 +1,281 @@ +/* Copyright (C) 2017 MariaDB Corporaton + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include +#include +#include +#include "regr_avgy.h" +#include "bytestream.h" +#include "objectreader.h" + +using namespace mcsv1sdk; + +class Add_regr_avgy_ToUDAFMap +{ +public: + Add_regr_avgy_ToUDAFMap() + { + UDAFMap::getMap()["regr_avgy"] = new regr_avgy(); + } +}; + +static Add_regr_avgy_ToUDAFMap addToMap; + +#define DATATYPE double + +// Use the simple data model +struct regr_avgy_data +{ + double sum; + uint64_t cnt; +}; + + +mcsv1_UDAF::ReturnCode regr_avgy::init(mcsv1Context* context, + ColumnDatum* colTypes) +{ + if (context->getParameterCount() != 2) + { + // The error message will be prepended with + // "The storage engine for the table doesn't support " + context->setErrorMessage("regr_avgy() with other than 2 arguments"); + return mcsv1_UDAF::ERROR; + } + + if (!(isNumeric(colTypes[0].dataType))) + { + // The error message will be prepended with + // "The storage engine for the table doesn't support " + context->setErrorMessage("regr_avgy() with a non-numeric x argument"); + return mcsv1_UDAF::ERROR; + } + + context->setUserDataSize(sizeof(regr_avgy_data)); + context->setResultType(CalpontSystemCatalog::DOUBLE); + context->setColWidth(8); + context->setScale(colTypes[0].scale + 4); + context->setPrecision(19); + context->setRunFlag(mcsv1sdk::UDAF_IGNORE_NULLS); + return mcsv1_UDAF::SUCCESS; + +} + +mcsv1_UDAF::ReturnCode regr_avgy::reset(mcsv1Context* context) +{ + struct regr_avgy_data* data = (struct regr_avgy_data*)context->getUserData()->data; + data->sum = 0; + data->cnt = 0; + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode regr_avgy::nextValue(mcsv1Context* context, ColumnDatum* valsIn) +{ + static_any::any& valIn_y = valsIn[0].columnData; + static_any::any& valIn_x = valsIn[1].columnData; + struct regr_avgy_data* data = (struct regr_avgy_data*)context->getUserData()->data; + DATATYPE val = 0.0; + + if (context->isParamNull(0) || context->isParamNull(1)) + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + if (valIn_x.empty() || valIn_y.empty()) // Usually empty if NULL. Probably redundant + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + + if (valIn_y.compatible(longTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(charTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(scharTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(shortTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(intTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(llTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(ucharTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(ushortTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(uintTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(ulongTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(ullTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(floatTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(doubleTypeId)) + { + val = valIn_y.cast(); + } + + // For decimal types, we need to move the decimal point. + uint32_t scale = valsIn[0].scale; + + if (val != 0 && scale > 0) + { + val /= pow(10.0, (double)scale); + } + + data->sum += val; + ++data->cnt; + + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode regr_avgy::subEvaluate(mcsv1Context* context, const UserData* userDataIn) +{ + if (!userDataIn) + { + return mcsv1_UDAF::SUCCESS; + } + + struct regr_avgy_data* outData = (struct regr_avgy_data*)context->getUserData()->data; + struct regr_avgy_data* inData = (struct regr_avgy_data*)userDataIn->data; + + outData->sum += inData->sum; + outData->cnt += inData->cnt; + + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode regr_avgy::evaluate(mcsv1Context* context, static_any::any& valOut) +{ + struct regr_avgy_data* data = (struct regr_avgy_data*)context->getUserData()->data; + + if (data->cnt == 0) + { + valOut = 0; + } + else + { + valOut = data->sum / (double)data->cnt; + } + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode regr_avgy::dropValue(mcsv1Context* context, ColumnDatum* valsDropped) +{ + static_any::any& valIn_y = valsDropped[0].columnData; + static_any::any& valIn_x = valsDropped[1].columnData; + struct regr_avgy_data* data = (struct regr_avgy_data*)context->getUserData()->data; + DATATYPE val = 0.0; + + if (context->isParamNull(0) || context->isParamNull(1)) + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + if (valIn_x.empty() || valIn_y.empty()) + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + + if (valIn_y.compatible(charTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(scharTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(shortTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(intTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(longTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(llTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(ucharTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(ushortTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(uintTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(ulongTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(ullTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(floatTypeId)) + { + val = valIn_y.cast(); + } + else if (valIn_y.compatible(doubleTypeId)) + { + val = valIn_y.cast(); + } + + // For decimal types, we need to move the decimal point. + uint32_t scale = valsDropped[0].scale; + + if (val != 0 && scale > 0) + { + val /= pow(10.0, (double)scale); + } + + data->sum -= val; + --data->cnt; + + return mcsv1_UDAF::SUCCESS; +} + diff --git a/utils/regr/regr_avgy.h b/utils/regr/regr_avgy.h new file mode 100644 index 000000000..c99021f9f --- /dev/null +++ b/utils/regr/regr_avgy.h @@ -0,0 +1,88 @@ +/* Copyright (C) 2017 MariaDB Corporaton + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/*********************************************************************** +* $Id$ +* +* regr_avgy.h +***********************************************************************/ + +/** + * Columnstore interface for for the regr_avgy function + * + * + * CREATE AGGREGATE FUNCTION regr_avgy returns REAL soname + * 'libregr_mysql.so'; + * + */ +#ifndef HEADER_regr_avgy +#define HEADER_regr_avgy + +#include +#include +#include +#ifdef _MSC_VER +#include +#else +#include +#endif + +#include "mcsv1_udaf.h" +#include "calpontsystemcatalog.h" +#include "windowfunctioncolumn.h" +using namespace execplan; + +#if defined(_MSC_VER) && defined(xxxRGNODE_DLLEXPORT) +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +namespace mcsv1sdk +{ + +// Return the regr_avgy value of the dataset + +class regr_avgy : public mcsv1_UDAF +{ +public: + // Defaults OK + regr_avgy() : mcsv1_UDAF() {}; + virtual ~regr_avgy() {}; + + virtual ReturnCode init(mcsv1Context* context, + ColumnDatum* colTypes); + + virtual ReturnCode reset(mcsv1Context* context); + + virtual ReturnCode nextValue(mcsv1Context* context, ColumnDatum* valsIn); + + virtual ReturnCode subEvaluate(mcsv1Context* context, const UserData* valIn); + + virtual ReturnCode evaluate(mcsv1Context* context, static_any::any& valOut); + + virtual ReturnCode dropValue(mcsv1Context* context, ColumnDatum* valsDropped); + +protected: +}; + +}; // namespace + +#undef EXPORT + +#endif // HEADER_regr_avgy.h + diff --git a/utils/regr/regr_count.cpp b/utils/regr/regr_count.cpp new file mode 100644 index 000000000..c65a1f4a6 --- /dev/null +++ b/utils/regr/regr_count.cpp @@ -0,0 +1,131 @@ +/* Copyright (C) 2017 MariaDB Corporaton + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include +#include +#include +#include "regr_count.h" +#include "bytestream.h" +#include "objectreader.h" + +using namespace mcsv1sdk; + +class Add_regr_count_ToUDAFMap +{ +public: + Add_regr_count_ToUDAFMap() + { + UDAFMap::getMap()["regr_count"] = new regr_count(); + } +}; + +static Add_regr_count_ToUDAFMap addToMap; + +// Use the simple data model +struct regr_count_data +{ + uint64_t cnt; +}; + + +mcsv1_UDAF::ReturnCode regr_count::init(mcsv1Context* context, + ColumnDatum* colTypes) +{ + if (context->getParameterCount() != 2) + { + // The error message will be prepended with + // "The storage engine for the table doesn't support " + context->setErrorMessage("regr_count() with other than 2 arguments"); + return mcsv1_UDAF::ERROR; + } + + context->setUserDataSize(sizeof(regr_count_data)); + context->setResultType(CalpontSystemCatalog::BIGINT); + context->setColWidth(8); + context->setRunFlag(mcsv1sdk::UDAF_IGNORE_NULLS); + return mcsv1_UDAF::SUCCESS; + +} + +mcsv1_UDAF::ReturnCode regr_count::reset(mcsv1Context* context) +{ + struct regr_count_data* data = (struct regr_count_data*)context->getUserData()->data; + data->cnt = 0; + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode regr_count::nextValue(mcsv1Context* context, ColumnDatum* valsIn) +{ + static_any::any& valIn_y = valsIn[0].columnData; + static_any::any& valIn_x = valsIn[1].columnData; + struct regr_count_data* data = (struct regr_count_data*)context->getUserData()->data; + + if (context->isParamNull(0) || context->isParamNull(1)) + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + if (valIn_x.empty() || valIn_y.empty()) // Usually empty if NULL. Probably redundant + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + ++data->cnt; + + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode regr_count::subEvaluate(mcsv1Context* context, const UserData* userDataIn) +{ + if (!userDataIn) + { + return mcsv1_UDAF::SUCCESS; + } + + struct regr_count_data* outData = (struct regr_count_data*)context->getUserData()->data; + struct regr_count_data* inData = (struct regr_count_data*)userDataIn->data; + + outData->cnt += inData->cnt; + + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode regr_count::evaluate(mcsv1Context* context, static_any::any& valOut) +{ + struct regr_count_data* data = (struct regr_count_data*)context->getUserData()->data; + + valOut = data->cnt; + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode regr_count::dropValue(mcsv1Context* context, ColumnDatum* valsDropped) +{ + static_any::any& valIn_y = valsDropped[0].columnData; + static_any::any& valIn_x = valsDropped[1].columnData; + struct regr_count_data* data = (struct regr_count_data*)context->getUserData()->data; + + if (context->isParamNull(0) || context->isParamNull(1)) + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + if (valIn_x.empty() || valIn_y.empty()) + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + --data->cnt; + + return mcsv1_UDAF::SUCCESS; +} + diff --git a/utils/regr/regr_count.h b/utils/regr/regr_count.h new file mode 100644 index 000000000..4f4fc558e --- /dev/null +++ b/utils/regr/regr_count.h @@ -0,0 +1,88 @@ +/* Copyright (C) 2017 MariaDB Corporaton + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/*********************************************************************** +* $Id$ +* +* regr_count.h +***********************************************************************/ + +/** + * Columnstore interface for for the regr_count function + * + * + * CREATE AGGREGATE FUNCTION regr_count returns INTEGER + * soname 'libregr_mysql.so'; + * + */ +#ifndef HEADER_regr_count +#define HEADER_regr_count + +#include +#include +#include +#ifdef _MSC_VER +#include +#else +#include +#endif + +#include "mcsv1_udaf.h" +#include "calpontsystemcatalog.h" +#include "windowfunctioncolumn.h" +using namespace execplan; + +#if defined(_MSC_VER) && defined(xxxRGNODE_DLLEXPORT) +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +namespace mcsv1sdk +{ + +// Return the regr_count value of the dataset + +class regr_count : public mcsv1_UDAF +{ +public: + // Defaults OK + regr_count() : mcsv1_UDAF() {}; + virtual ~regr_count() {}; + + virtual ReturnCode init(mcsv1Context* context, + ColumnDatum* colTypes); + + virtual ReturnCode reset(mcsv1Context* context); + + virtual ReturnCode nextValue(mcsv1Context* context, ColumnDatum* valsIn); + + virtual ReturnCode subEvaluate(mcsv1Context* context, const UserData* valIn); + + virtual ReturnCode evaluate(mcsv1Context* context, static_any::any& valOut); + + virtual ReturnCode dropValue(mcsv1Context* context, ColumnDatum* valsDropped); + +protected: +}; + +}; // namespace + +#undef EXPORT + +#endif // HEADER_regr_count.h + diff --git a/utils/regr/regrmysql.cpp b/utils/regr/regrmysql.cpp new file mode 100644 index 000000000..6870f3050 --- /dev/null +++ b/utils/regr/regrmysql.cpp @@ -0,0 +1,374 @@ +#include +#include +#include +#include +using namespace std; + +#include "idb_mysql.h" + +namespace +{ +inline double cvtArgToDouble(int t, const char* v) +{ + double d = 0.0; + + switch (t) + { + case INT_RESULT: + d = (double)(*((long long*)v)); + break; + + case REAL_RESULT: + d = *((double*)v); + break; + + case DECIMAL_RESULT: + case STRING_RESULT: + d = strtod(v, 0); + break; + + case ROW_RESULT: + break; + } + + return d; +} +inline long long cvtArgToInt(int t, const char* v) +{ + long long ll = 0; + + switch (t) + { + case INT_RESULT: + ll = *((long long*)v); + break; + + case REAL_RESULT: + ll = (long long)(*((double*)v)); + break; + + case DECIMAL_RESULT: + case STRING_RESULT: + ll = strtoll(v, 0, 0); + break; + + case ROW_RESULT: + break; + } + + return ll; +} +inline string cvtArgToString(int t, const char* v) +{ + string str; + + switch (t) + { + case INT_RESULT: + { + long long ll; + ll = *((long long*)v); + ostringstream oss; + oss << ll; + str = oss.str(); + break; + } + + case REAL_RESULT: + { + double d; + d = *((double*)v); + ostringstream oss; + oss << d; + str = oss.str(); + break; + } + + case DECIMAL_RESULT: + case STRING_RESULT: + str = v; + break; + + case ROW_RESULT: + break; + } + + return str; +} +} + +/**************************************************************************** + * UDF function interface for MariaDB connector to recognize is defined in + * this section. MariaDB's UDF function creation guideline needs to be followed. + * + * Three interface need to be defined on the connector for each UDF function. + * + * XXX_init: To allocate the necessary memory for the UDF function and validate + * the input. + * XXX_deinit: To clean up the memory. + * XXX: The function implementation. + * Detailed instruction can be found at MariaDB source directory: + * ~/sql/udf_example.cc. + * + * Please note that the implementation of the function defined on the connector + * will only be called when all the input arguments are constant. e.g., + * mcs_add(2,3). That way, the function does not run in a distributed fashion + * and could be slow. If there is a need for the UDF function to run with + * pure constant input, then one needs to put a implementation in the XXX + * body, which is very similar to the ones in getXXXval API. If there's no + * such need for a given UDF, then the XXX interface can just return a dummy + * result because this function will never be called. + */ +extern "C" +{ + +//======================================================================= + + /** + * regr_avgx connector stub + */ + struct regr_avgx_data + { + double sumx; + int64_t cnt; + }; + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + my_bool regr_avgx_init(UDF_INIT* initid, UDF_ARGS* args, char* message) + { + struct regr_avgx_data* data; + if (args->arg_count != 2) + { + strcpy(message,"regr_avgx() requires two arguments"); + return 1; + } + + if (!(data = (struct regr_avgx_data*) malloc(sizeof(struct regr_avgx_data)))) + { + strmov(message,"Couldn't allocate memory"); + return 1; + } + data->sumx = 0; + data->cnt = 0; + + initid->ptr = (char*)data; + return 0; + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + void regr_avgx_deinit(UDF_INIT* initid) + { + free(initid->ptr); + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + void + regr_avgx_clear(UDF_INIT* initid, char* is_null __attribute__((unused)), + char* message __attribute__((unused))) + { + struct regr_avgx_data* data = (struct regr_avgx_data*)initid->ptr; + data->sumx = 0; + data->cnt = 0; + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + void + regr_avgx_add(UDF_INIT* initid, UDF_ARGS* args, + char* is_null, + char* message __attribute__((unused))) + { + // Test for NULL in x and y + if (args->args[0] == 0 || args->args[1] == 0) + { + return; + } + struct regr_avgx_data* data = (struct regr_avgx_data*)initid->ptr; + double xval = cvtArgToDouble(args->arg_type[1], args->args[1]); + ++data->cnt; + data->sumx += xval; + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + long long regr_avgx(UDF_INIT* initid, UDF_ARGS* args __attribute__((unused)), + char* is_null, char* error __attribute__((unused))) + { + struct regr_avgx_data* data = (struct regr_avgx_data*)initid->ptr; + return data->sumx / data->cnt; + } + +//======================================================================= + + /** + * regr_avgy connector stub + */ + struct regr_avgy_data + { + double sumy; + int64_t cnt; + }; + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + my_bool regr_avgy_init(UDF_INIT* initid, UDF_ARGS* args, char* message) + { + struct regr_avgy_data* data; + if (args->arg_count != 2) + { + strcpy(message,"regr_avgy() requires two arguments"); + return 1; + } + + if (!(data = (struct regr_avgy_data*) malloc(sizeof(struct regr_avgy_data)))) + { + strmov(message,"Couldn't allocate memory"); + return 1; + } + data->sumy = 0; + data->cnt = 0; + + initid->ptr = (char*)data; + return 0; + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + void regr_avgy_deinit(UDF_INIT* initid) + { + free(initid->ptr); + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + void + regr_avgy_clear(UDF_INIT* initid, char* is_null __attribute__((unused)), + char* message __attribute__((unused))) + { + struct regr_avgy_data* data = (struct regr_avgy_data*)initid->ptr; + data->sumy = 0; + data->cnt = 0; + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + void + regr_avgy_add(UDF_INIT* initid, UDF_ARGS* args, + char* is_null, + char* message __attribute__((unused))) + { + // Test for NULL in x and y + if (args->args[0] == 0 || args->args[1] == 0) + { + return; + } + struct regr_avgy_data* data = (struct regr_avgy_data*)initid->ptr; + double yval = cvtArgToDouble(args->arg_type[0], args->args[0]); + ++data->cnt; + data->sumy += yval; + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + long long regr_avgy(UDF_INIT* initid, UDF_ARGS* args __attribute__((unused)), + char* is_null, char* error __attribute__((unused))) + { + struct regr_avgy_data* data = (struct regr_avgy_data*)initid->ptr; + return data->sumy / data->cnt; + } + +//======================================================================= + + /** + * regr_count connector stub + */ + struct regr_count_data + { + int64_t cnt; + }; + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + my_bool regr_count_init(UDF_INIT* initid, UDF_ARGS* args, char* message) + { + struct regr_count_data* data; + if (args->arg_count != 2) + { + strcpy(message,"regr_count() requires two arguments"); + return 1; + } + + if (!(data = (struct regr_count_data*) malloc(sizeof(struct regr_count_data)))) + { + strmov(message,"Couldn't allocate memory"); + return 1; + } + data->cnt = 0; + + initid->ptr = (char*)data; + return 0; + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + void regr_count_deinit(UDF_INIT* initid) + { + free(initid->ptr); + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + void + regr_count_clear(UDF_INIT* initid, char* is_null __attribute__((unused)), + char* message __attribute__((unused))) + { + struct regr_count_data* data = (struct regr_count_data*)initid->ptr; + data->cnt = 0; + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + void + regr_count_add(UDF_INIT* initid, UDF_ARGS* args, + char* is_null, + char* message __attribute__((unused))) + { + // Test for NULL in x and y + if (args->args[0] == 0 || args->args[1] == 0) + { + return; + } + struct regr_count_data* data = (struct regr_count_data*)initid->ptr; + ++data->cnt; + } + + #ifdef _MSC_VER + __declspec(dllexport) + #endif + long long regr_count(UDF_INIT* initid, UDF_ARGS* args __attribute__((unused)), + char* is_null, char* error __attribute__((unused))) + { + struct regr_count_data* data = (struct regr_count_data*)initid->ptr; + return data->cnt; + } +//======================================================================= +} +// vim:ts=4 sw=4: + diff --git a/utils/utils.vpj b/utils/utils.vpj index 53da962f3..d81586008 100755 --- a/utils/utils.vpj +++ b/utils/utils.vpj @@ -292,6 +292,8 @@ Filters="*.bmp"/> + Filters=""> + +