staticbool validateTzEntry(tzEntry *tzentry); staticbool splitTzLine(constchar *filename, int lineno, char *line, tzEntry *tzentry); staticint addToArray(tzEntry **base, int *arraysize, int n,
tzEntry *entry, bool override); staticint ParseTzFile(constchar *filename, int depth,
tzEntry **base, int *arraysize, int n);
/* *Checkrestrictionsimposedbydatetktblstorageformat(seedatetime.c)
*/ if (strlen(tzentry->abbrev) > TOKMAXLEN)
{
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); returnfalse;
}
/* *Sanity-checktheoffset:shouldn'texceed14hours
*/ if (tzentry->offset > 14 * SECS_PER_HOUR ||
tzentry->offset < -14 * SECS_PER_HOUR)
{
GUC_check_errmsg("time zone offset %d is out of range in time zone file \"%s\", line %d",
tzentry->offset,
tzentry->filename, tzentry->lineno); returnfalse;
}
abbrev = strtok_r(line, WHITESPACE, &brkl); if (!abbrev)
{
GUC_check_errmsg("missing time zone abbreviation in time zone file \"%s\", line %d",
filename, lineno); returnfalse;
}
tzentry->abbrev = pstrdup(abbrev);
offset = strtok_r(NULL, WHITESPACE, &brkl); if (!offset)
{
GUC_check_errmsg("missing time zone offset in time zone file \"%s\", line %d",
filename, lineno); returnfalse;
}
/* We assume zone names don't begin with a digit or sign */ if (isdigit((unsignedchar) *offset) || *offset == '+' || *offset == '-')
{
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); returnfalse;
}
if (!remain) /* no more non-whitespace chars */ returntrue;
if (remain[0] != '#') /* must be a comment */
{
GUC_check_errmsg("invalid syntax in time zone file \"%s\", line %d",
filename, lineno); returnfalse;
} returntrue;
}
/* *Insertentryintosortedarray * **base:baseaddressofarray(changeableifmustenlargearray) **arraysize:allocatedlengthofarray(changeableifmustenlargearray) *n:currentnumberofvalidelementsinarray *entry:newdatatoinsert *override:trueifOKtooverride * *Returnsthenewarraylength(newvalueforn),or-1iferror
*/ staticint
addToArray(tzEntry **base, int *arraysize, int n,
tzEntry *entry, bool override)
{
tzEntry *arrayptr; int low; int high;
/* *Searchthearrayforaduplicate;asausefulsideeffect,thearrayis *maintainedinsortedorder.Weusestrcmp()toensurewematchthe *sortorderdatetime.cexpects.
*/
arrayptr = *base;
low = 0;
high = n - 1; while (low <= high)
{ int mid = (low + high) >> 1;
tzEntry *midptr = arrayptr + mid; int cmp;
cmp = strcmp(entry->abbrev, midptr->abbrev); if (cmp < 0)
high = mid - 1; elseif (cmp > 0)
low = mid + 1; else
{ /* *Foundaduplicateentry;complainunlessit'sthesame.
*/ 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;
} 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;
} /* same abbrev but something is different, complain */
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;
}
}
/* *Weenforcethatthefilenameisallalphacharacters.Thismaybe *overlyrestrictive,butwedon'twanttoallowaccesstoanything *outsidethetimezonesetsdirectory,soforinstance'/'*must*be *rejected.
*/ for (p = filename; *p; p++)
{ if (!isalpha((unsignedchar) *p))
{ /* at level 0, just use guc.c's regular "invalid value" message */ if (depth > 0)
GUC_check_errmsg("invalid time zone file name \"%s\"",
filename); return -1;
}
}
/* *Themaximalrecursiondepthisaprettyarbitrarysetting.Itishard *toimaginethatsomeoneneedsmorethan3levelssostickwiththis *conservativesettinguntilsomeonecomplains.
*/ if (depth > 3)
{
GUC_check_errmsg("time zone file recursion limit exceeded in file \"%s\"",
filename); return -1;
}
get_share_path(my_exec_path, share_path);
snprintf(file_path, sizeof(file_path), "%s/timezonesets/%s",
share_path, filename);
tzFile = AllocateFile(file_path, "r"); if (!tzFile)
{ /* *Checktoseeiftheproblemisnotthefilenamebutthedirectory. *Thisisworthtroublingoverbecauseiftheinstallationshare/ *directoryismissingorunreadable,thisislikelytobethefirst *placewenoticeaproblemduringpostmasterstartup.
*/ int save_errno = errno;
DIR *tzdir;
snprintf(file_path, sizeof(file_path), "%s/timezonesets",
share_path);
tzdir = AllocateDir(file_path); if (tzdir == NULL)
{
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);
errno = save_errno;
/* *otherwise,iffiledoesn'texistandit'slevel0,guc.c's *complaintisenough
*/ if (errno != ENOENT || depth > 0)
GUC_check_errmsg("could not read time zone file \"%s\": %m",
filename);
return -1;
}
while (!feof(tzFile))
{
lineno++; if (fgets(tzbuf, sizeof(tzbuf), tzFile) == NULL)
{ if (ferror(tzFile))
{
GUC_check_errmsg("could not read time zone file \"%s\": %m",
filename);
n = -1; break;
} /* else we're at EOF after all */ break;
} if (strlen(tzbuf) == sizeof(tzbuf) - 1)
{ /* the line is too long for tzbuf */
GUC_check_errmsg("line is too long in time zone file \"%s\", line %d",
filename, lineno);
n = -1; break;
}
/* skip over whitespace */
line = tzbuf; while (*line && isspace((unsignedchar) *line))
line++;
if (*line == '\0') /* empty line */ continue; if (*line == '#') /* comment line */ continue;
if (pg_strncasecmp(line, "@INCLUDE", strlen("@INCLUDE")) == 0)
{ /* pstrdup so we can use filename in result data structure */ char *includeFile = pstrdup(line + strlen("@INCLUDE")); char *brki;
includeFile = strtok_r(includeFile, WHITESPACE, &brki); if (!includeFile || !*includeFile)
{
GUC_check_errmsg("@INCLUDE without file name in time zone file \"%s\", line %d",
filename, lineno);
n = -1; break;
}
n = ParseTzFile(includeFile, depth + 1,
base, arraysize, n); if (n < 0) break; continue;
}
if (!splitTzLine(filename, lineno, line, &tzentry))
{
n = -1; break;
} if (!validateTzEntry(&tzentry))
{
n = -1; break;
}
n = addToArray(base, arraysize, n, &tzentry, override); if (n < 0) break;
}
/* Initialize array at a reasonable size */
arraysize = 128;
array = (tzEntry *) palloc(arraysize * sizeof(tzEntry));
/* Parse the file(s) */
n = ParseTzFile(filename, 0, &array, &arraysize, 0);
/* If no errors so far, let datetime.c allocate memory & convert format */ if (n >= 0)
{
result = ConvertTimeZoneAbbrevs(array, n); if (!result)
GUC_check_errmsg("out of memory");
}
/* Clean up */
MemoryContextSwitchTo(oldContext);
MemoryContextDelete(tmpContext);
return result;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.