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

Commitb82791c

Browse files
Add overflow checks to money type.
None of the arithmetic functions for the the money type handleoverflow. This commit introduces several helper functions withoverflow checking and makes use of them in the money type'sarithmetic functions.Fixes bug #18240.Reported-by: Alexander LakhinAuthor: Joseph KoshakowDiscussion:https://postgr.es/m/18240-c5da758d7dc1ecf0%40postgresql.orgDiscussion:https://postgr.es/m/CAAvxfHdBPOyEGS7s%2Bxf4iaW0-cgiq25jpYdWBqQqvLtLe_t6tw%40mail.gmail.comBackpatch-through: 12
1 parente2e9928 commitb82791c

File tree

3 files changed

+124
-80
lines changed

3 files changed

+124
-80
lines changed

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

Lines changed: 94 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include"libpq/pqformat.h"
2727
#include"utils/builtins.h"
2828
#include"utils/cash.h"
29+
#include"utils/float.h"
2930
#include"utils/numeric.h"
3031
#include"utils/pg_locale.h"
3132

@@ -86,6 +87,82 @@ num_word(Cash value)
8687
returnbuf;
8788
}/* num_word() */
8889

90+
staticinlineCash
91+
cash_pl_cash(Cashc1,Cashc2)
92+
{
93+
Cashres;
94+
95+
if (unlikely(pg_add_s64_overflow(c1,c2,&res)))
96+
ereport(ERROR,
97+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
98+
errmsg("money out of range")));
99+
100+
returnres;
101+
}
102+
103+
staticinlineCash
104+
cash_mi_cash(Cashc1,Cashc2)
105+
{
106+
Cashres;
107+
108+
if (unlikely(pg_sub_s64_overflow(c1,c2,&res)))
109+
ereport(ERROR,
110+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
111+
errmsg("money out of range")));
112+
113+
returnres;
114+
}
115+
116+
staticinlineCash
117+
cash_mul_float8(Cashc,float8f)
118+
{
119+
float8res=rint(float8_mul((float8)c,f));
120+
121+
if (unlikely(isnan(res)|| !FLOAT8_FITS_IN_INT64(res)))
122+
ereport(ERROR,
123+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
124+
errmsg("money out of range")));
125+
126+
return (Cash)res;
127+
}
128+
129+
staticinlineCash
130+
cash_div_float8(Cashc,float8f)
131+
{
132+
float8res=rint(float8_div((float8)c,f));
133+
134+
if (unlikely(isnan(res)|| !FLOAT8_FITS_IN_INT64(res)))
135+
ereport(ERROR,
136+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
137+
errmsg("money out of range")));
138+
139+
return (Cash)res;
140+
}
141+
142+
staticinlineCash
143+
cash_mul_int64(Cashc,int64i)
144+
{
145+
Cashres;
146+
147+
if (unlikely(pg_mul_s64_overflow(c,i,&res)))
148+
ereport(ERROR,
149+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
150+
errmsg("money out of range")));
151+
152+
returnres;
153+
}
154+
155+
staticinlineCash
156+
cash_div_int64(Cashc,int64i)
157+
{
158+
if (unlikely(i==0))
159+
ereport(ERROR,
160+
(errcode(ERRCODE_DIVISION_BY_ZERO),
161+
errmsg("division by zero")));
162+
163+
returnc /i;
164+
}
165+
89166
/* cash_in()
90167
* Convert a string to a cash data type.
91168
* Format is [$]###[,]###[.##]
@@ -611,11 +688,8 @@ cash_pl(PG_FUNCTION_ARGS)
611688
{
612689
Cashc1=PG_GETARG_CASH(0);
613690
Cashc2=PG_GETARG_CASH(1);
614-
Cashresult;
615-
616-
result=c1+c2;
617691

618-
PG_RETURN_CASH(result);
692+
PG_RETURN_CASH(cash_pl_cash(c1,c2));
619693
}
620694

621695

@@ -627,11 +701,8 @@ cash_mi(PG_FUNCTION_ARGS)
627701
{
628702
Cashc1=PG_GETARG_CASH(0);
629703
Cashc2=PG_GETARG_CASH(1);
630-
Cashresult;
631-
632-
result=c1-c2;
633704

634-
PG_RETURN_CASH(result);
705+
PG_RETURN_CASH(cash_mi_cash(c1,c2));
635706
}
636707

637708

@@ -663,10 +734,8 @@ cash_mul_flt8(PG_FUNCTION_ARGS)
663734
{
664735
Cashc=PG_GETARG_CASH(0);
665736
float8f=PG_GETARG_FLOAT8(1);
666-
Cashresult;
667737

668-
result=rint(c*f);
669-
PG_RETURN_CASH(result);
738+
PG_RETURN_CASH(cash_mul_float8(c,f));
670739
}
671740

672741

@@ -678,10 +747,8 @@ flt8_mul_cash(PG_FUNCTION_ARGS)
678747
{
679748
float8f=PG_GETARG_FLOAT8(0);
680749
Cashc=PG_GETARG_CASH(1);
681-
Cashresult;
682750

683-
result=rint(f*c);
684-
PG_RETURN_CASH(result);
751+
PG_RETURN_CASH(cash_mul_float8(c,f));
685752
}
686753

687754

@@ -693,15 +760,8 @@ cash_div_flt8(PG_FUNCTION_ARGS)
693760
{
694761
Cashc=PG_GETARG_CASH(0);
695762
float8f=PG_GETARG_FLOAT8(1);
696-
Cashresult;
697763

698-
if (f==0.0)
699-
ereport(ERROR,
700-
(errcode(ERRCODE_DIVISION_BY_ZERO),
701-
errmsg("division by zero")));
702-
703-
result=rint(c /f);
704-
PG_RETURN_CASH(result);
764+
PG_RETURN_CASH(cash_div_float8(c,f));
705765
}
706766

707767

@@ -713,10 +773,8 @@ cash_mul_flt4(PG_FUNCTION_ARGS)
713773
{
714774
Cashc=PG_GETARG_CASH(0);
715775
float4f=PG_GETARG_FLOAT4(1);
716-
Cashresult;
717776

718-
result=rint(c* (float8)f);
719-
PG_RETURN_CASH(result);
777+
PG_RETURN_CASH(cash_mul_float8(c, (float8)f));
720778
}
721779

722780

@@ -728,10 +786,8 @@ flt4_mul_cash(PG_FUNCTION_ARGS)
728786
{
729787
float4f=PG_GETARG_FLOAT4(0);
730788
Cashc=PG_GETARG_CASH(1);
731-
Cashresult;
732789

733-
result=rint((float8)f*c);
734-
PG_RETURN_CASH(result);
790+
PG_RETURN_CASH(cash_mul_float8(c, (float8)f));
735791
}
736792

737793

@@ -744,15 +800,8 @@ cash_div_flt4(PG_FUNCTION_ARGS)
744800
{
745801
Cashc=PG_GETARG_CASH(0);
746802
float4f=PG_GETARG_FLOAT4(1);
747-
Cashresult;
748-
749-
if (f==0.0)
750-
ereport(ERROR,
751-
(errcode(ERRCODE_DIVISION_BY_ZERO),
752-
errmsg("division by zero")));
753803

754-
result=rint(c / (float8)f);
755-
PG_RETURN_CASH(result);
804+
PG_RETURN_CASH(cash_div_float8(c, (float8)f));
756805
}
757806

758807

@@ -764,10 +813,8 @@ cash_mul_int8(PG_FUNCTION_ARGS)
764813
{
765814
Cashc=PG_GETARG_CASH(0);
766815
int64i=PG_GETARG_INT64(1);
767-
Cashresult;
768816

769-
result=c*i;
770-
PG_RETURN_CASH(result);
817+
PG_RETURN_CASH(cash_mul_int64(c,i));
771818
}
772819

773820

@@ -779,10 +826,8 @@ int8_mul_cash(PG_FUNCTION_ARGS)
779826
{
780827
int64i=PG_GETARG_INT64(0);
781828
Cashc=PG_GETARG_CASH(1);
782-
Cashresult;
783829

784-
result=i*c;
785-
PG_RETURN_CASH(result);
830+
PG_RETURN_CASH(cash_mul_int64(c,i));
786831
}
787832

788833
/* cash_div_int8()
@@ -793,16 +838,8 @@ cash_div_int8(PG_FUNCTION_ARGS)
793838
{
794839
Cashc=PG_GETARG_CASH(0);
795840
int64i=PG_GETARG_INT64(1);
796-
Cashresult;
797-
798-
if (i==0)
799-
ereport(ERROR,
800-
(errcode(ERRCODE_DIVISION_BY_ZERO),
801-
errmsg("division by zero")));
802841

803-
result=c /i;
804-
805-
PG_RETURN_CASH(result);
842+
PG_RETURN_CASH(cash_div_int64(c,i));
806843
}
807844

808845

@@ -814,10 +851,8 @@ cash_mul_int4(PG_FUNCTION_ARGS)
814851
{
815852
Cashc=PG_GETARG_CASH(0);
816853
int32i=PG_GETARG_INT32(1);
817-
Cashresult;
818854

819-
result=c*i;
820-
PG_RETURN_CASH(result);
855+
PG_RETURN_CASH(cash_mul_int64(c, (int64)i));
821856
}
822857

823858

@@ -829,10 +864,8 @@ int4_mul_cash(PG_FUNCTION_ARGS)
829864
{
830865
int32i=PG_GETARG_INT32(0);
831866
Cashc=PG_GETARG_CASH(1);
832-
Cashresult;
833867

834-
result=i*c;
835-
PG_RETURN_CASH(result);
868+
PG_RETURN_CASH(cash_mul_int64(c, (int64)i));
836869
}
837870

838871

@@ -845,16 +878,8 @@ cash_div_int4(PG_FUNCTION_ARGS)
845878
{
846879
Cashc=PG_GETARG_CASH(0);
847880
int32i=PG_GETARG_INT32(1);
848-
Cashresult;
849-
850-
if (i==0)
851-
ereport(ERROR,
852-
(errcode(ERRCODE_DIVISION_BY_ZERO),
853-
errmsg("division by zero")));
854-
855-
result=c /i;
856881

857-
PG_RETURN_CASH(result);
882+
PG_RETURN_CASH(cash_div_int64(c, (int64)i));
858883
}
859884

860885

@@ -866,10 +891,8 @@ cash_mul_int2(PG_FUNCTION_ARGS)
866891
{
867892
Cashc=PG_GETARG_CASH(0);
868893
int16s=PG_GETARG_INT16(1);
869-
Cashresult;
870894

871-
result=c*s;
872-
PG_RETURN_CASH(result);
895+
PG_RETURN_CASH(cash_mul_int64(c, (int64)s));
873896
}
874897

875898
/* int2_mul_cash()
@@ -880,10 +903,8 @@ int2_mul_cash(PG_FUNCTION_ARGS)
880903
{
881904
int16s=PG_GETARG_INT16(0);
882905
Cashc=PG_GETARG_CASH(1);
883-
Cashresult;
884906

885-
result=s*c;
886-
PG_RETURN_CASH(result);
907+
PG_RETURN_CASH(cash_mul_int64(c, (int64)s));
887908
}
888909

889910
/* cash_div_int2()
@@ -895,15 +916,8 @@ cash_div_int2(PG_FUNCTION_ARGS)
895916
{
896917
Cashc=PG_GETARG_CASH(0);
897918
int16s=PG_GETARG_INT16(1);
898-
Cashresult;
899919

900-
if (s==0)
901-
ereport(ERROR,
902-
(errcode(ERRCODE_DIVISION_BY_ZERO),
903-
errmsg("division by zero")));
904-
905-
result=c /s;
906-
PG_RETURN_CASH(result);
920+
PG_RETURN_CASH(cash_div_int64(c, (int64)s));
907921
}
908922

909923
/* cashlarger()

‎src/test/regress/expected/money.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,3 +503,22 @@ SELECT '-92233720368547758.08'::money::numeric;
503503
-92233720368547758.08
504504
(1 row)
505505

506+
-- overflow checks
507+
SELECT '92233720368547758.07'::money + '0.01'::money;
508+
ERROR: money out of range
509+
SELECT '-92233720368547758.08'::money - '0.01'::money;
510+
ERROR: money out of range
511+
SELECT '92233720368547758.07'::money * 2::float8;
512+
ERROR: money out of range
513+
SELECT '-1'::money / 1.175494e-38::float4;
514+
ERROR: money out of range
515+
SELECT '92233720368547758.07'::money * 2::int4;
516+
ERROR: money out of range
517+
SELECT '1'::money / 0::int2;
518+
ERROR: division by zero
519+
SELECT '42'::money * 'inf'::float8;
520+
ERROR: money out of range
521+
SELECT '42'::money * '-inf'::float8;
522+
ERROR: money out of range
523+
SELECT '42'::money * 'nan'::float4;
524+
ERROR: money out of range

‎src/test/regress/sql/money.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,14 @@ SELECT '12345678901234567'::money::numeric;
129129
SELECT'-12345678901234567'::money::numeric;
130130
SELECT'92233720368547758.07'::money::numeric;
131131
SELECT'-92233720368547758.08'::money::numeric;
132+
133+
-- overflow checks
134+
SELECT'92233720368547758.07'::money+'0.01'::money;
135+
SELECT'-92233720368547758.08'::money-'0.01'::money;
136+
SELECT'92233720368547758.07'::money*2::float8;
137+
SELECT'-1'::money/1.175494e-38::float4;
138+
SELECT'92233720368547758.07'::money*2::int4;
139+
SELECT'1'::money/0::int2;
140+
SELECT'42'::money*'inf'::float8;
141+
SELECT'42'::money*'-inf'::float8;
142+
SELECT'42'::money*'nan'::float4;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp