aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/datetime.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2006-07-25 03:51:23 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2006-07-25 03:51:23 +0000
commitd8b5c95ca8a2ce7cd4062d4a12710ca977bac87c (patch)
treea22dd25471942e3a24edcc2319e03319bed0482b /src/backend/utils/adt/datetime.c
parent631ea6188366ee1b9818fed88d8fadd495246fd7 (diff)
downloadpostgresql-d8b5c95ca8a2ce7cd4062d4a12710ca977bac87c.tar.gz
postgresql-d8b5c95ca8a2ce7cd4062d4a12710ca977bac87c.zip
Remove hard-wired lists of timezone abbreviations in favor of providing
configuration files that can be altered by a DBA. The australian_timezones GUC setting disappears, replaced by a timezone_abbreviations setting (set this to 'Australia' to get the effect of australian_timezones). The list of zone names defined by default has undergone a bit of cleanup, too. Documentation still needs some work --- in particular, should we fix Table B-4, or just get rid of it? Joachim Wieland, with some editorializing by moi.
Diffstat (limited to 'src/backend/utils/adt/datetime.c')
-rw-r--r--src/backend/utils/adt/datetime.c558
1 files changed, 168 insertions, 390 deletions
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index b5478ac3373..f4aceed0aa3 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.168 2006/07/14 05:28:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.169 2006/07/25 03:51:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,11 +19,15 @@
#include <limits.h>
#include <math.h>
+#include "access/heapam.h"
#include "access/xact.h"
+#include "catalog/pg_type.h"
+#include "funcapi.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/datetime.h"
-#include "utils/guc.h"
+#include "utils/memutils.h"
+#include "utils/tzparser.h"
static int DecodeNumber(int flen, char *field, bool haveTextMonth,
@@ -37,7 +41,7 @@ static int DecodeTime(char *str, int fmask, int *tmask,
static int DecodeTimezone(char *str, int *tzp);
static int DecodePosixTimezone(char *str, int *tzp);
static int DecodeZicTimezone(char *str, int *tzp, struct pg_tm * tm);
-static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
+static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
static int DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm);
static void TrimTrailingZeros(char *str);
@@ -87,426 +91,92 @@ char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
* 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 zic time zone database.
- * Not all of them are unique, or even very understandable, so we will
- * leave some commented out for now.
+ * The static table contains no TZ or DTZ entries, rather those are loaded
+ * from configuration files and stored in timezonetktbl, which has the same
+ * format as the static datetktbl.
*/
-static datetkn datetktbl[] = {
+static datetkn *timezonetktbl = NULL;
+
+static int sztimezonetktbl = 0;
+
+static const 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 Summer Time */
- {"act", TZ, NEG(20)}, /* Atlantic/Porto Acre Time */
{DA_D, ADBC, AD}, /* "ad" for years > 0 */
- {"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 */
- {"almst", TZ, POS(28)}, /* Almaty Savings Time */
- {"almt", TZ, POS(24)}, /* Almaty Time */
{"am", AMPM, AM},
- {"amst", DTZ, POS(20)}, /* Armenia Summer Time (Yerevan) */
-#if 0
- {"amst", DTZ, NEG(12)}, /* Amazon Summer Time (Porto Velho) */
-#endif
- {"amt", TZ, POS(16)}, /* Armenia Time (Yerevan) */
-#if 0
- {"amt", TZ, NEG(16)}, /* Amazon Time (Porto Velho) */
-#endif
- {"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
- arst
-#endif
- {"art", TZ, NEG(12)}, /* Argentina Time */
-#if 0
- ashst
- ast /* Atlantic Standard Time, Arabia Standard
- * Time, Acre Standard Time */
-#endif
- {"ast", TZ, NEG(16)}, /* Atlantic Std Time (Canada) */
{"at", IGNORE_DTF, 0}, /* "at" (throwaway) */
{"aug", MONTH, 8},
{"august", MONTH, 8},
- {"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, 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(16)}, /* Bolivia Time */
- {"bra", TZ, NEG(12)}, /* Brazil Time */
- {"brst", DTZ, NEG(8)}, /* Brasilia Summer Time */
- {"brt", TZ, NEG(12)}, /* Brasilia Time */
- {"bst", DTZ, POS(4)}, /* British Summer Time */
-#if 0
- {"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, 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
- ckhst
-#endif
- {"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(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) */
{"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) */
{"dec", MONTH, 12},
{"december", MONTH, 12},
- {"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, POS(24)}, /* Dushanbe Summer Time */
-#endif
- {"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, 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(20)}, /* Eastern Standard Time */
{"feb", MONTH, 2},
{"february", MONTH, 2},
- {"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 */
- {"fnst", DTZ, NEG(4)}, /* Fernando de Noronha Summer Time */
- {"fnt", TZ, NEG(8)}, /* Fernando de Noronha Time */
{"fri", DOW, 5},
{"friday", DOW, 5},
- {"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, POS(48)}, /* Gilbert Islands Time */
- {"gmt", TZ, POS(0)}, /* Greenwich 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(36)}, /* Hawaii/Alaska Daylight Time */
-#if 0
- hkst
-#endif
- {"hkt", TZ, POS(32)}, /* Hong Kong Time */
-#if 0
- {"hmt", TZ, POS(12)}, /* Hellas ? ? */
- hovst
- hovt
-#endif
- {"hst", TZ, NEG(40)}, /* Hawaii Std Time */
-#if 0
- hwt
-#endif
- {"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, 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, POS(8)}, /* Israel */
- {"it", TZ, POS(14)}, /* Iran Time */
{"j", UNITS, DTK_JULIAN},
{"jan", MONTH, 1},
{"january", MONTH, 1},
- {"javt", TZ, POS(28)}, /* Java Time (07:00? see JT) */
- {"jayt", TZ, POS(36)}, /* Jayapura Time (Indonesia) */
{"jd", UNITS, DTK_JULIAN},
- {"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, 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, POS(48)}, /* Magadan Summer Time */
- {"magt", TZ, POS(44)}, /* Magadan Time */
{"mar", MONTH, 3},
{"march", MONTH, 3},
- {"mart", TZ, NEG(38)}, /* Marquesas Time */
- {"mawt", TZ, POS(24)}, /* Mawson, Antarctica */
{"may", MONTH, 5},
- {"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, POS(26)}, /* Myanmar Time */
{"mon", DOW, 1},
{"monday", DOW, 1},
-#if 0
- most
-#endif
- {"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, 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, POS(28)}, /* Novosibirsk Summer Time */
- {"novt", TZ, POS(24)}, /* Novosibirsk Standard Time */
{NOW, RESERV, DTK_NOW}, /* current transaction 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, 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(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, POS(32)}, /* Phillipine Time */
- {"pkt", TZ, POS(20)}, /* Pakistan Time */
{"pm", AMPM, PM},
- {"pmdt", DTZ, NEG(8)}, /* Pierre & Miquelon Daylight Time */
-#if 0
- pmst
-#endif
- {"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, POS(42)}, /* S. Australian Dayl. Time */
-#if 0
- samst
- samt
-#endif
- {"sast", TZ, POS(38)}, /* South Australian Std Time */
{"sat", DOW, 6},
{"saturday", DOW, 6},
-#if 0
- sbt
-#endif
- {"sct", DTZ, POS(16)}, /* Mahe Island Time */
{"sep", MONTH, 9},
{"sept", MONTH, 9},
{"september", MONTH, 9},
- {"set", TZ, NEG(4)}, /* Seychelles Time ?? */
-#if 0
- sgt
-#endif
- {"sst", DTZ, POS(8)}, /* Swedish Summer Time */
{"sun", DOW, 0},
{"sunday", DOW, 0},
- {"swt", TZ, POS(4)}, /* Swedish Winter Time */
-#if 0
- syot
-#endif
{"t", ISOTIME, DTK_TIME}, /* Filler for ISO time fields */
- {"tft", TZ, POS(20)}, /* Kerguelen Time */
- {"that", TZ, NEG(40)}, /* Tahiti Time */
{"thu", DOW, 4},
{"thur", DOW, 4},
{"thurs", DOW, 4},
{"thursday", DOW, 4},
- {"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, POS(52)}, /* Tonga Time */
-#if 0
- tpt
-#endif
- {"truk", TZ, POS(40)}, /* Truk Time */
{"tue", DOW, 2},
{"tues", DOW, 2},
{"tuesday", DOW, 2},
- {"tvt", TZ, POS(48)}, /* Tuvalu Time */
-#if 0
- uct
-#endif
- {"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, 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, POS(44)}, /* Vanuata Time */
- {"wadt", DTZ, POS(32)}, /* West Australian DST */
- {"wakt", TZ, POS(48)}, /* Wake Time */
-#if 0
- warst
-#endif
- {"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, 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, 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(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, 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 /
-sizeof australian_datetktbl[0];
+static int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
static datetkn deltatktbl[] = {
/* text, token, lexval */
@@ -576,11 +246,11 @@ static datetkn deltatktbl[] = {
{"yrs", UNITS, DTK_YEAR}, /* "years" relative */
};
-static unsigned int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
+static int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
-static datetkn *datecache[MAXDATEFIELDS] = {NULL};
+static const datetkn *datecache[MAXDATEFIELDS] = {NULL};
-static datetkn *deltacache[MAXDATEFIELDS] = {NULL};
+static const datetkn *deltacache[MAXDATEFIELDS] = {NULL};
/*
@@ -2998,21 +2668,15 @@ int
DecodeSpecial(int field, char *lowtoken, int *val)
{
int type;
- datetkn *tp;
+ const datetkn *tp;
- if (datecache[field] != NULL &&
- strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0)
- tp = datecache[field];
- else
+ tp = datecache[field];
+ if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
{
- tp = NULL;
- if (Australian_timezones)
- tp = datebsearch(lowtoken, australian_datetktbl,
- australian_szdatetktbl);
- if (!tp)
+ tp = datebsearch(lowtoken, timezonetktbl, sztimezonetktbl);
+ if (tp == NULL)
tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
}
- datecache[field] = tp;
if (tp == NULL)
{
type = UNKNOWN_FIELD;
@@ -3020,6 +2684,7 @@ DecodeSpecial(int field, char *lowtoken, int *val)
}
else
{
+ datecache[field] = tp;
type = tp->type;
switch (type)
{
@@ -3391,20 +3056,20 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
/* DecodeUnits()
* Decode text string using lookup table.
- * This routine supports time interval decoding.
+ * This routine supports time interval decoding
+ * (hence, it need not recognize timezone names).
*/
int
DecodeUnits(int field, char *lowtoken, int *val)
{
int type;
- datetkn *tp;
+ const datetkn *tp;
- if (deltacache[field] != NULL &&
- strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0)
- tp = deltacache[field];
- else
+ tp = deltacache[field];
+ if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
+ {
tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
- deltacache[field] = tp;
+ }
if (tp == NULL)
{
type = UNKNOWN_FIELD;
@@ -3412,6 +3077,7 @@ DecodeUnits(int field, char *lowtoken, int *val)
}
else
{
+ deltacache[field] = tp;
type = tp->type;
if (type == TZ || type == DTZ)
*val = FROMVAL(tp);
@@ -3477,10 +3143,10 @@ DateTimeParseError(int dterr, const char *str, const char *datatype)
* Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this
* is WAY faster than the generic bsearch().
*/
-static datetkn *
-datebsearch(char *key, datetkn *base, unsigned int nel)
+static const datetkn *
+datebsearch(const char *key, const datetkn *base, int nel)
{
- datetkn *last = base + nel - 1,
+ const datetkn *last = base + nel - 1,
*position;
int result;
@@ -4082,30 +3748,15 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str)
} /* EncodeInterval() */
-/* GUC assign_hook for australian_timezones */
-bool
-ClearDateCache(bool newval, bool doit, GucSource source)
-{
- int i;
-
- if (doit)
- {
- for (i = 0; i < MAXDATEFIELDS; i++)
- datecache[i] = NULL;
- }
-
- 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)
+CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
{
bool ok = true;
- unsigned int i;
+ int i;
for (i = 1; i < nel; i++)
{
@@ -4131,8 +3782,135 @@ CheckDateTokenTables(void)
ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
- ok &= CheckDateTokenTable("australian_datetktbl",
- australian_datetktbl,
- australian_szdatetktbl);
return ok;
}
+
+/*
+ * This function gets called during timezone config file load or reload
+ * to create the final array of timezone tokens. The argument array
+ * is already sorted in name order. This data is in a temporary memory
+ * context and must be copied to somewhere permanent.
+ */
+void
+InstallTimeZoneAbbrevs(tzEntry *abbrevs, int n)
+{
+ datetkn *newtbl;
+ int i;
+
+ /*
+ * Copy the data into TopMemoryContext and convert to datetkn format.
+ */
+ newtbl = (datetkn *) MemoryContextAlloc(TopMemoryContext,
+ n * sizeof(datetkn));
+ for (i = 0; i < n; i++)
+ {
+ strncpy(newtbl[i].token, abbrevs[i].abbrev, TOKMAXLEN);
+ newtbl[i].type = abbrevs[i].is_dst ? DTZ : TZ;
+ TOVAL(&newtbl[i], abbrevs[i].offset / 60);
+ }
+
+ /* Check the ordering, if testing */
+ Assert(CheckDateTokenTable("timezone offset", newtbl, n));
+
+ /* Now safe to replace existing table (if any) */
+ if (timezonetktbl)
+ pfree(timezonetktbl);
+ timezonetktbl = newtbl;
+ sztimezonetktbl = n;
+
+ /* clear date cache in case it contains any stale timezone names */
+ for (i = 0; i < MAXDATEFIELDS; i++)
+ datecache[i] = NULL;
+}
+
+/*
+ * This set-returning function reads all the available time zone abbreviations
+ * and returns a set of (name, utc_offset, is_dst).
+ */
+Datum
+pg_timezonenames(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ int *pindex;
+ Datum result;
+ Interval *resInterval;
+ HeapTuple tuple;
+ Datum values[3];
+ bool nulls[3];
+ char buffer[TOKMAXLEN + 1];
+ unsigned char *p;
+ struct pg_tm tm;
+
+ /* stuff done only on the first call of the function */
+ if (SRF_IS_FIRSTCALL())
+ {
+ TupleDesc tupdesc;
+ MemoryContext oldcontext;
+
+ /* create a function context for cross-call persistence */
+ funcctx = SRF_FIRSTCALL_INIT();
+
+ /*
+ * switch to memory context appropriate for multiple function
+ * calls
+ */
+ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+ /* allocate memory for user context */
+ pindex = (int *) palloc(sizeof(int));
+ *pindex = 0;
+ funcctx->user_fctx = (void *) pindex;
+
+ /*
+ * build tupdesc for result tuples. This must match the
+ * definition of the pg_timezonenames view in system_views.sql
+ */
+ tupdesc = CreateTemplateTupleDesc(3, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "utc_offset",
+ INTERVALOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_dst",
+ BOOLOID, -1, 0);
+
+ funcctx->tuple_desc = BlessTupleDesc(tupdesc);
+ MemoryContextSwitchTo(oldcontext);
+ }
+
+ /* stuff done on every call of the function */
+ funcctx = SRF_PERCALL_SETUP();
+ pindex = (int *) funcctx->user_fctx;
+
+ if (*pindex >= sztimezonetktbl)
+ SRF_RETURN_DONE(funcctx);
+
+ MemSet(nulls, 0, sizeof(nulls));
+
+ /*
+ * Convert name to text, using upcasing conversion that is the inverse
+ * of what ParseDateTime() uses.
+ */
+ strncpy(buffer, timezonetktbl[*pindex].token, TOKMAXLEN);
+ buffer[TOKMAXLEN] = '\0'; /* may not be null-terminated */
+ for (p = (unsigned char *) buffer; *p; p++)
+ *p = pg_toupper(*p);
+
+ values[0] = DirectFunctionCall1(textin, CStringGetDatum(buffer));
+
+ MemSet(&tm, 0, sizeof(struct pg_tm));
+ tm.tm_min = (-1) * FROMVAL(&timezonetktbl[*pindex]);
+ resInterval = (Interval *) palloc(sizeof(Interval));
+ tm2interval(&tm, 0, resInterval);
+ values[1] = IntervalPGetDatum(resInterval);
+
+ Assert(timezonetktbl[*pindex].type == DTZ ||
+ timezonetktbl[*pindex].type == TZ);
+ values[2] = BoolGetDatum(timezonetktbl[*pindex].type == DTZ);
+
+ (*pindex)++;
+
+ tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
+ result = HeapTupleGetDatum(tuple);
+
+ SRF_RETURN_NEXT(funcctx, result);
+}