From 52a8d4f8f7e286482886861175312c1434b1d4fd Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Mon, 10 Mar 2008 12:55:13 +0000 Subject: [PATCH] Implement enum type for guc parameters, and convert a couple of existing variables to it. More need to be converted, but I wanted to get this in before it conflicts with too much... Other than just centralising the text-to-int conversion for parameters, this allows the pg_settings view to contain a list of available options and allows an error hint to show what values are allowed. --- doc/src/sgml/catalogs.sgml | 12 +- doc/src/sgml/config.sgml | 5 +- src/backend/catalog/system_views.sql | 4 +- src/backend/tcop/postgres.c | 4 +- src/backend/utils/error/elog.c | 4 +- src/backend/utils/misc/guc.c | 607 +++++++++++++++++---------- src/include/tcop/tcopprot.h | 4 +- src/include/utils/elog.h | 4 +- src/include/utils/guc.h | 3 +- src/include/utils/guc_tables.h | 28 +- src/test/regress/expected/rules.out | 2 +- 11 files changed, 440 insertions(+), 237 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 8a16c77a7d..4c92c2c77a 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,4 +1,4 @@ - + @@ -6260,8 +6260,8 @@ vartype text - Parameter type (bool, integer, - real, or string) + Parameter type (bool, enum, + integer, real, or string) @@ -6281,6 +6281,12 @@ Maximum allowed value of the parameter (NULL for non-numeric values) + + enumvals + text + Allowed values in enum parameters (NULL for non-enum + values) + diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 0c2740890d..38f996ec0b 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -1,4 +1,4 @@ - + Server Configuration @@ -162,7 +162,8 @@ SET ENABLE_SEQSCAN TO OFF; displaying and updating session run-time parameters. It is equivalent to SHOW and SET, but can be more convenient to use because it can be joined with other tables, or selected from using - any desired selection condition. + any desired selection condition. It also contains more information about + what values are allowed for the parameters. diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 52fbc91ed7..0bbf48ac07 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -3,7 +3,7 @@ * * Copyright (c) 1996-2008, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.48 2008/01/01 19:45:48 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.49 2008/03/10 12:55:13 mha Exp $ */ CREATE VIEW pg_roles AS @@ -173,7 +173,7 @@ CREATE VIEW pg_settings AS SELECT * FROM pg_show_all_settings() AS A (name text, setting text, unit text, category text, short_desc text, extra_desc text, - context text, vartype text, source text, min_val text, max_val text); + context text, vartype text, source text, min_val text, max_val text, enumvals text); CREATE RULE pg_settings_u AS ON UPDATE TO pg_settings diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index c95695b7f9..9fc0389d96 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.543 2008/02/17 04:21:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.544 2008/03/10 12:55:13 mha Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -85,7 +85,7 @@ CommandDest whereToSendOutput = DestDebug; /* flag for logging end of session */ bool Log_disconnections = false; -LogStmtLevel log_statement = LOGSTMT_NONE; +int log_statement = LOGSTMT_NONE; /* GUC variable for maximum stack depth (measured in kilobytes) */ int max_stack_depth = 100; diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index cdb40bb13e..8ff4c2fb67 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -42,7 +42,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.201 2008/01/01 19:45:53 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.202 2008/03/10 12:55:13 mha Exp $ * *------------------------------------------------------------------------- */ @@ -80,7 +80,7 @@ sigjmp_buf *PG_exception_stack = NULL; extern bool redirection_done; /* GUC parameters */ -PGErrorVerbosity Log_error_verbosity = PGERROR_VERBOSE; +int Log_error_verbosity = PGERROR_VERBOSE; char *Log_line_prefix = NULL; /* format for extra log line info */ int Log_destination = LOG_DESTINATION_STDERR; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 49958cb4e7..9f7e87037f 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.436 2008/03/10 12:39:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.437 2008/03/10 12:55:13 mha Exp $ * *-------------------------------------------------------------------- */ @@ -144,18 +144,6 @@ static const char *assign_defaultxactisolevel(const char *newval, bool doit, GucSource source); static const char *assign_session_replication_role(const char *newval, bool doit, GucSource source); -static const char *assign_log_min_messages(const char *newval, bool doit, - GucSource source); -static const char *assign_client_min_messages(const char *newval, - bool doit, GucSource source); -static const char *assign_min_error_statement(const char *newval, bool doit, - GucSource source); -static const char *assign_msglvl(int *var, const char *newval, bool doit, - GucSource source); -static const char *assign_log_error_verbosity(const char *newval, bool doit, - GucSource source); -static const char *assign_log_statement(const char *newval, bool doit, - GucSource source); static const char *show_num_temp_buffers(void); static bool assign_phony_autocommit(bool newval, bool doit, GucSource source); static const char *assign_custom_variable_classes(const char *newval, bool doit, @@ -180,6 +168,41 @@ static const char *show_tcp_keepalives_count(void); static bool assign_autovacuum_max_workers(int newval, bool doit, GucSource source); static bool assign_maxconnections(int newval, bool doit, GucSource source); +/* + * Options for enum values defined in this module. + */ +static const struct config_enum_entry message_level_options[] = { + {"debug", DEBUG2}, + {"debug5", DEBUG5}, + {"debug4", DEBUG4}, + {"debug3", DEBUG3}, + {"debug2", DEBUG2}, + {"debug1", DEBUG1}, + {"log", LOG}, + {"info", INFO}, + {"notice", NOTICE}, + {"warning", WARNING}, + {"error", ERROR}, + {"fatal", FATAL}, + {"panic", PANIC}, + {NULL, 0} +}; + +static const struct config_enum_entry log_error_verbosity_options[] = { + {"default", PGERROR_DEFAULT}, + {"terse", PGERROR_TERSE}, + {"verbose", PGERROR_VERBOSE}, + {NULL, 0} +}; + +static const struct config_enum_entry log_statement_options[] = { + {"none", LOGSTMT_NONE}, + {"ddl", LOGSTMT_DDL}, + {"mod", LOGSTMT_MOD}, + {"all", LOGSTMT_ALL}, + {NULL, 0} +}; + /* * GUC option variables that are exported from this module */ @@ -230,11 +253,6 @@ int tcp_keepalives_count; * cases provide the value for SHOW to display. The real state is elsewhere * and is kept in sync by assign_hooks. */ -static char *client_min_messages_str; -static char *log_min_messages_str; -static char *log_error_verbosity_str; -static char *log_statement_str; -static char *log_min_error_statement_str; static char *log_destination_string; #ifdef HAVE_SYSLOG @@ -400,7 +418,8 @@ const char *const config_type_names[] = /* PGC_BOOL */ "bool", /* PGC_INT */ "integer", /* PGC_REAL */ "real", - /* PGC_STRING */ "string" + /* PGC_STRING */ "string", + /* PGC_ENUM */ "enum" }; @@ -1915,56 +1934,6 @@ static struct config_string ConfigureNamesString[] = "SQL_ASCII", assign_client_encoding, NULL }, - { - {"client_min_messages", PGC_USERSET, LOGGING_WHEN, - gettext_noop("Sets the message levels that are sent to the client."), - gettext_noop("Valid values are DEBUG5, DEBUG4, DEBUG3, DEBUG2, " - "DEBUG1, LOG, NOTICE, WARNING, and ERROR. Each level includes all the " - "levels that follow it. The later the level, the fewer messages are " - "sent.") - }, - &client_min_messages_str, - "notice", assign_client_min_messages, NULL - }, - - { - {"log_min_messages", PGC_SUSET, LOGGING_WHEN, - gettext_noop("Sets the message levels that are logged."), - gettext_noop("Valid values are DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, " - "INFO, NOTICE, WARNING, ERROR, LOG, FATAL, and PANIC. Each level " - "includes all the levels that follow it.") - }, - &log_min_messages_str, - "warning", assign_log_min_messages, NULL - }, - - { - {"log_error_verbosity", PGC_SUSET, LOGGING_WHEN, - gettext_noop("Sets the verbosity of logged messages."), - gettext_noop("Valid values are \"terse\", \"default\", and \"verbose\".") - }, - &log_error_verbosity_str, - "default", assign_log_error_verbosity, NULL - }, - { - {"log_statement", PGC_SUSET, LOGGING_WHAT, - gettext_noop("Sets the type of statements logged."), - gettext_noop("Valid values are \"none\", \"ddl\", \"mod\", and \"all\".") - }, - &log_statement_str, - "none", assign_log_statement, NULL - }, - - { - {"log_min_error_statement", PGC_SUSET, LOGGING_WHEN, - gettext_noop("Causes all statements generating error at or above this level to be logged."), - gettext_noop("All SQL statements that cause an error of the " - "specified level or a higher level are logged.") - }, - &log_min_error_statement_str, - "error", assign_min_error_statement, NULL - }, - { {"log_line_prefix", PGC_SIGHUP, LOGGING_WHAT, gettext_noop("Controls information prefixed to each log line."), @@ -2461,6 +2430,68 @@ static struct config_string ConfigureNamesString[] = }; +static struct config_enum ConfigureNamesEnum[] = +{ + { + {"client_min_messages", PGC_USERSET, LOGGING_WHEN, + gettext_noop("Sets the message levels that are sent to the client."), + gettext_noop("Valid values are DEBUG5, DEBUG4, DEBUG3, DEBUG2, " + "DEBUG1, LOG, NOTICE, WARNING, and ERROR. Each level includes all the " + "levels that follow it. The later the level, the fewer messages are " + "sent.") + }, + &client_min_messages, + NOTICE, message_level_options,NULL, NULL + }, + + { + {"log_error_verbosity", PGC_SUSET, LOGGING_WHEN, + gettext_noop("Sets the verbosity of logged messages."), + gettext_noop("Valid values are \"terse\", \"default\", and \"verbose\".") + }, + &Log_error_verbosity, + PGERROR_DEFAULT, log_error_verbosity_options, NULL, NULL + }, + + { + {"log_min_messages", PGC_SUSET, LOGGING_WHEN, + gettext_noop("Sets the message levels that are logged."), + gettext_noop("Valid values are DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, " + "INFO, NOTICE, WARNING, ERROR, LOG, FATAL, and PANIC. Each level " + "includes all the levels that follow it.") + }, + &log_min_messages, + WARNING, message_level_options, NULL, NULL + }, + + { + {"log_min_error_statement", PGC_SUSET, LOGGING_WHEN, + gettext_noop("Causes all statements generating error at or above this level to be logged."), + gettext_noop("All SQL statements that cause an error of the " + "specified level or a higher level are logged.") + }, + &log_min_error_statement, + ERROR, message_level_options, NULL, NULL + }, + + { + {"log_statement", PGC_SUSET, LOGGING_WHAT, + gettext_noop("Sets the type of statements logged."), + gettext_noop("Valid values are \"none\", \"ddl\", \"mod\", and \"all\".") + }, + &log_statement, + LOGSTMT_NONE, log_statement_options, NULL, NULL + }, + + + + + /* End-of-list marker */ + { + {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL + } +}; + /******** end of options list ********/ @@ -2627,6 +2658,10 @@ set_stack_value(struct config_generic * gconf, union config_var_value * val) &(val->stringval), *((struct config_string *) gconf)->variable); break; + case PGC_ENUM: + val->enumval = + *((struct config_enum *) gconf)->variable; + break; } } @@ -2641,6 +2676,7 @@ discard_stack_value(struct config_generic * gconf, union config_var_value * val) case PGC_BOOL: case PGC_INT: case PGC_REAL: + case PGC_ENUM: /* no need to do anything */ break; case PGC_STRING: @@ -2708,6 +2744,14 @@ build_guc_variables(void) num_vars++; } + for (i = 0; ConfigureNamesEnum[i].gen.name; i++) + { + struct config_enum *conf = &ConfigureNamesEnum[i]; + + conf->gen.vartype = PGC_ENUM; + num_vars++; + } + /* * Create table with 20% slack */ @@ -2730,6 +2774,9 @@ build_guc_variables(void) for (i = 0; ConfigureNamesString[i].gen.name; i++) guc_vars[num_vars++] = &ConfigureNamesString[i].gen; + for (i = 0; ConfigureNamesEnum[i].gen.name; i++) + guc_vars[num_vars++] = &ConfigureNamesEnum[i].gen; + if (guc_variables) free(guc_variables); guc_variables = guc_vars; @@ -3080,6 +3127,18 @@ InitializeGUCOptions(void) *conf->variable = str; break; } + case PGC_ENUM: + { + struct config_enum *conf = (struct config_enum *) gconf; + + if (conf->assign_hook) + if (!(*conf->assign_hook) (conf->boot_val, true, + PGC_S_DEFAULT)) + elog(FATAL, "failed to initialize %s to %d", + conf->gen.name, conf->boot_val); + *conf->variable = conf->reset_val = conf->boot_val; + break; + } } } @@ -3379,6 +3438,18 @@ ResetAllOptions(void) conf->gen.source = conf->gen.reset_source; break; } + case PGC_ENUM: + { + struct config_enum *conf = (struct config_enum *) gconf; + + if (conf->assign_hook) + if (!(*conf->assign_hook) (conf->reset_val, true, + PGC_S_SESSION)) + elog(ERROR, "failed to reset %s", conf->gen.name); + *conf->variable = conf->reset_val; + conf->gen.source = conf->gen.reset_source; + break; + } } if (gconf->flags & GUC_REPORT) @@ -3728,6 +3799,23 @@ AtEOXact_GUC(bool isCommit, int nestLevel) set_string_field(conf, &stack->masked.stringval, NULL); break; } + case PGC_ENUM: + { + struct config_enum *conf = (struct config_enum *) gconf; + int newval = newvalue.enumval; + + if (*conf->variable != newval) + { + if (conf->assign_hook) + if (!(*conf->assign_hook) (newval, + true, PGC_S_OVERRIDE)) + elog(LOG, "failed to commit %s", + conf->gen.name); + *conf->variable = newval; + changed = true; + } + break; + } } gconf->source = newsource; @@ -4114,6 +4202,100 @@ parse_real(const char *value, double *result) } +/* + * Lookup the name for an enum option with the selected value. + * Should only ever be called with known-valid values, so throws + * an elog(ERROR) if the enum option is not found. + * + * The returned string is a pointer to static data and not + * allocated for modification. + */ +static const char * +config_enum_lookup_value(struct config_enum *record, int val) +{ + const struct config_enum_entry *entry = record->options; + while (entry && entry->name) + { + if (entry->val == val) + return entry->name; + entry++; + } + elog(ERROR, "could not find enum option %d for %s", + val, record->gen.name); + return NULL; /* silence compiler */ +} + + +/* + * Lookup the value for an enum option with the selected name + * (case-insensitive). + * If the enum option is found, sets the retval value and returns + * true. If it's not found, return FALSE and don't touch retval. + * + */ +static bool +config_enum_lookup_name(struct config_enum *record, const char *value, int *retval) +{ + const struct config_enum_entry *entry = record->options; + + if (retval) + *retval = 0; /* suppress compiler warning */ + + while (entry && entry->name) + { + if (!pg_strcasecmp(value, entry->name)) + { + *retval = entry->val; + return TRUE; + } + entry++; + } + return FALSE; +} + + +/* + * Returna list of all available options for an enum, separated + * by ", " (comma-space). + * If prefix is gievn, it is added before the first enum value. + * If suffix is given, it is added to the end of the string. + */ +static char * +config_enum_get_options(struct config_enum *record, const char *prefix, const char *suffix) +{ + const struct config_enum_entry *entry = record->options; + int len = 0; + char *hintmsg; + + if (!entry || !entry->name) + return NULL; /* Should not happen */ + + while (entry && entry->name) + { + len += strlen(entry->name) + 2; /* string and ", " */ + entry++; + } + + hintmsg = palloc(len + strlen(prefix) + strlen(suffix) + 2); + + strcpy(hintmsg, prefix); + + entry = record->options; + while (entry && entry->name) + { + strcat(hintmsg, entry->name); + strcat(hintmsg, ", "); + entry++; + } + + /* Replace final comma/space */ + hintmsg[strlen(hintmsg)-2] = '\0'; + strcat(hintmsg, suffix); + + return hintmsg; +} + + /* * Call a GucStringAssignHook function, being careful to free the * "newval" string if the hook ereports. @@ -4678,6 +4860,77 @@ set_config_option(const char *name, const char *value, free(newval); break; } + case PGC_ENUM: + { + struct config_enum *conf = (struct config_enum *) record; + int newval; + + if (value) + { + if (!config_enum_lookup_name(conf, value, &newval)) + { + char *hintmsg = config_enum_get_options(conf, "Available values: ", "."); + + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", + name, value), + hintmsg ? errhint(hintmsg) : 0)); + + if (hintmsg) + pfree(hintmsg); + return false; + } + } + else if (source == PGC_S_DEFAULT) + newval = conf->boot_val; + else + { + newval = conf->reset_val; + source = conf->gen.reset_source; + } + + if (conf->assign_hook) + if (!(*conf->assign_hook) (newval, changeVal, source)) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%d\"", + name, newval))); + return false; + } + + if (changeVal || makeDefault) + { + /* Save old value to support transaction abort */ + if (!makeDefault) + push_old_value(&conf->gen, action); + if (changeVal) + { + *conf->variable = newval; + conf->gen.source = source; + } + if (makeDefault) + { + GucStack *stack; + + if (conf->gen.reset_source <= source) + { + conf->reset_val = newval; + conf->gen.reset_source = source; + } + for (stack = conf->gen.stack; stack; stack = stack->prev) + { + if (stack->source <= source) + { + stack->prior.enumval = newval; + stack->source = source; + } + } + } + } + break; + } } if (changeVal && (record->flags & GUC_REPORT)) @@ -4742,6 +4995,10 @@ GetConfigOption(const char *name) case PGC_STRING: return *((struct config_string *) record)->variable; + + case PGC_ENUM: + return config_enum_lookup_value((struct config_enum *) record, + *((struct config_enum *) record)->variable); } return NULL; } @@ -4786,6 +5043,10 @@ GetConfigOptionResetString(const char *name) case PGC_STRING: return ((struct config_string *) record)->reset_val; + + case PGC_ENUM: + return config_enum_lookup_value((struct config_enum *) record, + ((struct config_enum *) record)->reset_val); } return NULL; } @@ -5597,6 +5858,9 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) /* max_val */ values[10] = NULL; + + /* enumvals */ + values[11] = NULL; } break; @@ -5611,6 +5875,9 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) /* max_val */ snprintf(buffer, sizeof(buffer), "%d", lconf->max); values[10] = pstrdup(buffer); + + /* enumvals */ + values[11] = NULL; } break; @@ -5625,6 +5892,9 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) /* max_val */ snprintf(buffer, sizeof(buffer), "%g", lconf->max); values[10] = pstrdup(buffer); + + /* enumvals */ + values[11] = NULL; } break; @@ -5635,6 +5905,22 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) /* max_val */ values[10] = NULL; + + /* enumvals */ + values[11] = NULL; + } + break; + + case PGC_ENUM: + { + /* min_val */ + values[9] = NULL; + + /* max_val */ + values[10] = NULL; + + /* enumvals */ + values[11] = config_enum_get_options((struct config_enum *) conf, "", ""); } break; @@ -5649,6 +5935,9 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) /* max_val */ values[10] = NULL; + + /* enumvals */ + values[11] = NULL; } break; } @@ -5691,7 +5980,7 @@ show_config_by_name(PG_FUNCTION_ARGS) * show_all_settings - equiv to SHOW ALL command but implemented as * a Table Function. */ -#define NUM_PG_SETTINGS_ATTS 11 +#define NUM_PG_SETTINGS_ATTS 12 Datum show_all_settings(PG_FUNCTION_ARGS) @@ -5741,6 +6030,8 @@ show_all_settings(PG_FUNCTION_ARGS) TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 11, "max_val", TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 12, "enumvals", + TEXTOID, -1, 0); /* * Generate attribute metadata needed later to produce tuples from raw @@ -5933,6 +6224,17 @@ _ShowOption(struct config_generic * record, bool use_units) } break; + case PGC_ENUM: + { + struct config_enum *conf = (struct config_enum *) record; + + if(conf->show_hook) + val = (*conf->show_hook) (); + else + val = config_enum_lookup_value(conf, *conf->variable); + } + break; + default: /* just to keep compiler quiet */ val = "???"; @@ -5989,6 +6291,15 @@ is_newvalue_equal(struct config_generic * record, const char *newvalue) return *conf->variable != NULL && strcmp(*conf->variable, newvalue) == 0; } + + case PGC_ENUM: + { + struct config_enum *conf = (struct config_enum *) record; + int newval; + + return config_enum_lookup_name(conf, newvalue, &newval) + && *conf->variable == newval; + } } return false; @@ -6075,6 +6386,14 @@ write_nondefault_variables(GucContext context) fprintf(fp, "%s", *conf->variable); } break; + + case PGC_ENUM: + { + struct config_enum *conf = (struct config_enum *) gconf; + + fprintf(fp, "%s", config_enum_lookup_value(conf, *conf->variable)); + } + break; } fputc(0, fp); @@ -6600,154 +6919,6 @@ assign_session_replication_role(const char *newval, bool doit, GucSource source) return newval; } -static const char * -assign_log_min_messages(const char *newval, bool doit, GucSource source) -{ - return (assign_msglvl(&log_min_messages, newval, doit, source)); -} - -static const char * -assign_client_min_messages(const char *newval, bool doit, GucSource source) -{ - return (assign_msglvl(&client_min_messages, newval, doit, source)); -} - -static const char * -assign_min_error_statement(const char *newval, bool doit, GucSource source) -{ - return (assign_msglvl(&log_min_error_statement, newval, doit, source)); -} - -static const char * -assign_msglvl(int *var, const char *newval, bool doit, GucSource source) -{ - if (pg_strcasecmp(newval, "debug") == 0) - { - if (doit) - (*var) = DEBUG2; - } - else if (pg_strcasecmp(newval, "debug5") == 0) - { - if (doit) - (*var) = DEBUG5; - } - else if (pg_strcasecmp(newval, "debug4") == 0) - { - if (doit) - (*var) = DEBUG4; - } - else if (pg_strcasecmp(newval, "debug3") == 0) - { - if (doit) - (*var) = DEBUG3; - } - else if (pg_strcasecmp(newval, "debug2") == 0) - { - if (doit) - (*var) = DEBUG2; - } - else if (pg_strcasecmp(newval, "debug1") == 0) - { - if (doit) - (*var) = DEBUG1; - } - else if (pg_strcasecmp(newval, "log") == 0) - { - if (doit) - (*var) = LOG; - } - - /* - * Client_min_messages always prints 'info', but we allow it as a value - * anyway. - */ - else if (pg_strcasecmp(newval, "info") == 0) - { - if (doit) - (*var) = INFO; - } - else if (pg_strcasecmp(newval, "notice") == 0) - { - if (doit) - (*var) = NOTICE; - } - else if (pg_strcasecmp(newval, "warning") == 0) - { - if (doit) - (*var) = WARNING; - } - else if (pg_strcasecmp(newval, "error") == 0) - { - if (doit) - (*var) = ERROR; - } - /* We allow FATAL/PANIC for client-side messages too. */ - else if (pg_strcasecmp(newval, "fatal") == 0) - { - if (doit) - (*var) = FATAL; - } - else if (pg_strcasecmp(newval, "panic") == 0) - { - if (doit) - (*var) = PANIC; - } - else - return NULL; /* fail */ - return newval; /* OK */ -} - -static const char * -assign_log_error_verbosity(const char *newval, bool doit, GucSource source) -{ - if (pg_strcasecmp(newval, "terse") == 0) - { - if (doit) - Log_error_verbosity = PGERROR_TERSE; - } - else if (pg_strcasecmp(newval, "default") == 0) - { - if (doit) - Log_error_verbosity = PGERROR_DEFAULT; - } - else if (pg_strcasecmp(newval, "verbose") == 0) - { - if (doit) - Log_error_verbosity = PGERROR_VERBOSE; - } - else - return NULL; /* fail */ - return newval; /* OK */ -} - -static const char * -assign_log_statement(const char *newval, bool doit, GucSource source) -{ - if (pg_strcasecmp(newval, "none") == 0) - { - if (doit) - log_statement = LOGSTMT_NONE; - } - else if (pg_strcasecmp(newval, "ddl") == 0) - { - if (doit) - log_statement = LOGSTMT_DDL; - } - else if (pg_strcasecmp(newval, "mod") == 0) - { - if (doit) - log_statement = LOGSTMT_MOD; - } - else if (pg_strcasecmp(newval, "all") == 0) - { - if (doit) - log_statement = LOGSTMT_ALL; - } - else - return NULL; /* fail */ - return newval; /* OK */ -} - static const char * show_num_temp_buffers(void) { diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index 251d9ec92d..ef87e1ee05 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.92 2008/01/01 19:45:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.93 2008/03/10 12:55:13 mha Exp $ * * OLD COMMENTS * This file was created so that other c files could get the two @@ -42,7 +42,7 @@ typedef enum LOGSTMT_ALL /* log all statements */ } LogStmtLevel; -extern LogStmtLevel log_statement; +extern int log_statement; extern List *pg_parse_and_rewrite(const char *query_string, Oid *paramTypes, int numParams); diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 57ca153392..78939baa89 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.90 2008/01/01 19:45:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.91 2008/03/10 12:55:13 mha Exp $ * *------------------------------------------------------------------------- */ @@ -283,7 +283,7 @@ typedef enum PGERROR_VERBOSE /* all the facts, ma'am */ } PGErrorVerbosity; -extern PGErrorVerbosity Log_error_verbosity; +extern int Log_error_verbosity; extern char *Log_line_prefix; extern int Log_destination; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 75dd42aaf9..43c37eb4ff 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -7,7 +7,7 @@ * Copyright (c) 2000-2008, PostgreSQL Global Development Group * Written by Peter Eisentraut . * - * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.90 2008/01/01 19:45:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.91 2008/03/10 12:55:13 mha Exp $ *-------------------------------------------------------------------- */ #ifndef GUC_H @@ -97,6 +97,7 @@ typedef const char *(*GucStringAssignHook) (const char *newval, bool doit, GucSo typedef bool (*GucBoolAssignHook) (bool newval, bool doit, GucSource source); typedef bool (*GucIntAssignHook) (int newval, bool doit, GucSource source); typedef bool (*GucRealAssignHook) (double newval, bool doit, GucSource source); +typedef bool (*GucEnumAssignHook) (int newval, bool doit, GucSource source); typedef const char *(*GucShowHook) (void); diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h index 3d389acb2f..2b8d8e6e3e 100644 --- a/src/include/utils/guc_tables.h +++ b/src/include/utils/guc_tables.h @@ -7,7 +7,7 @@ * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.38 2008/01/01 19:45:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.39 2008/03/10 12:55:13 mha Exp $ * *------------------------------------------------------------------------- */ @@ -24,7 +24,8 @@ enum config_type PGC_BOOL, PGC_INT, PGC_REAL, - PGC_STRING + PGC_STRING, + PGC_ENUM }; union config_var_value @@ -33,6 +34,16 @@ union config_var_value int intval; double realval; char *stringval; + int enumval; +}; + +/* + * Enum values are made up of an array of name-value pairs + */ +struct config_enum_entry +{ + const char *name; + int val; }; /* @@ -210,6 +221,19 @@ struct config_string char *reset_val; }; +struct config_enum +{ + struct config_generic gen; + /* constant fields, must be set correctly in initial value: */ + int *variable; + int boot_val; + const struct config_enum_entry *options; + GucEnumAssignHook assign_hook; + GucShowHook show_hook; + /* variable fields, initialized at runtime: */ + int reset_val; +}; + /* constant tables corresponding to enums above and in guc.h */ extern const char *const config_group_names[]; extern const char *const config_type_names[]; diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 3439642fe6..124ebf87dc 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1287,7 +1287,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem pg_prepared_xacts | SELECT p.transaction, p.gid, p.prepared, u.rolname AS owner, d.datname AS database FROM ((pg_prepared_xact() p(transaction xid, gid text, prepared timestamp with time zone, ownerid oid, dbid oid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid))); pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, pg_authid.rolconfig, pg_authid.oid FROM pg_authid; pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name); - pg_settings | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val FROM pg_show_all_settings() a(name text, setting text, unit text, category text, short_desc text, extra_desc text, context text, vartype text, source text, min_val text, max_val text); + pg_settings | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val, a.enumvals FROM pg_show_all_settings() a(name text, setting text, unit text, category text, short_desc text, extra_desc text, context text, vartype text, source text, min_val text, max_val text, enumvals text); pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, pg_authid.rolconfig AS useconfig FROM pg_authid WHERE pg_authid.rolcanlogin; pg_stat_activity | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.rolname AS usename, pg_stat_get_backend_activity(s.backendid) AS current_query, pg_stat_get_backend_waiting(s.backendid) AS waiting, pg_stat_get_backend_xact_start(s.backendid) AS xact_start, pg_stat_get_backend_activity_start(s.backendid) AS query_start, pg_stat_get_backend_start(s.backendid) AS backend_start, pg_stat_get_backend_client_addr(s.backendid) AS client_addr, pg_stat_get_backend_client_port(s.backendid) AS client_port FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_authid u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.oid)); pg_stat_all_indexes | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])); -- GitLab