0001-Support-negative-years-in-make_timestamp.patch

text/plain

Filename: 0001-Support-negative-years-in-make_timestamp.patch
Type: text/plain
Part: 0
Message: Re: BUG #16419: wrong parsing BC year in to_date() function

Patch

Format: format-patch
Series: patch 0001
Subject: Support negative years in make_timestamp()
File+
src/backend/utils/adt/timestamp.c 9 5
src/test/regress/expected/date.out 2 0
src/test/regress/expected/timestamp.out 10 1
src/test/regress/sql/date.sql 1 0
src/test/regress/sql/timestamp.sql 4 1
From ef9b0cee4aee60268d4c72e8452e74e7bbc18ed1 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Fri, 4 Sep 2020 23:02:09 +0200
Subject: [PATCH] Support negative years in make_timestamp()

make_date() already supported it; adding it was trivial.

Bug: #16419
Discussion: https://www.postgresql.org/message-id/flat/16419-d8d9db0a7553f01b@postgresql.org
---
 src/backend/utils/adt/timestamp.c       | 14 +++++++++-----
 src/test/regress/expected/date.out      |  2 ++
 src/test/regress/expected/timestamp.out | 11 ++++++++++-
 src/test/regress/sql/date.sql           |  1 +
 src/test/regress/sql/timestamp.sql      |  5 ++++-
 5 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 5fe304cea7..4128e3a739 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -556,17 +556,21 @@ make_timestamp_internal(int year, int month, int day,
 	TimeOffset	date;
 	TimeOffset	time;
 	int			dterr;
+	bool		bc = false;
 	Timestamp	result;
 
 	tm.tm_year = year;
 	tm.tm_mon = month;
 	tm.tm_mday = day;
 
-	/*
-	 * Note: we'll reject zero or negative year values.  Perhaps negatives
-	 * should be allowed to represent BC years?
-	 */
-	dterr = ValidateDate(DTK_DATE_M, false, false, false, &tm);
+	/* Handle negative years as BC */
+	if (tm.tm_year < 0)
+	{
+		bc = true;
+		tm.tm_year = -tm.tm_year;
+	}
+
+	dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
 
 	if (dterr != 0)
 		ereport(ERROR,
diff --git a/src/test/regress/expected/date.out b/src/test/regress/expected/date.out
index 4cdf1635f2..c03329fb5a 100644
--- a/src/test/regress/expected/date.out
+++ b/src/test/regress/expected/date.out
@@ -1439,6 +1439,8 @@ select make_time(8, 20, 0.0);
 (1 row)
 
 -- should fail
+select make_date(0, 7, 15);
+ERROR:  date field value out of range: 0-07-15
 select make_date(2013, 2, 30);
 ERROR:  date field value out of range: 2013-02-30
 select make_date(2013, 13, 1);
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index 5f97505a30..9655116090 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -1704,9 +1704,18 @@ SELECT '' AS to_char_12, to_char(d, 'FF1 FF2 FF3 FF4 FF5 FF6  ff1 ff2 ff3 ff4 ff
 (4 rows)
 
 -- timestamp numeric fields constructor
-SELECT make_timestamp(2014,12,28,6,30,45.887);
+SELECT make_timestamp(2014, 12, 28, 6, 30, 45.887);
         make_timestamp        
 ------------------------------
  Sun Dec 28 06:30:45.887 2014
 (1 row)
 
+SELECT make_timestamp(-44, 3, 15, 12, 30, 15);
+       make_timestamp        
+-----------------------------
+ Fri Mar 15 12:30:15 0044 BC
+(1 row)
+
+-- should fail
+select make_timestamp(0, 7, 15, 12, 30, 15);
+ERROR:  date field value out of range: 0-07-15
diff --git a/src/test/regress/sql/date.sql b/src/test/regress/sql/date.sql
index 1c3adf70ce..77f94ed27b 100644
--- a/src/test/regress/sql/date.sql
+++ b/src/test/regress/sql/date.sql
@@ -335,6 +335,7 @@ CREATE TABLE DATE_TBL (f1 date);
 select make_date(-44, 3, 15);
 select make_time(8, 20, 0.0);
 -- should fail
+select make_date(0, 7, 15);
 select make_date(2013, 2, 30);
 select make_date(2013, 13, 1);
 select make_date(2013, 11, -1);
diff --git a/src/test/regress/sql/timestamp.sql b/src/test/regress/sql/timestamp.sql
index 7b58c3cfa5..727ee50084 100644
--- a/src/test/regress/sql/timestamp.sql
+++ b/src/test/regress/sql/timestamp.sql
@@ -240,4 +240,7 @@ CREATE TABLE TIMESTAMP_TBL (d1 timestamp(2) without time zone);
    ) d(d);
 
 -- timestamp numeric fields constructor
-SELECT make_timestamp(2014,12,28,6,30,45.887);
+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);
-- 
2.28.0