From 38fb906f93b40edc9ef367b5619f431851fc3867 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Sun, 27 Jul 2003 04:35:54 +0000
Subject: [PATCH] > Joe Conway <mail@joeconway.com> writes: >>ISTM that
 "source" is worth knowing. > > Hm, possibly.  Any other opinions?

This version has the seven fields I proposed, including "source". Here's
an example that shows why I think it's valuable:

regression=# \x
Expanded display is on.
regression=# select * from pg_settings where name = 'enable_seqscan';
-[ RECORD 1 ]-----------
name    | enable_seqscan
setting | on
context | user
vartype | bool
source  | default
min_val |
max_val |

regression=# update pg_settings set setting = 'off' where name =
'enable_seqscan';
-[ RECORD 1 ]---
set_config | off

regression=# select * from pg_settings where name = 'enable_seqscan';
-[ RECORD 1 ]-----------
name    | enable_seqscan
setting | off
context | user
vartype | bool
source  | session
min_val |
max_val |

regression=# alter user postgres set enable_seqscan to 'off';
ALTER USER

(log out and then back in again)

regression=# \x
Expanded display is on.
regression=# select * from pg_settings where name = 'enable_seqscan';
-[ RECORD 1 ]-----------
name    | enable_seqscan
setting | off
context | user
vartype | bool
source  | user
min_val |
max_val |

In the first case, enable_seqscan is set to its default value. After
setting it to off, it is obvious that the value has been changed for the
session only. In the third case, you can see that the value has been set
specifically for the user.

Joe Conway
---
 doc/src/sgml/runtime.sgml                |  37 ++++-
 src/backend/utils/misc/guc.c             | 179 +++++++++++++++++++----
 src/bin/initdb/initdb.sh                 |   6 +-
 src/include/utils/guc.h                  |  21 +--
 src/include/utils/guc_tables.h           |  10 +-
 src/test/regress/expected/rangefuncs.out |   2 +-
 src/test/regress/expected/rules.out      |   2 +-
 src/test/regress/sql/rangefuncs.sql      |   2 +-
 8 files changed, 204 insertions(+), 55 deletions(-)

diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 1f28e21559f..d5598cd0b96 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.195 2003/07/23 20:30:35 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.196 2003/07/27 04:35:53 momjian Exp $
 -->
 
 <Chapter Id="runtime">
@@ -571,14 +571,45 @@ SET ENABLE_SEQSCAN TO OFF;
       <row>
        <entry><literal>name</literal></entry>
        <entry><type>text</type></entry>
-       <entry>The name of the run-time configuration parameter</entry>
+       <entry>run-time configuration parameter name</entry>
       </row>
  
       <row>
        <entry><literal>setting</literal></entry>
        <entry><type>text</type></entry>
-       <entry>The current value of the run-time configuration parameter</entry>
+       <entry>current value of the parameter</entry>
       </row>
+
+      <row>
+       <entry><literal>context</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>context required to set the parameter's value</entry>
+      </row>
+
+      <row>
+       <entry><literal>vartype</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>parameter type</entry>
+      </row>
+
+      <row>
+       <entry><literal>source</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>source of the current parameter value</entry>
+      </row>
+
+      <row>
+       <entry><literal>min_val</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>minimum allowed value of the parameter</entry>
+      </row>
+
+      <row>
+       <entry><literal>max_val</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>maximum allowed value of the parameter</entry>
+      </row>
+
      </tbody>
     </tgroup>
     </table>
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index de1fd50d203..ef6053f3286 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.139 2003/07/25 20:17:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.140 2003/07/27 04:35:53 momjian Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -155,6 +155,47 @@ static char *timezone_string;
 static char *XactIsoLevel_string;
 
 
+/*
+ * Used for pg_settings. Keep in sync with config_type enum above
+ */
+static char *config_type_name[] = 
+{
+	"bool",
+	"integer",
+	"real",
+	"string"
+};
+
+/*
+ * Used for pg_settings. Keep in sync with GucContext enum in guc.h
+ */
+static char *GucContextName[] = 
+{
+	"internal",
+	"postmaster",
+	"sighup",
+	"backend",
+	"super-user",
+	"user"
+};
+
+/*
+ * Used for pg_settings. Keep in sync with GucSource enum in guc.h
+ */
+static char *GucSourceName[] = 
+{
+	"default",
+	"environment variable",
+	"configuration file",
+	"command line",
+	"database",
+	"user",
+	"client",
+	"override",
+	"session"
+};
+
+
 /* Macros for freeing malloc'd pointers only if appropriate to do so */
 /* Some of these tests are probably redundant, but be safe ... */
 #define SET_STRING_VARIABLE(rec, newval) \
@@ -3323,23 +3364,102 @@ GetConfigOptionByName(const char *name, const char **varname)
  * Return GUC variable value by variable number; optionally return canonical
  * form of name.  Return value is palloc'd.
  */
-char *
-GetConfigOptionByNum(int varnum, const char **varname, bool *noshow)
+void
+GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
 {
-	struct config_generic *conf;
+	char					buffer[256];
+	struct config_generic  *conf;
 
 	/* check requested variable number valid */
 	Assert((varnum >= 0) && (varnum < num_guc_variables));
 
 	conf = guc_variables[varnum];
 
-	if (varname)
-		*varname = conf->name;
-
 	if (noshow)
 		*noshow = (conf->flags & GUC_NO_SHOW_ALL) ? true : false;
 
-	return _ShowOption(conf);
+	/* first get the generic attributes */
+
+	/* name */
+	values[0] = conf->name;
+
+	/* setting : use _ShowOption in order to avoid duplicating the logic */
+	values[1] = _ShowOption(conf);
+
+	/* context */
+	values[2] = GucContextName[conf->context];
+
+	/* vartype */
+	values[3] = config_type_name[conf->vartype];
+
+	/* source */
+	values[4] = GucSourceName[conf->source];
+
+	/* now get the type specifc attributes */
+	switch (conf->vartype)
+	{
+		case PGC_BOOL:
+			{
+				/* min_val */
+				values[5] = NULL;
+
+				/* max_val */
+				values[6] = NULL;
+			}
+			break;
+
+		case PGC_INT:
+			{
+				struct config_int *lconf = (struct config_int *) conf;
+
+				/* min_val */
+				snprintf(buffer, sizeof(buffer), "%d", lconf->min);
+				values[5] = pstrdup(buffer);
+
+				/* max_val */
+				snprintf(buffer, sizeof(buffer), "%d", lconf->max);
+				values[6] = pstrdup(buffer);
+			}
+			break;
+
+		case PGC_REAL:
+			{
+				struct config_real *lconf = (struct config_real *) conf;
+
+				/* min_val */
+				snprintf(buffer, sizeof(buffer), "%g", lconf->min);
+				values[5] = pstrdup(buffer);
+
+				/* max_val */
+				snprintf(buffer, sizeof(buffer), "%g", lconf->max);
+				values[6] = pstrdup(buffer);
+			}
+			break;
+
+		case PGC_STRING:
+			{
+				/* min_val */
+				values[5] = NULL;
+
+				/* max_val */
+				values[6] = NULL;
+			}
+			break;
+
+		default:
+			{
+				/*
+				 * should never get here, but in case we do, set 'em to NULL
+				 */
+
+				/* min_val */
+				values[5] = NULL;
+
+				/* max_val */
+				values[6] = NULL;
+			}
+			break;
+	}
 }
 
 /*
@@ -3379,6 +3499,8 @@ 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	7
+
 Datum
 show_all_settings(PG_FUNCTION_ARGS)
 {
@@ -3402,12 +3524,25 @@ show_all_settings(PG_FUNCTION_ARGS)
 		 */
 		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
-		/* need a tuple descriptor representing two TEXT columns */
-		tupdesc = CreateTemplateTupleDesc(2, false);
+		/*
+		 * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns
+		 * of the appropriate types
+		 */
+		tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS, false);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
 						   TEXTOID, -1, 0, false);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
 						   TEXTOID, -1, 0, false);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "context",
+						   TEXTOID, -1, 0, false);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "vartype",
+						   TEXTOID, -1, 0, false);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "source",
+						   TEXTOID, -1, 0, false);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "min_val",
+						   TEXTOID, -1, 0, false);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 7, "max_val",
+						   TEXTOID, -1, 0, false);
 
 		/* allocate a slot for a tuple with this tupdesc */
 		slot = TupleDescGetSlot(tupdesc);
@@ -3438,9 +3573,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 
 	if (call_cntr < max_calls)	/* do when there is more left to send */
 	{
-		char	   *values[2];
-		char	   *varname;
-		char	   *varval;
+		char	   *values[NUM_PG_SETTINGS_ATTS];
 		bool		noshow;
 		HeapTuple	tuple;
 		Datum		result;
@@ -3450,15 +3583,9 @@ show_all_settings(PG_FUNCTION_ARGS)
 		 */
 		do
 		{
-			varval = GetConfigOptionByNum(call_cntr,
-										  (const char **) &varname,
-										  &noshow);
+			GetConfigOptionByNum(call_cntr, (const char **) values, &noshow);
 			if (noshow)
 			{
-				/* varval is a palloc'd copy, so free it */
-				if (varval != NULL)
-					pfree(varval);
-
 				/* bump the counter and get the next config setting */
 				call_cntr = ++funcctx->call_cntr;
 
@@ -3468,24 +3595,12 @@ show_all_settings(PG_FUNCTION_ARGS)
 			}
 		} while (noshow);
 
-		/*
-		 * Prepare a values array for storage in our slot. This should be
-		 * an array of C strings which will be processed later by the
-		 * appropriate "in" functions.
-		 */
-		values[0] = varname;
-		values[1] = varval;
-
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
 		result = TupleGetDatum(slot, tuple);
 
-		/* Clean up */
-		if (varval != NULL)
-			pfree(varval);
-
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 	else
diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh
index 62d1a8039ac..5908416ce40 100644
--- a/src/bin/initdb/initdb.sh
+++ b/src/bin/initdb/initdb.sh
@@ -27,7 +27,7 @@
 # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.198 2003/07/23 08:46:54 petere Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.199 2003/07/27 04:35:53 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -1000,7 +1000,9 @@ CREATE VIEW pg_locks AS \
 
 CREATE VIEW pg_settings AS \
     SELECT * \
-    FROM pg_show_all_settings() AS A(name text, setting text);
+    FROM pg_show_all_settings() AS A \
+    (name text, setting text, context text, vartype text, \
+     source text, min_val text, max_val text);
 
 CREATE RULE pg_settings_u AS \
     ON UPDATE TO pg_settings \
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 7199a6e2ea2..02d2a01d8bf 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -7,7 +7,7 @@
  * Copyright 2000-2003 by PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
- * $Id: guc.h,v 1.35 2003/07/21 21:02:12 momjian Exp $
+ * $Id: guc.h,v 1.36 2003/07/27 04:35:54 momjian Exp $
  *--------------------------------------------------------------------
  */
 #ifndef GUC_H
@@ -55,13 +55,13 @@
  */
 typedef enum
 {
-	PGC_INTERNAL,
-	PGC_POSTMASTER,
-	PGC_SIGHUP,
-	PGC_BACKEND,
-	PGC_SUSET,
-	PGC_USERLIMIT,
-	PGC_USERSET
+	PGC_INTERNAL = 0,
+	PGC_POSTMASTER = 1,
+	PGC_SIGHUP = 2,
+	PGC_BACKEND = 3,
+	PGC_SUSET = 4,
+	PGC_USERLIMIT = 5,
+	PGC_USERSET = 6
 } GucContext;
 
 /*
@@ -73,6 +73,8 @@ typedef enum
  * Sources <= PGC_S_OVERRIDE will set the default used by RESET, as well
  * as the current value.  Note that source == PGC_S_OVERRIDE should be
  * used when setting a PGC_INTERNAL option.
+ *
+ * Keep in sync with GucSourceName in guc.c
  */
 typedef enum
 {
@@ -92,7 +94,6 @@ typedef enum
 	PGC_S_SESSION = 9			/* SET command */
 } GucSource;
 
-
 /* GUC vars that are actually declared in guc.c, rather than elsewhere */
 extern bool log_statement;
 extern bool log_duration;
@@ -132,7 +133,7 @@ extern bool set_config_option(const char *name, const char *value,
 extern void ShowGUCConfigOption(const char *name, DestReceiver *dest);
 extern void ShowAllGUCConfig(DestReceiver *dest);
 extern char *GetConfigOptionByName(const char *name, const char **varname);
-extern char *GetConfigOptionByNum(int varnum, const char **varname, bool *noshow);
+extern void GetConfigOptionByNum(int varnum, const char **values, bool *noshow);
 extern int	GetNumConfigOptions(void);
 
 extern void SetPGVariable(const char *name, List *args, bool is_local);
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index e8ccfeefd00..0eb9376dd57 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -7,7 +7,7 @@
  *
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  *
- *	  $Id: guc_tables.h,v 1.1 2003/07/04 16:41:22 tgl Exp $
+ *	  $Id: guc_tables.h,v 1.2 2003/07/27 04:35:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,10 +61,10 @@ enum config_group
  */
 enum config_type
 {
-	PGC_BOOL,
-	PGC_INT,
-	PGC_REAL,
-	PGC_STRING
+	PGC_BOOL = 0,
+	PGC_INT = 1,
+	PGC_REAL = 2,
+	PGC_STRING = 3
 };
 
 /*
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
index 2790790717a..7acbbe9bc60 100644
--- a/src/test/regress/expected/rangefuncs.out
+++ b/src/test/regress/expected/rangefuncs.out
@@ -1,4 +1,4 @@
-SELECT * FROM pg_settings WHERE name LIKE 'enable%';
+SELECT name, setting FROM pg_settings WHERE name LIKE 'enable%';
        name       | setting 
 ------------------+---------
  enable_hashagg   | on
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 75e8a676d31..a00959e0f70 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1273,7 +1273,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
  pg_indexes               | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, pg_get_indexdef(i.oid) AS indexdef FROM (((pg_index x JOIN pg_class c 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 = 'r'::"char") AND (i.relkind = 'i'::"char"));
  pg_locks                 | SELECT l.relation, l."database", l."transaction", l.pid, l."mode", l.granted FROM pg_lock_status() l(relation oid, "database" oid, "transaction" xid, pid integer, "mode" text, granted boolean);
  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 FROM pg_show_all_settings() a(name text, setting text);
+ pg_settings              | SELECT a.name, a.setting, a.context, a.vartype, a.source, a.min_val, a.max_val FROM pg_show_all_settings() a(name text, setting text, context text, vartype text, source text, min_val text, max_val text);
  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.usename, pg_stat_get_backend_activity(s.backendid) AS current_query, pg_stat_get_backend_activity_start(s.backendid) AS query_start FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_shadow u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.usesysid));
  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 = 'r'::"char");
  pg_stat_all_tables       | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, sum(pg_stat_get_numscans(i.indexrelid)) AS idx_scan, sum(pg_stat_get_tuples_fetched(i.indexrelid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'r'::"char") GROUP BY c.oid, n.nspname, c.relname;
diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql
index 6522fdda10d..2f1c8e75130 100644
--- a/src/test/regress/sql/rangefuncs.sql
+++ b/src/test/regress/sql/rangefuncs.sql
@@ -1,4 +1,4 @@
-SELECT * FROM pg_settings WHERE name LIKE 'enable%';
+SELECT name, setting FROM pg_settings WHERE name LIKE 'enable%';
 
 CREATE TABLE foo2(fooid int, f2 int);
 INSERT INTO foo2 VALUES(1, 11);
-- 
GitLab