Skip to content

Instantly share code, notes, and snippets.

@joelonsql
Last active February 20, 2023 21:49
Show Gist options
  • Select an option

  • Save joelonsql/59bd2642d577fe4aaf2fb8b1ab7f67c4 to your computer and use it in GitHub Desktop.

Select an option

Save joelonsql/59bd2642d577fe4aaf2fb8b1ab7f67c4 to your computer and use it in GitHub Desktop.

Revisions

  1. joelonsql revised this gist Feb 20, 2023. 12 changed files with 0 additions and 0 deletions.
    Binary file modified full-range-add.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified full-range-div.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified full-range-mul.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified full-range-overview.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified up-to-20-digits-add.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified up-to-20-digits-div.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified up-to-20-digits-mul.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified up-to-20-digits-overview.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified up-to-200-digits-add.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified up-to-200-digits-div.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified up-to-200-digits-mul.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified up-to-200-digits-overview.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  2. joelonsql revised this gist Feb 20, 2023. 12 changed files with 0 additions and 0 deletions.
    Binary file added full-range-add.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added full-range-div.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added full-range-mul.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added full-range-overview.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added up-to-20-digits-add.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added up-to-20-digits-div.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added up-to-20-digits-mul.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added up-to-20-digits-overview.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added up-to-200-digits-add.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added up-to-200-digits-div.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added up-to-200-digits-mul.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added up-to-200-digits-overview.pdf.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  3. joelonsql created this gist Feb 20, 2023.
    955 changes: 955 additions & 0 deletions 0005-fixed-buf.patch
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,955 @@
    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++)
    {