diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index bd3dee4fa10f64adc47cabec004ae1216cc6402a..2449a881bcd0e761760479db3882ca138f5ae023 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12,7 +12,7 @@
  *	by PostgreSQL
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.367 2004/03/03 21:28:54 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.368 2004/03/20 20:09:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -67,6 +67,15 @@ extern int	optind,
 			opterr;
 
 
+typedef struct
+{
+	const char *descr;			/* comment for an object */
+	Oid			classoid;		/* object class (catalog OID) */
+	Oid			objoid;			/* object OID */
+	int			objsubid;		/* subobject (table column #) */
+} CommentItem;
+
+
 /* global decls */
 bool		g_verbose;			/* User wants verbose narration of our
 								 * activities. */
@@ -105,6 +114,9 @@ static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
 static void dumpComment(Archive *fout, const char *target,
 			const char *namespace, const char *owner,
 			CatalogId catalogId, int subid, DumpId dumpId);
+static int	findComments(Archive *fout, Oid classoid, Oid objoid,
+						 CommentItem **items);
+static int	collectComments(Archive *fout, CommentItem **items);
 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
 static void dumpType(Archive *fout, TypeInfo *tinfo);
@@ -3880,58 +3892,33 @@ dumpComment(Archive *fout, const char *target,
 			const char *namespace, const char *owner,
 			CatalogId catalogId, int subid, DumpId dumpId)
 {
-	PGresult   *res;
-	PQExpBuffer query;
-	int			i_description;
+	CommentItem *comments;
+	int			ncomments;
 
 	/* Comments are SCHEMA not data */
 	if (dataOnly)
 		return;
 
-	/*
-	 * Note we do NOT change source schema here; preserve the caller's
-	 * setting, instead.
-	 */
+	/* Search for comments associated with catalogId, using table */
+	ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
+							 &comments);
 
-	/* Build query to find comment */
-
-	query = createPQExpBuffer();
-
-	if (fout->remoteVersion >= 70300)
-	{
-		appendPQExpBuffer(query,
-						  "SELECT description FROM pg_catalog.pg_description "
-						  "WHERE classoid = '%u'::pg_catalog.oid and "
-						  "objoid = '%u'::pg_catalog.oid and objsubid = %d",
-						  catalogId.tableoid, catalogId.oid, subid);
-	}
-	else if (fout->remoteVersion >= 70200)
-	{
-		appendPQExpBuffer(query,
-						  "SELECT description FROM pg_description "
-						  "WHERE classoid = '%u'::oid and "
-						  "objoid = '%u'::oid and objsubid = %d",
-						  catalogId.tableoid, catalogId.oid, subid);
-	}
-	else
+	/* Is there one matching the subid? */
+	while (ncomments > 0)
 	{
-		/* Note: this will fail to find attribute comments in pre-7.2... */
-		appendPQExpBuffer(query, "SELECT description FROM pg_description WHERE objoid = '%u'::oid", catalogId.oid);
+		if (comments->objsubid == subid)
+			break;
+		comments++;
+		ncomments--;
 	}
 
-	/* Execute query */
-
-	res = PQexec(g_conn, query->data);
-	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
-
 	/* If a comment exists, build COMMENT ON statement */
-
-	if (PQntuples(res) == 1)
+	if (ncomments > 0)
 	{
-		i_description = PQfnumber(res, "description");
-		resetPQExpBuffer(query);
+		PQExpBuffer query = createPQExpBuffer();
+
 		appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
-		appendStringLiteral(query, PQgetvalue(res, 0, i_description), false);
+		appendStringLiteral(query, comments->descr, false);
 		appendPQExpBuffer(query, ";\n");
 
 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
@@ -3939,82 +3926,47 @@ dumpComment(Archive *fout, const char *target,
 					 "COMMENT", query->data, "", NULL,
 					 &(dumpId), 1,
 					 NULL, NULL);
-	}
 
-	PQclear(res);
-	destroyPQExpBuffer(query);
+		destroyPQExpBuffer(query);
+	}
 }
 
 /*
  * dumpTableComment --
  *
  * As above, but dump comments for both the specified table (or view)
- * and its columns.  For speed, we want to do this with only one query.
+ * and its columns.
  */
 static void
 dumpTableComment(Archive *fout, TableInfo *tbinfo,
 				 const char *reltypename)
 {
-	PGresult   *res;
+	CommentItem *comments;
+	int			ncomments;
 	PQExpBuffer query;
 	PQExpBuffer target;
-	int			i_description;
-	int			i_objsubid;
-	int			ntups;
-	int			i;
 
 	/* Comments are SCHEMA not data */
 	if (dataOnly)
 		return;
 
-	/*
-	 * Note we do NOT change source schema here; preserve the caller's
-	 * setting, instead.
-	 */
+	/* Search for comments associated with relation, using table */
+	ncomments = findComments(fout,
+							 tbinfo->dobj.catId.tableoid,
+							 tbinfo->dobj.catId.oid,
+							 &comments);
 
-	/* Build query to find comments */
+	/* If comments exist, build COMMENT ON statements */
+	if (ncomments <= 0)
+		return;
 
 	query = createPQExpBuffer();
 	target = createPQExpBuffer();
 
-	if (fout->remoteVersion >= 70300)
-	{
-		appendPQExpBuffer(query, "SELECT description, objsubid FROM pg_catalog.pg_description "
-						  "WHERE classoid = '%u'::pg_catalog.oid and "
-						  "objoid = '%u'::pg_catalog.oid "
-						  "ORDER BY objoid, classoid, objsubid",
-						  tbinfo->dobj.catId.tableoid, tbinfo->dobj.catId.oid);
-	}
-	else if (fout->remoteVersion >= 70200)
-	{
-		appendPQExpBuffer(query, "SELECT description, objsubid FROM pg_description "
-						  "WHERE classoid = '%u'::oid and "
-						  "objoid = '%u'::oid "
-						  "ORDER BY objoid, classoid, objsubid",
-						  tbinfo->dobj.catId.tableoid, tbinfo->dobj.catId.oid);
-	}
-	else
-	{
-		/* Note: this will fail to find attribute comments in pre-7.2... */
-		appendPQExpBuffer(query, "SELECT description, 0 as objsubid FROM pg_description WHERE objoid = '%u'::oid",
-						  tbinfo->dobj.catId.oid);
-	}
-
-	/* Execute query */
-
-	res = PQexec(g_conn, query->data);
-	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
-
-	i_description = PQfnumber(res, "description");
-	i_objsubid = PQfnumber(res, "objsubid");
-
-	/* If comments exist, build COMMENT ON statements */
-
-	ntups = PQntuples(res);
-	for (i = 0; i < ntups; i++)
+	while (ncomments > 0)
 	{
-		const char *descr = PQgetvalue(res, i, i_description);
-		int			objsubid = atoi(PQgetvalue(res, i, i_objsubid));
+		const char *descr = comments->descr;
+		int			objsubid = comments->objsubid;
 
 		if (objsubid == 0)
 		{
@@ -4054,13 +4006,183 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo,
 						 &(tbinfo->dobj.dumpId), 1,
 						 NULL, NULL);
 		}
+
+		comments++;
+		ncomments--;
 	}
 
-	PQclear(res);
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(target);
 }
 
+/*
+ * findComments --
+ *
+ * Find the comment(s), if any, associated with the given object.  All the
+ * objsubid values associated with the given classoid/objoid are found with
+ * one search.
+ */
+static int
+findComments(Archive *fout, Oid classoid, Oid objoid,
+			 CommentItem **items)
+{
+	/* static storage for table of comments */
+	static CommentItem *comments = NULL;
+	static int	ncomments = -1;
+
+	CommentItem *middle = NULL;
+	CommentItem *low;
+	CommentItem *high;
+	int			nmatch;
+
+	/* Get comments if we didn't already */
+	if (ncomments < 0)
+		ncomments = collectComments(fout, &comments);
+
+	/*
+	 * Pre-7.2, pg_description does not contain classoid, so collectComments
+	 * just stores a zero.  If there's a collision on object OID, well, you
+	 * get duplicate comments.
+	 */
+	if (fout->remoteVersion < 70200)
+		classoid = 0;
+
+	/*
+	 * Do binary search to find some item matching the object.
+	 */
+	low = &comments[0];
+	high = &comments[ncomments-1];
+	while (low <= high)
+	{
+		middle = low + (high - low) / 2;
+
+		if (classoid < middle->classoid)
+			high = middle - 1;
+		else if (classoid > middle->classoid)
+			low = middle + 1;
+		else if (objoid < middle->objoid)
+			high = middle - 1;
+		else if (objoid > middle->objoid)
+			low = middle + 1;
+		else
+			break;				/* found a match */
+	}
+
+	if (low > high)				/* no matches */
+	{
+		*items = NULL;
+		return 0;
+	}
+
+	/*
+	 * Now determine how many items match the object.  The search loop
+	 * invariant still holds: only items between low and high inclusive
+	 * could match.
+	 */
+	nmatch = 1;
+	while (middle > low)
+	{
+		if (classoid != middle[-1].classoid ||
+			objoid != middle[-1].objoid)
+			break;
+		middle--;
+		nmatch++;
+	}
+
+	*items = middle;
+
+	middle += nmatch;
+	while (middle <= high)
+	{
+		if (classoid != middle->classoid ||
+			objoid != middle->objoid)
+			break;
+		middle++;
+		nmatch++;
+	}
+
+	return nmatch;
+}
+
+/*
+ * collectComments --
+ *
+ * Construct a table of all comments available for database objects.
+ * We used to do per-object queries for the comments, but it's much faster
+ * to pull them all over at once, and on most databases the memory cost
+ * isn't high.
+ *
+ * The table is sorted by classoid/objid/objsubid for speed in lookup.
+ */
+static int
+collectComments(Archive *fout, CommentItem **items)
+{
+	PGresult   *res;
+	PQExpBuffer query;
+	int			i_description;
+	int			i_classoid;
+	int			i_objoid;
+	int			i_objsubid;
+	int			ntups;
+	int			i;
+	CommentItem *comments;
+
+	/*
+	 * Note we do NOT change source schema here; preserve the caller's
+	 * setting, instead.
+	 */
+
+	query = createPQExpBuffer();
+
+	if (fout->remoteVersion >= 70300)
+	{
+		appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
+						  "FROM pg_catalog.pg_description "
+						  "ORDER BY classoid, objoid, objsubid");
+	}
+	else if (fout->remoteVersion >= 70200)
+	{
+		appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
+						  "FROM pg_description "
+						  "ORDER BY classoid, objoid, objsubid");
+	}
+	else
+	{
+		/* Note: this will fail to find attribute comments in pre-7.2... */
+		appendPQExpBuffer(query, "SELECT description, 0 as classoid, objoid, 0 as objsubid "
+						  "FROM pg_description "
+						  "ORDER BY objoid");
+	}
+
+	res = PQexec(g_conn, query->data);
+	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+	/* Construct lookup table containing OIDs in numeric form */
+
+	i_description = PQfnumber(res, "description");
+	i_classoid = PQfnumber(res, "classoid");
+	i_objoid = PQfnumber(res, "objoid");
+	i_objsubid = PQfnumber(res, "objsubid");
+
+	ntups = PQntuples(res);
+
+	comments = (CommentItem *) malloc(ntups * sizeof(CommentItem));
+
+	for (i = 0; i < ntups; i++)
+	{
+		comments[i].descr = PQgetvalue(res, i, i_description);
+		comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
+		comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
+		comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
+	}
+
+	/* Do NOT free the PGresult since we are keeping pointers into it */
+	destroyPQExpBuffer(query);
+
+	*items = comments;
+	return ntups;
+}
+
 /*
  * dumpDumpableObject
  *