aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/misc/tzparser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/misc/tzparser.c')
-rw-r--r--src/backend/utils/misc/tzparser.c77
1 files changed, 45 insertions, 32 deletions
diff --git a/src/backend/utils/misc/tzparser.c b/src/backend/utils/misc/tzparser.c
index 6a5a7b39abf..a6a12ff06e3 100644
--- a/src/backend/utils/misc/tzparser.c
+++ b/src/backend/utils/misc/tzparser.c
@@ -63,13 +63,6 @@ validateTzEntry(tzEntry *tzentry)
tzentry->filename, tzentry->lineno);
return false;
}
- if (tzentry->offset % 900 != 0)
- {
- GUC_check_errmsg("time zone offset %d is not a multiple of 900 sec (15 min) in time zone file \"%s\", line %d",
- tzentry->offset,
- tzentry->filename, tzentry->lineno);
- return false;
- }
/*
* Sanity-check the offset: shouldn't exceed 14 hours
@@ -93,7 +86,11 @@ validateTzEntry(tzEntry *tzentry)
}
/*
- * Attempt to parse the line as a timezone abbrev spec (name, offset, dst)
+ * Attempt to parse the line as a timezone abbrev spec
+ *
+ * Valid formats are:
+ * name zone
+ * name offset dst
*
* Returns TRUE if OK, else false; data is stored in *tzentry
*/
@@ -116,7 +113,7 @@ splitTzLine(const char *filename, int lineno, char *line, tzEntry *tzentry)
filename, lineno);
return false;
}
- tzentry->abbrev = abbrev;
+ tzentry->abbrev = pstrdup(abbrev);
offset = strtok(NULL, WHITESPACE);
if (!offset)
@@ -125,25 +122,43 @@ splitTzLine(const char *filename, int lineno, char *line, tzEntry *tzentry)
filename, lineno);
return false;
}
- tzentry->offset = strtol(offset, &offset_endptr, 10);
- if (offset_endptr == offset || *offset_endptr != '\0')
- {
- GUC_check_errmsg("invalid number for time zone offset in time zone file \"%s\", line %d",
- filename, lineno);
- return false;
- }
- is_dst = strtok(NULL, WHITESPACE);
- if (is_dst && pg_strcasecmp(is_dst, "D") == 0)
+ /* We assume zone names don't begin with a digit or sign */
+ if (isdigit((unsigned char) *offset) || *offset == '+' || *offset == '-')
{
- tzentry->is_dst = true;
- remain = strtok(NULL, WHITESPACE);
+ tzentry->zone = NULL;
+ tzentry->offset = strtol(offset, &offset_endptr, 10);
+ if (offset_endptr == offset || *offset_endptr != '\0')
+ {
+ GUC_check_errmsg("invalid number for time zone offset in time zone file \"%s\", line %d",
+ filename, lineno);
+ return false;
+ }
+
+ is_dst = strtok(NULL, WHITESPACE);
+ if (is_dst && pg_strcasecmp(is_dst, "D") == 0)
+ {
+ tzentry->is_dst = true;
+ remain = strtok(NULL, WHITESPACE);
+ }
+ else
+ {
+ /* there was no 'D' dst specifier */
+ tzentry->is_dst = false;
+ remain = is_dst;
+ }
}
else
{
- /* there was no 'D' dst specifier */
+ /*
+ * Assume entry is a zone name. We do not try to validate it by
+ * looking up the zone, because that would force loading of a lot of
+ * zones that probably will never be used in the current session.
+ */
+ tzentry->zone = pstrdup(offset);
+ tzentry->offset = 0;
tzentry->is_dst = false;
- remain = is_dst;
+ remain = strtok(NULL, WHITESPACE);
}
if (!remain) /* no more non-whitespace chars */
@@ -201,8 +216,11 @@ addToArray(tzEntry **base, int *arraysize, int n,
/*
* Found a duplicate entry; complain unless it's the same.
*/
- if (midptr->offset == entry->offset &&
- midptr->is_dst == entry->is_dst)
+ if ((midptr->zone == NULL && entry->zone == NULL &&
+ midptr->offset == entry->offset &&
+ midptr->is_dst == entry->is_dst) ||
+ (midptr->zone != NULL && entry->zone != NULL &&
+ strcmp(midptr->zone, entry->zone) == 0))
{
/* return unchanged array */
return n;
@@ -210,6 +228,7 @@ addToArray(tzEntry **base, int *arraysize, int n,
if (override)
{
/* same abbrev but something is different, override */
+ midptr->zone = entry->zone;
midptr->offset = entry->offset;
midptr->is_dst = entry->is_dst;
return n;
@@ -239,9 +258,6 @@ addToArray(tzEntry **base, int *arraysize, int n,
memcpy(arrayptr, entry, sizeof(tzEntry));
- /* Must dup the abbrev to ensure it survives */
- arrayptr->abbrev = pstrdup(entry->abbrev);
-
return n + 1;
}
@@ -446,15 +462,12 @@ load_tzoffsets(const char *filename)
/* Parse the file(s) */
n = ParseTzFile(filename, 0, &array, &arraysize, 0);
- /* If no errors so far, allocate result and let datetime.c convert data */
+ /* If no errors so far, let datetime.c allocate memory & convert format */
if (n >= 0)
{
- result = malloc(offsetof(TimeZoneAbbrevTable, abbrevs) +
- n * sizeof(datetkn));
+ result = ConvertTimeZoneAbbrevs(array, n);
if (!result)
GUC_check_errmsg("out of memory");
- else
- ConvertTimeZoneAbbrevs(result, array, n);
}
/* Clean up */