5
5
*
6
6
*1998 Jan Wieck
7
7
*
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 $
9
9
*
10
10
* ----------
11
11
*/
@@ -249,46 +249,50 @@ numeric_out(Numeric num)
249
249
init_var (& x );
250
250
set_var_from_num (num ,& x );
251
251
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
-
266
252
/* ----------
267
253
* Check if we must round up before printing the value and
268
254
* do so.
269
255
* ----------
270
256
*/
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 )
272
259
{
273
- int j ;
274
- int carry ;
260
+ int carry = (x .digits [i ]> 4 ) ?1 :0 ;
275
261
276
- j = x .dscale + x .weight + 1 ;
277
- carry = (x .digits [j ]> 4 ) ?1 :0 ;
262
+ x .ndigits = i ;
278
263
279
264
while (carry )
280
265
{
281
- j -- ;
282
- carry += x .digits [j ];
283
- x .digits [j ]= carry %10 ;
266
+ carry += x .digits [-- i ];
267
+ x .digits [i ]= carry %10 ;
284
268
carry /=10 ;
285
269
}
286
- if (j < 0 )
270
+
271
+ if (i < 0 )
287
272
{
273
+ Assert (i == -1 );/* better not have added more than 1 digit */
274
+ Assert (x .digits > (NumericDigit * ) (x .buf + 1 ));
288
275
x .digits -- ;
276
+ x .ndigits ++ ;
289
277
x .weight ++ ;
290
278
}
291
279
}
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 ++ = '-' ;
292
296
293
297
/* ----------
294
298
* Output all digits before the decimal point
@@ -2212,7 +2216,8 @@ set_var_from_str(char *str, NumericVar *dest)
2212
2216
2213
2217
if (* cp == 'e' || * cp == 'E' )
2214
2218
{
2215
- /* Handle ...Ennn */
2219
+ /* XXX Should handle ...Ennn */
2220
+ elog (ERROR ,"Bad numeric input format '%s'" ,str );
2216
2221
}
2217
2222
2218
2223
while (dest -> ndigits > 0 && * (dest -> digits )== 0 )
@@ -2378,20 +2383,14 @@ apply_typmod(NumericVar *var, int32 typmod)
2378
2383
scale = typmod & 0xffff ;
2379
2384
maxweight = precision - scale ;
2380
2385
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 */
2389
2387
i = scale + var -> weight + 1 ;
2390
2388
if (i >=0 && var -> ndigits > i )
2391
2389
{
2392
- long carry = (var -> digits [i ]> 4 ) ?1 :0 ;
2390
+ int carry = (var -> digits [i ]> 4 ) ?1 :0 ;
2393
2391
2394
2392
var -> ndigits = i ;
2393
+
2395
2394
while (carry )
2396
2395
{
2397
2396
carry += var -> digits [-- i ];
@@ -2401,6 +2400,8 @@ apply_typmod(NumericVar *var, int32 typmod)
2401
2400
2402
2401
if (i < 0 )
2403
2402
{
2403
+ Assert (i == -1 );/* better not have added more than 1 digit */
2404
+ Assert (var -> digits > (NumericDigit * ) (var -> buf + 1 ));
2404
2405
var -> digits -- ;
2405
2406
var -> ndigits ++ ;
2406
2407
var -> weight ++ ;
@@ -2410,16 +2411,33 @@ apply_typmod(NumericVar *var, int32 typmod)
2410
2411
var -> ndigits = MAX (0 ,MIN (i ,var -> ndigits ));
2411
2412
2412
2413
/* ----------
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.
2415
2420
* ----------
2416
2421
*/
2417
2422
if (var -> weight >=maxweight )
2418
2423
{
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
+ }
2423
2441
}
2424
2442
2425
2443
var -> rscale = scale ;