From 8d2ddd6e0cd71e5054219d6ad7629ef715ed4ba4 Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
Date: Wed, 13 Sep 2023 12:43:49 +0530
Subject: [PATCH v27 3/8] Introduce 'infinity' interval specification in
 DecodeInterval()

This reverts commit d6d1430f404386162831bc32906ad174b2007776 since
RESERVE is required to support infinite intervals. 'infinity' is saved
as a RESERVE in datetktbl[], thus required to parse
'infinity'::interval.

Infinte interval specification i.e. "+infinity", "-infinity" or
"infinity" does not require anything other that one of the three
strings. Fix DecodeInterval() to disallow anything else.

"ago" may be used to revrse the sign of infinity specification like how
ago reverts the sign of finite intervals. But that is not as intuitive
as it is with finite intervals. Hence disallows "infinity ago" as well.

Ashutosh Bapat
---
 src/backend/utils/adt/datetime.c       | 24 ++++++++++++++++
 src/test/regress/expected/interval.out | 39 ++++++++++++++++++++++++++
 src/test/regress/sql/interval.sql      | 14 +++++++++
 3 files changed, 77 insertions(+)

diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index ea2bc65f50..73dadb747c 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -3271,6 +3271,9 @@ ClearPgItmIn(struct pg_itm_in *itm_in)
  *
  * Allow ISO-style time span, with implicit units on number of days
  *	preceding an hh:mm:ss field. - thomas 1998-04-30
+ *
+ * itm_in remains undefined for infinite interval values for which dtype alone
+ * suffices.
  */
 int
 DecodeInterval(char **field, int *ftype, int nf, int range,
@@ -3599,6 +3602,27 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
 						type = uval;
 						break;
 
+					case RESERV:
+						tmask = (DTK_DATE_M | DTK_TIME_M);
+
+						/*
+						 * Only reserved words corresponding to infinite
+						 * intervals are accepted.
+						 */
+						if (uval != DTK_LATE && uval != DTK_EARLY)
+							return DTERR_BAD_FORMAT;
+
+						/*
+						 * infinity can not be followed by anything else. We
+						 * could allow "ago" to reverse the sign of infinity
+						 * but that signed infinity is more intuitive.
+						 */
+						if (i != nf - 1)
+							return DTERR_BAD_FORMAT;
+
+						*dtype = uval;
+						break;
+
 					default:
 						return DTERR_BAD_FORMAT;
 				}
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index 5011fc4815..135d683285 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -2264,3 +2264,42 @@ SELECT INTERVAL '1 year months days 5 hours';
 ERROR:  invalid input syntax for type interval: "1 year months days 5 hours"
 LINE 1: SELECT INTERVAL '1 year months days 5 hours';
                         ^
+-- unacceptable reserved words in interval. Only "infinity", "+infinity" and
+-- "-infinity" are allowed.
+SELECT INTERVAL 'now';
+ERROR:  invalid input syntax for type interval: "now"
+LINE 1: SELECT INTERVAL 'now';
+                        ^
+SELECT INTERVAL 'today';
+ERROR:  invalid input syntax for type interval: "today"
+LINE 1: SELECT INTERVAL 'today';
+                        ^
+SELECT INTERVAL 'tomorrow';
+ERROR:  invalid input syntax for type interval: "tomorrow"
+LINE 1: SELECT INTERVAL 'tomorrow';
+                        ^
+SELECT INTERVAL 'allballs';
+ERROR:  invalid input syntax for type interval: "allballs"
+LINE 1: SELECT INTERVAL 'allballs';
+                        ^
+SELECT INTERVAL 'epoch';
+ERROR:  invalid input syntax for type interval: "epoch"
+LINE 1: SELECT INTERVAL 'epoch';
+                        ^
+SELECT INTERVAL 'yesterday';
+ERROR:  invalid input syntax for type interval: "yesterday"
+LINE 1: SELECT INTERVAL 'yesterday';
+                        ^
+-- infinity specification should be the only thing
+SELECT INTERVAL 'infinity years';
+ERROR:  invalid input syntax for type interval: "infinity years"
+LINE 1: SELECT INTERVAL 'infinity years';
+                        ^
+SELECT INTERVAL 'infinity ago';
+ERROR:  invalid input syntax for type interval: "infinity ago"
+LINE 1: SELECT INTERVAL 'infinity ago';
+                        ^
+SELECT INTERVAL '+infinity -infinity';
+ERROR:  invalid input syntax for type interval: "+infinity -infinity"
+LINE 1: SELECT INTERVAL '+infinity -infinity';
+                        ^
diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
index 590e1000bd..912803a1b0 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -745,3 +745,17 @@ SELECT INTERVAL '2 minutes ago 5 days';
 -- consecutive and dangling units are not allowed.
 SELECT INTERVAL 'hour 5 months';
 SELECT INTERVAL '1 year months days 5 hours';
+
+-- unacceptable reserved words in interval. Only "infinity", "+infinity" and
+-- "-infinity" are allowed.
+SELECT INTERVAL 'now';
+SELECT INTERVAL 'today';
+SELECT INTERVAL 'tomorrow';
+SELECT INTERVAL 'allballs';
+SELECT INTERVAL 'epoch';
+SELECT INTERVAL 'yesterday';
+
+-- infinity specification should be the only thing
+SELECT INTERVAL 'infinity years';
+SELECT INTERVAL 'infinity ago';
+SELECT INTERVAL '+infinity -infinity';
-- 
2.35.3

