1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-08-08 14:22:09 +03:00

MCOL-641 Implement int128_t versions of arithmetic operations and add unit test cases.

This commit is contained in:
Gagan Goel
2020-04-03 13:30:10 -04:00
committed by Roman Nozdrin
parent b5534eb847
commit 554c6da8e8
8 changed files with 1254 additions and 502 deletions

View File

@@ -35,19 +35,19 @@ namespace execplan
* Constructors/Destructors
*/
ArithmeticOperator::ArithmeticOperator() : Operator(),
fDecimalOverflowCheck(true)
fDecimalOverflowCheck(false)
{
}
ArithmeticOperator::ArithmeticOperator(const string& operatorName): Operator(operatorName),
fDecimalOverflowCheck(true)
fDecimalOverflowCheck(false)
{
}
ArithmeticOperator::ArithmeticOperator(const ArithmeticOperator& rhs):
Operator(rhs),
fTimeZone(rhs.timeZone()),
fDecimalOverflowCheck(true)
fDecimalOverflowCheck(false)
{
}

View File

@@ -196,7 +196,7 @@ public:
return TreeNode::getBoolVal();
}
void adjustResultType(const CalpontSystemCatalog::ColType& m);
constexpr inline bool getOverflowCheck()
constexpr inline bool getOverflowCheck() const
{
return fDecimalOverflowCheck;
}
@@ -209,7 +209,6 @@ private:
template <typename result_t>
inline result_t execute(result_t op1, result_t op2, bool& isNull);
inline void execute(IDB_Decimal& result, IDB_Decimal op1, IDB_Decimal op2, bool& isNull);
inline void execute(IDB_Decimal& result, IDB_Decimal op1, IDB_Decimal op2, bool& isNull, cscType& resultCscType);
std::string fTimeZone;
bool fDecimalOverflowCheck;
};
@@ -250,7 +249,7 @@ inline void ArithmeticOperator::evaluate(rowgroup::Row& row, bool& isNull, Parse
// WIP MCOL-641
case execplan::CalpontSystemCatalog::DECIMAL:
case execplan::CalpontSystemCatalog::UDECIMAL:
execute(fResult.decimalVal, lop->getDecimalVal(row, isNull), rop->getDecimalVal(row, isNull), isNull, fOperationType);
execute(fResult.decimalVal, lop->getDecimalVal(row, isNull), rop->getDecimalVal(row, isNull), isNull);
break;
default:
{
@@ -292,20 +291,36 @@ inline result_t ArithmeticOperator::execute(result_t op1, result_t op2, bool& is
}
}
inline void ArithmeticOperator::execute(IDB_Decimal& result, IDB_Decimal op1, IDB_Decimal op2, bool& isNull, cscType& resultCscType)
inline void ArithmeticOperator::execute(IDB_Decimal& result, IDB_Decimal op1, IDB_Decimal op2, bool& isNull)
{
switch (fOp)
{
case OP_ADD:
if (resultCscType.colWidth == datatypes::MAXDECIMALWIDTH)
if (fOperationType.colWidth == datatypes::MAXDECIMALWIDTH)
{
datatypes::Decimal::addition<decltype(result.s128Value),true>(
op1, op2, result);
if (LIKELY(!fDecimalOverflowCheck))
{
datatypes::Decimal::addition<decltype(result.s128Value), false>(
op1, op2, result);
}
else
{
datatypes::Decimal::addition<decltype(result.s128Value), true>(
op1, op2, result);
}
}
else if (resultCscType.colWidth == utils::MAXLEGACYWIDTH)
else if (fOperationType.colWidth == utils::MAXLEGACYWIDTH)
{
datatypes::Decimal::addition<decltype(result.value),false>(
op1, op2, result);
if (LIKELY(!fDecimalOverflowCheck))
{
datatypes::Decimal::addition<decltype(result.value), false>(
op1, op2, result);
}
else
{
datatypes::Decimal::addition<decltype(result.value), true>(
op1, op2, result);
}
}
else
{
@@ -315,52 +330,95 @@ inline void ArithmeticOperator::execute(IDB_Decimal& result, IDB_Decimal op1, ID
break;
case OP_SUB:
if (result.scale == op1.scale && result.scale == op2.scale)
if (fOperationType.colWidth == datatypes::MAXDECIMALWIDTH)
{
result.value = op1.value - op2.value;
break;
if (LIKELY(!fDecimalOverflowCheck))
{
datatypes::Decimal::subtraction<decltype(result.s128Value), false>(
op1, op2, result);
}
else
{
datatypes::Decimal::subtraction<decltype(result.s128Value), true>(
op1, op2, result);
}
}
else if (fOperationType.colWidth == utils::MAXLEGACYWIDTH)
{
if (LIKELY(!fDecimalOverflowCheck))
{
datatypes::Decimal::subtraction<decltype(result.value), false>(
op1, op2, result);
}
else
{
datatypes::Decimal::subtraction<decltype(result.value), true>(
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_MUL:
if (result.scale >= op1.scale + op2.scale)
result.value = op1.value * op2.value * IDB_pow[result.scale - (op1.scale + op2.scale)];
if (fOperationType.colWidth == datatypes::MAXDECIMALWIDTH)
{
if (LIKELY(!fDecimalOverflowCheck))
{
datatypes::Decimal::multiplication<decltype(result.s128Value), false>(
op1, op2, result);
}
else
{
datatypes::Decimal::multiplication<decltype(result.s128Value), true>(
op1, op2, result);
}
}
else if (fOperationType.colWidth == utils::MAXLEGACYWIDTH)
{
if (LIKELY(!fDecimalOverflowCheck))
{
datatypes::Decimal::multiplication<decltype(result.value), false>(
op1, op2, result);
}
else
{
datatypes::Decimal::multiplication<decltype(result.value), true>(
op1, op2, result);
}
}
else
result.value = (int64_t)(( (op1.value > 0 && op2.value > 0) || (op1.value < 0 && op2.value < 0) ?
(double)op1.value * op2.value / IDB_pow[op1.scale + op2.scale - result.scale] + 0.5 :
(double)op1.value * op2.value / IDB_pow[op1.scale + op2.scale - result.scale] - 0.5));
{
throw logging::InvalidArgumentExcept(
"Unexpected result width");
}
break;
case OP_DIV:
if (resultCscType.colWidth == 16)
if (fOperationType.colWidth == datatypes::MAXDECIMALWIDTH)
{
if (op2.s128Value == 0)
if ((datatypes::Decimal::isWideDecimalType(op2.precision) && op2.s128Value == 0)
|| (!datatypes::Decimal::isWideDecimalType(op2.precision) && op2.value == 0))
{
isNull = true;
break;
}
datatypes::Decimal::division<decltype(result.s128Value),false>(
op1, op2, result);
if (LIKELY(!fDecimalOverflowCheck))
{
datatypes::Decimal::division<decltype(result.s128Value), false>(
op1, op2, result);
}
else
{
datatypes::Decimal::division<decltype(result.s128Value), true>(
op1, op2, result);
}
}
else if (resultCscType.colWidth == 8)
else if (fOperationType.colWidth == utils::MAXLEGACYWIDTH)
{
if (op2.value == 0)
{
@@ -368,8 +426,16 @@ inline void ArithmeticOperator::execute(IDB_Decimal& result, IDB_Decimal op1, ID
break;
}
datatypes::Decimal::division<decltype(result.value),false>(
op1, op2, result);
if (LIKELY(!fDecimalOverflowCheck))
{
datatypes::Decimal::division<decltype(result.value), false>(
op1, op2, result);
}
else
{
datatypes::Decimal::division<decltype(result.value), true>(
op1, op2, result);
}
}
else
{

View File

@@ -3105,17 +3105,13 @@ CalpontSystemCatalog::ColType colType_MysqlToIDB (const Item* item)
case DECIMAL_RESULT:
{
Item_decimal* idp = (Item_decimal*)item;
ct.colDataType = CalpontSystemCatalog::DECIMAL;
ct.colWidth = (idp->max_length >= datatypes::INT64MAXPRECISION)
? datatypes::MAXDECIMALWIDTH : utils::MAXLEGACYWIDTH;
ct.scale = idp->decimals;
// WIP MCOL-641
if (ct.scale == 0)
ct.precision = (idp->max_length > datatypes::INT128MAXPRECISION)
? datatypes::INT128MAXPRECISION : idp->max_length - 1;
else
ct.precision = (idp->max_length > datatypes::INT128MAXPRECISION )
? datatypes::INT128MAXPRECISION : idp->max_length - idp->decimals;
unsigned int precision = idp->decimal_precision();
unsigned int scale = idp->decimal_scale();
datatypes::Decimal::setDecimalScalePrecision(ct, precision, scale);
break;
}
@@ -3141,7 +3137,7 @@ ReturnedColumn* buildReturnedColumn(
{
ReturnedColumn* rc = NULL;
if ( gwi.thd)
if (gwi.thd)
{
//if ( ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE ) || ((gwi.thd->lex)->sql_command == SQLCOM_UPDATE_MULTI ))
{
@@ -3444,6 +3440,7 @@ ArithmeticColumn* buildArithmeticColumn(
Item** sfitempp = item->arguments();
ArithmeticOperator* aop = new ArithmeticOperator(item->func_name());
aop->timeZone(gwi.thd->variables.time_zone->get_name()->ptr());
aop->setOverflowCheck(get_decimal_overflow_check(gwi.thd));
ParseTree* pt = new ParseTree(aop);
//ReturnedColumn *lhs = 0, *rhs = 0;
ParseTree* lhs = 0, *rhs = 0;
@@ -3606,6 +3603,60 @@ ArithmeticColumn* buildArithmeticColumn(
// decimal arithmetic operation gives double result when the session variable is set.
CalpontSystemCatalog::ColType mysql_type = colType_MysqlToIDB(item);
if (mysql_type.colDataType == CalpontSystemCatalog::DECIMAL ||
mysql_type.colDataType == CalpontSystemCatalog::UDECIMAL)
{
int32_t leftColWidth = pt->left()->data()->resultType().colWidth;
int32_t rightColWidth = pt->right()->data()->resultType().colWidth;
// Revert back to legacy values of scale and precision
// if the 2 columns involved in the expression are not wide
if (leftColWidth <= utils::MAXLEGACYWIDTH &&
rightColWidth <= utils::MAXLEGACYWIDTH)
{
Item_decimal* idp = (Item_decimal*)item;
mysql_type.colWidth = 8;
unsigned int precision = idp->max_length;
unsigned int scale = idp->decimals;
datatypes::Decimal::setDecimalScalePrecisionLegacy(mysql_type, precision, scale);
}
else
{
if (leftColWidth == datatypes::MAXDECIMALWIDTH ||
rightColWidth == datatypes::MAXDECIMALWIDTH)
mysql_type.colWidth = datatypes::MAXDECIMALWIDTH;
if (mysql_type.colWidth == datatypes::MAXDECIMALWIDTH)
{
string funcName = item->func_name();
int32_t scale1 = pt->left()->data()->resultType().scale;
int32_t scale2 = pt->right()->data()->resultType().scale;
if (funcName == "/" &&
(mysql_type.scale - (scale1 - scale2)) > datatypes::INT128MAXPRECISION)
{
Item_decimal* idp = (Item_decimal*)item;
unsigned int precision = idp->decimal_precision();
unsigned int scale = idp->decimal_scale();
datatypes::Decimal::setDecimalScalePrecisionHeuristic(mysql_type, precision, scale);
if (mysql_type.scale < scale1)
mysql_type.scale = scale1;
if (mysql_type.precision < mysql_type.scale)
mysql_type.precision = mysql_type.scale;
}
}
}
}
if (get_double_for_decimal_math(current_thd) == true)
aop->adjustResultType(mysql_type);
else

View File

@@ -159,6 +159,15 @@ static MYSQL_THDVAR_BOOL(
0
);
static MYSQL_THDVAR_BOOL(
decimal_overflow_check,
PLUGIN_VAR_NOCMDARG,
"Enable/disable for ColumnStore to check for overflow in arithmetic operation.",
NULL,
NULL,
0
);
static MYSQL_THDVAR_BOOL(
ordered_only,
PLUGIN_VAR_NOCMDARG,
@@ -353,6 +362,7 @@ st_mysql_sys_var* mcs_system_variables[] =
MYSQL_SYSVAR(diskjoin_bucketsize),
MYSQL_SYSVAR(um_mem_limit),
MYSQL_SYSVAR(double_for_decimal_math),
MYSQL_SYSVAR(decimal_overflow_check),
MYSQL_SYSVAR(local_query),
MYSQL_SYSVAR(use_import_for_batchinsert),
MYSQL_SYSVAR(import_for_batchinsert_delimiter),
@@ -557,6 +567,15 @@ void set_double_for_decimal_math(THD* thd, bool value)
THDVAR(thd, double_for_decimal_math) = value;
}
bool get_decimal_overflow_check(THD* thd)
{
return ( thd == NULL ) ? false : THDVAR(thd, decimal_overflow_check);
}
void set_decimal_overflow_check(THD* thd, bool value)
{
THDVAR(thd, decimal_overflow_check) = value;
}
ulong get_local_query(THD* thd)
{
return ( thd == NULL ) ? 0 : THDVAR(thd, local_query);

View File

@@ -101,6 +101,9 @@ void set_varbin_always_hex(THD* thd, bool value);
bool get_double_for_decimal_math(THD* thd);
void set_double_for_decimal_math(THD* thd, bool value);
bool get_decimal_overflow_check(THD* thd);
void set_decimal_overflow_check(THD* thd, bool value);
ulong get_local_query(THD* thd);
void set_local_query(THD* thd, ulong value);