Disallow infinite endpoints in generate_series() for timestamps.
authorTom Lane
Wed, 20 Apr 2022 22:08:15 +0000 (18:08 -0400)
committerTom Lane
Wed, 20 Apr 2022 22:08:23 +0000 (18:08 -0400)
Such cases will lead to infinite loops, so they're of no practical
value.  The numeric variant of generate_series() already threw error
for this, so borrow its message wording.

Per report from Richard Wesley.  Back-patch to all supported branches.

Discussion: https://postgr.es/m/91B44E7B-68D5-448F-95C8-B4B3B0F5DEAF@duckdblabs.com

src/backend/utils/adt/timestamp.c
src/test/regress/expected/timestamp.out
src/test/regress/expected/timestamptz.out
src/test/regress/sql/timestamp.sql
src/test/regress/sql/timestamptz.sql

index 552b631ba784e04a6f608b9c8406475e7930785d..93c10e1ae41a89f4fe28807f8778967b4d55e2b9 100644 (file)
@@ -5778,6 +5778,20 @@ generate_series_timestamp(PG_FUNCTION_ARGS)
        MemoryContext oldcontext;
        Interval    interval_zero;
 
+       /* Reject infinities in start and stop values */
+       if (TIMESTAMP_IS_NOBEGIN(start) ||
+           TIMESTAMP_IS_NOEND(start))
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("start value cannot be infinity")));
+       if (TIMESTAMP_IS_NOBEGIN(finish) ||
+           TIMESTAMP_IS_NOEND(finish))
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("stop value cannot be infinity")));
+
+       /* Interval doesn't (currently) have infinity, so nothing to check */
+
        /* create a function context for cross-call persistence */
        funcctx = SRF_FIRSTCALL_INIT();
 
@@ -5858,6 +5872,20 @@ generate_series_timestamptz(PG_FUNCTION_ARGS)
        MemoryContext oldcontext;
        Interval    interval_zero;
 
+       /* Reject infinities in start and stop values */
+       if (TIMESTAMP_IS_NOBEGIN(start) ||
+           TIMESTAMP_IS_NOEND(start))
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("start value cannot be infinity")));
+       if (TIMESTAMP_IS_NOBEGIN(finish) ||
+           TIMESTAMP_IS_NOEND(finish))
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("stop value cannot be infinity")));
+
+       /* Interval doesn't (currently) have infinity, so nothing to check */
+
        /* create a function context for cross-call persistence */
        funcctx = SRF_FIRSTCALL_INIT();
 
index 1a2d48cae96762ff6520df049db6af8f52d797a7..d5ca6b76a439344618f69eed9ce3caab2b5a1416 100644 (file)
@@ -2019,3 +2019,52 @@ SELECT make_timestamp(-44, 3, 15, 12, 30, 15);
 -- should fail
 select make_timestamp(0, 7, 15, 12, 30, 15);
 ERROR:  date field value out of range: 0-07-15
+-- generate_series for timestamp
+select * from generate_series('2020-01-01 00:00'::timestamp,
+                              '2020-01-02 03:00'::timestamp,
+                              '1 hour'::interval);
+     generate_series      
+--------------------------
+ Wed Jan 01 00:00:00 2020
+ Wed Jan 01 01:00:00 2020
+ Wed Jan 01 02:00:00 2020
+ Wed Jan 01 03:00:00 2020
+ Wed Jan 01 04:00:00 2020
+ Wed Jan 01 05:00:00 2020
+ Wed Jan 01 06:00:00 2020
+ Wed Jan 01 07:00:00 2020
+ Wed Jan 01 08:00:00 2020
+ Wed Jan 01 09:00:00 2020
+ Wed Jan 01 10:00:00 2020
+ Wed Jan 01 11:00:00 2020
+ Wed Jan 01 12:00:00 2020
+ Wed Jan 01 13:00:00 2020
+ Wed Jan 01 14:00:00 2020
+ Wed Jan 01 15:00:00 2020
+ Wed Jan 01 16:00:00 2020
+ Wed Jan 01 17:00:00 2020
+ Wed Jan 01 18:00:00 2020
+ Wed Jan 01 19:00:00 2020
+ Wed Jan 01 20:00:00 2020
+ Wed Jan 01 21:00:00 2020
+ Wed Jan 01 22:00:00 2020
+ Wed Jan 01 23:00:00 2020
+ Thu Jan 02 00:00:00 2020
+ Thu Jan 02 01:00:00 2020
+ Thu Jan 02 02:00:00 2020
+ Thu Jan 02 03:00:00 2020
+(28 rows)
+
+-- errors
+select * from generate_series('-infinity'::timestamp,
+                              '2020-01-02 03:00'::timestamp,
+                              '1 hour'::interval);
+ERROR:  start value cannot be infinity
+select * from generate_series('2020-01-01 00:00'::timestamp,
+                              'infinity'::timestamp,
+                              '1 hour'::interval);
+ERROR:  stop value cannot be infinity
+select * from generate_series('2020-01-01 00:00'::timestamp,
+                              '2020-01-02 03:00'::timestamp,
+                              '0 hour'::interval);
+ERROR:  step size cannot equal zero
index d402802db0dbc8ee9f7d5feeac317977bcebba0a..4a29484ec3630a7f3b7aa26487e3f902f2de200b 100644 (file)
@@ -2362,6 +2362,55 @@ SELECT make_timestamptz(2014, 12, 10, 10, 10, 10, 'PST8PDT');
 (1 row)
 
 RESET TimeZone;
+-- generate_series for timestamptz
+select * from generate_series('2020-01-01 00:00'::timestamptz,
+                              '2020-01-02 03:00'::timestamptz,
+                              '1 hour'::interval);
+       generate_series        
+------------------------------
+ Wed Jan 01 00:00:00 2020 PST
+ Wed Jan 01 01:00:00 2020 PST
+ Wed Jan 01 02:00:00 2020 PST
+ Wed Jan 01 03:00:00 2020 PST
+ Wed Jan 01 04:00:00 2020 PST
+ Wed Jan 01 05:00:00 2020 PST
+ Wed Jan 01 06:00:00 2020 PST
+ Wed Jan 01 07:00:00 2020 PST
+ Wed Jan 01 08:00:00 2020 PST
+ Wed Jan 01 09:00:00 2020 PST
+ Wed Jan 01 10:00:00 2020 PST
+ Wed Jan 01 11:00:00 2020 PST
+ Wed Jan 01 12:00:00 2020 PST
+ Wed Jan 01 13:00:00 2020 PST
+ Wed Jan 01 14:00:00 2020 PST
+ Wed Jan 01 15:00:00 2020 PST
+ Wed Jan 01 16:00:00 2020 PST
+ Wed Jan 01 17:00:00 2020 PST
+ Wed Jan 01 18:00:00 2020 PST
+ Wed Jan 01 19:00:00 2020 PST
+ Wed Jan 01 20:00:00 2020 PST
+ Wed Jan 01 21:00:00 2020 PST
+ Wed Jan 01 22:00:00 2020 PST
+ Wed Jan 01 23:00:00 2020 PST
+ Thu Jan 02 00:00:00 2020 PST
+ Thu Jan 02 01:00:00 2020 PST
+ Thu Jan 02 02:00:00 2020 PST
+ Thu Jan 02 03:00:00 2020 PST
+(28 rows)
+
+-- errors
+select * from generate_series('-infinity'::timestamptz,
+                              '2020-01-02 03:00'::timestamptz,
+                              '1 hour'::interval);
+ERROR:  start value cannot be infinity
+select * from generate_series('2020-01-01 00:00'::timestamptz,
+                              'infinity'::timestamptz,
+                              '1 hour'::interval);
+ERROR:  stop value cannot be infinity
+select * from generate_series('2020-01-01 00:00'::timestamptz,
+                              '2020-01-02 03:00'::timestamptz,
+                              '0 hour'::interval);
+ERROR:  step size cannot equal zero
 --
 -- Test behavior with a dynamic (time-varying) timezone abbreviation.
 -- These tests rely on the knowledge that MSK (Europe/Moscow standard time)
index e011e779ea2da20393f624505ad6dea7f9582438..0778e5d7c0c686a78212decd8d8a2ed001c31393 100644 (file)
@@ -370,3 +370,18 @@ SELECT make_timestamp(2014, 12, 28, 6, 30, 45.887);
 SELECT make_timestamp(-44, 3, 15, 12, 30, 15);
 -- should fail
 select make_timestamp(0, 7, 15, 12, 30, 15);
+
+-- generate_series for timestamp
+select * from generate_series('2020-01-01 00:00'::timestamp,
+                              '2020-01-02 03:00'::timestamp,
+                              '1 hour'::interval);
+-- errors
+select * from generate_series('-infinity'::timestamp,
+                              '2020-01-02 03:00'::timestamp,
+                              '1 hour'::interval);
+select * from generate_series('2020-01-01 00:00'::timestamp,
+                              'infinity'::timestamp,
+                              '1 hour'::interval);
+select * from generate_series('2020-01-01 00:00'::timestamp,
+                              '2020-01-02 03:00'::timestamp,
+                              '0 hour'::interval);
index 7cd2420b080598c02a3c44033a2a151423364eb9..c1643de0f1d237d2dd70a73d63d56d51705e1a38 100644 (file)
@@ -432,6 +432,21 @@ SELECT make_timestamptz(2014, 12, 10, 10, 10, 10, 'PST8PDT');
 
 RESET TimeZone;
 
+-- generate_series for timestamptz
+select * from generate_series('2020-01-01 00:00'::timestamptz,
+                              '2020-01-02 03:00'::timestamptz,
+                              '1 hour'::interval);
+-- errors
+select * from generate_series('-infinity'::timestamptz,
+                              '2020-01-02 03:00'::timestamptz,
+                              '1 hour'::interval);
+select * from generate_series('2020-01-01 00:00'::timestamptz,
+                              'infinity'::timestamptz,
+                              '1 hour'::interval);
+select * from generate_series('2020-01-01 00:00'::timestamptz,
+                              '2020-01-02 03:00'::timestamptz,
+                              '0 hour'::interval);
+
 --
 -- Test behavior with a dynamic (time-varying) timezone abbreviation.
 -- These tests rely on the knowledge that MSK (Europe/Moscow standard time)