diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 32346e413f37afacfb96ed073eb6f9444e8e5035..75392accf7d662bcfa4e1ff7637edca97697a6e2 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.204 2008/05/14 04:07:01 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.205 2008/05/16 16:59:05 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -1555,7 +1555,8 @@ lo_import 152801
           <term><literal>columns</literal></term>
           <listitem>
           <para>
-          Controls the target width for the <literal>wrapped</> format.
+          Controls the target width for the <literal>wrapped</> format,
+          and width for determining if wide output requires the pager.
           Zero (the default) causes the <literal>wrapped</> format to
           affect only screen output.
           </para>
@@ -1717,10 +1718,9 @@ lo_import 152801
           When the pager is <literal>off</>, the pager is not used. When the pager
           is <literal>on</>, the pager is used only when appropriate, i.e. the
           output is to a terminal and will not fit on the screen.
-          (<application>psql</> does not do a perfect job of estimating
-          when to use the pager.) <literal>\pset pager</> turns the
-          pager on and off. Pager can also be set to <literal>always</>,
-          which causes the pager to be always used.
+          <literal>\pset pager</> turns the pager on and off. Pager can
+          also be set to <literal>always</>, which causes the pager to be
+          always used.
           </para>
           </listitem>
           </varlistentry>
@@ -2734,8 +2734,9 @@ $endif
 
     <listitem>
      <para>
-      Used for the <literal>wrapped</> output format if 
-      <literal>\pset columns</> is zero.
+      If <literal>\pset columns</> is zero, controls the
+      width for the <literal>wrapped</> format and width for determining
+      if wide output requires the pager.
      </para>
     </listitem>
    </varlistentry>
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index f27c1e1f4887135df589aa526f514badf2d05cb6..9f531f25faafcdad6a194a73376807229a934650 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2008, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.101 2008/05/13 00:14:11 alvherre Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.102 2008/05/16 16:59:05 momjian Exp $
  */
 #include "postgres_fe.h"
 
@@ -45,6 +45,8 @@ static char *thousands_sep;
 
 /* Local functions */
 static int strlen_max_width(unsigned char *str, int *target_width, int encoding);
+static void IsPagerNeeded(const printTableContent *cont, const int extra_lines,
+						  FILE **fout, bool *is_pager);
 
 
 static void *
@@ -394,7 +396,7 @@ _print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths,
  *	Print pretty boxes around cells.
  */
 static void
-print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
+print_aligned_text(const printTableContent *cont, FILE *fout)
 {
 	bool		opt_tuples_only = cont->opt->tuples_only;
 	bool		opt_numeric_locale = cont->opt->numericLocale;
@@ -416,6 +418,8 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
 	unsigned char **format_buf;
 	unsigned int width_total;
 	unsigned int total_header_width;
+	unsigned int extra_row_output_lines = 0;
+	unsigned int extra_output_lines = 0;
 
 	const char * const *ptr;
 
@@ -424,6 +428,7 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
 	bool	   *header_done;	/* Have all header lines been output? */
 	int		   *bytes_output;	/* Bytes output for column value */
 	int			output_columns = 0;	/* Width of interactive console */
+	bool		is_pager = false;
 
 	if (cancel_pressed)
 		return;
@@ -476,9 +481,14 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
 			max_nl_lines[i] = nl_lines;
 		if (bytes_required > max_bytes[i])
 			max_bytes[i] = bytes_required;
+		if (nl_lines > extra_row_output_lines)
+			extra_row_output_lines = nl_lines;
 
 		width_header[i] = width;
 	}
+	/* Add height of tallest header column */
+	extra_output_lines += extra_row_output_lines;
+	extra_row_output_lines = 0;
 
 	/* scan all cells, find maximum width, compute cell_count */
 	for (i = 0, ptr = cont->cells; *ptr; ptr++, i++, cell_count++)
@@ -487,7 +497,6 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
 					nl_lines,
 					bytes_required;
 
-		/* Get width, ignore nl_lines */
 		pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding,
 				   &width, &nl_lines, &bytes_required);
 		if (opt_numeric_locale && cont->aligns[i % col_count] == 'r')
@@ -552,28 +561,28 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
 	for (i = 0; i < col_count; i++)
 		width_wrap[i] = max_width[i];
 
-	if (cont->opt->format == PRINT_WRAPPED)
+	/*
+	 * Choose target output width: \pset columns, or $COLUMNS, or ioctl
+	 */
+	if (cont->opt->columns > 0)
+		output_columns = cont->opt->columns;
+	else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
 	{
-		/*
-		 * Choose target output width: \pset columns, or $COLUMNS, or ioctl
-		 */
-		if (cont->opt->columns > 0)
-			output_columns = cont->opt->columns;
-		else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
-		{
-			if (cont->opt->env_columns > 0)
-				output_columns = cont->opt->env_columns;
+		if (cont->opt->env_columns > 0)
+			output_columns = cont->opt->env_columns;
 #ifdef TIOCGWINSZ
-			else
-			{
-				struct winsize screen_size;
-	
-				if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
-					output_columns = screen_size.ws_col;
-			}
-#endif
+		else
+		{
+			struct winsize screen_size;
+
+			if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
+				output_columns = screen_size.ws_col;
 		}
+#endif
+	}
 
+	if (cont->opt->format == PRINT_WRAPPED)
+	{
 		/*
 		 * Optional optimized word wrap. Shrink columns with a high max/avg
 		 * ratio.  Slighly bias against wider columns. (Increases chance a
@@ -623,6 +632,49 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
 		}
 	}
 
+	/* If we wrapped beyond the display width, use the pager */
+	if (!is_pager && output_columns > 0 &&
+		(output_columns < total_header_width || output_columns < width_total))
+	{
+		fout = PageOutput(INT_MAX, cont->opt->pager);	/* force pager */
+		is_pager = true;
+	}
+	
+	/* Check if newlines or our wrapping now need the pager */
+	if (!is_pager)
+	{
+		/* scan all cells, find maximum width, compute cell_count */
+		for (i = 0, ptr = cont->cells; *ptr; ptr++, i++, cell_count++)
+		{
+			int			width,
+						nl_lines,
+						bytes_required;
+	
+			pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding,
+					   &width, &nl_lines, &bytes_required);
+			if (opt_numeric_locale && cont->align[i % col_count] == 'r')
+				width += additional_numeric_locale_len(*ptr);
+	
+			/*
+			 *	A row can have both wrapping and newlines that cause
+			 *	it to display across multiple lines.  We check
+			 *	for both cases below.
+			 */
+			if (width > 0 && width_wrap[i] &&
+				(width-1) / width_wrap[i] + nl_lines > extra_row_output_lines)
+				extra_row_output_lines = (width-1) / width_wrap[i] + nl_lines;
+
+			/* If last column, add tallest column height */
+			if (i % col_count == col_count - 1)
+			{
+				/* Add height of tallest row */
+				extra_output_lines += extra_row_output_lines;
+				extra_row_output_lines = 0;
+			}
+		}
+		IsPagerNeeded(cont, extra_output_lines, &fout, &is_pager);
+	}
+	
 	/* time to output */
 	if (cont->opt->start_table)
 	{
@@ -882,6 +934,9 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
 	for (i = 0; i < col_count; i++)
 		free(format_buf[i]);
 	free(format_buf);
+
+	if (is_pager)
+		ClosePager(fout);
 }
 
 
@@ -2115,21 +2170,15 @@ printTableCleanup(printTableContent *content)
 }
 
 /*
- * Use this to print just any table in the supported formats.
+ * IsPagerNeeded
+ *
+ * Setup pager if required
  */
 void
-printTable(const printTableContent *cont, FILE *fout, FILE *flog)
+IsPagerNeeded(const printTableContent *cont, const int extra_lines, FILE **fout,
+			  bool *is_pager)
 {
-	FILE	   *output;
-	bool		is_pager = false;
-	
-	if (cancel_pressed)
-		return;
-
-	if (cont->opt->format == PRINT_NOTHING)
-		return;
-
-	if (fout == stdout)
+	if (*fout == stdout)
 	{
 		int			lines;
 
@@ -2150,58 +2199,79 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 				lines++;
 		}
 
-		output = PageOutput(lines, cont->opt->pager);
-		is_pager = (output != fout);
+		*fout = PageOutput(lines + extra_lines, cont->opt->pager);
+		*is_pager = (*fout != stdout);
 	}
 	else
-		output = fout;
+		*is_pager = false;
+}
+
+/*
+ * Use this to print just any table in the supported formats.
+ */
+void
+printTable(const printTableContent *cont, FILE *fout, FILE *flog)
+{
+	bool		is_pager = false;
+	
+	if (cancel_pressed)
+		return;
+
+	if (cont->opt->format == PRINT_NOTHING)
+		return;
+
+	/* print_aligned_text() handles the pager itself */
+	if ((cont->opt->format != PRINT_ALIGNED &&
+		 cont->opt->format != PRINT_WRAPPED) ||
+		 cont->opt->expanded)
+		IsPagerNeeded(cont, 0, &fout, &is_pager);
 
 	/* print the stuff */
 
 	if (flog)
-		print_aligned_text(cont, is_pager, flog);
+		print_aligned_text(cont, flog);
 
 	switch (cont->opt->format)
 	{
 		case PRINT_UNALIGNED:
 			if (cont->opt->expanded)
-				print_unaligned_vertical(cont, output);
+				print_unaligned_vertical(cont, fout);
 			else
-				print_unaligned_text(cont, output);
+				print_unaligned_text(cont, fout);
 			break;
 		case PRINT_ALIGNED:
 		case PRINT_WRAPPED:
 			if (cont->opt->expanded)
-				print_aligned_vertical(cont, output);
+				print_aligned_vertical(cont, fout);
 			else
-				print_aligned_text(cont, is_pager, output);
+				print_aligned_text(cont, fout);
 			break;
 		case PRINT_HTML:
 			if (cont->opt->expanded)
-				print_html_vertical(cont, output);
+				print_html_vertical(cont, fout);
 			else
-				print_html_text(cont, output);
+				print_html_text(cont, fout);
 			break;
 		case PRINT_LATEX:
 			if (cont->opt->expanded)
-				print_latex_vertical(cont, output);
+				print_latex_vertical(cont, fout);
 			else
-				print_latex_text(cont, output);
+				print_latex_text(cont, fout);
 			break;
 		case PRINT_TROFF_MS:
 			if (cont->opt->expanded)
-				print_troff_ms_vertical(cont, output);
+				print_troff_ms_vertical(cont, fout);
 			else
-				print_troff_ms_text(cont, output);
+				print_troff_ms_text(cont, fout);
 			break;
 		default:
-			fprintf(stderr, _("invalid output format (internal error): %d"),
+			fprintf(stderr, _("invalid fout format (internal error): %d"),
 					cont->opt->format);
 			exit(EXIT_FAILURE);
 	}
 
 	if (is_pager)
-		ClosePager(output);
+		ClosePager(fout);
 }
 
 /*