decimal simple conversion
This commit is contained in:
parent
9634a3867d
commit
1ef210980f
|
@ -27,15 +27,17 @@ typedef struct SValue SValue;
|
|||
typedef void DecimalType;
|
||||
|
||||
typedef struct Decimal64 {
|
||||
DecimalWord words[1]; // do not touch it directly, use DECIMAL64_GET_VALUE MACRO
|
||||
DecimalWord words[1]; // do not touch it directly, use DECIMAL64_GET_VALUE MACRO
|
||||
} Decimal64;
|
||||
|
||||
#define DECIMAL64_GET_VALUE(pDec) (int64_t)((pDec)->words[0])
|
||||
#define DECIMAL64_GET_VALUE(pDec) (int64_t)((pDec)->words[0])
|
||||
#define DECIMAL64_SET_VALUE(pDec, val) (*(int64_t*)((pDec)->words)) = (int64_t)(val)
|
||||
#define DECIMAL64_CLONE(pDst, pFrom) ((Decimal64*)(pDst))->words[0] = ((Decimal64*)(pFrom))->words[0]
|
||||
#define DECIMAL64_CLONE(pDst, pFrom) ((Decimal64*)(pDst))->words[0] = ((Decimal64*)(pFrom))->words[0]
|
||||
#define DECIMAL64_MAX 999999999999999999LL
|
||||
#define DECIMAL64_MIN -999999999999999999LL
|
||||
|
||||
typedef struct Decimal128 {
|
||||
DecimalWord words[2]; // do not touch it directly, use DECIMAL128_HIGH_WORD/DECIMAL128_LOW_WORD
|
||||
DecimalWord words[2]; // do not touch it directly, use DECIMAL128_HIGH_WORD/DECIMAL128_LOW_WORD
|
||||
} Decimal128;
|
||||
|
||||
#define Decimal Decimal128
|
||||
|
@ -63,7 +65,7 @@ int32_t decimalToStr(const DecimalType* pDec, int8_t type, int8_t precision, int
|
|||
int32_t decimalGetRetType(const SDataType* pLeftT, const SDataType* pRightT, EOperatorType opType, SDataType* pOutType);
|
||||
int32_t decimalOp(EOperatorType op, const SDataType* pLeftT, const SDataType* pRightT, const SDataType* pOutT,
|
||||
const void* pLeftData, const void* pRightData, void* pOutputData);
|
||||
int32_t convertToDecimal(const void* pData, const SDataType* pInputType, void* pOut, const SDataType* poutType);
|
||||
int32_t convertToDecimal(const void* pData, const SDataType* pInputType, void* pOut, const SDataType* pOutType);
|
||||
|
||||
// TODO wjm change rightWordNum to DecimalType??
|
||||
typedef struct SDecimalOps {
|
||||
|
@ -82,6 +84,8 @@ typedef struct SDecimalOps {
|
|||
|
||||
SDecimalOps* getDecimalOps(int8_t dataType);
|
||||
|
||||
__int128 decimal128ToInt128(const Decimal128* pDec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -54,8 +54,9 @@ bool uInt128Lt(const UInt128* pLeft, const UInt128* pRight);
|
|||
bool uInt128Gt(const UInt128* pLeft, const UInt128* pRight);
|
||||
bool uInt128Eq(const UInt128* pLeft, const UInt128* pRight);
|
||||
|
||||
extern UInt128 uInt128_1e18;
|
||||
extern UInt128 uInt128Zero;
|
||||
extern const UInt128 uInt128_1e18;
|
||||
extern const UInt128 uInt128Zero;
|
||||
extern const uint64_t k1e18;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -274,6 +274,8 @@ static bool decimal64Lt(const DecimalType* pLeft, const DecimalType* pRight,
|
|||
static bool decimal64Gt(const DecimalType* pLeft, const DecimalType* pRight, uint8_t rightWordNum);
|
||||
static bool decimal64Eq(const DecimalType* pLeft, const DecimalType* pRight, uint8_t rightWordNum);
|
||||
static int32_t decimal64ToStr(const DecimalType* pInt, uint8_t scale, char* pBuf, int32_t bufLen);
|
||||
static void decimal64ScaleDown(Decimal64* pDec, uint8_t scaleDown);
|
||||
static void decimal64ScaleUp(Decimal64* pDec, uint8_t scaleUp);
|
||||
|
||||
static void decimal128Negate(DecimalType* pInt);
|
||||
static void decimal128Abs(DecimalType* pWord);
|
||||
|
@ -287,7 +289,9 @@ static bool decimal128Lt(const DecimalType* pLeft, const DecimalType* pRight,
|
|||
static bool decimal128Gt(const DecimalType* pLeft, const DecimalType* pRight, uint8_t rightWordNum);
|
||||
static bool decimal128Eq(const DecimalType* pLeft, const DecimalType* pRight, uint8_t rightWordNum);
|
||||
static int32_t decimal128ToStr(const DecimalType* pInt, uint8_t scale, char* pBuf, int32_t bufLen);
|
||||
static void decimal64ScaleTo(Decimal64* pDec, uint8_t oldScale, uint8_t newScale);
|
||||
void decimal128ScaleTo(Decimal128* pDec, uint8_t oldScale, uint8_t newScale);
|
||||
void decimal128ScaleDown(Decimal128* pDec, uint8_t scaleDown);
|
||||
void decimal128ScaleUp(Decimal128* pDec, uint8_t scaleUp);
|
||||
|
||||
SDecimalOps decimal64Ops = {decimal64Negate, decimal64Abs, decimal64Add, decimal64Subtract,
|
||||
decimal64Multiply, decimal64divide, decimal64Mod, decimal64Lt,
|
||||
|
@ -376,10 +380,26 @@ bool decimal64Eq(const DecimalType* pLeft, const DecimalType* pRight, uint8_t ri
|
|||
return DECIMAL64_GET_VALUE((Decimal64*)pLeft) == DECIMAL64_GET_VALUE(((Decimal64*)pRight));
|
||||
}
|
||||
int32_t decimal64ToStr(const DecimalType* pInt, uint8_t scale, char* pBuf, int32_t bufLen) {
|
||||
char format[16] = "\%0";
|
||||
snprintf(format + 2, 14, "%" PRIu8 PRIu64, scale);
|
||||
return snprintf(pBuf, bufLen, DECIMAL64_GET_VALUE((Decimal64*)pInt) != 0 ? format : "%" PRIu64,
|
||||
DECIMAL64_GET_VALUE((Decimal64*)pInt));
|
||||
Decimal whole = {0}, frac = {0};
|
||||
DecimalWord zero = 0; // TODO wjm remove zero, use SIGN
|
||||
int32_t pos = 0;
|
||||
|
||||
if (DECIMAL64_SIGN((Decimal64*)pInt) == -1) {
|
||||
pos = sprintf(pBuf, "-");
|
||||
}
|
||||
int32_t code = decimalGetWhole(pInt, DECIMAL_64, scale, &whole);
|
||||
pos += snprintf(pBuf + pos, bufLen - pos, "%" PRId64, DECIMAL64_GET_VALUE(&whole));
|
||||
if (scale > 0) {
|
||||
decimalGetFrac(pInt, DECIMAL_64, scale, &frac);
|
||||
if (DECIMAL64_GET_VALUE(&frac) != 0 || DECIMAL64_GET_VALUE(&whole) != 0) {
|
||||
TAOS_STRCAT(pBuf + pos, ".");
|
||||
pos += 1;
|
||||
char format[16] = "\%0";
|
||||
snprintf(format + 2, 14, "%" PRIu8 PRIu64, scale);
|
||||
snprintf(pBuf + pos, bufLen - pos, format, DECIMAL64_GET_VALUE(&frac));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO wjm handle endian problem
|
||||
|
@ -450,7 +470,7 @@ void makeDecimal128(Decimal128* pDec128, int64_t hi, uint64_t low) {
|
|||
}
|
||||
|
||||
static void makeDecimal128FromDecimal64(Decimal128* pTarget, Decimal64 decimal64) {
|
||||
bool negative = false;
|
||||
bool negative = false;
|
||||
if (DECIMAL64_SIGN(&decimal64) == -1) {
|
||||
decimal64Negate(&decimal64);
|
||||
negative = true;
|
||||
|
@ -577,13 +597,12 @@ static bool decimal128Eq(const DecimalType* pLeft, const DecimalType* pRight, ui
|
|||
|
||||
static void extractDecimal128Digits(const Decimal128* pDec, uint64_t* digits, int32_t* digitNum) {
|
||||
#define DIGIT_NUM_ONCE 18
|
||||
const uint64_t k1e18 = 100000000000000000;
|
||||
UInt128 a = {0};
|
||||
UInt128 b = {0};
|
||||
UInt128 a = {0};
|
||||
UInt128 b = {0};
|
||||
*digitNum = 0;
|
||||
makeUInt128(&a, DECIMAL128_HIGH_WORD(pDec), DECIMAL128_LOW_WORD(pDec));
|
||||
while (!uInt128Eq(&a, &uInt128Zero)) {
|
||||
uint64_t hi = a >> 64;
|
||||
uint64_t hi = a >> 64; // TODO wjm ???
|
||||
uint64_t lo = a;
|
||||
|
||||
uint64_t hiQuotient = hi / k1e18;
|
||||
|
@ -602,7 +621,7 @@ static void extractDecimal128Digits(const Decimal128* pDec, uint64_t* digits, in
|
|||
// TODO wjm checkBuflen
|
||||
static int32_t decimal128ToStr(const DecimalType* pInt, uint8_t scale, char* pBuf, int32_t bufLen) {
|
||||
const Decimal128* pDec = (const Decimal128*)pInt;
|
||||
bool negative = DECIMAL128_SIGN(pDec) < 0;
|
||||
bool negative = DECIMAL128_SIGN(pDec) == -1;
|
||||
uint64_t segments[3] = {0};
|
||||
int32_t digitNum = 0;
|
||||
char buf[64] = {0};
|
||||
|
@ -617,6 +636,10 @@ static int32_t decimal128ToStr(const DecimalType* pInt, uint8_t scale, char* pBu
|
|||
} else {
|
||||
extractDecimal128Digits(pDec, segments, &digitNum);
|
||||
}
|
||||
if (digitNum == 0) {
|
||||
TAOS_STRNCAT(pBuf, "0", 2);
|
||||
return 0;
|
||||
}
|
||||
for (int32_t i = digitNum - 1; i >= 0; --i) {
|
||||
// TODO wjm test 0.0000000000000000000000000000000001
|
||||
len += snprintf(buf + len, 64 - len, i == digitNum - 1 ? "%" PRIu64 : "%018" PRIu64, segments[i]);
|
||||
|
@ -637,25 +660,8 @@ int32_t decimalToStr(const DecimalType* pDec, int8_t dataType, int8_t precision,
|
|||
pBuf[0] = '\0';
|
||||
DecimalInternalType iType = DECIMAL_GET_INTERNAL_TYPE(dataType);
|
||||
switch (iType) {
|
||||
case DECIMAL_64: {
|
||||
int32_t wordNum = DECIMAL_GET_WORD_NUM(iType);
|
||||
SDecimalOps* pOps = getDecimalOpsImp(iType);
|
||||
Decimal whole = {0}, frac = {0};
|
||||
DecimalWord zero = 0;// TODO wjm remove zero, use SIGN
|
||||
int32_t pos = 0;
|
||||
|
||||
if (pOps->lt(pDec, &zero, 1)) {
|
||||
pos = sprintf(pBuf, "-");
|
||||
}
|
||||
int32_t code = decimalGetWhole(pDec, iType, scale, &whole);
|
||||
if (!pOps->eq(&whole, &zero, 1)) {
|
||||
pos += pOps->toStr(&whole, scale, pBuf + pos, bufLen - pos);
|
||||
}
|
||||
code = decimalGetFrac(pDec, iType, scale, &frac);
|
||||
if (DECIMAL64_GET_VALUE(&frac) != 0) pos += snprintf(pBuf + pos, bufLen - pos, ".");
|
||||
pOps->toStr(&frac, scale, pBuf + pos, bufLen - pos);
|
||||
return 0;
|
||||
}
|
||||
case DECIMAL_64:
|
||||
return decimal64ToStr(pDec, scale, pBuf, bufLen);
|
||||
case DECIMAL_128:
|
||||
return decimal128ToStr(pDec, scale, pBuf, bufLen);
|
||||
default:
|
||||
|
@ -701,7 +707,7 @@ int32_t decimalOp(EOperatorType op, const SDataType* pLeftT, const SDataType* pR
|
|||
int32_t code = 0; \
|
||||
Decimal64 dv = {ABS(v)}; \
|
||||
if (DECIMAL64_IS_OVERFLOW(dv, max)) { \
|
||||
code = TSDB_CODE_INTERNAL_ERROR; \
|
||||
code = TSDB_CODE_DECIMAL_OVERFLOW; \
|
||||
} else { \
|
||||
makeDecimal64(pDec, (int64_t)(v)); \
|
||||
} \
|
||||
|
@ -711,13 +717,96 @@ int32_t decimalOp(EOperatorType op, const SDataType* pLeftT, const SDataType* pR
|
|||
#define MAKE_DECIMAL64_SIGNED(pDec, v, max) CHECK_OVERFLOW_AND_MAKE_DECIMAL64(pDec, v, max, ABS_INT64)
|
||||
#define MAKE_DECIMAL64_UNSIGNED(pDec, v, max) CHECK_OVERFLOW_AND_MAKE_DECIMAL64(pDec, v, max, ABS_UINT64);
|
||||
|
||||
static int32_t decimal64FromInt64(DecimalType* pDec, uint8_t prec, uint8_t scale, int64_t val) {
|
||||
Decimal64 max = {0};
|
||||
DECIMAL64_GET_MAX(prec - scale, &max);
|
||||
if (DECIMAL64_GET_VALUE(&max) < val || -DECIMAL64_GET_VALUE(&max) > val) {
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
DECIMAL64_SET_VALUE((Decimal64*)pDec, val);
|
||||
decimal64ScaleUp(pDec, scale);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t decimal64FromUint64(DecimalType* pDec, uint8_t prec, uint8_t scale, uint64_t val) {
|
||||
Decimal64 max = {0};
|
||||
DECIMAL64_GET_MAX(prec - scale, &max);
|
||||
if ((uint64_t)DECIMAL64_GET_VALUE(&max) < val) return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
DECIMAL64_SET_VALUE((Decimal64*)pDec, val);
|
||||
decimal64ScaleUp(pDec, scale);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t decimal64FromDouble(DecimalType* pDec, uint8_t prec, uint8_t scale, double val) { return 0; }
|
||||
|
||||
static int32_t decimal64FromDecimal128(DecimalType* pDec, uint8_t pec, uint8_t scale, const DecimalType* pVal,
|
||||
uint8_t valPrec, uint8_t valScale) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t decimal64FromDecimal64(DecimalType* pDec, uint8_t pec, uint8_t scale, const DecimalType* pVal,
|
||||
uint8_t valPrec, uint8_t valScale) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t decimal128FromInt64(DecimalType* pDec, uint8_t prec, uint8_t scale, int64_t val) {
|
||||
if (prec - scale <= 18) {
|
||||
Decimal64 max = {0};
|
||||
DECIMAL64_GET_MAX(prec - scale, &max);
|
||||
if (DECIMAL64_GET_VALUE(&max) < val || -DECIMAL64_GET_VALUE(&max) > val) return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
uint64_t valAbs = ABS_INT64(val);
|
||||
makeDecimal128(pDec, 0, valAbs);
|
||||
if (val < 0) decimal128Negate(pDec);
|
||||
decimal128ScaleUp(pDec, scale);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t decimal128FromUint64(DecimalType* pDec, uint8_t prec, uint8_t scale, uint64_t val) {
|
||||
if (prec - scale <= 19) {
|
||||
Decimal128 max = {0}, decVal = {0};
|
||||
DECIMAL128_GET_MAX(prec - scale, &max);
|
||||
makeDecimal128(&decVal, 0, val);
|
||||
if (decimal128Gt(&decVal, &max, DECIMAL_WORD_NUM(Decimal128))) {
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
}
|
||||
makeDecimal128(pDec, 0, val);
|
||||
decimal128ScaleUp(pDec, scale);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t decimal128FromDouble(DecimalType* pDec, uint8_t prec, uint8_t scale, double val) { return 0; }
|
||||
|
||||
static int32_t decimal128FromDecimal64(DecimalType* pDec, uint8_t prec, uint8_t scale, const DecimalType* pVal,
|
||||
uint8_t valPrec, uint8_t valScale) {
|
||||
Decimal64 dec64 = *(Decimal64*)pVal;
|
||||
bool negative = false;
|
||||
if (DECIMAL64_SIGN(&dec64) == -1) {
|
||||
decimal64Abs(&dec64);
|
||||
negative = true;
|
||||
}
|
||||
Decimal128 max = {0};
|
||||
DECIMAL128_GET_MAX(prec - scale, &max);
|
||||
if (decimal128Lt(&max, &dec64, WORD_NUM(Decimal64))) {
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
makeDecimal128(pDec, 0, DECIMAL64_GET_VALUE(&dec64));
|
||||
if (negative) decimal128Negate(pDec);
|
||||
decimal128ScaleTo(pDec, valScale, scale);
|
||||
return 0;
|
||||
}
|
||||
static int32_t decimal128FromDecimal128(DecimalType* pDec, uint8_t prec, uint8_t scale, const DecimalType* pVal,
|
||||
uint8_t valPrec, uint8_t valScale) {
|
||||
return 0;
|
||||
}
|
||||
#define CHECK_OVERFLOW_AND_MAKE_DECIMAL128(pDec, v, max, ABS) \
|
||||
({ \
|
||||
int32_t code = 0; \
|
||||
Decimal128 dv = {0}; \
|
||||
makeDecimal128(&dv, 0, ABS(v)); \
|
||||
if (DECIMAL128_IS_OVERFLOW(dv, max)) { \
|
||||
code = TSDB_CODE_INTERNAL_ERROR; \
|
||||
code = TSDB_CODE_DECIMAL_OVERFLOW; \
|
||||
} else { \
|
||||
makeDecimal128(pDec, v < 0 ? -1 : 0, ABS(v)); \
|
||||
} \
|
||||
|
@ -791,71 +880,168 @@ int32_t decimalOp(EOperatorType op, const SDataType* pLeftT, const SDataType* pR
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define CONVERT_TO_DECIMAL2(pData, pInputType, pOut, pOutType, decimal) \
|
||||
({ \
|
||||
int32_t code = 0; \
|
||||
int64_t val = 0; \
|
||||
uint64_t uval = 0; \
|
||||
double dval = 0; \
|
||||
switch (pInputType->type) { \
|
||||
case TSDB_DATA_TYPE_NULL: \
|
||||
break; \
|
||||
case TSDB_DATA_TYPE_BOOL: \
|
||||
uval = *(const bool*)pData; \
|
||||
code = decimal##FromUint64(pOut, pOutType->precision, pOutType->scale, uval); \
|
||||
break; \
|
||||
case TSDB_DATA_TYPE_TINYINT: \
|
||||
val = *(const int8_t*)pData; \
|
||||
code = decimal##FromInt64(pOut, pOutType->precision, pOutType->scale, val); \
|
||||
break; \
|
||||
case TSDB_DATA_TYPE_SMALLINT: \
|
||||
val = *(const int16_t*)pData; \
|
||||
code = decimal##FromInt64(pOut, pOutType->precision, pOutType->scale, val); \
|
||||
break; \
|
||||
case TSDB_DATA_TYPE_INT: \
|
||||
val = *(const int32_t*)pData; \
|
||||
code = decimal##FromInt64(pOut, pOutType->precision, pOutType->scale, val); \
|
||||
break; \
|
||||
case TSDB_DATA_TYPE_TIMESTAMP: \
|
||||
case TSDB_DATA_TYPE_BIGINT: \
|
||||
val = *(const int64_t*)pData; \
|
||||
code = decimal##FromInt64(pOut, pOutType->precision, pOutType->scale, val); \
|
||||
break; \
|
||||
case TSDB_DATA_TYPE_UTINYINT: \
|
||||
uval = *(const uint8_t*)pData; \
|
||||
code = decimal##FromUint64(pOut, pOutType->precision, pOutType->scale, uval); \
|
||||
break; \
|
||||
case TSDB_DATA_TYPE_USMALLINT: \
|
||||
uval = *(const uint16_t*)pData; \
|
||||
code = decimal##FromUint64(pOut, pOutType->precision, pOutType->scale, uval); \
|
||||
break; \
|
||||
case TSDB_DATA_TYPE_UINT: \
|
||||
uval = *(const uint32_t*)pData; \
|
||||
code = decimal##FromUint64(pOut, pOutType->precision, pOutType->scale, uval); \
|
||||
break; \
|
||||
case TSDB_DATA_TYPE_UBIGINT: \
|
||||
uval = *(const uint64_t*)pData; \
|
||||
code = decimal##FromUint64(pOut, pOutType->precision, pOutType->scale, uval); \
|
||||
break; \
|
||||
case TSDB_DATA_TYPE_FLOAT: { \
|
||||
dval = *(const float*)pData; \
|
||||
code = decimal##FromDouble(pOut, pOutType->precision, pOutType->scale, dval); \
|
||||
} break; \
|
||||
case TSDB_DATA_TYPE_DOUBLE: { \
|
||||
dval = *(const double*)pData; \
|
||||
code = decimal##FromDouble(pOut, pOutType->precision, pOutType->scale, dval); \
|
||||
} break; \
|
||||
case TSDB_DATA_TYPE_VARCHAR: \
|
||||
case TSDB_DATA_TYPE_VARBINARY: \
|
||||
case TSDB_DATA_TYPE_NCHAR: { \
|
||||
/*decimal##FromStr()*/ \
|
||||
} break; \
|
||||
case TSDB_DATA_TYPE_DECIMAL64: { \
|
||||
code = decimal##FromDecimal64(pOut, pOutType->precision, pOutType->scale, pData, pInputType->precision, \
|
||||
pInputType->scale); \
|
||||
} break; \
|
||||
case TSDB_DATA_TYPE_DECIMAL: { \
|
||||
code = decimal##FromDecimal128(pOut, pOutType->precision, pOutType->scale, pData, pInputType->precision, \
|
||||
pInputType->scale); \
|
||||
} break; \
|
||||
default: \
|
||||
code = TSDB_CODE_OPS_NOT_SUPPORT; \
|
||||
break; \
|
||||
} \
|
||||
code; \
|
||||
})
|
||||
|
||||
int32_t convertToDecimal(const void* pData, const SDataType* pInputType, void* pOut, const SDataType* pOutType) {
|
||||
if (pInputType->type == pOutType->type) return 0;
|
||||
int32_t code = 0;
|
||||
|
||||
switch (pOutType->type) {
|
||||
case TSDB_DATA_TYPE_DECIMAL64: {
|
||||
Decimal64 max = {0};
|
||||
DECIMAL64_GET_MAX(pOutType->precision - pOutType->scale, &max);
|
||||
CONVERT_TO_DECIMAL(pInputType->type, pData, pOut, MAKE_DECIMAL64, max, code);
|
||||
code = CONVERT_TO_DECIMAL2(pData, pInputType, pOut, pOutType, decimal64);
|
||||
} break;
|
||||
case TSDB_DATA_TYPE_DECIMAL: {
|
||||
Decimal128 max = {0};
|
||||
DECIMAL128_GET_MAX(pOutType->precision - pOutType->scale, &max);
|
||||
CONVERT_TO_DECIMAL(pInputType->type, pData, pOut, MAKE_DECIMAL128, max, code);
|
||||
code = CONVERT_TO_DECIMAL2(pData, pInputType, pOut, pOutType, decimal128);
|
||||
} break;
|
||||
default:
|
||||
code = TSDB_CODE_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
// scale to output scale
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
void decimal64ScaleDown(Decimal64* pDec, uint8_t scaleDown) {
|
||||
Decimal64 divisor = SCALE_MULTIPLIER_64[scaleDown];
|
||||
decimal64divide(pDec, &divisor, WORD_NUM(Decimal64), NULL);
|
||||
}
|
||||
|
||||
void decimal64ScaleUp(Decimal64* pDec, uint8_t scaleUp) {
|
||||
Decimal64 multiplier = SCALE_MULTIPLIER_64[scaleUp];
|
||||
decimal64Multiply(pDec, &multiplier, WORD_NUM(Decimal64));
|
||||
}
|
||||
|
||||
void decimal64ScaleTo(Decimal64* pDec, uint8_t oldScale, uint8_t newScale) {
|
||||
if (newScale < oldScale) {
|
||||
Decimal64 divisor = SCALE_MULTIPLIER_64[oldScale - newScale];
|
||||
decimal64divide(pDec, &divisor, 1, NULL);
|
||||
}
|
||||
if (newScale > oldScale)
|
||||
decimal64ScaleUp(pDec, newScale - oldScale);
|
||||
else if (newScale < oldScale)
|
||||
decimal64ScaleDown(pDec, oldScale - newScale);
|
||||
}
|
||||
|
||||
int32_t decimal64FromStr(const char* str, int32_t len, uint8_t expectPrecision, uint8_t expectScale,
|
||||
Decimal64* result) {
|
||||
int32_t decimal64FromStr(const char* str, int32_t len, uint8_t expectPrecision, uint8_t expectScale, Decimal64* pRes) {
|
||||
int32_t code = 0;
|
||||
DecimalVar var = {.type = DECIMAL_64, .pDec = result->words};
|
||||
DecimalVar var = {.type = DECIMAL_64, .pDec = pRes->words};
|
||||
DECIMAL64_SET_VALUE(pRes, 0);
|
||||
code = decimalVarFromStr(str, len, &var);
|
||||
if (TSDB_CODE_SUCCESS != code) return code;
|
||||
Decimal64 max = {0};
|
||||
DECIMAL64_GET_MAX(expectPrecision - expectScale, &max);
|
||||
if (var.scale > expectScale) decimal64ScaleTo(result, var.scale, expectScale);
|
||||
if (decimal64Gt(result, &max, 1)) {
|
||||
DECIMAL64_GET_MAX(expectPrecision, &max);
|
||||
decimal64ScaleTo(pRes, var.scale, expectScale);
|
||||
if (decimal64Gt(pRes, &max, 1)) {
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
void decimal128ScaleDown(Decimal128* pDec, uint8_t scaleDown) {
|
||||
Decimal128 divisor = SCALE_MULTIPLIER_128[scaleDown];
|
||||
decimal128Divide(pDec, &divisor, 2, NULL);
|
||||
}
|
||||
|
||||
void decimal128ScaleUp(Decimal128* pDec, uint8_t scaleUp) {
|
||||
Decimal128 multiplier = SCALE_MULTIPLIER_128[scaleUp];
|
||||
decimal128Multiply(pDec, &multiplier, WORD_NUM(Decimal128));
|
||||
}
|
||||
|
||||
void decimal128ScaleTo(Decimal128* pDec, uint8_t oldScale, uint8_t newScale) {
|
||||
if (newScale < oldScale) {
|
||||
Decimal128 divisor = SCALE_MULTIPLIER_128[oldScale - newScale];
|
||||
decimal128Divide(pDec, &divisor, 2, NULL);
|
||||
}
|
||||
if (newScale > oldScale)
|
||||
decimal128ScaleUp(pDec, newScale - oldScale);
|
||||
else if (newScale < oldScale)
|
||||
decimal128ScaleDown(pDec, oldScale - newScale);
|
||||
}
|
||||
|
||||
int32_t decimal128FromStr(const char* str, int32_t len, uint8_t expectPrecision, uint8_t expectScale,
|
||||
Decimal128* result) {
|
||||
Decimal128* pRes) {
|
||||
int32_t code = 0;
|
||||
DecimalVar var = {.type = DECIMAL_128, .pDec = result->words};
|
||||
DecimalVar var = {.type = DECIMAL_128, .pDec = pRes->words};
|
||||
DECIMAL128_SET_HIGH_WORD(pRes, 0);
|
||||
DECIMAL128_SET_LOW_WORD(pRes, 0);
|
||||
code = decimalVarFromStr(str, len, &var);
|
||||
if (TSDB_CODE_SUCCESS != code) return code;
|
||||
Decimal128 max = {0};
|
||||
DECIMAL128_GET_MAX(expectPrecision - expectScale, &max);
|
||||
if (var.scale > expectScale) decimal128ScaleTo(result, var.scale, expectScale);
|
||||
if (decimal128Gt(result, &max, 2)) {
|
||||
DECIMAL128_GET_MAX(expectPrecision, &max);
|
||||
decimal128ScaleTo(pRes, var.scale, expectScale);
|
||||
if (decimal128Gt(pRes, &max, 2)) {
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
__int128 decimal128ToInt128(const Decimal128* pDec) {
|
||||
__int128 ret = 0;
|
||||
ret = DECIMAL128_HIGH_WORD(pDec);
|
||||
ret <<= 64;
|
||||
ret |= DECIMAL128_LOW_WORD(pDec);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -16,8 +16,9 @@ bool uInt128Lt(const UInt128* pLeft, const UInt128* pRight);
|
|||
bool uInt128Gt(const UInt128* pLeft, const UInt128* pRight);
|
||||
bool uInt128Eq(const UInt128* pLeft, const UInt128* pRight) { return *pLeft == *pRight; }
|
||||
|
||||
UInt128 uInt128Zero = 0;
|
||||
UInt128 uInt128_1e18 = 1000000000000000000;
|
||||
const UInt128 uInt128Zero = 0;
|
||||
const uint64_t k1e18 = 1000000000000000000LL;
|
||||
const UInt128 uInt128_1e18 = k1e18;
|
||||
#else
|
||||
|
||||
void uInt128Multiply(UInt128* pLeft, const UInt128* pRight) {}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "decimal.h"
|
||||
#include "libs/nodes/querynodes.h"
|
||||
#include "tcommon.h"
|
||||
#include "wideInteger.h"
|
||||
using namespace std;
|
||||
|
||||
template <int N>
|
||||
void printArray(const std::array<uint64_t, N> &arr) {
|
||||
void printArray(const std::array<uint64_t, N>& arr) {
|
||||
auto it = arr.rbegin();
|
||||
for (; it != arr.rend(); ++it) {
|
||||
cout << *it;
|
||||
|
@ -61,9 +63,9 @@ TEST(decimal, a) {
|
|||
}
|
||||
|
||||
TEST(decimal128, to_string) {
|
||||
__int128 i = generate_big_int128(37);
|
||||
int64_t hi = i >> 64;
|
||||
uint64_t lo = i;
|
||||
__int128 i = generate_big_int128(37);
|
||||
int64_t hi = i >> 64;
|
||||
uint64_t lo = i;
|
||||
Decimal128 d;
|
||||
makeDecimal128(&d, hi, lo);
|
||||
char buf[64] = {0};
|
||||
|
@ -76,21 +78,21 @@ TEST(decimal128, to_string) {
|
|||
}
|
||||
|
||||
TEST(decimal128, divide) {
|
||||
__int128 i = generate_big_int128(15);
|
||||
int64_t hi = i >> 64;
|
||||
uint64_t lo = i;
|
||||
__int128 i = generate_big_int128(15);
|
||||
int64_t hi = i >> 64;
|
||||
uint64_t lo = i;
|
||||
Decimal128 d;
|
||||
makeDecimal128(&d, hi, lo);
|
||||
|
||||
Decimal128 d2 = {0};
|
||||
makeDecimal128(&d2, 0, 12345678);
|
||||
|
||||
auto ops = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
|
||||
auto ops = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
|
||||
Decimal128 remainder = {0};
|
||||
int8_t precision1 = 38, scale1 = 5, precision2 = 10, scale2 = 2;
|
||||
int8_t out_scale = 25;
|
||||
int8_t out_precision = std::min(precision1 - scale1 + scale2 + out_scale, 38);
|
||||
int8_t delta_scale = out_scale + scale2 - scale1;
|
||||
int8_t precision1 = 38, scale1 = 5, precision2 = 10, scale2 = 2;
|
||||
int8_t out_scale = 25;
|
||||
int8_t out_precision = std::min(precision1 - scale1 + scale2 + out_scale, 38);
|
||||
int8_t delta_scale = out_scale + scale2 - scale1;
|
||||
printDecimal128(&d, precision1, scale1);
|
||||
__int128 a = 1;
|
||||
while (delta_scale-- > 0) a *= 10;
|
||||
|
@ -105,6 +107,7 @@ TEST(decimal128, divide) {
|
|||
}
|
||||
|
||||
TEST(decimal, cpi_taos_fetch_rows) {
|
||||
GTEST_SKIP();
|
||||
const char* host = "127.0.0.1";
|
||||
const char* user = "root";
|
||||
const char* passwd = "taosdata";
|
||||
|
@ -117,16 +120,16 @@ TEST(decimal, cpi_taos_fetch_rows) {
|
|||
FAIL();
|
||||
}
|
||||
|
||||
auto *res = taos_query(pTaos, sql);
|
||||
auto* res = taos_query(pTaos, sql);
|
||||
int32_t code = taos_errno(res);
|
||||
if (code != 0) {
|
||||
cout << "taos_query with sql: " << sql << " failed: " << taos_errstr(res);
|
||||
FAIL();
|
||||
}
|
||||
|
||||
char buf[1024] = {0};
|
||||
auto *fields = taos_fetch_fields(res);
|
||||
auto fieldNum = taos_field_count(res);
|
||||
char buf[1024] = {0};
|
||||
auto* fields = taos_fetch_fields(res);
|
||||
auto fieldNum = taos_field_count(res);
|
||||
while (auto row = taos_fetch_row(res)) {
|
||||
taos_print_row(buf, row, fields, fieldNum);
|
||||
cout << buf << endl;
|
||||
|
@ -140,7 +143,7 @@ TEST(decimal, cpi_taos_fetch_rows) {
|
|||
FAIL();
|
||||
}
|
||||
|
||||
void* pData = NULL;
|
||||
void* pData = NULL;
|
||||
int32_t numOfRows = 0;
|
||||
code = taos_fetch_raw_block(res, &numOfRows, &pData);
|
||||
if (code != 0) {
|
||||
|
@ -151,12 +154,98 @@ TEST(decimal, cpi_taos_fetch_rows) {
|
|||
SSDataBlock* pBlock;
|
||||
taos_free_result(res);
|
||||
|
||||
|
||||
taos_close(pTaos);
|
||||
taos_cleanup();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
void printDecimal(const char* pDecStr, uint8_t type, uint8_t prec, uint8_t scale) {
|
||||
ASSERT_TRUE(type == prec > 18 ? TSDB_DATA_TYPE_DECIMAL : TSDB_DATA_TYPE_DECIMAL64);
|
||||
ASSERT_TRUE(scale <= prec);
|
||||
|
||||
cout << "decimal" << (prec > 18 ? 128 : 64) << " " << (int32_t)prec << ":" << (int32_t)scale << " -> " << pDecStr << endl;
|
||||
}
|
||||
|
||||
TEST(decimal, conversion) {
|
||||
// convert uint8 to decimal
|
||||
char buf[64] = {0};
|
||||
int8_t i8 = 22;
|
||||
SDataType inputType = {.type = TSDB_DATA_TYPE_TINYINT, .bytes = 1};
|
||||
uint8_t prec = 10, scale = 2;
|
||||
SDataType decType = {.type = TSDB_DATA_TYPE_DECIMAL64, .precision = prec, .scale = scale, .bytes = 8};
|
||||
Decimal64 dec64 = {0};
|
||||
int32_t code = convertToDecimal(&i8, &inputType, &dec64, &decType);
|
||||
ASSERT_TRUE(code == 0);
|
||||
code = decimalToStr(&dec64, TSDB_DATA_TYPE_DECIMAL64, prec, scale, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
cout << "convert uint8: " << (int32_t)i8 << " to decimal64 " << (uint32_t)prec << ":" << (uint32_t)scale << "-> "
|
||||
<< buf << endl;
|
||||
ASSERT_STREQ(buf, "22.00");
|
||||
|
||||
Decimal128 dec128 = {0};
|
||||
decType.type = TSDB_DATA_TYPE_DECIMAL;
|
||||
decType.precision = 38;
|
||||
decType.scale = 10;
|
||||
decType.bytes = 16;
|
||||
code = convertToDecimal(&i8, &inputType, &dec128, &decType);
|
||||
ASSERT_TRUE(code == 0);
|
||||
code = decimalToStr(&dec128, TSDB_DATA_TYPE_DECIMAL, decType.precision, decType.scale, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
cout << "convert uint8: " << (int32_t)i8 << " to ";
|
||||
printDecimal(buf, TSDB_DATA_TYPE_DECIMAL, decType.precision, decType.scale);
|
||||
const char* expect = "22.0000000000";
|
||||
ASSERT_STREQ(buf, expect);
|
||||
|
||||
char inputBuf[64] = "123.000000000000000000000000000000001";
|
||||
code = decimal128FromStr(inputBuf, strlen(inputBuf), 38, 35, &dec128);
|
||||
ASSERT_EQ(code, 0);
|
||||
code = decimalToStr(&dec128, TSDB_DATA_TYPE_DECIMAL, 38, 35, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
printDecimal(buf, TSDB_DATA_TYPE_DECIMAL, 38, 35);
|
||||
expect = "123.00000000000000000000000000000000100";
|
||||
ASSERT_STREQ(expect, buf);
|
||||
|
||||
inputType.type = TSDB_DATA_TYPE_DECIMAL64;
|
||||
inputType.precision = prec;
|
||||
inputType.scale = scale;
|
||||
code = convertToDecimal(&dec64, &inputType, &dec128, &decType);
|
||||
ASSERT_EQ(code, 0);
|
||||
decimalToStr(&dec128, TSDB_DATA_TYPE_DECIMAL, 38, 10, buf, 64);
|
||||
expect = "22.0000000000";
|
||||
ASSERT_STREQ(expect, buf);
|
||||
printDecimal(buf, TSDB_DATA_TYPE_DECIMAL, 38, 10);
|
||||
}
|
||||
|
||||
static constexpr uint64_t k1E16 = 10000000000000000LL;
|
||||
|
||||
TEST(decimal, decimalFromStr) {
|
||||
char inputBuf[64] = "123.000000000000000000000000000000001";
|
||||
Decimal128 dec128 = {0};
|
||||
int32_t code = decimal128FromStr(inputBuf, strlen(inputBuf), 38, 35, &dec128);
|
||||
ASSERT_EQ(code, 0);
|
||||
__int128 res = decimal128ToInt128(&dec128);
|
||||
__int128 resExpect = 123;
|
||||
resExpect *= k1E16;
|
||||
resExpect *= k1E16;
|
||||
resExpect *= 10;
|
||||
resExpect += 1;
|
||||
resExpect *= 100;
|
||||
ASSERT_EQ(res, resExpect);
|
||||
}
|
||||
|
||||
TEST(decimal, toStr) {
|
||||
Decimal64 dec = {0};
|
||||
char buf[64] = {0};
|
||||
int32_t code = decimalToStr(&dec, TSDB_DATA_TYPE_DECIMAL64, 10, 2, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
ASSERT_STREQ(buf, "0");
|
||||
|
||||
Decimal128 dec128 = {0};
|
||||
code = decimalToStr(&dec128, TSDB_DATA_TYPE_DECIMAL, 38, 10, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
ASSERT_STREQ(buf, "0");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue