aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/variable.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2004-05-21 05:08:06 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2004-05-21 05:08:06 +0000
commit63bd0db12199c5df043e1dea0f2b574f622b3a4c (patch)
treedbafdb6e4541162ad369dbfeca24cbd62aefddcc /src/backend/commands/variable.c
parent260b513fc37b6ed2df51586c487d0832b89d0d70 (diff)
downloadpostgresql-63bd0db12199c5df043e1dea0f2b574f622b3a4c.tar.gz
postgresql-63bd0db12199c5df043e1dea0f2b574f622b3a4c.zip
Integrate src/timezone library for all platforms. There is more we can
and should do now that we control our own destiny for timezone handling, but this commit gets the bulk of the picayune diffs in place. Magnus Hagander and Tom Lane.
Diffstat (limited to 'src/backend/commands/variable.c')
-rw-r--r--src/backend/commands/variable.c257
1 files changed, 36 insertions, 221 deletions
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index f83ce51baca..45ed717951e 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.94 2004/05/07 00:24:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.95 2004/05/21 05:07:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,13 +17,13 @@
#include "postgres.h"
#include <ctype.h>
-#include <time.h>
#include "access/xact.h"
#include "catalog/pg_shadow.h"
#include "commands/variable.h"
#include "miscadmin.h"
#include "parser/scansup.h"
+#include "pgtime.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/syscache.h"
@@ -31,17 +31,6 @@
#include "mb/pg_wchar.h"
/*
- * Some systems have tzname[] but don't declare it in <time.h>. Use this
- * to duplicate the test in AC_STRUCT_TIMEZONE.
- */
-#ifdef HAVE_TZNAME
-#ifndef tzname /* For SGI. */
-extern char *tzname[];
-#endif
-#endif
-
-
-/*
* DATESTYLE
*/
@@ -238,149 +227,6 @@ assign_datestyle(const char *value, bool doit, GucSource source)
*/
/*
- * Storage for TZ env var is allocated with an arbitrary size of 64 bytes.
- */
-#define TZBUF_LEN 64
-
-static char tzbuf[TZBUF_LEN];
-
-/*
- * First time through, we remember the original environment TZ value, if any.
- */
-static bool have_saved_tz = false;
-static char orig_tzbuf[TZBUF_LEN];
-
-/*
- * Convenience subroutine for assigning the value of TZ
- */
-static void
-set_tz(const char *tz)
-{
- strcpy(tzbuf, "TZ=");
- strncpy(tzbuf + 3, tz, sizeof(tzbuf) - 4);
- if (putenv(tzbuf) != 0) /* shouldn't happen? */
- elog(LOG, "could not set TZ environment variable");
- tzset();
-}
-
-/*
- * Remove any value of TZ we have established
- *
- * Note: this leaves us with *no* value of TZ in the environment, and
- * is therefore only appropriate for reverting to that state, not for
- * reverting to a state where TZ was set to something else.
- */
-static void
-clear_tz(void)
-{
- /*
- * unsetenv() works fine, but is BSD, not POSIX, and is not available
- * under Solaris, among others. Apparently putenv() called as below
- * clears the process-specific environment variables. Other
- * reasonable arguments to putenv() (e.g. "TZ=", "TZ", "") result in a
- * core dump (under Linux anyway). - thomas 1998-01-26
- */
- if (tzbuf[0] == 'T')
- {
- strcpy(tzbuf, "=");
- if (putenv(tzbuf) != 0)
- elog(LOG, "could not clear TZ environment variable");
- tzset();
- }
-}
-
-/*
- * Check whether tzset() succeeded
- *
- * Unfortunately, tzset doesn't offer any well-defined way to detect that the
- * value of TZ was bad. Often it will just select UTC (GMT) as the effective
- * timezone. We use the following heuristics:
- *
- * If tzname[1] is a nonempty string, *or* the global timezone variable is
- * not zero, then tzset must have recognized the TZ value as something
- * different from UTC. Return true.
- *
- * Otherwise, check to see if the TZ name is a known spelling of "UTC"
- * (ie, appears in our internal tables as a timezone equivalent to UTC).
- * If so, accept it.
- *
- * This will reject nonstandard spellings of UTC unless tzset() chose to
- * set tzname[1] as well as tzname[0]. The glibc version of tzset() will
- * do so, but on other systems we may be tightening the spec a little.
- *
- * Another problem is that on some platforms (eg HPUX), if tzset thinks the
- * input is bogus then it will adopt the system default timezone, which we
- * really can't tell is not the intended translation of the input.
- *
- * Still, it beats failing to detect bad TZ names at all, and a silent
- * failure mode of adopting the system-wide default is much better than
- * a silent failure mode of adopting UTC.
- *
- * NB: this must NOT ereport(ERROR). The caller must get control back so that
- * it can restore the old value of TZ if we don't like the new one.
- */
-static bool
-tzset_succeeded(const char *tz)
-{
- char *tztmp;
- int tzval;
-
- /*
- * Check first set of heuristics to say that tzset definitely worked.
- */
-#ifdef HAVE_TZNAME
- if (tzname[1] && tzname[1][0] != '\0')
- return true;
-#endif
- if (TIMEZONE_GLOBAL != 0)
- return true;
-
- /*
- * Check for known spellings of "UTC". Note we must downcase the
- * input before passing it to DecodePosixTimezone().
- */
- tztmp = downcase_truncate_identifier(tz, strlen(tz), false);
- if (DecodePosixTimezone(tztmp, &tzval) == 0)
- if (tzval == 0)
- return true;
-
- return false;
-}
-
-/*
- * Check whether timezone is acceptable.
- *
- * What we are doing here is checking for leap-second-aware timekeeping.
- * We need to reject such TZ settings because they'll wreak havoc with our
- * date/time arithmetic.
- *
- * NB: this must NOT ereport(ERROR). The caller must get control back so that
- * it can restore the old value of TZ if we don't like the new one.
- */
-static bool
-tz_acceptable(void)
-{
- struct tm tt;
- time_t time2000;
-
- /*
- * To detect leap-second timekeeping, compute the time_t value for
- * local midnight, 2000-01-01. Insist that this be a multiple of 60;
- * any partial-minute offset has to be due to leap seconds.
- */
- MemSet(&tt, 0, sizeof(tt));
- tt.tm_year = 100;
- tt.tm_mon = 0;
- tt.tm_mday = 1;
- tt.tm_isdst = -1;
- time2000 = mktime(&tt);
- if ((time2000 % 60) != 0)
- return false;
-
- return true;
-}
-
-/*
* assign_timezone: GUC assign_hook for timezone
*/
const char *
@@ -391,21 +237,6 @@ assign_timezone(const char *value, bool doit, GucSource source)
double hours;
/*
- * On first call, see if there is a TZ in the original environment.
- * Save that value permanently.
- */
- if (!have_saved_tz)
- {
- char *orig_tz = getenv("TZ");
-
- if (orig_tz)
- StrNCpy(orig_tzbuf, orig_tz, sizeof(orig_tzbuf));
- else
- orig_tzbuf[0] = '\0';
- have_saved_tz = true;
- }
-
- /*
* Check for INTERVAL 'foo'
*/
if (pg_strncasecmp(value, "interval", 8) == 0)
@@ -476,36 +307,21 @@ assign_timezone(const char *value, bool doit, GucSource source)
{
/*
* UNKNOWN is the value shown as the "default" for TimeZone in
- * guc.c. We interpret it as meaning the original TZ
- * inherited from the environment. Note that if there is an
- * original TZ setting, we will return that rather than
+ * guc.c. We interpret it as being a complete no-op; we don't
+ * change the timezone setting. Note that if there is a known
+ * timezone setting, we will return that name rather than
* 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
+ * 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.
*/
- if (doit)
- {
- bool ok;
-
- /* Revert to original setting of TZ, whatever it was */
- if (orig_tzbuf[0])
- {
- set_tz(orig_tzbuf);
- ok = tzset_succeeded(orig_tzbuf) && tz_acceptable();
- }
- else
- {
- clear_tz();
- ok = tz_acceptable();
- }
+ const char *curzone = pg_get_current_timezone();
- if (ok)
- HasCTZSet = false;
- else
- {
- /* Bogus, so force UTC (equivalent to INTERVAL 0) */
- CTimeZone = 0;
- HasCTZSet = true;
- }
- }
+ if (curzone)
+ value = curzone;
}
else
{
@@ -514,22 +330,22 @@ assign_timezone(const char *value, bool doit, GucSource source)
*
* 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. Note that it's possible the old setting
- * is in tzbuf, so we'd better copy it.
+ * have to back out. We have to copy since pg_get_current_timezone
+ * returns a pointer to its static state.
*/
- char save_tzbuf[TZBUF_LEN];
+ const char *cur_tz;
char *save_tz;
bool known,
acceptable;
- save_tz = getenv("TZ");
- if (save_tz)
- StrNCpy(save_tzbuf, save_tz, sizeof(save_tzbuf));
-
- set_tz(value);
+ cur_tz = pg_get_current_timezone();
+ if (cur_tz)
+ save_tz = pstrdup(cur_tz);
+ else
+ save_tz = NULL;
- known = tzset_succeeded(value);
- acceptable = tz_acceptable();
+ known = pg_tzset(value);
+ acceptable = known ? tz_acceptable() : false;
if (doit && known && acceptable)
{
@@ -544,9 +360,9 @@ assign_timezone(const char *value, bool doit, GucSource source)
* a fixed offset, we still are.
*/
if (save_tz)
- set_tz(save_tzbuf);
- else
- clear_tz();
+ pg_tzset(save_tz);
+ else /* TZ library not initialized yet */
+ select_default_timezone();
/* Complain if it was bad */
if (!known)
{
@@ -578,17 +394,16 @@ assign_timezone(const char *value, bool doit, GucSource source)
/*
* Prepare the canonical string to return. GUC wants it malloc'd.
*/
- result = (char *) malloc(sizeof(tzbuf));
- if (!result)
- return NULL;
-
if (HasCTZSet)
- snprintf(result, sizeof(tzbuf), "%.5f",
+ {
+ result = (char *) malloc(64);
+ if (!result)
+ return NULL;
+ snprintf(result, 64, "%.5f",
(double) (-CTimeZone) / 3600.0);
- else if (tzbuf[0] == 'T')
- strcpy(result, tzbuf + 3);
+ }
else
- strcpy(result, "UNKNOWN");
+ result = strdup(value);
return result;
}
@@ -599,7 +414,7 @@ assign_timezone(const char *value, bool doit, GucSource source)
const char *
show_timezone(void)
{
- char *tzn;
+ const char *tzn;
if (HasCTZSet)
{
@@ -612,7 +427,7 @@ show_timezone(void)
IntervalPGetDatum(&interval)));
}
else
- tzn = getenv("TZ");
+ tzn = pg_get_current_timezone();
if (tzn != NULL)
return tzn;