1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-04-23 07:05:36 +03:00
Sergey Zefirov 5c9770d1e6
fix(funcexp): MCOL-5607: JSON function use crashes query execution (#3028)
JSON functions were implemented violating an assumption of their
pureness, as they should not have any state. This concrete patch
fixes implementation of JSON_VALUE function.
2023-11-21 23:46:03 +03:00

269 lines
7.6 KiB
C++

/* Copyright (C) 2014 InfiniDB, Inc.
Copyright (C) 2019 MariaDB Corporation
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: functor.h 3495 2013-01-21 14:09:51Z rdempsey $
/** @file */
#pragma once
#include <cstdlib>
#include <string>
#include <sstream>
#include <string>
#include <mutex>
#include "parsetree.h"
#include "exceptclasses.h"
#include "errorids.h"
#include "idberrorinfo.h"
#include "calpontsystemcatalog.h"
#include "dataconvert.h"
#include "nullstring.h"
namespace rowgroup
{
class Row;
}
namespace execplan
{
class FunctionColumn;
extern const std::string colDataTypeToString(CalpontSystemCatalog::ColDataType cdt);
} // namespace execplan
namespace funcexp
{
// typedef std::vector<execplan::STNP> FunctionParm;
typedef std::vector<execplan::SPTP> FunctionParm;
constexpr const int32_t MAX_MICROSECOND_PRECISION = 6;
/** @brief Func class
*
* @desc IMPORTANT: functions are pure transformers, they should
* not have state shared between invocations. This is so because
* functions' objects are, essentially, singletons and the same
* objects will be used in diffeent threads.
*/
class Func
{
public:
Func();
Func(const std::string& funcName);
virtual ~Func()
{
}
const std::string funcName() const
{
return fFuncName;
}
void funcName(const std::string funcName)
{
fFuncName = funcName;
}
void raiseIllegalParameterDataTypeError(const execplan::CalpontSystemCatalog::ColType& colType) const
{
std::ostringstream oss;
oss << "Illegal parameter data type " << execplan::colDataTypeToString(colType.colDataType)
<< " for operation " << funcName();
throw logging::IDBExcept(oss.str(), logging::ERR_DATATYPE_NOT_SUPPORT);
}
virtual bool fix(execplan::FunctionColumn& col) const
{
return false;
}
virtual execplan::CalpontSystemCatalog::ColType operationType(
FunctionParm& fp, execplan::CalpontSystemCatalog::ColType& resultType) = 0;
virtual int64_t getIntVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct) = 0;
virtual uint64_t getUintVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
return static_cast<uint64_t>(getIntVal(row, fp, isNull, op_ct));
}
virtual double getDoubleVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct) = 0;
virtual long double getLongDoubleVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct) = 0;
virtual std::string getStrVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct) = 0;
utils::NullString getNullStrVal(rowgroup::Row& row, FunctionParm& fp,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
bool isNull;
std::string val = getStrVal(row, fp, isNull, op_ct);
utils::NullString result;
if (!isNull)
{
result.assign(val);
}
return result;
}
virtual execplan::IDB_Decimal getDecimalVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
return execplan::IDB_Decimal(getIntVal(row, fp, isNull, op_ct), 0, 0);
}
virtual int32_t getDateIntVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
return intToDate(getIntVal(row, fp, isNull, op_ct));
}
virtual int64_t getDatetimeIntVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
return intToDatetime(getIntVal(row, fp, isNull, op_ct));
}
virtual int64_t getTimestampIntVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
return intToTimestamp(getIntVal(row, fp, isNull, op_ct));
}
virtual int64_t getTimeIntVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
return intToTime(getIntVal(row, fp, isNull, op_ct));
}
virtual bool getBoolVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
int64_t intVal = getIntVal(row, fp, isNull, op_ct);
return (!isNull && intVal);
}
virtual float getFloatVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
return getDoubleVal(row, fp, isNull, op_ct);
}
float floatNullVal() const
{
return fFloatNullVal;
}
double doubleNullVal() const
{
return fDoubleNullVal;
}
long double longDoubleNullVal() const
{
return fLongDoubleNullVal;
}
protected:
virtual uint32_t stringToDate(std::string);
virtual uint64_t stringToDatetime(std::string);
virtual uint64_t stringToTimestamp(const std::string&, long);
virtual int64_t stringToTime(std::string);
virtual uint32_t intToDate(int64_t);
virtual uint64_t intToDatetime(int64_t);
virtual uint64_t intToTimestamp(int64_t);
virtual int64_t intToTime(int64_t);
virtual std::string intToString(int64_t);
virtual std::string doubleToString(double);
virtual std::string longDoubleToString(long double);
virtual int64_t nowDatetime();
virtual int64_t addTime(dataconvert::DateTime& dt1, dataconvert::Time& dt2);
virtual int64_t addTime(dataconvert::Time& dt1, dataconvert::Time& dt2);
std::string fFuncName;
private:
// defaults okay
// Func(const Func& rhs);
// Func& operator=(const Func& rhs);
void init();
float fFloatNullVal;
double fDoubleNullVal;
long double fLongDoubleNullVal;
};
class ParmTSInt64 : public datatypes::TSInt64Null
{
public:
ParmTSInt64()
{
}
ParmTSInt64(rowgroup::Row& row, const execplan::SPTP& parm, const funcexp::Func& thisFunc, long timeZone)
: TSInt64Null(parm->data()->toTSInt64Null(row))
{
}
};
class ParmTUInt64 : public datatypes::TUInt64Null
{
public:
ParmTUInt64()
{
}
ParmTUInt64(rowgroup::Row& row, const execplan::SPTP& parm, const funcexp::Func& thisFunc, long timeZone)
: TUInt64Null(parm->data()->toTUInt64Null(row))
{
}
};
template <class TA, class TB>
class Arg2Lazy
{
public:
TA a;
TB b;
Arg2Lazy(rowgroup::Row& row, FunctionParm& parm, const Func& thisFunc, long timeZone)
: a(row, parm[0], thisFunc, timeZone), b(a.isNull() ? TB() : TB(row, parm[1], thisFunc, timeZone))
{
}
};
template <class TA, class TB>
class Arg2Eager
{
public:
TA a;
TB b;
Arg2Eager(rowgroup::Row& row, FunctionParm& parm, const Func& thisFunc, long timeZone)
: a(row, parm[0], thisFunc, timeZone), b(row, parm[1], thisFunc, timeZone)
{
}
};
} // namespace funcexp