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

Commit54bd1e4

Browse files
committed
Handle integer overflow in interval justification functions.
justify_interval, justify_hours, and justify_days didn't check foroverflow when promoting hours to days or days to months; but that'spossible when the upper field's value is already large. Detect andreport any such overflow.Also, we can avoid unnecessary overflow in some cases in justify_intervalby pre-justifying the days field. (Thanks to Nathan Bossart for thisidea.)Joe KoshakowDiscussion:https://postgr.es/m/CAAvxfHeNqsJ2xYFbPUf_8nNQUiJqkag04NW6aBQQ0dbZsxfWHA@mail.gmail.com
1 parenta59c795 commit54bd1e4

File tree

3 files changed

+79
-4
lines changed

3 files changed

+79
-4
lines changed

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

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2717,12 +2717,33 @@ interval_justify_interval(PG_FUNCTION_ARGS)
27172717
result->day=span->day;
27182718
result->time=span->time;
27192719

2720+
/* pre-justify days if it might prevent overflow */
2721+
if ((result->day>0&&result->time>0)||
2722+
(result->day<0&&result->time<0))
2723+
{
2724+
wholemonth=result->day /DAYS_PER_MONTH;
2725+
result->day-=wholemonth*DAYS_PER_MONTH;
2726+
if (pg_add_s32_overflow(result->month,wholemonth,&result->month))
2727+
ereport(ERROR,
2728+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2729+
errmsg("interval out of range")));
2730+
}
2731+
2732+
/*
2733+
* Since TimeOffset is int64, abs(wholeday) can't exceed about 1.07e8. If
2734+
* we pre-justified then abs(result->day) is less than DAYS_PER_MONTH, so
2735+
* this addition can't overflow. If we didn't pre-justify, then day and
2736+
* time are of different signs, so it still can't overflow.
2737+
*/
27202738
TMODULO(result->time,wholeday,USECS_PER_DAY);
2721-
result->day+=wholeday;/* could overflow... */
2739+
result->day+=wholeday;
27222740

27232741
wholemonth=result->day /DAYS_PER_MONTH;
27242742
result->day-=wholemonth*DAYS_PER_MONTH;
2725-
result->month+=wholemonth;
2743+
if (pg_add_s32_overflow(result->month,wholemonth,&result->month))
2744+
ereport(ERROR,
2745+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2746+
errmsg("interval out of range")));
27262747

27272748
if (result->month>0&&
27282749
(result->day<0|| (result->day==0&&result->time<0)))
@@ -2772,7 +2793,10 @@ interval_justify_hours(PG_FUNCTION_ARGS)
27722793
result->time=span->time;
27732794

27742795
TMODULO(result->time,wholeday,USECS_PER_DAY);
2775-
result->day+=wholeday;/* could overflow... */
2796+
if (pg_add_s32_overflow(result->day,wholeday,&result->day))
2797+
ereport(ERROR,
2798+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2799+
errmsg("interval out of range")));
27762800

27772801
if (result->day>0&&result->time<0)
27782802
{
@@ -2808,7 +2832,10 @@ interval_justify_days(PG_FUNCTION_ARGS)
28082832

28092833
wholemonth=result->day /DAYS_PER_MONTH;
28102834
result->day-=wholemonth*DAYS_PER_MONTH;
2811-
result->month+=wholemonth;
2835+
if (pg_add_s32_overflow(result->month,wholemonth,&result->month))
2836+
ereport(ERROR,
2837+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2838+
errmsg("interval out of range")));
28122839

28132840
if (result->month>0&&result->day<0)
28142841
{

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,13 +396,49 @@ SELECT justify_days(interval '6 months 36 days 5 hours 4 minutes 3 seconds') as
396396
@ 7 mons 6 days 5 hours 4 mins 3 secs
397397
(1 row)
398398

399+
SELECT justify_hours(interval '2147483647 days 24 hrs');
400+
ERROR: interval out of range
401+
SELECT justify_days(interval '2147483647 months 30 days');
402+
ERROR: interval out of range
399403
-- test justify_interval()
400404
SELECT justify_interval(interval '1 month -1 hour') as "1 month -1 hour";
401405
1 month -1 hour
402406
--------------------
403407
@ 29 days 23 hours
404408
(1 row)
405409

410+
SELECT justify_interval(interval '2147483647 days 24 hrs');
411+
justify_interval
412+
-------------------------------
413+
@ 5965232 years 4 mons 8 days
414+
(1 row)
415+
416+
SELECT justify_interval(interval '-2147483648 days -24 hrs');
417+
justify_interval
418+
-----------------------------------
419+
@ 5965232 years 4 mons 9 days ago
420+
(1 row)
421+
422+
SELECT justify_interval(interval '2147483647 months 30 days');
423+
ERROR: interval out of range
424+
SELECT justify_interval(interval '-2147483648 months -30 days');
425+
ERROR: interval out of range
426+
SELECT justify_interval(interval '2147483647 months 30 days -24 hrs');
427+
justify_interval
428+
----------------------------------
429+
@ 178956970 years 7 mons 29 days
430+
(1 row)
431+
432+
SELECT justify_interval(interval '-2147483648 months -30 days 24 hrs');
433+
justify_interval
434+
--------------------------------------
435+
@ 178956970 years 8 mons 29 days ago
436+
(1 row)
437+
438+
SELECT justify_interval(interval '2147483647 months -30 days 1440 hrs');
439+
ERROR: interval out of range
440+
SELECT justify_interval(interval '-2147483648 months 30 days -1440 hrs');
441+
ERROR: interval out of range
406442
-- test fractional second input, and detection of duplicate units
407443
SET DATESTYLE = 'ISO';
408444
SET IntervalStyle TO postgres;

‎src/test/regress/sql/interval.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,22 @@ select '100000000y 10mon -1000000000d -100000h -10min -10.000001s ago'::interval
149149
SELECT justify_hours(interval'6 months 3 days 52 hours 3 minutes 2 seconds')as"6 mons 5 days 4 hours 3 mins 2 seconds";
150150
SELECT justify_days(interval'6 months 36 days 5 hours 4 minutes 3 seconds')as"7 mons 6 days 5 hours 4 mins 3 seconds";
151151

152+
SELECT justify_hours(interval'2147483647 days 24 hrs');
153+
SELECT justify_days(interval'2147483647 months 30 days');
154+
152155
-- test justify_interval()
153156

154157
SELECT justify_interval(interval'1 month -1 hour')as"1 month -1 hour";
155158

159+
SELECT justify_interval(interval'2147483647 days 24 hrs');
160+
SELECT justify_interval(interval'-2147483648 days -24 hrs');
161+
SELECT justify_interval(interval'2147483647 months 30 days');
162+
SELECT justify_interval(interval'-2147483648 months -30 days');
163+
SELECT justify_interval(interval'2147483647 months 30 days -24 hrs');
164+
SELECT justify_interval(interval'-2147483648 months -30 days 24 hrs');
165+
SELECT justify_interval(interval'2147483647 months -30 days 1440 hrs');
166+
SELECT justify_interval(interval'-2147483648 months 30 days -1440 hrs');
167+
156168
-- test fractional second input, and detection of duplicate units
157169
SET DATESTYLE='ISO';
158170
SET IntervalStyle TO postgres;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp