diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index bf3e39640d9c51aa3dfafd747ce7ccc77c451e57..b8eef7e06b06c73937d5ba649f4806647fd391a2 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.84 2001/11/05 17:46:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.85 2001/11/10 23:51:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -171,8 +171,7 @@ btbuild(PG_FUNCTION_ARGS)
 #ifdef BTREE_BUILD_STATS
 	if (Show_btree_build_stats)
 	{
-		fprintf(stderr, "BTREE BUILD STATS\n");
-		ShowUsage();
+		ShowUsage("BTREE BUILD STATS");
 		ResetUsage();
 	}
 #endif   /* BTREE_BUILD_STATS */
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index 6d584526f55d669e241515e78b766216be694abd..cb1903194b00d751fa55b11d0596bde4a53b8487 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -35,7 +35,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.62 2001/11/05 17:46:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.63 2001/11/10 23:51:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -160,8 +160,7 @@ _bt_leafbuild(BTSpool *btspool, BTSpool *btspool2)
 #ifdef BTREE_BUILD_STATS
 	if (Show_btree_build_stats)
 	{
-		fprintf(StatFp, "BTREE BUILD (Spool) STATISTICS\n");
-		ShowUsage();
+		ShowUsage("BTREE BUILD (Spool) STATISTICS");
 		ResetUsage();
 	}
 #endif   /* BTREE_BUILD_STATS */
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 428a4cb7d3fe34f78b35dc372387aa8ed151969d..a790277bae710354633fca80288b41b1438dd492 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.61 2001/11/05 19:41:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.62 2001/11/10 23:51:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "catalog/heap.h"
 #include "commands/command.h"
 #include "executor/spi_priv.h"
+#include "tcop/tcopprot.h"
 
 
 uint32		SPI_processed = 0;
@@ -47,11 +48,6 @@ static MemoryContext _SPI_execmem(void);
 static MemoryContext _SPI_procmem(void);
 static bool _SPI_checktuples(void);
 
-#ifdef SPI_EXECUTOR_STATS
-extern int	ShowExecutorStats;
-extern void ResetUsage(void);
-extern void ShowUsage(void);
-#endif
 
 /* =================== interface functions =================== */
 
@@ -1180,10 +1176,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
 
 #ifdef SPI_EXECUTOR_STATS
 	if (ShowExecutorStats)
-	{
-		fprintf(stderr, "! Executor Stats:\n");
-		ShowUsage();
-	}
+		ShowUsage("SPI EXECUTOR STATS");
 #endif
 
 	if (dest == SPI)
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 49ee9990be35a867ece428b5fd2cad27717b0b7b..43b4da50ed32647327f67fc3b1e8bb6deaefdd31 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.119 2001/11/05 17:46:27 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.120 2001/11/10 23:51:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,6 +46,7 @@
 #include <math.h>
 #include <signal.h>
 
+#include "lib/stringinfo.h"
 #include "miscadmin.h"
 #include "storage/buf_internals.h"
 #include "storage/bufmgr.h"
@@ -869,14 +870,21 @@ WaitIO(BufferDesc *buf)
 
 long		NDirectFileRead;	/* some I/O's are direct file access.
 								 * bypass bufmgr */
-long		NDirectFileWrite;	/* e.g., I/O in psort and hashjoin.					*/
+long		NDirectFileWrite;	/* e.g., I/O in psort and hashjoin. */
 
-void
-PrintBufferUsage(FILE *statfp)
+
+/*
+ * Return a palloc'd string containing buffer usage statistics.
+ */
+char *
+ShowBufferUsage(void)
 {
+	StringInfoData str;
 	float		hitrate;
 	float		localhitrate;
 
+	initStringInfo(&str);
+
 	if (ReadBufferCount == 0)
 		hitrate = 0.0;
 	else
@@ -887,16 +895,21 @@ PrintBufferUsage(FILE *statfp)
 	else
 		localhitrate = (float) LocalBufferHitCount *100.0 / ReadLocalBufferCount;
 
-	fprintf(statfp, "!\tShared blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
+	appendStringInfo(&str,
+			"!\tShared blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
 			ReadBufferCount - BufferHitCount, BufferFlushCount, hitrate);
-	fprintf(statfp, "!\tLocal  blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
+	appendStringInfo(&str,
+			"!\tLocal  blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
 			ReadLocalBufferCount - LocalBufferHitCount, LocalBufferFlushCount, localhitrate);
-	fprintf(statfp, "!\tDirect blocks: %10ld read, %10ld written\n",
+	appendStringInfo(&str,
+			"!\tDirect blocks: %10ld read, %10ld written\n",
 			NDirectFileRead, NDirectFileWrite);
+
+	return str.data;
 }
 
 void
-ResetBufferUsage()
+ResetBufferUsage(void)
 {
 	BufferHitCount = 0;
 	ReadBufferCount = 0;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 29222d7285c95ff530e08821dff9400ea8c16c1f..c7b227cd7153db0d732960b15c6cc9f907803b55 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.241 2001/11/05 17:46:28 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.242 2001/11/10 23:51:14 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -86,7 +86,6 @@ bool		Warn_restart_ready = false;
 bool		InError = false;
 
 static bool EchoQuery = false;	/* default don't echo */
-FILE	   *StatFp = NULL;
 
 /* ----------------
  *		people who want to use EOF should #define DONTUSENEWLINE in
@@ -378,10 +377,7 @@ pg_parse_query(char *query_string, Oid *typev, int nargs)
 	raw_parsetree_list = parser(query_string, typev, nargs);
 
 	if (Show_parser_stats)
-	{
-		fprintf(StatFp, "PARSER STATISTICS\n");
-		ShowUsage();
-	}
+		ShowUsage("PARSER STATISTICS");
 
 	return raw_parsetree_list;
 }
@@ -413,8 +409,7 @@ pg_analyze_and_rewrite(Node *parsetree)
 
 	if (Show_parser_stats)
 	{
-		fprintf(StatFp, "PARSE ANALYSIS STATISTICS\n");
-		ShowUsage();
+		ShowUsage("PARSE ANALYSIS STATISTICS");
 		ResetUsage();
 	}
 
@@ -457,10 +452,7 @@ pg_analyze_and_rewrite(Node *parsetree)
 	querytree_list = new_list;
 
 	if (Show_parser_stats)
-	{
-		fprintf(StatFp, "REWRITER STATISTICS\n");
-		ShowUsage();
-	}
+		ShowUsage("REWRITER STATISTICS");
 
 #ifdef COPY_PARSE_PLAN_TREES
 
@@ -520,10 +512,7 @@ pg_plan_query(Query *querytree)
 	plan = planner(querytree);
 
 	if (Show_planner_stats)
-	{
-		fprintf(StatFp, "PLANNER STATISTICS\n");
-		ShowUsage();
-	}
+		ShowUsage("PLANNER STATISTICS");
 
 #ifdef COPY_PARSE_PLAN_TREES
 	/* Optional debugging check: pass plan output through copyObject() */
@@ -794,10 +783,7 @@ pg_exec_query_string(char *query_string,		/* string to execute */
 				}
 
 				if (Show_executor_stats)
-				{
-					fprintf(StatFp, "EXECUTOR STATISTICS\n");
-					ShowUsage();
-				}
+					ShowUsage("EXECUTOR STATISTICS");
 			}
 
 			/*
@@ -1155,7 +1141,6 @@ PostgresMain(int argc, char *argv[], const char *username)
 		ResetAllOptions(true);
 		potential_DataDir = getenv("PGDATA");
 	}
-	StatFp = stderr;
 
 	/* Check for PGDATESTYLE environment variable */
 	set_default_datestyle();
@@ -1642,7 +1627,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 	if (!IsUnderPostmaster)
 	{
 		puts("\nPOSTGRES backend interactive interface ");
-		puts("$Revision: 1.241 $ $Date: 2001/11/05 17:46:28 $\n");
+		puts("$Revision: 1.242 $ $Date: 2001/11/10 23:51:14 $\n");
 	}
 
 	/*
@@ -1867,10 +1852,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 										 QueryContext);
 
 					if (Show_query_stats)
-					{
-						fprintf(StatFp, "QUERY STATISTICS\n");
-						ShowUsage();
-					}
+						ShowUsage("QUERY STATISTICS");
 				}
 				break;
 
@@ -1933,18 +1915,20 @@ ResetUsage(void)
 }
 
 void
-ShowUsage(void)
+ShowUsage(const char *title)
 {
+	StringInfoData str;
 	struct timeval user,
 				sys;
 	struct timeval elapse_t;
 	struct timezone tz;
 	struct rusage r;
+	char *bufusage;
 
 	getrusage(RUSAGE_SELF, &r);
 	gettimeofday(&elapse_t, &tz);
-	memmove((char *) &user, (char *) &r.ru_utime, sizeof(user));
-	memmove((char *) &sys, (char *) &r.ru_stime, sizeof(sys));
+	memcpy((char *) &user, (char *) &r.ru_utime, sizeof(user));
+	memcpy((char *) &sys, (char *) &r.ru_stime, sizeof(sys));
 	if (elapse_t.tv_usec < Save_t.tv_usec)
 	{
 		elapse_t.tv_sec--;
@@ -1961,12 +1945,6 @@ ShowUsage(void)
 		r.ru_stime.tv_usec += 1000000;
 	}
 
-	/*
-	 * Set output destination if not otherwise set
-	 */
-	if (StatFp == NULL)
-		StatFp = stderr;
-
 	/*
 	 * the only stats we don't show here are for memory usage -- i can't
 	 * figure out how to interpret the relevant fields in the rusage
@@ -1975,9 +1953,10 @@ ShowUsage(void)
 	 * resident set size, shared text size, and unshared data and stack
 	 * sizes.
 	 */
+	initStringInfo(&str);
 
-	fprintf(StatFp, "! system usage stats:\n");
-	fprintf(StatFp,
+	appendStringInfo(&str, "! system usage stats:\n");
+	appendStringInfo(&str,
 			"!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
 			(long int) elapse_t.tv_sec - Save_t.tv_sec,
 			(long int) elapse_t.tv_usec - Save_t.tv_usec,
@@ -1985,7 +1964,7 @@ ShowUsage(void)
 			(long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
 			(long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
 			(long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
-	fprintf(StatFp,
+	appendStringInfo(&str,
 			"!\t[%ld.%06ld user %ld.%06ld sys total]\n",
 			(long int) user.tv_sec,
 			(long int) user.tv_usec,
@@ -1993,35 +1972,44 @@ ShowUsage(void)
 			(long int) sys.tv_usec);
 /* BeOS has rusage but only has some fields, and not these... */
 #if defined(HAVE_GETRUSAGE)
-	fprintf(StatFp,
+	appendStringInfo(&str,
 			"!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
 			r.ru_inblock - Save_r.ru_inblock,
 	/* they only drink coffee at dec */
 			r.ru_oublock - Save_r.ru_oublock,
 			r.ru_inblock, r.ru_oublock);
-	fprintf(StatFp,
+	appendStringInfo(&str,
 		  "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
 			r.ru_majflt - Save_r.ru_majflt,
 			r.ru_minflt - Save_r.ru_minflt,
 			r.ru_majflt, r.ru_minflt,
 			r.ru_nswap - Save_r.ru_nswap,
 			r.ru_nswap);
-	fprintf(StatFp,
+	appendStringInfo(&str,
 	 "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
 			r.ru_nsignals - Save_r.ru_nsignals,
 			r.ru_nsignals,
 			r.ru_msgrcv - Save_r.ru_msgrcv,
 			r.ru_msgsnd - Save_r.ru_msgsnd,
 			r.ru_msgrcv, r.ru_msgsnd);
-	fprintf(StatFp,
+	appendStringInfo(&str,
 		 "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
 			r.ru_nvcsw - Save_r.ru_nvcsw,
 			r.ru_nivcsw - Save_r.ru_nivcsw,
 			r.ru_nvcsw, r.ru_nivcsw);
 #endif   /* HAVE_GETRUSAGE */
-	fprintf(StatFp, "! postgres usage stats:\n");
-	PrintBufferUsage(StatFp);
-/*	   DisplayTupleCount(StatFp); */
+
+	bufusage = ShowBufferUsage();
+	appendStringInfo(&str, "! postgres usage stats:\n%s", bufusage);
+	pfree(bufusage);
+
+	/* remove trailing newline */
+	if (str.data[str.len-1] == '\n')
+		str.data[--str.len] = '\0';
+
+	elog(DEBUG, "%s\n%s", title, str.data);
+
+	pfree(str.data);
 }
 
 #ifdef NOT_USED
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 1655ad02e5073a5dbd4aa5e8fdcc89096da5ddbc..2bdae7a3a5a7842f7c8a263a8fb8701d8c60d07f 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: bufmgr.h,v 1.56 2001/10/28 06:26:08 momjian Exp $
+ * $Id: bufmgr.h,v 1.57 2001/11/10 23:51:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -164,7 +164,7 @@ extern int	FlushBuffer(Buffer buffer, bool sync, bool release);
 
 extern void InitBufferPool(void);
 extern void InitBufferPoolAccess(void);
-extern void PrintBufferUsage(FILE *statfp);
+extern char *ShowBufferUsage(void);
 extern void ResetBufferUsage(void);
 extern void ResetBufferPool(bool isCommit);
 extern bool BufferPoolCheckLeak(void);
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index 5b5d60e025971470bd811ebaf1097e342a11059a..28e45e7b5e98068b53cc444f1381ba3243219513 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: tcopprot.h,v 1.46 2001/11/05 17:46:36 momjian Exp $
+ * $Id: tcopprot.h,v 1.47 2001/11/10 23:51:14 tgl Exp $
  *
  * OLD COMMENTS
  *	  This file was created so that other c files could get the two
@@ -20,14 +20,15 @@
 #define TCOPPROT_H
 
 #include <setjmp.h>
+
 #include "executor/execdesc.h"
 #include "tcop/dest.h"
 
+
 extern DLLIMPORT sigjmp_buf Warn_restart;
 extern bool Warn_restart_ready;
 extern bool InError;
 extern CommandDest whereToSendOutput;
-
 extern bool HostnameLookup;
 extern bool ShowPortNumber;
 
@@ -46,7 +47,6 @@ extern void quickdie(SIGNAL_ARGS);
 extern void authdie(SIGNAL_ARGS);
 extern int	PostgresMain(int argc, char *argv[], const char *username);
 extern void ResetUsage(void);
-extern void ShowUsage(void);
-extern FILE *StatFp;
+extern void ShowUsage(const char *title);
 
 #endif   /* TCOPPROT_H */