diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-07-04 16:41:22 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-07-04 16:41:22 +0000 |
commit | b700a672feadbb6f122b7c7249967fb0f58dda2b (patch) | |
tree | 85013f1378d8edaa12cf35b039c4aa768bc9b4a9 /src/backend/utils/misc/help_config.c | |
parent | efbbd107c7b08b7a1351c0199ee4602182e09f05 (diff) | |
download | postgresql-b700a672feadbb6f122b7c7249967fb0f58dda2b.tar.gz postgresql-b700a672feadbb6f122b7c7249967fb0f58dda2b.zip |
Add --help-config facility to dump information about GUC parameters
without needing a running backend. Reorder postgresql.conf.sample
to match new layout of runtime.sgml. This commit re-adds work lost
in Wednesday's crash.
Diffstat (limited to 'src/backend/utils/misc/help_config.c')
-rw-r--r-- | src/backend/utils/misc/help_config.c | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/src/backend/utils/misc/help_config.c b/src/backend/utils/misc/help_config.c new file mode 100644 index 00000000000..0ea1fbd99d6 --- /dev/null +++ b/src/backend/utils/misc/help_config.c @@ -0,0 +1,461 @@ +/*------------------------------------------------------------------------- + * help_config.c + * + * Displays available options under grand unified configuration scheme + * + * The purpose of this option is to list, sort, and make searchable, all + * runtime options available to Postgresql, by their description and grouping. + * + * Valid command-line options to this program: + * + * none : All available variables are sorted by group and name + * and formatted nicely. ( for human consumption ) + * <string> : list all the variables whose name matches this string + * -g <string> : list all the variables whose group matches this string + * -l : lists all currently defined groups and terminates + * -G : no sort by groups (you get strict name order, instead) + * -m : output the list in Machine friendly format, with a header row + * -M : same as m, except no header + * -h : help + * + * Options whose flag bits are set to GUC_NO_SHOW_ALL, GUC_NOT_IN_SAMPLE, + * or GUC_DISALLOW_IN_FILE are not displayed, unless the user specifically + * requests that variable by name + * + * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/misc/help_config.c,v 1.1 2003/07/04 16:41:21 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include <fcntl.h> +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#endif +#include <errno.h> +#include <float.h> +#include <limits.h> +#include <unistd.h> + +#include "utils/guc.h" +#include "utils/guc_tables.h" +#include "utils/help_config.h" + +extern int optind; +extern char *optarg; + + +/* + * The following char constructs provide the different formats the variables + * can be outputted in. + */ +enum outputFormat +{ + HUMAN_OUTPUT, + MACHINE_OUTPUT +}; + +static const char * const GENERIC_FORMAT[] = { + gettext_noop("Name : %-20s \nContext : %-20s \nGroup : %-20s\n"), + gettext_noop("%s\t%s\t%s\t") +}; +static const char * const GENERIC_DESC[] = { + gettext_noop("Description: %s\n%s\n"), + gettext_noop("%s %s\n") +}; +static const char * const BOOL_FORMAT[] = { + gettext_noop("Type : BOOL\nReset Value: %-s \n"), + gettext_noop("BOOL\t%s\t\t\t") +}; +static const char * const INT_FORMAT[] = { + gettext_noop("Type : INT\nReset Value: %-20d \nMin Value : %-20d \nMax Value : %-20d \n"), + gettext_noop("INT\t%d\t%d\t%d\t") +}; +static const char * const REAL_FORMAT[] = { + gettext_noop("Type : REAL\nReset Value: %-20g \nMin Value : %-20g \nMax Value : %-20g \n"), + gettext_noop("REAL\t%g\t%g\t%g\t") +}; +static const char * const STRING_FORMAT[] = { + gettext_noop("Type : STRING\nReset Value: %-s \n"), + gettext_noop("STRING\t%s\t\t\t") +}; +static const char * const COLUMN_HEADER[] = { + "", + gettext_noop("NAME\tCONTEXT\tGROUP\tTYPE\tRESET_VALUE\tMIN\tMAX\tSHORT_DESCRIPTION\tLONG_DESCRIPTION\n") +}; +static const char * const ROW_SEPARATOR[] = { + "------------------------------------------------------------\n", + "" +}; + +/* + * Variables loaded from the command line + */ +static char *nameString = NULL; /* The var name pattern to match */ +static bool nameRegexBool = false; /* Match the name pattern as a + * regex */ +static char *groupString = NULL; /* The var group pattern to match */ +static bool groupRegexBool = false; /* Match the group pattern as a + * regex */ +static enum outputFormat outFormat = HUMAN_OUTPUT; +static bool suppressAllHeaders = false; /* MACHINE_OUTPUT output, no column + * headers */ +static bool groupResults = true; /* sort result list by groups */ + + +/* + * This union allows us to mix the numerous different types of structs + * that we are organizing. + */ +typedef union +{ + struct config_generic generic; + struct config_bool bool; + struct config_real real; + struct config_int integer; + struct config_string string; +} mixedStruct; + + +/* function prototypes */ +static bool varMatches(mixedStruct * structToTest); +static int compareMixedStructs(const void *, const void *); +static mixedStruct **varsToDisplay(int *resultListSize); +static const char *usageErrMsg(void); +static void helpMessage(void); +static void listAllGroups(void); +static void printGenericHead(struct config_generic structToPrint); +static void printGenericFoot(struct config_generic structToPrint); +static void printMixedStruct(mixedStruct * structToPrint); +static bool displayStruct(mixedStruct * structToDisplay); + +/* + * This array contains the display names for each of the GucContexts available + * + * Note: these strings are deliberately not localized. + */ +static const char *const GucContext_names[] = { + "INTERNAL", + "POSTMASTER", + "SIGHUP", + "BACKEND", + "SUSET", + "USERSET" +}; + +/* + * Reads in the the command line options and sets the state of the program + * accordingly. Initializes the result list and sorts it. + */ +int +GucInfoMain(int argc, char *argv[]) +{ + mixedStruct **varList; + int resultListSize; + int c; + int i; + + while ((c = getopt(argc, argv, "g:rGmMlh")) != -1) + { + switch (c) + { + case 'g': + groupString = optarg; + break; + case 'r': /* not actually implemented yet */ + nameRegexBool = true; + break; + case 'G': + groupResults = false; + break; + case 'm': + outFormat = MACHINE_OUTPUT; + break; + case 'M': + outFormat = MACHINE_OUTPUT; + suppressAllHeaders = true; + break; + case 'l': + listAllGroups(); + exit(0); + case 'h': + helpMessage(); + exit(0); + + default: + fprintf(stderr, gettext("%s \n Try -h for further details\n"), usageErrMsg()); + exit(1); + } + } + + if (optind < argc) + nameString = argv[optind]; + + /* get the list of variables that match the user's specs. */ + varList = varsToDisplay(&resultListSize); + + /* sort them by group if desired */ + /* (without this, we get the original sort by name from guc.c) */ + if (groupResults) + qsort(varList, resultListSize, + sizeof(mixedStruct *), compareMixedStructs); + + /* output the results */ + if (!suppressAllHeaders) + printf(gettext(COLUMN_HEADER[outFormat])); + + for (i = 0; varList[i] != NULL; i++) + { + printf(gettext(ROW_SEPARATOR[outFormat])); + printMixedStruct(varList[i]); + } + + return 0; +} + + +/* + * This function is used to compare two mixedStruct types. It compares based + * on the value of the 'group' field, and then the name of the variable. + * Each void* is expected to be a pointer to a pointer to a struct. + * (This is because it is used by qsort to sort an array of struct pointers) + * + * Returns an integer less than, equal to, or greater than zero if the first + * argument (struct1) is considered to be respectively less than, equal to, + * or greater than the second (struct2). The comparison is made frist on the + * value of struct{1,2}.generic.group and then struct{1,2}.generic.name. The + * groups will display in the order they are defined in enum config_group + */ +static int +compareMixedStructs(const void *struct1, const void *struct2) +{ + mixedStruct *structVar1 = *(mixedStruct **) struct1; + mixedStruct *structVar2 = *(mixedStruct **) struct2; + + if (structVar1->generic.group > structVar2->generic.group) + return 1; + else if (structVar1->generic.group < structVar2->generic.group) + return -1; + else + return strcmp(structVar1->generic.name, structVar2->generic.name); +} + + +/* + * This function returns a complete list of all the variables to display, + * according to what the user wants to see. + */ +static mixedStruct ** +varsToDisplay(int *resultListSize) +{ + mixedStruct **resultList; + int arrayIndex; + int i; + + /* Initialize the guc_variables[] array */ + build_guc_variables(); + + /* Extract just the ones we want to display */ + resultList = malloc((num_guc_variables + 1) * sizeof(mixedStruct *)); + arrayIndex = 0; + + for (i = 0; i < num_guc_variables; i++) + { + mixedStruct *var = (mixedStruct *) guc_variables[i]; + + if (varMatches(var)) + resultList[arrayIndex++] = var; + } + + /* add an end marker */ + resultList[arrayIndex] = NULL; + + *resultListSize = arrayIndex; + return resultList; +} + + +/* + * This function will return true if the struct passed to it + * should be displayed to the user. + * + * The criteria to determine if the struct should not be displayed is: + * + It's flag bits are set to GUC_NO_SHOW_ALL + * + It's flag bits are set to GUC_NOT_IN_SAMPLE + * + It's flag bits are set to GUC_DISALLOW_IN_FILE + */ +static bool +displayStruct(mixedStruct * structToDisplay) +{ + if (structToDisplay->generic.flags & (GUC_NO_SHOW_ALL | + GUC_NOT_IN_SAMPLE | + GUC_DISALLOW_IN_FILE)) + return false; + else + return true; +} + + +/* + * Used to determine if a variable matches the user's specifications (stored in + * global variables). Returns true if this particular variable information should + * be returned to the user. + */ +static bool +varMatches(mixedStruct * structToTest) +{ + bool matches = false; + bool specificSearch = false; /* This is true if the user + * searched for a variable in + * particular. */ + + if (nameString != NULL && !nameRegexBool) + { + if (strstr(structToTest->generic.name, nameString) != NULL) + { + matches = true; + specificSearch = true; + } + } + + if (nameString != NULL && nameRegexBool) + { + /* We do not support this option yet */ + } + + if (groupString != NULL && !groupRegexBool) + { + if (strstr(config_group_names[structToTest->generic.group], groupString) != NULL) + { + if (nameString != NULL) + matches = (matches && true); + else + matches = true; + } + else + matches = false; + } + + if (groupString != NULL && groupRegexBool) + { + /* We do not support this option yet */ + } + + /* return all variables */ + if (nameString == NULL && groupString == NULL) + matches = true; + + if (specificSearch) + return matches; + else + return matches && displayStruct(structToTest); +} + + +/* + * This function prints out the generic struct passed to it. It will print out + * a different format, depending on what the user wants to see. + */ +static void +printMixedStruct(mixedStruct * structToPrint) +{ + printGenericHead(structToPrint->generic); + + switch (structToPrint->generic.vartype) + { + + case PGC_BOOL: + printf(gettext(BOOL_FORMAT[outFormat]), + (structToPrint->bool.reset_val == 0) ? + gettext("FALSE") : gettext("TRUE")); + break; + + case PGC_INT: + printf(gettext(INT_FORMAT[outFormat]), + structToPrint->integer.reset_val, + structToPrint->integer.min, + structToPrint->integer.max); + break; + + case PGC_REAL: + printf(gettext(REAL_FORMAT[outFormat]), + structToPrint->real.reset_val, + structToPrint->real.min, + structToPrint->real.max); + break; + + case PGC_STRING: + printf(gettext(STRING_FORMAT[outFormat]), + structToPrint->string.boot_val); + break; + + default: + printf(gettext("Unrecognized variable type!\n")); + break; + } + + printGenericFoot(structToPrint->generic); +} + +static void +printGenericHead(struct config_generic structToPrint) +{ + printf(gettext(GENERIC_FORMAT[outFormat]), + structToPrint.name, + GucContext_names[structToPrint.context], + gettext(config_group_names[structToPrint.group])); +} + +static void +printGenericFoot(struct config_generic sPrint) +{ + printf(gettext(GENERIC_DESC[outFormat]), + (sPrint.short_desc == NULL) ? "" : gettext(sPrint.short_desc), + (sPrint.long_desc == NULL) ? "" : gettext(sPrint.long_desc)); +} + +static void +listAllGroups(void) +{ + int i; + + printf(gettext("All currently defined groups\n")); + printf(gettext("----------------------------\n")); + for (i = 0; config_group_names[i] != NULL; i++) + printf(gettext("%s\n"), gettext(config_group_names[i])); +} + +static const char * +usageErrMsg(void) +{ + return gettext("Usage for --help-config option: [-h] [-g <group>] [-l] [-G] [-m] [-M] [string]\n"); +} + +static void +helpMessage(void) +{ + printf(gettext("Description:\n" + "--help-config displays all the runtime options available in PostgreSQL.\n" + "It groups them by category and sorts them by name. If available, it will\n" + "present a short description, default, max and min values as well as other\n" + "information about each option.\n\n" + "With no options specified, it will output all available runtime options\n" + "in human friendly format, grouped by category and sorted by name.\n\n" + + "%s\n" + + "General Options:\n" + " [string] All options with names that match this string\n" + " -g GROUP All options in categories that match GROUP\n" + " -l Prints list of all groups / subgroups\n" + " -h Prints this help message\n" + "\nOutput Options:\n" + " -G Do not group by category\n" + " -m Machine friendly format: tab separated fields\n" + " -M Same as m, except header with column names is suppressed\n"), + usageErrMsg() + ); +} |