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

MCOL-641 Fixes for arithmetic operations.

1. Perform type promotion to wide decimal if the result
   of an arithmetic operation has a precision > 18.
2. Only set the decimal width of an arithmetic operation to wide
   if both the LHS and RHS of the operation are decimal types.
This commit is contained in:
Gagan Goel
2020-10-22 12:16:48 -04:00
committed by Roman Nozdrin
parent 844472d812
commit 1f4a781704
3 changed files with 72 additions and 65 deletions

View File

@@ -470,6 +470,21 @@ class Decimal
scale += (scaleAvailable >= MAXSCALEINC4AVG) ? MAXSCALEINC4AVG : scaleAvailable; scale += (scaleAvailable >= MAXSCALEINC4AVG) ? MAXSCALEINC4AVG : scaleAvailable;
precision += (precisionAvailable >= MAXSCALEINC4AVG) ? MAXSCALEINC4AVG : precisionAvailable; precision += (precisionAvailable >= MAXSCALEINC4AVG) ? MAXSCALEINC4AVG : precisionAvailable;
} }
/**
@brief Returns true if all arguments have a DECIMAL/UDECIMAL type
*/
static inline bool isDecimalOperands(const ColDataTypeAlias resultDataType,
const ColDataTypeAlias leftColDataType,
const ColDataTypeAlias rightColDataType)
{
return ((resultDataType == execplan::CalpontSystemCatalog::DECIMAL ||
resultDataType == execplan::CalpontSystemCatalog::UDECIMAL) &&
(leftColDataType == execplan::CalpontSystemCatalog::DECIMAL ||
leftColDataType == execplan::CalpontSystemCatalog::UDECIMAL) &&
(rightColDataType == execplan::CalpontSystemCatalog::DECIMAL ||
rightColDataType == execplan::CalpontSystemCatalog::UDECIMAL));
}
}; };
/** /**

View File

@@ -343,12 +343,8 @@ namespace joblist
void wideDecimalOrLongDouble(const uint64_t colProj, void wideDecimalOrLongDouble(const uint64_t colProj,
const CalpontSystemCatalog::ColDataType type, const CalpontSystemCatalog::ColDataType type,
const vector<uint32_t>& precisionProj, const vector<uint32_t>& precisionProj,
const vector<uint32_t>& oidsProj,
const uint32_t aggKey,
const vector<uint32_t>& scaleProj, const vector<uint32_t>& scaleProj,
const vector<uint32_t>& width, const vector<uint32_t>& width,
vector<uint32_t>& oidsAgg,
vector<uint32_t>& keysAgg,
vector<CalpontSystemCatalog::ColDataType>& typeAgg, vector<CalpontSystemCatalog::ColDataType>& typeAgg,
vector<uint32_t>& scaleAgg, vector<uint32_t>& scaleAgg,
vector<uint32_t>& precisionAgg, vector<uint32_t>& precisionAgg,
@@ -358,8 +354,6 @@ void wideDecimalOrLongDouble(const uint64_t colProj,
|| type == CalpontSystemCatalog::UDECIMAL) || type == CalpontSystemCatalog::UDECIMAL)
&& datatypes::Decimal::isWideDecimalType(precisionProj[colProj])) && datatypes::Decimal::isWideDecimalType(precisionProj[colProj]))
{ {
oidsAgg.push_back(oidsProj[colProj]);
keysAgg.push_back(aggKey);
typeAgg.push_back(type); typeAgg.push_back(type);
scaleAgg.push_back(scaleProj[colProj]); scaleAgg.push_back(scaleProj[colProj]);
precisionAgg.push_back(precisionProj[colProj]); precisionAgg.push_back(precisionProj[colProj]);
@@ -367,8 +361,6 @@ void wideDecimalOrLongDouble(const uint64_t colProj,
} }
else else
{ {
oidsAgg.push_back(oidsProj[colProj]);
keysAgg.push_back(aggKey);
typeAgg.push_back(CalpontSystemCatalog::LONGDOUBLE); typeAgg.push_back(CalpontSystemCatalog::LONGDOUBLE);
scaleAgg.push_back(0); scaleAgg.push_back(0);
precisionAgg.push_back(-1); precisionAgg.push_back(-1);
@@ -758,29 +750,38 @@ void TupleAggregateStep::configDeliveredRowGroup(const JobInfo& jobInfo)
if (jobInfo.havingStep) if (jobInfo.havingStep)
{ {
retColCount = jobInfo.returnedColVec.size(); retColCount = jobInfo.returnedColVec.size();
idbassert(jobInfo.returnedColVec.size() == jobInfo.nonConstCols.size()); idbassert(jobInfo.returnedColVec.size() == jobInfo.nonConstCols.size());
for (auto& rc : jobInfo.nonConstCols)
for (size_t i = 0; i < jobInfo.nonConstCols.size() &&
scaleIter != scale.end(); i++)
{ {
auto& colType = rc->resultType(); const auto& colType = jobInfo.nonConstCols[i]->resultType();
if (datatypes::Decimal::isWideDecimalType(colType)) if (datatypes::Decimal::isWideDecimalType(colType))
{ {
*scaleIter = colType.scale; *scaleIter = colType.scale;
*precisionIter = colType.precision; *precisionIter = colType.precision;
} }
scaleIter++; precisionIter++; scaleIter++; precisionIter++;
} }
} }
else else
{ {
retColCount = jobInfo.nonConstDelCols.size(); retColCount = jobInfo.nonConstDelCols.size();
for (auto& rc : jobInfo.nonConstDelCols)
for (size_t i = 0; i < jobInfo.nonConstDelCols.size() &&
scaleIter != scale.end(); i++)
{ {
auto& colType = rc->resultType(); const auto& colType = jobInfo.nonConstDelCols[i]->resultType();
if (datatypes::Decimal::isWideDecimalType(colType)) if (datatypes::Decimal::isWideDecimalType(colType))
{ {
*scaleIter = colType.scale; *scaleIter = colType.scale;
*precisionIter = colType.precision; *precisionIter = colType.precision;
} }
scaleIter++; precisionIter++; scaleIter++; precisionIter++;
} }
} }
@@ -1356,10 +1357,13 @@ void TupleAggregateStep::prep1PhaseAggregate(
cerr << "prep1PhaseAggregate: " << emsg << endl; cerr << "prep1PhaseAggregate: " << emsg << endl;
throw IDBExcept(emsg, ERR_AGGREGATE_TYPE_NOT_SUPPORT); throw IDBExcept(emsg, ERR_AGGREGATE_TYPE_NOT_SUPPORT);
} }
wideDecimalOrLongDouble(colProj, typeProj[colProj], wideDecimalOrLongDouble(colProj, typeProj[colProj],
precisionProj, oidsProj, key, scaleProj, width, precisionProj, scaleProj, width,
oidsAgg, keysAgg, typeAgg, scaleAgg, typeAgg, scaleAgg, precisionAgg, widthAgg);
precisionAgg, widthAgg);
oidsAgg.push_back(oidsProj[colProj]);
keysAgg.push_back(key);
csNumAgg.push_back(csNumProj[colProj]); csNumAgg.push_back(csNumProj[colProj]);
} }
break; break;
@@ -3181,10 +3185,13 @@ void TupleAggregateStep::prep2PhasesAggregate(
cerr << "prep2PhasesAggregate: " << emsg << endl; cerr << "prep2PhasesAggregate: " << emsg << endl;
throw IDBExcept(emsg, ERR_AGGREGATE_TYPE_NOT_SUPPORT); throw IDBExcept(emsg, ERR_AGGREGATE_TYPE_NOT_SUPPORT);
} }
wideDecimalOrLongDouble(colProj, typeProj[colProj], wideDecimalOrLongDouble(colProj, typeProj[colProj],
precisionProj, oidsProj, aggKey, scaleProj, width, precisionProj, scaleProj, width,
oidsAggPm, keysAggPm, typeAggPm, scaleAggPm, typeAggPm, scaleAggPm, precisionAggPm, widthAggPm);
precisionAggPm, widthAggPm);
oidsAggPm.push_back(oidsProj[colProj]);
keysAggPm.push_back(aggKey);
csNumAggPm.push_back(8); csNumAggPm.push_back(8);
colAggPm++; colAggPm++;
} }
@@ -3469,9 +3476,11 @@ void TupleAggregateStep::prep2PhasesAggregate(
if (aggOp == ROWAGG_SUM) if (aggOp == ROWAGG_SUM)
{ {
wideDecimalOrLongDouble(colPm, typeProj[colPm], wideDecimalOrLongDouble(colPm, typeProj[colPm],
precisionProj, oidsProj, retKey, scaleProj, widthAggPm, precisionProj, scaleProj, widthAggPm,
oidsAggUm, keysAggUm, typeAggUm, scaleAggUm, typeAggUm, scaleAggUm, precisionAggUm, widthAggUm);
precisionAggUm, widthAggUm);
oidsAggUm.push_back(oidsProj[colPm]);
keysAggUm.push_back(retKey);
csNumAggUm.push_back(8); csNumAggUm.push_back(8);
} }
else else

View File

@@ -3602,68 +3602,51 @@ ArithmeticColumn* buildArithmeticColumn(
// @bug5715. Use InfiniDB adjusted coltype for result type. // @bug5715. Use InfiniDB adjusted coltype for result type.
// decimal arithmetic operation gives double result when the session variable is set. // decimal arithmetic operation gives double result when the session variable is set.
CalpontSystemCatalog::ColType mysql_type = colType_MysqlToIDB(item); CalpontSystemCatalog::ColType mysqlType = colType_MysqlToIDB(item);
if (mysql_type.colDataType == CalpontSystemCatalog::DECIMAL || const CalpontSystemCatalog::ColType& leftColType = pt->left()->data()->resultType();
mysql_type.colDataType == CalpontSystemCatalog::UDECIMAL) const CalpontSystemCatalog::ColType& rightColType = pt->right()->data()->resultType();
{
int32_t leftColWidth = pt->left()->data()->resultType().colWidth; // Only tinker with the type if all columns involved are decimal
int32_t rightColWidth = pt->right()->data()->resultType().colWidth; if (datatypes::Decimal::isDecimalOperands(mysqlType.colDataType,
leftColType.colDataType, rightColType.colDataType))
// 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
{ {
int32_t leftColWidth = leftColType.colWidth;
int32_t rightColWidth = rightColType.colWidth;
if (leftColWidth == datatypes::MAXDECIMALWIDTH || if (leftColWidth == datatypes::MAXDECIMALWIDTH ||
rightColWidth == datatypes::MAXDECIMALWIDTH) rightColWidth == datatypes::MAXDECIMALWIDTH)
mysql_type.colWidth = datatypes::MAXDECIMALWIDTH;
if (mysql_type.colWidth == datatypes::MAXDECIMALWIDTH)
{ {
mysqlType.colWidth = datatypes::MAXDECIMALWIDTH;
string funcName = item->func_name(); string funcName = item->func_name();
int32_t scale1 = pt->left()->data()->resultType().scale; int32_t scale1 = leftColType.scale;
int32_t scale2 = pt->right()->data()->resultType().scale; int32_t scale2 = rightColType.scale;
if (funcName == "/" && if (funcName == "/" &&
(mysql_type.scale - (scale1 - scale2)) > (mysqlType.scale - (scale1 - scale2)) > datatypes::INT128MAXPRECISION)
datatypes::INT128MAXPRECISION)
{ {
Item_decimal* idp = (Item_decimal*)item; Item_decimal* idp = (Item_decimal*)item;
unsigned int precision = idp->decimal_precision(); unsigned int precision = idp->decimal_precision();
unsigned int scale = idp->decimal_scale(); unsigned int scale = idp->decimal_scale();
datatypes::Decimal::setDecimalScalePrecisionHeuristic(mysql_type, precision, scale); datatypes::Decimal::setDecimalScalePrecisionHeuristic(mysqlType, precision, scale);
if (mysql_type.scale < scale1) if (mysqlType.scale < scale1)
mysql_type.scale = scale1; mysqlType.scale = scale1;
if (mysql_type.precision < mysql_type.scale) if (mysqlType.precision < mysqlType.scale)
mysql_type.precision = mysql_type.scale; mysqlType.precision = mysqlType.scale;
}
} }
} }
} }
if (get_double_for_decimal_math(current_thd) == true) if (get_double_for_decimal_math(current_thd) == true)
aop->adjustResultType(mysql_type); aop->adjustResultType(mysqlType);
else else
aop->resultType(mysql_type); aop->resultType(mysqlType);
// adjust decimal result type according to internalDecimalScale // adjust decimal result type according to internalDecimalScale
if (gwi.internalDecimalScale >= 0 && aop->resultType().colDataType == CalpontSystemCatalog::DECIMAL) if (gwi.internalDecimalScale >= 0 && aop->resultType().colDataType == CalpontSystemCatalog::DECIMAL)