From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 30 May 2012 23:58:47 +0000 (-0400)
Subject: Expand the allowed range of timezone offsets to +/-15:59:59 from Greenwich.
X-Git-Tag: REL9_0_8~6
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9b0875a2045cecc9de2a0f1c16e7930510a394ae;p=postgresql

Expand the allowed range of timezone offsets to +/-15:59:59 from Greenwich.

We used to only allow offsets less than +/-13 hours, then it was +/14,
then it was +/-15.  That's still not good enough though, as per today's bug
report from Patric Bechtel.  This time I actually looked through the Olson
timezone database to find the largest offsets used anywhere.  The winners
are Asia/Manila, at -15:56:00 until 1844, and America/Metlakatla, at
+15:13:42 until 1867.  So we'd better allow offsets less than +/-16 hours.

Given the history, we are way overdue to have some greppable #define
symbols controlling this, so make some ... and also remove an obsolete
comment that didn't get fixed the last time.

Back-patch to all supported branches.
---

diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index c97ecf4a1a..c10931317e 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -1924,9 +1924,8 @@ timetz_recv(PG_FUNCTION_ARGS)
 
 	result->zone = pq_getmsgint(buf, sizeof(result->zone));
 
-	/* we allow GMT displacements up to 14:59:59, cf DecodeTimezone() */
-	if (result->zone <= -15 * SECS_PER_HOUR ||
-		result->zone >= 15 * SECS_PER_HOUR)
+	/* Check for sane GMT displacement; see notes in utils/timestamp.h */
+	if (result->zone <= -TZDISP_LIMIT || result->zone >= TZDISP_LIMIT)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
 				 errmsg("time zone displacement out of range")));
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 705fcf195c..b82aad0f7e 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -2699,9 +2699,6 @@ DecodeNumberField(int len, char *str, int fmask,
  * Return 0 if okay (and set *tzp), a DTERR code if not okay.
  *
  * NB: this must *not* ereport on failure; see commands/variable.c.
- *
- * Note: we allow timezone offsets up to 13:59.  There are places that
- * use +1300 summer time.
  */
 static int
 DecodeTimezone(char *str, int *tzp)
@@ -2746,7 +2743,8 @@ DecodeTimezone(char *str, int *tzp)
 	else
 		min = 0;
 
-	if (hr < 0 || hr > 14)
+	/* Range-check the values; see notes in utils/timestamp.h */
+	if (hr < 0 || hr > MAX_TZDISP_HOUR)
 		return DTERR_TZDISP_OVERFLOW;
 	if (min < 0 || min >= 60)
 		return DTERR_TZDISP_OVERFLOW;
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index ee42eb498e..f1ae1ff978 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -100,6 +100,16 @@ typedef struct
 #define USECS_PER_SEC	INT64CONST(1000000)
 #endif
 
+/*
+ * We allow numeric timezone offsets up to 15:59:59 either way from Greenwich.
+ * Currently, the record holders for wackiest offsets in actual use are zones
+ * Asia/Manila, at -15:56:00 until 1844, and America/Metlakatla, at +15:13:42
+ * until 1867.  If we were to reject such values we would fail to dump and
+ * restore old timestamptz values with these zone settings.
+ */
+#define MAX_TZDISP_HOUR		15				/* maximum allowed hour part */
+#define TZDISP_LIMIT		((MAX_TZDISP_HOUR + 1) * SECS_PER_HOUR)
+
 /*
  * Macros for fmgr-callable functions.
  *