1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-23 14:01:44 +03:00

Sync our copy of the timezone library with IANA tzcode master.

This patch absorbs a few unreleased fixes in the IANA code.
It corresponds to commit 2d8b944c1cec0808ac4f7a9ee1a463c28f9cd00a
in https://github.com/eggert/tz.  Non-cosmetic changes include:

TZDEFRULESTRING is updated to match current US DST practice,
rather than what it was over ten years ago.  This only matters
for interpretation of POSIX-style zone names (e.g., "EST5EDT"),
and only if the timezone database doesn't include either an exact
match for the zone name or a "posixrules" entry.  The latter
should not be true in any current Postgres installation, but
this could possibly matter when using --with-system-tzdata.

Get rid of a nonportable use of "++var" on a bool var.
This is part of a larger fix that eliminates some vestigial
support for consecutive leap seconds, and adds checks to
the "zic" compiler that the data files do not specify that.

Remove a couple of ancient compatibility hacks.  The IANA
crew think these are obsolete, and I tend to agree.  But
perhaps our buildfarm will think different.

Back-patch to all supported branches, in line with our policy
that all branches should be using current IANA code.  Before v10,
this includes application of current pgindent rules, to avoid
whitespace problems in future back-patches.

Discussion: https://postgr.es/m/E1dsWhf-0000pT-F9@gemulon.postgresql.org
This commit is contained in:
Tom Lane
2017-09-22 00:04:21 -04:00
parent a890432a87
commit 47f849a3c9
4 changed files with 173 additions and 139 deletions

View File

@ -11,7 +11,6 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "pg_getopt.h"
@ -46,9 +45,12 @@ typedef int64 zic_t;
static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
#endif
/* The type and printf format for line numbers. */
/*
* The type for line numbers. In Postgres, use %d to format them; upstream
* uses PRIdMAX but we prefer not to rely on that, not least because it
* results in platform-dependent strings to be translated.
*/
typedef int lineno_t;
#define PRIdLINENO "d"
struct rule
{
@ -293,10 +295,13 @@ struct lookup
static struct lookup const *byword(const char *string,
const struct lookup *lp);
static struct lookup const line_codes[] = {
static struct lookup const zi_line_codes[] = {
{"Rule", LC_RULE},
{"Zone", LC_ZONE},
{"Link", LC_LINK},
{NULL, 0}
};
static struct lookup const leap_line_codes[] = {
{"Leap", LC_LEAP},
{NULL, 0}
};
@ -435,7 +440,8 @@ growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
return ptr;
else
{
ptrdiff_t amax = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
ptrdiff_t amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
if ((amax - 1) / 3 * 2 < *nitems_alloc)
memory_exhausted(_("integer overflow"));
@ -471,10 +477,10 @@ verror(const char *string, va_list args)
* "*" -v on BSD systems.
*/
if (filename)
fprintf(stderr, _("\"%s\", line %" PRIdLINENO ": "), filename, linenum);
fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
vfprintf(stderr, string, args);
if (rfilename != NULL)
fprintf(stderr, _(" (rule from \"%s\", line %" PRIdLINENO ")"),
fprintf(stderr, _(" (rule from \"%s\", line %d)"),
rfilename, rlinenum);
fprintf(stderr, "\n");
}
@ -563,7 +569,7 @@ static const char *leapsec;
static const char *yitcommand;
int
main(int argc, char *argv[])
main(int argc, char **argv)
{
int c,
k;
@ -572,7 +578,7 @@ main(int argc, char *argv[])
#ifndef WIN32
umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
#endif /* !WIN32 */
#endif
progname = argv[0];
if (TYPE_BIT(zic_t) <64)
{
@ -631,7 +637,10 @@ main(int argc, char *argv[])
break;
case 'y':
if (yitcommand == NULL)
{
warning(_("-y is obsolescent"));
yitcommand = strdup(optarg);
}
else
{
fprintf(stderr,
@ -1202,6 +1211,9 @@ infile(const char *name)
wantcont = inzcont(fields, nfields);
else
{
struct lookup const *line_codes
= name == leapsec ? leap_line_codes : zi_line_codes;
lp = byword(fields[0], line_codes);
if (lp == NULL)
error(_("input line of unknown type"));
@ -1220,12 +1232,7 @@ infile(const char *name)
wantcont = false;
break;
case LC_LEAP:
if (name != leapsec)
warning(_("%s: Leap line in non leap"
" seconds file %s"),
progname, name);
else
inleap(fields, nfields);
inleap(fields, nfields);
wantcont = false;
break;
default: /* "cannot happen" */
@ -1359,7 +1366,7 @@ inzone(char **fields, int nfields)
strcmp(zones[i].z_name, fields[ZF_NAME]) == 0)
{
error(_("duplicate zone name %s"
" (file \"%s\", line %" PRIdLINENO ")"),
" (file \"%s\", line %d)"),
fields[ZF_NAME],
zones[i].z_filename,
zones[i].z_linenum);
@ -1573,21 +1580,11 @@ inleap(char **fields, int nfields)
positive = false;
count = 1;
}
else if (strcmp(cp, "--") == 0)
{
positive = false;
count = 2;
}
else if (strcmp(cp, "+") == 0)
{
positive = true;
count = 1;
}
else if (strcmp(cp, "++") == 0)
{
positive = true;
count = 2;
}
else
{
error(_("illegal CORRECTION field on Leap line"));
@ -1599,9 +1596,9 @@ inleap(char **fields, int nfields)
return;
}
t = tadd(t, tod);
if (t < early_time)
if (t < 0)
{
error(_("leap second precedes Big Bang"));
error(_("leap second precedes Epoch"));
return;
}
leapadd(t, positive, lp->l_value, count);
@ -1753,11 +1750,14 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
error(_("typed single year"));
return;
}
warning(_("year type \"%s\" is obsolete; use \"-\" instead"),
typep);
rp->r_yrtype = ecpyalloc(typep);
}
/*
* Day work. Accept things such as: 1 last-Sunday Sun<=20 Sun>=7
* Day work. Accept things such as: 1 lastSunday last-Sunday
* (undocumented; warn about this) Sun<=20 Sun>=7
*/
dp = ecpyalloc(dayp);
if ((lp = byword(dp, lasts)) != NULL)
@ -2850,9 +2850,10 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
{
ptrdiff_t k;
zic_t jtime,
ktime = 0;
ktime;
zic_t offset;
INITIALIZE(ktime);
if (useuntil)
{
/*
@ -2929,7 +2930,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
continue;
}
if (*startbuf == '\0' &&
startoff == oadd(zp->z_gmtoff, stdoff))
startoff == oadd(zp->z_gmtoff,
stdoff))
{
doabbr(startbuf,
zp,
@ -3104,14 +3106,7 @@ leapadd(zic_t t, bool positive, int rolling, int count)
}
for (i = 0; i < leapcnt; ++i)
if (t <= trans[i])
{
if (t == trans[i])
{
error(_("repeated leap second moment"));
exit(EXIT_FAILURE);
}
break;
}
do
{
for (j = leapcnt; j > i; --j)
@ -3132,12 +3127,19 @@ adjleap(void)
{
int i;
zic_t last = 0;
zic_t prevtrans = 0;
/*
* propagate leap seconds forward
*/
for (i = 0; i < leapcnt; ++i)
{
if (trans[i] - prevtrans < 28 * SECSPERDAY)
{
error(_("Leap seconds too close together"));
exit(EXIT_FAILURE);
}
prevtrans = trans[i];
trans[i] = tadd(trans[i], last);
last = corr[i] += last;
}
@ -3191,7 +3193,7 @@ yearistype(zic_t year, const char *type)
exit(EXIT_FAILURE);
}
/* Is A a space character in the C locale? */
/* Is A a space character in the C locale? */
static bool
is_space(char a)
{
@ -3362,6 +3364,19 @@ itsabbr(const char *abbr, const char *word)
return true;
}
/* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
static bool
ciprefix(char const *abbr, char const *word)
{
do
if (!*abbr)
return true;
while (lowerit(*abbr++) == lowerit(*word++));
return false;
}
static const struct lookup *
byword(const char *word, const struct lookup *table)
{
@ -3371,6 +3386,23 @@ byword(const char *word, const struct lookup *table)
if (word == NULL || table == NULL)
return NULL;
/*
* If TABLE is LASTS and the word starts with "last" followed by a
* non-'-', skip the "last" and look in WDAY_NAMES instead. Warn about any
* usage of the undocumented prefix "last-".
*/
if (table == lasts && ciprefix("last", word) && word[4])
{
if (word[4] == '-')
warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
word, word + 5);
else
{
word += 4;
table = wday_names;
}
}
/*
* Look for exact match.
*/
@ -3383,13 +3415,31 @@ byword(const char *word, const struct lookup *table)
*/
foundlp = NULL;
for (lp = table; lp->l_word != NULL; ++lp)
if (itsabbr(word, lp->l_word))
if (ciprefix(word, lp->l_word))
{
if (foundlp == NULL)
foundlp = lp;
else
return NULL; /* multiple inexact matches */
}
/* Warn about any backward-compatibility issue with pre-2017c zic. */
if (foundlp)
{
bool pre_2017c_match = false;
for (lp = table; lp->l_word; lp++)
if (itsabbr(word, lp->l_word))
{
if (pre_2017c_match)
{
warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
break;
}
pre_2017c_match = true;
}
}
return foundlp;
}
@ -3621,11 +3671,15 @@ mkdirs(char const *argname, bool ancestors)
cp = name = ecpyalloc(argname);
/*
* On MS-Windows systems, do not worry about drive letters or backslashes,
* as this should suffice in practice. Time zone names do not use drive
* letters and backslashes. If the -d option of zic does not name an
* already-existing directory, it can use slashes to separate the
* already-existing ancestor prefix from the to-be-created subdirectories.
*/
/* Do not mkdir a root directory, as it must exist. */
#ifdef WIN32
if (is_alpha(name[0]) && name[1] == ':')
cp += 2;
#endif
while (*cp == '/')
cp++;