From 95421580c4d6e878efd7b6485f3579f4ffa9deda Mon Sep 17 00:00:00 2001 From: wanghao19920907 Date: Wed, 11 Jan 2023 05:20:02 -0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96numeric=E8=BD=AC=E5=A4=A7?= =?UTF-8?q?=E6=95=B0=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/utils/adt/numeric.cpp | 128 +++++++++++++++++- .../vecexecutor/vecnode/vecrowtovector.cpp | 34 +++-- src/include/utils/numeric.h | 1 + src/include/utils/numeric_gs.h | 18 +++ 4 files changed, 167 insertions(+), 14 deletions(-) diff --git a/src/common/backend/utils/adt/numeric.cpp b/src/common/backend/utils/adt/numeric.cpp index f81f05d27..25d75e398 100644 --- a/src/common/backend/utils/adt/numeric.cpp +++ b/src/common/backend/utils/adt/numeric.cpp @@ -18936,6 +18936,23 @@ int64 convert_short_numeric_to_int64_byscale(_in_ Numeric n, _in_ int scale) return (int64)result; } +int64 convert_short_numeric_to_int64_byscale_fast(int weight, int ndigits, NumericDigit* digits, int sign, int dscale) +{ + int128 result = 0; + int ascale = (ndigits > 0) ? (ndigits - weight - 1) : 0; + int scaleDiff = dscale - ascale * DEC_DIGITS; + + encode_digits(result, digits, ndigits); + + /* adjust scale */ + result = (scaleDiff > 0) ? (result * ScaleMultipler[scaleDiff]) : (result / ScaleMultipler[-scaleDiff]); + /* get the result by sign */ + result = (NUMERIC_POS == sign) ? result : -result; + Assert(INT128_INT64_EQ(result)); + + return (int64)result; +} + /* * n: ndigits * w: weight @@ -19027,6 +19044,47 @@ void convert_short_numeric_to_int128_byscale(_in_ Numeric n, _in_ int dscale, _o result = (NUMERIC_POS == NUMERIC_SIGN(n)) ? result : -result; } +void convert_short_numeric_to_int128_byscale_fast(int weight, int ndigits, NumericDigit* digits, int sign, int dscale, int128& result) +{ + bool special_do = false; + + /* ndigits is 0, result is 0, return directly */ + result = 0; + if (0 == ndigits) { + return; + } + + int remainder = dscale % DEC_DIGITS; + int ascale = ndigits - (weight + 1); + int end_index = ndigits; + int diff_scale = 0; + Assert(ndigits >= 0); + + if (ascale > 0 && remainder != 0 && (dscale / DEC_DIGITS + 1) == ascale) { + special_do = true; + --end_index; + } + + /* step1. get all valid digitals to result */ + for (int i = 0; i < end_index; i++) + result += (digits[i] * getScaleMultiplier((end_index - 1 - i) * DEC_DIGITS)); + + if (special_do) { + result = (result * getScaleMultiplier(remainder)) + + (digits[ndigits - 1] / getScaleMultiplier(DEC_DIGITS - remainder)); + /* step2. get diff_scale by dscale and ascale */ + diff_scale = dscale - (ascale - 1) * 4 - dscale % 4; + } else { + /* step2. get diff_scale by dscale and ascale */ + diff_scale = dscale - ascale * 4; + } + + /* step3. adjust result by diff_scale */ + result *= getScaleMultiplier(diff_scale); + + result = (NUMERIC_POS == sign) ? result : -result; +} + /* * vscale is from orc file, and dscale is from gaussdb */ @@ -19111,7 +19169,75 @@ Datum try_convert_numeric_normal_to_fast(Datum value, ScalarVector *arr) } else if (CAN_CONVERT_BI128(whole_scale)) { int128 result = 0; convert_short_numeric_to_int128_byscale(val, numVar.dscale, result); - return makeNumeric128(result, numVar.dscale); + return makeNumeric128(result, numVar.dscale, arr); + } else + return NumericGetDatum(val); +} + +Datum try_direct_convert_numeric_normal_to_fast(Datum value, ScalarVector *arr) +{ + Numeric val; + struct varlena* attr = (struct varlena*)value; + union NumericChoice* choice; + NumericVar numVar; + + if (u_sess->attr.attr_sql.enable_fast_numeric == false) { + return NumericGetDatum(DatumGetNumeric(value)); + } + + if (VARATT_IS_EXTENDED(attr)) { + if (VARATT_IS_SHORT(attr) && !VARATT_IS_HUGE_TOAST_POINTER(attr)) { + choice = (union NumericChoice*)VARDATA_SHORT(attr); + + if (NUMERIC_IS_NANORBI_CHOICE(choice)) + return NumericGetDatum(DatumGetNumeric(value)); + + numVar.ndigits = ((VARSIZE_SHORT(attr) - NUMERIC_HEADER_SIZE_CHOICE_1B(choice)) / sizeof(NumericDigit)); + numVar.weight = NUMERIC_WEIGHT_CHOICE(choice); + numVar.sign = NUMERIC_SIGN_CHOICE(choice); + numVar.dscale = NUMERIC_DSCALE_CHOICE(choice); + numVar.digits = NUMERIC_DIGITS_CHOICE(choice); + } + else { + val = DatumGetNumeric(value); + choice = &val->choice; + + if (NUMERIC_IS_NANORBI_CHOICE(choice)) + return NumericGetDatum(DatumGetNumeric(value)); + + numVar.ndigits = NUMERIC_NDIGITS(val); + numVar.weight = NUMERIC_WEIGHT(val); + numVar.sign = NUMERIC_SIGN(val); + numVar.dscale = NUMERIC_DSCALE(val); + numVar.digits = NUMERIC_DIGITS(val); + } + } + else { + val = (Numeric)value; + choice = &val->choice; + + if (NUMERIC_IS_NANORBI_CHOICE(choice)) + return NumericGetDatum(DatumGetNumeric(value)); + + numVar.ndigits = NUMERIC_NDIGITS(val); + numVar.weight = NUMERIC_WEIGHT(val); + numVar.sign = NUMERIC_SIGN(val); + numVar.dscale = NUMERIC_DSCALE(val); + numVar.digits = NUMERIC_DIGITS(val); + } + + int whole_scale = get_whole_scale(numVar); + + // should be ( whole_scale <= MAXINT64DIGIT) + if (CAN_CONVERT_BI64(whole_scale)) { + int64 result = convert_short_numeric_to_int64_byscale_fast( + numVar.weight, numVar.ndigits, numVar.digits, numVar.sign, numVar.dscale); + return makeNumeric64(result, numVar.dscale, arr); + } else if (CAN_CONVERT_BI128(whole_scale)) { + int128 result = 0; + convert_short_numeric_to_int128_byscale_fast( + numVar.weight, numVar.ndigits, numVar.digits, numVar.sign, numVar.dscale, result); + return makeNumeric128(result, numVar.dscale, arr); } else return NumericGetDatum(val); } diff --git a/src/gausskernel/runtime/vecexecutor/vecnode/vecrowtovector.cpp b/src/gausskernel/runtime/vecexecutor/vecnode/vecrowtovector.cpp index b2b1789d3..928e3ec26 100644 --- a/src/gausskernel/runtime/vecexecutor/vecnode/vecrowtovector.cpp +++ b/src/gausskernel/runtime/vecexecutor/vecnode/vecrowtovector.cpp @@ -184,22 +184,30 @@ static void TransformScalarVector(Form_pg_attribute attr, ScalarVector* pVector, FillVector(pVector, rows); break; case -1: - for (i = 0; i < rows; i++) { - if (hasNull && unlikely(IS_NULL(pVector->m_flag[i]))) { - continue; - } + if (attr->atttypid == NUMERICOID) { + for (i = 0; i < rows; i++) { + if (hasNull && unlikely(IS_NULL(pVector->m_flag[i]))) { + continue; + } - v0 = pVector->m_vals[i]; - v = PointerGetDatum(DetoastDatumBatch((struct varlena *)DatumGetPointer(v0), pVector)); - /* if numeric cloumn, try to convert numeric to big integer */ - if (attr->atttypid == NUMERICOID) { - v = try_convert_numeric_normal_to_fast(v, pVector); + v = pVector->m_vals[i]; + /* if numeric cloumn, try to convert numeric to big integer */ + pVector->m_vals[i] = try_direct_convert_numeric_normal_to_fast(v, pVector); } + } + else { + for (i = 0; i < rows; i++) { + if (hasNull && unlikely(IS_NULL(pVector->m_flag[i]))) { + continue; + } - if (v == v0) { - pVector->AddVar(v0, i); - } else { - pVector->m_vals[i] = v; + v0 = pVector->m_vals[i]; + v = PointerGetDatum(DetoastDatumBatch((struct varlena *)DatumGetPointer(v0), pVector)); + if (v == v0) { + pVector->AddVar(v0, i); + } else { + pVector->m_vals[i] = v; + } } } break; diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h index 4ebd41a8e..fbf10a664 100644 --- a/src/include/utils/numeric.h +++ b/src/include/utils/numeric.h @@ -236,6 +236,7 @@ extern int convert_int128_to_short_numeric_byscale( extern Datum convert_short_numeric_to_int64(_in_ Numeric inNum, _out_ bool* outSuccess); extern Datum convert_short_numeric_to_int128(_in_ Numeric inNum, _out_ bool* outSuccess); extern Datum try_convert_numeric_normal_to_fast(Datum value, ScalarVector *arr = NULL); +extern Datum try_direct_convert_numeric_normal_to_fast(Datum value, ScalarVector *arr); extern int64 convert_short_numeric_to_int64_byscale(_in_ Numeric n, _in_ int scale); extern void convert_short_numeric_to_int128_byscale(_in_ Numeric n, _in_ int scale, _out_ int128& result); extern int32 get_ndigit_from_numeric(_in_ Numeric num); diff --git a/src/include/utils/numeric_gs.h b/src/include/utils/numeric_gs.h index 88d8dbf1d..62bf9720e 100644 --- a/src/include/utils/numeric_gs.h +++ b/src/include/utils/numeric_gs.h @@ -22,7 +22,9 @@ #define NUMERIC_HDRSZ_SHORT (VARHDRSZ + sizeof(uint16)) #define NUMERIC_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_SIGN_MASK) +#define NUMERIC_FLAGBITS_CHOICE(n) ((n)->n_header & NUMERIC_SIGN_MASK) #define NUMERIC_NB_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_BI_MASK) // nan or biginteger +#define NUMERIC_NB_FLAGBITS_CHOICE(n) ((n)->n_header & NUMERIC_BI_MASK) #define NUMERIC_IS_NAN(n) (NUMERIC_NB_FLAGBITS(n) == NUMERIC_NAN) #define NUMERIC_IS_SHORT(n) (NUMERIC_FLAGBITS(n) == NUMERIC_SHORT) @@ -44,6 +46,7 @@ * verify whether a numeric data is NAN or BI by itself. */ #define NUMERIC_IS_NANORBI(n) (NUMERIC_NB_FLAGBITS(n) >= NUMERIC_NAN) +#define NUMERIC_IS_NANORBI_CHOICE(n) (NUMERIC_NB_FLAGBITS_CHOICE(n) >= NUMERIC_NAN) #define NUMERIC_IS_BI(n) (NUMERIC_NB_FLAGBITS(n) > NUMERIC_NAN) #define NUMERIC_IS_BI64(n) (NUMERIC_NB_FLAGBITS(n) == NUMERIC_64) #define NUMERIC_IS_BI128(n) (NUMERIC_NB_FLAGBITS(n) == NUMERIC_128) @@ -76,7 +79,9 @@ * can just look at the high bit, for a slight efficiency gain. */ #define NUMERIC_HEADER_IS_SHORT(n) (((n)->choice.n_header & 0x8000) != 0) +#define NUMERIC_HEADER_IS_SHORT_CHOICE(n) (((n)->n_header & 0x8000) != 0) #define NUMERIC_HEADER_SIZE(n) (VARHDRSZ + sizeof(uint16) + (NUMERIC_HEADER_IS_SHORT(n) ? 0 : sizeof(int16))) +#define NUMERIC_HEADER_SIZE_CHOICE_1B(n) (VARHDRSZ_SHORT + sizeof(uint16) + (NUMERIC_HEADER_IS_SHORT_CHOICE(n) ? 0 : sizeof(int16))) /* * Short format definitions. @@ -109,6 +114,19 @@ #define NUMERIC_DIGITS(num) (NUMERIC_HEADER_IS_SHORT(num) ? (num)->choice.n_short.n_data : (num)->choice.n_long.n_data) #define NUMERIC_NDIGITS(num) ((VARSIZE(num) - NUMERIC_HEADER_SIZE(num)) / sizeof(NumericDigit)) +#define NUMERIC_SIGN_CHOICE(n) \ + (NUMERIC_HEADER_IS_SHORT_CHOICE(n) ? (((n)->n_short.n_header & NUMERIC_SHORT_SIGN_MASK) ? NUMERIC_NEG : NUMERIC_POS) \ + : NUMERIC_FLAGBITS_CHOICE(n)) +#define NUMERIC_DSCALE_CHOICE(n) \ + (NUMERIC_HEADER_IS_SHORT_CHOICE((n)) ? ((n)->n_short.n_header & NUMERIC_SHORT_DSCALE_MASK) >> NUMERIC_SHORT_DSCALE_SHIFT \ + : ((n)->n_long.n_sign_dscale & NUMERIC_DSCALE_MASK)) +#define NUMERIC_WEIGHT_CHOICE(n) \ + (NUMERIC_HEADER_IS_SHORT_CHOICE((n)) \ + ? (((n)->n_short.n_header & NUMERIC_SHORT_WEIGHT_SIGN_MASK ? ~NUMERIC_SHORT_WEIGHT_MASK : 0) | \ + ((n)->n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \ + : ((n)->n_long.n_weight)) +#define NUMERIC_DIGITS_CHOICE(num) (NUMERIC_HEADER_IS_SHORT_CHOICE(num) ? (num)->n_short.n_data : (num)->n_long.n_data) + /* * @Description: copy bi64 to ptr, this operation no need to allocate memory * @IN ptr: the numeric pointer