diff --git a/utils/udfsdk/avgx.cpp b/utils/udfsdk/avgx.cpp new file mode 100644 index 000000000..887a8418e --- /dev/null +++ b/utils/udfsdk/avgx.cpp @@ -0,0 +1,257 @@ +/* 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 "avgx.h" +#include "bytestream.h" +#include "objectreader.h" + +using namespace mcsv1sdk; + +#define DATATYPE double + +// Use the simple data model +struct avgx_data +{ + double sum; + uint64_t cnt; +}; + + +mcsv1_UDAF::ReturnCode avgx::init(mcsv1Context* context, + ColumnDatum* colTypes) +{ + if (context->getParameterCount() != 1) + { + // The error message will be prepended with + // "The storage engine for the table doesn't support " + context->setErrorMessage("avgx() with other than 1 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("avgx() with a non-numeric x argument"); + return mcsv1_UDAF::ERROR; + } + + context->setUserDataSize(sizeof(avgx_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 avgx::reset(mcsv1Context* context) +{ + struct avgx_data* data = (struct avgx_data*)context->getUserData()->data; + data->sum = 0; + data->cnt = 0; + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode avgx::nextValue(mcsv1Context* context, ColumnDatum* valsIn) +{ + static_any::any& valIn_x = valsIn[0].columnData; + struct avgx_data* data = (struct avgx_data*)context->getUserData()->data; + DATATYPE val = 0.0; + + if (valIn_x.empty()) + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + + if (valIn_x.compatible(longTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(charTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(scharTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(shortTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(intTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(longTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(llTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ucharTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ushortTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(uintTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ulongTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ullTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(floatTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(doubleTypeId)) + { + val = valIn_x.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 avgx::subEvaluate(mcsv1Context* context, const UserData* userDataIn) +{ + if (!userDataIn) + { + return mcsv1_UDAF::SUCCESS; + } + + struct avgx_data* outData = (struct avgx_data*)context->getUserData()->data; + struct avgx_data* inData = (struct avgx_data*)userDataIn->data; + + outData->sum += inData->sum; + outData->cnt += inData->cnt; + + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode avgx::evaluate(mcsv1Context* context, static_any::any& valOut) +{ + struct avgx_data* data = (struct avgx_data*)context->getUserData()->data; + + valOut = data->sum / (double)data->cnt; + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode avgx::dropValue(mcsv1Context* context, ColumnDatum* valsDropped) +{ + static_any::any& valIn_x = valsDropped[0].columnData; + struct avgx_data* data = (struct avgx_data*)context->getUserData()->data; + DATATYPE val = 0.0; + + if (valIn_x.empty()) + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + + if (valIn_x.compatible(charTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(scharTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(shortTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(intTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(longTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(llTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ucharTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ushortTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(uintTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ulongTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ullTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(floatTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(doubleTypeId)) + { + val = valIn_x.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/udfsdk/avgx.h b/utils/udfsdk/avgx.h new file mode 100644 index 000000000..0569b6091 --- /dev/null +++ b/utils/udfsdk/avgx.h @@ -0,0 +1,99 @@ +/* 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$ +* +* avgx.h +***********************************************************************/ + +/** + * Columnstore interface for for the avgx function + * + * + * CREATE AGGREGATE FUNCTION avgx returns REAL soname + * 'libudf_mysql.so'; + * + */ +#ifndef HEADER_avgx +#define HEADER_avgx + +#include +#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 +{ + +// Override mcsv1_UDAF to build your User Defined Aggregate (UDAF) and/or +// User Defined Analytic Function (UDAnF). +// These will be singleton classes, so don't put any instance +// specific data in here. All instance data is stored in mcsv1Context +// passed to each user function and retrieved by the getUserData() method. +// +// Each API function returns a ReturnCode. If ERROR is returned at any time, +// the query is aborted, getInterrupted() will begin to return true and the +// message set in config->setErrorMessage() is returned to MariaDB. + +// Return the avgx value of the dataset + +class avgx : public mcsv1_UDAF +{ +public: + // Defaults OK + avgx() : mcsv1_UDAF() {}; + virtual ~avgx() {}; + + 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_.h + diff --git a/utils/udfsdk/regr_avgx.cpp b/utils/udfsdk/regr_avgx.cpp new file mode 100644 index 000000000..c7cc5b56e --- /dev/null +++ b/utils/udfsdk/regr_avgx.cpp @@ -0,0 +1,270 @@ +/* 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_avgx.h" +#include "bytestream.h" +#include "objectreader.h" + +using namespace mcsv1sdk; + +#define DATATYPE double + +// Use the simple data model +struct regr_avgx_data +{ + double sum; + uint64_t cnt; +}; + + +mcsv1_UDAF::ReturnCode regr_avgx::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_avgx() with other than 2 arguments"); + return mcsv1_UDAF::ERROR; + } + + if (!(isNumeric(colTypes[1].dataType))) + { + // The error message will be prepended with + // "The storage engine for the table doesn't support " + context->setErrorMessage("regr_avgx() with a non-numeric x argument"); + return mcsv1_UDAF::ERROR; + } + + context->setUserDataSize(sizeof(regr_avgx_data)); + context->setResultType(CalpontSystemCatalog::DOUBLE); + context->setColWidth(8); + context->setScale(colTypes[1].scale + 4); + context->setPrecision(19); + context->setRunFlag(mcsv1sdk::UDAF_IGNORE_NULLS); + return mcsv1_UDAF::SUCCESS; + +} + +mcsv1_UDAF::ReturnCode regr_avgx::reset(mcsv1Context* context) +{ + struct regr_avgx_data* data = (struct regr_avgx_data*)context->getUserData()->data; + data->sum = 0; + data->cnt = 0; + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode regr_avgx::nextValue(mcsv1Context* context, ColumnDatum* valsIn) +{ + static_any::any& valIn_y = valsIn[0].columnData; + static_any::any& valIn_x = valsIn[1].columnData; + 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. + } + + if (valIn_x.compatible(longTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(charTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(scharTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(shortTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(intTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(longTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(llTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ucharTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ushortTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(uintTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ulongTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ullTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(floatTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(doubleTypeId)) + { + val = valIn_x.cast(); + } + + // For decimal types, we need to move the decimal point. + uint32_t scale = valsIn[1].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_avgx::subEvaluate(mcsv1Context* context, const UserData* userDataIn) +{ + if (!userDataIn) + { + return mcsv1_UDAF::SUCCESS; + } + + struct regr_avgx_data* outData = (struct regr_avgx_data*)context->getUserData()->data; + struct regr_avgx_data* inData = (struct regr_avgx_data*)userDataIn->data; + + outData->sum += inData->sum; + outData->cnt += inData->cnt; + + return mcsv1_UDAF::SUCCESS; +} + +mcsv1_UDAF::ReturnCode regr_avgx::evaluate(mcsv1Context* context, static_any::any& valOut) +{ + struct regr_avgx_data* data = (struct regr_avgx_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_avgx::dropValue(mcsv1Context* context, ColumnDatum* valsDropped) +{ + static_any::any& valIn_y = valsDropped[0].columnData; + static_any::any& valIn_x = valsDropped[1].columnData; + struct regr_avgx_data* data = (struct regr_avgx_data*)context->getUserData()->data; + DATATYPE val = 0.0; + + if (valIn_x.empty() || valIn_y.empty()) + { + return mcsv1_UDAF::SUCCESS; // Ought not happen when UDAF_IGNORE_NULLS is on. + } + + if (valIn_x.compatible(charTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(scharTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(shortTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(intTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(longTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(llTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ucharTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ushortTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(uintTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ulongTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(ullTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(floatTypeId)) + { + val = valIn_x.cast(); + } + else if (valIn_x.compatible(doubleTypeId)) + { + val = valIn_x.cast(); + } + + // For decimal types, we need to move the decimal point. + uint32_t scale = valsDropped[1].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/udfsdk/regr_avgx.h b/utils/udfsdk/regr_avgx.h new file mode 100644 index 000000000..f70f30d8c --- /dev/null +++ b/utils/udfsdk/regr_avgx.h @@ -0,0 +1,99 @@ +/* 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_avgx.h +***********************************************************************/ + +/** + * Columnstore interface for for the regr_avgx function + * + * + * CREATE AGGREGATE FUNCTION regr_avgx returns REAL soname + * 'libudf_mysql.so'; + * + */ +#ifndef HEADER_regr_avgx +#define HEADER_regr_avgx + +#include +#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 +{ + +// Override mcsv1_UDAF to build your User Defined Aggregate (UDAF) and/or +// User Defined Analytic Function (UDAnF). +// These will be singleton classes, so don't put any instance +// specific data in here. All instance data is stored in mcsv1Context +// passed to each user function and retrieved by the getUserData() method. +// +// Each API function returns a ReturnCode. If ERROR is returned at any time, +// the query is aborted, getInterrupted() will begin to return true and the +// message set in config->setErrorMessage() is returned to MariaDB. + +// Return the regr_avgx value of the dataset + +class regr_avgx : public mcsv1_UDAF +{ +public: + // Defaults OK + regr_avgx() : mcsv1_UDAF() {}; + virtual ~regr_avgx() {}; + + 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_avgx.h +