1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-14 08:21:07 +03:00

Repair an embarrassingly large number of alphabetization mistakes in the

datetime token tables.  Even more embarrassing, the regression tests
revealed some of the problems --- but evidently the bogus output wasn't
questioned.  Add code to postmaster startup to directly check the tables
for correct ordering, in hopes of not being embarrassed like this again.
This commit is contained in:
Tom Lane
2003-01-16 00:26:49 +00:00
parent 828822bc96
commit cb23b8415b
5 changed files with 79 additions and 31 deletions

View File

@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.304 2003/01/07 18:48:13 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.305 2003/01/16 00:26:44 tgl Exp $
*
* NOTES
*
@ -594,6 +594,15 @@ PostmasterMain(int argc, char *argv[])
ExitPostmaster(1);
}
/*
* Other one-time internal sanity checks can go here.
*/
if (!CheckDateTokenTables())
{
postmaster_error("Invalid datetoken tables, please fix.");
ExitPostmaster(1);
}
/*
* Now that we are done processing the postmaster arguments, reset
* getopt(3) library so that it will work correctly in subprocesses.

View File

@ -8,21 +8,21 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.97 2002/11/13 17:24:05 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.98 2003/01/16 00:26:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <ctype.h>
#include <math.h>
#include <errno.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include "miscadmin.h"
#include "utils/guc.h"
#include "utils/datetime.h"
#include "utils/guc.h"
static int DecodeNumber(int flen, char *field,
@ -37,7 +37,7 @@ static int DecodeTimezone(char *str, int *tzp);
static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm);
static int DecodePosixTimezone(char *str, int *val);
void TrimTrailingZeros(char *str);
static void TrimTrailingZeros(char *str);
int day_tab[2][13] = {
@ -69,14 +69,16 @@ char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
#define TOVAL(tp, v) ((tp)->value = ((v) < 0? NEG((-(v))/15): POS(v)/15))
/*
* datetktbl holds date/time keywords. Note that this table must be strictly
* ordered to allow an O(ln(N)) search algorithm.
* datetktbl holds date/time keywords.
*
* The text field is not guaranteed to be NULL-terminated.
* Note that this table must be strictly alphabetically ordered to allow an
* O(ln(N)) search algorithm to be used.
*
* The text field is NOT guaranteed to be NULL-terminated.
*
* To keep this table reasonably small, we divide the lexval for TZ and DTZ
* entries by 15 (so they are on 15 minute boundaries) and truncate the text
* field at MAXTOKLEN characters.
* field at TOKMAXLEN characters.
* Formerly, we divided by 10 rather than 15 but there are a few time zones
* which are 30 or 45 minutes away from an even hour, most are on an hour
* boundary, and none on other boundaries.
@ -88,11 +90,11 @@ char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
static datetkn datetktbl[] = {
/* text, token, lexval */
{EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
{"abstime", IGNORE_DTF, 0}, /* for pre-v6.1 "Invalid Abstime" */
{"acsst", DTZ, POS(42)}, /* Cent. Australia */
{"acst", DTZ, NEG(16)}, /* Atlantic/Porto Acre */
{"act", TZ, NEG(20)}, /* Atlantic/Porto Acre */
{DA_D, ADBC, AD}, /* "ad" for years >= 0 */
{"abstime", IGNORE_DTF, 0}, /* for pre-v6.1 "Invalid Abstime" */
{"adt", DTZ, NEG(12)}, /* Atlantic Daylight Time */
{"aesst", DTZ, POS(44)}, /* E. Australia */
{"aest", TZ, POS(40)}, /* Australia Eastern Std Time */
@ -101,16 +103,18 @@ static datetkn datetktbl[] = {
{"akdt", DTZ, NEG(32)}, /* Alaska Daylight Time */
{"akst", DTZ, NEG(36)}, /* Alaska Standard Time */
{"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
{"almt", TZ, POS(24)}, /* Almaty Time */
{"almst", TZ, POS(28)}, /* Almaty Savings Time */
{"almt", TZ, POS(24)}, /* Almaty Time */
{"am", AMPM, AM},
{"amst", DTZ, POS(20)}, /* Armenia Summer Time (Yerevan) */
{"amt", TZ, POS(16)}, /* Armenia Time (Yerevan) */
#if 0
{"amst", DTZ, NEG(12)}, /* Porto Velho */
#endif
{"amt", TZ, POS(16)}, /* Armenia Time (Yerevan) */
{"anast", DTZ, POS(52)}, /* Anadyr Summer Time (Russia) */
{"anat", TZ, POS(48)}, /* Anadyr Time (Russia) */
{"apr", MONTH, 4},
{"april", MONTH, 4},
#if 0
aqtst
aqtt
@ -122,8 +126,6 @@ static datetkn datetktbl[] = {
ast /* Atlantic Standard Time, Arabia Standard
* Time, Acre Standard Time */
#endif
{"apr", MONTH, 4},
{"april", MONTH, 4},
{"ast", TZ, NEG(16)}, /* Atlantic Std Time (Canada) */
{"at", IGNORE_DTF, 0}, /* "at" (throwaway) */
{"aug", MONTH, 8},
@ -181,12 +183,12 @@ static datetkn datetktbl[] = {
#endif
{"cot", TZ, NEG(20)}, /* Columbia Time */
{"cst", TZ, NEG(24)}, /* Central Standard Time */
{DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */
#if 0
cvst
#endif
{"cvt", TZ, POS(28)}, /* Christmas Island Time (Indian Ocean) */
{"cxt", TZ, POS(28)}, /* Christmas Island Time (Indian Ocean) */
{DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */
{"d", UNITS, DTK_DAY}, /* "day of month" for ISO input */
{"davt", TZ, POS(28)}, /* Davis Time (Antarctica) */
{"ddut", TZ, POS(40)}, /* Dumont-d'Urville Time (Antarctica) */
@ -414,8 +416,8 @@ static datetkn datetktbl[] = {
syot
#endif
{"t", ISOTIME, DTK_TIME}, /* Filler for ISO time fields */
{"that", TZ, NEG(40)}, /* Tahiti Time */
{"tft", TZ, POS(20)}, /* Kerguelen Time */
{"that", TZ, NEG(40)}, /* Tahiti Time */
{"thu", DOW, 4},
{"thur", DOW, 4},
{"thurs", DOW, 4},
@ -516,9 +518,9 @@ static datetkn deltatktbl[] = {
{DDAY, UNITS, DTK_DAY}, /* "day" relative */
{"days", UNITS, DTK_DAY}, /* "days" relative */
{"dec", UNITS, DTK_DECADE}, /* "decade" relative */
{"decs", UNITS, DTK_DECADE}, /* "decades" relative */
{DDECADE, UNITS, DTK_DECADE}, /* "decade" relative */
{"decades", UNITS, DTK_DECADE}, /* "decades" relative */
{"decs", UNITS, DTK_DECADE}, /* "decades" relative */
{"h", UNITS, DTK_HOUR}, /* "hour" relative */
{DHOUR, UNITS, DTK_HOUR}, /* "hour" relative */
{"hours", UNITS, DTK_HOUR}, /* "hours" relative */
@ -534,7 +536,6 @@ static datetkn deltatktbl[] = {
{"mils", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */
{"min", UNITS, DTK_MINUTE}, /* "minute" relative */
{"mins", UNITS, DTK_MINUTE}, /* "minutes" relative */
{"mins", UNITS, DTK_MINUTE}, /* "minutes" relative */
{DMINUTE, UNITS, DTK_MINUTE}, /* "minute" relative */
{"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative */
{"mon", UNITS, DTK_MONTH}, /* "months" relative */
@ -555,7 +556,6 @@ static datetkn deltatktbl[] = {
{"seconds", UNITS, DTK_SECOND},
{"secs", UNITS, DTK_SECOND},
{DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
{"timezone", UNITS, DTK_TZ}, /* "timezone" time offset */
{"timezone_h", UNITS, DTK_TZ_HOUR}, /* timezone hour units */
{"timezone_m", UNITS, DTK_TZ_MINUTE}, /* timezone minutes units */
{"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
@ -576,9 +576,9 @@ static datetkn deltatktbl[] = {
static unsigned int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
datetkn *datecache[MAXDATEFIELDS] = {NULL};
static datetkn *datecache[MAXDATEFIELDS] = {NULL};
datetkn *deltacache[MAXDATEFIELDS] = {NULL};
static datetkn *deltacache[MAXDATEFIELDS] = {NULL};
/*
@ -653,7 +653,7 @@ j2day(int date)
/* TrimTrailingZeros()
* ... resulting from printing numbers with full precision.
*/
void
static void
TrimTrailingZeros(char *str)
{
int len = strlen(str);
@ -3690,3 +3690,40 @@ ClearDateCache(bool newval, bool doit, bool interactive)
return true;
}
/*
* We've been burnt by stupid errors in the ordering of the datetkn tables
* once too often. Arrange to check them during postmaster start.
*/
static bool
CheckDateTokenTable(const char *tablename, datetkn *base, unsigned int nel)
{
bool ok = true;
unsigned int i;
for (i = 1; i < nel; i++)
{
if (strncmp(base[i-1].token, base[i].token, TOKMAXLEN) >= 0)
{
elog(LOG, "Ordering error in %s table: \"%.*s\" >= \"%.*s\"",
tablename,
TOKMAXLEN, base[i-1].token,
TOKMAXLEN, base[i].token);
ok = false;
}
}
return ok;
}
bool
CheckDateTokenTables(void)
{
bool ok = true;
ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
ok &= CheckDateTokenTable("australian_datetktbl",
australian_datetktbl,
australian_szdatetktbl);
return ok;
}