aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/variable.c
diff options
context:
space:
mode:
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;