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++)
 	{
