diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index cf5d3f3b8555490b7ed454205e4de9cce592a5fd..dfb6348e1d633b26e7c4706f96b6030730c39df0 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.127 2006/07/25 03:51:21 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.128 2006/07/27 08:30:41 petere Exp $ -->
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
  -->
@@ -5482,6 +5482,12 @@
       <entry></entry>
       <entry>current value of the parameter</entry>
      </row>
+     <row>
+      <entry><structfield>unit</structfield></entry>
+      <entry><type>text</type></entry>
+      <entry></entry>
+      <entry>implicit unit of the parameter</entry>
+     </row>
      <row>
       <entry><structfield>category</structfield></entry>
       <entry><type>text</type></entry>
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 45350ac7ae9c099bb340a0e9bd852cc7c53257d8..0acdd27507865fd6c33dca47c5698facb9553357 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.70 2006/07/26 11:35:55 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.71 2006/07/27 08:30:41 petere Exp $ -->
 
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
@@ -28,6 +28,20 @@
     (all case-insensitive) or any unambiguous prefix of these.
    </para>
 
+   <para>
+    Some settings specify a memory or time value.  Each of these has
+    an implicit unit, which is either kilobytes, blocks (typically 8
+    kilobytes), milliseconds, seconds, or minutes.  For convenience, a
+    (possibly different) unit can also be specified explicitly.  Valid
+    memory units are <literal>kB</literal> (kilobytes),
+    <literal>MB</literal> (megabytes), and <literal>GB</literal>
+    (gigabytes); valid time units are <literal>ms</literal>
+    (milliseconds), <literal>s</literal> (seconds),
+    <literal>min</literal> (minutes), <literal>h</literal> (hours),
+    and <literal>d</literal> (days).  Note that the multiplier for
+    memory units in 1024, not 1000.
+   </para>
+
    <para>
     One way to set these parameters is to edit the file
     <filename>postgresql.conf</><indexterm><primary>postgresql.conf</></>,
@@ -39,6 +53,7 @@
 log_connections = yes
 log_destination = 'syslog'
 search_path = '"$user", public'
+shared_buffers = 128MB
 </programlisting>
     One parameter is specified per line. The equal sign between name and
     value is optional. Whitespace is insignificant and blank lines are
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2190caa7c724a86d69aaa301dd3459208c8c18bc..e88626aa5970ff53bde0b1eb38e53b74f3a9d15e 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1996-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.28 2006/07/25 03:51:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.29 2006/07/27 08:30:41 petere Exp $
  */
 
 CREATE VIEW pg_roles AS 
@@ -172,7 +172,7 @@ CREATE VIEW pg_prepared_statements AS
 CREATE VIEW pg_settings AS 
     SELECT * 
     FROM pg_show_all_settings() AS A 
-    (name text, setting text, category text, short_desc text, extra_desc text,
+    (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);
 
 CREATE RULE pg_settings_u AS 
diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l
index dd59d5f99b2ceb7d919b188aff2673ee88957f68..82c1f03445037aa98db013155bb6cebd2ae61370 100644
--- a/src/backend/utils/misc/guc-file.l
+++ b/src/backend/utils/misc/guc-file.l
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.37 2006/03/07 01:03:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.38 2006/07/27 08:30:41 petere Exp $
  */
 
 %{
@@ -68,7 +68,9 @@ SIGN            ("-"|"+")
 DIGIT           [0-9]
 HEXDIGIT        [0-9a-fA-F]
 
-INTEGER         {SIGN}?({DIGIT}+|0x{HEXDIGIT}+)
+UNIT_LETTER     [a-zA-Z]
+
+INTEGER         {SIGN}?({DIGIT}+|0x{HEXDIGIT}+){UNIT_LETTER}*
 
 EXPONENT        [Ee]{SIGN}?{DIGIT}+
 REAL            {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}?
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index ee05662b58c06bbad5444928988ff2842c798e17..5791e63d87b5e1ac439a81bf3e545270f474dc8f 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
- *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.331 2006/07/26 11:39:47 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.332 2006/07/27 08:30:41 petere Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -83,6 +83,14 @@
 #define MAX_KILOBYTES	(INT_MAX / 1024)
 #endif
 
+#define KB_PER_MB (1024)
+#define KB_PER_GB (1024*1024)
+
+#define MS_PER_S 1000
+#define MS_PER_MIN (1000 * 60)
+#define MS_PER_H (1000 * 60 * 60)
+#define MS_PER_D (1000 * 60 * 60 * 24)
+
 /* XXX these should appear in other modules' header files */
 extern bool Log_disconnections;
 extern bool check_function_bodies;
@@ -1015,7 +1023,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"post_auth_delay", PGC_BACKEND, DEVELOPER_OPTIONS,
 		 gettext_noop("Waits N seconds on connection startup after authentication."),
 		 gettext_noop("This allows attaching a debugger to the process."),
-		 GUC_NOT_IN_SAMPLE
+		 GUC_NOT_IN_SAMPLE | GUC_UNIT_S
 		},
 		&PostAuthDelay,
 		0, 0, INT_MAX, NULL, NULL
@@ -1087,7 +1095,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"deadlock_timeout", PGC_SIGHUP, LOCK_MANAGEMENT,
 			gettext_noop("The time in milliseconds to wait on lock before checking for deadlock."),
-			NULL
+			NULL,
+			GUC_UNIT_MS
 		},
 		&DeadlockTimeout,
 		1000, 0, INT_MAX, NULL, NULL
@@ -1125,7 +1134,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"shared_buffers", PGC_POSTMASTER, RESOURCES_MEM,
 			gettext_noop("Sets the number of shared memory buffers used by the server."),
-			NULL
+			NULL,
+			GUC_UNIT_BLOCKS
 		},
 		&NBuffers,
 		1000, 16, INT_MAX / 2, NULL, NULL
@@ -1134,7 +1144,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
 			gettext_noop("Sets the maximum number of temporary buffers used by each session."),
-			NULL
+			NULL,
+			GUC_UNIT_BLOCKS
 		},
 		&num_temp_buffers,
 		1000, 100, INT_MAX / 2, NULL, show_num_temp_buffers
@@ -1167,7 +1178,8 @@ static struct config_int ConfigureNamesInt[] =
 			gettext_noop("Sets the maximum memory to be used for query workspaces."),
 			gettext_noop("This much memory may be used by each internal "
 						 "sort operation and hash table before switching to "
-						 "temporary disk files.")
+						 "temporary disk files."),
+			GUC_UNIT_KB
 		},
 		&work_mem,
 		1024, 8 * BLCKSZ / 1024, MAX_KILOBYTES, NULL, NULL
@@ -1176,7 +1188,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"maintenance_work_mem", PGC_USERSET, RESOURCES_MEM,
 			gettext_noop("Sets the maximum memory to be used for maintenance operations."),
-			gettext_noop("This includes operations such as VACUUM and CREATE INDEX.")
+			gettext_noop("This includes operations such as VACUUM and CREATE INDEX."),
+			GUC_UNIT_KB
 		},
 		&maintenance_work_mem,
 		16384, 1024, MAX_KILOBYTES, NULL, NULL
@@ -1185,7 +1198,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"max_stack_depth", PGC_SUSET, RESOURCES_MEM,
 			gettext_noop("Sets the maximum stack depth, in kilobytes."),
-			NULL
+			NULL,
+			GUC_UNIT_KB
 		},
 		&max_stack_depth,
 		2048, 100, MAX_KILOBYTES, assign_max_stack_depth, NULL
@@ -1230,7 +1244,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"vacuum_cost_delay", PGC_USERSET, RESOURCES,
 			gettext_noop("Vacuum cost delay in milliseconds."),
-			NULL
+			NULL,
+			GUC_UNIT_MS
 		},
 		&VacuumCostDelay,
 		0, 0, 1000, NULL, NULL
@@ -1239,7 +1254,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"autovacuum_vacuum_cost_delay", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Vacuum cost delay in milliseconds, for autovacuum."),
-			NULL
+			NULL,
+			GUC_UNIT_MS
 		},
 		&autovacuum_vac_cost_delay,
 		-1, -1, 1000, NULL, NULL
@@ -1296,7 +1312,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"statement_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
 			gettext_noop("Sets the maximum allowed duration (in milliseconds) of any statement."),
-			gettext_noop("A value of 0 turns off the timeout.")
+			gettext_noop("A value of 0 turns off the timeout."),
+			GUC_UNIT_MS
 		},
 		&StatementTimeout,
 		0, 0, INT_MAX, NULL, NULL
@@ -1333,7 +1350,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"authentication_timeout", PGC_SIGHUP, CONN_AUTH_SECURITY,
 			gettext_noop("Sets the maximum time in seconds to complete client authentication."),
-			NULL
+			NULL,
+			GUC_UNIT_S
 		},
 		&AuthenticationTimeout,
 		60, 1, 600, NULL, NULL
@@ -1344,7 +1362,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"pre_auth_delay", PGC_SIGHUP, DEVELOPER_OPTIONS,
 			gettext_noop("no description available"),
 			NULL,
-			GUC_NOT_IN_SAMPLE
+			GUC_NOT_IN_SAMPLE | GUC_UNIT_S
 		},
 		&PreAuthDelay,
 		0, 0, 60, NULL, NULL
@@ -1362,7 +1380,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"checkpoint_timeout", PGC_SIGHUP, WAL_CHECKPOINTS,
 			gettext_noop("Sets the maximum time in seconds between automatic WAL checkpoints."),
-			NULL
+			NULL,
+			GUC_UNIT_S
 		},
 		&CheckPointTimeout,
 		300, 30, 3600, NULL, NULL
@@ -1424,7 +1443,8 @@ static struct config_int ConfigureNamesInt[] =
 		{"log_min_duration_statement", PGC_SUSET, LOGGING_WHEN,
 			gettext_noop("Sets the minimum execution time in milliseconds above which statements will "
 						 "be logged."),
-			gettext_noop("Zero prints all queries. The default is -1 (turning this feature off).")
+			gettext_noop("Zero prints all queries. The default is -1 (turning this feature off)."),
+			GUC_UNIT_MS
 		},
 		&log_min_duration_statement,
 		-1, -1, INT_MAX / 1000, NULL, NULL
@@ -1433,7 +1453,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"bgwriter_delay", PGC_SIGHUP, RESOURCES,
 			gettext_noop("Background writer sleep time between rounds in milliseconds"),
-			NULL
+			NULL,
+			GUC_UNIT_MS
 		},
 		&BgWriterDelay,
 		200, 10, 10000, NULL, NULL
@@ -1460,7 +1481,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"log_rotation_age", PGC_SIGHUP, LOGGING_WHERE,
 			gettext_noop("Automatic log file rotation will occur after N minutes"),
-			NULL
+			NULL,
+			GUC_UNIT_MIN
 		},
 		&Log_RotationAge,
 		HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / MINS_PER_HOUR, NULL, NULL
@@ -1469,7 +1491,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"log_rotation_size", PGC_SIGHUP, LOGGING_WHERE,
 			gettext_noop("Automatic log file rotation will occur after N kilobytes"),
-			NULL
+			NULL,
+			GUC_UNIT_KB
 		},
 		&Log_RotationSize,
 		10 * 1024, 0, INT_MAX / 1024, NULL, NULL
@@ -1518,7 +1541,8 @@ static struct config_int ConfigureNamesInt[] =
 	{
 		{"autovacuum_naptime", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Time to sleep between autovacuum runs, in seconds."),
-			NULL
+			NULL,
+			GUC_UNIT_S
 		},
 		&autovacuum_naptime,
 		60, 1, INT_MAX, NULL, NULL
@@ -1544,6 +1568,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"tcp_keepalives_idle", PGC_USERSET, CLIENT_CONN_OTHER,
 			gettext_noop("Seconds between issuing TCP keepalives."),
 			gettext_noop("A value of 0 uses the system default."),
+			GUC_UNIT_S
 		},
 		&tcp_keepalives_idle,
 		0, 0, INT_MAX, assign_tcp_keepalives_idle, show_tcp_keepalives_idle
@@ -1553,6 +1578,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"tcp_keepalives_interval", PGC_USERSET, CLIENT_CONN_OTHER,
 			gettext_noop("Seconds between TCP keepalive retransmits."),
 			gettext_noop("A value of 0 uses the system default."),
+			GUC_UNIT_S
 		},
 		&tcp_keepalives_interval,
 		0, 0, INT_MAX, assign_tcp_keepalives_interval, show_tcp_keepalives_interval
@@ -1584,7 +1610,8 @@ static struct config_int ConfigureNamesInt[] =
 			gettext_noop("Sets the planner's assumption about size of the disk cache."),
 			gettext_noop("That is, the portion of the kernel's disk cache that "
 						 "will be used for PostgreSQL data files. This is measured in disk "
-						 "pages, which are normally 8 kB each.")
+						 "pages, which are normally 8 kB each."),
+			GUC_UNIT_BLOCKS,
 		},
 		&effective_cache_size,
 		DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX, NULL, NULL
@@ -2233,7 +2260,7 @@ static void push_old_value(struct config_generic * gconf);
 static void ReportGUCOption(struct config_generic * record);
 static void ShowGUCConfigOption(const char *name, DestReceiver *dest);
 static void ShowAllGUCConfig(DestReceiver *dest);
-static char *_ShowOption(struct config_generic * record);
+static char *_ShowOption(struct config_generic * record, bool use_units);
 static bool is_newvalue_equal(struct config_generic *record, const char *newvalue);
 
 
@@ -3427,7 +3454,7 @@ ReportGUCOption(struct config_generic * record)
 {
 	if (reporting_enabled && (record->flags & GUC_REPORT))
 	{
-		char	   *val = _ShowOption(record);
+		char	   *val = _ShowOption(record, false);
 		StringInfoData msgbuf;
 
 		pq_beginmessage(&msgbuf, 'S');
@@ -3513,13 +3540,86 @@ parse_bool(const char *value, bool *result)
  * value there.
  */
 static bool
-parse_int(const char *value, int *result)
+parse_int(const char *value, int *result, int flags)
 {
 	long		val;
 	char	   *endptr;
 
 	errno = 0;
 	val = strtol(value, &endptr, 0);
+
+	if ((flags & GUC_UNIT_MEMORY) && endptr != value)
+	{
+		bool used = false;
+
+		while (*endptr == ' ')
+			endptr++;
+
+		if (strcmp(endptr, "kB") == 0)
+		{
+			used = true;
+			endptr += 2;
+		}
+		else if (strcmp(endptr, "MB") == 0)
+		{
+			val *= KB_PER_MB;
+			used = true;
+			endptr += 2;
+		}
+		else if (strcmp(endptr, "GB") == 0)
+		{
+			val *= KB_PER_MB;
+			used = true;
+			endptr += 2;
+		}
+
+		if (used && (flags & GUC_UNIT_BLOCKS))
+			val /= (BLCKSZ/1024);
+	}
+
+	if ((flags & GUC_UNIT_TIME) && endptr != value)
+	{
+		bool used = false;
+
+		while (*endptr == ' ')
+			endptr++;
+
+		if (strcmp(endptr, "ms") == 0)
+		{
+			used = true;
+			endptr += 2;
+		}
+		else if (strcmp(endptr, "s") == 0)
+		{
+			val *= MS_PER_S;
+			used = true;
+			endptr += 1;
+		}
+		else if (strcmp(endptr, "min") == 0)
+		{
+			val *= MS_PER_MIN;
+			used = true;
+			endptr += 3;
+		}
+		else if (strcmp(endptr, "h") == 0)
+		{
+			val *= MS_PER_H;
+			used = true;
+			endptr += 1;
+		}
+		else if (strcmp(endptr, "d") == 0)
+		{
+			val *= MS_PER_D;
+			used = true;
+			endptr += 1;
+		}
+
+		if (used && (flags & GUC_UNIT_S))
+			val /= MS_PER_S;
+		else if (used && (flags & GUC_UNIT_MIN))
+			val /= MS_PER_MIN;
+	}
+
 	if (endptr == value || *endptr != '\0' || errno == ERANGE
 #ifdef HAVE_LONG_INT_64
 	/* if long > 32 bits, check for overflow of int4 */
@@ -3850,7 +3950,7 @@ set_config_option(const char *name, const char *value,
 
 				if (value)
 				{
-					if (!parse_int(value, &newval))
+					if (!parse_int(value, &newval, conf->gen.flags))
 					{
 						ereport(elevel,
 								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -4754,7 +4854,7 @@ ShowAllGUCConfig(DestReceiver *dest)
 
 		/* assign to the values array */
 		values[0] = (char *) conf->name;
-		values[1] = _ShowOption(conf);
+		values[1] = _ShowOption(conf, true);
 		values[2] = (char *) conf->short_desc;
 
 		/* send it to dest */
@@ -4790,7 +4890,7 @@ GetConfigOptionByName(const char *name, const char **varname)
 	if (varname)
 		*varname = record->name;
 
-	return _ShowOption(record);
+	return _ShowOption(record, true);
 }
 
 /*
@@ -4823,25 +4923,49 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
 	values[0] = conf->name;
 
 	/* setting : use _ShowOption in order to avoid duplicating the logic */
-	values[1] = _ShowOption(conf);
+	values[1] = _ShowOption(conf, false);
+
+	/* unit */
+	if (conf->vartype == PGC_INT)
+	{
+		if (conf->flags & GUC_UNIT_KB)
+			values[2] = "kB";
+		else if (conf->flags & GUC_UNIT_BLOCKS)
+		{
+			static char buf[8];
+
+			snprintf(buf, sizeof(buf), "%dkB", BLCKSZ/1024);
+			values[2] = buf;
+		}
+		else if (conf->flags & GUC_UNIT_MS)
+			values[2] = "ms";
+		else if (conf->flags & GUC_UNIT_S)
+			values[2] = "s";
+		else if (conf->flags & GUC_UNIT_MIN)
+			values[2] = "min";
+		else
+			values[2] = "";
+	}
+	else
+		values[2] = NULL;
 
 	/* group */
-	values[2] = config_group_names[conf->group];
+	values[3] = config_group_names[conf->group];
 
 	/* short_desc */
-	values[3] = conf->short_desc;
+	values[4] = conf->short_desc;
 
 	/* extra_desc */
-	values[4] = conf->long_desc;
+	values[5] = conf->long_desc;
 
 	/* context */
-	values[5] = GucContext_Names[conf->context];
+	values[6] = GucContext_Names[conf->context];
 
 	/* vartype */
-	values[6] = config_type_names[conf->vartype];
+	values[7] = config_type_names[conf->vartype];
 
 	/* source */
-	values[7] = GucSource_Names[conf->source];
+	values[8] = GucSource_Names[conf->source];
 
 	/* now get the type specifc attributes */
 	switch (conf->vartype)
@@ -4849,10 +4973,10 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
 		case PGC_BOOL:
 			{
 				/* min_val */
-				values[8] = NULL;
+				values[9] = NULL;
 
 				/* max_val */
-				values[9] = NULL;
+				values[10] = NULL;
 			}
 			break;
 
@@ -4862,11 +4986,11 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
 
 				/* min_val */
 				snprintf(buffer, sizeof(buffer), "%d", lconf->min);
-				values[8] = pstrdup(buffer);
+				values[9] = pstrdup(buffer);
 
 				/* max_val */
 				snprintf(buffer, sizeof(buffer), "%d", lconf->max);
-				values[9] = pstrdup(buffer);
+				values[10] = pstrdup(buffer);
 			}
 			break;
 
@@ -4876,21 +5000,21 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
 
 				/* min_val */
 				snprintf(buffer, sizeof(buffer), "%g", lconf->min);
-				values[8] = pstrdup(buffer);
+				values[9] = pstrdup(buffer);
 
 				/* max_val */
 				snprintf(buffer, sizeof(buffer), "%g", lconf->max);
-				values[9] = pstrdup(buffer);
+				values[10] = pstrdup(buffer);
 			}
 			break;
 
 		case PGC_STRING:
 			{
 				/* min_val */
-				values[8] = NULL;
+				values[9] = NULL;
 
 				/* max_val */
-				values[9] = NULL;
+				values[10] = NULL;
 			}
 			break;
 
@@ -4901,10 +5025,10 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
 				 */
 
 				/* min_val */
-				values[8] = NULL;
+				values[9] = NULL;
 
 				/* max_val */
-				values[9] = NULL;
+				values[10] = NULL;
 			}
 			break;
 	}
@@ -4947,7 +5071,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	10
+#define NUM_PG_SETTINGS_ATTS	11
 
 Datum
 show_all_settings(PG_FUNCTION_ARGS)
@@ -4979,21 +5103,23 @@ show_all_settings(PG_FUNCTION_ARGS)
 						   TEXTOID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
 						   TEXTOID, -1, 0);
-		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "category",
+		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "unit",
 						   TEXTOID, -1, 0);
-		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "short_desc",
+		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "category",
 						   TEXTOID, -1, 0);
-		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "extra_desc",
+		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "short_desc",
 						   TEXTOID, -1, 0);
-		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "context",
+		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "extra_desc",
 						   TEXTOID, -1, 0);
-		TupleDescInitEntry(tupdesc, (AttrNumber) 7, "vartype",
+		TupleDescInitEntry(tupdesc, (AttrNumber) 7, "context",
 						   TEXTOID, -1, 0);
-		TupleDescInitEntry(tupdesc, (AttrNumber) 8, "source",
+		TupleDescInitEntry(tupdesc, (AttrNumber) 8, "vartype",
 						   TEXTOID, -1, 0);
-		TupleDescInitEntry(tupdesc, (AttrNumber) 9, "min_val",
+		TupleDescInitEntry(tupdesc, (AttrNumber) 9, "source",
 						   TEXTOID, -1, 0);
-		TupleDescInitEntry(tupdesc, (AttrNumber) 10, "max_val",
+		TupleDescInitEntry(tupdesc, (AttrNumber) 10, "min_val",
+						   TEXTOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 11, "max_val",
 						   TEXTOID, -1, 0);
 
 		/*
@@ -5056,7 +5182,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 }
 
 static char *
-_ShowOption(struct config_generic * record)
+_ShowOption(struct config_generic * record, bool use_units)
 {
 	char		buffer[256];
 	const char *val;
@@ -5082,8 +5208,66 @@ _ShowOption(struct config_generic * record)
 					val = (*conf->show_hook) ();
 				else
 				{
-					snprintf(buffer, sizeof(buffer), "%d",
-							 *conf->variable);
+					char unit[4];
+					int result = *conf->variable;
+
+					if (use_units && result > 0 && (record->flags & GUC_UNIT_MEMORY))
+					{
+						if (record->flags & GUC_UNIT_BLOCKS)
+							result *= BLCKSZ/1024;
+
+						if (result % KB_PER_GB == 0)
+						{
+							result /= KB_PER_GB;
+							strcpy(unit, "GB");
+						}
+						else if (result % KB_PER_MB == 0)
+						{
+							result /= KB_PER_MB;
+							strcpy(unit, "MB");
+						}
+						else
+						{
+							strcpy(unit, "kB");
+						}
+					}
+					else if (use_units && result > 0 && (record->flags & GUC_UNIT_TIME))
+					{
+						if (record->flags & GUC_UNIT_S)
+							result = result * MS_PER_S;
+						else if (record->flags & GUC_UNIT_MIN)
+							result = result * MS_PER_MIN;
+
+						if (result % MS_PER_D == 0)
+						{
+							result /= MS_PER_D;
+							strcpy(unit, "d");
+						}
+						else if (result % MS_PER_H == 0)
+						{
+							result /= MS_PER_H;
+							strcpy(unit, "h");
+						}
+						else if (result % MS_PER_MIN == 0)
+						{
+							result /= MS_PER_MIN;
+							strcpy(unit, "min");
+						}
+						else if (result % MS_PER_S == 0)
+						{
+							result /= MS_PER_S;
+							strcpy(unit, "s");
+						}
+						else
+						{
+							strcpy(unit, "ms");
+						}
+					}
+					else
+						strcpy(unit, "");
+
+					snprintf(buffer, sizeof(buffer), "%d%s",
+							 (int)result, unit);
 					val = buffer;
 				}
 			}
@@ -5144,7 +5328,7 @@ is_newvalue_equal(struct config_generic *record, const char *newvalue)
 			struct config_int *conf = (struct config_int *) record;
 			int newval;
 
-			return parse_int(newvalue, &newval) && *conf->variable == newval;
+			return parse_int(newvalue, &newval, record->flags) && *conf->variable == newval;
 		}
 		case PGC_REAL:
 		{
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 89c496ee2e03687004193af70a1aea661e38d641..63bed4e91951b6bcf49c6dd2d2ec97ff9943c9f2 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -42,7 +42,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  * Portions taken from FreeBSD.
  *
- * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.118 2006/06/18 15:38:37 petere Exp $
+ * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.119 2006/07/27 08:30:41 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1105,16 +1105,16 @@ test_config_settings(void)
 	 *
 	 */
 
-#define MIN_BUFS_FOR_CONNS(nconns)  ((nconns) * 10)
+#define MIN_BUFS_FOR_CONNS(nconns)  ((nconns) * 10 * (BLCKSZ/1024))
 #define FSM_FOR_BUFS(nbuffers)  ((nbuffers) > 1000 ? 50 * (nbuffers) : 20000)
 
 	static const int trial_conns[] = {
 		100, 50, 40, 30, 20, 10
 	};
 	static const int trial_bufs[] = {
-		4000, 3500, 3000, 2500, 2000, 1500,
-		1000, 900, 800, 700, 600, 500,
-		400, 300, 200, 100, 50
+		32000, 28000, 24000, 20000, 16000, 12000,
+		8000, 7200, 6400, 5600, 4800, 4000,
+		3200, 2400, 1600, 800, 400
 	};
 
 	char		cmd[MAXPGPATH];
@@ -1140,7 +1140,7 @@ test_config_settings(void)
 		snprintf(cmd, sizeof(cmd),
 				 "%s\"%s\" --boot -x0 %s "
 				 "-c max_connections=%d "
-				 "-c shared_buffers=%d "
+				 "-c shared_buffers=%dkB "
 				 "-c max_fsm_pages=%d "
 				 "template1 < \"%s\" > \"%s\" 2>&1%s",
 				 SYSTEMQUOTE, backend_exec, boot_options,
@@ -1175,7 +1175,7 @@ test_config_settings(void)
 		snprintf(cmd, sizeof(cmd),
 				 "%s\"%s\" --boot -x0 %s "
 				 "-c max_connections=%d "
-				 "-c shared_buffers=%d "
+				 "-c shared_buffers=%dkB "
 				 "-c max_fsm_pages=%d "
 				 "template1 < \"%s\" > \"%s\" 2>&1%s",
 				 SYSTEMQUOTE, backend_exec, boot_options,
@@ -1188,7 +1188,7 @@ test_config_settings(void)
 	n_buffers = test_buffs;
 	n_fsm_pages = FSM_FOR_BUFS(n_buffers);
 
-	printf("%d/%d\n", n_buffers, n_fsm_pages);
+	printf("%dkB/%d\n", n_buffers, n_fsm_pages);
 }
 
 /*
@@ -1211,7 +1211,7 @@ setup_config(void)
 	snprintf(repltok, sizeof(repltok), "max_connections = %d", n_connections);
 	conflines = replace_token(conflines, "#max_connections = 100", repltok);
 
-	snprintf(repltok, sizeof(repltok), "shared_buffers = %d", n_buffers);
+	snprintf(repltok, sizeof(repltok), "shared_buffers = %dkB", n_buffers);
 	conflines = replace_token(conflines, "#shared_buffers = 1000", repltok);
 
 	snprintf(repltok, sizeof(repltok), "max_fsm_pages = %d", n_fsm_pages);
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 822bcfc98356368875db4bb6eefcf0e8bd44e065..ecb49cb22a99fb1686a4a634b9f61c48f285971a 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -7,7 +7,7 @@
  *
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  *
- *	  $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.23 2006/07/13 16:49:20 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.24 2006/07/27 08:30:41 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -130,6 +130,15 @@ struct config_generic
 #define GUC_SUPERUSER_ONLY		0x0100	/* show only to superusers */
 #define GUC_IS_NAME				0x0200	/* limit string to NAMEDATALEN-1 */
 
+#define GUC_UNIT_KB				0x0400	/* value is in 1 kB */
+#define GUC_UNIT_BLOCKS			0x0800	/* value is in blocks */
+#define GUC_UNIT_MEMORY			(GUC_UNIT_KB|GUC_UNIT_BLOCKS)
+
+#define GUC_UNIT_MS				0x1000	/* value is in milliseconds */
+#define GUC_UNIT_S				0x2000	/* value is in seconds */
+#define GUC_UNIT_MIN			0x4000	/* value is in minutes */
+#define GUC_UNIT_TIME			(GUC_UNIT_MS|GUC_UNIT_S|GUC_UNIT_MIN)
+
 /* bit values in status field */
 #define GUC_HAVE_TENTATIVE	0x0001		/* tentative value is defined */
 #define GUC_HAVE_LOCAL		0x0002		/* a SET LOCAL has been executed */
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 350d73a735344227ce28d0b97c178537a9560467..0815196bbceb31da390313ca40cc67eaad7841b2 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1285,7 +1285,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.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, 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 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_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_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"]));