Add guard code to protect from buffer overruns on long date/time input
authorThomas G. Lockhart
Sun, 4 Aug 2002 06:44:47 +0000 (06:44 +0000)
committerThomas G. Lockhart
Sun, 4 Aug 2002 06:44:47 +0000 (06:44 +0000)
 strings. Should go back in and look at doing this a bit more elegantly
 and (hopefully) cheaper. Probably not too bad anyway, but it seems a
 shame to scan the strings twice: once for length for this buffer overrun
 protection, and once to parse the line.
Remove use of pow() in date/time handling; was already gone from everything
 *but* the time data types.
Define macros for handling typmod manipulation for date/time types.
 Should be more robust than all of that brute-force inline code.
Rename macros for masking and typmod manipulation to put TIMESTAMP_
 or INTERVAL_ in front of the macro name, to reduce the possibility
 of name space collisions.

src/backend/utils/adt/date.c
src/backend/utils/adt/datetime.c
src/backend/utils/adt/format_type.c
src/backend/utils/adt/nabstime.c
src/backend/utils/adt/timestamp.c
src/backend/utils/adt/varlena.c

index 06d0e3abe95cb56942d78c4cea234b16286cb474..4b9d0f15e6dd5b7a291c10e3d9e5b32b6bd15f8a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.69 2002/06/20 20:29:36 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.70 2002/08/04 06:44:47 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,6 +57,9 @@ date_in(PG_FUNCTION_ARGS)
    int         ftype[MAXDATEFIELDS];
    char        lowstr[MAXDATELEN + 1];
 
+   if (strlen(str) >= sizeof(lowstr))
+       elog(ERROR, "Bad date external representation (too long) '%s'", str);
+
    if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
     || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp) != 0))
        elog(ERROR, "Bad date external representation '%s'", str);
@@ -518,6 +521,9 @@ time_in(PG_FUNCTION_ARGS)
    int         dtype;
    int         ftype[MAXDATEFIELDS];
 
+   if (strlen(str) >= sizeof(lowstr))
+       elog(ERROR, "Bad time external representation (too long) '%s'", str);
+
    if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
     || (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, NULL) != 0))
        elog(ERROR, "Bad time external representation '%s'", str);
@@ -606,37 +612,85 @@ time_scale(PG_FUNCTION_ARGS)
    PG_RETURN_TIMEADT(result);
 }
 
+/* AdjustTimeForTypmod()
+ * Force the precision of the time value to a specified value.
+ * Uses *exactly* the same code as in AdjustTimestampForTypemod()
+ * but we make a separate copy because those types do not
+ * have a fundamental tie together but rather a coincidence of
+ * implementation. - thomas
+ */
 static void
 AdjustTimeForTypmod(TimeADT *time, int32 typmod)
 {
-   if ((typmod >= 0) && (typmod <= MAX_TIME_PRECISION))
-   {
 #ifdef HAVE_INT64_TIMESTAMP
-       static int64 TimeScale = INT64CONST(1000000);
+   static const int64 TimeScales[MAX_TIMESTAMP_PRECISION+1] = {
+       INT64CONST(1000000),
+       INT64CONST(100000),
+       INT64CONST(10000),
+       INT64CONST(1000),
+       INT64CONST(100),
+       INT64CONST(10),
+       INT64CONST(1)
+   };
+
+   static const int64 TimeOffsets[MAX_TIMESTAMP_PRECISION+1] = {
+       INT64CONST(-500000),
+       INT64CONST(-50000),
+       INT64CONST(-5000),
+       INT64CONST(-500),
+       INT64CONST(-50),
+       INT64CONST(-5),
+       INT64CONST(0)
+   };
 #else
-       static double TimeScale = 1;
+   static const double TimeScales[MAX_TIMESTAMP_PRECISION+1] = {
+       1,
+       10,
+       100,
+       1000,
+       10000,
+       100000,
+       1000000
+   };
+
+   static const double TimeOffsets[MAX_TIMESTAMP_PRECISION+1] = {
+       0.5,
+       0.05,
+       0.005,
+       0.0005,
+       0.00005,
+       0.000005,
+       0.0000005
+   };
 #endif
-       static int32 TimeTypmod = 0;
 
-       if (typmod != TimeTypmod)
-       {
+   if ((typmod >= 0) && (typmod <= MAX_TIME_PRECISION))
+   {
 #ifdef HAVE_INT64_TIMESTAMP
-           TimeScale = pow(10.0, (MAX_TIME_PRECISION-typmod));
-#else
-           TimeScale = pow(10.0, typmod);
-#endif
-           TimeTypmod = typmod;
+       /* we have different truncation behavior depending on sign */
+       if (*time >= INT64CONST(0))
+       {
+           *time = ((*time / TimeScales[typmod])
+                    * TimeScales[typmod]);
+       }
+       else
+       {
+           *time = (((*time + TimeOffsets[typmod]) / TimeScales[typmod])
+                    * TimeScales[typmod]);
        }
-
-#ifdef HAVE_INT64_TIMESTAMP
-       *time = ((*time / TimeScale) * TimeScale);
-       if (*time >= INT64CONST(86400000000))
-           *time -= INT64CONST(86400000000);
 #else
-       *time = (rint(((double) *time) * TimeScale) / TimeScale);
-
-       if (*time >= 86400)
-           *time -= 86400;
+       /* we have different truncation behavior depending on sign */
+       if (*time >= 0)
+       {
+           *time = (rint(((double) *time) * TimeScales[typmod])
+                    / TimeScales[typmod]);
+       }
+       else
+       {
+           /* Scale and truncate first, then add to help the rounding behavior */
+           *time = (rint((((double) *time) * TimeScales[typmod]) + TimeOffsets[typmod])
+                    / TimeScales[typmod]);
+       }
 #endif
    }
 
@@ -1269,6 +1323,10 @@ timetz_in(PG_FUNCTION_ARGS)
    int         dtype;
    int         ftype[MAXDATEFIELDS];
 
+   if (strlen(str) >= sizeof(lowstr))
+       elog(ERROR, "Bad time with time zone"
+            " external representation (too long) '%s'", str);
+
    if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
      || (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
        elog(ERROR, "Bad time external representation '%s'", str);
index 184ad15ff38370476a91eef052c98bc5fc45bea4..2457421a62aa6a9a9894a3b0f0753d0556aba2bf 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.92 2002/06/20 20:29:37 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.93 2002/08/04 06:44:47 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,21 +56,31 @@ char       *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
  *  PRIVATE ROUTINES                                                        *
  *****************************************************************************/
 
-/* definitions for squeezing values into "value" */
+/*
+ * Definitions for squeezing values into "value"
+ * We set aside a high bit for a sign, and scale the timezone offsets
+ * in minutes by a factor of 15 (so can represent quarter-hour increments).
+ */
 #define ABS_SIGNBIT        ((char) 0200)
 #define VALMASK            ((char) 0177)
+#define POS(n)         (n)
 #define NEG(n)         ((n)|ABS_SIGNBIT)
 #define SIGNEDCHAR(c)  ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
-#define FROMVAL(tp)        (-SIGNEDCHAR((tp)->value) * 10) /* uncompress */
-#define TOVAL(tp, v)   ((tp)->value = ((v) < 0? NEG((-(v))/10): (v)/10))
+#define FROMVAL(tp)        (-SIGNEDCHAR((tp)->value) * 15) /* uncompress */
+#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.
  *
+ * 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 10 and truncate the text field at MAXTOKLEN characters.
- * the text field is not guaranteed to be NULL-terminated.
+ * entries by 15 (so they are on 15 minute boundaries) and truncate the text
+ * field at MAXTOKLEN 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.
  *
  * Let's include all strings from my current zinc time zone database.
  * Not all of them are unique, or even very understandable, so we will
@@ -79,414 +89,415 @@ char     *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
 static datetkn datetktbl[] = {
 /* text, token, lexval */
    {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
-   {"acsst", DTZ, 63},         /* Cent. Australia */
-   {"acst", DTZ, NEG(24)},     /* Atlantic/Porto Acre */
-   {"act", TZ, NEG(30)},       /* Atlantic/Porto Acre */
+   {"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(18)},      /* Atlantic Daylight Time */
-   {"aesst", DTZ, 66},         /* E. Australia */
-   {"aest", TZ, 60},           /* Australia Eastern Std Time */
-   {"aft", TZ, 27},            /* Kabul */
-   {"ahst", TZ, NEG(60)},      /* Alaska-Hawaii Std Time */
-   {"akdt", DTZ, NEG(48)},     /* Alaska Daylight Time */
-   {"akst", DTZ, NEG(54)},     /* Alaska Standard Time */
-   {"allballs", RESERV, DTK_ZULU},     /* 00:00:00 */
-   {"almt", TZ, 36},           /* Almaty Time */
-   {"almst", TZ, 42},          /* Almaty Savings Time */
+   {"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 */
+   {"aft", TZ, POS(18)},       /* Kabul */
+   {"ahst", TZ, NEG(40)},      /* Alaska-Hawaii Std Time */
+   {"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 */
    {"am", AMPM, AM},
-   {"amst", DTZ, 30},          /* Armenia Summer Time (Yerevan) */
-   {"amt", TZ, 24},            /* Armenia Time (Yerevan) */
+   {"amst", DTZ, POS(20)},     /* Armenia Summer Time (Yerevan) */
+   {"amt", TZ, POS(16)},       /* Armenia Time (Yerevan) */
 #if 0
-   {"amst", DTZ, NEG(18)},     /* Porto Velho */
+   {"amst", DTZ, NEG(12)},     /* Porto Velho */
 #endif
-   {"anast", DTZ, 78},         /* Anadyr Summer Time (Russia) */
-   {"anat", TZ, 72},           /* Anadyr Time (Russia) */
+   {"anast", DTZ, POS(52)},    /* Anadyr Summer Time (Russia) */
+   {"anat", TZ, POS(48)},      /* Anadyr Time (Russia) */
 #if 0
 aqtst
 aqtt
 arst
 #endif
-   {"art", TZ, NEG(18)},       /* Argentina Time */
+   {"art", TZ, NEG(12)},       /* Argentina Time */
 #if 0
 ashst
 ast /* Atlantic Standard Time, Arabia Standard Time, Acre Standard Time */
 #endif
    {"apr", MONTH, 4},
    {"april", MONTH, 4},
-   {"ast", TZ, NEG(24)},       /* Atlantic Std Time (Canada) */
-   {"at", IGNORE_DTF, 0},          /* "at" (throwaway) */
+   {"ast", TZ, NEG(16)},       /* Atlantic Std Time (Canada) */
+   {"at", IGNORE_DTF, 0},      /* "at" (throwaway) */
    {"aug", MONTH, 8},
    {"august", MONTH, 8},
-   {"awsst", DTZ, 54},         /* W. Australia */
-   {"awst", TZ, 48},           /* W. Australia */
-   {"awt", DTZ, NEG(18)},
-   {"azost", DTZ, 0},          /* Azores Summer Time */
-   {"azot", TZ, NEG(6)},       /* Azores Time */
-   {"azst", DTZ, 30},          /* Azerbaijan Summer Time */
-   {"azt", TZ, 24},            /* Azerbaijan Time */
+   {"awsst", DTZ, POS(36)},    /* W. Australia */
+   {"awst", TZ, POS(32)},      /* W. Australia */
+   {"awt", DTZ, NEG(12)},
+   {"azost", DTZ, POS(0)},     /* Azores Summer Time */
+   {"azot", TZ, NEG(4)},       /* Azores Time */
+   {"azst", DTZ, POS(20)},     /* Azerbaijan Summer Time */
+   {"azt", TZ, POS(16)},       /* Azerbaijan Time */
    {DB_C, ADBC, BC},           /* "bc" for years < 0 */
-   {"bdst", TZ, 12},           /* British Double Summer Time */
-   {"bdt", TZ, 36},            /* Dacca */
-   {"bnt", TZ, 48},            /* Brunei Darussalam Time */
-   {"bort", TZ, 48},           /* Borneo Time (Indonesia) */
+   {"bdst", TZ, POS(8)},       /* British Double Summer Time */
+   {"bdt", TZ, POS(24)},       /* Dacca */
+   {"bnt", TZ, POS(32)},       /* Brunei Darussalam Time */
+   {"bort", TZ, POS(32)},      /* Borneo Time (Indonesia) */
 #if 0
 bortst
 bost
 #endif
-   {"bot", TZ, NEG(24)},       /* Bolivia Time */
-   {"bra", TZ, NEG(18)},       /* Brazil Time */
+   {"bot", TZ, NEG(16)},       /* Bolivia Time */
+   {"bra", TZ, NEG(12)},       /* Brazil Time */
 #if 0
 brst
 brt
 #endif
-   {"bst", DTZ, 6},            /* British Summer Time */
+   {"bst", DTZ, POS(4)},       /* British Summer Time */
 #if 0
-   {"bst", TZ, NEG(18)},       /* Brazil Standard Time */
-   {"bst", DTZ, NEG(66)},      /* Bering Summer Time */
-#endif
-   {"bt", TZ, 18},             /* Baghdad Time */
-   {"btt", TZ, 36},            /* Bhutan Time */
-   {"cadt", DTZ, 63},          /* Central Australian DST */
-   {"cast", TZ, 57},           /* Central Australian ST */
-   {"cat", TZ, NEG(60)},       /* Central Alaska Time */
-   {"cct", TZ, 48},            /* China Coast Time */
+   {"bst", TZ, NEG(12)},       /* Brazil Standard Time */
+   {"bst", DTZ, NEG(44)},      /* Bering Summer Time */
+#endif
+   {"bt", TZ, POS(12)},        /* Baghdad Time */
+   {"btt", TZ, POS(24)},       /* Bhutan Time */
+   {"cadt", DTZ, POS(42)},     /* Central Australian DST */
+   {"cast", TZ, POS(38)},      /* Central Australian ST */
+   {"cat", TZ, NEG(40)},       /* Central Alaska Time */
+   {"cct", TZ, POS(32)},       /* China Coast Time */
 #if 0
-   {"cct", TZ, 39},            /* Indian Cocos (Island) Time */
-#endif
-   {"cdt", DTZ, NEG(30)},      /* Central Daylight Time */
-   {"cest", DTZ, 12},          /* Central European Dayl.Time */
-   {"cet", TZ, 6},             /* Central European Time */
-   {"cetdst", DTZ, 12},        /* Central European Dayl.Time */
+   {"cct", TZ, POS(26)},       /* Indian Cocos (Island) Time */
+#endif
+   {"cdt", DTZ, NEG(20)},      /* Central Daylight Time */
+   {"cest", DTZ, POS(8)},      /* Central European Dayl.Time */
+   {"cet", TZ, POS(4)},            /* Central European Time */
+   {"cetdst", DTZ, POS(8)},    /* Central European Dayl.Time */
+   {"chadt", DTZ, POS(55)},        /* Chatham Island Daylight Time (13:45) */
+   {"chast", TZ, POS(51)},     /* Chatham Island Time (12:45) */
 #if 0
-   {"chadt", DTZ, 82},         /* Chatham Island Daylight Time (13:45? set to 13:40) */
-   {"chast", TZ, 76},          /* Chatham Island Time (12:45? set to 12:40) */
 ckhst
 #endif
-   {"ckt", TZ, 72},            /* Cook Islands Time */
-   {"clst", DTZ, NEG(18)},     /* Chile Summer Time */
-   {"clt", TZ, NEG(24)},       /* Chile Time */
+   {"ckt", TZ, POS(48)},       /* Cook Islands Time */
+   {"clst", DTZ, NEG(12)},     /* Chile Summer Time */
+   {"clt", TZ, NEG(16)},       /* Chile Time */
 #if 0
 cost
 #endif
-   {"cot", TZ, NEG(30)},       /* Columbia Time */
-   {"cst", TZ, NEG(36)},       /* Central Standard Time */
+   {"cot", TZ, NEG(20)},       /* Columbia Time */
+   {"cst", TZ, NEG(24)},       /* Central Standard Time */
 #if 0
 cvst
 #endif
-   {"cvt", TZ, 42},            /* Christmas Island Time (Indian Ocean) */
-   {"cxt", TZ, 42},            /* Christmas Island Time (Indian Ocean) */
+   {"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, 42},           /* Davis Time (Antarctica) */
-   {"ddut", TZ, 60},           /* Dumont-d'Urville Time (Antarctica) */
+   {"davt", TZ, POS(28)},      /* Davis Time (Antarctica) */
+   {"ddut", TZ, POS(40)},      /* Dumont-d'Urville Time (Antarctica) */
    {"dec", MONTH, 12},
    {"december", MONTH, 12},
-   {"dnt", TZ, 6},             /* Dansk Normal Tid */
+   {"dnt", TZ, POS(4)},        /* Dansk Normal Tid */
    {"dow", RESERV, DTK_DOW},   /* day of week */
    {"doy", RESERV, DTK_DOY},   /* day of year */
    {"dst", DTZMOD, 6},
 #if 0
-   {"dusst", DTZ, 36},         /* Dushanbe Summer Time */
+   {"dusst", DTZ, POS(24)},    /* Dushanbe Summer Time */
 #endif
-   {"easst", DTZ, NEG(30)},    /* Easter Island Summer Time */
-   {"east", TZ, NEG(36)},      /* Easter Island Time */
-   {"eat", TZ, 18},            /* East Africa Time */
+   {"easst", DTZ, NEG(20)},    /* Easter Island Summer Time */
+   {"east", TZ, NEG(24)},      /* Easter Island Time */
+   {"eat", TZ, POS(12)},       /* East Africa Time */
 #if 0
-   {"east", DTZ, 24},          /* Indian Antananarivo Savings Time */
-   {"eat", TZ, 18},            /* Indian Antananarivo Time */
-   {"ect", TZ, NEG(24)},       /* Eastern Caribbean Time */
-   {"ect", TZ, NEG(30)},       /* Ecuador Time */
-#endif
-   {"edt", DTZ, NEG(24)},      /* Eastern Daylight Time */
-   {"eest", DTZ, 18},          /* Eastern Europe Summer Time */
-   {"eet", TZ, 12},            /* East. Europe, USSR Zone 1 */
-   {"eetdst", DTZ, 18},        /* Eastern Europe Daylight Time */
-   {"egst", DTZ, 0},           /* East Greenland Summer Time */
-   {"egt", TZ, NEG(6)},        /* East Greenland Time */
+   {"east", DTZ, POS(16)},     /* Indian Antananarivo Savings Time */
+   {"eat", TZ, POS(12)},       /* Indian Antananarivo Time */
+   {"ect", TZ, NEG(16)},       /* Eastern Caribbean Time */
+   {"ect", TZ, NEG(20)},       /* Ecuador Time */
+#endif
+   {"edt", DTZ, NEG(16)},      /* Eastern Daylight Time */
+   {"eest", DTZ, POS(12)},     /* Eastern Europe Summer Time */
+   {"eet", TZ, POS(8)},        /* East. Europe, USSR Zone 1 */
+   {"eetdst", DTZ, POS(12)},   /* Eastern Europe Daylight Time */
+   {"egst", DTZ, POS(0)},      /* East Greenland Summer Time */
+   {"egt", TZ, NEG(4)},        /* East Greenland Time */
 #if 0
 ehdt
 #endif
    {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
-   {"est", TZ, NEG(30)},       /* Eastern Standard Time */
+   {"est", TZ, NEG(20)},       /* Eastern Standard Time */
    {"feb", MONTH, 2},
    {"february", MONTH, 2},
-   {"fjst", DTZ, NEG(78)},     /* Fiji Summer Time (13 hour offset!) */
-   {"fjt", TZ, NEG(72)},       /* Fiji Time */
-   {"fkst", DTZ, NEG(18)},     /* Falkland Islands Summer Time */
-   {"fkt", TZ, NEG(12)},       /* Falkland Islands Time */
+   {"fjst", DTZ, NEG(52)},     /* Fiji Summer Time (13 hour offset!) */
+   {"fjt", TZ, NEG(48)},       /* Fiji Time */
+   {"fkst", DTZ, NEG(12)},     /* Falkland Islands Summer Time */
+   {"fkt", TZ, NEG(8)},        /* Falkland Islands Time */
 #if 0
 fnst
 fnt
 #endif
    {"fri", DOW, 5},
    {"friday", DOW, 5},
-   {"fst", TZ, 6},             /* French Summer Time */
-   {"fwt", DTZ, 12},           /* French Winter Time  */
-   {"galt", TZ, NEG(36)},      /* Galapagos Time */
-   {"gamt", TZ, NEG(54)},      /* Gambier Time */
-   {"gest", DTZ, 30},          /* Georgia Summer Time */
-   {"get", TZ, 24},            /* Georgia Time */
-   {"gft", TZ, NEG(18)},       /* French Guiana Time */
+   {"fst", TZ, POS(4)},        /* French Summer Time */
+   {"fwt", DTZ, POS(8)},       /* French Winter Time  */
+   {"galt", TZ, NEG(24)},      /* Galapagos Time */
+   {"gamt", TZ, NEG(36)},      /* Gambier Time */
+   {"gest", DTZ, POS(20)},     /* Georgia Summer Time */
+   {"get", TZ, POS(16)},       /* Georgia Time */
+   {"gft", TZ, NEG(12)},       /* French Guiana Time */
 #if 0
 ghst
 #endif
-   {"gilt", TZ, 72},           /* Gilbert Islands Time */
-   {"gmt", TZ, 0},             /* Greenwish Mean Time */
-   {"gst", TZ, 60},            /* Guam Std Time, USSR Zone 9 */
-   {"gyt", TZ, NEG(24)},       /* Guyana Time */
+   {"gilt", TZ, POS(48)},      /* Gilbert Islands Time */
+   {"gmt", TZ, POS(0)},        /* Greenwish Mean Time */
+   {"gst", TZ, POS(40)},       /* Guam Std Time, USSR Zone 9 */
+   {"gyt", TZ, NEG(16)},       /* Guyana Time */
    {"h", UNITS, DTK_HOUR},     /* "hour" */
 #if 0
 hadt
 hast
 #endif
-   {"hdt", DTZ, NEG(54)},      /* Hawaii/Alaska Daylight Time */
+   {"hdt", DTZ, NEG(36)},      /* Hawaii/Alaska Daylight Time */
 #if 0
 hkst
 #endif
-   {"hkt", TZ, 48},            /* Hong Kong Time */
+   {"hkt", TZ, POS(32)},       /* Hong Kong Time */
 #if 0
-   {"hmt", TZ, 18},            /* Hellas ? ? */
+   {"hmt", TZ, POS(12)},       /* Hellas ? ? */
 hovst
 hovt
 #endif
-   {"hst", TZ, NEG(60)},       /* Hawaii Std Time */
+   {"hst", TZ, NEG(40)},       /* Hawaii Std Time */
 #if 0
 hwt
 #endif
-   {"ict", TZ, 42},            /* Indochina Time */
-   {"idle", TZ, 72},           /* Intl. Date Line, East */
-   {"idlw", TZ, NEG(72)},      /* Intl. Date Line, West */
+   {"ict", TZ, POS(28)},       /* Indochina Time */
+   {"idle", TZ, POS(48)},      /* Intl. Date Line, East */
+   {"idlw", TZ, NEG(48)},      /* Intl. Date Line, West */
 #if 0
 idt /* Israeli, Iran, Indian Daylight Time */
 #endif
    {LATE, RESERV, DTK_LATE},   /* "infinity" reserved for "late time" */
    {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for bad time */
-   {"iot", TZ, 30},            /* Indian Chagos Time */
-   {"irkst", DTZ, 54},         /* Irkutsk Summer Time */
-   {"irkt", TZ, 48},           /* Irkutsk Time */
-   {"irt", TZ, 21},            /* Iran Time */
+   {"iot", TZ, POS(20)},       /* Indian Chagos Time */
+   {"irkst", DTZ, POS(36)},    /* Irkutsk Summer Time */
+   {"irkt", TZ, POS(32)},      /* Irkutsk Time */
+   {"irt", TZ, POS(14)},       /* Iran Time */
 #if 0
 isst
 #endif
-   {"ist", TZ, 12},            /* Israel */
-   {"it", TZ, 21},             /* Iran Time */
+   {"ist", TZ, POS(8)},        /* Israel */
+   {"it", TZ, POS(14)},        /* Iran Time */
    {"j", UNITS, DTK_JULIAN},
    {"jan", MONTH, 1},
    {"january", MONTH, 1},
-   {"javt", TZ, 42},           /* Java Time (07:00? see JT) */
-   {"jayt", TZ, 54},           /* Jayapura Time (Indonesia) */
+   {"javt", TZ, POS(28)},      /* Java Time (07:00? see JT) */
+   {"jayt", TZ, POS(36)},      /* Jayapura Time (Indonesia) */
    {"jd", UNITS, DTK_JULIAN},
-   {"jst", TZ, 54},            /* Japan Std Time,USSR Zone 8 */
-   {"jt", TZ, 45},             /* Java Time (07:30? see JAVT) */
+   {"jst", TZ, POS(36)},       /* Japan Std Time,USSR Zone 8 */
+   {"jt", TZ, POS(30)},        /* Java Time (07:30? see JAVT) */
    {"jul", MONTH, 7},
    {"julian", UNITS, DTK_JULIAN},
    {"july", MONTH, 7},
    {"jun", MONTH, 6},
    {"june", MONTH, 6},
-   {"kdt", DTZ, 60},           /* Korea Daylight Time */
-   {"kgst", DTZ, 36},          /* Kyrgyzstan Summer Time */
-   {"kgt", TZ, 30},            /* Kyrgyzstan Time */
-   {"kost", TZ, 72},           /* Kosrae Time */
-   {"krast", DTZ, 42},         /* Krasnoyarsk Summer Time */
-   {"krat", TZ, 48},           /* Krasnoyarsk Standard Time */
-   {"kst", TZ, 54},            /* Korea Standard Time */
-   {"lhdt", DTZ, 66},          /* Lord Howe Daylight Time, Australia */
-   {"lhst", TZ, 63},           /* Lord Howe Standard Time, Australia */
-   {"ligt", TZ, 60},           /* From Melbourne, Australia */
-   {"lint", TZ, 84},           /* Line Islands Time (Kiribati; +14 hours!) */
-   {"lkt", TZ, 36},            /* Lanka Time */
+   {"kdt", DTZ, POS(40)},      /* Korea Daylight Time */
+   {"kgst", DTZ, POS(24)},     /* Kyrgyzstan Summer Time */
+   {"kgt", TZ, POS(20)},       /* Kyrgyzstan Time */
+   {"kost", TZ, POS(48)},      /* Kosrae Time */
+   {"krast", DTZ, POS(28)},    /* Krasnoyarsk Summer Time */
+   {"krat", TZ, POS(32)},      /* Krasnoyarsk Standard Time */
+   {"kst", TZ, POS(36)},       /* Korea Standard Time */
+   {"lhdt", DTZ, POS(44)},     /* Lord Howe Daylight Time, Australia */
+   {"lhst", TZ, POS(42)},      /* Lord Howe Standard Time, Australia */
+   {"ligt", TZ, POS(40)},      /* From Melbourne, Australia */
+   {"lint", TZ, POS(56)},      /* Line Islands Time (Kiribati; +14 hours!) */
+   {"lkt", TZ, POS(24)},       /* Lanka Time */
    {"m", UNITS, DTK_MONTH},    /* "month" for ISO input */
-   {"magst", DTZ, 72},         /* Magadan Summer Time */
-   {"magt", TZ, 66},           /* Magadan Time */
+   {"magst", DTZ, POS(48)},    /* Magadan Summer Time */
+   {"magt", TZ, POS(44)},      /* Magadan Time */
    {"mar", MONTH, 3},
    {"march", MONTH, 3},
-   {"mart", TZ, NEG(57)},      /* Marquesas Time */
-   {"mawt", TZ, 36},           /* Mawson, Antarctica */
+   {"mart", TZ, NEG(38)},      /* Marquesas Time */
+   {"mawt", TZ, POS(24)},      /* Mawson, Antarctica */
    {"may", MONTH, 5},
-   {"mdt", DTZ, NEG(36)},      /* Mountain Daylight Time */
-   {"mest", DTZ, 12},          /* Middle Europe Summer Time */
-   {"met", TZ, 6},             /* Middle Europe Time */
-   {"metdst", DTZ, 12},        /* Middle Europe Daylight Time */
-   {"mewt", TZ, 6},            /* Middle Europe Winter Time */
-   {"mez", TZ, 6},             /* Middle Europe Zone */
-   {"mht", TZ, 72},            /* Kwajalein */
+   {"mdt", DTZ, NEG(24)},      /* Mountain Daylight Time */
+   {"mest", DTZ, POS(8)},      /* Middle Europe Summer Time */
+   {"met", TZ, POS(4)},        /* Middle Europe Time */
+   {"metdst", DTZ, POS(8)},    /* Middle Europe Daylight Time */
+   {"mewt", TZ, POS(4)},       /* Middle Europe Winter Time */
+   {"mez", TZ, POS(4)},        /* Middle Europe Zone */
+   {"mht", TZ, POS(48)},       /* Kwajalein */
    {"mm", UNITS, DTK_MINUTE},  /* "minute" for ISO input */
-   {"mmt", TZ, 39},            /* Myannar Time */
+   {"mmt", TZ, POS(26)},       /* Myannar Time */
    {"mon", DOW, 1},
    {"monday", DOW, 1},
 #if 0
 most
 #endif
-   {"mpt", TZ, 60},            /* North Mariana Islands Time */
-   {"msd", DTZ, 24},           /* Moscow Summer Time */
-   {"msk", TZ, 18},            /* Moscow Time */
-   {"mst", TZ, NEG(42)},       /* Mountain Standard Time */
-   {"mt", TZ, 51},             /* Moluccas Time */
-   {"mut", TZ, 24},            /* Mauritius Island Time */
-   {"mvt", TZ, 30},            /* Maldives Island Time */
-   {"myt", TZ, 48},            /* Malaysia Time */
+   {"mpt", TZ, POS(40)},       /* North Mariana Islands Time */
+   {"msd", DTZ, POS(16)},      /* Moscow Summer Time */
+   {"msk", TZ, POS(12)},       /* Moscow Time */
+   {"mst", TZ, NEG(28)},       /* Mountain Standard Time */
+   {"mt", TZ, POS(34)},        /* Moluccas Time */
+   {"mut", TZ, POS(16)},       /* Mauritius Island Time */
+   {"mvt", TZ, POS(20)},       /* Maldives Island Time */
+   {"myt", TZ, POS(32)},       /* Malaysia Time */
 #if 0
 ncst
 #endif
-   {"nct", TZ, 66},            /* New Caledonia Time */
-   {"ndt", DTZ, NEG(15)},      /* Nfld. Daylight Time */
-   {"nft", TZ, NEG(21)},       /* Newfoundland Standard Time */
-   {"nor", TZ, 6},             /* Norway Standard Time */
+   {"nct", TZ, POS(44)},       /* New Caledonia Time */
+   {"ndt", DTZ, NEG(10)},      /* Nfld. Daylight Time */
+   {"nft", TZ, NEG(14)},       /* Newfoundland Standard Time */
+   {"nor", TZ, POS(4)},        /* Norway Standard Time */
    {"nov", MONTH, 11},
    {"november", MONTH, 11},
-   {"novst", DTZ, 42},         /* Novosibirsk Summer Time */
-   {"novt", TZ, 36},           /* Novosibirsk Standard Time */
+   {"novst", DTZ, POS(28)},    /* Novosibirsk Summer Time */
+   {"novt", TZ, POS(24)},      /* Novosibirsk Standard Time */
    {NOW, RESERV, DTK_NOW},     /* current transaction time */
-   {"nst", TZ, NEG(21)},       /* Nfld. Standard Time */
-   {"nt", TZ, NEG(66)},        /* Nome Time */
-   {"nut", TZ, NEG(66)},       /* Niue Time */
-   {"nzdt", DTZ, 78},          /* New Zealand Daylight Time */
-   {"nzst", TZ, 72},           /* New Zealand Standard Time */
-   {"nzt", TZ, 72},            /* New Zealand Time */
+   {"npt", TZ, POS(23)},       /* Nepal Standard Time (GMT-5:45) */
+   {"nst", TZ, NEG(14)},       /* Nfld. Standard Time */
+   {"nt", TZ, NEG(44)},        /* Nome Time */
+   {"nut", TZ, NEG(44)},       /* Niue Time */
+   {"nzdt", DTZ, POS(52)},     /* New Zealand Daylight Time */
+   {"nzst", TZ, POS(48)},      /* New Zealand Standard Time */
+   {"nzt", TZ, POS(48)},       /* New Zealand Time */
    {"oct", MONTH, 10},
    {"october", MONTH, 10},
-   {"omsst", DTZ, 42},         /* Omsk Summer Time */
-   {"omst", TZ, 36},           /* Omsk Time */
-   {"on", IGNORE_DTF, 0},          /* "on" (throwaway) */
-   {"pdt", DTZ, NEG(42)},      /* Pacific Daylight Time */
+   {"omsst", DTZ, POS(28)},    /* Omsk Summer Time */
+   {"omst", TZ, POS(24)},      /* Omsk Time */
+   {"on", IGNORE_DTF, 0},      /* "on" (throwaway) */
+   {"pdt", DTZ, NEG(28)},      /* Pacific Daylight Time */
 #if 0
 pest
 #endif
-   {"pet", TZ, NEG(30)},       /* Peru Time */
-   {"petst", DTZ, 78},         /* Petropavlovsk-Kamchatski Summer Time */
-   {"pett", TZ, 72},           /* Petropavlovsk-Kamchatski Time */
-   {"pgt", TZ, 60},            /* Papua New Guinea Time */
-   {"phot", TZ, 78},           /* Phoenix Islands (Kiribati) Time */
+   {"pet", TZ, NEG(20)},       /* Peru Time */
+   {"petst", DTZ, POS(52)},    /* Petropavlovsk-Kamchatski Summer Time */
+   {"pett", TZ, POS(48)},      /* Petropavlovsk-Kamchatski Time */
+   {"pgt", TZ, POS(40)},       /* Papua New Guinea Time */
+   {"phot", TZ, POS(52)},      /* Phoenix Islands (Kiribati) Time */
 #if 0
 phst
 #endif
-   {"pht", TZ, 48},            /* Phillipine Time */
-   {"pkt", TZ, 30},            /* Pakistan Time */
+   {"pht", TZ, POS(32)},       /* Phillipine Time */
+   {"pkt", TZ, POS(20)},       /* Pakistan Time */
    {"pm", AMPM, PM},
-   {"pmdt", DTZ, NEG(12)},     /* Pierre & Miquelon Daylight Time */
+   {"pmdt", DTZ, NEG(8)},      /* Pierre & Miquelon Daylight Time */
 #if 0
 pmst
 #endif
-   {"pont", TZ, 66},           /* Ponape Time (Micronesia) */
-   {"pst", TZ, NEG(48)},       /* Pacific Standard Time */
-   {"pwt", TZ, 54},            /* Palau Time */
-   {"pyst", DTZ, NEG(18)},     /* Paraguay Summer Time */
-   {"pyt", TZ, NEG(24)},       /* Paraguay Time */
-   {"ret", DTZ, 24},           /* Reunion Island Time */
+   {"pont", TZ, POS(44)},      /* Ponape Time (Micronesia) */
+   {"pst", TZ, NEG(32)},       /* Pacific Standard Time */
+   {"pwt", TZ, POS(36)},       /* Palau Time */
+   {"pyst", DTZ, NEG(12)},     /* Paraguay Summer Time */
+   {"pyt", TZ, NEG(16)},       /* Paraguay Time */
+   {"ret", DTZ, POS(16)},      /* Reunion Island Time */
    {"s", UNITS, DTK_SECOND},   /* "seconds" for ISO input */
-   {"sadt", DTZ, 63},          /* S. Australian Dayl. Time */
+   {"sadt", DTZ, POS(42)},     /* S. Australian Dayl. Time */
 #if 0
 samst
 samt
 #endif
-   {"sast", TZ, 57},           /* South Australian Std Time */
+   {"sast", TZ, POS(38)},      /* South Australian Std Time */
    {"sat", DOW, 6},
    {"saturday", DOW, 6},
 #if 0
 sbt
 #endif
-   {"sct", DTZ, 24},           /* Mahe Island Time */
+   {"sct", DTZ, POS(16)},      /* Mahe Island Time */
    {"sep", MONTH, 9},
    {"sept", MONTH, 9},
    {"september", MONTH, 9},
-   {"set", TZ, NEG(6)},        /* Seychelles Time ?? */
+   {"set", TZ, NEG(4)},        /* Seychelles Time ?? */
 #if 0
 sgt
 #endif
-   {"sst", DTZ, 12},           /* Swedish Summer Time */
+   {"sst", DTZ, POS(8)},       /* Swedish Summer Time */
    {"sun", DOW, 0},
    {"sunday", DOW, 0},
-   {"swt", TZ, 6},             /* Swedish Winter Time  */
+   {"swt", TZ, POS(4)},        /* Swedish Winter Time */
 #if 0
 syot
 #endif
    {"t", ISOTIME, DTK_TIME},   /* Filler for ISO time fields */
-   {"that", TZ, NEG(60)},      /* Tahiti Time */
-   {"tft", TZ, 30},            /* Kerguelen Time */
+   {"that", TZ, NEG(40)},      /* Tahiti Time */
+   {"tft", TZ, POS(20)},       /* Kerguelen Time */
    {"thu", DOW, 4},
    {"thur", DOW, 4},
    {"thurs", DOW, 4},
    {"thursday", DOW, 4},
-   {"tjt", TZ, 30},            /* Tajikistan Time */
-   {"tkt", TZ, NEG(60)},       /* Tokelau Time */
-   {"tmt", TZ, 30},            /* Turkmenistan Time */
+   {"tjt", TZ, POS(20)},       /* Tajikistan Time */
+   {"tkt", TZ, NEG(40)},       /* Tokelau Time */
+   {"tmt", TZ, POS(20)},       /* Turkmenistan Time */
    {TODAY, RESERV, DTK_TODAY}, /* midnight */
    {TOMORROW, RESERV, DTK_TOMORROW},   /* tomorrow midnight */
 #if 0
 tost
 #endif
-   {"tot", TZ, 78},            /* Tonga Time */
+   {"tot", TZ, POS(52)},       /* Tonga Time */
 #if 0
 tpt
 #endif
-   {"truk", TZ, 60},           /* Truk Time */
+   {"truk", TZ, POS(40)},      /* Truk Time */
    {"tue", DOW, 2},
    {"tues", DOW, 2},
    {"tuesday", DOW, 2},
-   {"tvt", TZ, 72},            /* Tuvalu Time */
+   {"tvt", TZ, POS(48)},       /* Tuvalu Time */
 #if 0
 uct
 #endif
-   {"ulast", DTZ, 54},         /* Ulan Bator Summer Time */
-   {"ulat", TZ, 48},           /* Ulan Bator Time */
+   {"ulast", DTZ, POS(36)},    /* Ulan Bator Summer Time */
+   {"ulat", TZ, POS(32)},      /* Ulan Bator Time */
    {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
-   {"ut", TZ, 0},
-   {"utc", TZ, 0},
-   {"uyst", DTZ, NEG(12)},     /* Uruguay Summer Time */
-   {"uyt", TZ, NEG(18)},       /* Uruguay Time */
-   {"uzst", DTZ, 36},          /* Uzbekistan Summer Time */
-   {"uzt", TZ, 30},            /* Uzbekistan Time */
-   {"vet", TZ, NEG(24)},       /* Venezuela Time */
-   {"vlast", DTZ, 66},         /* Vladivostok Summer Time */
-   {"vlat", TZ, 60},           /* Vladivostok Time */
+   {"ut", TZ, POS(0)},
+   {"utc", TZ, POS(0)},
+   {"uyst", DTZ, NEG(8)},      /* Uruguay Summer Time */
+   {"uyt", TZ, NEG(12)},       /* Uruguay Time */
+   {"uzst", DTZ, POS(24)},     /* Uzbekistan Summer Time */
+   {"uzt", TZ, POS(20)},       /* Uzbekistan Time */
+   {"vet", TZ, NEG(16)},       /* Venezuela Time */
+   {"vlast", DTZ, POS(44)},    /* Vladivostok Summer Time */
+   {"vlat", TZ, POS(40)},      /* Vladivostok Time */
 #if 0
 vust
 #endif
-   {"vut", TZ, 66},            /* Vanuata Time */
-   {"wadt", DTZ, 48},          /* West Australian DST */
-   {"wakt", TZ, 72},           /* Wake Time */
+   {"vut", TZ, POS(44)},       /* Vanuata Time */
+   {"wadt", DTZ, POS(32)},     /* West Australian DST */
+   {"wakt", TZ, POS(48)},      /* Wake Time */
 #if 0
 warst
 #endif
-   {"wast", TZ, 42},           /* West Australian Std Time */
-   {"wat", TZ, NEG(6)},        /* West Africa Time */
-   {"wdt", DTZ, 54},           /* West Australian DST */
+   {"wast", TZ, POS(28)},      /* West Australian Std Time */
+   {"wat", TZ, NEG(4)},        /* West Africa Time */
+   {"wdt", DTZ, POS(36)},      /* West Australian DST */
    {"wed", DOW, 3},
    {"wednesday", DOW, 3},
    {"weds", DOW, 3},
-   {"west", DTZ, 6},           /* Western Europe Summer Time */
-   {"wet", TZ, 0},             /* Western Europe */
-   {"wetdst", DTZ, 6},         /* Western Europe Daylight Savings Time */
-   {"wft", TZ, 72},            /* Wallis and Futuna Time */
-   {"wgst", DTZ, NEG(12)},     /* West Greenland Summer Time */
-   {"wgt", TZ, NEG(18)},       /* West Greenland Time */
-   {"wst", TZ, 48},            /* West Australian Standard Time */
+   {"west", DTZ, POS(4)},      /* Western Europe Summer Time */
+   {"wet", TZ, POS(0)},        /* Western Europe */
+   {"wetdst", DTZ, POS(4)},    /* Western Europe Daylight Savings Time */
+   {"wft", TZ, POS(48)},       /* Wallis and Futuna Time */
+   {"wgst", DTZ, NEG(8)},      /* West Greenland Summer Time */
+   {"wgt", TZ, NEG(12)},       /* West Greenland Time */
+   {"wst", TZ, POS(32)},       /* West Australian Standard Time */
    {"y", UNITS, DTK_YEAR},     /* "year" for ISO input */
-   {"yakst", DTZ, 60},         /* Yakutsk Summer Time */
-   {"yakt", TZ, 54},           /* Yakutsk Time */
-   {"yapt", TZ, 60},           /* Yap Time (Micronesia) */
-   {"ydt", DTZ, NEG(48)},      /* Yukon Daylight Time */
-   {"yekst", DTZ, 36},         /* Yekaterinburg Summer Time */
-   {"yekt", TZ, 30},           /* Yekaterinburg Time */
+   {"yakst", DTZ, POS(40)},    /* Yakutsk Summer Time */
+   {"yakt", TZ, POS(36)},      /* Yakutsk Time */
+   {"yapt", TZ, POS(40)},      /* Yap Time (Micronesia) */
+   {"ydt", DTZ, NEG(32)},      /* Yukon Daylight Time */
+   {"yekst", DTZ, POS(24)},    /* Yekaterinburg Summer Time */
+   {"yekt", TZ, POS(20)},      /* Yekaterinburg Time */
    {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
-   {"yst", TZ, NEG(54)},       /* Yukon Standard Time */
-   {"z", TZ, 0},               /* time zone tag per ISO-8601 */
-   {"zp4", TZ, NEG(24)},       /* UTC +4  hours. */
-   {"zp5", TZ, NEG(30)},       /* UTC +5  hours. */
-   {"zp6", TZ, NEG(36)},       /* UTC +6  hours. */
-   {ZULU, TZ, 0},              /* UTC */
+   {"yst", TZ, NEG(36)},       /* Yukon Standard Time */
+   {"z", TZ, POS(0)},          /* time zone tag per ISO-8601 */
+   {"zp4", TZ, NEG(16)},       /* UTC +4  hours. */
+   {"zp5", TZ, NEG(20)},       /* UTC +5  hours. */
+   {"zp6", TZ, NEG(24)},       /* UTC +6  hours. */
+   {ZULU, TZ, POS(0)},         /* UTC */
 };
 
 static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
 
 /* Used for SET australian_timezones to override North American ones */
 static datetkn australian_datetktbl[] = {
-   {"acst", TZ, 57},           /* Cent. Australia */
-   {"cst", TZ, 63},            /* Australia Central Std Time */
-   {"east", TZ, 60},           /* East Australian Std Time */
-   {"est", TZ, 60},            /* Australia Eastern Std Time */
-   {"sat", TZ, 57},
+   {"acst", TZ, POS(38)},      /* Cent. Australia */
+   {"cst", TZ, POS(42)},       /* Australia Central Std Time */
+   {"east", TZ, POS(40)},      /* East Australian Std Time */
+   {"est", TZ, POS(40)},       /* Australia Eastern Std Time */
+   {"sat", TZ, POS(38)},
 };
 
 static unsigned int australian_szdatetktbl = sizeof australian_datetktbl /
@@ -494,7 +505,7 @@ sizeof australian_datetktbl[0];
 
 static datetkn deltatktbl[] = {
    /* text, token, lexval */
-   {"@", IGNORE_DTF, 0},           /* postgres relative prefix */
+   {"@", IGNORE_DTF, 0},       /* postgres relative prefix */
    {DAGO, AGO, 0},             /* "ago" indicates negative time offset */
    {"c", UNITS, DTK_CENTURY},  /* "century" relative */
    {"cent", UNITS, DTK_CENTURY},       /* "century" relative */
@@ -505,22 +516,22 @@ static datetkn deltatktbl[] = {
    {"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 */
+   {DDECADE, UNITS, DTK_DECADE},   /* "decade" relative */
+   {"decades", UNITS, DTK_DECADE}, /* "decades" relative */
    {"h", UNITS, DTK_HOUR},     /* "hour" relative */
    {DHOUR, UNITS, DTK_HOUR},   /* "hour" relative */
    {"hours", UNITS, DTK_HOUR}, /* "hours" relative */
    {"hr", UNITS, DTK_HOUR},    /* "hour" relative */
    {"hrs", UNITS, DTK_HOUR},   /* "hours" relative */
-   {INVALID, RESERV, DTK_INVALID},     /* reserved for invalid time */
+   {INVALID, RESERV, DTK_INVALID}, /* reserved for invalid time */
    {"m", UNITS, DTK_MINUTE},   /* "minute" relative */
-   {"microsecon", UNITS, DTK_MICROSEC},        /* "microsecond" relative */
-   {"mil", UNITS, DTK_MILLENNIUM},     /* "millennium" relative */
-   {"millennia", UNITS, DTK_MILLENNIUM},       /* "millennia" relative */
-   {DMILLENNIUM, UNITS, DTK_MILLENNIUM},       /* "millennium" relative */
-   {"millisecon", UNITS, DTK_MILLISEC},        /* relative */
-   {"mils", UNITS, DTK_MILLENNIUM},    /* "millennia" relative */
-   {"min", UNITS, DTK_MINUTE}, /* "minute" relative */
+   {"microsecon", UNITS, DTK_MICROSEC},    /* "microsecond" relative */
+   {"mil", UNITS, DTK_MILLENNIUM},         /* "millennium" relative */
+   {"millennia", UNITS, DTK_MILLENNIUM},   /* "millennia" relative */
+   {DMILLENNIUM, UNITS, DTK_MILLENNIUM},   /* "millennium" relative */
+   {"millisecon", UNITS, DTK_MILLISEC},    /* relative */
+   {"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 */
@@ -535,19 +546,19 @@ static datetkn deltatktbl[] = {
    {"mseconds", UNITS, DTK_MILLISEC},
    {"msecs", UNITS, DTK_MILLISEC},
    {"qtr", UNITS, DTK_QUARTER},    /* "quarter" relative */
-   {DQUARTER, UNITS, DTK_QUARTER},     /* "quarter" relative */
+   {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative */
    {"reltime", IGNORE_DTF, 0},     /* pre-v6.1 "Undefined Reltime" */
    {"s", UNITS, DTK_SECOND},
    {"sec", UNITS, DTK_SECOND},
    {DSECOND, UNITS, DTK_SECOND},
    {"seconds", UNITS, DTK_SECOND},
    {"secs", UNITS, DTK_SECOND},
-   {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
+   {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 */
+   {"timezone_m", UNITS, DTK_TZ_MINUTE},   /* timezone minutes units */
    {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
-   {"us", UNITS, DTK_MICROSEC},    /* "microsecond" relative */
+   {"us", UNITS, DTK_MICROSEC},        /* "microsecond" relative */
    {"usec", UNITS, DTK_MICROSEC},      /* "microsecond" relative */
    {DMICROSEC, UNITS, DTK_MICROSEC},   /* "microsecond" relative */
    {"useconds", UNITS, DTK_MICROSEC},  /* "microseconds" relative */
index 5a5b7b491ae89cf7e6b0dbcc3805761b4fc15bb6..e3d78f1f90818890c444b9315dc23699c88fa491 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.30 2002/06/20 20:29:37 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.31 2002/08/04 06:44:47 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,9 +29,6 @@
 #include "mb/pg_wchar.h"
 #endif
 
-
-#define MASK(b) (1 << (b))
-
 #define MAX_INT32_LEN 11
 #define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))
 
@@ -258,52 +255,63 @@ format_type_internal(Oid type_oid, int32 typemod,
        case INTERVALOID:
            if (with_typemod)
            {
-               int         fields = typemod >> 16;
-               int         precision = typemod & 0xFFFF;
+               int         fields = INTERVAL_RANGE(typemod);
+               int         precision = INTERVAL_PRECISION(typemod);
                const char *fieldstr;
 
                switch (fields)
                {
-                   case MASK(YEAR):
+                   case INTERVAL_MASK(YEAR):
                        fieldstr = " year";
                        break;
-                   case MASK(MONTH):
+                   case INTERVAL_MASK(MONTH):
                        fieldstr = " month";
                        break;
-                   case MASK(DAY):
+                   case INTERVAL_MASK(DAY):
                        fieldstr = " day";
                        break;
-                   case MASK(HOUR):
+                   case INTERVAL_MASK(HOUR):
                        fieldstr = " hour";
                        break;
-                   case MASK(MINUTE):
+                   case INTERVAL_MASK(MINUTE):
                        fieldstr = " minute";
                        break;
-                   case MASK(SECOND):
+                   case INTERVAL_MASK(SECOND):
                        fieldstr = " second";
                        break;
-                   case MASK(YEAR) | MASK(MONTH):
+                   case INTERVAL_MASK(YEAR)
+                     | INTERVAL_MASK(MONTH):
                        fieldstr = " year to month";
                        break;
-                   case MASK(DAY) | MASK(HOUR):
+                   case INTERVAL_MASK(DAY)
+                     | INTERVAL_MASK(HOUR):
                        fieldstr = " day to hour";
                        break;
-                   case MASK(DAY) | MASK(HOUR) | MASK(MINUTE):
+                   case INTERVAL_MASK(DAY)
+                     | INTERVAL_MASK(HOUR)
+                     | INTERVAL_MASK(MINUTE):
                        fieldstr = " day to minute";
                        break;
-                   case MASK(DAY) | MASK(HOUR) | MASK(MINUTE) | MASK(SECOND):
+                   case INTERVAL_MASK(DAY)
+                     | INTERVAL_MASK(HOUR)
+                     | INTERVAL_MASK(MINUTE)
+                     | INTERVAL_MASK(SECOND):
                        fieldstr = " day to second";
                        break;
-                   case MASK(HOUR) | MASK(MINUTE):
+                   case INTERVAL_MASK(HOUR)
+                     | INTERVAL_MASK(MINUTE):
                        fieldstr = " hour to minute";
                        break;
-                   case MASK(HOUR) | MASK(MINUTE) | MASK(SECOND):
+                   case INTERVAL_MASK(HOUR)
+                     | INTERVAL_MASK(MINUTE)
+                     | INTERVAL_MASK(SECOND):
                        fieldstr = " hour to second";
                        break;
-                   case MASK(MINUTE) | MASK(SECOND):
+                   case INTERVAL_MASK(MINUTE)
+                     | INTERVAL_MASK(SECOND):
                        fieldstr = " minute to second";
                        break;
-                   case 0x7FFF:
+                   case INTERVAL_FULL_RANGE:
                        fieldstr = "";
                        break;
                    default:
@@ -311,7 +319,7 @@ format_type_internal(Oid type_oid, int32 typemod,
                        fieldstr = "";
                        break;
                }
-               if (precision != 0xFFFF)
+               if (precision != INTERVAL_FULL_PRECISION)
                    buf = psnprintf(100, "interval(%d)%s",
                                    precision, fieldstr);
                else
index fdb144f0e940bec313c86eb5820cb78d4ae80b14..d2e73d1d5e516a4fb16925abd02d6528ff7df031 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.95 2002/06/20 20:29:37 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.96 2002/08/04 06:44:47 thomas Exp $
  *
  * NOTES
  *
@@ -486,8 +486,8 @@ nabstimein(PG_FUNCTION_ARGS)
    int         nf,
                ftype[MAXDATEFIELDS];
 
-   if (strlen(str) > MAXDATELEN)
-       elog(ERROR, "Bad (length) abstime external representation '%s'", str);
+   if (strlen(str) >= sizeof(lowstr))
+       elog(ERROR, "Bad abstime external representation (too long) '%s'", str);
 
    if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
      || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
@@ -849,8 +849,8 @@ reltimein(PG_FUNCTION_ARGS)
                ftype[MAXDATEFIELDS];
    char        lowstr[MAXDATELEN + 1];
 
-   if (strlen(str) > MAXDATELEN)
-       elog(ERROR, "Bad (length) reltime external representation '%s'", str);
+   if (strlen(str) >= sizeof(lowstr))
+       elog(ERROR, "Bad reltime external representation (too long) '%s'", str);
 
    if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
        || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
index 79420310bdf843490834627e02ac533ac5660663..5be34e6199c1c08dfd05de58dc797517ce3d4f37 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.68 2002/06/20 20:29:38 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.69 2002/08/04 06:44:47 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,7 +65,10 @@ timestamp_in(PG_FUNCTION_ARGS)
    int         nf;
    char       *field[MAXDATEFIELDS];
    int         ftype[MAXDATEFIELDS];
-   char        lowstr[MAXDATELEN + 1];
+   char        lowstr[MAXDATELEN + MAXDATEFIELDS];
+
+   if (strlen(str) >= sizeof(lowstr))
+       elog(ERROR, "Bad timestamp external representation (too long) '%s'", str);
 
    if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
      || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
@@ -251,7 +254,11 @@ timestamptz_in(PG_FUNCTION_ARGS)
    int         nf;
    char       *field[MAXDATEFIELDS];
    int         ftype[MAXDATEFIELDS];
-   char        lowstr[MAXDATELEN + 1];
+   char        lowstr[MAXDATELEN + MAXDATEFIELDS];
+
+   if (strlen(str) >= sizeof(lowstr))
+       elog(ERROR, "Bad timestamp with time zone"
+            " external representation (too long) '%s'", str);
 
    if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
      || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
@@ -359,7 +366,7 @@ interval_in(PG_FUNCTION_ARGS)
    int         nf;
    char       *field[MAXDATEFIELDS];
    int         ftype[MAXDATEFIELDS];
-   char        lowstr[MAXDATELEN + 1];
+   char        lowstr[MAXDATELEN + MAXDATEFIELDS];
 
    tm->tm_year = 0;
    tm->tm_mon = 0;
@@ -369,6 +376,9 @@ interval_in(PG_FUNCTION_ARGS)
    tm->tm_sec = 0;
    fsec = 0;
 
+   if (strlen(str) >= sizeof(lowstr))
+       elog(ERROR, "Bad interval external representation (too long) '%s'", str);
+
    if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
        || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
        elog(ERROR, "Bad interval external representation '%s'", str);
@@ -436,8 +446,6 @@ interval_scale(PG_FUNCTION_ARGS)
    PG_RETURN_INTERVAL_P(result);
 }
 
-#define MASK(b) (1 << (b))
-
 static void
 AdjustIntervalForTypmod(Interval *interval, int32 typmod)
 {
@@ -483,31 +491,34 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
    };
 #endif
 
+   /* Unspecified range and precision? Then not necessary to adjust.
+    * Setting typmod to -1 is the convention for all types.
+    */
    if (typmod != -1)
    {
-       int         range = ((typmod >> 16) & 0x7FFF);
-       int         precision = (typmod & 0xFFFF);
+       int         range = INTERVAL_RANGE(typmod);
+       int         precision = INTERVAL_PRECISION(typmod);
 
-       if (range == 0x7FFF)
+       if (range == INTERVAL_FULL_RANGE)
        {
            /* Do nothing... */
        }
-       else if (range == MASK(YEAR))
+       else if (range == INTERVAL_MASK(YEAR))
        {
            interval->month = ((interval->month / 12) * 12);
            interval->time = 0;
        }
-       else if (range == MASK(MONTH))
+       else if (range == INTERVAL_MASK(MONTH))
        {
            interval->month %= 12;
            interval->time = 0;
        }
        /* YEAR TO MONTH */
-       else if (range == (MASK(YEAR) | MASK(MONTH)))
+       else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH)))
        {
            interval->time = 0;
        }
-       else if (range == MASK(DAY))
+       else if (range == INTERVAL_MASK(DAY))
        {
            interval->month = 0;
 #ifdef HAVE_INT64_TIMESTAMP
@@ -517,7 +528,7 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
            interval->time = (((int) (interval->time / 86400)) * 86400);
 #endif
        }
-       else if (range == MASK(HOUR))
+       else if (range == INTERVAL_MASK(HOUR))
        {
 #ifdef HAVE_INT64_TIMESTAMP
            int64       day;
@@ -536,7 +547,7 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
            interval->time = (((int) (interval->time / 3600)) * 3600.0);
 #endif
        }
-       else if (range == MASK(MINUTE))
+       else if (range == INTERVAL_MASK(MINUTE))
        {
 #ifdef HAVE_INT64_TIMESTAMP
            int64       hour;
@@ -555,7 +566,7 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
            interval->time = (((int) (interval->time / 60)) * 60);
 #endif
        }
-       else if (range == MASK(SECOND))
+       else if (range == INTERVAL_MASK(SECOND))
        {
 #ifdef HAVE_INT64_TIMESTAMP
            int64       minute;
@@ -573,7 +584,8 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
 #endif
        }
        /* DAY TO HOUR */
-       else if (range == (MASK(DAY) | MASK(HOUR)))
+       else if (range == (INTERVAL_MASK(DAY) |
+                          INTERVAL_MASK(HOUR)))
        {
            interval->month = 0;
 #ifdef HAVE_INT64_TIMESTAMP
@@ -584,7 +596,9 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
 #endif
        }
        /* DAY TO MINUTE */
-       else if (range == (MASK(DAY) | MASK(HOUR) | MASK(MINUTE)))
+       else if (range == (INTERVAL_MASK(DAY) |
+                          INTERVAL_MASK(HOUR) |
+                          INTERVAL_MASK(MINUTE)))
        {
            interval->month = 0;
 #ifdef HAVE_INT64_TIMESTAMP
@@ -595,12 +609,16 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
 #endif
        }
        /* DAY TO SECOND */
-       else if (range == (MASK(DAY) | MASK(HOUR) | MASK(MINUTE) | MASK(SECOND)))
+       else if (range == (INTERVAL_MASK(DAY) |
+                          INTERVAL_MASK(HOUR) |
+                          INTERVAL_MASK(MINUTE) |
+                          INTERVAL_MASK(SECOND)))
        {
            interval->month = 0;
        }
        /* HOUR TO MINUTE */
-       else if (range == (MASK(HOUR) | MASK(MINUTE)))
+       else if (range == (INTERVAL_MASK(HOUR) |
+                          INTERVAL_MASK(MINUTE)))
        {
 #ifdef HAVE_INT64_TIMESTAMP
            int64       day;
@@ -620,7 +638,9 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
 #endif
        }
        /* HOUR TO SECOND */
-       else if (range == (MASK(HOUR) | MASK(MINUTE) | MASK(SECOND)))
+       else if (range == (INTERVAL_MASK(HOUR) |
+                          INTERVAL_MASK(MINUTE) |
+                          INTERVAL_MASK(SECOND)))
        {
 #ifdef HAVE_INT64_TIMESTAMP
            int64       day;
@@ -637,7 +657,8 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
 #endif
        }
        /* MINUTE TO SECOND */
-       else if (range == (MASK(MINUTE) | MASK(SECOND)))
+       else if (range == (INTERVAL_MASK(MINUTE) |
+                          INTERVAL_MASK(SECOND)))
        {
 #ifdef HAVE_INT64_TIMESTAMP
            int64       hour;
@@ -657,7 +678,7 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
            elog(ERROR, "AdjustIntervalForTypmod(): internal coding error");
 
        /* Need to adjust precision? If not, don't even try! */
-       if (precision != 0xFFFF)
+       if (precision != INTERVAL_FULL_PRECISION)
        {
            if ((precision < 0) || (precision > MAX_INTERVAL_PRECISION))
                elog(ERROR, "INTERVAL(%d) precision must be between %d and %d",
index b3ff70d43bde2afc9ee2f412639894c293349e35..bdcffa954e0fe17aae68363d0ab2e93752c9f2fa 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.86 2002/06/20 20:29:38 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.87 2002/08/04 06:44:47 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -550,7 +550,7 @@ varstr_cmp(char *arg1, int len1, char *arg2, int len2)
    /*
     * Unfortunately, there is no strncoll(), so in the non-C locale
     * case we have to do some memory copying.  This turns out to be
-    * significantly slower, so we optimize the case were LC_COLLATE
+    * significantly slower, so we optimize the case where LC_COLLATE
     * is C.
     */
    if (!lc_collate_is_c())