diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 592eeba4177bb81e5a06e46f4c3d211bbc5e0b8f..608ebf93ce819d56e3db632a3df03e531277fbed 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.162 2007/04/27 22:05:47 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.163 2007/05/04 21:29:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,6 +30,7 @@
 #include "utils/builtins.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
+#include "utils/tuplesort.h"
 
 
 typedef struct ExplainState
@@ -58,6 +59,8 @@ static void show_upper_qual(List *qual, const char *qlabel, Plan *plan,
 static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
 			   const char *qlabel,
 			   StringInfo str, int indent, ExplainState *es);
+static void show_sort_info(SortState *sortstate,
+			   StringInfo str, int indent, ExplainState *es);
 
 /*
  * ExplainQuery -
@@ -818,6 +821,8 @@ explain_outNode(StringInfo str,
 						   ((Sort *) plan)->sortColIdx,
 						   "Sort Key",
 						   str, indent, es);
+			show_sort_info((SortState *) planstate,
+						   str, indent, es);
 			break;
 		case T_Result:
 			show_upper_qual((List *) ((Result *) plan)->resconstantqual,
@@ -1123,3 +1128,25 @@ show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
 
 	appendStringInfo(str, "\n");
 }
+
+/*
+ * If it's EXPLAIN ANALYZE, show tuplesort explain info for a sort node
+ */
+static void
+show_sort_info(SortState *sortstate,
+			   StringInfo str, int indent, ExplainState *es)
+{
+	Assert(IsA(sortstate, SortState));
+	if (es->printAnalyze && sortstate->sort_Done &&
+		sortstate->tuplesortstate != NULL)
+	{
+		char	   *sortinfo;
+		int			i;
+
+		sortinfo = tuplesort_explain((Tuplesortstate *) sortstate->tuplesortstate);
+		for (i = 0; i < indent; i++)
+			appendStringInfo(str, "  ");
+		appendStringInfo(str, "  %s\n", sortinfo);
+		pfree(sortinfo);
+	}
+}
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index e4fc74b3e933b22d95c9c603d2272315fc5d14ff..707112d5fb1cb8356f359f9f427b970784056ffa 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -91,7 +91,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.75 2007/05/04 01:13:44 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.76 2007/05/04 21:29:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -196,6 +196,7 @@ struct Tuplesortstate
 	bool		randomAccess;	/* did caller request random access? */
 	bool		bounded;		/* did caller specify a maximum number of
 								 * tuples to return? */
+	bool		boundUsed;		/* true if we made use of a bounded heap */
 	int			bound;			/* if bounded, the maximum number of tuples */
 	long		availMem;		/* remaining memory available, in bytes */
 	long		allowedMem;		/* total memory allowed, in bytes */
@@ -505,6 +506,8 @@ tuplesort_begin_common(int workMem, bool randomAccess)
 
 	state->status = TSS_INITIAL;
 	state->randomAccess = randomAccess;
+	state->bounded = false;
+	state->boundUsed = false;
 	state->allowedMem = workMem * 1024L;
 	state->availMem = state->allowedMem;
 	state->sortcontext = sortcontext;
@@ -2113,6 +2116,64 @@ tuplesort_restorepos(Tuplesortstate *state)
 	MemoryContextSwitchTo(oldcontext);
 }
 
+/*
+ * tuplesort_explain - produce a line of information for EXPLAIN ANALYZE
+ *
+ * This can be called after tuplesort_performsort() finishes to obtain
+ * printable summary information about how the sort was performed.
+ *
+ * The result is a palloc'd string.
+ */
+char *
+tuplesort_explain(Tuplesortstate *state)
+{
+	char	   *result = (char *) palloc(100);
+	long		spaceUsed;
+
+	/*
+	 * Note: it might seem we should print both memory and disk usage for a
+	 * disk-based sort.  However, the current code doesn't track memory space
+	 * accurately once we have begun to return tuples to the caller (since
+	 * we don't account for pfree's the caller is expected to do), so we
+	 * cannot rely on availMem in a disk sort.  This does not seem worth the
+	 * overhead to fix.  Is it worth creating an API for the memory context
+	 * code to tell us how much is actually used in sortcontext?
+	 */
+	if (state->tapeset)
+		spaceUsed = LogicalTapeSetBlocks(state->tapeset) * (BLCKSZ / 1024);
+	else
+		spaceUsed = (state->allowedMem - state->availMem + 1023) / 1024;
+
+	switch (state->status)
+	{
+		case TSS_SORTEDINMEM:
+			if (state->boundUsed)
+				snprintf(result, 100,
+						 "Sort Method:  top-N heapsort  Memory: %ldkB",
+						 spaceUsed);
+			else
+				snprintf(result, 100,
+						 "Sort Method:  quicksort  Memory: %ldkB",
+						 spaceUsed);
+			break;
+		case TSS_SORTEDONTAPE:
+			snprintf(result, 100,
+					 "Sort Method:  external sort  Disk: %ldkB",
+					 spaceUsed);
+			break;
+		case TSS_FINALMERGE:
+			snprintf(result, 100,
+					 "Sort Method:  external merge  Disk: %ldkB",
+					 spaceUsed);
+			break;
+		default:
+			snprintf(result, 100, "sort still in progress");
+			break;
+	}
+
+	return result;
+}
+
 
 /*
  * Heap manipulation routines, per Knuth's Algorithm 5.2.3H.
@@ -2216,6 +2277,7 @@ sort_bounded_heap(Tuplesortstate *state)
 	REVERSEDIRECTION(state);
 
 	state->status = TSS_SORTEDINMEM;
+	state->boundUsed = true;
 }
 
 /*
diff --git a/src/include/utils/tuplesort.h b/src/include/utils/tuplesort.h
index c736896a9a984c78bb552e5319568e0dbb84f2a9..b522c3ef7b6760fdb2b5dda5c5e2384ec29b34f8 100644
--- a/src/include/utils/tuplesort.h
+++ b/src/include/utils/tuplesort.h
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/tuplesort.h,v 1.26 2007/05/04 01:13:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/tuplesort.h,v 1.27 2007/05/04 21:29:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -74,6 +74,8 @@ extern bool tuplesort_getdatum(Tuplesortstate *state, bool forward,
 
 extern void tuplesort_end(Tuplesortstate *state);
 
+extern char *tuplesort_explain(Tuplesortstate *state);
+
 extern int	tuplesort_merge_order(long allowedMem);
 
 /*