postgresql/src/backend/commands/variable.c
Tom Lane b1577a7c78 New cost model for planning, incorporating a penalty for random page
accesses versus sequential accesses, a (very crude) estimate of the
effects of caching on random page accesses, and cost to evaluate WHERE-
clause expressions.  Export critical parameters for this model as SET
variables.  Also, create SET variables for the planner's enable flags
(enable_seqscan, enable_indexscan, etc) so that these can be controlled
more conveniently than via PGOPTIONS.

Planner now estimates both startup cost (cost before retrieving
first tuple) and total cost of each path, so it can optimize queries
with LIMIT on a reasonable basis by interpolating between these costs.
Same facility is a win for EXISTS(...) subqueries and some other cases.

Redesign pathkey representation to achieve a major speedup in planning
(I saw as much as 5X on a 10-way join); also minor changes in planner
to reduce memory consumption by recycling discarded Path nodes and
not constructing unnecessary lists.

Minor cleanups to display more-plausible costs in some cases in
EXPLAIN output.

Initdb forced by change in interface to index cost estimation
functions.
2000-02-15 20:49:31 +00:00

1119 lines
20 KiB
C

/*-------------------------------------------------------------------------
*
* variable.c
* Routines for handling of 'SET var TO',
* 'SHOW var' and 'RESET var' statements.
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.29 2000/02/15 20:49:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <time.h>
#include "postgres.h"
#include "access/xact.h"
#include "catalog/pg_shadow.h"
#include "commands/variable.h"
#include "miscadmin.h"
#include "optimizer/cost.h"
#include "optimizer/paths.h"
#include "utils/builtins.h"
#include "utils/tqual.h"
#include "utils/trace.h"
#ifdef MULTIBYTE
#include "mb/pg_wchar.h"
#endif
/* XXX should be in a header file */
extern bool _use_keyset_query_optimizer;
static bool show_date(void);
static bool reset_date(void);
static bool parse_date(const char *);
static bool show_timezone(void);
static bool reset_timezone(void);
static bool parse_timezone(const char *);
static bool show_effective_cache_size(void);
static bool reset_effective_cache_size(void);
static bool parse_effective_cache_size(const char *);
static bool show_random_page_cost(void);
static bool reset_random_page_cost(void);
static bool parse_random_page_cost(const char *);
static bool show_cpu_tuple_cost(void);
static bool reset_cpu_tuple_cost(void);
static bool parse_cpu_tuple_cost(const char *);
static bool show_cpu_index_tuple_cost(void);
static bool reset_cpu_index_tuple_cost(void);
static bool parse_cpu_index_tuple_cost(const char *);
static bool show_cpu_operator_cost(void);
static bool reset_cpu_operator_cost(void);
static bool parse_cpu_operator_cost(const char *);
static bool reset_enable_seqscan(void);
static bool show_enable_seqscan(void);
static bool parse_enable_seqscan(const char *);
static bool reset_enable_indexscan(void);
static bool show_enable_indexscan(void);
static bool parse_enable_indexscan(const char *);
static bool reset_enable_tidscan(void);
static bool show_enable_tidscan(void);
static bool parse_enable_tidscan(const char *);
static bool reset_enable_sort(void);
static bool show_enable_sort(void);
static bool parse_enable_sort(const char *);
static bool reset_enable_nestloop(void);
static bool show_enable_nestloop(void);
static bool parse_enable_nestloop(const char *);
static bool reset_enable_mergejoin(void);
static bool show_enable_mergejoin(void);
static bool parse_enable_mergejoin(const char *);
static bool reset_enable_hashjoin(void);
static bool show_enable_hashjoin(void);
static bool parse_enable_hashjoin(const char *);
static bool reset_geqo(void);
static bool show_geqo(void);
static bool parse_geqo(const char *);
static bool show_ksqo(void);
static bool reset_ksqo(void);
static bool parse_ksqo(const char *);
static bool show_XactIsoLevel(void);
static bool reset_XactIsoLevel(void);
static bool parse_XactIsoLevel(const char *);
/*
*
* Get_Token
*
*/
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;
}
/*
* Generic parse routine for boolean ON/OFF variables
*/
static bool
parse_boolean_var(const char *value,
bool *variable, const char *varname, bool defaultval)
{
if (value == NULL)
{
*variable = defaultval;
return TRUE;
}
if (strcasecmp(value, "on") == 0)
*variable = true;
else if (strcasecmp(value, "off") == 0)
*variable = false;
else
elog(ERROR, "Bad value for %s (%s)", varname, value);
return TRUE;
}
/*
* ENABLE_SEQSCAN
*/
static bool
parse_enable_seqscan(const char *value)
{
return parse_boolean_var(value, &enable_seqscan,
"ENABLE_SEQSCAN", true);
}
static bool
show_enable_seqscan()
{
elog(NOTICE, "ENABLE_SEQSCAN is %s",
enable_seqscan ? "ON" : "OFF");
return TRUE;
}
static bool
reset_enable_seqscan()
{
enable_seqscan = true;
return TRUE;
}
/*
* ENABLE_INDEXSCAN
*/
static bool
parse_enable_indexscan(const char *value)
{
return parse_boolean_var(value, &enable_indexscan,
"ENABLE_INDEXSCAN", true);
}
static bool
show_enable_indexscan()
{
elog(NOTICE, "ENABLE_INDEXSCAN is %s",
enable_indexscan ? "ON" : "OFF");
return TRUE;
}
static bool
reset_enable_indexscan()
{
enable_indexscan = true;
return TRUE;
}
/*
* ENABLE_TIDSCAN
*/
static bool
parse_enable_tidscan(const char *value)
{
return parse_boolean_var(value, &enable_tidscan,
"ENABLE_TIDSCAN", true);
}
static bool
show_enable_tidscan()
{
elog(NOTICE, "ENABLE_TIDSCAN is %s",
enable_tidscan ? "ON" : "OFF");
return TRUE;
}
static bool
reset_enable_tidscan()
{
enable_tidscan = true;
return TRUE;
}
/*
* ENABLE_SORT
*/
static bool
parse_enable_sort(const char *value)
{
return parse_boolean_var(value, &enable_sort,
"ENABLE_SORT", true);
}
static bool
show_enable_sort()
{
elog(NOTICE, "ENABLE_SORT is %s",
enable_sort ? "ON" : "OFF");
return TRUE;
}
static bool
reset_enable_sort()
{
enable_sort = true;
return TRUE;
}
/*
* ENABLE_NESTLOOP
*/
static bool
parse_enable_nestloop(const char *value)
{
return parse_boolean_var(value, &enable_nestloop,
"ENABLE_NESTLOOP", true);
}
static bool
show_enable_nestloop()
{
elog(NOTICE, "ENABLE_NESTLOOP is %s",
enable_nestloop ? "ON" : "OFF");
return TRUE;
}
static bool
reset_enable_nestloop()
{
enable_nestloop = true;
return TRUE;
}
/*
* ENABLE_MERGEJOIN
*/
static bool
parse_enable_mergejoin(const char *value)
{
return parse_boolean_var(value, &enable_mergejoin,
"ENABLE_MERGEJOIN", true);
}
static bool
show_enable_mergejoin()
{
elog(NOTICE, "ENABLE_MERGEJOIN is %s",
enable_mergejoin ? "ON" : "OFF");
return TRUE;
}
static bool
reset_enable_mergejoin()
{
enable_mergejoin = true;
return TRUE;
}
/*
* ENABLE_HASHJOIN
*/
static bool
parse_enable_hashjoin(const char *value)
{
return parse_boolean_var(value, &enable_hashjoin,
"ENABLE_HASHJOIN", true);
}
static bool
show_enable_hashjoin()
{
elog(NOTICE, "ENABLE_HASHJOIN is %s",
enable_hashjoin ? "ON" : "OFF");
return TRUE;
}
static bool
reset_enable_hashjoin()
{
enable_hashjoin = true;
return TRUE;
}
/*
*
* GEQO
*
*/
static 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)
{
int new_geqo_rels = GEQO_RELS;
if (val != NULL)
{
new_geqo_rels = pg_atoi(val, sizeof(int), '\0');
if (new_geqo_rels <= 1)
elog(ERROR, "Bad value for # of relations (%s)", val);
pfree(val);
}
enable_geqo = true;
geqo_rels = new_geqo_rels;
}
else if (strcasecmp(tok, "off") == 0)
{
if ((val != NULL) && (*val != '\0'))
elog(ERROR, "%s does not allow a parameter", tok);
enable_geqo = false;
}
else
elog(ERROR, "Bad value for GEQO (%s)", value);
pfree(tok);
return TRUE;
}
static bool
show_geqo()
{
if (enable_geqo)
elog(NOTICE, "GEQO is ON beginning with %d relations", geqo_rels);
else
elog(NOTICE, "GEQO is OFF");
return TRUE;
}
static bool
reset_geqo(void)
{
#ifdef GEQO
enable_geqo = true;
#else
enable_geqo = false;
#endif
geqo_rels = GEQO_RELS;
return TRUE;
}
/*
* EFFECTIVE_CACHE_SIZE
*/
static bool
parse_effective_cache_size(const char *value)
{
float64 res;
if (value == NULL)
{
reset_effective_cache_size();
return TRUE;
}
res = float8in((char *) value);
effective_cache_size = *res;
return TRUE;
}
static bool
show_effective_cache_size()
{
elog(NOTICE, "EFFECTIVE_CACHE_SIZE is %g (%dK pages)",
effective_cache_size, BLCKSZ/1024);
return TRUE;
}
static bool
reset_effective_cache_size()
{
effective_cache_size = DEFAULT_EFFECTIVE_CACHE_SIZE;
return TRUE;
}
/*
* RANDOM_PAGE_COST
*/
static bool
parse_random_page_cost(const char *value)
{
float64 res;
if (value == NULL)
{
reset_random_page_cost();
return TRUE;
}
res = float8in((char *) value);
random_page_cost = *res;
return TRUE;
}
static bool
show_random_page_cost()
{
elog(NOTICE, "RANDOM_PAGE_COST is %g", random_page_cost);
return TRUE;
}
static bool
reset_random_page_cost()
{
random_page_cost = DEFAULT_RANDOM_PAGE_COST;
return TRUE;
}
/*
* CPU_TUPLE_COST
*/
static bool
parse_cpu_tuple_cost(const char *value)
{
float64 res;
if (value == NULL)
{
reset_cpu_tuple_cost();
return TRUE;
}
res = float8in((char *) value);
cpu_tuple_cost = *res;
return TRUE;
}
static bool
show_cpu_tuple_cost()
{
elog(NOTICE, "CPU_TUPLE_COST is %g", cpu_tuple_cost);
return TRUE;
}
static bool
reset_cpu_tuple_cost()
{
cpu_tuple_cost = DEFAULT_CPU_TUPLE_COST;
return TRUE;
}
/*
* CPU_INDEX_TUPLE_COST
*/
static bool
parse_cpu_index_tuple_cost(const char *value)
{
float64 res;
if (value == NULL)
{
reset_cpu_index_tuple_cost();
return TRUE;
}
res = float8in((char *) value);
cpu_index_tuple_cost = *res;
return TRUE;
}
static bool
show_cpu_index_tuple_cost()
{
elog(NOTICE, "CPU_INDEX_TUPLE_COST is %g", cpu_index_tuple_cost);
return TRUE;
}
static bool
reset_cpu_index_tuple_cost()
{
cpu_index_tuple_cost = DEFAULT_CPU_INDEX_TUPLE_COST;
return TRUE;
}
/*
* CPU_OPERATOR_COST
*/
static bool
parse_cpu_operator_cost(const char *value)
{
float64 res;
if (value == NULL)
{
reset_cpu_operator_cost();
return TRUE;
}
res = float8in((char *) value);
cpu_operator_cost = *res;
return TRUE;
}
static bool
show_cpu_operator_cost()
{
elog(NOTICE, "CPU_OPERATOR_COST is %g", cpu_operator_cost);
return TRUE;
}
static bool
reset_cpu_operator_cost()
{
cpu_operator_cost = DEFAULT_CPU_OPERATOR_COST;
return TRUE;
}
/*
*
* DATE_STYLE
*
*/
static 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;
}
static 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;
}
static 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];
/*
*
* TIMEZONE
*
*/
/* parse_timezone()
* Handle SET TIME ZONE...
* Try to save existing TZ environment variable for later use in RESET TIME ZONE.
* - thomas 1997-11-10
*/
static 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 ((defaultTZ = getenv("TZ")) != NULL)
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() */
static 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).
* - thomas 1998-01-26
*/
static bool
reset_timezone()
{
/* no time zone has been set in this session? */
if (defaultTZ == NULL)
{
}
/* time zone was set and original explicit time zone available? */
else if (defaultTZ != (char *) -1)
{
strcpy(tzbuf, "TZ=");
strcat(tzbuf, TZvalue);
if (putenv(tzbuf) != 0)
elog(ERROR, "Unable to set TZ environment variable to %s", TZvalue);
tzset();
}
/*
* otherwise, time zone was set but no original explicit time zone
* available
*/
else
{
strcpy(tzbuf, "=");
if (putenv(tzbuf) != 0)
elog(ERROR, "Unable to clear TZ environment variable");
tzset();
}
return TRUE;
} /* reset_timezone() */
/*-----------------------------------------------------------------------
KSQO code will one day be unnecessary when the optimizer makes use of
indexes when multiple ORs are specified in the where clause.
See optimizer/prep/prepkeyset.c for more on this.
daveh@insightdist.com 6/16/98
-----------------------------------------------------------------------*/
static bool
parse_ksqo(const char *value)
{
return parse_boolean_var(value, &_use_keyset_query_optimizer,
"KSQO", false);
}
static bool
show_ksqo()
{
elog(NOTICE, "KSQO is %s",
_use_keyset_query_optimizer ? "ON" : "OFF");
return TRUE;
}
static bool
reset_ksqo()
{
_use_keyset_query_optimizer = false;
return TRUE;
}
/* SET TRANSACTION */
static bool
parse_XactIsoLevel(const char *value)
{
if (value == NULL)
{
reset_XactIsoLevel();
return TRUE;
}
if (SerializableSnapshot != NULL)
{
elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
return TRUE;
}
if (strcasecmp(value, "SERIALIZABLE") == 0)
XactIsoLevel = XACT_SERIALIZABLE;
else if (strcasecmp(value, "COMMITTED") == 0)
XactIsoLevel = XACT_READ_COMMITTED;
else
elog(ERROR, "Bad TRANSACTION ISOLATION LEVEL (%s)", value);
return TRUE;
}
static bool
show_XactIsoLevel()
{
if (XactIsoLevel == XACT_SERIALIZABLE)
elog(NOTICE, "TRANSACTION ISOLATION LEVEL is SERIALIZABLE");
else
elog(NOTICE, "TRANSACTION ISOLATION LEVEL is READ COMMITTED");
return TRUE;
}
static bool
reset_XactIsoLevel()
{
if (SerializableSnapshot != NULL)
{
elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
return TRUE;
}
XactIsoLevel = DefaultXactIsoLevel;
return TRUE;
}
/*
* Pg_options
*/
static bool
parse_pg_options(const char *value)
{
if (!superuser()) {
elog(ERROR, "Only users with superuser privilege can set pg_options");
}
parse_options((char *) value, TRUE);
return (TRUE);
}
static bool
show_pg_options(void)
{
show_options();
return (TRUE);
}
static bool
reset_pg_options(void)
{
if (!superuser()) {
elog(ERROR, "Only users with superuser privilege can set pg_options");
}
read_pg_options(0);
return (TRUE);
}
/*-----------------------------------------------------------------------*/
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
},
{
"effective_cache_size", parse_effective_cache_size,
show_effective_cache_size, reset_effective_cache_size
},
{
"random_page_cost", parse_random_page_cost,
show_random_page_cost, reset_random_page_cost
},
{
"cpu_tuple_cost", parse_cpu_tuple_cost,
show_cpu_tuple_cost, reset_cpu_tuple_cost
},
{
"cpu_index_tuple_cost", parse_cpu_index_tuple_cost,
show_cpu_index_tuple_cost, reset_cpu_index_tuple_cost
},
{
"cpu_operator_cost", parse_cpu_operator_cost,
show_cpu_operator_cost, reset_cpu_operator_cost
},
{
"enable_seqscan", parse_enable_seqscan,
show_enable_seqscan, reset_enable_seqscan
},
{
"enable_indexscan", parse_enable_indexscan,
show_enable_indexscan, reset_enable_indexscan
},
{
"enable_tidscan", parse_enable_tidscan,
show_enable_tidscan, reset_enable_tidscan
},
{
"enable_sort", parse_enable_sort,
show_enable_sort, reset_enable_sort
},
{
"enable_nestloop", parse_enable_nestloop,
show_enable_nestloop, reset_enable_nestloop
},
{
"enable_mergejoin", parse_enable_mergejoin,
show_enable_mergejoin, reset_enable_mergejoin
},
{
"enable_hashjoin", parse_enable_hashjoin,
show_enable_hashjoin, reset_enable_hashjoin
},
{
"geqo", parse_geqo, show_geqo, reset_geqo
},
#ifdef MULTIBYTE
{
"client_encoding", parse_client_encoding, show_client_encoding, reset_client_encoding
},
{
"server_encoding", parse_server_encoding, show_server_encoding, reset_server_encoding
},
#endif
{
"ksqo", parse_ksqo, show_ksqo, reset_ksqo
},
{
"XactIsoLevel", parse_XactIsoLevel, show_XactIsoLevel, reset_XactIsoLevel
},
{
"pg_options", parse_pg_options, show_pg_options, reset_pg_options
},
{
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;
}