You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-07-29 08:21:15 +03:00
MCOL-641 Initial version of Math operations for wide decimal.
This commit is contained in:
@ -200,7 +200,8 @@ ENDIF()
|
||||
|
||||
|
||||
SET (ENGINE_LDFLAGS "-Wl,--no-as-needed -Wl,--add-needed")
|
||||
SET (ENGINE_COMMON_LIBS messageqcpp loggingcpp configcpp idbboot ${Boost_LIBRARIES} xml2 pthread rt libmysql_client datatypes)
|
||||
SET (ENGINE_DT_LIB datatypes)
|
||||
SET (ENGINE_COMMON_LIBS messageqcpp loggingcpp configcpp idbboot ${Boost_LIBRARIES} xml2 pthread rt libmysql_client ${ENGINE_DT_LIB})
|
||||
SET (ENGINE_OAM_LIBS oamcpp alarmmanager)
|
||||
SET (ENGINE_BRM_LIBS brm idbdatafile cacheutils rwlock ${ENGINE_OAM_LIBS} ${ENGINE_COMMON_LIBS})
|
||||
SET (ENGINE_EXEC_LIBS joblist execplan windowfunction joiner rowgroup funcexp udfsdk regr dataconvert common compress querystats querytele thrift threadpool ${ENGINE_BRM_LIBS})
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
include_directories( ${ENGINE_COMMON_INCLUDES} )
|
||||
set(datatypes_LIB_SRCS
|
||||
csdecimal.cpp)
|
||||
mcs_decimal.cpp)
|
||||
|
||||
add_library(datatypes SHARED ${datatypes_LIB_SRCS})
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
/* Copyright (C) 2020 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. */
|
||||
|
||||
#include "csdecimal.h"
|
||||
|
||||
const datatypes::Decimal someDecimal;
|
||||
|
||||
namespace datatypes
|
||||
{
|
||||
|
||||
int Decimal::compare(const execplan::IDB_Decimal& l, const execplan::IDB_Decimal& r)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end of namespace
|
@ -1,39 +0,0 @@
|
||||
/* Copyright (C) 2020 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. */
|
||||
|
||||
#ifndef H_DECIMALDATATYPE
|
||||
#define H_DECIMALDATATYPE
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace execplan
|
||||
{
|
||||
struct IDB_Decimal;
|
||||
}
|
||||
|
||||
namespace datatypes
|
||||
{
|
||||
class Decimal
|
||||
{
|
||||
public:
|
||||
Decimal() { };
|
||||
~Decimal() { };
|
||||
static int compare(const execplan::IDB_Decimal& l, const execplan::IDB_Decimal& r);
|
||||
};
|
||||
|
||||
} //end of namespace
|
||||
#endif
|
261
datatypes/mcs_decimal.cpp
Normal file
261
datatypes/mcs_decimal.cpp
Normal file
@ -0,0 +1,261 @@
|
||||
/* Copyright (C) 2020 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. */
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "mcs_decimal.h"
|
||||
#include "treenode.h"
|
||||
#include "exceptclasses.h"
|
||||
|
||||
namespace datatypes
|
||||
{
|
||||
template<typename BinaryOperation,
|
||||
typename OpOverflowCheck,
|
||||
typename MultiplicationOverflowCheck>
|
||||
void execute(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r,
|
||||
execplan::IDB_Decimal& result,
|
||||
BinaryOperation op,
|
||||
OpOverflowCheck opOverflowCheck,
|
||||
MultiplicationOverflowCheck mulOverflowCheck)
|
||||
{
|
||||
int128_t lValue = Decimal::isWideDecimalType(l.precision)
|
||||
? l.s128Value : l.value;
|
||||
int128_t rValue = Decimal::isWideDecimalType(l.precision)
|
||||
? r.s128Value : r.value;
|
||||
|
||||
if (result.scale == l.scale && result.scale == r.scale)
|
||||
{
|
||||
opOverflowCheck(lValue, rValue);
|
||||
result.s128Value = op(lValue, rValue);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.scale > l.scale)
|
||||
{
|
||||
int128_t scaleMultiplier;
|
||||
getScaleDivisor(scaleMultiplier, result.scale - l.scale);
|
||||
mulOverflowCheck(lValue, scaleMultiplier);
|
||||
lValue *= scaleMultiplier;
|
||||
}
|
||||
else if (result.scale < l.scale)
|
||||
{
|
||||
int128_t scaleMultiplier;
|
||||
getScaleDivisor(scaleMultiplier, l.scale - result.scale);
|
||||
lValue /= scaleMultiplier;
|
||||
}
|
||||
|
||||
if (result.scale > r.scale)
|
||||
{
|
||||
int128_t scaleMultiplier;
|
||||
getScaleDivisor(scaleMultiplier, result.scale - r.scale);
|
||||
mulOverflowCheck(rValue, scaleMultiplier);
|
||||
rValue *= scaleMultiplier;
|
||||
}
|
||||
else if (result.scale < r.scale)
|
||||
{
|
||||
int128_t scaleMultiplier;
|
||||
getScaleDivisor(scaleMultiplier, r.scale - result.scale);
|
||||
mulOverflowCheck(rValue, scaleMultiplier);
|
||||
rValue /= scaleMultiplier;
|
||||
}
|
||||
|
||||
// We assume there is no way that lValue or rValue calculations
|
||||
// give an overflow and this is an incorrect assumption.
|
||||
opOverflowCheck(lValue, rValue);
|
||||
|
||||
result.s128Value = op(lValue, rValue);
|
||||
}
|
||||
|
||||
// This is wide Decimal version only ATM
|
||||
std::string Decimal::toString(execplan::IDB_Decimal& value)
|
||||
{
|
||||
char buf[utils::MAXLENGTH16BYTES];
|
||||
dataconvert::DataConvert::decimalToString(&value.s128Value,
|
||||
value.scale, buf, sizeof(buf),
|
||||
execplan::CalpontSystemCatalog::DECIMAL);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
int Decimal::compare(const execplan::IDB_Decimal& l, const execplan::IDB_Decimal& r)
|
||||
{
|
||||
int128_t divL, divR;
|
||||
getScaleDivisor(divL, l.scale);
|
||||
getScaleDivisor(divR, r.scale);
|
||||
int128_t quotinentL, quotinentR, remainderL, remainderR;
|
||||
quotinentL = l.s128Value/divL;
|
||||
remainderL = l.s128Value%divL;
|
||||
quotinentR = r.s128Value/divR;
|
||||
remainderR = r.s128Value%divR;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if (quotinentL > quotinentR)
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else if (quotinentL < quotinentR)
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// rem carries the value's sign, but needs to be normalized.
|
||||
int32_t s = l.scale - r.scale;
|
||||
|
||||
if (s < 0)
|
||||
{
|
||||
if ((remainderL * mcs_pow_10[-s]) > remainderR)
|
||||
ret = 1;
|
||||
else if ((remainderL * mcs_pow_10[-s]) < remainderR)
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (remainderL > (remainderR * mcs_pow_10[s]))
|
||||
ret = 1;
|
||||
else if (remainderL < (remainderR * mcs_pow_10[s]))
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// no overflow check
|
||||
template<>
|
||||
void Decimal::addition<int128_t, false>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result)
|
||||
{
|
||||
std::plus<int128_t> add;
|
||||
NoOverflowCheck noOverflowCheck;
|
||||
execute(l, r, result, add, noOverflowCheck, noOverflowCheck);
|
||||
}
|
||||
|
||||
template
|
||||
void Decimal::addition<int128_t, false>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result);
|
||||
|
||||
// with overflow check
|
||||
template<>
|
||||
void Decimal::addition<int128_t, true>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result)
|
||||
{
|
||||
std::plus<int128_t> add;
|
||||
AdditionOverflowCheck overflowCheck;
|
||||
MultiplicationOverflowCheck mulOverflowCheck;
|
||||
execute(l, r, result, add, overflowCheck, mulOverflowCheck);
|
||||
}
|
||||
|
||||
template
|
||||
void Decimal::addition<int128_t, false>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result);
|
||||
|
||||
template<>
|
||||
void Decimal::addition<int64_t, false>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result)
|
||||
{
|
||||
if (result.scale == l.scale && result.scale == r.scale)
|
||||
{
|
||||
result.value = l.value + r.value;
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t lValue = 0, rValue = 0;
|
||||
|
||||
if (result.scale >= l.scale)
|
||||
lValue = l.value * mcs_pow_10[result.scale - l.scale];
|
||||
else
|
||||
lValue = (int64_t)(l.value > 0 ?
|
||||
(double)l.value / mcs_pow_10[l.scale - result.scale] + 0.5 :
|
||||
(double)l.value / mcs_pow_10[l.scale - result.scale] - 0.5);
|
||||
|
||||
if (result.scale >= r.scale)
|
||||
rValue = r.value * mcs_pow_10[result.scale - r.scale];
|
||||
else
|
||||
rValue = (int64_t)(r.value > 0 ?
|
||||
(double)r.value / mcs_pow_10[r.scale - result.scale] + 0.5 :
|
||||
(double)r.value / mcs_pow_10[r.scale - result.scale] - 0.5);
|
||||
|
||||
result.value = lValue + rValue;
|
||||
}
|
||||
template
|
||||
void Decimal::addition<int64_t, false>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result);
|
||||
|
||||
template<>
|
||||
void Decimal::addition<int64_t, true>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result)
|
||||
{
|
||||
throw logging::NotImplementedExcept("Decimal::addition<int64>");
|
||||
}
|
||||
|
||||
template<>
|
||||
void Decimal::division<int128_t, false>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result)
|
||||
{
|
||||
std::divides<int128_t> division;
|
||||
NoOverflowCheck noOverflowCheck;
|
||||
execute(l, r, result, division, noOverflowCheck, noOverflowCheck);
|
||||
}
|
||||
|
||||
template
|
||||
void Decimal::division<int128_t, false>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result);
|
||||
|
||||
// With overflow check
|
||||
template<>
|
||||
void Decimal::division<int128_t, true>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result)
|
||||
{
|
||||
std::divides<int128_t> division;
|
||||
DivisionOverflowCheck overflowCheck;
|
||||
MultiplicationOverflowCheck mulOverflowCheck;
|
||||
execute(l, r, result, division, overflowCheck, mulOverflowCheck);
|
||||
}
|
||||
|
||||
// We rely on the zero check from ArithmeticOperator::execute
|
||||
template<>
|
||||
void Decimal::division<int64_t, false>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result)
|
||||
{
|
||||
if (result.scale >= l.scale - r.scale)
|
||||
result.value = (int64_t)(( (l.value > 0 && r.value > 0)
|
||||
|| (l.value < 0 && r.value < 0) ?
|
||||
(long double)l.value / r.value * mcs_pow_10[result.scale - (l.scale - r.scale)] + 0.5 :
|
||||
(long double)l.value / r.value * mcs_pow_10[result.scale - (l.scale - r.scale)] - 0.5));
|
||||
else
|
||||
result.value = (int64_t)(( (l.value > 0 && r.value > 0)
|
||||
|| (l.value < 0 && r.value < 0) ?
|
||||
(long double)l.value / r.value / mcs_pow_10[l.scale - r.scale - result.scale] + 0.5 :
|
||||
(long double)l.value / r.value / mcs_pow_10[l.scale - r.scale - result.scale] - 0.5));
|
||||
|
||||
}
|
||||
|
||||
template
|
||||
void Decimal::division<int64_t, false>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result);
|
||||
|
||||
template<>
|
||||
void Decimal::division<int64_t, true>(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r, execplan::IDB_Decimal& result)
|
||||
{
|
||||
throw logging::NotImplementedExcept("Decimal::division<int64>");
|
||||
}
|
||||
|
||||
} // end of namespace
|
224
datatypes/mcs_decimal.h
Normal file
224
datatypes/mcs_decimal.h
Normal file
@ -0,0 +1,224 @@
|
||||
/* Copyright (C) 2020 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. */
|
||||
|
||||
#ifndef H_DECIMALDATATYPE
|
||||
#define H_DECIMALDATATYPE
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "calpontsystemcatalog.h"
|
||||
|
||||
using int128_t = __int128;
|
||||
|
||||
namespace execplan
|
||||
{
|
||||
struct IDB_Decimal;
|
||||
}
|
||||
|
||||
namespace datatypes
|
||||
{
|
||||
|
||||
constexpr uint32_t MAXDECIMALWIDTH = 16U;
|
||||
constexpr uint8_t INT64MAXPRECISION = 18U;
|
||||
constexpr uint8_t INT128MAXPRECISION = 38U;
|
||||
|
||||
const uint64_t mcs_pow_10[20] =
|
||||
{
|
||||
1ULL,
|
||||
10ULL,
|
||||
100ULL,
|
||||
1000ULL,
|
||||
10000ULL,
|
||||
100000ULL,
|
||||
1000000ULL,
|
||||
10000000ULL,
|
||||
100000000ULL,
|
||||
1000000000ULL,
|
||||
10000000000ULL,
|
||||
100000000000ULL,
|
||||
1000000000000ULL,
|
||||
10000000000000ULL,
|
||||
100000000000000ULL,
|
||||
1000000000000000ULL,
|
||||
10000000000000000ULL,
|
||||
100000000000000000ULL,
|
||||
1000000000000000000ULL,
|
||||
10000000000000000000ULL
|
||||
};
|
||||
|
||||
constexpr uint32_t maxPowOf10 = sizeof(mcs_pow_10)/sizeof(mcs_pow_10[0])-1;
|
||||
constexpr int128_t Decimal128Null = int128_t(0x8000000000000000LL) << 64;
|
||||
|
||||
/**
|
||||
@brief The function to produce scale multiplier/divisor for
|
||||
wide decimals.
|
||||
*/
|
||||
inline void getScaleDivisor(int128_t& divisor, const int8_t scale)
|
||||
{
|
||||
divisor = 1;
|
||||
switch (scale/maxPowOf10)
|
||||
{
|
||||
case 2:
|
||||
divisor *= mcs_pow_10[maxPowOf10];
|
||||
divisor *= mcs_pow_10[maxPowOf10];
|
||||
break;
|
||||
case 1:
|
||||
divisor *= mcs_pow_10[maxPowOf10];
|
||||
case 0:
|
||||
divisor *= mcs_pow_10[scale%maxPowOf10];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief The template to generalise common math operation
|
||||
execution path using struct from <functional>.
|
||||
*/
|
||||
template<typename BinaryOperation, typename OverflowCheck>
|
||||
void execute(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r,
|
||||
execplan::IDB_Decimal& result,
|
||||
BinaryOperation op,
|
||||
OverflowCheck overflowCheck);
|
||||
|
||||
/**
|
||||
@brief Contains subset of decimal related operations.
|
||||
|
||||
Most of the methods are static to allow to call them from
|
||||
the existing code.
|
||||
The main purpose of the class is to collect methods for a
|
||||
base Datatype class.
|
||||
*/
|
||||
class Decimal
|
||||
{
|
||||
public:
|
||||
Decimal() { };
|
||||
~Decimal() { };
|
||||
|
||||
static constexpr int128_t minInt128 = int128_t(0x8000000000000000LL) << 64;
|
||||
static constexpr int128_t maxInt128 = (int128_t(0x7FFFFFFFFFFFFFFFLL) << 64) + 0xFFFFFFFFFFFFFFFFLL;
|
||||
|
||||
/**
|
||||
@brief Compares two IDB_Decimal taking scale into account.
|
||||
*/
|
||||
static int compare(const execplan::IDB_Decimal& l, const execplan::IDB_Decimal& r);
|
||||
/**
|
||||
@brief Addition template that supports overflow check and
|
||||
two internal representations of decimal.
|
||||
*/
|
||||
template<typename T, bool overflow>
|
||||
static void addition(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r,
|
||||
execplan::IDB_Decimal& result);
|
||||
|
||||
/**
|
||||
@brief Division template that supports overflow check and
|
||||
two internal representations of decimal.
|
||||
*/
|
||||
template<typename T, bool overflow>
|
||||
static void division(const execplan::IDB_Decimal& l,
|
||||
const execplan::IDB_Decimal& r,
|
||||
execplan::IDB_Decimal& result);
|
||||
|
||||
/**
|
||||
@brief Convinience method to put decimal into a std:;string.
|
||||
*/
|
||||
static std::string toString(execplan::IDB_Decimal& value);
|
||||
|
||||
/**
|
||||
@brief The method detects whether decimal type is wide
|
||||
using csc data type.
|
||||
*/
|
||||
static constexpr inline bool isWideDecimalType(const execplan::CalpontSystemCatalog::ColType& ct)
|
||||
{
|
||||
return ((ct.colDataType == execplan::CalpontSystemCatalog::DECIMAL ||
|
||||
ct.colDataType == execplan::CalpontSystemCatalog::UDECIMAL) &&
|
||||
ct.colWidth == MAXDECIMALWIDTH);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief The method detects whether decimal type is wide
|
||||
using precision.
|
||||
*/
|
||||
static constexpr inline bool isWideDecimalType(const int32_t precision)
|
||||
{
|
||||
return precision > INT64MAXPRECISION
|
||||
&& precision <= INT128MAXPRECISION;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@brief The structure contains an overflow check for int128
|
||||
division.
|
||||
*/
|
||||
struct DivisionOverflowCheck {
|
||||
void operator()(const int128_t& x, const int128_t& y)
|
||||
{
|
||||
if (x == Decimal::maxInt128 && y == -1)
|
||||
{
|
||||
throw logging::OperationOverflowExcept(
|
||||
"Decimal::division<int128_t> produces an overflow.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@brief The structure contains an overflow check for int128
|
||||
addition.
|
||||
*/
|
||||
struct MultiplicationOverflowCheck {
|
||||
void operator()(const int128_t& x, const int128_t& y)
|
||||
{
|
||||
if (x * y / x != y)
|
||||
{
|
||||
throw logging::OperationOverflowExcept(
|
||||
"Decimal::multiplication<int128_t> or scale multiplicationproduces an overflow.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@brief The structure contains an overflow check for int128
|
||||
addition.
|
||||
*/
|
||||
struct AdditionOverflowCheck {
|
||||
void operator()(const int128_t& x, const int128_t& y)
|
||||
{
|
||||
if ((y > 0 && x > Decimal::maxInt128 - y)
|
||||
|| (y < 0 && x < Decimal::minInt128 - y))
|
||||
{
|
||||
throw logging::OperationOverflowExcept(
|
||||
"Decimal::addition<int128_t> produces an overflow.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@brief The strucuture runs an empty overflow check for int128
|
||||
operation.
|
||||
*/
|
||||
struct NoOverflowCheck {
|
||||
void operator()(const int128_t& x, const int128_t& y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
} //end of namespace
|
||||
#endif
|
@ -48,7 +48,6 @@ add_library(execplan SHARED ${execplan_LIB_SRCS})
|
||||
|
||||
add_dependencies(execplan loggingcpp)
|
||||
|
||||
target_link_libraries(execplan ${NETSNMP_LIBRARIES} ${MARIADB_STRING_LIBS})
|
||||
target_link_libraries(execplan ${NETSNMP_LIBRARIES} ${MARIADB_STRING_LIBS} ${ENGINE_DT_LIB})
|
||||
|
||||
install(TARGETS execplan DESTINATION ${ENGINE_LIBDIR} COMPONENT columnstore-engine)
|
||||
|
||||
|
@ -290,31 +290,19 @@ inline void ArithmeticOperator::execute(IDB_Decimal& result, IDB_Decimal op1, ID
|
||||
case OP_ADD:
|
||||
if (resultCscType.colWidth == 16)
|
||||
{
|
||||
result.s128Value = op1.s128Value + op2.s128Value;
|
||||
break;
|
||||
datatypes::Decimal::addition<decltype(result.s128Value),false>(
|
||||
op1, op2, result);
|
||||
}
|
||||
|
||||
if (result.scale == op1.scale && result.scale == op2.scale)
|
||||
else if (resultCscType.colWidth == 8)
|
||||
{
|
||||
result.value = op1.value + op2.value;
|
||||
break;
|
||||
datatypes::Decimal::addition<decltype(result.value),false>(
|
||||
op1, op2, result);
|
||||
}
|
||||
|
||||
if (result.scale >= op1.scale)
|
||||
op1.value *= IDB_pow[result.scale - op1.scale];
|
||||
else
|
||||
op1.value = (int64_t)(op1.value > 0 ?
|
||||
(double)op1.value / IDB_pow[op1.scale - result.scale] + 0.5 :
|
||||
(double)op1.value / IDB_pow[op1.scale - result.scale] - 0.5);
|
||||
|
||||
if (result.scale >= op2.scale)
|
||||
op2.value *= IDB_pow[result.scale - op2.scale];
|
||||
else
|
||||
op2.value = (int64_t)(op2.value > 0 ?
|
||||
(double)op2.value / IDB_pow[op2.scale - result.scale] + 0.5 :
|
||||
(double)op2.value / IDB_pow[op2.scale - result.scale] - 0.5);
|
||||
|
||||
result.value = op1.value + op2.value;
|
||||
{
|
||||
throw logging::InvalidArgumentExcept(
|
||||
"Unexpected result width");
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_SUB:
|
||||
@ -352,21 +340,33 @@ inline void ArithmeticOperator::execute(IDB_Decimal& result, IDB_Decimal op1, ID
|
||||
break;
|
||||
|
||||
case OP_DIV:
|
||||
if (resultCscType.colWidth == 16)
|
||||
{
|
||||
if (op2.s128Value == 0)
|
||||
{
|
||||
isNull = true;
|
||||
break;
|
||||
}
|
||||
|
||||
datatypes::Decimal::division<decltype(result.s128Value),false>(
|
||||
op1, op2, result);
|
||||
}
|
||||
else if (resultCscType.colWidth == 8)
|
||||
{
|
||||
if (op2.value == 0)
|
||||
{
|
||||
isNull = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result.scale >= op1.scale - op2.scale)
|
||||
result.value = (int64_t)(( (op1.value > 0 && op2.value > 0) || (op1.value < 0 && op2.value < 0) ?
|
||||
(long double)op1.value / op2.value * IDB_pow[result.scale - (op1.scale - op2.scale)] + 0.5 :
|
||||
(long double)op1.value / op2.value * IDB_pow[result.scale - (op1.scale - op2.scale)] - 0.5));
|
||||
datatypes::Decimal::division<decltype(result.value),false>(
|
||||
op1, op2, result);
|
||||
}
|
||||
else
|
||||
result.value = (int64_t)(( (op1.value > 0 && op2.value > 0) || (op1.value < 0 && op2.value < 0) ?
|
||||
(long double)op1.value / op2.value / IDB_pow[op1.scale - op2.scale - result.scale] + 0.5 :
|
||||
(long double)op1.value / op2.value / IDB_pow[op1.scale - op2.scale - result.scale] - 0.5));
|
||||
|
||||
{
|
||||
throw logging::InvalidArgumentExcept(
|
||||
"Unexpected result width");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -36,9 +36,7 @@
|
||||
#include "exceptclasses.h"
|
||||
#include "dataconvert.h"
|
||||
#include "columnwidth.h"
|
||||
#include "csdecimal.h"
|
||||
|
||||
using int128_t = __int128;
|
||||
#include "mcs_decimal.h"
|
||||
|
||||
namespace messageqcpp
|
||||
{
|
||||
|
@ -38,6 +38,7 @@ using namespace BRM;
|
||||
|
||||
#include "jlf_common.h"
|
||||
using namespace joblist;
|
||||
#include "mcs_decimal.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -332,7 +333,7 @@ string extractTableAlias(const SSC& sc)
|
||||
//------------------------------------------------------------------------------
|
||||
CalpontSystemCatalog::OID isDictCol(const CalpontSystemCatalog::ColType& colType)
|
||||
{
|
||||
if (utils::isWideDecimalType(colType)) return 0;
|
||||
if (datatypes::Decimal::isWideDecimalType(colType)) return 0;
|
||||
|
||||
if (colType.colWidth > 8) return colType.ddn.dictOID;
|
||||
|
||||
|
@ -88,7 +88,7 @@ using namespace logging;
|
||||
#include "jlf_common.h"
|
||||
#include "jlf_subquery.h"
|
||||
#include "jlf_tuplejoblist.h"
|
||||
#include "columnwidth.h"
|
||||
#include "mcs_decimal.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -1897,7 +1897,7 @@ const JobStepVector doSimpleFilter(SimpleFilter* sf, JobInfo& jobInfo)
|
||||
// WIP MCOL-641 width check must be a f() not a literal
|
||||
// make a template from convertValueNum to avoid extra if
|
||||
// this condition doesn't support UDECIMAL
|
||||
if (utils::isWideDecimalType(ct))
|
||||
if (datatypes::Decimal::isWideDecimalType(ct))
|
||||
convertValueNum(constval, ct, isNull, rf, jobInfo.timeZone, value128);
|
||||
else
|
||||
convertValueNum(constval, ct, isNull, rf, jobInfo.timeZone, value);
|
||||
@ -1934,7 +1934,7 @@ const JobStepVector doSimpleFilter(SimpleFilter* sf, JobInfo& jobInfo)
|
||||
|
||||
if (sc->isColumnStore())
|
||||
{
|
||||
if (utils::isWideDecimalType(ct))
|
||||
if (datatypes::Decimal::isWideDecimalType(ct))
|
||||
pcs->addFilter(cop, value128, rf);
|
||||
else
|
||||
pcs->addFilter(cop, value, rf);
|
||||
@ -3012,7 +3012,7 @@ const JobStepVector doConstantFilter(const ConstantFilter* cf, JobInfo& jobInfo)
|
||||
uint8_t rf = 0;
|
||||
bool isNull = ConstantColumn::NULLDATA == cc->type();
|
||||
|
||||
if (utils::isWideDecimalType(ct))
|
||||
if (datatypes::Decimal::isWideDecimalType(ct))
|
||||
convertValueNum(constval, ct, isNull, rf, jobInfo.timeZone, value128);
|
||||
else
|
||||
convertValueNum(constval, ct, isNull, rf, jobInfo.timeZone, value);
|
||||
@ -3032,7 +3032,7 @@ const JobStepVector doConstantFilter(const ConstantFilter* cf, JobInfo& jobInfo)
|
||||
if (ConstantColumn::NULLDATA == cc->type() && (opeq == *sop || opne == *sop))
|
||||
cop = COMPARE_NIL;
|
||||
|
||||
if (utils::isWideDecimalType(ct))
|
||||
if (datatypes::Decimal::isWideDecimalType(ct))
|
||||
pcs->addFilter(cop, value128, rf);
|
||||
else
|
||||
pcs->addFilter(cop, value, rf);
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "brm.h"
|
||||
#include "brmtypes.h"
|
||||
#include "dataconvert.h"
|
||||
#include "columnwidth.h"
|
||||
#include "mcs_decimal.h"
|
||||
|
||||
#define IS_VERBOSE (fDebug >= 4)
|
||||
#define IS_DETAIL (fDebug >= 3)
|
||||
@ -809,7 +809,7 @@ bool LBIDList::CasualPartitionPredicate(const BRM::EMCasualPartition_t& cpRange,
|
||||
|
||||
// Should we also check for empty here?
|
||||
// TODO MCOL-641
|
||||
if (utils::isWideDecimalType(ct))
|
||||
if (datatypes::Decimal::isWideDecimalType(ct))
|
||||
{
|
||||
if (isNull(bigValue, ct))
|
||||
continue;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "dictstep.h"
|
||||
#include "filtercommand.h"
|
||||
#include "dataconvert.h"
|
||||
#include "mcs_decimal.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace messageqcpp;
|
||||
@ -249,7 +250,7 @@ void FilterCommand::setColTypes(const execplan::CalpontSystemCatalog::ColType& l
|
||||
leftColType = left;
|
||||
rightColType = right;
|
||||
|
||||
if (utils::isWideDecimalType(left) || utils::isWideDecimalType(right))
|
||||
if (datatypes::Decimal::isWideDecimalType(left) || datatypes::Decimal::isWideDecimalType(right))
|
||||
hasWideDecimalType = true;
|
||||
}
|
||||
|
||||
@ -281,7 +282,7 @@ void FilterCommand::doFilter()
|
||||
bpp->relRids[bpp->ridCount] = bpp->fFiltCmdRids[0][i];
|
||||
// WIP MCOL-641 How is bpp->(binary)values used given that
|
||||
// we are setting the relRids?
|
||||
if (utils::isWideDecimalType(leftColType))
|
||||
if (datatypes::Decimal::isWideDecimalType(leftColType))
|
||||
bpp->binaryValues[bpp->ridCount] = bpp->fFiltCmdBinaryValues[0][i];
|
||||
else
|
||||
bpp->values[bpp->ridCount] = bpp->fFiltCmdValues[0][i];
|
||||
@ -343,7 +344,7 @@ bool FilterCommand::binaryCompare(uint64_t i, uint64_t j)
|
||||
// not int128_t
|
||||
int128_t leftVal, rightVal;
|
||||
|
||||
if (utils::isWideDecimalType(leftColType))
|
||||
if (datatypes::Decimal::isWideDecimalType(leftColType))
|
||||
{
|
||||
if (execplan::isNull(bpp->fFiltCmdBinaryValues[0][i], leftColType))
|
||||
return false;
|
||||
@ -356,7 +357,7 @@ bool FilterCommand::binaryCompare(uint64_t i, uint64_t j)
|
||||
leftVal = bpp->fFiltCmdValues[0][i];
|
||||
}
|
||||
|
||||
if (utils::isWideDecimalType(rightColType))
|
||||
if (datatypes::Decimal::isWideDecimalType(rightColType))
|
||||
{
|
||||
if (execplan::isNull(bpp->fFiltCmdBinaryValues[1][j], rightColType))
|
||||
return false;
|
||||
|
@ -12,6 +12,12 @@ if (WITH_ARITHMETICOPERATOR_UT)
|
||||
install(TARGETS rowgroup_tests DESTINATION ${ENGINE_BINDIR} COMPONENT columnstore-platform)
|
||||
endif()
|
||||
|
||||
if (WITH_CSDECIMAL_UT)
|
||||
add_executable(mcs_decimal_tests mcs_decimal-tests.cpp)
|
||||
target_link_libraries(mcs_decimal_tests ${ENGINE_LDFLAGS} ${GTEST_LIBRARIES} ${ENGINE_EXEC_LIBS} ${MARIADB_CLIENT_LIBS})
|
||||
install(TARGETS rowgroup_tests DESTINATION ${ENGINE_BINDIR} COMPONENT columnstore-platform)
|
||||
endif()
|
||||
|
||||
if (WITH_DATACONVERT_UT)
|
||||
add_executable(dataconvert_tests dataconvert-tests.cpp)
|
||||
target_link_libraries(dataconvert_tests ${ENGINE_LDFLAGS} ${GTEST_LIBRARIES} ${ENGINE_EXEC_LIBS} ${MARIADB_CLIENT_LIBS})
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* Copyright (C) 2020 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. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(DataConvertTest, Strtoll128)
|
||||
{
|
||||
EXPECT_TRUE(true);
|
||||
}
|
731
tests/mcs_decimal-tests.cpp
Normal file
731
tests/mcs_decimal-tests.cpp
Normal file
@ -0,0 +1,731 @@
|
||||
/* Copyright (C) 2020 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. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "treenode.h"
|
||||
#include "mcs_decimal.h"
|
||||
#include "widedecimalutils.h"
|
||||
|
||||
TEST(Decimal, compareCheck)
|
||||
{
|
||||
// L values = R value, L scale < R scale
|
||||
execplan::IDB_Decimal l, r;
|
||||
l.scale = 20;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 21;
|
||||
l.precision = 38;
|
||||
r.s128Value = 420;
|
||||
EXPECT_EQ(0, datatypes::Decimal::compare(l, r));
|
||||
// L values = R value, L scale > R scale
|
||||
l.scale = 21;
|
||||
l.precision = 38;
|
||||
l.s128Value = 420;
|
||||
|
||||
r.scale = 20;
|
||||
l.precision = 38;
|
||||
r.s128Value = 42;
|
||||
EXPECT_EQ(0, datatypes::Decimal::compare(l, r));
|
||||
// L values > R value, L scale < R scale
|
||||
l.scale = 20;
|
||||
l.precision = 38;
|
||||
l.s128Value = 999999;
|
||||
|
||||
r.scale = 21;
|
||||
l.precision = 38;
|
||||
r.s128Value = 420;
|
||||
EXPECT_EQ(1, datatypes::Decimal::compare(l, r));
|
||||
// L values > R value, L scale > R scale
|
||||
l.scale = 21;
|
||||
l.precision = 38;
|
||||
l.s128Value = 99999999;
|
||||
|
||||
r.scale = 20;
|
||||
l.precision = 38;
|
||||
r.s128Value = 420;
|
||||
EXPECT_EQ(1, datatypes::Decimal::compare(l, r));
|
||||
// L values < R value, L scale < R scale
|
||||
l.scale = 20;
|
||||
l.precision = 38;
|
||||
l.s128Value = 99;
|
||||
|
||||
r.scale = 21;
|
||||
l.precision = 38;
|
||||
r.s128Value = 42000;
|
||||
EXPECT_EQ(-1, datatypes::Decimal::compare(l, r));
|
||||
// L values < R value, L scale > R scale
|
||||
l.scale = 21;
|
||||
l.precision = 38;
|
||||
l.s128Value = 99;
|
||||
|
||||
r.scale = 20;
|
||||
l.precision = 38;
|
||||
r.s128Value = 420;
|
||||
EXPECT_EQ(-1, datatypes::Decimal::compare(l, r));
|
||||
}
|
||||
|
||||
TEST(Decimal, additionNoOverflowCheck)
|
||||
{
|
||||
// Addition w/o overflow check
|
||||
execplan::IDB_Decimal l, r, result;
|
||||
// same precision, same scale, both positive values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = 420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
EXPECT_EQ(462, result.s128Value);
|
||||
// same precision, same scale, both negative values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = -42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
EXPECT_EQ(-462, result.s128Value);
|
||||
// same precision, same scale, +- values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
EXPECT_EQ(-378, result.s128Value);
|
||||
// same precision, same scale, both 0
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 0;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = 0;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
EXPECT_EQ(0, result.s128Value);
|
||||
// diff scale
|
||||
// same precision, L scale > R scale, both positive values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 15;
|
||||
r.precision = 38;
|
||||
r.s128Value = 420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
int128_t s128ScaleMultiplier1 =
|
||||
static_cast<int128_t>(10000000000000)*10000000000;
|
||||
int128_t s128Result = r.s128Value*s128ScaleMultiplier1+l.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale > R scale, both negative values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = -42;
|
||||
|
||||
r.scale = 15;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = r.s128Value*s128ScaleMultiplier1+l.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale > R scale, +- values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 15;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = r.s128Value*s128ScaleMultiplier1+l.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale > R scale, both 0
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 0;
|
||||
|
||||
r.scale = 15;
|
||||
r.precision = 38;
|
||||
r.s128Value = 0;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
EXPECT_EQ(0, result.s128Value);
|
||||
// same precision, L scale < R scale, both positive values
|
||||
l.scale = 15;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = 420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = l.s128Value*s128ScaleMultiplier1+r.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale < R scale, both negative values
|
||||
l.scale = 15;
|
||||
l.precision = 38;
|
||||
l.s128Value = -42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = l.s128Value*s128ScaleMultiplier1+r.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale < R scale, +- values
|
||||
l.scale = 15;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = l.s128Value*s128ScaleMultiplier1+r.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale < R scale, both 0
|
||||
l.scale = 15;
|
||||
l.precision = 38;
|
||||
l.s128Value = 0;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = 0;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::addition<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = l.s128Value*s128ScaleMultiplier1+r.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
}
|
||||
|
||||
TEST(Decimal, divisionNoOverflowCheck)
|
||||
{
|
||||
// DIVISION
|
||||
// same precision, same scale, both positive values
|
||||
std::string decimalStr;
|
||||
execplan::IDB_Decimal l, r, result;
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 43;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = 420;
|
||||
|
||||
result.scale = r.scale;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(r, l, result);
|
||||
|
||||
EXPECT_EQ(r.scale, result.scale);
|
||||
EXPECT_EQ(result.precision, result.precision);
|
||||
EXPECT_EQ(r.s128Value/l.s128Value, result.s128Value);
|
||||
// same precision, same scale, both negative values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = -42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = r.scale;
|
||||
result.precision = r.precision;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(r, l, result);
|
||||
EXPECT_EQ(r.scale, result.scale);
|
||||
EXPECT_EQ(r.precision, result.precision);
|
||||
EXPECT_EQ(r.s128Value/l.s128Value, result.s128Value);
|
||||
// same precision, same scale, +- values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
EXPECT_EQ(l.s128Value/r.s128Value, result.s128Value);
|
||||
// same precision, same scale, l = 0
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 0;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = 42424242;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
EXPECT_EQ(0, result.s128Value);
|
||||
// diff scale
|
||||
// same precision, L scale > R scale, both positive values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 15;
|
||||
r.precision = 38;
|
||||
r.s128Value = 420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(r, l, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
int128_t s128ScaleMultiplier1 =
|
||||
static_cast<int128_t>(10000000000000)*10000000000;
|
||||
int128_t s128Result = r.s128Value*s128ScaleMultiplier1/l.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale > R scale, both negative values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = -42;
|
||||
|
||||
r.scale = 15;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(r, l, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = r.s128Value*s128ScaleMultiplier1/l.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale > R scale, +- values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 15;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(r, l, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = r.s128Value*s128ScaleMultiplier1/l.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale > R scale, L = 0
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 0;
|
||||
|
||||
r.scale = 15;
|
||||
r.precision = 38;
|
||||
r.s128Value = 424242;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
EXPECT_EQ(0, result.s128Value);
|
||||
// same precision, L scale > R scale, both MAX positive values
|
||||
// WIP Investigate the next two
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 0; utils::int128Max(l.s128Value);
|
||||
|
||||
r.scale = 15;
|
||||
r.precision = 38;
|
||||
r.s128Value = 0; utils::int128Max(r.s128Value);
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
// Use as an examplar
|
||||
utils::int128Max(r.s128Value);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = r.s128Value*s128ScaleMultiplier1/l.s128Value;
|
||||
// WIP
|
||||
//EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale > R scale, both MIN negative values
|
||||
l.scale = 38;
|
||||
l.precision = 38;
|
||||
l.s128Value = 0; utils::int128Min(l.s128Value);
|
||||
|
||||
r.scale = 15;
|
||||
r.precision = 38;
|
||||
r.s128Value = 0; utils::int128Min(l.s128Value);
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
//datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
// Use as an examplar
|
||||
utils::int128Min(r.s128Value);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = r.s128Value*s128ScaleMultiplier1/l.s128Value;
|
||||
//EXPECT_EQ(s128Result, result.s128Value);
|
||||
// WIP
|
||||
//EXPECT_EQ(r.s128Value, result.s128Value);
|
||||
|
||||
// same precision, L scale < R scale, both positive values
|
||||
l.scale = 15;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = 420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = l.s128Value*s128ScaleMultiplier1/r.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale < R scale, both negative values
|
||||
l.scale = 15;
|
||||
l.precision = 38;
|
||||
l.s128Value = -42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = l.s128Value*s128ScaleMultiplier1/r.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale < R scale, +- values
|
||||
l.scale = 15;
|
||||
l.precision = 38;
|
||||
l.s128Value = 42;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = -420;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = l.s128Value*s128ScaleMultiplier1/r.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale < R scale, L = 0
|
||||
l.scale = 15;
|
||||
l.precision = 38;
|
||||
l.s128Value = 0;
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = 42;
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = l.s128Value*s128ScaleMultiplier1/r.s128Value;
|
||||
EXPECT_EQ(s128Result, result.s128Value);
|
||||
// same precision, L scale < R scale, both MAX positive values
|
||||
// WIP Investigate the next two
|
||||
l.scale = 15;
|
||||
l.precision = 38;
|
||||
l.s128Value = 0; utils::int128Max(l.s128Value);
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = 0; utils::int128Max(r.s128Value);
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
// Use as an examplar
|
||||
utils::int128Max(r.s128Value);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = l.s128Value*s128ScaleMultiplier1/r.s128Value;
|
||||
// WIP
|
||||
//EXPECT_EQ(s128Result, result.s128Value);
|
||||
//EXPECT_EQ(r.s128Value, result.s128Value);
|
||||
// same precision, L scale < R scale, both MIN negative values
|
||||
l.scale = 15;
|
||||
l.precision = 38;
|
||||
l.s128Value = 0; utils::int128Min(l.s128Value);
|
||||
|
||||
r.scale = 38;
|
||||
r.precision = 38;
|
||||
r.s128Value = 0; utils::int128Min(l.s128Value);
|
||||
|
||||
result.scale = 38;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
//datatypes::Decimal::division<int128_t, false>(l, r, result);
|
||||
// Use as an examplar
|
||||
utils::int128Min(r.s128Value);
|
||||
EXPECT_EQ(38, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
s128Result = l.s128Value*s128ScaleMultiplier1/r.s128Value;
|
||||
// WIP
|
||||
// EXPECT_EQ(s128Result, result.s128Value);
|
||||
//EXPECT_EQ(r.s128Value, result.s128Value);
|
||||
}
|
||||
|
||||
void doDiv(execplan::IDB_Decimal& l,
|
||||
execplan::IDB_Decimal& r,
|
||||
execplan::IDB_Decimal& result)
|
||||
{
|
||||
datatypes::Decimal::division<int128_t, true>(l, r, result);
|
||||
}
|
||||
|
||||
TEST(Decimal, divisionWithOverflowCheck)
|
||||
{
|
||||
|
||||
// Divide max int128 by -1
|
||||
execplan::IDB_Decimal l, r, result;
|
||||
l.scale = 0;
|
||||
l.precision = 38;
|
||||
l.s128Value = datatypes::Decimal::maxInt128;
|
||||
|
||||
r.scale = 0;
|
||||
r.precision = 38;
|
||||
r.s128Value = -1;
|
||||
|
||||
result.scale = 0;
|
||||
result.precision = 38;
|
||||
result.s128Value = 42;
|
||||
EXPECT_THROW(doDiv(l, r, result), logging::OperationOverflowExcept);
|
||||
// Divide two ints one of which overflows after the scaling.
|
||||
l.scale = 0;
|
||||
l.precision = 38;
|
||||
l.s128Value = datatypes::Decimal::maxInt128;
|
||||
|
||||
r.scale = 1;
|
||||
r.precision = 38;
|
||||
r.s128Value = 42;
|
||||
|
||||
result.scale = 1;
|
||||
result.precision = 38;
|
||||
result.s128Value = 42;
|
||||
EXPECT_THROW(doDiv(l, r, result), logging::OperationOverflowExcept);
|
||||
// Normal execution w/o overflow
|
||||
l.scale = 0;
|
||||
l.precision = 38;
|
||||
l.s128Value = datatypes::Decimal::maxInt128-1;
|
||||
|
||||
r.scale = 0;
|
||||
r.precision = 38;
|
||||
r.s128Value = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
result.scale = 0;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
EXPECT_NO_THROW(doDiv(l, r, result));
|
||||
|
||||
l.s128Value /= r.s128Value;
|
||||
|
||||
EXPECT_EQ(0, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
EXPECT_EQ(l.s128Value, result.s128Value);
|
||||
}
|
||||
|
||||
void doAdd(execplan::IDB_Decimal& l,
|
||||
execplan::IDB_Decimal& r,
|
||||
execplan::IDB_Decimal& result)
|
||||
{
|
||||
datatypes::Decimal::addition<int128_t, true>(l, r, result);
|
||||
}
|
||||
|
||||
TEST(Decimal, additionWithOverflowCheck)
|
||||
{
|
||||
// Add two max ints
|
||||
execplan::IDB_Decimal l, r, result;
|
||||
l.scale = 0;
|
||||
l.precision = 38;
|
||||
l.s128Value = datatypes::Decimal::maxInt128-1;
|
||||
|
||||
r.scale = 0;
|
||||
r.precision = 38;
|
||||
r.s128Value = datatypes::Decimal::maxInt128-1;
|
||||
|
||||
result.scale = 0;
|
||||
result.precision = 38;
|
||||
result.s128Value = 42;
|
||||
EXPECT_THROW(doAdd(l, r, result), logging::OperationOverflowExcept);
|
||||
// Add two ints one of which overflows after the scaling.
|
||||
l.scale = 0;
|
||||
l.precision = 38;
|
||||
l.s128Value = datatypes::Decimal::maxInt128-1;
|
||||
|
||||
r.scale = 1;
|
||||
r.precision = 38;
|
||||
r.s128Value = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
result.scale = 1;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
EXPECT_THROW(doAdd(l, r, result), logging::OperationOverflowExcept);
|
||||
// Normal execution w/o overflow
|
||||
l.scale = 0;
|
||||
l.precision = 38;
|
||||
l.s128Value = datatypes::Decimal::maxInt128-1;
|
||||
|
||||
r.scale = 0;
|
||||
r.precision = 38;
|
||||
r.s128Value = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
result.scale = 0;
|
||||
result.precision = 38;
|
||||
result.s128Value = 0;
|
||||
|
||||
EXPECT_NO_THROW(doDiv(l, r, result));
|
||||
|
||||
l.s128Value /= r.s128Value;
|
||||
|
||||
EXPECT_EQ(0, result.scale);
|
||||
EXPECT_EQ(38, result.precision);
|
||||
EXPECT_EQ(l.s128Value, result.s128Value);
|
||||
}
|
@ -18,7 +18,6 @@
|
||||
#ifndef UTILS_COLWIDTH_H
|
||||
#define UTILS_COLWIDTH_H
|
||||
|
||||
#include "calpontsystemcatalog.h"
|
||||
#include "branchpred.h"
|
||||
|
||||
namespace utils
|
||||
@ -36,13 +35,6 @@ namespace utils
|
||||
return width <= MAXLEGACYWIDTH;
|
||||
}
|
||||
|
||||
inline bool isWideDecimalType(const execplan::CalpontSystemCatalog::ColType& ct)
|
||||
{
|
||||
return ((ct.colDataType == execplan::CalpontSystemCatalog::DECIMAL ||
|
||||
ct.colDataType == execplan::CalpontSystemCatalog::UDECIMAL) &&
|
||||
ct.colWidth == MAXCOLUMNWIDTH);
|
||||
}
|
||||
|
||||
/** @brief Map a DECIMAL precision to data width in bytes */
|
||||
inline uint8_t widthByPrecision(unsigned p)
|
||||
{
|
||||
|
@ -80,9 +80,7 @@ namespace utils
|
||||
|
||||
inline void int128Min(int128_t& val)
|
||||
{
|
||||
uint64_t* ptr = reinterpret_cast<uint64_t*>(&val);
|
||||
ptr[0] = 0;
|
||||
ptr[1] = 0x8000000000000000;
|
||||
val = int128_t(0x8000000000000000LL) << 64;
|
||||
}
|
||||
|
||||
inline void uint128Max(uint128_t& val)
|
||||
|
@ -102,30 +102,6 @@ const string columnstore_big_precision[20] =
|
||||
"99999999999999999999999999999999999999"
|
||||
};
|
||||
|
||||
const uint64_t columnstore_pow_10[20] =
|
||||
{
|
||||
1ULL,
|
||||
10ULL,
|
||||
100ULL,
|
||||
1000ULL,
|
||||
10000ULL,
|
||||
100000ULL,
|
||||
1000000ULL,
|
||||
10000000ULL,
|
||||
100000000ULL,
|
||||
1000000000ULL,
|
||||
10000000000ULL,
|
||||
100000000000ULL,
|
||||
1000000000000ULL,
|
||||
10000000000000ULL,
|
||||
100000000000000ULL,
|
||||
1000000000000000ULL,
|
||||
10000000000000000ULL,
|
||||
100000000000000000ULL,
|
||||
1000000000000000000ULL,
|
||||
10000000000000000000ULL
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool from_string(T& t, const std::string& s, std::ios_base & (*f)(std::ios_base&))
|
||||
{
|
||||
@ -1257,33 +1233,30 @@ size_t DataConvert::writeIntPart(int128_t* dec,
|
||||
{
|
||||
int128_t intPart = *dec;
|
||||
int128_t high = 0, mid = 0, low = 0;
|
||||
uint64_t div = 10000000000000000000ULL;
|
||||
uint64_t maxUint64divisor = 10000000000000000000ULL;
|
||||
|
||||
if (scale)
|
||||
{
|
||||
const uint8_t maxPowOf10 =
|
||||
(sizeof(columnstore_pow_10) / sizeof(columnstore_pow_10[0])) - 1;
|
||||
|
||||
// Assuming scale = [0, 56]
|
||||
switch (scale / maxPowOf10)
|
||||
switch (scale / datatypes::maxPowOf10)
|
||||
{
|
||||
case 2: // scale = [38, 56]
|
||||
intPart /= columnstore_pow_10[maxPowOf10];
|
||||
intPart /= columnstore_pow_10[maxPowOf10];
|
||||
intPart /= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
intPart /= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
low = intPart;
|
||||
break;
|
||||
case 1: // scale = [19, 37]
|
||||
intPart /= columnstore_pow_10[maxPowOf10];
|
||||
intPart /= columnstore_pow_10[scale % maxPowOf10];
|
||||
low = intPart % div;
|
||||
mid = intPart / div;
|
||||
intPart /= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
intPart /= datatypes::mcs_pow_10[scale % datatypes::maxPowOf10];
|
||||
low = intPart % maxUint64divisor;
|
||||
mid = intPart / maxUint64divisor;
|
||||
break;
|
||||
case 0: // scale = [0, 18]
|
||||
intPart /= columnstore_pow_10[scale % maxPowOf10];
|
||||
low = intPart % div;
|
||||
intPart /= div;
|
||||
mid = intPart % div;
|
||||
high = intPart / div;
|
||||
intPart /= datatypes::mcs_pow_10[scale % datatypes::maxPowOf10];
|
||||
low = intPart % maxUint64divisor;
|
||||
intPart /= maxUint64divisor;
|
||||
mid = intPart % maxUint64divisor;
|
||||
high = intPart / maxUint64divisor;
|
||||
break;
|
||||
default:
|
||||
throw QueryDataExcept("writeIntPart() bad scale", formatErr);
|
||||
@ -1291,10 +1264,10 @@ size_t DataConvert::writeIntPart(int128_t* dec,
|
||||
}
|
||||
else
|
||||
{
|
||||
low = intPart % div;
|
||||
intPart /= div;
|
||||
mid = intPart % div;
|
||||
high = intPart / div;
|
||||
low = intPart % maxUint64divisor;
|
||||
intPart /= maxUint64divisor;
|
||||
mid = intPart % maxUint64divisor;
|
||||
high = intPart / maxUint64divisor;
|
||||
}
|
||||
|
||||
// pod[0] is low 8 bytes, pod[1] is high 8 bytes
|
||||
@ -1337,19 +1310,16 @@ size_t DataConvert::writeFractionalPart(int128_t* dec,
|
||||
{
|
||||
int128_t scaleDivisor = 1;
|
||||
|
||||
const uint8_t maxPowOf10 =
|
||||
(sizeof(columnstore_pow_10) / sizeof(columnstore_pow_10[0])) - 1;
|
||||
|
||||
switch (scale / maxPowOf10)
|
||||
switch (scale / datatypes::maxPowOf10)
|
||||
{
|
||||
case 2:
|
||||
scaleDivisor *= columnstore_pow_10[maxPowOf10];
|
||||
scaleDivisor *= columnstore_pow_10[maxPowOf10];
|
||||
scaleDivisor *= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
scaleDivisor *= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
break;
|
||||
case 1:
|
||||
scaleDivisor *= columnstore_pow_10[maxPowOf10];
|
||||
scaleDivisor *= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
case 0:
|
||||
scaleDivisor *= columnstore_pow_10[scale % maxPowOf10];
|
||||
scaleDivisor *= datatypes::mcs_pow_10[scale % datatypes::maxPowOf10];
|
||||
}
|
||||
|
||||
int128_t fractionalPart = *dec % scaleDivisor;
|
||||
|
@ -42,6 +42,8 @@ using namespace joblist;
|
||||
#include "../udfsdk/udfsdk.h"
|
||||
#endif
|
||||
|
||||
#include "mcs_decimal.h"
|
||||
|
||||
namespace funcexp
|
||||
{
|
||||
|
||||
@ -471,14 +473,23 @@ void FuncExp::evaluate(rowgroup::Row& row, std::vector<execplan::SRCP>& expressi
|
||||
case CalpontSystemCatalog::UDECIMAL:
|
||||
{
|
||||
IDB_Decimal val = expression[i]->getDecimalVal(row, isNull);
|
||||
|
||||
// WIP check for null and overflow here.
|
||||
if (expression[i]->resultType().colWidth == 16)
|
||||
if (expression[i]->resultType().colWidth
|
||||
== datatypes::MAXDECIMALWIDTH)
|
||||
{
|
||||
if (isNull)
|
||||
{
|
||||
row.setBinaryField_offset(
|
||||
const_cast<int128_t*>(&datatypes::Decimal128Null),
|
||||
expression[i]->resultType().colWidth,
|
||||
row.getOffset(expression[i]->outputIndex()));
|
||||
}
|
||||
else
|
||||
{
|
||||
row.setBinaryField_offset(&val.s128Value,
|
||||
expression[i]->resultType().colWidth,
|
||||
row.getOffset(expression[i]->outputIndex()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isNull)
|
||||
|
@ -187,6 +187,16 @@ public:
|
||||
std::runtime_error(msg) { }
|
||||
};
|
||||
|
||||
/** @brief Exception for F&E framework to throw on op overflow
|
||||
* Invalid Operation Exception
|
||||
*/
|
||||
class OperationOverflowExcept : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
/** Takes a character string describing the error. */
|
||||
OperationOverflowExcept(const std::string& msg) :
|
||||
std::runtime_error(msg) { }
|
||||
};
|
||||
/** @brief specific error exception class for getSysData in Calpontsystemcatalog.
|
||||
* @bug 2574
|
||||
*
|
||||
|
@ -1629,7 +1629,6 @@ void applyMapping(const int* mapping, const Row& in, Row* out)
|
||||
out->setVarBinaryField(in.getVarBinaryField(i), in.getVarBinaryLength(i), mapping[i]);
|
||||
else if (UNLIKELY(in.isLongString(i)))
|
||||
out->setStringField(in.getStringPointer(i), in.getStringLength(i), mapping[i]);
|
||||
//out->setStringField(in.getStringField(i), mapping[i]);
|
||||
else if (UNLIKELY(in.isShortString(i)))
|
||||
out->setUintField(in.getUintField(i), mapping[i]);
|
||||
else if (UNLIKELY(in.getColTypes()[i] == execplan::CalpontSystemCatalog::LONGDOUBLE))
|
||||
|
Reference in New Issue
Block a user