From: Bruce Momjian Date: Tue, 19 Apr 2005 03:13:59 +0000 (+0000) Subject: Attached patch gets rid of the global timezone in the following steps: X-Git-Tag: REL9_0_0~10386 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=aa8bdab272b6def93864797a31ebe34814d0f4bb;p=pg-rex%2Fsyncrep.git Attached patch gets rid of the global timezone in the following steps: * Changes the APIs to the timezone functions to take a pg_tz pointer as an argument, representing the timezone to use for the selected operation. * Adds a global_timezone variable that represents the current timezone in the backend as set by SET TIMEZONE (or guc, or env, etc). * Implements a hash-table cache of loaded tables, so we don't have to read and parse the TZ file everytime we change a timezone. While not necesasry now (we don't change timezones very often), I beleive this will be necessary (or at least good) when "multiple timezones in the same query" is eventually implemented. And code-wise, this was the time to do it. There are no user-visible changes at this time. Implementing the "multiple zones in one query" is a later step... This also gets rid of some of the cruft needed to "back out a timezone change", since we previously couldn't check a timezone unless it was activated first. Passes regression tests on win32, linux (slackware 10) and solaris x86. Magnus Hagander --- diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 7add658d6a..e776204062 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.105 2004/12/31 21:59:42 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.106 2005/04/19 03:13:58 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -315,13 +315,13 @@ assign_timezone(const char *value, bool doit, GucSource source) * UNKNOWN as the canonical spelling. * * During GUC initialization, since the timezone library isn't - * set up yet, pg_get_current_timezone will return NULL and we + * set up yet, pg_get_timezone_name will return NULL and we * will leave the setting as UNKNOWN. If this isn't * overridden from the config file then * pg_timezone_initialize() will eventually select a default * value from the environment. */ - const char *curzone = pg_get_current_timezone(); + const char *curzone = pg_get_timezone_name(global_timezone); if (curzone) value = curzone; @@ -329,90 +329,36 @@ assign_timezone(const char *value, bool doit, GucSource source) else { /* - * Otherwise assume it is a timezone name. - * - * We have to actually apply the change before we can have any - * hope of checking it. So, save the old value in case we - * have to back out. We have to copy since - * pg_get_current_timezone returns a pointer to its static - * state. - * - * This would all get a lot simpler if the TZ library had a - * better API that would let us look up and test a timezone - * name without making it the default. + * Otherwise assume it is a timezone name, and try to load it. */ - const char *cur_tz; - char *save_tz; - bool known, - acceptable; + pg_tz *new_tz; - cur_tz = pg_get_current_timezone(); - if (cur_tz) - save_tz = pstrdup(cur_tz); - else - save_tz = NULL; + new_tz = pg_tzset(value); - known = pg_tzset(value); - acceptable = known ? tz_acceptable() : false; + if (!new_tz) + { + ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized time zone name: \"%s\"", + value))); + return NULL; + } - if (doit && known && acceptable) + if (!tz_acceptable(new_tz)) { - /* Keep the changed TZ */ - HasCTZSet = false; + ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("time zone \"%s\" appears to use leap seconds", + value), + errdetail("PostgreSQL does not support leap seconds."))); + return NULL; } - else + + if (doit) { - /* - * Revert to prior TZ setting; note we haven't changed - * HasCTZSet in this path, so if we were previously using - * a fixed offset, we still are. - */ - if (save_tz) - pg_tzset(save_tz); - else - { - /* - * TZ library wasn't initialized yet. Annoyingly, we - * will come here during startup because guc-file.l - * checks the value with doit = false before actually - * applying. The best approach seems to be as follows: - * - * 1. known && acceptable: leave the setting in place, - * since we'll apply it soon anyway. This is mainly - * so that any log messages printed during this - * interval are timestamped with the user's requested - * timezone. - * - * 2. known && !acceptable: revert to GMT for lack of any - * better idea. (select_default_timezone() may get - * called later to undo this.) - * - * 3. !known: no need to do anything since TZ library did - * not change its state. - * - * Again, this should all go away sometime soon. - */ - if (known && !acceptable) - pg_tzset("GMT"); - } - /* Complain if it was bad */ - if (!known) - { - ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized time zone name: \"%s\"", - value))); - return NULL; - } - if (!acceptable) - { - ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("time zone \"%s\" appears to use leap seconds", - value), - errdetail("PostgreSQL does not support leap seconds."))); - return NULL; - } + /* Save the changed TZ */ + global_timezone = new_tz; + HasCTZSet = false; } } } @@ -459,7 +405,7 @@ show_timezone(void) IntervalPGetDatum(&interval))); } else - tzn = pg_get_current_timezone(); + tzn = pg_get_timezone_name(global_timezone); if (tzn != NULL) return tzn; diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index d019127c79..1899d8f21a 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -18,7 +18,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.14 2005/03/12 01:54:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.15 2005/04/19 03:13:59 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -833,7 +833,7 @@ logfile_getname(pg_time_t timestamp) if (strchr(Log_filename, '%')) { /* treat it as a strftime pattern */ - tm = pg_localtime(×tamp); + tm = pg_localtime(×tamp, global_timezone); pg_strftime(filename + len, MAXPGPATH - len, Log_filename, tm); } else @@ -868,7 +868,7 @@ set_next_rotation_time(void) */ rotinterval = Log_RotationAge * 60; /* convert to seconds */ now = time(NULL); - tm = pg_localtime(&now); + tm = pg_localtime(&now, global_timezone); now += tm->tm_gmtoff; now -= now % rotinterval; now += rotinterval; diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 47dc28d132..0ac92c304b 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.137 2005/01/11 18:33:45 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.138 2005/04/19 03:13:59 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1634,7 +1634,8 @@ DetermineLocalTimeZone(struct pg_tm * tm) res = pg_next_dst_boundary(&prevtime, &before_gmtoff, &before_isdst, &boundary, - &after_gmtoff, &after_isdst); + &after_gmtoff, &after_isdst, + global_timezone); if (res < 0) goto overflow; /* failure? */ diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c index 4e2069f5fb..631c700c5a 100644 --- a/src/backend/utils/adt/nabstime.c +++ b/src/backend/utils/adt/nabstime.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.127 2004/12/31 22:01:22 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.128 2005/04/19 03:13:59 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -192,7 +192,7 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm * tm, char **tzn) time -= CTimeZone; if ((!HasCTZSet) && (tzp != NULL)) - tx = pg_localtime(&time); + tx = pg_localtime(&time,global_timezone); else tx = pg_gmtime(&time); @@ -1677,7 +1677,7 @@ timeofday(PG_FUNCTION_ARGS) gettimeofday(&tp, &tpz); tt = (pg_time_t) tp.tv_sec; pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z", - pg_localtime(&tt)); + pg_localtime(&tt,global_timezone)); snprintf(buf, sizeof(buf), templ, tp.tv_usec); len = VARHDRSZ + strlen(buf); diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 1f82b2fec9..1da473dbfb 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.118 2005/04/01 14:25:23 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.119 2005/04/19 03:13:59 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1078,7 +1078,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn utime = (pg_time_t) dt; if ((Timestamp) utime == dt) { - struct pg_tm *tx = pg_localtime(&utime); + struct pg_tm *tx = pg_localtime(&utime, global_timezone); tm->tm_year = tx->tm_year + 1900; tm->tm_mon = tx->tm_mon + 1; diff --git a/src/include/pgtime.h b/src/include/pgtime.h index 8b38945f4c..b3322234e1 100644 --- a/src/include/pgtime.h +++ b/src/include/pgtime.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/include/pgtime.h,v 1.6 2004/12/31 22:03:19 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/pgtime.h,v 1.7 2005/04/19 03:13:59 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -37,21 +37,24 @@ struct pg_tm const char *tm_zone; }; -extern struct pg_tm *pg_localtime(const pg_time_t *timep); +typedef struct pg_tz pg_tz; + +extern struct pg_tm *pg_localtime(const pg_time_t *timep, const pg_tz *tz); extern struct pg_tm *pg_gmtime(const pg_time_t *timep); extern int pg_next_dst_boundary(const pg_time_t *timep, long int *before_gmtoff, int *before_isdst, pg_time_t *boundary, long int *after_gmtoff, - int *after_isdst); + int *after_isdst, + const pg_tz *tz); extern size_t pg_strftime(char *s, size_t max, const char *format, const struct pg_tm * tm); extern void pg_timezone_initialize(void); -extern bool pg_tzset(const char *tzname); -extern bool tz_acceptable(void); -extern const char *select_default_timezone(void); -extern const char *pg_get_current_timezone(void); +extern pg_tz *pg_tzset(const char *tzname); +extern bool tz_acceptable(pg_tz *tz); +extern const char *pg_get_timezone_name(pg_tz *tz); +extern pg_tz *global_timezone; #endif /* _PGTIME_H */ diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c index 8e64f065b4..28b8f289a2 100644 --- a/src/timezone/localtime.c +++ b/src/timezone/localtime.c @@ -3,7 +3,7 @@ * 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/localtime.c,v 1.9 2004/11/01 21:34:44 tgl Exp $ + * $PostgreSQL: pgsql/src/timezone/localtime.c,v 1.10 2005/04/19 03:13:59 momjian Exp $ */ /* @@ -16,8 +16,8 @@ #include -#include "pgtz.h" #include "private.h" +#include "pgtz.h" #include "tzfile.h" @@ -58,37 +58,6 @@ static const char gmt[] = "GMT"; */ #define TZDEFRULESTRING ",M4.1.0,M10.5.0" -struct ttinfo -{ /* time type information */ - long tt_gmtoff; /* UTC offset in seconds */ - int tt_isdst; /* used to set tm_isdst */ - int tt_abbrind; /* abbreviation list index */ - int tt_ttisstd; /* TRUE if transition is std time */ - int tt_ttisgmt; /* TRUE if transition is UTC */ -}; - -struct lsinfo -{ /* leap second information */ - pg_time_t ls_trans; /* transition time */ - long ls_corr; /* correction to apply */ -}; - -#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) - -struct state -{ - int leapcnt; - int timecnt; - int typecnt; - int charcnt; - pg_time_t ats[TZ_MAX_TIMES]; - unsigned char types[TZ_MAX_TIMES]; - struct ttinfo ttis[TZ_MAX_TYPES]; - char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), - (2 * (TZ_STRLEN_MAX + 1)))]; - struct lsinfo lsis[TZ_MAX_LEAPS]; -}; - struct rule { int r_type; /* type of rule--see below */ @@ -115,22 +84,19 @@ static const char *getoffset(const char *strp, long *offsetp); static const char *getrule(const char *strp, struct rule * rulep); static void gmtload(struct state * sp); static void gmtsub(const pg_time_t *timep, long offset, struct pg_tm * tmp); -static void localsub(const pg_time_t *timep, long offset, struct pg_tm * tmp); +static void localsub(const pg_time_t *timep, long offset, struct pg_tm * tmp, const pg_tz *tz); static void timesub(const pg_time_t *timep, long offset, const struct state * sp, struct pg_tm * tmp); static pg_time_t transtime(pg_time_t janfirst, int year, - const struct rule * rulep, long offset); -static int tzload(const char *name, struct state * sp); -static int tzparse(const char *name, struct state * sp, int lastditch); + const struct rule * rulep, long offset); +int tzparse(const char *name, struct state * sp, int lastditch); -static struct state lclmem; +/* GMT timezone */ static struct state gmtmem; -#define lclptr (&lclmem) #define gmtptr (&gmtmem) -static char lcl_TZname[TZ_STRLEN_MAX + 1]; -static int lcl_is_set = 0; + static int gmt_is_set = 0; /* @@ -156,7 +122,7 @@ detzcode(const char *codep) return result; } -static int +int tzload(register const char *name, register struct state * sp) { register const char *p; @@ -589,7 +555,7 @@ transtime(const pg_time_t janfirst, const int year, * appropriate. */ -static int +int tzparse(const char *name, register struct state * sp, const int lastditch) { const char *stdname; @@ -839,30 +805,6 @@ gmtload(struct state * sp) } -bool -pg_tzset(const char *name) -{ - if (lcl_is_set && strcmp(lcl_TZname, name) == 0) - return true; /* no change */ - - if (strlen(name) >= sizeof(lcl_TZname)) - return false; /* not gonna fit */ - - if (tzload(name, lclptr) != 0) - { - if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) - { - /* Unknown timezone. Fail our call instead of loading GMT! */ - return false; - } - } - - strcpy(lcl_TZname, name); - lcl_is_set = true; - - return true; -} - /* * The easy way to behave "as if no library function calls" localtime * is to not call it--so we drop its guts into "localsub", which can be @@ -872,14 +814,14 @@ pg_tzset(const char *name) * The unused offset argument is for the benefit of mktime variants. */ static void -localsub(const pg_time_t *timep, const long offset, struct pg_tm * tmp) +localsub(const pg_time_t *timep, const long offset, struct pg_tm * tmp, const pg_tz *tz) { - register struct state *sp; + register const struct state *sp; register const struct ttinfo *ttisp; register int i; const pg_time_t t = *timep; - sp = lclptr; + sp = &tz->state; if (sp->timecnt == 0 || t < sp->ats[0]) { i = 0; @@ -906,9 +848,9 @@ localsub(const pg_time_t *timep, const long offset, struct pg_tm * tmp) struct pg_tm * -pg_localtime(const pg_time_t *timep) +pg_localtime(const pg_time_t *timep, const pg_tz *tz) { - localsub(timep, 0L, &tm); + localsub(timep, 0L, &tm, tz); return &tm; } @@ -1084,15 +1026,16 @@ pg_next_dst_boundary(const pg_time_t *timep, int *before_isdst, pg_time_t *boundary, long int *after_gmtoff, - int *after_isdst) + int *after_isdst, + const pg_tz *tz) { - register struct state *sp; + register const struct state *sp; register const struct ttinfo *ttisp; int i; int j; const pg_time_t t = *timep; - sp = lclptr; + sp = &tz->state; if (sp->timecnt == 0) { /* non-DST zone, use lowest-numbered standard type */ @@ -1158,9 +1101,9 @@ pg_next_dst_boundary(const pg_time_t *timep, * Return the name of the current timezone */ const char * -pg_get_current_timezone(void) +pg_get_timezone_name(pg_tz *tz) { - if (lcl_is_set) - return lcl_TZname; + if (tz) + return tz->TZname; return NULL; } diff --git a/src/timezone/pgtz.c b/src/timezone/pgtz.c index 599aaac4ef..f228ed5bac 100644 --- a/src/timezone/pgtz.c +++ b/src/timezone/pgtz.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.29 2004/12/31 22:03:59 pgsql Exp $ + * $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.30 2005/04/19 03:13:59 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -26,12 +26,18 @@ #include "utils/datetime.h" #include "utils/elog.h" #include "utils/guc.h" +#include "utils/hsearch.h" + +/* Current global timezone */ +pg_tz *global_timezone = NULL; static char tzdir[MAXPGPATH]; static int done_tzdir = 0; static const char *identify_system_timezone(void); +static const char *select_default_timezone(void); +static bool set_global_timezone(const char *tzname); /* @@ -156,12 +162,14 @@ score_timezone(const char *tzname, struct tztry * tt) struct tm *systm; struct pg_tm *pgtm; char cbuf[TZ_STRLEN_MAX + 1]; + pg_tz *tz; - if (!pg_tzset(tzname)) + tz = pg_tzset(tzname); + if (!tz) return -1; /* can't handle the TZ name at all */ /* Reject if leap seconds involved */ - if (!tz_acceptable()) + if (!tz_acceptable(tz)) { elog(DEBUG4, "Reject TZ \"%s\": uses leap seconds", tzname); return -1; @@ -171,7 +179,7 @@ score_timezone(const char *tzname, struct tztry * tt) for (i = 0; i < tt->n_test_times; i++) { pgtt = (pg_time_t) (tt->test_times[i]); - pgtm = pg_localtime(&pgtt); + pgtm = pg_localtime(&pgtt, tz); if (!pgtm) return -1; /* probably shouldn't happen */ systm = localtime(&(tt->test_times[i])); @@ -957,6 +965,82 @@ identify_system_timezone(void) #endif /* WIN32 */ + +/* + * We keep loaded timezones in a hashtable so we don't have to + * load and parse the TZ definition file every time it is selected. + */ +static HTAB *timezone_cache = NULL; +static bool +init_timezone_hashtable(void) +{ + HASHCTL hash_ctl; + + MemSet(&hash_ctl, 0, sizeof(hash_ctl)); + + hash_ctl.keysize = TZ_STRLEN_MAX; + hash_ctl.entrysize = sizeof(pg_tz); + + timezone_cache = hash_create("Timezones", + 31, + &hash_ctl, + HASH_ELEM); + if (!timezone_cache) + return false; + + return true; +} + +/* + * Load a timezone from file or from cache. + * Does not verify that the timezone is acceptable! + */ +struct pg_tz * +pg_tzset(const char *name) +{ + pg_tz *tzp; + pg_tz tz; + + if (strlen(name) >= TZ_STRLEN_MAX) + return NULL; /* not going to fit */ + + if (!timezone_cache) + if (!init_timezone_hashtable()) + return NULL; + + tzp = (pg_tz *)hash_search(timezone_cache, + name, + HASH_FIND, + NULL); + if (tzp) + /* Timezone found in cache, nothing more to do */ + return tzp; + + if (tzload(name, &tz.state) != 0) + { + if (name[0] == ':' || tzparse(name, &tz.state, FALSE) != 0) + /* Unknown timezone. Fail our call instead of loading GMT! */ + return NULL; + } + + strcpy(tz.TZname, name); + + /* Save timezone in the cache */ + tzp = hash_search(timezone_cache, + name, + HASH_ENTER, + NULL); + + if (!tzp) + return NULL; + + strcpy(tzp->TZname, tz.TZname); + memcpy(&tzp->state, &tz.state, sizeof(tz.state)); + + return tzp; +} + + /* * Check whether timezone is acceptable. * @@ -968,7 +1052,7 @@ identify_system_timezone(void) * it can restore the old value of TZ if we don't like the new one. */ bool -tz_acceptable(void) +tz_acceptable(pg_tz *tz) { struct pg_tm *tt; pg_time_t time2000; @@ -979,13 +1063,36 @@ tz_acceptable(void) * any other result has to be due to leap seconds. */ time2000 = (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400; - tt = pg_localtime(&time2000); + tt = pg_localtime(&time2000, tz); if (!tt || tt->tm_sec != 0) return false; return true; } + +/* + * Set the global timezone. Verify that it's acceptable first. + */ +static bool +set_global_timezone(const char *tzname) +{ + pg_tz *tznew; + + if (!tzname || !tzname[0]) + return false; + + tznew = pg_tzset(tzname); + if (!tznew) + return false; + + if (!tz_acceptable(tznew)) + return false; + + global_timezone = tznew; + return true; +} + /* * Identify a suitable default timezone setting based on the environment, * and make it active. @@ -995,20 +1102,20 @@ tz_acceptable(void) * from the behavior of the system timezone library. When all else fails, * fall back to GMT. */ -const char * +static const char * select_default_timezone(void) { const char *def_tz; def_tz = getenv("TZ"); - if (def_tz && pg_tzset(def_tz) && tz_acceptable()) + if (set_global_timezone(def_tz)) return def_tz; def_tz = identify_system_timezone(); - if (def_tz && pg_tzset(def_tz) && tz_acceptable()) + if (set_global_timezone(def_tz)) return def_tz; - if (pg_tzset("GMT") && tz_acceptable()) + if (set_global_timezone("GMT")) return "GMT"; ereport(FATAL, diff --git a/src/timezone/pgtz.h b/src/timezone/pgtz.h index 6c05198aed..e325dec483 100644 --- a/src/timezone/pgtz.h +++ b/src/timezone/pgtz.h @@ -9,15 +9,57 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/pgtz.h,v 1.10 2004/12/31 22:03:59 pgsql Exp $ + * $PostgreSQL: pgsql/src/timezone/pgtz.h,v 1.11 2005/04/19 03:13:59 momjian Exp $ * *------------------------------------------------------------------------- */ #ifndef _PGTZ_H #define _PGTZ_H +#include "tzfile.h" + #define TZ_STRLEN_MAX 255 extern char *pg_TZDIR(void); +#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) + +struct ttinfo +{ /* time type information */ + long tt_gmtoff; /* UTC offset in seconds */ + int tt_isdst; /* used to set tm_isdst */ + int tt_abbrind; /* abbreviation list index */ + int tt_ttisstd; /* TRUE if transition is std time */ + int tt_ttisgmt; /* TRUE if transition is UTC */ +}; + +struct lsinfo +{ /* leap second information */ + pg_time_t ls_trans; /* transition time */ + long ls_corr; /* correction to apply */ +}; + +struct state +{ + int leapcnt; + int timecnt; + int typecnt; + int charcnt; + pg_time_t ats[TZ_MAX_TIMES]; + unsigned char types[TZ_MAX_TIMES]; + struct ttinfo ttis[TZ_MAX_TYPES]; + char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, 3 /* sizeof gmt */), + (2 * (TZ_STRLEN_MAX + 1)))]; + struct lsinfo lsis[TZ_MAX_LEAPS]; +}; + + +struct pg_tz { + char TZname[TZ_STRLEN_MAX + 1]; + struct state state; +}; + +int tzload(const char *name, struct state * sp); +int tzparse(const char *name, struct state * sp, int lastditch); + #endif /* _PGTZ_H */ diff --git a/src/timezone/strftime.c b/src/timezone/strftime.c index c23ae7cb6f..cc45527fe4 100644 --- a/src/timezone/strftime.c +++ b/src/timezone/strftime.c @@ -15,7 +15,7 @@ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/strftime.c,v 1.5 2004/08/29 05:07:02 momjian Exp $ + * $PostgreSQL: pgsql/src/timezone/strftime.c,v 1.6 2005/04/19 03:13:59 momjian Exp $ */ #include "postgres.h" @@ -23,8 +23,8 @@ #include #include -#include "pgtz.h" #include "private.h" +#include "pgtz.h" #include "tzfile.h" diff --git a/src/timezone/zic.c b/src/timezone/zic.c index 5cc2432998..1d3695b659 100644 --- a/src/timezone/zic.c +++ b/src/timezone/zic.c @@ -3,7 +3,7 @@ * 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/zic.c,v 1.13 2004/09/27 19:16:03 momjian Exp $ + * $PostgreSQL: pgsql/src/timezone/zic.c,v 1.14 2005/04/19 03:13:59 momjian Exp $ */ #include "postgres.h" @@ -14,8 +14,8 @@ #include #include -#include "pgtz.h" #include "private.h" +#include "pgtz.h" #include "tzfile.h" #ifdef HAVE_SYS_STAT_H