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)
249249init_var (& x );
250250set_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
279264while (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 ;
284268carry /=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 ));
288275x .digits -- ;
276+ x .ndigits ++ ;
289277x .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
22132217if (* cp == 'e' || * cp == 'E' )
22142218{
2215- /* Handle ...Ennn */
2219+ /* XXX Should handle ...Ennn */
2220+ elog (ERROR ,"Bad numeric input format '%s'" ,str );
22162221}
22172222
22182223while (dest -> ndigits > 0 && * (dest -> digits )== 0 )
@@ -2378,20 +2383,14 @@ apply_typmod(NumericVar *var, int32 typmod)
23782383scale = typmod & 0xffff ;
23792384maxweight = 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 */
23892387i = scale + var -> weight + 1 ;
23902388if (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
23942392var -> ndigits = i ;
2393+
23952394while (carry )
23962395{
23972396carry += var -> digits [-- i ];
@@ -2401,6 +2400,8 @@ apply_typmod(NumericVar *var, int32 typmod)
24012400
24022401if (i < 0 )
24032402{
2403+ Assert (i == -1 );/* better not have added more than 1 digit */
2404+ Assert (var -> digits > (NumericDigit * ) (var -> buf + 1 ));
24042405var -> digits -- ;
24052406var -> ndigits ++ ;
24062407var -> weight ++ ;
@@ -2410,16 +2411,33 @@ apply_typmod(NumericVar *var, int32 typmod)
24102411var -> 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 */
24172422if (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
24252443var -> rscale = scale ;