variable.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 832 行 · 第 1/2 页
C
832 行
/*------------------------------------------------------------------------- * * variable.c * Routines for handling specialized SET variables. * * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.88.2.1 2004/08/11 21:10:50 tgl Exp $ * *------------------------------------------------------------------------- */#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 "utils/builtins.h"#include "utils/guc.h"#include "utils/syscache.h"#include "utils/tqual.h"#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 *//* * assign_datestyle: GUC assign_hook for datestyle */const char *assign_datestyle(const char *value, bool doit, bool interactive){ int newDateStyle = DateStyle; int newDateOrder = DateOrder; bool ok = true; int scnt = 0, ocnt = 0; char *rawstring; char *result; List *elemlist; List *l; /* Need a modifiable copy of string */ rawstring = pstrdup(value); /* Parse string into list of identifiers */ if (!SplitIdentifierString(rawstring, ',', &elemlist)) { /* syntax error in list */ pfree(rawstring); freeList(elemlist); if (interactive) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid list syntax for parameter \"datestyle\""))); return NULL; } foreach(l, elemlist) { char *tok = (char *) lfirst(l); /* Ugh. Somebody ought to write a table driven version -- mjl */ if (strcasecmp(tok, "ISO") == 0) { newDateStyle = USE_ISO_DATES; scnt++; } else if (strcasecmp(tok, "SQL") == 0) { newDateStyle = USE_SQL_DATES; scnt++; } else if (strncasecmp(tok, "POSTGRES", 8) == 0) { newDateStyle = USE_POSTGRES_DATES; scnt++; } else if (strcasecmp(tok, "GERMAN") == 0) { newDateStyle = USE_GERMAN_DATES; scnt++; /* GERMAN also sets DMY, unless explicitly overridden */ if (ocnt == 0) newDateOrder = DATEORDER_DMY; } else if (strcasecmp(tok, "YMD") == 0) { newDateOrder = DATEORDER_YMD; ocnt++; } else if (strcasecmp(tok, "DMY") == 0 || strncasecmp(tok, "EURO", 4) == 0) { newDateOrder = DATEORDER_DMY; ocnt++; } else if (strcasecmp(tok, "MDY") == 0 || strcasecmp(tok, "US") == 0 || strncasecmp(tok, "NONEURO", 7) == 0) { newDateOrder = DATEORDER_MDY; ocnt++; } else if (strcasecmp(tok, "DEFAULT") == 0) { /* * Easiest way to get the current DEFAULT state is to fetch * the DEFAULT string from guc.c and recursively parse it. * * We can't simply "return assign_datestyle(...)" because we need * to handle constructs like "DEFAULT, ISO". */ int saveDateStyle = DateStyle; int saveDateOrder = DateOrder; const char *subval; subval = assign_datestyle(GetConfigOptionResetString("datestyle"), true, interactive); if (scnt == 0) newDateStyle = DateStyle; if (ocnt == 0) newDateOrder = DateOrder; DateStyle = saveDateStyle; DateOrder = saveDateOrder; if (!subval) { ok = false; break; } /* Here we know that our own return value is always malloc'd */ /* when doit is true */ free((char *) subval); } else { if (interactive) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized \"datestyle\" key word: \"%s\"", tok))); ok = false; break; } } if (scnt > 1 || ocnt > 1) ok = false; pfree(rawstring); freeList(elemlist); if (!ok) { if (interactive) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("conflicting \"datestyle\" specifications"))); return NULL; } /* * If we aren't going to do the assignment, just return OK indicator. */ if (!doit) return value; /* * Prepare the canonical string to return. GUC wants it malloc'd. */ result = (char *) malloc(32); if (!result) return NULL; switch (newDateStyle) { case USE_ISO_DATES: strcpy(result, "ISO"); break; case USE_SQL_DATES: strcpy(result, "SQL"); break; case USE_GERMAN_DATES: strcpy(result, "German"); break; default: strcpy(result, "Postgres"); break; } switch (newDateOrder) { case DATEORDER_YMD: strcat(result, ", YMD"); break; case DATEORDER_DMY: strcat(result, ", DMY"); break; default: strcat(result, ", MDY"); break; } /* * Finally, it's safe to assign to the global variables; the * assignment cannot fail now. */ DateStyle = newDateStyle; DateOrder = newDateOrder; return result;}/* * TIMEZONE *//* * Storage for TZ env var is allocated with an arbitrary size of 64 bytes. */#define TZBUF_LEN 64static 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 voidset_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 voidclear_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 booltzset_succeeded(const char *tz){ char tztmp[TZBUF_LEN]; char *cp; 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(). */ StrNCpy(tztmp, tz, sizeof(tztmp)); for (cp = tztmp; *cp; cp++) *cp = tolower((unsigned char) *cp); 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 booltz_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 *assign_timezone(const char *value, bool doit, bool interactive){ char *result; char *endptr; 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 (strncasecmp(value, "interval", 8) == 0) { const char *valueptr = value; char *val;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?