aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/misc/help_config.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-07-04 16:41:22 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-07-04 16:41:22 +0000
commitb700a672feadbb6f122b7c7249967fb0f58dda2b (patch)
tree85013f1378d8edaa12cf35b039c4aa768bc9b4a9 /src/backend/utils/misc/help_config.c
parentefbbd107c7b08b7a1351c0199ee4602182e09f05 (diff)
downloadpostgresql-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.c461
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()
+ );
+}