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 + -
显示快捷键?