diff --git a/src/common/backend/utils/adt/numeric.cpp b/src/common/backend/utils/adt/numeric.cpp index e8cab3a80..6bb92a741 100644 --- a/src/common/backend/utils/adt/numeric.cpp +++ b/src/common/backend/utils/adt/numeric.cpp @@ -144,13 +144,6 @@ static void dump_var(const char* str, NumericVar* var); #define dump_var(s, v) #endif -#define digitbuf_alloc(ndigits) ((NumericDigit*)palloc((ndigits) * sizeof(NumericDigit))) -#define digitbuf_free(buf) \ - do { \ - if ((buf) != NULL) \ - pfree_ext(buf); \ - } while (0) - #define NUMERIC_CAN_BE_SHORT(scale, weight) \ ((scale) <= NUMERIC_SHORT_DSCALE_MAX && (weight) <= NUMERIC_SHORT_WEIGHT_MAX && \ (weight) >= NUMERIC_SHORT_WEIGHT_MIN) @@ -504,7 +497,7 @@ Datum numeric_recv(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid length in external \"numeric\" value"))); - alloc_var(&value, len); + init_alloc_var(&value, len); value.weight = (int16)pq_getmsgint(buf, sizeof(int16)); value.sign = (uint16)pq_getmsgint(buf, sizeof(uint16)); @@ -3927,24 +3920,8 @@ static void dump_var(const char* str, NumericVar* var) */ static void alloc_var(NumericVar* var, int ndigits) { - digitbuf_free(var->buf); - var->buf = digitbuf_alloc(ndigits + 1); - var->buf[0] = 0; /* spare digit for rounding */ - var->digits = var->buf + 1; - var->ndigits = ndigits; -} - -/* - * free_var() - - * - * Return the digit buffer of a variable to the free pool - */ -void free_var(NumericVar* var) -{ - digitbuf_free(var->buf); - var->buf = NULL; - var->digits = NULL; - var->sign = NUMERIC_NAN; + digitbuf_free(var); + init_alloc_var(var, ndigits); } /* @@ -3955,9 +3932,8 @@ void free_var(NumericVar* var) */ static void zero_var(NumericVar* var) { - digitbuf_free(var->buf); - var->buf = NULL; - var->digits = NULL; + digitbuf_free(var); + quick_init_var(var); var->ndigits = 0; var->weight = 0; /* by convention; doesn't really matter */ var->sign = NUMERIC_POS; /* anything but NAN... */ @@ -4161,7 +4137,7 @@ void init_var_from_num(Numeric num, NumericVar* dest) dest->sign = NUMERIC_SIGN(num); dest->dscale = NUMERIC_DSCALE(num); dest->digits = NUMERIC_DIGITS(num); - dest->buf = NULL; /* digits array is not palloc'd */ + dest->buf = dest->ndb; } /* @@ -4181,7 +4157,7 @@ static void set_var_from_var(const NumericVar* value, NumericVar* dest) newbuf + 1, value->ndigits * sizeof(NumericDigit), value->digits, value->ndigits * sizeof(NumericDigit)); securec_check(rc, "\0", "\0"); } - digitbuf_free(dest->buf); + digitbuf_free(dest); rc = memmove_s(dest, sizeof(NumericVar), value, sizeof(NumericVar)); securec_check(rc, "\0", "\0"); @@ -4431,10 +4407,8 @@ static char* get_str_from_var_sci(NumericVar* var, int rscale) else denom_scale = 0; - ret = memset_s(&denominator, sizeof(NumericVar), 0, sizeof(NumericVar)); - securec_check(ret, "", ""); - ret = memset_s(&significand, sizeof(NumericVar), 0, sizeof(NumericVar)); - securec_check(ret, "", ""); + init_var(&denominator); + init_var(&significand); power_var_int(&const_ten, exponent, &denominator, denom_scale); div_var(var, &denominator, &significand, rscale, true); @@ -6664,7 +6638,7 @@ static void add_abs(NumericVar* var1, NumericVar* var2, NumericVar* result) Assert(carry == 0); /* else we failed to allow for carry out */ - digitbuf_free(result->buf); + digitbuf_free(result); result->ndigits = res_ndigits; result->buf = res_buf; result->digits = res_digits; @@ -6740,7 +6714,7 @@ static void sub_abs(NumericVar* var1, NumericVar* var2, NumericVar* result) Assert(borrow == 0); /* else caller gave us var1 < var2 */ - digitbuf_free(result->buf); + digitbuf_free(result); result->ndigits = res_ndigits; result->buf = res_buf; result->digits = res_digits; diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h index 2cf3c1b1c..f12ee49a5 100644 --- a/src/include/utils/numeric.h +++ b/src/include/utils/numeric.h @@ -288,6 +288,8 @@ extern int32 get_ndigit_from_numeric(_in_ Numeric num); * This is feasible because the digit buffer is separate from the variable. * ---------- */ +#define NUMERIC_LOCAL_NDIG 36 /* number of 'digits' in local digits[] */ +#define NUMERIC_LOCAL_NMAX (NUMERIC_LOCAL_NDIG - 2) typedef struct NumericVar { int ndigits; /* # of digits in digits[] - can be 0! */ int weight; /* weight of first digit */ @@ -295,13 +297,55 @@ typedef struct NumericVar { int dscale; /* display scale */ NumericDigit* buf; /* start of palloc'd space for digits[] */ NumericDigit* digits; /* base-NBASE digits */ + NumericDigit ndb[NUMERIC_LOCAL_NDIG]; /* local space for digits[] */ } NumericVar; -#define init_var(v) MemSetAligned(v, 0, sizeof(NumericVar)) +#define quick_init_var(v) \ + do { \ + (v)->buf = (v)->ndb; \ + (v)->digits = NULL; \ + } while (0) + +#define init_var(v) \ + do { \ + quick_init_var((v)); \ + (v)->ndigits = 0; \ + (v)->weight = 0; \ + (v)->sign = 0; \ + (v)->dscale = 0; \ + } while (0) + +#define digitbuf_alloc(ndigits) \ + ((NumericDigit*) palloc((ndigits) * sizeof(NumericDigit))) + +#define digitbuf_free(v) \ + do { \ + if ((v)->buf != (v)->ndb) { \ + pfree((v)->buf); \ + (v)->buf = (v)->ndb; \ + } \ + } while (0) + +#define free_var(v) digitbuf_free((v)); + +/* + * Init a var and allocate digit buffer of ndigits digits (plus a spare digit for rounding). + * Called when first using a var. + */ +#define init_alloc_var(v, n) \ + do { \ + (v)->buf = (v)->ndb; \ + (v)->ndigits = (n); \ + if ((n) > NUMERIC_LOCAL_NMAX) { \ + (v)->buf = digitbuf_alloc((n) + 1); \ + } \ + (v)->buf[0] = 0; \ + (v)->digits = (v)->buf + 1; \ + } while (0) + Numeric makeNumeric(NumericVar* var); extern Numeric make_result(NumericVar *var); extern void init_var_from_num(Numeric num, NumericVar* dest); -extern void free_var(NumericVar *var); extern bool numericvar_to_int64(const NumericVar* var, int64* result, bool can_ignore = false); extern void int64_to_numericvar(int64 val, NumericVar *var); extern void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result);