优化numeric转大数的逻辑

This commit is contained in:
wanghao19920907 2023-01-11 05:20:02 -08:00
parent c883406e78
commit 95421580c4
4 changed files with 167 additions and 14 deletions

View File

@ -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);
}

View File

@ -184,22 +184,30 @@ static void TransformScalarVector(Form_pg_attribute attr, ScalarVector* pVector,
FillVector<hasNull>(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;

View File

@ -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);

View File

@ -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