aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-09-06 11:03:56 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-09-06 11:03:56 -0400
commit388e71af880d579212c2489686903c2cfdea9032 (patch)
treea9cccdcd9c5a5409eaec1191487a9ec800ca19c3
parent78aa616be74a13156f4fc8db3a131f1fdc2cce47 (diff)
downloadpostgresql-388e71af880d579212c2489686903c2cfdea9032.tar.gz
postgresql-388e71af880d579212c2489686903c2cfdea9032.zip
Make timetz_zone() stable, and correct a bug for DYNTZ abbreviations.
Historically, timetz_zone() has used time(NULL) as the reference point for deciding whether DST is active. That means its result can change intra-statement, requiring it to be marked VOLATILE (cf. 35979e6c3). But that definition is pretty inconsistent with the way we deal with timestamps elsewhere. Let's make it use the transaction start time ("now()") as the reference point instead. That lets it be marked STABLE, and also saves a kernel call per invocation. While at it, remove the function's use of pg_time_t and pg_localtime. Those are inconsistent with the other code in this area, which indeed created a bug: timetz_zone() delivered completely wrong answers if the zone was specified by a dynamic TZ abbreviation. (We need to do something about that in the back branches, but the fix will look different from this.) Aleksander Alekseev and Tom Lane Discussion: https://postgr.es/m/CAJ7c6TOMG8zSNEZtCn5SPe+cCk3Lfxb71ZaQwT2F4T7PJ_t=KA@mail.gmail.com
-rw-r--r--src/backend/utils/adt/date.c28
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.dat2
3 files changed, 16 insertions, 16 deletions
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 0bea16cb671..9e8baeaa9c8 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -1481,9 +1481,7 @@ float_time_overflows(int hour, int min, double sec)
/* time2tm()
* Convert time data type to POSIX time structure.
*
- * For dates within the range of pg_time_t, convert to the local time zone.
- * If out of this range, leave as UTC (in practice that could only happen
- * if pg_time_t is just 32 bits) - thomas 97/05/27
+ * Note that only the hour/min/sec/fractional-sec fields are filled in.
*/
int
time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec)
@@ -3029,7 +3027,7 @@ extract_timetz(PG_FUNCTION_ARGS)
/* timetz_zone()
* Encode time with time zone type with specified time zone.
- * Applies DST rules as of the current date.
+ * Applies DST rules as of the transaction start time.
*/
Datum
timetz_zone(PG_FUNCTION_ARGS)
@@ -3068,12 +3066,11 @@ timetz_zone(PG_FUNCTION_ARGS)
}
else if (type == DYNTZ)
{
- /* dynamic-offset abbreviation, resolve using current time */
- pg_time_t now = (pg_time_t) time(NULL);
- struct pg_tm *tm;
+ /* dynamic-offset abbreviation, resolve using transaction start time */
+ TimestampTz now = GetCurrentTransactionStartTimestamp();
+ int isdst;
- tm = pg_localtime(&now, tzp);
- tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
+ tz = DetermineTimeZoneAbbrevOffsetTS(now, tzname, tzp, &isdst);
}
else
{
@@ -3081,12 +3078,15 @@ timetz_zone(PG_FUNCTION_ARGS)
tzp = pg_tzset(tzname);
if (tzp)
{
- /* Get the offset-from-GMT that is valid today for the zone */
- pg_time_t now = (pg_time_t) time(NULL);
- struct pg_tm *tm;
+ /* Get the offset-from-GMT that is valid now for the zone */
+ TimestampTz now = GetCurrentTransactionStartTimestamp();
+ struct pg_tm tm;
+ fsec_t fsec;
- tm = pg_localtime(&now, tzp);
- tz = -tm->tm_gmtoff;
+ if (timestamp2tm(now, &tz, &tm, &fsec, NULL, tzp) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
}
else
{
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 3190d82a868..fb35d3d5be4 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202109032
+#define CATALOG_VERSION_NO 202109061
#endif
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index c07b2c6a556..d068d6532ec 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5953,7 +5953,7 @@
proname => 'timestamp_larger', prorettype => 'timestamp',
proargtypes => 'timestamp timestamp', prosrc => 'timestamp_larger' },
{ oid => '2037', descr => 'adjust time with time zone to new zone',
- proname => 'timezone', provolatile => 'v', prorettype => 'timetz',
+ proname => 'timezone', provolatile => 's', prorettype => 'timetz',
proargtypes => 'text timetz', prosrc => 'timetz_zone' },
{ oid => '2038', descr => 'adjust time with time zone to new zone',
proname => 'timezone', prorettype => 'timetz',