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
This commit is contained in:
parent
dd39dd232f
commit
aa8bdab272
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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.
|
* UNKNOWN as the canonical spelling.
|
||||||
*
|
*
|
||||||
* During GUC initialization, since the timezone library isn't
|
* 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
|
* will leave the setting as UNKNOWN. If this isn't
|
||||||
* overridden from the config file then
|
* overridden from the config file then
|
||||||
* pg_timezone_initialize() will eventually select a default
|
* pg_timezone_initialize() will eventually select a default
|
||||||
* value from the environment.
|
* value from the environment.
|
||||||
*/
|
*/
|
||||||
const char *curzone = pg_get_current_timezone();
|
const char *curzone = pg_get_timezone_name(global_timezone);
|
||||||
|
|
||||||
if (curzone)
|
if (curzone)
|
||||||
value = curzone;
|
value = curzone;
|
||||||
@ -329,74 +329,13 @@ assign_timezone(const char *value, bool doit, GucSource source)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Otherwise assume it is a timezone name.
|
* Otherwise assume it is a timezone name, and try to load it.
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
const char *cur_tz;
|
pg_tz *new_tz;
|
||||||
char *save_tz;
|
|
||||||
bool known,
|
|
||||||
acceptable;
|
|
||||||
|
|
||||||
cur_tz = pg_get_current_timezone();
|
new_tz = pg_tzset(value);
|
||||||
if (cur_tz)
|
|
||||||
save_tz = pstrdup(cur_tz);
|
|
||||||
else
|
|
||||||
save_tz = NULL;
|
|
||||||
|
|
||||||
known = pg_tzset(value);
|
if (!new_tz)
|
||||||
acceptable = known ? tz_acceptable() : false;
|
|
||||||
|
|
||||||
if (doit && known && acceptable)
|
|
||||||
{
|
|
||||||
/* Keep the changed TZ */
|
|
||||||
HasCTZSet = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* 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,
|
ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
@ -404,7 +343,8 @@ assign_timezone(const char *value, bool doit, GucSource source)
|
|||||||
value)));
|
value)));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!acceptable)
|
|
||||||
|
if (!tz_acceptable(new_tz))
|
||||||
{
|
{
|
||||||
ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
|
ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
@ -413,6 +353,12 @@ assign_timezone(const char *value, bool doit, GucSource source)
|
|||||||
errdetail("PostgreSQL does not support leap seconds.")));
|
errdetail("PostgreSQL does not support leap seconds.")));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (doit)
|
||||||
|
{
|
||||||
|
/* Save the changed TZ */
|
||||||
|
global_timezone = new_tz;
|
||||||
|
HasCTZSet = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -459,7 +405,7 @@ show_timezone(void)
|
|||||||
IntervalPGetDatum(&interval)));
|
IntervalPGetDatum(&interval)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tzn = pg_get_current_timezone();
|
tzn = pg_get_timezone_name(global_timezone);
|
||||||
|
|
||||||
if (tzn != NULL)
|
if (tzn != NULL)
|
||||||
return tzn;
|
return tzn;
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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, '%'))
|
if (strchr(Log_filename, '%'))
|
||||||
{
|
{
|
||||||
/* treat it as a strftime pattern */
|
/* 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);
|
pg_strftime(filename + len, MAXPGPATH - len, Log_filename, tm);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -868,7 +868,7 @@ set_next_rotation_time(void)
|
|||||||
*/
|
*/
|
||||||
rotinterval = Log_RotationAge * 60; /* convert to seconds */
|
rotinterval = Log_RotationAge * 60; /* convert to seconds */
|
||||||
now = time(NULL);
|
now = time(NULL);
|
||||||
tm = pg_localtime(&now);
|
tm = pg_localtime(&now, global_timezone);
|
||||||
now += tm->tm_gmtoff;
|
now += tm->tm_gmtoff;
|
||||||
now -= now % rotinterval;
|
now -= now % rotinterval;
|
||||||
now += rotinterval;
|
now += rotinterval;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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,
|
res = pg_next_dst_boundary(&prevtime,
|
||||||
&before_gmtoff, &before_isdst,
|
&before_gmtoff, &before_isdst,
|
||||||
&boundary,
|
&boundary,
|
||||||
&after_gmtoff, &after_isdst);
|
&after_gmtoff, &after_isdst,
|
||||||
|
global_timezone);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto overflow; /* failure? */
|
goto overflow; /* failure? */
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
time -= CTimeZone;
|
||||||
|
|
||||||
if ((!HasCTZSet) && (tzp != NULL))
|
if ((!HasCTZSet) && (tzp != NULL))
|
||||||
tx = pg_localtime(&time);
|
tx = pg_localtime(&time,global_timezone);
|
||||||
else
|
else
|
||||||
tx = pg_gmtime(&time);
|
tx = pg_gmtime(&time);
|
||||||
|
|
||||||
@ -1677,7 +1677,7 @@ timeofday(PG_FUNCTION_ARGS)
|
|||||||
gettimeofday(&tp, &tpz);
|
gettimeofday(&tp, &tpz);
|
||||||
tt = (pg_time_t) tp.tv_sec;
|
tt = (pg_time_t) tp.tv_sec;
|
||||||
pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
|
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);
|
snprintf(buf, sizeof(buf), templ, tp.tv_usec);
|
||||||
|
|
||||||
len = VARHDRSZ + strlen(buf);
|
len = VARHDRSZ + strlen(buf);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
utime = (pg_time_t) dt;
|
||||||
if ((Timestamp) utime == 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_year = tx->tm_year + 1900;
|
||||||
tm->tm_mon = tx->tm_mon + 1;
|
tm->tm_mon = tx->tm_mon + 1;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
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 struct pg_tm *pg_gmtime(const pg_time_t *timep);
|
||||||
extern int pg_next_dst_boundary(const pg_time_t *timep,
|
extern int pg_next_dst_boundary(const pg_time_t *timep,
|
||||||
long int *before_gmtoff,
|
long int *before_gmtoff,
|
||||||
int *before_isdst,
|
int *before_isdst,
|
||||||
pg_time_t *boundary,
|
pg_time_t *boundary,
|
||||||
long int *after_gmtoff,
|
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,
|
extern size_t pg_strftime(char *s, size_t max, const char *format,
|
||||||
const struct pg_tm * tm);
|
const struct pg_tm * tm);
|
||||||
|
|
||||||
extern void pg_timezone_initialize(void);
|
extern void pg_timezone_initialize(void);
|
||||||
extern bool pg_tzset(const char *tzname);
|
extern pg_tz *pg_tzset(const char *tzname);
|
||||||
extern bool tz_acceptable(void);
|
extern bool tz_acceptable(pg_tz *tz);
|
||||||
extern const char *select_default_timezone(void);
|
extern const char *pg_get_timezone_name(pg_tz *tz);
|
||||||
extern const char *pg_get_current_timezone(void);
|
|
||||||
|
|
||||||
|
extern pg_tz *global_timezone;
|
||||||
#endif /* _PGTIME_H */
|
#endif /* _PGTIME_H */
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
|
* 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "pgtz.h"
|
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
|
#include "pgtz.h"
|
||||||
#include "tzfile.h"
|
#include "tzfile.h"
|
||||||
|
|
||||||
|
|
||||||
@ -58,37 +58,6 @@ static const char gmt[] = "GMT";
|
|||||||
*/
|
*/
|
||||||
#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
|
#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
|
struct rule
|
||||||
{
|
{
|
||||||
int r_type; /* type of rule--see below */
|
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 const char *getrule(const char *strp, struct rule * rulep);
|
||||||
static void gmtload(struct state * sp);
|
static void gmtload(struct state * sp);
|
||||||
static void gmtsub(const pg_time_t *timep, long offset, struct pg_tm * tmp);
|
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,
|
static void timesub(const pg_time_t *timep, long offset,
|
||||||
const struct state * sp, struct pg_tm * tmp);
|
const struct state * sp, struct pg_tm * tmp);
|
||||||
static pg_time_t transtime(pg_time_t janfirst, int year,
|
static pg_time_t transtime(pg_time_t janfirst, int year,
|
||||||
const struct rule * rulep, long offset);
|
const struct rule * rulep, long offset);
|
||||||
static int tzload(const char *name, struct state * sp);
|
int tzparse(const char *name, struct state * sp, int lastditch);
|
||||||
static int tzparse(const char *name, struct state * sp, int lastditch);
|
|
||||||
|
|
||||||
static struct state lclmem;
|
/* GMT timezone */
|
||||||
static struct state gmtmem;
|
static struct state gmtmem;
|
||||||
|
|
||||||
#define lclptr (&lclmem)
|
|
||||||
#define gmtptr (&gmtmem)
|
#define gmtptr (&gmtmem)
|
||||||
|
|
||||||
static char lcl_TZname[TZ_STRLEN_MAX + 1];
|
|
||||||
static int lcl_is_set = 0;
|
|
||||||
static int gmt_is_set = 0;
|
static int gmt_is_set = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -156,7 +122,7 @@ detzcode(const char *codep)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
tzload(register const char *name, register struct state * sp)
|
tzload(register const char *name, register struct state * sp)
|
||||||
{
|
{
|
||||||
register const char *p;
|
register const char *p;
|
||||||
@ -589,7 +555,7 @@ transtime(const pg_time_t janfirst, const int year,
|
|||||||
* appropriate.
|
* appropriate.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
int
|
||||||
tzparse(const char *name, register struct state * sp, const int lastditch)
|
tzparse(const char *name, register struct state * sp, const int lastditch)
|
||||||
{
|
{
|
||||||
const char *stdname;
|
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
|
* 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
|
* 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.
|
* The unused offset argument is for the benefit of mktime variants.
|
||||||
*/
|
*/
|
||||||
static void
|
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 const struct ttinfo *ttisp;
|
||||||
register int i;
|
register int i;
|
||||||
const pg_time_t t = *timep;
|
const pg_time_t t = *timep;
|
||||||
|
|
||||||
sp = lclptr;
|
sp = &tz->state;
|
||||||
if (sp->timecnt == 0 || t < sp->ats[0])
|
if (sp->timecnt == 0 || t < sp->ats[0])
|
||||||
{
|
{
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -906,9 +848,9 @@ localsub(const pg_time_t *timep, const long offset, struct pg_tm * tmp)
|
|||||||
|
|
||||||
|
|
||||||
struct pg_tm *
|
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;
|
return &tm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1084,15 +1026,16 @@ pg_next_dst_boundary(const pg_time_t *timep,
|
|||||||
int *before_isdst,
|
int *before_isdst,
|
||||||
pg_time_t *boundary,
|
pg_time_t *boundary,
|
||||||
long int *after_gmtoff,
|
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;
|
register const struct ttinfo *ttisp;
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
const pg_time_t t = *timep;
|
const pg_time_t t = *timep;
|
||||||
|
|
||||||
sp = lclptr;
|
sp = &tz->state;
|
||||||
if (sp->timecnt == 0)
|
if (sp->timecnt == 0)
|
||||||
{
|
{
|
||||||
/* non-DST zone, use lowest-numbered standard type */
|
/* 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
|
* Return the name of the current timezone
|
||||||
*/
|
*/
|
||||||
const char *
|
const char *
|
||||||
pg_get_current_timezone(void)
|
pg_get_timezone_name(pg_tz *tz)
|
||||||
{
|
{
|
||||||
if (lcl_is_set)
|
if (tz)
|
||||||
return lcl_TZname;
|
return tz->TZname;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/datetime.h"
|
||||||
#include "utils/elog.h"
|
#include "utils/elog.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
|
#include "utils/hsearch.h"
|
||||||
|
|
||||||
|
/* Current global timezone */
|
||||||
|
pg_tz *global_timezone = NULL;
|
||||||
|
|
||||||
|
|
||||||
static char tzdir[MAXPGPATH];
|
static char tzdir[MAXPGPATH];
|
||||||
static int done_tzdir = 0;
|
static int done_tzdir = 0;
|
||||||
|
|
||||||
static const char *identify_system_timezone(void);
|
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 tm *systm;
|
||||||
struct pg_tm *pgtm;
|
struct pg_tm *pgtm;
|
||||||
char cbuf[TZ_STRLEN_MAX + 1];
|
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 */
|
return -1; /* can't handle the TZ name at all */
|
||||||
|
|
||||||
/* Reject if leap seconds involved */
|
/* Reject if leap seconds involved */
|
||||||
if (!tz_acceptable())
|
if (!tz_acceptable(tz))
|
||||||
{
|
{
|
||||||
elog(DEBUG4, "Reject TZ \"%s\": uses leap seconds", tzname);
|
elog(DEBUG4, "Reject TZ \"%s\": uses leap seconds", tzname);
|
||||||
return -1;
|
return -1;
|
||||||
@ -171,7 +179,7 @@ score_timezone(const char *tzname, struct tztry * tt)
|
|||||||
for (i = 0; i < tt->n_test_times; i++)
|
for (i = 0; i < tt->n_test_times; i++)
|
||||||
{
|
{
|
||||||
pgtt = (pg_time_t) (tt->test_times[i]);
|
pgtt = (pg_time_t) (tt->test_times[i]);
|
||||||
pgtm = pg_localtime(&pgtt);
|
pgtm = pg_localtime(&pgtt, tz);
|
||||||
if (!pgtm)
|
if (!pgtm)
|
||||||
return -1; /* probably shouldn't happen */
|
return -1; /* probably shouldn't happen */
|
||||||
systm = localtime(&(tt->test_times[i]));
|
systm = localtime(&(tt->test_times[i]));
|
||||||
@ -957,6 +965,82 @@ identify_system_timezone(void)
|
|||||||
#endif /* WIN32 */
|
#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.
|
* 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.
|
* it can restore the old value of TZ if we don't like the new one.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
tz_acceptable(void)
|
tz_acceptable(pg_tz *tz)
|
||||||
{
|
{
|
||||||
struct pg_tm *tt;
|
struct pg_tm *tt;
|
||||||
pg_time_t time2000;
|
pg_time_t time2000;
|
||||||
@ -979,13 +1063,36 @@ tz_acceptable(void)
|
|||||||
* any other result has to be due to leap seconds.
|
* any other result has to be due to leap seconds.
|
||||||
*/
|
*/
|
||||||
time2000 = (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400;
|
time2000 = (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400;
|
||||||
tt = pg_localtime(&time2000);
|
tt = pg_localtime(&time2000, tz);
|
||||||
if (!tt || tt->tm_sec != 0)
|
if (!tt || tt->tm_sec != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
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,
|
* Identify a suitable default timezone setting based on the environment,
|
||||||
* and make it active.
|
* and make it active.
|
||||||
@ -995,20 +1102,20 @@ tz_acceptable(void)
|
|||||||
* from the behavior of the system timezone library. When all else fails,
|
* from the behavior of the system timezone library. When all else fails,
|
||||||
* fall back to GMT.
|
* fall back to GMT.
|
||||||
*/
|
*/
|
||||||
const char *
|
static const char *
|
||||||
select_default_timezone(void)
|
select_default_timezone(void)
|
||||||
{
|
{
|
||||||
const char *def_tz;
|
const char *def_tz;
|
||||||
|
|
||||||
def_tz = getenv("TZ");
|
def_tz = getenv("TZ");
|
||||||
if (def_tz && pg_tzset(def_tz) && tz_acceptable())
|
if (set_global_timezone(def_tz))
|
||||||
return def_tz;
|
return def_tz;
|
||||||
|
|
||||||
def_tz = identify_system_timezone();
|
def_tz = identify_system_timezone();
|
||||||
if (def_tz && pg_tzset(def_tz) && tz_acceptable())
|
if (set_global_timezone(def_tz))
|
||||||
return def_tz;
|
return def_tz;
|
||||||
|
|
||||||
if (pg_tzset("GMT") && tz_acceptable())
|
if (set_global_timezone("GMT"))
|
||||||
return "GMT";
|
return "GMT";
|
||||||
|
|
||||||
ereport(FATAL,
|
ereport(FATAL,
|
||||||
|
@ -9,15 +9,57 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
#ifndef _PGTZ_H
|
||||||
#define _PGTZ_H
|
#define _PGTZ_H
|
||||||
|
|
||||||
|
#include "tzfile.h"
|
||||||
|
|
||||||
#define TZ_STRLEN_MAX 255
|
#define TZ_STRLEN_MAX 255
|
||||||
|
|
||||||
extern char *pg_TZDIR(void);
|
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 */
|
#endif /* _PGTZ_H */
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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"
|
#include "postgres.h"
|
||||||
@ -23,8 +23,8 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
#include "pgtz.h"
|
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
|
#include "pgtz.h"
|
||||||
#include "tzfile.h"
|
#include "tzfile.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
|
* 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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"
|
#include "postgres.h"
|
||||||
@ -14,8 +14,8 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
#include "pgtz.h"
|
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
|
#include "pgtz.h"
|
||||||
#include "tzfile.h"
|
#include "tzfile.h"
|
||||||
|
|
||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user