diff options
Diffstat (limited to 'src/backend/utils/misc/tzparser.c')
-rw-r--r-- | src/backend/utils/misc/tzparser.c | 152 |
1 files changed, 63 insertions, 89 deletions
diff --git a/src/backend/utils/misc/tzparser.c b/src/backend/utils/misc/tzparser.c index e63ce58e69a..b2f6dd3a2bb 100644 --- a/src/backend/utils/misc/tzparser.c +++ b/src/backend/utils/misc/tzparser.c @@ -3,10 +3,12 @@ * tzparser.c * Functions for parsing timezone offset files * - * Note: we generally should not throw any errors in this file, but instead - * try to return an error code. This is not completely bulletproof at - * present --- in particular out-of-memory will throw an error. Could - * probably fix with PG_TRY if necessary. + * Note: this code is invoked from the check_hook for the GUC variable + * timezone_abbreviations. Therefore, it should report problems using + * GUC_check_errmsg() and related functions, and try to avoid throwing + * elog(ERROR). This is not completely bulletproof at present --- in + * particular out-of-memory will throw an error. Could probably fix with + * PG_TRY if necessary. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group @@ -24,15 +26,13 @@ #include "miscadmin.h" #include "storage/fd.h" -#include "utils/datetime.h" +#include "utils/guc.h" #include "utils/memutils.h" #include "utils/tzparser.h" #define WHITESPACE " \t\n\r" -static int tz_elevel; /* to avoid passing this around a lot */ - static bool validateTzEntry(tzEntry *tzentry); static bool splitTzLine(const char *filename, int lineno, char *line, tzEntry *tzentry); @@ -58,20 +58,16 @@ validateTzEntry(tzEntry *tzentry) */ if (strlen(tzentry->abbrev) > TOKMAXLEN) { - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("time zone abbreviation \"%s\" is too long (maximum %d characters) in time zone file \"%s\", line %d", - tzentry->abbrev, TOKMAXLEN, - tzentry->filename, tzentry->lineno))); + GUC_check_errmsg("time zone abbreviation \"%s\" is too long (maximum %d characters) in time zone file \"%s\", line %d", + tzentry->abbrev, TOKMAXLEN, + tzentry->filename, tzentry->lineno); return false; } if (tzentry->offset % 900 != 0) { - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - 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))); + 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; } @@ -81,11 +77,9 @@ validateTzEntry(tzEntry *tzentry) if (tzentry->offset > 14 * 60 * 60 || tzentry->offset < -14 * 60 * 60) { - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("time zone offset %d is out of range in time zone file \"%s\", line %d", - tzentry->offset, - tzentry->filename, tzentry->lineno))); + GUC_check_errmsg("time zone offset %d is out of range in time zone file \"%s\", line %d", + tzentry->offset, + tzentry->filename, tzentry->lineno); return false; } @@ -118,10 +112,8 @@ splitTzLine(const char *filename, int lineno, char *line, tzEntry *tzentry) abbrev = strtok(line, WHITESPACE); if (!abbrev) { - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("missing time zone abbreviation in time zone file \"%s\", line %d", - filename, lineno))); + GUC_check_errmsg("missing time zone abbreviation in time zone file \"%s\", line %d", + filename, lineno); return false; } tzentry->abbrev = abbrev; @@ -129,19 +121,15 @@ splitTzLine(const char *filename, int lineno, char *line, tzEntry *tzentry) offset = strtok(NULL, WHITESPACE); if (!offset) { - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("missing time zone offset in time zone file \"%s\", line %d", - filename, lineno))); + GUC_check_errmsg("missing time zone offset in time zone file \"%s\", line %d", + filename, lineno); return false; } tzentry->offset = strtol(offset, &offset_endptr, 10); if (offset_endptr == offset || *offset_endptr != '\0') { - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid number for time zone offset in time zone file \"%s\", line %d", - filename, lineno))); + GUC_check_errmsg("invalid number for time zone offset in time zone file \"%s\", line %d", + filename, lineno); return false; } @@ -163,10 +151,8 @@ splitTzLine(const char *filename, int lineno, char *line, tzEntry *tzentry) if (remain[0] != '#') /* must be a comment */ { - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid syntax in time zone file \"%s\", line %d", - filename, lineno))); + GUC_check_errmsg("invalid syntax in time zone file \"%s\", line %d", + filename, lineno); return false; } return true; @@ -229,13 +215,11 @@ addToArray(tzEntry **base, int *arraysize, int n, return n; } /* same abbrev but something is different, complain */ - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("time zone abbreviation \"%s\" is multiply defined", - entry->abbrev), - errdetail("Entry in time zone file \"%s\", line %d, conflicts with entry in file \"%s\", line %d.", - midptr->filename, midptr->lineno, - entry->filename, entry->lineno))); + GUC_check_errmsg("time zone abbreviation \"%s\" is multiply defined", + entry->abbrev); + GUC_check_errdetail("Entry in time zone file \"%s\", line %d, conflicts with entry in file \"%s\", line %d.", + midptr->filename, midptr->lineno, + entry->filename, entry->lineno); return -1; } } @@ -296,12 +280,10 @@ ParseTzFile(const char *filename, int depth, { if (!isalpha((unsigned char) *p)) { - /* at level 0, we need no ereport since guc.c will say enough */ + /* at level 0, just use guc.c's regular "invalid value" message */ if (depth > 0) - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid time zone file name \"%s\"", - filename))); + GUC_check_errmsg("invalid time zone file name \"%s\"", + filename); return -1; } } @@ -313,10 +295,8 @@ ParseTzFile(const char *filename, int depth, */ if (depth > 3) { - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("time zone file recursion limit exceeded in file \"%s\"", - filename))); + GUC_check_errmsg("time zone file recursion limit exceeded in file \"%s\"", + filename); return -1; } @@ -340,12 +320,10 @@ ParseTzFile(const char *filename, int depth, tzdir = AllocateDir(file_path); if (tzdir == NULL) { - ereport(tz_elevel, - (errcode_for_file_access(), - errmsg("could not open directory \"%s\": %m", - file_path), - errhint("This may indicate an incomplete PostgreSQL installation, or that the file \"%s\" has been moved away from its proper location.", - my_exec_path))); + GUC_check_errmsg("could not open directory \"%s\": %m", + file_path); + GUC_check_errhint("This may indicate an incomplete PostgreSQL installation, or that the file \"%s\" has been moved away from its proper location.", + my_exec_path); return -1; } FreeDir(tzdir); @@ -356,10 +334,8 @@ ParseTzFile(const char *filename, int depth, * complaint is enough */ if (errno != ENOENT || depth > 0) - ereport(tz_elevel, - (errcode_for_file_access(), - errmsg("could not read time zone file \"%s\": %m", - filename))); + GUC_check_errmsg("could not read time zone file \"%s\": %m", + filename); return -1; } @@ -371,10 +347,8 @@ ParseTzFile(const char *filename, int depth, { if (ferror(tzFile)) { - ereport(tz_elevel, - (errcode_for_file_access(), - errmsg("could not read time zone file \"%s\": %m", - filename))); + GUC_check_errmsg("could not read time zone file \"%s\": %m", + filename); return -1; } /* else we're at EOF after all */ @@ -383,10 +357,8 @@ ParseTzFile(const char *filename, int depth, if (strlen(tzbuf) == sizeof(tzbuf) - 1) { /* the line is too long for tzbuf */ - ereport(tz_elevel, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("line is too long in time zone file \"%s\", line %d", - filename, lineno))); + GUC_check_errmsg("line is too long in time zone file \"%s\", line %d", + filename, lineno); return -1; } @@ -408,10 +380,8 @@ ParseTzFile(const char *filename, int depth, includeFile = strtok(includeFile, WHITESPACE); if (!includeFile || !*includeFile) { - ereport(tz_elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("@INCLUDE without file name in time zone file \"%s\", line %d", - filename, lineno))); + GUC_check_errmsg("@INCLUDE without file name in time zone file \"%s\", line %d", + filename, lineno); return -1; } n = ParseTzFile(includeFile, depth + 1, @@ -444,23 +414,20 @@ ParseTzFile(const char *filename, int depth, /* * load_tzoffsets --- read and parse the specified timezone offset file * - * filename: name specified by user - * doit: whether to actually apply the new values, or just check - * elevel: elog reporting level (will be less than ERROR) - * - * Returns TRUE if OK, FALSE if not; should avoid erroring out + * On success, return a filled-in TimeZoneAbbrevTable, which must have been + * malloc'd not palloc'd. On failure, return NULL, using GUC_check_errmsg + * and friends to give details of the problem. */ -bool -load_tzoffsets(const char *filename, bool doit, int elevel) +TimeZoneAbbrevTable * +load_tzoffsets(const char *filename) { + TimeZoneAbbrevTable *result = NULL; MemoryContext tmpContext; MemoryContext oldContext; tzEntry *array; int arraysize; int n; - tz_elevel = elevel; - /* * Create a temp memory context to work in. This makes it easy to clean * up afterwards. @@ -479,13 +446,20 @@ load_tzoffsets(const char *filename, bool doit, int elevel) /* Parse the file(s) */ n = ParseTzFile(filename, 0, &array, &arraysize, 0); - /* If no errors and we should apply the result, pass it to datetime.c */ - if (n >= 0 && doit) - InstallTimeZoneAbbrevs(array, n); + /* If no errors so far, allocate result and let datetime.c convert data */ + if (n >= 0) + { + result = malloc(offsetof(TimeZoneAbbrevTable, abbrevs) + + n * sizeof(datetkn)); + if (!result) + GUC_check_errmsg("out of memory"); + else + ConvertTimeZoneAbbrevs(result, array, n); + } /* Clean up */ MemoryContextSwitchTo(oldContext); MemoryContextDelete(tmpContext); - return (n >= 0); + return result; } |