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

Commit22b0ccd

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 parentaa60798 commit22b0ccd

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 [$]###[,]###[.##]
@@ -612,11 +689,8 @@ cash_pl(PG_FUNCTION_ARGS)
612689
{
613690
Cashc1=PG_GETARG_CASH(0);
614691
Cashc2=PG_GETARG_CASH(1);
615-
Cashresult;
616-
617-
result=c1+c2;
618692

619-
PG_RETURN_CASH(result);
693+
PG_RETURN_CASH(cash_pl_cash(c1,c2));
620694
}
621695

622696

@@ -628,11 +702,8 @@ cash_mi(PG_FUNCTION_ARGS)
628702
{
629703
Cashc1=PG_GETARG_CASH(0);
630704
Cashc2=PG_GETARG_CASH(1);
631-
Cashresult;
632-
633-
result=c1-c2;
634705

635-
PG_RETURN_CASH(result);
706+
PG_RETURN_CASH(cash_mi_cash(c1,c2));
636707
}
637708

638709

@@ -664,10 +735,8 @@ cash_mul_flt8(PG_FUNCTION_ARGS)
664735
{
665736
Cashc=PG_GETARG_CASH(0);
666737
float8f=PG_GETARG_FLOAT8(1);
667-
Cashresult;
668738

669-
result=rint(c*f);
670-
PG_RETURN_CASH(result);
739+
PG_RETURN_CASH(cash_mul_float8(c,f));
671740
}
672741

673742

@@ -679,10 +748,8 @@ flt8_mul_cash(PG_FUNCTION_ARGS)
679748
{
680749
float8f=PG_GETARG_FLOAT8(0);
681750
Cashc=PG_GETARG_CASH(1);
682-
Cashresult;
683751

684-
result=rint(f*c);
685-
PG_RETURN_CASH(result);
752+
PG_RETURN_CASH(cash_mul_float8(c,f));
686753
}
687754

688755

@@ -694,15 +761,8 @@ cash_div_flt8(PG_FUNCTION_ARGS)
694761
{
695762
Cashc=PG_GETARG_CASH(0);
696763
float8f=PG_GETARG_FLOAT8(1);
697-
Cashresult;
698764

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

708768

@@ -714,10 +774,8 @@ cash_mul_flt4(PG_FUNCTION_ARGS)
714774
{
715775
Cashc=PG_GETARG_CASH(0);
716776
float4f=PG_GETARG_FLOAT4(1);
717-
Cashresult;
718777

719-
result=rint(c* (float8)f);
720-
PG_RETURN_CASH(result);
778+
PG_RETURN_CASH(cash_mul_float8(c, (float8)f));
721779
}
722780

723781

@@ -729,10 +787,8 @@ flt4_mul_cash(PG_FUNCTION_ARGS)
729787
{
730788
float4f=PG_GETARG_FLOAT4(0);
731789
Cashc=PG_GETARG_CASH(1);
732-
Cashresult;
733790

734-
result=rint((float8)f*c);
735-
PG_RETURN_CASH(result);
791+
PG_RETURN_CASH(cash_mul_float8(c, (float8)f));
736792
}
737793

738794

@@ -745,15 +801,8 @@ cash_div_flt4(PG_FUNCTION_ARGS)
745801
{
746802
Cashc=PG_GETARG_CASH(0);
747803
float4f=PG_GETARG_FLOAT4(1);
748-
Cashresult;
749-
750-
if (f==0.0)
751-
ereport(ERROR,
752-
(errcode(ERRCODE_DIVISION_BY_ZERO),
753-
errmsg("division by zero")));
754804

755-
result=rint(c / (float8)f);
756-
PG_RETURN_CASH(result);
805+
PG_RETURN_CASH(cash_div_float8(c, (float8)f));
757806
}
758807

759808

@@ -765,10 +814,8 @@ cash_mul_int8(PG_FUNCTION_ARGS)
765814
{
766815
Cashc=PG_GETARG_CASH(0);
767816
int64i=PG_GETARG_INT64(1);
768-
Cashresult;
769817

770-
result=c*i;
771-
PG_RETURN_CASH(result);
818+
PG_RETURN_CASH(cash_mul_int64(c,i));
772819
}
773820

774821

@@ -780,10 +827,8 @@ int8_mul_cash(PG_FUNCTION_ARGS)
780827
{
781828
int64i=PG_GETARG_INT64(0);
782829
Cashc=PG_GETARG_CASH(1);
783-
Cashresult;
784830

785-
result=i*c;
786-
PG_RETURN_CASH(result);
831+
PG_RETURN_CASH(cash_mul_int64(c,i));
787832
}
788833

789834
/* cash_div_int8()
@@ -794,16 +839,8 @@ cash_div_int8(PG_FUNCTION_ARGS)
794839
{
795840
Cashc=PG_GETARG_CASH(0);
796841
int64i=PG_GETARG_INT64(1);
797-
Cashresult;
798-
799-
if (i==0)
800-
ereport(ERROR,
801-
(errcode(ERRCODE_DIVISION_BY_ZERO),
802-
errmsg("division by zero")));
803842

804-
result=c /i;
805-
806-
PG_RETURN_CASH(result);
843+
PG_RETURN_CASH(cash_div_int64(c,i));
807844
}
808845

809846

@@ -815,10 +852,8 @@ cash_mul_int4(PG_FUNCTION_ARGS)
815852
{
816853
Cashc=PG_GETARG_CASH(0);
817854
int32i=PG_GETARG_INT32(1);
818-
Cashresult;
819855

820-
result=c*i;
821-
PG_RETURN_CASH(result);
856+
PG_RETURN_CASH(cash_mul_int64(c, (int64)i));
822857
}
823858

824859

@@ -830,10 +865,8 @@ int4_mul_cash(PG_FUNCTION_ARGS)
830865
{
831866
int32i=PG_GETARG_INT32(0);
832867
Cashc=PG_GETARG_CASH(1);
833-
Cashresult;
834868

835-
result=i*c;
836-
PG_RETURN_CASH(result);
869+
PG_RETURN_CASH(cash_mul_int64(c, (int64)i));
837870
}
838871

839872

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

858-
PG_RETURN_CASH(result);
883+
PG_RETURN_CASH(cash_div_int64(c, (int64)i));
859884
}
860885

861886

@@ -867,10 +892,8 @@ cash_mul_int2(PG_FUNCTION_ARGS)
867892
{
868893
Cashc=PG_GETARG_CASH(0);
869894
int16s=PG_GETARG_INT16(1);
870-
Cashresult;
871895

872-
result=c*s;
873-
PG_RETURN_CASH(result);
896+
PG_RETURN_CASH(cash_mul_int64(c, (int64)s));
874897
}
875898

876899
/* int2_mul_cash()
@@ -881,10 +904,8 @@ int2_mul_cash(PG_FUNCTION_ARGS)
881904
{
882905
int16s=PG_GETARG_INT16(0);
883906
Cashc=PG_GETARG_CASH(1);
884-
Cashresult;
885907

886-
result=s*c;
887-
PG_RETURN_CASH(result);
908+
PG_RETURN_CASH(cash_mul_int64(c, (int64)s));
888909
}
889910

890911
/* cash_div_int2()
@@ -896,15 +917,8 @@ cash_div_int2(PG_FUNCTION_ARGS)
896917
{
897918
Cashc=PG_GETARG_CASH(0);
898919
int16s=PG_GETARG_INT16(1);
899-
Cashresult;
900920

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

910924
/* cashlarger()

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,3 +528,22 @@ SELECT '-92233720368547758.08'::money::numeric;
528528
-92233720368547758.08
529529
(1 row)
530530

531+
-- overflow checks
532+
SELECT '92233720368547758.07'::money + '0.01'::money;
533+
ERROR: money out of range
534+
SELECT '-92233720368547758.08'::money - '0.01'::money;
535+
ERROR: money out of range
536+
SELECT '92233720368547758.07'::money * 2::float8;
537+
ERROR: money out of range
538+
SELECT '-1'::money / 1.175494e-38::float4;
539+
ERROR: money out of range
540+
SELECT '92233720368547758.07'::money * 2::int4;
541+
ERROR: money out of range
542+
SELECT '1'::money / 0::int2;
543+
ERROR: division by zero
544+
SELECT '42'::money * 'inf'::float8;
545+
ERROR: money out of range
546+
SELECT '42'::money * '-inf'::float8;
547+
ERROR: money out of range
548+
SELECT '42'::money * 'nan'::float4;
549+
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
@@ -135,3 +135,14 @@ SELECT '12345678901234567'::money::numeric;
135135
SELECT'-12345678901234567'::money::numeric;
136136
SELECT'92233720368547758.07'::money::numeric;
137137
SELECT'-92233720368547758.08'::money::numeric;
138+
139+
-- overflow checks
140+
SELECT'92233720368547758.07'::money+'0.01'::money;
141+
SELECT'-92233720368547758.08'::money-'0.01'::money;
142+
SELECT'92233720368547758.07'::money*2::float8;
143+
SELECT'-1'::money/1.175494e-38::float4;
144+
SELECT'92233720368547758.07'::money*2::int4;
145+
SELECT'1'::money/0::int2;
146+
SELECT'42'::money*'inf'::float8;
147+
SELECT'42'::money*'-inf'::float8;
148+
SELECT'42'::money*'nan'::float4;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp