diff options
author | Bruce Momjian <bruce@momjian.us> | 1998-01-05 18:43:18 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 1998-01-05 18:43:18 +0000 |
commit | 9db64857e0bd31eee463e90c21aba52be8174726 (patch) | |
tree | 3872821a2d3c96896bfccbd450ab29ab977a467d /src/backend/commands/variable.c | |
parent | deea69b90efa866544de6dd34b6e01c04f09806f (diff) | |
download | postgresql-9db64857e0bd31eee463e90c21aba52be8174726.tar.gz postgresql-9db64857e0bd31eee463e90c21aba52be8174726.zip |
Move variable.c to commands/ and aclchk.c to catalog/.
Diffstat (limited to 'src/backend/commands/variable.c')
-rw-r--r-- | src/backend/commands/variable.c | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c new file mode 100644 index 00000000000..8ee7e777af8 --- /dev/null +++ b/src/backend/commands/variable.c @@ -0,0 +1,612 @@ +/* + * Routines for handling of 'SET var TO', + * 'SHOW var' and 'RESET var' statements. + * + * $Id: variable.c,v 1.1 1998/01/05 18:42:50 momjian Exp $ + * + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#include "postgres.h" +#include "miscadmin.h" +#include "commands/variable.h" +#include "utils/builtins.h" +#include "optimizer/internal.h" + +extern Cost _cpu_page_wight_; +extern Cost _cpu_index_page_wight_; +extern bool _use_geqo_; +extern int32 _use_geqo_rels_; +extern bool _use_right_sided_plans_; + +/*-----------------------------------------------------------------------*/ +#if USE_EURODATES +#define DATE_EURO TRUE +#else +#define DATE_EURO FALSE +#endif + +/*-----------------------------------------------------------------------*/ +struct PGVariables PGVariables = +{ + {DATE_EURO, Date_Postgres} +}; + +/*-----------------------------------------------------------------------*/ +static const char * +get_token(char **tok, char **val, const char *str) +{ + const char *start; + int len = 0; + + *tok = NULL; + if (val != NULL) + *val = NULL; + + if (!(*str)) + return NULL; + + /* skip white spaces */ + while (isspace(*str)) + str++; + if (*str == ',' || *str == '=') + elog(ERROR, "Syntax error near (%s): empty setting", str); + + /* end of string? then return NULL */ + if (!(*str)) + return NULL; + + /* OK, at beginning of non-NULL string... */ + start = str; + + /* + * count chars in token until we hit white space or comma or '=' or + * end of string + */ + while (*str && (!isspace(*str)) + && *str != ',' && *str != '=') + { + str++; + len++; + } + + *tok = (char *) PALLOC(len + 1); + StrNCpy(*tok, start, len+1); + + /* skip white spaces */ + while (isspace(*str)) + str++; + + /* end of string? */ + if (!(*str)) + { + return (str); + + /* delimiter? */ + } + else if (*str == ',') + { + return (++str); + + } + else if ((val == NULL) || (*str != '=')) + { + elog(ERROR, "Syntax error near (%s)", str); + }; + + str++; /* '=': get value */ + len = 0; + + /* skip white spaces */ + while (isspace(*str)) + str++; + + if (*str == ',' || !(*str)) + elog(ERROR, "Syntax error near (=%s)", str); + + start = str; + + /* + * count chars in token's value until we hit white space or comma or + * end of string + */ + while (*str && (!isspace(*str)) && *str != ',') + { + str++; + len++; + } + + *val = (char *) PALLOC(len + 1); + StrNCpy(*val, start, len+1); + + /* skip white spaces */ + while (isspace(*str)) + str++; + + if (!(*str)) + return (NULL); + if (*str == ',') + return (++str); + + elog(ERROR, "Syntax error near (%s)", str); + + return str; +} + +/*-----------------------------------------------------------------------*/ +#if FALSE +static bool +parse_null(const char *value) +{ + return TRUE; +} + +static bool +show_null(const char *value) +{ + return TRUE; +} + +static bool +reset_null(const char *value) +{ + return TRUE; +} +#endif + +bool +parse_geqo(const char *value) +{ + const char *rest; + char *tok, + *val; + + if (value == NULL) + { + reset_geqo(); + return TRUE; + } + + rest = get_token(&tok, &val, value); + if (tok == NULL) + elog(ERROR, "Value undefined"); + + if ((rest) && (*rest != '\0')) + elog(ERROR, "Unable to parse '%s'", value); + + if (strcasecmp(tok, "on") == 0) + { + int32 geqo_rels = GEQO_RELS; + + if (val != NULL) + { + geqo_rels = pg_atoi(val, sizeof(int32), '\0'); + if (geqo_rels <= 1) + elog(ERROR, "Bad value for # of relations (%s)", val); + PFREE(val); + } + _use_geqo_ = true; + _use_geqo_rels_ = geqo_rels; + } + else if (strcasecmp(tok, "off") == 0) + { + if ((val != NULL) && (*val != '\0')) + elog(ERROR, "%s does not allow a parameter", tok); + _use_geqo_ = false; + } + else + elog(ERROR, "Bad value for GEQO (%s)", value); + + PFREE(tok); + return TRUE; +} + +bool +show_geqo() +{ + + if (_use_geqo_) + elog(NOTICE, "GEQO is ON beginning with %d relations", _use_geqo_rels_); + else + elog(NOTICE, "GEQO is OFF"); + return TRUE; +} + +bool +reset_geqo(void) +{ + +#ifdef GEQO + _use_geqo_ = true; +#else + _use_geqo_ = false; +#endif + _use_geqo_rels_ = GEQO_RELS; + return TRUE; +} + +bool +parse_r_plans(const char *value) +{ + if (value == NULL) + { + reset_r_plans(); + return TRUE; + } + + if (strcasecmp(value, "on") == 0) + _use_right_sided_plans_ = true; + else if (strcasecmp(value, "off") == 0) + _use_right_sided_plans_ = false; + else + elog(ERROR, "Bad value for Right-sided Plans (%s)", value); + + return TRUE; +} + +bool +show_r_plans() +{ + + if (_use_right_sided_plans_) + elog(NOTICE, "Right-sided Plans are ON"); + else + elog(NOTICE, "Right-sided Plans are OFF"); + return TRUE; +} + +bool +reset_r_plans() +{ + +#ifdef USE_RIGHT_SIDED_PLANS + _use_right_sided_plans_ = true; +#else + _use_right_sided_plans_ = false; +#endif + return TRUE; +} + +bool +parse_cost_heap(const char *value) +{ + float32 res; + + if (value == NULL) + { + reset_cost_heap(); + return TRUE; + } + + res = float4in((char *) value); + _cpu_page_wight_ = *res; + + return TRUE; +} + +bool +show_cost_heap() +{ + + elog(NOTICE, "COST_HEAP is %f", _cpu_page_wight_); + return TRUE; +} + +bool +reset_cost_heap() +{ + _cpu_page_wight_ = _CPU_PAGE_WEIGHT_; + return TRUE; +} + +bool +parse_cost_index(const char *value) +{ + float32 res; + + if (value == NULL) + { + reset_cost_index(); + return TRUE; + } + + res = float4in((char *) value); + _cpu_index_page_wight_ = *res; + + return TRUE; +} + +bool +show_cost_index() +{ + + elog(NOTICE, "COST_INDEX is %f", _cpu_index_page_wight_); + return TRUE; +} + +bool +reset_cost_index() +{ + _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_; + return TRUE; +} + +bool +parse_date(const char *value) +{ + char *tok; + int dcnt = 0, + ecnt = 0; + + if (value == NULL) + { + reset_date(); + return TRUE; + } + + while ((value = get_token(&tok, NULL, value)) != 0) + { + /* Ugh. Somebody ought to write a table driven version -- mjl */ + + if (!strcasecmp(tok, "ISO")) + { + DateStyle = USE_ISO_DATES; + dcnt++; + } + else if (!strcasecmp(tok, "SQL")) + { + DateStyle = USE_SQL_DATES; + dcnt++; + } + else if (!strcasecmp(tok, "POSTGRES")) + { + DateStyle = USE_POSTGRES_DATES; + dcnt++; + } + else if (!strcasecmp(tok, "GERMAN")) + { + DateStyle = USE_GERMAN_DATES; + dcnt++; + EuroDates = TRUE; + if ((ecnt > 0) && (! EuroDates)) ecnt++; + } + else if (!strncasecmp(tok, "EURO", 4)) + { + EuroDates = TRUE; + if ((dcnt <= 0) || (DateStyle != USE_GERMAN_DATES)) ecnt++; + } + else if ((!strcasecmp(tok, "US")) + || (!strncasecmp(tok, "NONEURO", 7))) + { + EuroDates = FALSE; + if ((dcnt <= 0) || (DateStyle == USE_GERMAN_DATES)) ecnt++; + } + else if (!strcasecmp(tok, "DEFAULT")) + { + DateStyle = USE_POSTGRES_DATES; + EuroDates = FALSE; + ecnt++; + } + else + { + elog(ERROR, "Bad value for date style (%s)", tok); + } + PFREE(tok); + } + + if (dcnt > 1 || ecnt > 1) + elog(NOTICE, "Conflicting settings for date"); + + return TRUE; +} + +bool +show_date() +{ + char buf[64]; + + strcpy(buf, "DateStyle is "); + switch (DateStyle) + { + case USE_ISO_DATES: + strcat(buf, "ISO"); + break; + case USE_SQL_DATES: + strcat(buf, "SQL"); + break; + case USE_GERMAN_DATES: + strcat(buf, "German"); + break; + default: + strcat(buf, "Postgres"); + break; + }; + strcat(buf, " with "); + strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)")); + strcat(buf, " conventions"); + + elog(NOTICE, buf, NULL); + + return TRUE; +} + +bool +reset_date() +{ + DateStyle = USE_POSTGRES_DATES; + EuroDates = FALSE; + + return TRUE; +} + +/* Timezone support + * Working storage for strings is allocated with an arbitrary size of 64 bytes. + */ + +static char *defaultTZ = NULL; +static char TZvalue[64]; +static char tzbuf[64]; + +/* parse_timezone() + * Handle SET TIME ZONE... + * Try to save existing TZ environment variable for later use in RESET TIME ZONE. + * - thomas 1997-11-10 + */ +bool +parse_timezone(const char *value) +{ + char *tok; + + if (value == NULL) + { + reset_timezone(); + return TRUE; + } + + while ((value = get_token(&tok, NULL, value)) != 0) + { + /* Not yet tried to save original value from environment? */ + if (defaultTZ == NULL) + { + /* found something? then save it for later */ + if (getenv("TZ") != NULL) + { + defaultTZ = getenv("TZ"); + if (defaultTZ == NULL) + defaultTZ = (char *) -1; + else + strcpy(TZvalue, defaultTZ); + } + /* found nothing so mark with an invalid pointer */ + else + { + defaultTZ = (char *) -1; + } + } + + strcpy(tzbuf, "TZ="); + strcat(tzbuf, tok); + if (putenv(tzbuf) != 0) + elog(ERROR, "Unable to set TZ environment variable to %s", tok); + + tzset(); + PFREE(tok); + } + + return TRUE; +} /* parse_timezone() */ + +bool +show_timezone() +{ + char *tz; + + tz = getenv("TZ"); + + elog(NOTICE, "Time zone is %s", ((tz != NULL)? tz: "unknown")); + + return TRUE; +} /* show_timezone() */ + +/* reset_timezone() + * Set TZ environment variable to original value. + * Note that if TZ was originally not set, TZ should be cleared. + * 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). + */ +bool +reset_timezone() +{ + if ((defaultTZ != NULL) && (defaultTZ != (char *) -1)) + { + strcpy(tzbuf, "TZ="); + strcat(tzbuf, TZvalue); + if (putenv(tzbuf) != 0) + elog(ERROR, "Unable to set TZ environment variable to %s", TZvalue); + } + else + { + strcpy(tzbuf, "="); + if (putenv(tzbuf) != 0) + elog(ERROR, "Unable to clear TZ environment variable", NULL); + } + tzset(); + + return TRUE; +} /* reset_timezone() */ + +/*-----------------------------------------------------------------------*/ +struct VariableParsers +{ + const char *name; + bool (*parser) (const char *); + bool (*show) (); + bool (*reset) (); +} VariableParsers[] = + +{ + { "datestyle", parse_date, show_date, reset_date }, + { "timezone", parse_timezone, show_timezone, reset_timezone }, + { "cost_heap", parse_cost_heap, show_cost_heap, reset_cost_heap }, + { "cost_index", parse_cost_index, show_cost_index, reset_cost_index }, + { "geqo", parse_geqo, show_geqo, reset_geqo }, + { "r_plans", parse_r_plans, show_r_plans, reset_r_plans }, + { NULL, NULL, NULL, NULL } +}; + +/*-----------------------------------------------------------------------*/ +bool +SetPGVariable(const char *name, const char *value) +{ + struct VariableParsers *vp; + + for (vp = VariableParsers; vp->name; vp++) + { + if (!strcasecmp(vp->name, name)) + return (vp->parser) (value); + } + + elog(NOTICE, "Unrecognized variable %s", name); + + return TRUE; +} + +/*-----------------------------------------------------------------------*/ +bool +GetPGVariable(const char *name) +{ + struct VariableParsers *vp; + + for (vp = VariableParsers; vp->name; vp++) + { + if (!strcasecmp(vp->name, name)) + return (vp->show) (); + } + + elog(NOTICE, "Unrecognized variable %s", name); + + return TRUE; +} + +/*-----------------------------------------------------------------------*/ +bool +ResetPGVariable(const char *name) +{ + struct VariableParsers *vp; + + for (vp = VariableParsers; vp->name; vp++) + { + if (!strcasecmp(vp->name, name)) + return (vp->reset) (); + } + + elog(NOTICE, "Unrecognized variable %s", name); + + return TRUE; +} |