forked from openGauss-Ecosystem/openGauss-server
优化numeric转大数的逻辑
This commit is contained in:
parent
c883406e78
commit
95421580c4
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue