You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-08-26 05:02:32 +03:00
MCOL-4387 Convert dataconvert::decimalToString() into VDecimal and TSInt128 methods
This commit is contained in:
@@ -632,16 +632,20 @@ int TypeHandlerSLongDouble::storeValueToField(rowgroup::Row &row, int pos,
|
||||
int TypeHandlerXDecimal::storeValueToField64(rowgroup::Row &row, int pos,
|
||||
StoreField *f) const
|
||||
{
|
||||
int64_t val = row.getIntField(pos);
|
||||
return f->store_decimal64(val);
|
||||
return f->store_decimal64(datatypes::VDecimal(row.getIntField(pos),
|
||||
f->scale(),
|
||||
f->precision()));
|
||||
}
|
||||
|
||||
|
||||
int TypeHandlerXDecimal::storeValueToField128(rowgroup::Row &row, int pos,
|
||||
StoreField *f) const
|
||||
{
|
||||
int128_t* dec= row.getBinaryField<int128_t>(pos);
|
||||
return f->store_decimal128(*dec);
|
||||
int128_t* decPtr = row.getBinaryField<int128_t>(pos);
|
||||
return f->store_decimal128(datatypes::VDecimal(0,
|
||||
f->scale(),
|
||||
f->precision(),
|
||||
decPtr));
|
||||
}
|
||||
|
||||
|
||||
@@ -780,12 +784,8 @@ TypeHandlerXDecimal::format128(const SimpleValue &v,
|
||||
const
|
||||
{
|
||||
idbassert(isValidXDecimal128(attr));
|
||||
ostringstream oss;
|
||||
char buf[datatypes::Decimal::MAXLENGTH16BYTES];
|
||||
int128_t tmp= v.toSInt128();
|
||||
DataConvert::decimalToString(&tmp, (unsigned) attr.scale, buf, (uint8_t) sizeof(buf), code());
|
||||
oss << buf;
|
||||
return oss.str();
|
||||
datatypes::VDecimal dec(0, attr.scale, attr.precision, v.toSInt128());
|
||||
return dec.toString(true);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -720,6 +720,7 @@ public:
|
||||
virtual ~StoreField() {}
|
||||
virtual int32_t colWidth() const = 0;
|
||||
virtual int32_t precision() const = 0;
|
||||
virtual int32_t scale() const = 0;
|
||||
virtual int store_date(int64_t val) = 0;
|
||||
virtual int store_datetime(int64_t val) = 0;
|
||||
virtual int store_time(int64_t val) = 0;
|
||||
@@ -730,8 +731,8 @@ public:
|
||||
virtual int store_float(float val) = 0;
|
||||
virtual int store_double(double val) = 0;
|
||||
virtual int store_long_double(long double val) = 0;
|
||||
virtual int store_decimal64(int64_t val) = 0;
|
||||
virtual int store_decimal128(const int128_t &val) = 0;
|
||||
virtual int store_decimal64(const datatypes::VDecimal& dec) = 0;
|
||||
virtual int store_decimal128(const datatypes::VDecimal& dec) = 0;
|
||||
virtual int store_lob(const char *str, size_t length) = 0;
|
||||
};
|
||||
|
||||
|
@@ -195,45 +195,6 @@ namespace datatypes
|
||||
}
|
||||
}
|
||||
|
||||
std::string Decimal::toString(VDecimal& value)
|
||||
{
|
||||
char buf[Decimal::MAXLENGTH16BYTES];
|
||||
if (value.s128Value == Decimal128Null)
|
||||
{
|
||||
return std::string("NULL");
|
||||
}
|
||||
else if (value.s128Value == Decimal128Empty)
|
||||
{
|
||||
return std::string("EMPTY");
|
||||
}
|
||||
dataconvert::DataConvert::decimalToString(&value.s128Value,
|
||||
value.scale, buf, (uint8_t) sizeof(buf),
|
||||
datatypes::SystemCatalog::DECIMAL);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
std::string Decimal::toString(const VDecimal& value)
|
||||
{
|
||||
return toString(const_cast<VDecimal&>(value));
|
||||
}
|
||||
|
||||
std::string Decimal::toString(const int128_t& value)
|
||||
{
|
||||
char buf[Decimal::MAXLENGTH16BYTES];
|
||||
if (value == Decimal128Null)
|
||||
{
|
||||
return std::string("NULL");
|
||||
}
|
||||
else if (value == Decimal128Empty)
|
||||
{
|
||||
return std::string("EMPTY");
|
||||
}
|
||||
int128_t& constLessValue = const_cast<int128_t&>(value);
|
||||
dataconvert::DataConvert::decimalToString(&constLessValue,
|
||||
0, buf, sizeof(buf), datatypes::SystemCatalog::DECIMAL);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
int Decimal::compare(const VDecimal& l, const VDecimal& r)
|
||||
{
|
||||
int128_t divisorL, divisorR;
|
||||
@@ -559,4 +520,221 @@ namespace datatypes
|
||||
}
|
||||
}
|
||||
|
||||
// Writes integer part of a Decimal using int128 argument provided
|
||||
uint8_t VDecimal::writeIntPart(const int128_t& x,
|
||||
char* buf,
|
||||
const uint8_t buflen) const
|
||||
{
|
||||
char* p = buf;
|
||||
int128_t intPart = x;
|
||||
int128_t high = 0, mid = 0, low = 0;
|
||||
uint64_t maxUint64divisor = 10000000000000000000ULL;
|
||||
|
||||
// Assuming scale = [0, 56]
|
||||
switch (scale / datatypes::maxPowOf10)
|
||||
{
|
||||
case 2: // scale = [38, 56]
|
||||
intPart /= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
intPart /= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
low = intPart;
|
||||
break;
|
||||
case 1: // scale = [19, 37]
|
||||
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 /= datatypes::mcs_pow_10[scale % datatypes::maxPowOf10];
|
||||
low = intPart % maxUint64divisor;
|
||||
intPart /= maxUint64divisor;
|
||||
mid = intPart % maxUint64divisor;
|
||||
high = intPart / maxUint64divisor;
|
||||
break;
|
||||
default:
|
||||
throw logging::QueryDataExcept("VDecimal::writeIntPart() bad scale",
|
||||
logging::formatErr);
|
||||
}
|
||||
|
||||
p += printPodParts(p, high, mid, low);
|
||||
uint8_t written = p - buf;
|
||||
if (buflen <= written)
|
||||
{
|
||||
throw logging::QueryDataExcept("VDecimal::writeIntPart() char buffer overflow.",
|
||||
logging::formatErr);
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
uint8_t VDecimal::writeFractionalPart(const int128_t& x,
|
||||
char* buf,
|
||||
const uint8_t buflen) const
|
||||
{
|
||||
int128_t scaleDivisor = 1;
|
||||
char* p = buf;
|
||||
|
||||
switch (scale / datatypes::maxPowOf10)
|
||||
{
|
||||
case 2:
|
||||
scaleDivisor *= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
scaleDivisor *= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
break;
|
||||
case 1:
|
||||
scaleDivisor *= datatypes::mcs_pow_10[datatypes::maxPowOf10];
|
||||
//fallthrough
|
||||
case 0:
|
||||
scaleDivisor *= datatypes::mcs_pow_10[scale % datatypes::maxPowOf10];
|
||||
}
|
||||
|
||||
int128_t fractionalPart = x % scaleDivisor;
|
||||
|
||||
// divide by the base until we have non-zero quotient
|
||||
scaleDivisor /= 10;
|
||||
|
||||
while (scaleDivisor > 1 && fractionalPart / scaleDivisor == 0)
|
||||
{
|
||||
*p++ = '0';
|
||||
scaleDivisor /= 10;
|
||||
}
|
||||
size_t written = p - buf;;
|
||||
p += TSInt128::writeIntPart(fractionalPart, p, buflen - written);
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
// The method writes Decimal based on TSInt128 with scale provided.
|
||||
// It first writes sign, then extracts integer part
|
||||
// prints delimiter and then decimal part.
|
||||
std::string VDecimal::toStringTSInt128WithScale() const
|
||||
{
|
||||
char buf[Decimal::MAXLENGTH16BYTES];
|
||||
uint8_t left = sizeof(buf);
|
||||
char* p = buf;
|
||||
int128_t tempValue = s128Value;
|
||||
// sign
|
||||
if (tempValue < static_cast<int128_t>(0))
|
||||
{
|
||||
*p++ = '-';
|
||||
tempValue *= -1;
|
||||
left--;
|
||||
}
|
||||
|
||||
// integer part
|
||||
p += writeIntPart(tempValue, p, left);
|
||||
|
||||
// decimal delimiter
|
||||
*p++ = '.';
|
||||
// decimal part
|
||||
left = sizeof(buf) - (p - buf);
|
||||
p += writeFractionalPart(tempValue, p, left);
|
||||
|
||||
*p = '\0';
|
||||
|
||||
uint8_t written = p - buf;
|
||||
if (sizeof(buf) <= written)
|
||||
{
|
||||
throw logging::QueryDataExcept("VDecimal::toString() char buffer overflow.",
|
||||
logging::formatErr);
|
||||
}
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
std::string VDecimal::toStringTSInt64() const
|
||||
{
|
||||
char buf[Decimal::MAXLENGTH8BYTES];
|
||||
// Need 19 digits maxium to hold a sum result of 18 digits decimal column.
|
||||
// We don't make a copy of value b/c we mutate its string
|
||||
// representation.
|
||||
#ifndef __LP64__
|
||||
snprintf(buf, sizeof(buf), "%lld", value);
|
||||
#else
|
||||
snprintf(buf, sizeof(buf), "%ld", value);
|
||||
#endif
|
||||
|
||||
//we want to move the last dt_scale chars right by one spot
|
||||
// to insert the dp we want to move the trailing null as well,
|
||||
// so it's really dt_scale+1 chars
|
||||
size_t l1 = strlen(buf);
|
||||
char* ptr = &buf[0];
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
ptr++;
|
||||
idbassert(l1 >= 2);
|
||||
l1--;
|
||||
}
|
||||
|
||||
//need to make sure we have enough leading zeros for this to work.
|
||||
//at this point scale is always > 0
|
||||
size_t l2 = 1;
|
||||
|
||||
if ((unsigned)scale > l1)
|
||||
{
|
||||
const char* zeros = "00000000000000000000"; //20 0's
|
||||
size_t diff = 0;
|
||||
|
||||
if (value != 0)
|
||||
diff = scale - l1; //this will always be > 0
|
||||
else
|
||||
diff = scale;
|
||||
|
||||
memmove((ptr + diff), ptr, l1 + 1); //also move null
|
||||
memcpy(ptr, zeros, diff);
|
||||
|
||||
if (value != 0)
|
||||
l1 = 0;
|
||||
else
|
||||
l1 = 1;
|
||||
}
|
||||
else if ((unsigned)scale == l1)
|
||||
{
|
||||
l1 = 0;
|
||||
l2 = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
l1 -= scale;
|
||||
}
|
||||
|
||||
memmove((ptr + l1 + l2), (ptr + l1), scale + 1); //also move null
|
||||
|
||||
if (l2 == 2)
|
||||
*(ptr + l1++) = '0';
|
||||
|
||||
*(ptr + l1) = '.';
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
// Dispatcher method for toString() implementations
|
||||
std::string VDecimal::toString(bool hasTSInt128) const
|
||||
{
|
||||
// There must be no empty at this point though
|
||||
if (isNull())
|
||||
{
|
||||
return std::string("NULL");
|
||||
}
|
||||
|
||||
if(LIKELY(hasTSInt128 || isTSInt128ByPrecision()))
|
||||
{
|
||||
if (scale)
|
||||
{
|
||||
return toStringTSInt128WithScale();
|
||||
}
|
||||
return TSInt128::toString();
|
||||
}
|
||||
// TSInt64 Decimal
|
||||
if (scale)
|
||||
{
|
||||
return toStringTSInt64();
|
||||
}
|
||||
return std::to_string(value);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const VDecimal& dec)
|
||||
{
|
||||
os << dec.toString();
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
} // end of namespace
|
||||
|
@@ -131,8 +131,8 @@ const int128_t mcs_pow_10_128[20] =
|
||||
};
|
||||
|
||||
constexpr uint32_t maxPowOf10 = sizeof(mcs_pow_10)/sizeof(mcs_pow_10[0])-1;
|
||||
constexpr int128_t Decimal128Null = int128_t(0x8000000000000000LL) << 64;
|
||||
constexpr int128_t Decimal128Empty = (int128_t(0x8000000000000000LL) << 64) + 1;
|
||||
constexpr int128_t Decimal128Null = TSInt128::NullValue;
|
||||
constexpr int128_t Decimal128Empty = TSInt128::EmptyValue;
|
||||
|
||||
|
||||
/**
|
||||
@@ -172,7 +172,7 @@ class Decimal
|
||||
Decimal() { };
|
||||
~Decimal() { };
|
||||
|
||||
static constexpr uint8_t MAXLENGTH16BYTES = 42;
|
||||
static constexpr uint8_t MAXLENGTH16BYTES = TSInt128::maxLength();
|
||||
static constexpr uint8_t MAXLENGTH8BYTES = 23;
|
||||
|
||||
static inline bool isWideDecimalNullValue(const int128_t& val)
|
||||
@@ -259,13 +259,6 @@ class Decimal
|
||||
const VDecimal& r,
|
||||
VDecimal& result);
|
||||
|
||||
/**
|
||||
@brief Convenience methods to put decimal into a std::string.
|
||||
*/
|
||||
static std::string toString(VDecimal& value);
|
||||
static std::string toString(const VDecimal& value);
|
||||
static std::string toString(const int128_t& value);
|
||||
|
||||
/**
|
||||
@brief The method detects whether decimal type is wide
|
||||
using precision.
|
||||
@@ -558,6 +551,14 @@ class VDecimal: public TSInt128
|
||||
precision(p)
|
||||
{ }
|
||||
|
||||
VDecimal(int64_t unused, int8_t s, uint8_t p, const int128_t* val128Ptr) :
|
||||
TSInt128(val128Ptr),
|
||||
value(unused),
|
||||
scale(s),
|
||||
precision(p)
|
||||
{ }
|
||||
|
||||
|
||||
int decimalComp(const VDecimal& d) const
|
||||
{
|
||||
lldiv_t d1 = lldiv(value, static_cast<int64_t>(mcs_pow_10[scale]));
|
||||
@@ -819,9 +820,35 @@ class VDecimal: public TSInt128
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isTSInt128ByPrecision() const
|
||||
{
|
||||
return precision > INT64MAXPRECISION
|
||||
&& precision <= INT128MAXPRECISION;
|
||||
}
|
||||
// hasTSInt128 explicitly tells to print int128 out in cases
|
||||
// where precision can't detect decimal type properly, e.g.
|
||||
// DECIMAL(10)/DECIMAL(38)
|
||||
std::string toString(bool hasTSInt128 = false) const;
|
||||
friend std::ostream& operator<<(std::ostream& os, const VDecimal& dec);
|
||||
|
||||
int64_t value;
|
||||
int8_t scale; // 0~38
|
||||
uint8_t precision; // 1~38
|
||||
|
||||
// STRICTLY for unit tests!!!
|
||||
void setTSInt64Value(const int64_t x) { value = x; }
|
||||
void setTSInt128Value(const int128_t& x) { s128Value = x; }
|
||||
|
||||
private:
|
||||
uint8_t writeIntPart(const int128_t& x,
|
||||
char* buf,
|
||||
const uint8_t buflen) const;
|
||||
uint8_t writeFractionalPart(const int128_t& x,
|
||||
char* buf,
|
||||
const uint8_t buflen) const;
|
||||
std::string toStringTSInt128WithScale() const;
|
||||
std::string toStringTSInt64() const;
|
||||
|
||||
};
|
||||
|
||||
} //end of namespace
|
||||
|
@@ -17,7 +17,10 @@
|
||||
MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "mcs_int128.h"
|
||||
#include "exceptclasses.h"
|
||||
|
||||
namespace datatypes
|
||||
{
|
||||
@@ -33,6 +36,99 @@ namespace datatypes
|
||||
return getLongDoubleFromFloat128(static_cast<__float128>(s128Value));
|
||||
}
|
||||
|
||||
uint8_t TSInt128::printPodParts(char* buf,
|
||||
const int128_t& high,
|
||||
const int128_t& mid,
|
||||
const int128_t& low) const
|
||||
{
|
||||
char* p = buf;
|
||||
// pod[0] is low 8 bytes, pod[1] is high 8 bytes
|
||||
const uint64_t* high_pod = reinterpret_cast<const uint64_t*>(&high);
|
||||
const uint64_t* mid_pod = reinterpret_cast<const uint64_t*>(&mid);
|
||||
const uint64_t* low_pod = reinterpret_cast<const uint64_t*>(&low);
|
||||
|
||||
if (high_pod[0] != 0)
|
||||
{
|
||||
p += sprintf(p, "%lu", high_pod[0]);
|
||||
p += sprintf(p, "%019lu", mid_pod[0]);
|
||||
p += sprintf(p, "%019lu", low_pod[0]);
|
||||
}
|
||||
else if (mid_pod[0] != 0)
|
||||
{
|
||||
p += sprintf(p, "%lu", mid_pod[0]);
|
||||
p += sprintf(p, "%019lu", low_pod[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
p += sprintf(p, "%lu", low_pod[0]);
|
||||
}
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
// This method writes unsigned integer representation of TSInt128
|
||||
uint8_t TSInt128::writeIntPart(const int128_t& x,
|
||||
char* buf,
|
||||
const uint8_t buflen) const
|
||||
{
|
||||
char* p = buf;
|
||||
int128_t high = 0, mid = 0, low = 0;
|
||||
uint64_t maxUint64divisor = 10000000000000000000ULL;
|
||||
|
||||
low = x % maxUint64divisor;
|
||||
int128_t value = x / maxUint64divisor;
|
||||
mid = value % maxUint64divisor;
|
||||
high = value / maxUint64divisor;
|
||||
|
||||
p += printPodParts(p, high, mid, low);
|
||||
uint8_t written = p - buf;
|
||||
if (buflen <= written)
|
||||
{
|
||||
throw logging::QueryDataExcept("TSInt128::writeIntPart() char buffer overflow.",
|
||||
logging::formatErr);
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
// conversion to std::string
|
||||
std::string TSInt128::toString() const
|
||||
{
|
||||
if (isNull())
|
||||
{
|
||||
return std::string("NULL");
|
||||
}
|
||||
|
||||
if (isEmpty())
|
||||
{
|
||||
return std::string("EMPTY");
|
||||
}
|
||||
|
||||
int128_t tempValue = s128Value;
|
||||
char buf[TSInt128::MAXLENGTH16BYTES];
|
||||
uint8_t left = sizeof(buf);
|
||||
char* p = buf;
|
||||
// sign
|
||||
if (tempValue < static_cast<int128_t>(0))
|
||||
{
|
||||
*p++ = '-';
|
||||
tempValue *= -1;
|
||||
left--;
|
||||
}
|
||||
// integer part
|
||||
// reduce the size by one to account for \0
|
||||
left--;
|
||||
p += writeIntPart(tempValue, p, left);
|
||||
*p = '\0';
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const TSInt128& x)
|
||||
{
|
||||
os << x.toString();
|
||||
return os;
|
||||
}
|
||||
|
||||
// The method converts a wide decimal s128Value to an int64_t,
|
||||
// saturating the s128Value if necessary.
|
||||
inline int64_t TSInt128::getInt64FromWideDecimal()
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
|
||||
// Inline asm has three argument lists: output, input and clobber list
|
||||
#if defined(__GNUC__) && (__GNUC___ > 7)
|
||||
@@ -116,18 +117,41 @@ static inline long double getLongDoubleFromFloat128(const __float128& value)
|
||||
class TSInt128
|
||||
{
|
||||
public:
|
||||
// A variety of ctors for aligned and unaligned arguments
|
||||
static constexpr uint8_t MAXLENGTH16BYTES = 42;
|
||||
static constexpr int128_t NullValue = int128_t(0x8000000000000000LL) << 64;
|
||||
static constexpr int128_t EmptyValue = (int128_t(0x8000000000000000LL) << 64) + 1;
|
||||
|
||||
|
||||
// A variety of ctors for aligned and unaligned arguments
|
||||
TSInt128(): s128Value(0) { }
|
||||
|
||||
// aligned argument
|
||||
// aligned argument
|
||||
TSInt128(const int128_t& x) { s128Value = x; }
|
||||
|
||||
// unaligned argument
|
||||
// unaligned argument
|
||||
TSInt128(const int128_t* x) { assignPtrPtr(&s128Value, x); }
|
||||
|
||||
// unaligned argument
|
||||
// unaligned argument
|
||||
TSInt128(const unsigned char* x) { assignPtrPtr(&s128Value, x); }
|
||||
|
||||
// Method returns max length of a string representation
|
||||
static constexpr uint8_t maxLength()
|
||||
{
|
||||
return TSInt128::MAXLENGTH16BYTES;
|
||||
}
|
||||
|
||||
// Checks if the value is NULL
|
||||
inline bool isNull() const
|
||||
{
|
||||
return s128Value == NullValue;
|
||||
}
|
||||
|
||||
// Checks if the value is Empty
|
||||
inline bool isEmpty() const
|
||||
{
|
||||
return s128Value == EmptyValue;
|
||||
}
|
||||
|
||||
// The method copies 16 bytes from one memory cell
|
||||
// into another using memcpy or SIMD.
|
||||
// memcpy in gcc >= 7 is replaced with SIMD instructions
|
||||
@@ -158,6 +182,22 @@ class TSInt128
|
||||
return s128Value == static_cast<int128_t>(x);
|
||||
}
|
||||
|
||||
// print int128_t parts represented as PODs
|
||||
uint8_t printPodParts(char* buf,
|
||||
const int128_t& high,
|
||||
const int128_t& mid,
|
||||
const int128_t& low) const;
|
||||
|
||||
// writes integer part of dec into a buffer
|
||||
uint8_t writeIntPart(const int128_t& x,
|
||||
char* buf,
|
||||
const uint8_t buflen) const;
|
||||
|
||||
// string representation of TSInt128
|
||||
std::string toString() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const TSInt128& x);
|
||||
|
||||
// The method converts a wide decimal s128Value to a double.
|
||||
inline double getDoubleFromWideDecimal();
|
||||
|
||||
|
Reference in New Issue
Block a user