55 *
66 * 1998 Jan Wieck
77 *
8- * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.16.2.1 1999/08/02 05:24:55 scrappy Exp $
8+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.16.2.2 2000/01/16 00:44:06 tgl Exp $
99 *
1010 * ----------
1111 */
@@ -249,46 +249,50 @@ numeric_out(Numeric num)
249249 init_var (& x );
250250 set_var_from_num (num , & x );
251251
252- /* ----------
253- * Allocate space for the result
254- * ----------
255- */
256- str = palloc (x .dscale + MAX (0 , x .weight ) + 5 );
257- cp = str ;
258-
259- /* ----------
260- * Output a dash for negative values
261- * ----------
262- */
263- if (x .sign == NUMERIC_NEG )
264- * cp ++ = '-' ;
265-
266252 /* ----------
267253 * Check if we must round up before printing the value and
268254 * do so.
269255 * ----------
270256 */
271- if (x .dscale < x .rscale && (x .dscale + x .weight + 1 ) < x .ndigits )
257+ i = x .dscale + x .weight + 1 ;
258+ if (i >= 0 && x .ndigits > i )
272259 {
273- int j ;
274- int carry ;
260+ int carry = (x .digits [i ] > 4 ) ? 1 : 0 ;
275261
276- j = x .dscale + x .weight + 1 ;
277- carry = (x .digits [j ] > 4 ) ? 1 : 0 ;
262+ x .ndigits = i ;
278263
279264 while (carry )
280265 {
281- j -- ;
282- carry += x .digits [j ];
283- x .digits [j ] = carry % 10 ;
266+ carry += x .digits [-- i ];
267+ x .digits [i ] = carry % 10 ;
284268 carry /= 10 ;
285269 }
286- if (j < 0 )
270+
271+ if (i < 0 )
287272 {
273+ Assert (i == -1 ); /* better not have added more than 1 digit */
274+ Assert (x .digits > (NumericDigit * ) (x .buf + 1 ));
288275 x .digits -- ;
276+ x .ndigits ++ ;
289277 x .weight ++ ;
290278 }
291279 }
280+ else
281+ x .ndigits = MAX (0 , MIN (i , x .ndigits ));
282+
283+ /* ----------
284+ * Allocate space for the result
285+ * ----------
286+ */
287+ str = palloc (MAX (0 , x .dscale ) + MAX (0 , x .weight ) + 4 );
288+ cp = str ;
289+
290+ /* ----------
291+ * Output a dash for negative values
292+ * ----------
293+ */
294+ if (x .sign == NUMERIC_NEG )
295+ * cp ++ = '-' ;
292296
293297 /* ----------
294298 * Output all digits before the decimal point
@@ -2212,7 +2216,8 @@ set_var_from_str(char *str, NumericVar *dest)
22122216
22132217 if (* cp == 'e' || * cp == 'E' )
22142218 {
2215- /* Handle ...Ennn */
2219+ /* XXX Should handle ...Ennn */
2220+ elog (ERROR , "Bad numeric input format '%s'" , str );
22162221 }
22172222
22182223 while (dest -> ndigits > 0 && * (dest -> digits ) == 0 )
@@ -2378,20 +2383,14 @@ apply_typmod(NumericVar *var, int32 typmod)
23782383 scale = typmod & 0xffff ;
23792384 maxweight = precision - scale ;
23802385
2381- if (var -> weight >= maxweight )
2382- {
2383- free_allvars ();
2384- elog (ERROR , "overflow on numeric "
2385- "ABS(value) >= 10^%d for field with precision %d scale %d" ,
2386- var -> weight , precision , scale );
2387- }
2388-
2386+ /* Round to target scale */
23892387 i = scale + var -> weight + 1 ;
23902388 if (i >= 0 && var -> ndigits > i )
23912389 {
2392- long carry = (var -> digits [i ] > 4 ) ? 1 : 0 ;
2390+ int carry = (var -> digits [i ] > 4 ) ? 1 : 0 ;
23932391
23942392 var -> ndigits = i ;
2393+
23952394 while (carry )
23962395 {
23972396 carry += var -> digits [-- i ];
@@ -2401,6 +2400,8 @@ apply_typmod(NumericVar *var, int32 typmod)
24012400
24022401 if (i < 0 )
24032402 {
2403+ Assert (i == -1 ); /* better not have added more than 1 digit */
2404+ Assert (var -> digits > (NumericDigit * ) (var -> buf + 1 ));
24042405 var -> digits -- ;
24052406 var -> ndigits ++ ;
24062407 var -> weight ++ ;
@@ -2410,16 +2411,33 @@ apply_typmod(NumericVar *var, int32 typmod)
24102411 var -> ndigits = MAX (0 , MIN (i , var -> ndigits ));
24112412
24122413 /* ----------
2413- * Check for overflow again - rounding could have raised the
2414- * weight.
2414+ * Check for overflow - note we can't do this before rounding,
2415+ * because rounding could raise the weight. Also note that the
2416+ * var's weight could be inflated by leading zeroes, which will
2417+ * be stripped before storage but perhaps might not have been yet.
2418+ * In any case, we must recognize a true zero, whose weight doesn't
2419+ * mean anything.
24152420 * ----------
24162421 */
24172422 if (var -> weight >= maxweight )
24182423 {
2419- free_allvars ();
2420- elog (ERROR , "overflow on numeric "
2421- "ABS(value) >= 10^%d for field with precision %d scale %d" ,
2422- var -> weight , precision , scale );
2424+ /* Determine true weight; and check for all-zero result */
2425+ int tweight = var -> weight ;
2426+
2427+ for (i = 0 ; i < var -> ndigits ; i ++ )
2428+ {
2429+ if (var -> digits [i ])
2430+ break ;
2431+ tweight -- ;
2432+ }
2433+
2434+ if (tweight >= maxweight && i < var -> ndigits )
2435+ {
2436+ free_allvars ();
2437+ elog (ERROR , "overflow on numeric "
2438+ "ABS(value) >= 10^%d for field with precision %d scale %d" ,
2439+ tweight , precision , scale );
2440+ }
24232441 }
24242442
24252443 var -> rscale = scale ;
0 commit comments