Skip to content

Commit 5fbd9d9

Browse files
committed
Merge branch 'REL9_5_STABLE' into PGPRO9_5
2 parents f8c2ef3 + 0ce0801 commit 5fbd9d9

File tree

20 files changed

+276
-131
lines changed

20 files changed

+276
-131
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9770,6 +9770,13 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
97709770
</tgroup>
97719771
</table>
97729772

9773+
<para>
9774+
While most timezone abbreviations represent fixed offsets from UTC,
9775+
there are some that have historically varied in value
9776+
(see <xref linkend="datetime-config-files"> for more information).
9777+
In such cases this view presents their current meaning.
9778+
</para>
9779+
97739780
</sect1>
97749781

97759782
<sect1 id="view-pg-timezone-names">

doc/src/sgml/datetime.sgml

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -384,19 +384,38 @@
384384

385385
<para>
386386
A <replaceable>zone_abbreviation</replaceable> is just the abbreviation
387-
being defined. The <replaceable>offset</replaceable> is the equivalent
388-
offset in seconds from UTC, positive being east from Greenwich and
389-
negative being west. For example, -18000 would be five hours west
390-
of Greenwich, or North American east coast standard time. <literal>D</>
391-
indicates that the zone name represents local daylight-savings time rather
392-
than standard time. Alternatively, a <replaceable>time_zone_name</> can
393-
be given, in which case that time zone definition is consulted, and the
394-
abbreviation's meaning in that zone is used. This alternative is
395-
recommended only for abbreviations whose meaning has historically varied,
396-
as looking up the meaning is noticeably more expensive than just using
397-
a fixed integer value.
387+
being defined. An <replaceable>offset</replaceable> is an integer giving
388+
the equivalent offset in seconds from UTC, positive being east from
389+
Greenwich and negative being west. For example, -18000 would be five
390+
hours west of Greenwich, or North American east coast standard time.
391+
<literal>D</> indicates that the zone name represents local
392+
daylight-savings time rather than standard time.
398393
</para>
399394

395+
<para>
396+
Alternatively, a <replaceable>time_zone_name</> can be given, referencing
397+
a zone name defined in the IANA timezone database. The zone's definition
398+
is consulted to see whether the abbreviation is or has been in use in
399+
that zone, and if so, the appropriate meaning is used &mdash; that is,
400+
the meaning that was currently in use at the timestamp whose value is
401+
being determined, or the meaning in use immediately before that if it
402+
wasn't current at that time, or the oldest meaning if it was used only
403+
after that time. This behavior is essential for dealing with
404+
abbreviations whose meaning has historically varied. It is also allowed
405+
to define an abbreviation in terms of a zone name in which that
406+
abbreviation does not appear; then using the abbreviation is just
407+
equivalent to writing out the zone name.
408+
</para>
409+
410+
<tip>
411+
<para>
412+
Using a simple integer <replaceable>offset</replaceable> is preferred
413+
when defining an abbreviation whose offset from UTC has never changed,
414+
as such abbreviations are much cheaper to process than those that
415+
require consulting a time zone definition.
416+
</para>
417+
</tip>
418+
400419
<para>
401420
The <literal>@INCLUDE</> syntax allows inclusion of another file in the
402421
<filename>.../share/timezonesets/</> directory. Inclusion can be nested,

src/backend/access/gin/gindatapage.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ typedef struct
8686
char action;
8787

8888
ItemPointerData *modifieditems;
89-
int nmodifieditems;
89+
uint16 nmodifieditems;
9090

9191
/*
9292
* The following fields represent the items in this segment. If 'items' is

src/backend/access/transam/xlog.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4980,7 +4980,8 @@ readRecoveryCommandFile(void)
49804980
rtli = (TimeLineID) strtoul(item->value, NULL, 0);
49814981
if (errno == EINVAL || errno == ERANGE)
49824982
ereport(FATAL,
4983-
(errmsg("recovery_target_timeline is not a valid number: \"%s\"",
4983+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4984+
errmsg("recovery_target_timeline is not a valid number: \"%s\"",
49844985
item->value)));
49854986
}
49864987
if (rtli)
@@ -4996,7 +4997,8 @@ readRecoveryCommandFile(void)
49964997
recoveryTargetXid = (TransactionId) strtoul(item->value, NULL, 0);
49974998
if (errno == EINVAL || errno == ERANGE)
49984999
ereport(FATAL,
4999-
(errmsg("recovery_target_xid is not a valid number: \"%s\"",
5000+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5001+
errmsg("recovery_target_xid is not a valid number: \"%s\"",
50005002
item->value)));
50015003
ereport(DEBUG2,
50025004
(errmsg_internal("recovery_target_xid = %u",
@@ -5111,7 +5113,8 @@ readRecoveryCommandFile(void)
51115113
}
51125114
else
51135115
ereport(FATAL,
5114-
(errmsg("unrecognized recovery parameter \"%s\"",
5116+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5117+
errmsg("unrecognized recovery parameter \"%s\"",
51155118
item->name)));
51165119
}
51175120

@@ -5130,7 +5133,8 @@ readRecoveryCommandFile(void)
51305133
{
51315134
if (recoveryRestoreCommand == NULL)
51325135
ereport(FATAL,
5133-
(errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
5136+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5137+
errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
51345138
RECOVERY_COMMAND_FILE)));
51355139
}
51365140

@@ -5144,6 +5148,15 @@ readRecoveryCommandFile(void)
51445148
!EnableHotStandby)
51455149
recoveryTargetAction = RECOVERY_TARGET_ACTION_SHUTDOWN;
51465150

5151+
/*
5152+
* We don't support standby_mode in standalone backends; that requires
5153+
* other processes such as the WAL receiver to be alive.
5154+
*/
5155+
if (StandbyModeRequested && !IsUnderPostmaster)
5156+
ereport(FATAL,
5157+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5158+
errmsg("standby mode is not supported by single-user servers")));
5159+
51475160
/* Enable fetching from archive recovery area */
51485161
ArchiveRecoveryRequested = true;
51495162

@@ -5160,7 +5173,8 @@ readRecoveryCommandFile(void)
51605173
/* Timeline 1 does not have a history file, all else should */
51615174
if (rtli != 1 && !existsTimeLineHistory(rtli))
51625175
ereport(FATAL,
5163-
(errmsg("recovery target timeline %u does not exist",
5176+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5177+
errmsg("recovery target timeline %u does not exist",
51645178
rtli)));
51655179
recoveryTargetTLI = rtli;
51665180
recoveryTargetIsLatest = false;

src/backend/utils/adt/datetime.c

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec,
5252
int scale);
5353
static int DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp,
5454
pg_time_t *tp);
55-
static int DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr,
56-
pg_tz *tzp, int *isdst);
55+
static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t,
56+
const char *abbr, pg_tz *tzp,
57+
int *offset, int *isdst);
5758
static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp);
5859

5960

@@ -1620,19 +1621,40 @@ DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp, pg_time_t *tp)
16201621
* This differs from the behavior of DetermineTimeZoneOffset() in that a
16211622
* standard-time or daylight-time abbreviation forces use of the corresponding
16221623
* GMT offset even when the zone was then in DS or standard time respectively.
1624+
* (However, that happens only if we can match the given abbreviation to some
1625+
* abbreviation that appears in the IANA timezone data. Otherwise, we fall
1626+
* back to doing DetermineTimeZoneOffset().)
16231627
*/
16241628
int
16251629
DetermineTimeZoneAbbrevOffset(struct pg_tm * tm, const char *abbr, pg_tz *tzp)
16261630
{
16271631
pg_time_t t;
1632+
int zone_offset;
1633+
int abbr_offset;
1634+
int abbr_isdst;
16281635

16291636
/*
16301637
* Compute the UTC time we want to probe at. (In event of overflow, we'll
16311638
* probe at the epoch, which is a bit random but probably doesn't matter.)
16321639
*/
1633-
(void) DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1640+
zone_offset = DetermineTimeZoneOffsetInternal(tm, tzp, &t);
16341641

1635-
return DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, &tm->tm_isdst);
1642+
/*
1643+
* Try to match the abbreviation to something in the zone definition.
1644+
*/
1645+
if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1646+
&abbr_offset, &abbr_isdst))
1647+
{
1648+
/* Success, so use the abbrev-specific answers. */
1649+
tm->tm_isdst = abbr_isdst;
1650+
return abbr_offset;
1651+
}
1652+
1653+
/*
1654+
* No match, so use the answers we already got from
1655+
* DetermineTimeZoneOffsetInternal.
1656+
*/
1657+
return zone_offset;
16361658
}
16371659

16381660

@@ -1646,19 +1668,41 @@ DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr,
16461668
pg_tz *tzp, int *isdst)
16471669
{
16481670
pg_time_t t = timestamptz_to_time_t(ts);
1671+
int zone_offset;
1672+
int abbr_offset;
1673+
int tz;
1674+
struct pg_tm tm;
1675+
fsec_t fsec;
16491676

1650-
return DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, isdst);
1677+
/*
1678+
* If the abbrev matches anything in the zone data, this is pretty easy.
1679+
*/
1680+
if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1681+
&abbr_offset, isdst))
1682+
return abbr_offset;
1683+
1684+
/*
1685+
* Else, break down the timestamp so we can use DetermineTimeZoneOffset.
1686+
*/
1687+
if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0)
1688+
ereport(ERROR,
1689+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1690+
errmsg("timestamp out of range")));
1691+
1692+
zone_offset = DetermineTimeZoneOffset(&tm, tzp);
1693+
*isdst = tm.tm_isdst;
1694+
return zone_offset;
16511695
}
16521696

16531697

16541698
/* DetermineTimeZoneAbbrevOffsetInternal()
16551699
*
16561700
* Workhorse for above two functions: work from a pg_time_t probe instant.
1657-
* DST status is returned into *isdst.
1701+
* On success, return GMT offset and DST status into *offset and *isdst.
16581702
*/
1659-
static int
1660-
DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr,
1661-
pg_tz *tzp, int *isdst)
1703+
static bool
1704+
DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp,
1705+
int *offset, int *isdst)
16621706
{
16631707
char upabbr[TZ_STRLEN_MAX + 1];
16641708
unsigned char *p;
@@ -1670,18 +1714,17 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr,
16701714
*p = pg_toupper(*p);
16711715

16721716
/* Look up the abbrev's meaning at this time in this zone */
1673-
if (!pg_interpret_timezone_abbrev(upabbr,
1674-
&t,
1675-
&gmtoff,
1676-
isdst,
1677-
tzp))
1678-
ereport(ERROR,
1679-
(errcode(ERRCODE_CONFIG_FILE_ERROR),
1680-
errmsg("time zone abbreviation \"%s\" is not used in time zone \"%s\"",
1681-
abbr, pg_get_timezone_name(tzp))));
1682-
1683-
/* Change sign to agree with DetermineTimeZoneOffset() */
1684-
return (int) -gmtoff;
1717+
if (pg_interpret_timezone_abbrev(upabbr,
1718+
&t,
1719+
&gmtoff,
1720+
isdst,
1721+
tzp))
1722+
{
1723+
/* Change sign to agree with DetermineTimeZoneOffset() */
1724+
*offset = (int) -gmtoff;
1725+
return true;
1726+
}
1727+
return false;
16851728
}
16861729

16871730

src/bin/pg_basebackup/receivelog.c

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -516,26 +516,28 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline,
516516
if (!CheckServerVersionForStreaming(conn))
517517
return false;
518518

519+
/*
520+
* Decide whether we want to report the flush position. If we report
521+
* the flush position, the primary will know what WAL we'll
522+
* possibly re-request, and it can then remove older WAL safely.
523+
* We must always do that when we are using slots.
524+
*
525+
* Reporting the flush position makes one eligible as a synchronous
526+
* replica. People shouldn't include generic names in
527+
* synchronous_standby_names, but we've protected them against it so
528+
* far, so let's continue to do so unless specifically requested.
529+
*/
519530
if (replication_slot != NULL)
520531
{
521-
/*
522-
* Report the flush position, so the primary can know what WAL we'll
523-
* possibly re-request, and remove older WAL safely.
524-
*
525-
* We only report it when a slot has explicitly been used, because
526-
* reporting the flush position makes one eligible as a synchronous
527-
* replica. People shouldn't include generic names in
528-
* synchronous_standby_names, but we've protected them against it so
529-
* far, so let's continue to do so in the situations when possible. If
530-
* they've got a slot, though, we need to report the flush position,
531-
* so that the master can remove WAL.
532-
*/
533532
reportFlushPosition = true;
534533
sprintf(slotcmd, "SLOT \"%s\" ", replication_slot);
535534
}
536535
else
537536
{
538-
reportFlushPosition = false;
537+
if (synchronous)
538+
reportFlushPosition = true;
539+
else
540+
reportFlushPosition = false;
539541
slotcmd[0] = 0;
540542
}
541543

src/port/path.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ skip_drive(const char *path)
8686
bool
8787
has_drive_prefix(const char *path)
8888
{
89+
#ifdef WIN32
8990
return skip_drive(path) != path;
91+
#else
92+
return false;
93+
#endif
9094
}
9195

9296
/*

src/test/regress/expected/timestamptz.out

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,3 +2538,38 @@ SELECT '2007-12-09 07:30:00 UTC'::timestamptz AT TIME ZONE 'VET';
25382538
Sun Dec 09 03:00:00 2007
25392539
(1 row)
25402540

2541+
--
2542+
-- Test that the pg_timezone_names and pg_timezone_abbrevs views are
2543+
-- more-or-less working. We can't test their contents in any great detail
2544+
-- without the outputs changing anytime IANA updates the underlying data,
2545+
-- but it seems reasonable to expect at least one entry per major meridian.
2546+
-- (At the time of writing, the actual counts are around 38 because of
2547+
-- zones using fractional GMT offsets, so this is a pretty loose test.)
2548+
--
2549+
select count(distinct utc_offset) >= 24 as ok from pg_timezone_names;
2550+
ok
2551+
----
2552+
t
2553+
(1 row)
2554+
2555+
select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs;
2556+
ok
2557+
----
2558+
t
2559+
(1 row)
2560+
2561+
-- Let's check the non-default timezone abbreviation sets, too
2562+
set timezone_abbreviations = 'Australia';
2563+
select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs;
2564+
ok
2565+
----
2566+
t
2567+
(1 row)
2568+
2569+
set timezone_abbreviations = 'India';
2570+
select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs;
2571+
ok
2572+
----
2573+
t
2574+
(1 row)
2575+

src/test/regress/sql/timestamptz.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,3 +449,19 @@ SELECT '2007-12-09 07:00:00 UTC'::timestamptz AT TIME ZONE 'VET';
449449
SELECT '2007-12-09 07:00:01 UTC'::timestamptz AT TIME ZONE 'VET';
450450
SELECT '2007-12-09 07:29:59 UTC'::timestamptz AT TIME ZONE 'VET';
451451
SELECT '2007-12-09 07:30:00 UTC'::timestamptz AT TIME ZONE 'VET';
452+
453+
--
454+
-- Test that the pg_timezone_names and pg_timezone_abbrevs views are
455+
-- more-or-less working. We can't test their contents in any great detail
456+
-- without the outputs changing anytime IANA updates the underlying data,
457+
-- but it seems reasonable to expect at least one entry per major meridian.
458+
-- (At the time of writing, the actual counts are around 38 because of
459+
-- zones using fractional GMT offsets, so this is a pretty loose test.)
460+
--
461+
select count(distinct utc_offset) >= 24 as ok from pg_timezone_names;
462+
select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs;
463+
-- Let's check the non-default timezone abbreviation sets, too
464+
set timezone_abbreviations = 'Australia';
465+
select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs;
466+
set timezone_abbreviations = 'India';
467+
select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs;

src/timezone/README

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ in the same commit. Usually, if a known abbreviation has changed meaning,
3434
the appropriate fix is to make it refer to a long-form zone name instead
3535
of a fixed GMT offset.
3636

37+
The core regression test suite does some simple validation of the zone
38+
data and abbreviations data (notably by checking that the pg_timezone_names
39+
and pg_timezone_abbrevs views don't throw errors). It's worth running it
40+
as a cross-check on proposed updates.
41+
3742
When there has been a new release of Windows (probably including Service
3843
Packs), the list of matching timezones need to be updated. Run the
3944
script in src/tools/win32tzlist.pl on a Windows machine running this new

0 commit comments

Comments
 (0)