unit test for decimal
This commit is contained in:
parent
1ef210980f
commit
c1f49fee95
|
@ -52,20 +52,28 @@ static uint8_t maxPrecision(DecimalInternalType type) {
|
|||
|
||||
int32_t decimalGetRetType(const SDataType* pLeftT, const SDataType* pRightT, EOperatorType opType,
|
||||
SDataType* pOutType) {
|
||||
if (IS_FLOAT_TYPE(pLeftT->type) || IS_FLOAT_TYPE(pRightT->type)) {
|
||||
if (IS_FLOAT_TYPE(pLeftT->type) || IS_FLOAT_TYPE(pRightT->type) || IS_VAR_DATA_TYPE(pLeftT->type) ||
|
||||
IS_VAR_DATA_TYPE(pRightT->type)) {
|
||||
pOutType->type = TSDB_DATA_TYPE_DOUBLE;
|
||||
pOutType->bytes = tDataTypes[TSDB_DATA_TYPE_DOUBLE].bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IS_NULL_TYPE(pLeftT->type) || IS_NULL_TYPE(pRightT->type)) {
|
||||
pOutType->type = TSDB_DATA_TYPE_NULL;
|
||||
pOutType->bytes = tDataTypes[TSDB_DATA_TYPE_NULL].bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO wjm check not supported types
|
||||
uint8_t p1 = pLeftT->precision, s1 = pLeftT->scale, p2 = pRightT->precision, s2 = pRightT->scale;
|
||||
|
||||
if (IS_DECIMAL_TYPE(pLeftT->type)) {
|
||||
p2 = TSDB_DECIMAL128_MAX_PRECISION;
|
||||
if (!IS_DECIMAL_TYPE(pLeftT->type)) {
|
||||
p1 = TSDB_DECIMAL_MAX_PRECISION;
|
||||
s1 = s2; // TODO wjm take which scale? Maybe use default DecimalMax
|
||||
} else {
|
||||
p1 = TSDB_DECIMAL128_MAX_PRECISION;
|
||||
}
|
||||
if (!IS_DECIMAL_TYPE(pRightT->type)) {
|
||||
p1 = TSDB_DECIMAL_MAX_PRECISION;
|
||||
s2 = s1;
|
||||
}
|
||||
|
||||
|
@ -90,8 +98,10 @@ int32_t decimalGetRetType(const SDataType* pLeftT, const SDataType* pRightT, EOp
|
|||
default:
|
||||
return TSDB_CODE_TSC_INVALID_OPERATION;
|
||||
}
|
||||
pOutType->type = TSDB_DATA_TYPE_DECIMAL;
|
||||
pOutType->bytes = tDataTypes[TSDB_DATA_TYPE_DECIMAL].bytes;
|
||||
pOutType->precision = TMIN(pOutType->precision, TSDB_DECIMAL_MAX_PRECISION);
|
||||
pOutType->scale = TMIN(pOutType->scale, TSDB_DECIMAL_MAX_SCALE);
|
||||
pOutType->type = pOutType->precision > TSDB_DECIMAL64_MAX_PRECISION ? TSDB_DATA_TYPE_DECIMAL : TSDB_DATA_TYPE_DECIMAL64;
|
||||
pOutType->bytes = tDataTypes[pOutType->type].bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -458,6 +468,7 @@ static Decimal128 SCALE_MULTIPLIER_128[38 + 1] = {
|
|||
#define DECIMAL128_ONE SCALE_MULTIPLIER_128[0]
|
||||
#define DECIMAL128_TEN SCALE_MULTIPLIER_128[1]
|
||||
|
||||
// TODO wjm pre define it?? actually, its MAX_INTEGER, not MAX
|
||||
#define DECIMAL128_GET_MAX(precision, pMax) \
|
||||
do { \
|
||||
*(pMax) = SCALE_MULTIPLIER_128[precision]; \
|
||||
|
@ -641,7 +652,6 @@ static int32_t decimal128ToStr(const DecimalType* pInt, uint8_t scale, char* pBu
|
|||
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]);
|
||||
}
|
||||
int32_t wholeLen = len - scale;
|
||||
|
@ -673,15 +683,18 @@ int32_t decimalToStr(const DecimalType* pDec, int8_t dataType, int8_t precision,
|
|||
int32_t decimalOp(EOperatorType op, const SDataType* pLeftT, const SDataType* pRightT, const SDataType* pOutT,
|
||||
const void* pLeftData, const void* pRightData, void* pOutputData) {
|
||||
int32_t code = 0;
|
||||
if (pOutT->type != TSDB_DATA_TYPE_DECIMAL) return TSDB_CODE_INTERNAL_ERROR;
|
||||
// TODO wjm if output precision <= 18, no need to convert to decimal128
|
||||
|
||||
Decimal pLeft = *(Decimal*)pLeftData, pRight = *(Decimal*)pRightData;
|
||||
Decimal pLeft = {0}, pRight = {0};
|
||||
SDataType tmpType = *pOutT;
|
||||
tmpType.type = TSDB_DATA_TYPE_DECIMAL;
|
||||
tmpType.precision = TSDB_DECIMAL_MAX_PRECISION;
|
||||
if (TSDB_DATA_TYPE_DECIMAL != pLeftT->type || pLeftT->scale != pOutT->scale) {
|
||||
code = convertToDecimal(pLeftData, pLeftT, &pLeft, pOutT);
|
||||
code = convertToDecimal(pLeftData, pLeftT, &pLeft, &tmpType);
|
||||
if (TSDB_CODE_SUCCESS != code) return code;
|
||||
}
|
||||
if (pRightT && (TSDB_DATA_TYPE_DECIMAL != pRightT->type || pRightT->scale != pOutT->scale)) {
|
||||
code = convertToDecimal(pRightData, pRightT, &pRight, pOutT);
|
||||
code = convertToDecimal(pRightData, pRightT, &pRight, &tmpType);
|
||||
if (TSDB_CODE_SUCCESS != code) return code;
|
||||
}
|
||||
|
||||
|
@ -693,7 +706,7 @@ int32_t decimalOp(EOperatorType op, const SDataType* pLeftT, const SDataType* pR
|
|||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
return convertToDecimal(&pLeft, &tmpType, pOutputData, pOutT);
|
||||
}
|
||||
|
||||
#define ABS_INT64(v) (v) == INT64_MIN ? (uint64_t)INT64_MAX + 1 : (uint64_t)llabs(v)
|
||||
|
@ -796,8 +809,12 @@ static int32_t decimal128FromDecimal64(DecimalType* pDec, uint8_t prec, uint8_t
|
|||
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) {
|
||||
Decimal128 max = {0};
|
||||
DECIMAL128_GET_MAX(prec - scale, &max);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define CHECK_OVERFLOW_AND_MAKE_DECIMAL128(pDec, v, max, ABS) \
|
||||
|
|
|
@ -230,6 +230,12 @@ TEST(decimal, decimalFromStr) {
|
|||
resExpect += 1;
|
||||
resExpect *= 100;
|
||||
ASSERT_EQ(res, resExpect);
|
||||
|
||||
char buf[64] = "999.999";
|
||||
Decimal64 dec64 = {0};
|
||||
code = decimal64FromStr(buf, strlen(buf), 6, 3, &dec64);
|
||||
ASSERT_EQ(code, 0);
|
||||
ASSERT_EQ(999999, DECIMAL64_GET_VALUE(&dec64));
|
||||
}
|
||||
|
||||
TEST(decimal, toStr) {
|
||||
|
@ -245,6 +251,78 @@ TEST(decimal, toStr) {
|
|||
ASSERT_STREQ(buf, "0");
|
||||
}
|
||||
|
||||
SDataType getDecimalType(uint8_t prec, uint8_t scale) {
|
||||
if (prec <= 18) {
|
||||
return {.type = TSDB_DATA_TYPE_DECIMAL64, .precision = prec, .scale = scale, .bytes = 8};
|
||||
} else if (prec <= 38) {
|
||||
return {.type = TSDB_DATA_TYPE_DECIMAL, .precision = prec, .scale = scale, .bytes = 16};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool operator==(const SDataType& lt, const SDataType& rt) {
|
||||
return lt.type == rt.type && lt.precision == rt.precision && lt.scale == rt.scale && lt.bytes == rt.bytes;
|
||||
}
|
||||
|
||||
TEST(decimal, decimalOpRetType) {
|
||||
EOperatorType op = OP_TYPE_ADD;
|
||||
auto ta = getDecimalType(10, 2);
|
||||
auto tb = getDecimalType(10, 2);
|
||||
SDataType tc{}, tExpect = {.type = TSDB_DATA_TYPE_DECIMAL64, .precision = 11, .scale = 2, .bytes = sizeof(Decimal64)};
|
||||
int32_t code = decimalGetRetType(&ta, &tb, op, &tc);
|
||||
ASSERT_EQ(code, 0);
|
||||
ASSERT_EQ(tExpect, tc);
|
||||
|
||||
ta.bytes = 8;
|
||||
ta.type = TSDB_DATA_TYPE_TIMESTAMP;
|
||||
|
||||
code = decimalGetRetType(&ta, &tb, op, &tc);
|
||||
ASSERT_EQ(code, 0);
|
||||
tExpect.type = TSDB_DATA_TYPE_DECIMAL;
|
||||
tExpect.precision = TSDB_DECIMAL_MAX_PRECISION;
|
||||
tExpect.scale = 2;
|
||||
tExpect.bytes = sizeof(Decimal);
|
||||
ASSERT_EQ(tExpect, tc);
|
||||
|
||||
ta.bytes = 8;
|
||||
ta.type = TSDB_DATA_TYPE_DOUBLE;
|
||||
tc = {0};
|
||||
code = decimalGetRetType(&ta, &tb, op, &tc);
|
||||
ASSERT_EQ(code, 0);
|
||||
tExpect.type = TSDB_DATA_TYPE_DOUBLE;
|
||||
tExpect.precision = 0;
|
||||
tExpect.scale = 0;
|
||||
tExpect.bytes = 8;
|
||||
ASSERT_EQ(tExpect, tc);
|
||||
}
|
||||
|
||||
TEST(decimal, op) {
|
||||
const char* stra = "123.99", * strb = "456.12";
|
||||
EOperatorType op = OP_TYPE_ADD;
|
||||
auto ta = getDecimalType(10, 2);
|
||||
Decimal64 a = {0};
|
||||
int32_t code = decimal64FromStr(stra, strlen(stra), ta.precision, ta.scale, &a);
|
||||
ASSERT_EQ(code, 0);
|
||||
|
||||
auto tb = getDecimalType(10, 2);
|
||||
Decimal64 b{0};
|
||||
code = decimal64FromStr(strb, strlen(strb), tb.precision, tb.scale, &b);
|
||||
ASSERT_EQ(code, 0);
|
||||
|
||||
SDataType tc{}, tExpect{.type = TSDB_DATA_TYPE_DECIMAL64, .precision = 11, .scale = 2, .bytes = sizeof(Decimal64)};
|
||||
code = decimalGetRetType(&ta, &tb, op, &tc);
|
||||
ASSERT_EQ(code, 0);
|
||||
ASSERT_EQ(tc, tExpect);
|
||||
Decimal64 res{};
|
||||
code = decimalOp(op, &ta, &tb, &tc, &a, &b, &res);
|
||||
ASSERT_EQ(code, 0);
|
||||
|
||||
char buf[64] = {0};
|
||||
code = decimalToStr(&res, TSDB_DATA_TYPE_DECIMAL64, tc.precision, tc.scale, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
ASSERT_STREQ(buf, "580.11");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
|
|
Loading…
Reference in New Issue