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

Commit25cd2d6

Browse files
committed
Detect Julian-date overflow in timestamp[tz]_pl_interval.
We perform addition of the days field of an interval viaarithmetic on the Julian-date representation of the timestamp's date.This step is subject to int32 overflow, and we also should not letthe Julian date become very negative, for fear of weird results fromj2date. (In the timestamptz case, allow a Julian date of -1 to pass,since it might convert back to zero after timezone rotation.)The additions of the months and microseconds fields could alsooverflow, of course. However, I believe we need no additionalchecks there; the existing range checks should catch such cases.The difficulty here is that j2date's magic modular arithmetic couldproduce something that looks like it's in-range.Per bug #18313 from Christian Maurer. This has been wrong fora long time, so back-patch to all supported branches.Discussion:https://postgr.es/m/18313-64d2c8952d81e84b@postgresql.org
1 parent5ddf997 commit25cd2d6

File tree

3 files changed

+29
-4
lines changed

3 files changed

+29
-4
lines changed

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3120,8 +3120,16 @@ timestamp_pl_interval(PG_FUNCTION_ARGS)
31203120
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
31213121
errmsg("timestamp out of range")));
31223122

3123-
/* Add days by converting to and from Julian */
3124-
julian=date2j(tm->tm_year,tm->tm_mon,tm->tm_mday)+span->day;
3123+
/*
3124+
* Add days by converting to and from Julian. We need an overflow
3125+
* check here since j2date expects a non-negative integer input.
3126+
*/
3127+
julian=date2j(tm->tm_year,tm->tm_mon,tm->tm_mday);
3128+
if (pg_add_s32_overflow(julian,span->day,&julian)||
3129+
julian<0)
3130+
ereport(ERROR,
3131+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3132+
errmsg("timestamp out of range")));
31253133
j2date(julian,&tm->tm_year,&tm->tm_mon,&tm->tm_mday);
31263134

31273135
if (tm2timestamp(tm,fsec,NULL,&timestamp)!=0)
@@ -3256,8 +3264,19 @@ timestamptz_pl_interval_internal(TimestampTz timestamp,
32563264
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
32573265
errmsg("timestamp out of range")));
32583266

3259-
/* Add days by converting to and from Julian */
3260-
julian=date2j(tm->tm_year,tm->tm_mon,tm->tm_mday)+span->day;
3267+
/*
3268+
* Add days by converting to and from Julian. We need an overflow
3269+
* check here since j2date expects a non-negative integer input.
3270+
* In practice though, it will give correct answers for small
3271+
* negative Julian dates; we should allow -1 to avoid
3272+
* timezone-dependent failures, as discussed in timestamp.h.
3273+
*/
3274+
julian=date2j(tm->tm_year,tm->tm_mon,tm->tm_mday);
3275+
if (pg_add_s32_overflow(julian,span->day,&julian)||
3276+
julian<-1)
3277+
ereport(ERROR,
3278+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3279+
errmsg("timestamp out of range")));
32613280
j2date(julian,&tm->tm_year,&tm->tm_mon,&tm->tm_mday);
32623281

32633282
tz=DetermineTimeZoneOffset(tm,attimezone);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,8 @@ SELECT timestamp without time zone 'Jan 1, 4713 BC' + interval '109203489 days'
482482
Sun Dec 31 00:00:00 294276
483483
(1 row)
484484

485+
SELECT timestamp without time zone '2000-01-01' - interval '2483590 days' AS "out of range";
486+
ERROR: timestamp out of range
485487
SELECT timestamp without time zone '12/31/294276' - timestamp without time zone '12/23/1999' AS "106751991 Days";
486488
106751991 Days
487489
------------------
@@ -742,6 +744,8 @@ SELECT timestamp with time zone '1999-12-01' + interval '1 month - 1 second' AS
742744
Fri Dec 31 23:59:59 1999 PST
743745
(1 row)
744746

747+
SELECT timestamp with time zone '2000-01-01' - interval '2483590 days' AS "out of range";
748+
ERROR: timestamp out of range
745749
SELECT (timestamp with time zone 'today' = (timestamp with time zone 'yesterday' + interval '1 day')) as "True";
746750
True
747751
------

‎src/test/regress/sql/horology.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ SELECT timestamp without time zone '1999-12-01' + interval '1 month - 1 second'
120120
SELECTtimestamp without time zone'Jan 1, 4713 BC'+ interval'106000000 days'AS"Feb 23, 285506";
121121
SELECTtimestamp without time zone'Jan 1, 4713 BC'+ interval'107000000 days'AS"Jan 20, 288244";
122122
SELECTtimestamp without time zone'Jan 1, 4713 BC'+ interval'109203489 days'AS"Dec 31, 294276";
123+
SELECTtimestamp without time zone'2000-01-01'- interval'2483590 days'AS"out of range";
123124
SELECTtimestamp without time zone'12/31/294276'-timestamp without time zone'12/23/1999'AS"106751991 Days";
124125

125126
-- Shorthand values
@@ -151,6 +152,7 @@ SELECT timestamp with time zone '1996-03-01' - interval '1 second' AS "Feb 29";
151152
SELECTtimestamp with time zone'1999-03-01'- interval'1 second'AS"Feb 28";
152153
SELECTtimestamp with time zone'2000-03-01'- interval'1 second'AS"Feb 29";
153154
SELECTtimestamp with time zone'1999-12-01'+ interval'1 month - 1 second'AS"Dec 31";
155+
SELECTtimestamp with time zone'2000-01-01'- interval'2483590 days'AS"out of range";
154156

155157
SELECT (timestamp with time zone'today'= (timestamp with time zone'yesterday'+ interval'1 day'))as"True";
156158
SELECT (timestamp with time zone'today'= (timestamp with time zone'tomorrow'- interval'1 day'))as"True";

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp