/* * Initialize timezone library * * This is called after initial loading of postgresql.conf. If no TimeZone * setting was found therein, we try to derive one from the environment. * Likewise for log_timezone. * * Note: this is also called from ProcessConfigFile, to re-establish valid * GUC settings if the GUCs have been reset to default following their * removal from postgresql.conf. */ void pg_timezone_initialize(void) { pg_tz *def_tz = NULL; /* * Make sure that session_timezone and log_timezone are set. * (session_timezone could still be NULL even if a timezone value was set * in postgresql.conf, if that setting was interval-based rather than * timezone-based.) */ if (!session_timezone) { def_tz = select_default_timezone(); session_timezone = def_tz; } if (!log_timezone) { /* Don't duplicate work */ if (!def_tz) def_tz = select_default_timezone(); log_timezone = def_tz; } /* * Now, set the timezone and log_timezone GUCs if they're still default. * (This will redundantly call pg_tzset().) * * We choose to label these values PGC_S_ENV_VAR, rather than * PGC_S_DYNAMIC_DEFAULT which would be functionally equivalent, because * they came either from getenv("TZ") or from libc behavior that's * determined by process environment of some kind. * * Note: in the case where a setting has just been removed from * postgresql.conf, this code will not do what you might expect, namely * call select_default_timezone() and install that value as the setting. * Rather, the previously active setting --- typically the one from * postgresql.conf --- will be reinstalled, relabeled as PGC_S_ENV_VAR. If * we did try to install the "correct" default value, the effect would be * that each postmaster child would independently run an extremely * expensive search of the timezone database, bringing the database to its * knees for possibly multiple seconds. This is so unpleasant, and could * so easily be triggered quite unintentionally, that it seems better to * violate the principle of least astonishment. */ if (GetConfigOptionResetString("timezone") == NULL) SetConfigOption("timezone", pg_get_timezone_name(session_timezone), PGC_POSTMASTER, PGC_S_ENV_VAR); if (GetConfigOptionResetString("log_timezone") == NULL) SetConfigOption("log_timezone", pg_get_timezone_name(log_timezone), PGC_POSTMASTER, PGC_S_ENV_VAR); }
/* * assign_datestyle: GUC assign_hook for datestyle */ const char * assign_datestyle(const char *value, bool doit, GucSource source) { int newDateStyle = DateStyle; int newDateOrder = DateOrder; bool have_style = false; bool have_order = false; bool ok = true; char *rawstring; char *result; List *elemlist; ListCell *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); list_free(elemlist); ereport(GUC_complaint_elevel(source), (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 (pg_strcasecmp(tok, "ISO") == 0) { if (have_style && newDateStyle != USE_ISO_DATES) ok = false; /* conflicting styles */ newDateStyle = USE_ISO_DATES; have_style = true; } else if (pg_strcasecmp(tok, "SQL") == 0) { if (have_style && newDateStyle != USE_SQL_DATES) ok = false; /* conflicting styles */ newDateStyle = USE_SQL_DATES; have_style = true; } else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0) { if (have_style && newDateStyle != USE_POSTGRES_DATES) ok = false; /* conflicting styles */ newDateStyle = USE_POSTGRES_DATES; have_style = true; } else if (pg_strcasecmp(tok, "GERMAN") == 0) { if (have_style && newDateStyle != USE_GERMAN_DATES) ok = false; /* conflicting styles */ newDateStyle = USE_GERMAN_DATES; have_style = true; /* GERMAN also sets DMY, unless explicitly overridden */ if (!have_order) newDateOrder = DATEORDER_DMY; } else if (pg_strcasecmp(tok, "YMD") == 0) { if (have_order && newDateOrder != DATEORDER_YMD) ok = false; /* conflicting orders */ newDateOrder = DATEORDER_YMD; have_order = true; } else if (pg_strcasecmp(tok, "DMY") == 0 || pg_strncasecmp(tok, "EURO", 4) == 0) { if (have_order && newDateOrder != DATEORDER_DMY) ok = false; /* conflicting orders */ newDateOrder = DATEORDER_DMY; have_order = true; } else if (pg_strcasecmp(tok, "MDY") == 0 || pg_strcasecmp(tok, "US") == 0 || pg_strncasecmp(tok, "NONEURO", 7) == 0) { if (have_order && newDateOrder != DATEORDER_MDY) ok = false; /* conflicting orders */ newDateOrder = DATEORDER_MDY; have_order = true; } else if (pg_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, source); if (!have_style) newDateStyle = DateStyle; if (!have_order) 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 { ereport(GUC_complaint_elevel(source), (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized \"datestyle\" key word: \"%s\"", tok))); ok = false; break; } }
/* * check_datestyle: GUC check_hook for datestyle */ bool check_datestyle(char **newval, void **extra, GucSource source) { int newDateStyle = DateStyle; int newDateOrder = DateOrder; bool have_style = false; bool have_order = false; bool ok = true; char *rawstring; int *myextra; char *result; List *elemlist; ListCell *l; /* Need a modifiable copy of string */ rawstring = pstrdup(*newval); /* Parse string into list of identifiers */ if (!SplitIdentifierString(rawstring, ',', &elemlist)) { /* syntax error in list */ GUC_check_errdetail("List syntax is invalid."); pfree(rawstring); list_free(elemlist); return false; } foreach(l, elemlist) { char *tok = (char *) lfirst(l); /* Ugh. Somebody ought to write a table driven version -- mjl */ if (pg_strcasecmp(tok, "ISO") == 0) { if (have_style && newDateStyle != USE_ISO_DATES) ok = false; /* conflicting styles */ newDateStyle = USE_ISO_DATES; have_style = true; } else if (pg_strcasecmp(tok, "SQL") == 0) { if (have_style && newDateStyle != USE_SQL_DATES) ok = false; /* conflicting styles */ newDateStyle = USE_SQL_DATES; have_style = true; } else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0) { if (have_style && newDateStyle != USE_POSTGRES_DATES) ok = false; /* conflicting styles */ newDateStyle = USE_POSTGRES_DATES; have_style = true; } else if (pg_strcasecmp(tok, "GERMAN") == 0) { if (have_style && newDateStyle != USE_GERMAN_DATES) ok = false; /* conflicting styles */ newDateStyle = USE_GERMAN_DATES; have_style = true; /* GERMAN also sets DMY, unless explicitly overridden */ if (!have_order) newDateOrder = DATEORDER_DMY; } else if (pg_strcasecmp(tok, "YMD") == 0) { if (have_order && newDateOrder != DATEORDER_YMD) ok = false; /* conflicting orders */ newDateOrder = DATEORDER_YMD; have_order = true; } else if (pg_strcasecmp(tok, "DMY") == 0 || pg_strncasecmp(tok, "EURO", 4) == 0) { if (have_order && newDateOrder != DATEORDER_DMY) ok = false; /* conflicting orders */ newDateOrder = DATEORDER_DMY; have_order = true; } else if (pg_strcasecmp(tok, "MDY") == 0 || pg_strcasecmp(tok, "US") == 0 || pg_strncasecmp(tok, "NONEURO", 7) == 0) { if (have_order && newDateOrder != DATEORDER_MDY) ok = false; /* conflicting orders */ newDateOrder = DATEORDER_MDY; have_order = true; } else if (pg_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 check_datestyle(...)" because we need * to handle constructs like "DEFAULT, ISO". */ char *subval; void *subextra = NULL; subval = strdup(GetConfigOptionResetString("datestyle")); if (!subval) { ok = false; break; } if (!check_datestyle(&subval, &subextra, source)) { free(subval); ok = false; break; } myextra = (int *) subextra; if (!have_style) newDateStyle = myextra[0]; if (!have_order) newDateOrder = myextra[1]; free(subval); free(subextra); } else { GUC_check_errdetail("Unrecognized key word: \"%s\".", tok); pfree(rawstring); list_free(elemlist); return false; } }