Last active
February 20, 2023 21:49
-
-
Save joelonsql/59bd2642d577fe4aaf2fb8b1ab7f67c4 to your computer and use it in GitHub Desktop.
0005-fixed-buf.patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c | |
index a83feea396..dea55847fd 100644 | |
--- a/src/backend/utils/adt/numeric.c | |
+++ b/src/backend/utils/adt/numeric.c | |
@@ -301,6 +301,7 @@ struct NumericData | |
* This is feasible because the digit buffer is separate from the variable. | |
* ---------- | |
*/ | |
+#define FIXED_BUF_LEN 8 | |
typedef struct NumericVar | |
{ | |
int ndigits; /* # of digits in digits[] - can be 0! */ | |
@@ -309,6 +310,8 @@ typedef struct NumericVar | |
int dscale; /* display scale */ | |
NumericDigit *buf; /* start of palloc'd space for digits[] */ | |
NumericDigit *digits; /* base-NBASE digits */ | |
+ int buf_len; | |
+ NumericDigit fixed_buf[FIXED_BUF_LEN]; | |
} NumericVar; | |
@@ -321,6 +324,7 @@ typedef struct | |
NumericVar current; | |
NumericVar stop; | |
NumericVar step; | |
+ NumericVar tmp_var; | |
} generate_series_numeric_fctx; | |
@@ -414,18 +418,18 @@ typedef struct NumericSumAccum | |
*/ | |
static const NumericDigit const_zero_data[1] = {0}; | |
static const NumericVar const_zero = | |
-{0, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_zero_data}; | |
+{0, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_zero_data, 0, {0}}; | |
static const NumericDigit const_one_data[1] = {1}; | |
static const NumericVar const_one = | |
-{1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_one_data}; | |
+{1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_one_data, 0, {0}}; | |
static const NumericVar const_minus_one = | |
-{1, 0, NUMERIC_NEG, 0, NULL, (NumericDigit *) const_one_data}; | |
+{1, 0, NUMERIC_NEG, 0, NULL, (NumericDigit *) const_one_data, 0, {0}}; | |
static const NumericDigit const_two_data[1] = {2}; | |
static const NumericVar const_two = | |
-{1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_two_data}; | |
+{1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_two_data, 0, {0}}; | |
#if DEC_DIGITS == 4 | |
static const NumericDigit const_zero_point_nine_data[1] = {9000}; | |
@@ -435,7 +439,7 @@ static const NumericDigit const_zero_point_nine_data[1] = {90}; | |
static const NumericDigit const_zero_point_nine_data[1] = {9}; | |
#endif | |
static const NumericVar const_zero_point_nine = | |
-{1, -1, NUMERIC_POS, 1, NULL, (NumericDigit *) const_zero_point_nine_data}; | |
+{1, -1, NUMERIC_POS, 1, NULL, (NumericDigit *) const_zero_point_nine_data, 0, {0}}; | |
#if DEC_DIGITS == 4 | |
static const NumericDigit const_one_point_one_data[2] = {1, 1000}; | |
@@ -445,16 +449,16 @@ static const NumericDigit const_one_point_one_data[2] = {1, 10}; | |
static const NumericDigit const_one_point_one_data[2] = {1, 1}; | |
#endif | |
static const NumericVar const_one_point_one = | |
-{2, 0, NUMERIC_POS, 1, NULL, (NumericDigit *) const_one_point_one_data}; | |
+{2, 0, NUMERIC_POS, 1, NULL, (NumericDigit *) const_one_point_one_data, 0, {0}}; | |
static const NumericVar const_nan = | |
-{0, 0, NUMERIC_NAN, 0, NULL, NULL}; | |
+{0, 0, NUMERIC_NAN, 0, NULL, NULL, 0, {0}}; | |
static const NumericVar const_pinf = | |
-{0, 0, NUMERIC_PINF, 0, NULL, NULL}; | |
+{0, 0, NUMERIC_PINF, 0, NULL, NULL, 0, {0}}; | |
static const NumericVar const_ninf = | |
-{0, 0, NUMERIC_NINF, 0, NULL, NULL}; | |
+{0, 0, NUMERIC_NINF, 0, NULL, NULL, 0, {0}}; | |
#if DEC_DIGITS == 4 | |
static const int round_powers[4] = {0, 1000, 100, 10}; | |
@@ -1770,6 +1774,7 @@ generate_series_step_numeric(PG_FUNCTION_ARGS) | |
init_var(&fctx->current); | |
init_var(&fctx->stop); | |
init_var(&fctx->step); | |
+ init_var(&fctx->tmp_var); | |
set_var_from_num(start_num, &fctx->current); | |
set_var_from_num(stop_num, &fctx->stop); | |
@@ -1799,7 +1804,8 @@ generate_series_step_numeric(PG_FUNCTION_ARGS) | |
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); | |
/* increment current in preparation for next iteration */ | |
- add_var(&fctx->current, &fctx->step, &fctx->current); | |
+ set_var_from_var(&fctx->current, &fctx->tmp_var); | |
+ add_var(&fctx->tmp_var, &fctx->step, &fctx->current); | |
MemoryContextSwitchTo(oldcontext); | |
/* do when there is more left to send */ | |
@@ -1917,35 +1923,42 @@ compute_bucket(Numeric operand, Numeric bound1, Numeric bound2, | |
const NumericVar *count_var, bool reversed_bounds, | |
NumericVar *result_var) | |
{ | |
- NumericVar bound1_var; | |
- NumericVar bound2_var; | |
- NumericVar operand_var; | |
+ NumericVar tmp_var1; | |
+ NumericVar tmp_var2; | |
+ NumericVar tmp_var3; | |
+ NumericVar tmp_var4; | |
- init_var_from_num(bound1, &bound1_var); | |
- init_var_from_num(bound2, &bound2_var); | |
- init_var_from_num(operand, &operand_var); | |
+ init_var_from_num(bound1, &tmp_var1); | |
+ init_var_from_num(bound2, &tmp_var2); | |
+ init_var_from_num(operand, &tmp_var3); | |
+ init_var(&tmp_var4); | |
if (!reversed_bounds) | |
{ | |
- sub_var(&operand_var, &bound1_var, &operand_var); | |
- sub_var(&bound2_var, &bound1_var, &bound2_var); | |
+ set_var_from_var(&tmp_var3, &tmp_var4); | |
+ sub_var(&tmp_var4, &tmp_var1, &tmp_var3); | |
+ set_var_from_var(&tmp_var2, &tmp_var4); | |
+ sub_var(&tmp_var4, &tmp_var1, &tmp_var2); | |
} | |
else | |
{ | |
- sub_var(&bound1_var, &operand_var, &operand_var); | |
- sub_var(&bound1_var, &bound2_var, &bound2_var); | |
+ set_var_from_var(&tmp_var3, &tmp_var4); | |
+ sub_var(&tmp_var1, &tmp_var4, &tmp_var3); | |
+ set_var_from_var(&tmp_var2, &tmp_var4); | |
+ sub_var(&tmp_var1, &tmp_var4, &tmp_var2); | |
} | |
- mul_var(&operand_var, count_var, &operand_var, | |
- operand_var.dscale + count_var->dscale); | |
- div_var(&operand_var, &bound2_var, result_var, | |
- select_div_scale(&operand_var, &bound2_var), true); | |
- add_var(result_var, &const_one, result_var); | |
+ mul_var(&tmp_var3, count_var, &tmp_var3, | |
+ tmp_var3.dscale + count_var->dscale); | |
+ div_var(&tmp_var3, &tmp_var2, &tmp_var4, | |
+ select_div_scale(&tmp_var3, &tmp_var2), true); | |
+ add_var(&tmp_var4, &const_one, result_var); | |
floor_var(result_var, result_var); | |
- free_var(&bound1_var); | |
- free_var(&bound2_var); | |
- free_var(&operand_var); | |
+ free_var(&tmp_var1); | |
+ free_var(&tmp_var2); | |
+ free_var(&tmp_var3); | |
+ free_var(&tmp_var4); | |
} | |
/* ---------------------------------------------------------------------- | |
@@ -3426,8 +3439,11 @@ numeric_inc(PG_FUNCTION_ARGS) | |
{ | |
Numeric num = PG_GETARG_NUMERIC(0); | |
NumericVar arg; | |
+ NumericVar result; | |
Numeric res; | |
+ init_var(&result); | |
+ | |
/* | |
* Handle NaN and infinities | |
*/ | |
@@ -3439,11 +3455,11 @@ numeric_inc(PG_FUNCTION_ARGS) | |
*/ | |
init_var_from_num(num, &arg); | |
- add_var(&arg, &const_one, &arg); | |
+ add_var(&arg, &const_one, &result); | |
- res = make_result(&arg); | |
+ res = make_result(&result); | |
- free_var(&arg); | |
+ free_var(&result); | |
PG_RETURN_NUMERIC(res); | |
} | |
@@ -3555,7 +3571,8 @@ numeric_lcm(PG_FUNCTION_ARGS) | |
Numeric num2 = PG_GETARG_NUMERIC(1); | |
NumericVar arg1; | |
NumericVar arg2; | |
- NumericVar result; | |
+ NumericVar tmp_var1; | |
+ NumericVar tmp_var2; | |
Numeric res; | |
/* | |
@@ -3571,7 +3588,8 @@ numeric_lcm(PG_FUNCTION_ARGS) | |
init_var_from_num(num1, &arg1); | |
init_var_from_num(num2, &arg2); | |
- init_var(&result); | |
+ init_var(&tmp_var1); | |
+ init_var(&tmp_var2); | |
/* | |
* Compute the result using lcm(x, y) = abs(x / gcd(x, y) * y), returning | |
@@ -3584,20 +3602,21 @@ numeric_lcm(PG_FUNCTION_ARGS) | |
* display scale is no smaller than either input. | |
*/ | |
if (arg1.ndigits == 0 || arg2.ndigits == 0) | |
- set_var_from_var(&const_zero, &result); | |
+ set_var_from_var(&const_zero, &tmp_var1); | |
else | |
{ | |
- gcd_var(&arg1, &arg2, &result); | |
- div_var(&arg1, &result, &result, 0, false); | |
- mul_var(&arg2, &result, &result, arg2.dscale); | |
- result.sign = NUMERIC_POS; | |
+ gcd_var(&arg1, &arg2, &tmp_var1); | |
+ div_var(&arg1, &tmp_var1, &tmp_var2, 0, false); | |
+ mul_var(&arg2, &tmp_var2, &tmp_var1, arg2.dscale); | |
+ tmp_var1.sign = NUMERIC_POS; | |
} | |
- result.dscale = Max(arg1.dscale, arg2.dscale); | |
+ tmp_var1.dscale = Max(arg1.dscale, arg2.dscale); | |
- res = make_result(&result); | |
+ res = make_result(&tmp_var1); | |
- free_var(&result); | |
+ free_var(&tmp_var1); | |
+ free_var(&tmp_var2); | |
PG_RETURN_NUMERIC(res); | |
} | |
@@ -6130,7 +6149,8 @@ numeric_stddev_internal(NumericAggState *state, | |
NumericVar vN, | |
vsumX, | |
vsumX2, | |
- vNminus1; | |
+ vNminus1, | |
+ tmpVar; | |
int64 totCount; | |
int rscale; | |
@@ -6164,6 +6184,7 @@ numeric_stddev_internal(NumericAggState *state, | |
init_var(&vN); | |
init_var(&vsumX); | |
init_var(&vsumX2); | |
+ init_var(&tmpVar); | |
int64_to_numericvar(state->N, &vN); | |
accum_sum_final(&(state->sumX), &vsumX); | |
@@ -6177,7 +6198,9 @@ numeric_stddev_internal(NumericAggState *state, | |
mul_var(&vsumX, &vsumX, &vsumX, rscale); /* vsumX = sumX * sumX */ | |
mul_var(&vN, &vsumX2, &vsumX2, rscale); /* vsumX2 = N * sumX2 */ | |
- sub_var(&vsumX2, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */ | |
+ | |
+ set_var_from_var(&vsumX2, &tmpVar); | |
+ sub_var(&tmpVar, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */ | |
if (cmp_var(&vsumX2, &const_zero) <= 0) | |
{ | |
@@ -6871,11 +6894,35 @@ 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; | |
+ if (ndigits <= FIXED_BUF_LEN - 1) | |
+ { | |
+ if (var->buf_len > 0) | |
+ { | |
+ digitbuf_free(var->buf); | |
+ var->buf_len = 0; | |
+ } | |
+ var->fixed_buf[0] = 0; /* spare digit for rounding */ | |
+ var->digits = var->fixed_buf + 1; | |
+ var->ndigits = ndigits; | |
+ } | |
+ else if (ndigits < var->buf_len) | |
+ { | |
+ var->buf[0] = 0; | |
+ var->digits = var->buf + 1; | |
+ var->ndigits = ndigits; | |
+ } | |
+ else | |
+ { | |
+ if (var->buf_len > 0) | |
+ { | |
+ digitbuf_free(var->buf); | |
+ } | |
+ var->buf = digitbuf_alloc(ndigits + 1); | |
+ var->buf_len = ndigits + 1; | |
+ var->buf[0] = 0; /* spare digit for rounding */ | |
+ var->digits = var->buf + 1; | |
+ var->ndigits = ndigits; | |
+ } | |
} | |
@@ -6887,8 +6934,12 @@ alloc_var(NumericVar *var, int ndigits) | |
static void | |
free_var(NumericVar *var) | |
{ | |
- digitbuf_free(var->buf); | |
- var->buf = NULL; | |
+ if (var->buf_len > 0) | |
+ { | |
+ digitbuf_free(var->buf); | |
+ var->buf = NULL; | |
+ var->buf_len = 0; | |
+ } | |
var->digits = NULL; | |
var->sign = NUMERIC_NAN; | |
} | |
@@ -6903,8 +6954,12 @@ free_var(NumericVar *var) | |
static void | |
zero_var(NumericVar *var) | |
{ | |
- digitbuf_free(var->buf); | |
- var->buf = NULL; | |
+ if (var->buf_len > 0) | |
+ { | |
+ digitbuf_free(var->buf); | |
+ var->buf = NULL; | |
+ var->buf_len = 0; | |
+ } | |
var->digits = NULL; | |
var->ndigits = 0; | |
var->weight = 0; /* by convention; doesn't really matter */ | |
@@ -7166,8 +7221,10 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign, | |
int64 tmp; | |
int64 mul; | |
NumericVar tmp_var; | |
+ NumericVar tmp_var2; | |
init_var(&tmp_var); | |
+ init_var(&tmp_var2); | |
zero_var(dest); | |
@@ -7190,9 +7247,9 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign, | |
{ | |
/* Add the contribution from this group of digits */ | |
int64_to_numericvar(mul, &tmp_var); | |
- mul_var(dest, &tmp_var, dest, 0); | |
+ mul_var(dest, &tmp_var, &tmp_var2, 0); | |
int64_to_numericvar(tmp, &tmp_var); | |
- add_var(dest, &tmp_var, dest); | |
+ add_var(&tmp_var2, &tmp_var, dest); | |
/* Result will overflow if weight overflows int16 */ | |
if (dest->weight > SHRT_MAX) | |
@@ -7227,9 +7284,9 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign, | |
{ | |
/* Add the contribution from this group of digits */ | |
int64_to_numericvar(mul, &tmp_var); | |
- mul_var(dest, &tmp_var, dest, 0); | |
+ mul_var(dest, &tmp_var, &tmp_var2, 0); | |
int64_to_numericvar(tmp, &tmp_var); | |
- add_var(dest, &tmp_var, dest); | |
+ add_var(&tmp_var2, &tmp_var, dest); | |
/* Result will overflow if weight overflows int16 */ | |
if (dest->weight > SHRT_MAX) | |
@@ -7264,9 +7321,9 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign, | |
{ | |
/* Add the contribution from this group of digits */ | |
int64_to_numericvar(mul, &tmp_var); | |
- mul_var(dest, &tmp_var, dest, 0); | |
+ mul_var(dest, &tmp_var, &tmp_var2, 0); | |
int64_to_numericvar(tmp, &tmp_var); | |
- add_var(dest, &tmp_var, dest); | |
+ add_var(&tmp_var2, &tmp_var, dest); | |
/* Result will overflow if weight overflows int16 */ | |
if (dest->weight > SHRT_MAX) | |
@@ -7301,9 +7358,9 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign, | |
/* Add the contribution from the final group of digits */ | |
int64_to_numericvar(mul, &tmp_var); | |
- mul_var(dest, &tmp_var, dest, 0); | |
+ mul_var(dest, &tmp_var, &tmp_var2, 0); | |
int64_to_numericvar(tmp, &tmp_var); | |
- add_var(dest, &tmp_var, dest); | |
+ add_var(&tmp_var2, &tmp_var, dest); | |
if (dest->weight > SHRT_MAX) | |
goto out_of_range; | |
@@ -7375,6 +7432,7 @@ init_var_from_num(Numeric num, NumericVar *dest) | |
dest->dscale = NUMERIC_DSCALE(num); | |
dest->digits = NUMERIC_DIGITS(num); | |
dest->buf = NULL; /* digits array is not palloc'd */ | |
+ dest->buf_len = 0; | |
} | |
@@ -7388,17 +7446,54 @@ set_var_from_var(const NumericVar *value, NumericVar *dest) | |
{ | |
NumericDigit *newbuf; | |
- newbuf = digitbuf_alloc(value->ndigits + 1); | |
- newbuf[0] = 0; /* spare digit for rounding */ | |
- if (value->ndigits > 0) /* else value->digits might be null */ | |
- memcpy(newbuf + 1, value->digits, | |
- value->ndigits * sizeof(NumericDigit)); | |
+ if (value->ndigits <= FIXED_BUF_LEN - 1) | |
+ { | |
+ if (unlikely(dest->buf_len > 0)) | |
+ { | |
+ digitbuf_free(dest->buf); | |
+ } | |
+ memmove(dest, value, sizeof(NumericVar)); | |
+ dest->buf = NULL; | |
+ dest->buf_len = 0; | |
+ newbuf = dest->fixed_buf; | |
+ newbuf[0] = 0; /* spare digit for rounding */ | |
+ if (value->ndigits > 0) /* else value->digits might be null */ | |
+ memcpy(newbuf + 1, value->digits, | |
+ value->ndigits * sizeof(NumericDigit)); | |
+ dest->digits = newbuf + 1; | |
+ } | |
+ else if (value->ndigits <= dest->buf_len - 1) | |
+ { | |
+ int buf_len = dest->buf_len; | |
+ newbuf = dest->buf; | |
+ newbuf[0] = 0; /* spare digit for rounding */ | |
+ memmove(dest, value, sizeof(NumericVar)); | |
+ if (value->ndigits > 0) /* else value->digits might be null */ | |
+ memmove(newbuf + 1, value->digits, | |
+ value->ndigits * sizeof(NumericDigit)); | |
+ dest->buf = newbuf; | |
+ dest->digits = newbuf + 1; | |
+ dest->buf_len = buf_len; | |
- digitbuf_free(dest->buf); | |
+ } | |
+ else | |
+ { | |
+ newbuf = digitbuf_alloc(value->ndigits + 1); | |
+ newbuf[0] = 0; /* spare digit for rounding */ | |
+ if (value->ndigits > 0) /* else value->digits might be null */ | |
+ memcpy(newbuf + 1, value->digits, | |
+ value->ndigits * sizeof(NumericDigit)); | |
- memmove(dest, value, sizeof(NumericVar)); | |
- dest->buf = newbuf; | |
- dest->digits = newbuf + 1; | |
+ if (dest->buf_len > 0) | |
+ { | |
+ digitbuf_free(dest->buf); | |
+ } | |
+ | |
+ memmove(dest, value, sizeof(NumericVar)); | |
+ dest->buf = newbuf; | |
+ dest->buf_len = value->ndigits + 1; | |
+ dest->digits = newbuf + 1; | |
+ } | |
} | |
@@ -7567,6 +7662,7 @@ get_str_from_var_sci(const NumericVar *var, int rscale) | |
{ | |
int32 exponent; | |
NumericVar tmp_var; | |
+ NumericVar tmp_var2; | |
size_t len; | |
char *str; | |
char *sig_out; | |
@@ -7607,9 +7703,11 @@ get_str_from_var_sci(const NumericVar *var, int rscale) | |
* decimal digits in the process. | |
*/ | |
init_var(&tmp_var); | |
+ init_var(&tmp_var2); | |
power_ten_int(exponent, &tmp_var); | |
- div_var(var, &tmp_var, &tmp_var, rscale, true); | |
+ set_var_from_var(&tmp_var, &tmp_var2); | |
+ div_var(var, &tmp_var2, &tmp_var, rscale, true); | |
sig_out = get_str_from_var(&tmp_var); | |
free_var(&tmp_var); | |
@@ -8814,6 +8912,9 @@ div_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result, | |
int var1ndigits = var1->ndigits; | |
int var2ndigits = var2->ndigits; | |
+ Assert(var1 != result); | |
+ Assert(var2 != result); | |
+ | |
/* | |
* First of all division by zero check; we must not be handed an | |
* unnormalized divisor. | |
@@ -9127,6 +9228,9 @@ div_var_fast(const NumericVar *var1, const NumericVar *var2, | |
NumericDigit *var1digits = var1->digits; | |
NumericDigit *var2digits = var2->digits; | |
+ Assert(var1 != result); | |
+ Assert(var2 != result); | |
+ | |
/* | |
* First of all division by zero check; we must not be handed an | |
* unnormalized divisor. | |
@@ -9473,11 +9577,12 @@ div_var_int(const NumericVar *var, int ival, int ival_weight, | |
int res_sign; | |
int res_weight; | |
int res_ndigits; | |
- NumericDigit *res_buf; | |
NumericDigit *res_digits; | |
uint32 divisor; | |
int i; | |
+ Assert (var != result); | |
+ | |
/* Guard against division by zero */ | |
if (ival == 0) | |
ereport(ERROR, | |
@@ -9510,9 +9615,8 @@ div_var_int(const NumericVar *var, int ival, int ival_weight, | |
if (round) | |
res_ndigits++; | |
- res_buf = digitbuf_alloc(res_ndigits + 1); | |
- res_buf[0] = 0; /* spare digit for later rounding */ | |
- res_digits = res_buf + 1; | |
+ alloc_var(result, res_ndigits); | |
+ res_digits = result->digits; | |
/* | |
* Now compute the quotient digits. This is the short division algorithm | |
@@ -9552,9 +9656,7 @@ div_var_int(const NumericVar *var, int ival, int ival_weight, | |
} | |
/* Store the quotient in result */ | |
- digitbuf_free(result->buf); | |
result->ndigits = res_ndigits; | |
- result->buf = res_buf; | |
result->digits = res_digits; | |
result->weight = res_weight; | |
result->sign = res_sign; | |
@@ -9589,11 +9691,12 @@ div_var_int64(const NumericVar *var, int64 ival, int ival_weight, | |
int res_sign; | |
int res_weight; | |
int res_ndigits; | |
- NumericDigit *res_buf; | |
NumericDigit *res_digits; | |
uint64 divisor; | |
int i; | |
+ Assert(var != result); | |
+ | |
/* Guard against division by zero */ | |
if (ival == 0) | |
ereport(ERROR, | |
@@ -9626,9 +9729,8 @@ div_var_int64(const NumericVar *var, int64 ival, int ival_weight, | |
if (round) | |
res_ndigits++; | |
- res_buf = digitbuf_alloc(res_ndigits + 1); | |
- res_buf[0] = 0; /* spare digit for later rounding */ | |
- res_digits = res_buf + 1; | |
+ alloc_var(result, res_ndigits); | |
+ res_digits = result->digits; | |
/* | |
* Now compute the quotient digits. This is the short division algorithm | |
@@ -9668,9 +9770,7 @@ div_var_int64(const NumericVar *var, int64 ival, int ival_weight, | |
} | |
/* Store the quotient in result */ | |
- digitbuf_free(result->buf); | |
result->ndigits = res_ndigits; | |
- result->buf = res_buf; | |
result->digits = res_digits; | |
result->weight = res_weight; | |
result->sign = res_sign; | |
@@ -9796,9 +9896,11 @@ div_mod_var(const NumericVar *var1, const NumericVar *var2, | |
{ | |
NumericVar q; | |
NumericVar r; | |
+ NumericVar tmp_var; | |
init_var(&q); | |
init_var(&r); | |
+ init_var(&tmp_var); | |
/* | |
* Use div_var_fast() to get an initial estimate for the integer quotient. | |
@@ -9809,7 +9911,8 @@ div_mod_var(const NumericVar *var1, const NumericVar *var2, | |
/* Compute initial estimate of remainder using the quotient estimate. */ | |
mul_var(var2, &q, &r, var2->dscale); | |
- sub_var(var1, &r, &r); | |
+ set_var_from_var(&r, &tmp_var); | |
+ sub_var(var1, &tmp_var, &r); | |
/* | |
* Adjust the results if necessary --- the remainder should have the same | |
@@ -9821,13 +9924,17 @@ div_mod_var(const NumericVar *var1, const NumericVar *var2, | |
/* The absolute value of the quotient is too large */ | |
if (var1->sign == var2->sign) | |
{ | |
- sub_var(&q, &const_one, &q); | |
- add_var(&r, var2, &r); | |
+ set_var_from_var(&q, &tmp_var); | |
+ sub_var(&tmp_var, &const_one, &q); | |
+ set_var_from_var(&r, &tmp_var); | |
+ add_var(&tmp_var, var2, &r); | |
} | |
else | |
{ | |
- add_var(&q, &const_one, &q); | |
- sub_var(&r, var2, &r); | |
+ set_var_from_var(&q, &tmp_var); | |
+ add_var(&tmp_var, &const_one, &q); | |
+ set_var_from_var(&r, &tmp_var); | |
+ sub_var(&tmp_var, var2, &r); | |
} | |
} | |
@@ -9836,13 +9943,17 @@ div_mod_var(const NumericVar *var1, const NumericVar *var2, | |
/* The absolute value of the quotient is too small */ | |
if (var1->sign == var2->sign) | |
{ | |
- add_var(&q, &const_one, &q); | |
- sub_var(&r, var2, &r); | |
+ set_var_from_var(&q, &tmp_var); | |
+ add_var(&tmp_var, &const_one, &q); | |
+ set_var_from_var(&r, &tmp_var); | |
+ sub_var(&tmp_var, var2, &r); | |
} | |
else | |
{ | |
- sub_var(&q, &const_one, &q); | |
- add_var(&r, var2, &r); | |
+ set_var_from_var(&q, &tmp_var); | |
+ sub_var(&tmp_var, &const_one, &q); | |
+ set_var_from_var(&r, &tmp_var); | |
+ add_var(&tmp_var, var2, &r); | |
} | |
} | |
@@ -9851,6 +9962,7 @@ div_mod_var(const NumericVar *var1, const NumericVar *var2, | |
free_var(&q); | |
free_var(&r); | |
+ free_var(&tmp_var); | |
} | |
@@ -9871,9 +9983,10 @@ ceil_var(const NumericVar *var, NumericVar *result) | |
trunc_var(&tmp, 0); | |
if (var->sign == NUMERIC_POS && cmp_var(var, &tmp) != 0) | |
- add_var(&tmp, &const_one, &tmp); | |
+ add_var(&tmp, &const_one, result); | |
+ else | |
+ set_var_from_var(&tmp, result); | |
- set_var_from_var(&tmp, result); | |
free_var(&tmp); | |
} | |
@@ -9895,9 +10008,10 @@ floor_var(const NumericVar *var, NumericVar *result) | |
trunc_var(&tmp, 0); | |
if (var->sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0) | |
- sub_var(&tmp, &const_one, &tmp); | |
+ sub_var(&tmp, &const_one, result); | |
+ else | |
+ set_var_from_var(&tmp, result); | |
- set_var_from_var(&tmp, result); | |
free_var(&tmp); | |
} | |
@@ -9997,6 +10111,7 @@ sqrt_var(const NumericVar *arg, NumericVar *result, int rscale) | |
NumericVar a1_var; | |
NumericVar q_var; | |
NumericVar u_var; | |
+ NumericVar tmp_var; | |
stat = cmp_var(arg, &const_zero); | |
if (stat == 0) | |
@@ -10021,6 +10136,7 @@ sqrt_var(const NumericVar *arg, NumericVar *result, int rscale) | |
init_var(&a1_var); | |
init_var(&q_var); | |
init_var(&u_var); | |
+ init_var(&tmp_var); | |
/* | |
* The result weight is half the input weight, rounded towards minus | |
@@ -10388,13 +10504,15 @@ sqrt_var(const NumericVar *arg, NumericVar *result, int rscale) | |
/* Compute (q,u) = DivRem(r*b + a1, 2*s) */ | |
set_var_from_var(&r_var, &q_var); | |
q_var.weight += blen; | |
- add_var(&q_var, &a1_var, &q_var); | |
+ set_var_from_var(&q_var, &tmp_var); | |
+ add_var(&tmp_var, &a1_var, &q_var); | |
add_var(&s_var, &s_var, &u_var); | |
div_mod_var(&q_var, &u_var, &q_var, &u_var); | |
/* Compute s = s*b + q */ | |
s_var.weight += blen; | |
- add_var(&s_var, &q_var, &s_var); | |
+ set_var_from_var(&s_var, &tmp_var); | |
+ add_var(&tmp_var, &q_var, &s_var); | |
/* | |
* Compute r = u*b + a0 - q^2. | |
@@ -10404,7 +10522,8 @@ sqrt_var(const NumericVar *arg, NumericVar *result, int rscale) | |
* So instead of the final subtraction we can just compare. | |
*/ | |
u_var.weight += blen; | |
- add_var(&u_var, &a0_var, &u_var); | |
+ set_var_from_var(&u_var, &tmp_var); | |
+ add_var(&tmp_var, &a0_var, &u_var); | |
mul_var(&q_var, &q_var, &q_var, 0); | |
if (step > 0) | |
@@ -10414,16 +10533,22 @@ sqrt_var(const NumericVar *arg, NumericVar *result, int rscale) | |
if (r_var.sign == NUMERIC_NEG) | |
{ | |
/* s is too large by 1; set r += s, s--, r += s */ | |
- add_var(&r_var, &s_var, &r_var); | |
- sub_var(&s_var, &const_one, &s_var); | |
- add_var(&r_var, &s_var, &r_var); | |
+ set_var_from_var(&r_var, &tmp_var); | |
+ add_var(&tmp_var, &s_var, &r_var); | |
+ set_var_from_var(&s_var, &tmp_var); | |
+ sub_var(&tmp_var, &const_one, &s_var); | |
+ set_var_from_var(&r_var, &tmp_var); | |
+ add_var(&tmp_var, &s_var, &r_var); | |
} | |
} | |
else | |
{ | |
/* Don't need r anymore, except to test if s is too large by 1 */ | |
if (cmp_var(&u_var, &q_var) < 0) | |
- sub_var(&s_var, &const_one, &s_var); | |
+ { | |
+ set_var_from_var(&s_var, &tmp_var); | |
+ sub_var(&tmp_var, &const_one, &s_var); | |
+ } | |
} | |
Assert(src_idx == src_ndigits); /* All input digits consumed */ | |
@@ -10461,6 +10586,7 @@ static void | |
exp_var(const NumericVar *arg, NumericVar *result, int rscale) | |
{ | |
NumericVar x; | |
+ NumericVar xx; | |
NumericVar elem; | |
int ni; | |
double val; | |
@@ -10470,6 +10596,7 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale) | |
int local_rscale; | |
init_var(&x); | |
+ init_var(&xx); | |
init_var(&elem); | |
set_var_from_var(arg, &x); | |
@@ -10515,7 +10642,8 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale) | |
} | |
local_rscale = x.dscale + ndiv2; | |
- div_var_int(&x, 1 << ndiv2, 0, &x, local_rscale, true); | |
+ set_var_from_var(&x, &xx); | |
+ div_var_int(&xx, 1 << ndiv2, 0, &x, local_rscale, true); | |
} | |
else | |
ndiv2 = 0; | |
@@ -10544,15 +10672,18 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale) | |
mul_var(&x, &x, &elem, local_rscale); | |
ni = 2; | |
- div_var_int(&elem, ni, 0, &elem, local_rscale, true); | |
+ set_var_from_var(&elem, &xx); | |
+ div_var_int(&xx, ni, 0, &elem, local_rscale, true); | |
while (elem.ndigits != 0) | |
{ | |
- add_var(result, &elem, result); | |
+ set_var_from_var(result, &xx); | |
+ add_var(&xx, &elem, result); | |
mul_var(&elem, &x, &elem, local_rscale); | |
ni++; | |
- div_var_int(&elem, ni, 0, &elem, local_rscale, true); | |
+ set_var_from_var(&elem, &xx); | |
+ div_var_int(&xx, ni, 0, &elem, local_rscale, true); | |
} | |
/* | |
@@ -10673,6 +10804,7 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale) | |
{ | |
NumericVar x; | |
NumericVar xx; | |
+ NumericVar xxx; | |
int ni; | |
NumericVar elem; | |
NumericVar fact; | |
@@ -10692,6 +10824,7 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale) | |
init_var(&x); | |
init_var(&xx); | |
+ init_var(&xxx); | |
init_var(&elem); | |
init_var(&fact); | |
@@ -10748,7 +10881,8 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale) | |
sub_var(&x, &const_one, result); | |
add_var(&x, &const_one, &elem); | |
- div_var_fast(result, &elem, result, local_rscale, true); | |
+ set_var_from_var(result, &xxx); | |
+ div_var_fast(&xxx, &elem, result, local_rscale, true); | |
set_var_from_var(result, &xx); | |
mul_var(result, result, &x, local_rscale); | |
@@ -10763,7 +10897,8 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale) | |
if (elem.ndigits == 0) | |
break; | |
- add_var(result, &elem, result); | |
+ set_var_from_var(result, &xxx); | |
+ add_var(&xxx, &elem, result); | |
if (elem.weight < (result->weight - local_rscale * 2 / DEC_DIGITS)) | |
break; | |
@@ -10774,6 +10909,7 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale) | |
free_var(&x); | |
free_var(&xx); | |
+ free_var(&xxx); | |
free_var(&elem); | |
free_var(&fact); | |
} | |
@@ -11196,13 +11332,16 @@ power_var_int(const NumericVar *base, int exp, int exp_dscale, | |
} | |
} | |
- free_var(&base_prod); | |
- | |
/* Compensate for input sign, and round to requested rscale */ | |
if (neg) | |
- div_var_fast(&const_one, result, result, rscale, true); | |
+ { | |
+ div_var_fast(&const_one, result, &base_prod, rscale, true); | |
+ set_var_from_var(&base_prod, result); | |
+ } | |
else | |
round_var(result, rscale); | |
+ | |
+ free_var(&base_prod); | |
} | |
/* | |
@@ -11333,7 +11472,6 @@ cmp_abs_common(const NumericDigit *var1digits, int var1ndigits, int var1weight, | |
static void | |
add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) | |
{ | |
- NumericDigit *res_buf; | |
NumericDigit *res_digits; | |
int res_ndigits; | |
int res_weight; | |
@@ -11352,6 +11490,9 @@ add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) | |
NumericDigit *var1digits = var1->digits; | |
NumericDigit *var2digits = var2->digits; | |
+ Assert(var1 != result); | |
+ Assert(var2 != result); | |
+ | |
res_weight = Max(var1->weight, var2->weight) + 1; | |
res_dscale = Max(var1->dscale, var2->dscale); | |
@@ -11365,9 +11506,8 @@ add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) | |
if (res_ndigits <= 0) | |
res_ndigits = 1; | |
- res_buf = digitbuf_alloc(res_ndigits + 1); | |
- res_buf[0] = 0; /* spare digit for later rounding */ | |
- res_digits = res_buf + 1; | |
+ alloc_var(result, res_ndigits); | |
+ res_digits = result->digits; | |
i1 = res_rscale + var1->weight + 1; | |
i2 = res_rscale + var2->weight + 1; | |
@@ -11394,10 +11534,7 @@ add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) | |
Assert(carry == 0); /* else we failed to allow for carry out */ | |
- digitbuf_free(result->buf); | |
result->ndigits = res_ndigits; | |
- result->buf = res_buf; | |
- result->digits = res_digits; | |
result->weight = res_weight; | |
result->dscale = res_dscale; | |
@@ -11418,7 +11555,6 @@ add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) | |
static void | |
sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) | |
{ | |
- NumericDigit *res_buf; | |
NumericDigit *res_digits; | |
int res_ndigits; | |
int res_weight; | |
@@ -11437,6 +11573,9 @@ sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) | |
NumericDigit *var1digits = var1->digits; | |
NumericDigit *var2digits = var2->digits; | |
+ Assert(var1 != result); | |
+ Assert(var2 != result); | |
+ | |
res_weight = var1->weight; | |
res_dscale = Max(var1->dscale, var2->dscale); | |
@@ -11450,9 +11589,8 @@ sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) | |
if (res_ndigits <= 0) | |
res_ndigits = 1; | |
- res_buf = digitbuf_alloc(res_ndigits + 1); | |
- res_buf[0] = 0; /* spare digit for later rounding */ | |
- res_digits = res_buf + 1; | |
+ alloc_var(result, res_ndigits); | |
+ res_digits = result->digits; | |
i1 = res_rscale + var1->weight + 1; | |
i2 = res_rscale + var2->weight + 1; | |
@@ -11479,10 +11617,7 @@ sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) | |
Assert(borrow == 0); /* else caller gave us var1 < var2 */ | |
- digitbuf_free(result->buf); | |
result->ndigits = res_ndigits; | |
- result->buf = res_buf; | |
- result->digits = res_digits; | |
result->weight = res_weight; | |
result->dscale = res_dscale; | |
@@ -11960,6 +12095,7 @@ accum_sum_final(NumericSumAccum *accum, NumericVar *result) | |
pos_var.buf = pos_var.digits = digitbuf_alloc(accum->ndigits); | |
neg_var.buf = neg_var.digits = digitbuf_alloc(accum->ndigits); | |
+ pos_var.buf_len = neg_var.buf_len = accum->ndigits; | |
for (i = 0; i < accum->ndigits; i++) | |
{ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment