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

MCOL-4361 Replace pow(10.0, (double)scale) expressions with a static dictionary lookup.

This commit is contained in:
Alexander Barkov
2021-04-09 12:14:41 +04:00
parent fd720bfd7d
commit 362bfcd15e
13 changed files with 153 additions and 132 deletions

View File

@ -479,45 +479,22 @@ void TupleUnion::normalize(const Row& in, Row* out)
case CalpontSystemCatalog::FLOAT:
case CalpontSystemCatalog::UFLOAT:
{
int scale = in.getScale(i);
if (scale != 0)
{
float f = in.getIntField(i);
f /= (uint64_t) pow(10.0, scale);
out->setFloatField(f, i);
}
else
out->setFloatField(in.getIntField(i), i);
auto d = in.getScaledSInt64FieldAsXFloat<double>(i);
out->setFloatField((float) d, i);
break;
}
case CalpontSystemCatalog::DOUBLE:
case CalpontSystemCatalog::UDOUBLE:
{
int scale = in.getScale(i);
if (scale != 0)
{
double d = in.getIntField(i);
d /= (uint64_t) pow(10.0, scale);
out->setDoubleField(d, i);
}
else
out->setDoubleField(in.getIntField(i), i);
auto d = in.getScaledSInt64FieldAsXFloat<double>(i);
out->setDoubleField(d, i);
break;
}
case CalpontSystemCatalog::LONGDOUBLE:
{
int scale = in.getScale(i);
long double d = in.getIntField(i);
if (scale != 0)
{
d /= (uint64_t) pow(10.0, scale);
}
auto d = in.getScaledSInt64FieldAsXFloat<long double>(i);
out->setLongDoubleField(d, i);
break;
}
@ -526,13 +503,30 @@ void TupleUnion::normalize(const Row& in, Row* out)
case CalpontSystemCatalog::UDECIMAL:
{
dec1:
uint64_t val = in.getIntField(i);
int diff = out->getScale(i) - in.getScale(i);
if (diff < 0)
val /= (uint64_t) pow((double) 10, (double) - diff);
else
val *= (uint64_t) pow((double) 10, (double) diff);
/*
Signed INT to XDecimal
TODO: there are a few problems here:
- This code is not wide decimal friendly.
`uint64_t val` can overflow when applying a positive scale
It's not possible to make a reproducible bug report
at the moment: MCOL-4612 and MCOL-4613 should be fixed first.
- Using uint64_t is wrong here. The data type of "in" field is
signed. In case of a negative diff, the result will be wrong,
because division (unlike multiplication) is sensitive to
the signess of the operands.
Perhaps diff cannot be negative and we can put an assert for it.
Anyway, it's safer to change `uint64_t val` to `int64_t val`.
- This code does not handle overflow that may happen on
scale multiplication (MCOL-4613). Instead of returning a garbage
we should probably apply saturation here. In long terms we
should implement DECIMAL(65,x) to avoid overflow completely
(so the UNION between DECIMAL and integer can choose a proper
DECIMAL(M,N) result data type to guarantee that any incoming
integer value can fit into it).
*/
// TODO: isn't overflow possible below?
uint64_t val = datatypes::applySignedScale<uint64_t>(in.getIntField(i), diff);
if (out->getColumnWidth(i) == datatypes::MAXDECIMALWIDTH)
out->setInt128Field(val, i);
@ -606,50 +600,23 @@ dec1:
case CalpontSystemCatalog::FLOAT:
case CalpontSystemCatalog::UFLOAT:
{
int scale = in.getScale(i);
if (scale != 0)
{
float f = in.getUintField(i);
f /= (uint64_t) pow(10.0, scale);
out->setFloatField(f, i);
}
else
out->setFloatField(in.getUintField(i), i);
auto d = in.getScaledUInt64FieldAsXFloat<double>(i);
out->setFloatField((float) d, i);
break;
}
case CalpontSystemCatalog::DOUBLE:
case CalpontSystemCatalog::UDOUBLE:
{
int scale = in.getScale(i);
if (scale != 0)
{
double d = in.getUintField(i);
d /= (uint64_t) pow(10.0, scale);
out->setDoubleField(d, i);
}
else
out->setDoubleField(in.getUintField(i), i);
auto d = in.getScaledUInt64FieldAsXFloat<double>(i);
out->setDoubleField(d, i);
break;
}
case CalpontSystemCatalog::LONGDOUBLE:
{
int scale = in.getScale(i);
if (scale != 0)
{
long double d = in.getUintField(i);
d /= (uint64_t) pow(10.0, scale);
out->setLongDoubleField(d, i);
}
else
out->setLongDoubleField(in.getUintField(i), i);
auto d = in.getScaledUInt64FieldAsXFloat<long double>(i);
out->setLongDoubleField(d, i);
break;
}
@ -657,13 +624,16 @@ dec1:
case CalpontSystemCatalog::UDECIMAL:
{
dec2:
uint64_t val = in.getIntField(i);
int diff = out->getScale(i) - in.getScale(i);
if (diff < 0)
val /= (uint64_t) pow((double) 10, (double) - diff);
else
val *= (uint64_t) pow((double) 10, (double) diff);
/*
Unsigned INT to XDecimal
TODO: There are a few problems here:
- It should use in.getUintField() instead of in.getIntField()
- All problems mentioned in the code under label "dec1:" are
also applicable here.
*/
// TODO: isn't overflow possible below?
uint64_t val = datatypes::applySignedScale<uint64_t>(in.getIntField(i), diff);
if (out->getColumnWidth(i) == datatypes::MAXDECIMALWIDTH)
out->setInt128Field(val, i);
@ -989,13 +959,15 @@ dec2:
{
dec3: /* have to pick a scale to use for the double. using 5... */
uint32_t scale = 5;
uint64_t ival = (uint64_t) (double) (val * pow((double) 10, (double) scale));
uint64_t ival = (uint64_t) (double) (val * datatypes::scaleDivisor<double>(scale));
int diff = out->getScale(i) - scale;
if (diff < 0)
ival /= (uint64_t) pow((double) 10, (double) - diff);
else
ival *= (uint64_t) pow((double) 10, (double) diff);
// xFLOAT or xDOUBLE to xDECIMAL conversion. Is it really possible?
// TODO:
// Perhaps we should add an assert here that this combination is not possible
// In the current reduction all problems mentioned in the code under
// label "dec1:" are also applicable here.
// TODO: isn't overflow possible below?
ival = datatypes::applySignedScale<uint64_t>(ival, diff);
if (out->getColumnWidth(i) == datatypes::MAXDECIMALWIDTH)
out->setInt128Field(ival, i);
@ -1070,13 +1042,15 @@ dec3: /* have to pick a scale to use for the double. using 5..
{
dec4: /* have to pick a scale to use for the double. using 5... */
uint32_t scale = 5;
uint64_t ival = (uint64_t) (double) (val * pow((double) 10, (double) scale));
uint64_t ival = (uint64_t) (double) (val * datatypes::scaleDivisor<double>(scale));
int diff = out->getScale(i) - scale;
if (diff < 0)
ival /= (uint64_t) pow((double) 10, (double) - diff);
else
ival *= (uint64_t) pow((double) 10, (double) diff);
// LONGDOUBLE to xDECIMAL conversions: is it really possible?
// TODO:
// Perhaps we should add an assert here that this combination is not possible
// In the current reduction all problems mentioned in the code under
// label "dec1:" are also applicable here.
ival = datatypes::applySignedScale<uint64_t>(ival, diff);
if (out->getColumnWidth(i) == datatypes::MAXDECIMALWIDTH)
out->setInt128Field(ival, i);