Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite631df3

Browse files
committed
Extend numeric_round and numeric_trunc to accept negative scale inputs
(ie, allow rounding to occur at a digit position left of the decimalpoint). Apparently this is how Oracle handles it, and there areprecedents in other programming languages as well.
1 parent57cf095 commite631df3

File tree

1 file changed

+79
-20
lines changed

1 file changed

+79
-20
lines changed

‎src/backend/utils/adt/numeric.c

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
*1998 Jan Wieck
77
*
8-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.25 2000/02/24 02:05:30 tgl Exp $
8+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.26 2000/03/13 02:31:13 tgl Exp $
99
*
1010
* ----------
1111
*/
@@ -491,14 +491,17 @@ numeric_sign(Numeric num)
491491
/* ----------
492492
* numeric_round() -
493493
*
494-
*Modify rscale and dscale of a number and round it if required.
494+
*Round a value to have 'scale' digits after the decimal point.
495+
*We allow negative 'scale', implying rounding before the decimal
496+
*point --- Oracle interprets rounding that way.
495497
* ----------
496498
*/
497499
Numeric
498500
numeric_round(Numericnum,int32scale)
499501
{
500-
int32typmod;
501-
intprecision;
502+
Numericres;
503+
NumericVararg;
504+
inti;
502505

503506
/* ----------
504507
* Handle NULL
@@ -515,27 +518,79 @@ numeric_round(Numeric num, int32 scale)
515518
returnmake_result(&const_nan);
516519

517520
/* ----------
518-
*Check thattherequestedscaleis valid
521+
*Limitthe scalevalue to avoid possible overflow in calculations below.
519522
* ----------
520523
*/
521-
if (scale<0||scale>NUMERIC_MAX_DISPLAY_SCALE)
522-
elog(ERROR,"illegal numeric scale %d - must be between 0 and %d",
523-
scale,NUMERIC_MAX_DISPLAY_SCALE);
524+
scale=MIN(NUMERIC_MAX_RESULT_SCALE,
525+
MAX(-NUMERIC_MAX_RESULT_SCALE,scale));
524526

525527
/* ----------
526-
*Let numeric()andin turn apply_typmod() dothejob
528+
*Unpack the argumentandround it attheproper digit position
527529
* ----------
528530
*/
529-
precision=MAX(0,num->n_weight)+scale;
530-
typmod= (((precision+2) <<16) |scale)+VARHDRSZ;
531-
returnnumeric(num,typmod);
531+
init_var(&arg);
532+
set_var_from_num(num,&arg);
533+
534+
i=arg.weight+scale+1;
535+
536+
if (i<arg.ndigits)
537+
{
538+
/* If i = 0, the value loses all digits, but could round up if its
539+
* first digit is more than 4. If i < 0 the result must be 0.
540+
*/
541+
if (i<0)
542+
{
543+
arg.ndigits=0;
544+
}
545+
else
546+
{
547+
intcarry= (arg.digits[i]>4) ?1 :0;
548+
549+
arg.ndigits=i;
550+
551+
while (carry)
552+
{
553+
carry+=arg.digits[--i];
554+
arg.digits[i]=carry %10;
555+
carry /=10;
556+
}
557+
558+
if (i<0)
559+
{
560+
Assert(i==-1);/* better not have added more than 1 digit */
561+
Assert(arg.digits>arg.buf);
562+
arg.digits--;
563+
arg.ndigits++;
564+
arg.weight++;
565+
}
566+
}
567+
}
568+
569+
/* ----------
570+
* Set result's scale to something reasonable.
571+
* ----------
572+
*/
573+
scale=MIN(NUMERIC_MAX_DISPLAY_SCALE,MAX(0,scale));
574+
arg.rscale=scale;
575+
arg.dscale=scale;
576+
577+
/* ----------
578+
* Return the rounded result
579+
* ----------
580+
*/
581+
res=make_result(&arg);
582+
583+
free_var(&arg);
584+
returnres;
532585
}
533586

534587

535588
/* ----------
536589
* numeric_trunc() -
537590
*
538-
*Modify rscale and dscale of a number and cut it if required.
591+
*Truncate a value to have 'scale' digits after the decimal point.
592+
*We allow negative 'scale', implying a truncation before the decimal
593+
*point --- Oracle interprets truncation that way.
539594
* ----------
540595
*/
541596
Numeric
@@ -559,25 +614,29 @@ numeric_trunc(Numeric num, int32 scale)
559614
returnmake_result(&const_nan);
560615

561616
/* ----------
562-
*Check thattherequestedscaleis valid
617+
*Limitthe scalevalue to avoid possible overflow in calculations below.
563618
* ----------
564619
*/
565-
if (scale<0||scale>NUMERIC_MAX_DISPLAY_SCALE)
566-
elog(ERROR,"illegal numeric scale %d - must be between 0 and %d",
567-
scale,NUMERIC_MAX_DISPLAY_SCALE);
620+
scale=MIN(NUMERIC_MAX_RESULT_SCALE,
621+
MAX(-NUMERIC_MAX_RESULT_SCALE,scale));
568622

569623
/* ----------
570-
* Unpack the argument and truncate it
624+
* Unpack the argument and truncate it at the proper digit position
571625
* ----------
572626
*/
573627
init_var(&arg);
574628
set_var_from_num(num,&arg);
575629

630+
arg.ndigits=MIN(arg.ndigits,MAX(0,arg.weight+scale+1));
631+
632+
/* ----------
633+
* Set result's scale to something reasonable.
634+
* ----------
635+
*/
636+
scale=MIN(NUMERIC_MAX_DISPLAY_SCALE,MAX(0,scale));
576637
arg.rscale=scale;
577638
arg.dscale=scale;
578639

579-
arg.ndigits=MIN(arg.ndigits,MAX(0,arg.weight+scale+1));
580-
581640
/* ----------
582641
* Return the truncated result
583642
* ----------

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp