psql expanded auto

Started by Peter Eisentrautabout 15 years ago14 messages
#1Peter Eisentraut
peter_e@gmx.net
1 attachment(s)

I have often found myself wanting that psql automatically switch between
normal and \x mode depending on the width of the output. Would others
find this useful?

Attached is a crude demo patch. Enable with \pset expanded auto.

Attachments:

psql-expanded-auto.difftext/x-patch; charset=UTF-8; name=psql-expanded-auto.diffDownload
diff --git i/src/bin/psql/command.c w/src/bin/psql/command.c
index c1edf44..7e24903 100644
--- i/src/bin/psql/command.c
+++ w/src/bin/psql/command.c
@@ -2129,14 +2129,21 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 	/* set expanded/vertical mode */
 	else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
 	{
-		if (value)
+		if (value && pg_strcasecmp(value, "auto") == 0)
+			popt->topt.expanded = 2;
+		else if (value)
 			popt->topt.expanded = ParseVariableBool(value);
 		else
 			popt->topt.expanded = !popt->topt.expanded;
 		if (!quiet)
-			printf(popt->topt.expanded
-				   ? _("Expanded display is on.\n")
-				   : _("Expanded display is off.\n"));
+		{
+			if (popt->topt.expanded == 1)
+				printf(_("Expanded display is on.\n"));
+			else if (popt->topt.expanded == 2)
+				printf(_("Expanded display is used automatically.\n"));
+			else
+				printf(_("Expanded display is off.\n"));
+		}
 	}
 
 	/* locale-aware numeric output */
diff --git i/src/bin/psql/print.c w/src/bin/psql/print.c
index c946076..07f27bc 100644
--- i/src/bin/psql/print.c
+++ w/src/bin/psql/print.c
@@ -122,9 +122,11 @@ const printTextFormat pg_utf8format =
 
 /* 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,
+static void IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded,
 			  FILE **fout, bool *is_pager);
 
+static void print_aligned_vertical(const printTableContent *cont, FILE *fout);
+
 
 static void *
 pg_local_malloc(size_t size)
@@ -713,6 +715,13 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 		}
 	}
 
+	if (cont->opt->expanded == 2 &&
+		(output_columns < total_header_width || output_columns < width_total))
+	{
+		print_aligned_vertical(cont, fout);
+		return;
+	}
+
 	/* If we wrapped beyond the display width, use the pager */
 	if (!is_pager && fout == stdout && output_columns > 0 &&
 		(output_columns < total_header_width || output_columns < width_total))
@@ -756,7 +765,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 				extra_row_output_lines = 0;
 			}
 		}
-		IsPagerNeeded(cont, extra_output_lines, &fout, &is_pager);
+		IsPagerNeeded(cont, extra_output_lines, false, &fout, &is_pager);
 	}
 
 	/* time to output */
@@ -2265,14 +2274,14 @@ printTableCleanup(printTableContent *const content)
  * Setup pager if required
  */
 static void
-IsPagerNeeded(const printTableContent *cont, const int extra_lines, FILE **fout,
+IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded, FILE **fout,
 			  bool *is_pager)
 {
 	if (*fout == stdout)
 	{
 		int			lines;
 
-		if (cont->opt->expanded)
+		if (expanded)
 			lines = (cont->ncolumns + 1) * cont->nrows;
 		else
 			lines = cont->nrows + 1;
@@ -2313,8 +2322,8 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 	/* 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);
+		cont->opt->expanded == 1)
+		IsPagerNeeded(cont, 0, true, &fout, &is_pager);
 
 	/* print the stuff */
 
@@ -2324,32 +2333,32 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 	switch (cont->opt->format)
 	{
 		case PRINT_UNALIGNED:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_unaligned_vertical(cont, fout);
 			else
 				print_unaligned_text(cont, fout);
 			break;
 		case PRINT_ALIGNED:
 		case PRINT_WRAPPED:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_aligned_vertical(cont, fout);
 			else
 				print_aligned_text(cont, fout);
 			break;
 		case PRINT_HTML:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_html_vertical(cont, fout);
 			else
 				print_html_text(cont, fout);
 			break;
 		case PRINT_LATEX:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_latex_vertical(cont, fout);
 			else
 				print_latex_text(cont, fout);
 			break;
 		case PRINT_TROFF_MS:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_troff_ms_vertical(cont, fout);
 			else
 				print_troff_ms_text(cont, fout);
diff --git i/src/bin/psql/print.h w/src/bin/psql/print.h
index 1f54075..b79a73b 100644
--- i/src/bin/psql/print.h
+++ w/src/bin/psql/print.h
@@ -70,8 +70,8 @@ typedef struct printTextFormat
 typedef struct printTableOpt
 {
 	enum printFormat format;	/* see enum above */
-	bool		expanded;		/* expanded/vertical output (if supported by
-								 * output format) */
+	unsigned short int expanded;/* expanded/vertical output (if supported by
+								 * output format); 0=no, 1=yes, 2=auto */
 	unsigned short int border;	/* Print a border around the table. 0=none,
 								 * 1=dividing lines, 2=full */
 	unsigned short int pager;	/* use pager for output (if to stdout and
#2Chris Browne
cbbrowne@acm.org
In reply to: Peter Eisentraut (#1)
Re: psql expanded auto

peter_e@gmx.net (Peter Eisentraut) writes:

I have often found myself wanting that psql automatically switch between
normal and \x mode depending on the width of the output. Would others
find this useful?

I haven't tested the patch, but that *does* sound generally useful.
It's no fun trying to get one's eyes to visually line up output that
spans 3 lines...
--
select 'cbbrowne' || '@' || 'gmail.com';
http://linuxdatabases.info/info/nonrdbms.html
"Very little is known about the War of 1812 because the Americans lost
it." -- Eric Nicol

#3Itagaki Takahiro
itagaki.takahiro@gmail.com
In reply to: Peter Eisentraut (#1)
Re: psql expanded auto

On Sat, Dec 18, 2010 at 07:12, Peter Eisentraut <peter_e@gmx.net> wrote:

I have often found myself wanting that psql automatically switch between
normal and \x mode depending on the width of the output.  Would others
find this useful?

+1

Attached is a crude demo patch.  Enable with \pset expanded auto.

How about adding not only "auto" but also "on" and "off" as arguments
for \x? If not specified, the default behavior will be still "toggle".

--
Itagaki Takahiro

#4Bruce Momjian
bruce@momjian.us
In reply to: Peter Eisentraut (#1)
Re: psql expanded auto

Peter Eisentraut wrote:

I have often found myself wanting that psql automatically switch between
normal and \x mode depending on the width of the output. Would others
find this useful?

Attached is a crude demo patch. Enable with \pset expanded auto.

It is a TODO:

Add auto-expanded mode so expanded output is used if the row length is
wider than the screen width.

Consider using auto-expanded mode for backslash commands like \df+.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +

#5Bruce Momjian
bruce@momjian.us
In reply to: Peter Eisentraut (#1)
Re: psql expanded auto

I have added a link to this on the TODO list:

Add "auto" expanded mode that outputs in expanded format if "wrapped"
mode can't wrap the output to the screen width

* Re: psql wrapped format default for backslash-d commands
* http://archives.postgresql.org/pgsql-hackers/2010-12/msg01638.php

---------------------------------------------------------------------------

Peter Eisentraut wrote:

I have often found myself wanting that psql automatically switch between
normal and \x mode depending on the width of the output. Would others
find this useful?

Attached is a crude demo patch. Enable with \pset expanded auto.

[ Attachment, skipping... ]

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +

#6Peter Eisentraut
peter_e@gmx.net
In reply to: Peter Eisentraut (#1)
1 attachment(s)
Re: psql expanded auto

I wrote:

I have often found myself wanting that psql automatically switch between
normal and \x mode depending on the width of the output. Would others
find this useful?

Attached is a crude demo patch. Enable with \pset expanded auto.

Here is a finalized patch for this. The first hunk of the patch is the
documentation change, so you can see there how it's supposed to work.
Let me know what you think.

Attachments:

psql-expanded-auto.patchtext/x-patch; charset=UTF-8; name=psql-expanded-auto.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index d6941e0..e0f5ef4 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1876,15 +1876,19 @@ lo_import 152801
           <term><literal>expanded</literal> (or <literal>x</literal>)</term>
           <listitem>
           <para>
-          If <replaceable class="parameter">value</replaceable> is specified
-          it must be either <literal>on</literal> or <literal>off</literal>
-          which will enable or disable expanded mode.  If <replaceable
-          class="parameter">value</replaceable> is omitted the command toggles
-          between regular and expanded mode.
-          When expanded mode is enabled, query results
-          are displayed in two columns, with the column name on the left and
-          the data on the right. This mode is useful if the data wouldn't fit
-          on the screen in the normal <quote>horizontal</quote> mode.
+          If <replaceable class="parameter">value</replaceable> is specified it
+          must be either <literal>on</literal> or <literal>off</literal>, which
+          will enable or disable expanded mode, or <literal>auto</literal>.
+          If <replaceable class="parameter">value</replaceable> is omitted the
+          command toggles between the on and off settings.  When expanded mode
+          is enabled, query results are displayed in two columns, with the
+          column name on the left and the data on the right. This mode is
+          useful if the data wouldn't fit on the screen in the
+          normal <quote>horizontal</quote> mode.  In the auto setting, the
+          expanded mode is used whenever the query output is wider than the
+          screen, otherwise the regular mode is used.  The auto setting is only
+          effective in the aligned and wrapped formats.  In other formats, it
+          always behaves as if the expanded mode is off.
           </para>
           </listitem>
           </varlistentry>
@@ -2326,10 +2330,10 @@ lo_import 152801
 
 
       <varlistentry>
-        <term><literal>\x</literal></term>
+        <term><literal>\x [ <replaceable class="parameter">on</replaceable> | <replaceable class="parameter">off</replaceable> | <replaceable class="parameter">auto</replaceable> ]</literal></term>
         <listitem>
         <para>
-        Toggles expanded table formatting mode. As such it is equivalent to
+        Sets or toggles expanded table formatting mode. As such it is equivalent to
         <literal>\pset expanded</literal>.
        </para>
        </listitem>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 2c38902..5edeeb1 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -1343,7 +1343,7 @@ exec_command(const char *cmd,
 		free(fname);
 	}
 
-	/* \x -- toggle expanded table representation */
+	/* \x -- set or toggle expanded table representation */
 	else if (strcmp(cmd, "x") == 0)
 	{
 		char	   *opt = psql_scan_slash_option(scan_state,
@@ -2177,14 +2177,21 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 	/* set expanded/vertical mode */
 	else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
 	{
-		if (value)
+		if (value && pg_strcasecmp(value, "auto") == 0)
+			popt->topt.expanded = 2;
+		else if (value)
 			popt->topt.expanded = ParseVariableBool(value);
 		else
 			popt->topt.expanded = !popt->topt.expanded;
 		if (!quiet)
-			printf(popt->topt.expanded
-				   ? _("Expanded display is on.\n")
-				   : _("Expanded display is off.\n"));
+		{
+			if (popt->topt.expanded == 1)
+				printf(_("Expanded display is on.\n"));
+			else if (popt->topt.expanded == 2)
+				printf(_("Expanded display is used automatically.\n"));
+			else
+				printf(_("Expanded display is off.\n"));
+		}
 	}
 
 	/* locale-aware numeric output */
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index 0d18665..c693040 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -122,9 +122,11 @@ const printTextFormat pg_utf8format =
 
 /* 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,
+static void IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded,
 			  FILE **fout, bool *is_pager);
 
+static void print_aligned_vertical(const printTableContent *cont, FILE *fout);
+
 
 static void *
 pg_local_malloc(size_t size)
@@ -713,6 +715,17 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 		}
 	}
 
+	/*
+	 * If in expanded auto mode, we have now calculated the expected width, so
+	 * we can now escape to vertical mode if necessary.
+	 */
+	if (cont->opt->expanded == 2 &&
+		(output_columns < total_header_width || output_columns < width_total))
+	{
+		print_aligned_vertical(cont, fout);
+		return;
+	}
+
 	/* If we wrapped beyond the display width, use the pager */
 	if (!is_pager && fout == stdout && output_columns > 0 &&
 		(output_columns < total_header_width || output_columns < width_total))
@@ -756,7 +769,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 				extra_row_output_lines = 0;
 			}
 		}
-		IsPagerNeeded(cont, extra_output_lines, &fout, &is_pager);
+		IsPagerNeeded(cont, extra_output_lines, false, &fout, &is_pager);
 	}
 
 	/* time to output */
@@ -1125,6 +1138,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 				dformatsize = 0;
 	struct lineptr *hlineptr,
 			   *dlineptr;
+	bool		is_pager = false;
 
 	if (cancel_pressed)
 		return;
@@ -1139,6 +1153,13 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 		return;
 	}
 
+	/*
+	 * Deal with the pager here instead of in printTable(), because we could
+	 * get here via print_aligned_text() in expanded auto mode, and so we have
+	 * to recalcuate the pager requirement based on vertical output.
+	 */
+	IsPagerNeeded(cont, 0, true, &fout, &is_pager);
+
 	/* Find the maximum dimensions for the headers */
 	for (i = 0; i < cont->ncolumns; i++)
 	{
@@ -1295,6 +1316,9 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 	free(dlineptr->ptr);
 	free(hlineptr);
 	free(dlineptr);
+
+	if (is_pager)
+		ClosePager(fout);
 }
 
 
@@ -2265,14 +2289,14 @@ printTableCleanup(printTableContent *const content)
  * Setup pager if required
  */
 static void
-IsPagerNeeded(const printTableContent *cont, const int extra_lines, FILE **fout,
+IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded, FILE **fout,
 			  bool *is_pager)
 {
 	if (*fout == stdout)
 	{
 		int			lines;
 
-		if (cont->opt->expanded)
+		if (expanded)
 			lines = (cont->ncolumns + 1) * cont->nrows;
 		else
 			lines = cont->nrows + 1;
@@ -2310,11 +2334,10 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 	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_aligned_*() handles the pager themselves */
+	if (cont->opt->format != PRINT_ALIGNED &&
+		cont->opt->format != PRINT_WRAPPED)
+		IsPagerNeeded(cont, 0, (cont->opt->expanded == 1), &fout, &is_pager);
 
 	/* print the stuff */
 
@@ -2324,32 +2347,32 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 	switch (cont->opt->format)
 	{
 		case PRINT_UNALIGNED:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_unaligned_vertical(cont, fout);
 			else
 				print_unaligned_text(cont, fout);
 			break;
 		case PRINT_ALIGNED:
 		case PRINT_WRAPPED:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_aligned_vertical(cont, fout);
 			else
 				print_aligned_text(cont, fout);
 			break;
 		case PRINT_HTML:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_html_vertical(cont, fout);
 			else
 				print_html_text(cont, fout);
 			break;
 		case PRINT_LATEX:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_latex_vertical(cont, fout);
 			else
 				print_latex_text(cont, fout);
 			break;
 		case PRINT_TROFF_MS:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_troff_ms_vertical(cont, fout);
 			else
 				print_troff_ms_text(cont, fout);
diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h
index 35bb4cd..bb20613 100644
--- a/src/bin/psql/print.h
+++ b/src/bin/psql/print.h
@@ -70,8 +70,8 @@ typedef struct printTextFormat
 typedef struct printTableOpt
 {
 	enum printFormat format;	/* see enum above */
-	bool		expanded;		/* expanded/vertical output (if supported by
-								 * output format) */
+	unsigned short int expanded;/* expanded/vertical output (if supported by
+								 * output format); 0=no, 1=yes, 2=auto */
 	unsigned short int border;	/* Print a border around the table. 0=none,
 								 * 1=dividing lines, 2=full */
 	unsigned short int pager;	/* use pager for output (if to stdout and
#7Jan Lentfer
Jan.Lentfer@web.de
In reply to: Peter Eisentraut (#6)
Re: psql expanded auto

I have not tried the patch (yet), but Informix'sl dbacess would do about
the same - and it's something I really missed.

Jan
--
Diese Nachricht wurde von meinem Android-Mobiltelefon mit K-9 Mail gesendet.

#8Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Peter Eisentraut (#6)
Re: psql expanded auto

Peter Eisentraut <peter_e@gmx.net> writes:

Here is a finalized patch for this. The first hunk of the patch is the
documentation change, so you can see there how it's supposed to work.
Let me know what you think.

+1

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#9Noah Misch
noah@leadboat.com
In reply to: Peter Eisentraut (#6)
Re: psql expanded auto

On Tue, Nov 01, 2011 at 06:22:47AM +0200, Peter Eisentraut wrote:

I wrote:

I have often found myself wanting that psql automatically switch between
normal and \x mode depending on the width of the output. Would others
find this useful?

Attached is a crude demo patch. Enable with \pset expanded auto.

Here is a finalized patch for this. The first hunk of the patch is the
documentation change, so you can see there how it's supposed to work.
Let me know what you think.

+1. I'm anticipating liking this enough to put it in ".psqlrc".

Perhaps this message should change to just "Target width is 120.", since it now
applies to more than just the wrapped format:

[local] test=# \pset columns 120
Target width for "wrapped" format is 120.

Similarly, psql documentation for "\pset columns" and the COLUMNS environment
variable should note expanded auto in addition to the wrapped format.

For "\pset format wrapped", we only use $COLUMNS when the output is a tty. I'm
thinking it's best, although not terribly important, to apply the same rule to
this feature.

Thanks,
nm

#10Peter Geoghegan
peter@2ndquadrant.com
In reply to: Peter Eisentraut (#1)
Re: psql expanded auto

On 17 December 2010 22:12, Peter Eisentraut <peter_e@gmx.net> wrote:

I have often found myself wanting that psql automatically switch between
normal and \x mode depending on the width of the output.  Would others
find this useful?

+1

Sounds like a very good idea.

--
Peter Geoghegan       http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training and Services

#11Peter Eisentraut
peter_e@gmx.net
In reply to: Noah Misch (#9)
Re: psql expanded auto

On fre, 2011-11-04 at 07:34 -0400, Noah Misch wrote:

For "\pset format wrapped", we only use $COLUMNS when the output is a
tty. I'm thinking it's best, although not terribly important, to
apply the same rule to this feature.

I think it does work that way. There is only one place where the
environment variable is queries, and it's used for both wrapped format
and expanded auto format.

#12Noah Misch
noah@leadboat.com
In reply to: Peter Eisentraut (#11)
Re: psql expanded auto

On Sat, Nov 05, 2011 at 04:53:56PM +0200, Peter Eisentraut wrote:

On fre, 2011-11-04 at 07:34 -0400, Noah Misch wrote:

For "\pset format wrapped", we only use $COLUMNS when the output is a
tty. I'm thinking it's best, although not terribly important, to
apply the same rule to this feature.

I think it does work that way. There is only one place where the
environment variable is queries, and it's used for both wrapped format
and expanded auto format.

You're correct; given output to a non-tty and no use of \pset columns,
output_columns always becomes zero. This makes wrapped format never wrap, but
it makes expanded auto mode always expand. Would it be more consistent to never
expand when output_columns == 0? That is, make these give the same output:

psql -X -P expanded=auto -c "select 'a' as a"
psql -X -P expanded=auto -c "select 'a' as a" | cat

I just noticed: the help text for \x in slashUsage() will also need an update.

#13Peter Eisentraut
peter_e@gmx.net
In reply to: Noah Misch (#12)
1 attachment(s)
Re: psql expanded auto

On lör, 2011-11-05 at 12:26 -0400, Noah Misch wrote:

On Sat, Nov 05, 2011 at 04:53:56PM +0200, Peter Eisentraut wrote:

On fre, 2011-11-04 at 07:34 -0400, Noah Misch wrote:

For "\pset format wrapped", we only use $COLUMNS when the output is a
tty. I'm thinking it's best, although not terribly important, to
apply the same rule to this feature.

I think it does work that way. There is only one place where the
environment variable is queries, and it's used for both wrapped format
and expanded auto format.

You're correct; given output to a non-tty and no use of \pset columns,
output_columns always becomes zero. This makes wrapped format never wrap, but
it makes expanded auto mode always expand. Would it be more consistent to never
expand when output_columns == 0? That is, make these give the same output:

psql -X -P expanded=auto -c "select 'a' as a"
psql -X -P expanded=auto -c "select 'a' as a" | cat

I just noticed: the help text for \x in slashUsage() will also need an update.

Here is an updated patch that addresses all the issues you pointed out.

Attachments:

psql-expanded-auto-v2.patchtext/x-patch; charset=UTF-8; name=psql-expanded-auto-v2.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index d6941e0..01f57c4 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1860,7 +1860,8 @@ lo_import 152801
           <para>
           Sets the target width for the <literal>wrapped</> format, and also
           the width limit for determining whether output is wide enough to
-          require the pager.
+          require the pager or switch to the vertical display in expanded auto
+          mode.
           Zero (the default) causes the target width to be controlled by the
           environment variable <envar>COLUMNS</>, or the detected screen width
           if <envar>COLUMNS</> is not set.
@@ -1876,15 +1877,19 @@ lo_import 152801
           <term><literal>expanded</literal> (or <literal>x</literal>)</term>
           <listitem>
           <para>
-          If <replaceable class="parameter">value</replaceable> is specified
-          it must be either <literal>on</literal> or <literal>off</literal>
-          which will enable or disable expanded mode.  If <replaceable
-          class="parameter">value</replaceable> is omitted the command toggles
-          between regular and expanded mode.
-          When expanded mode is enabled, query results
-          are displayed in two columns, with the column name on the left and
-          the data on the right. This mode is useful if the data wouldn't fit
-          on the screen in the normal <quote>horizontal</quote> mode.
+          If <replaceable class="parameter">value</replaceable> is specified it
+          must be either <literal>on</literal> or <literal>off</literal>, which
+          will enable or disable expanded mode, or <literal>auto</literal>.
+          If <replaceable class="parameter">value</replaceable> is omitted the
+          command toggles between the on and off settings.  When expanded mode
+          is enabled, query results are displayed in two columns, with the
+          column name on the left and the data on the right. This mode is
+          useful if the data wouldn't fit on the screen in the
+          normal <quote>horizontal</quote> mode.  In the auto setting, the
+          expanded mode is used whenever the query output is wider than the
+          screen, otherwise the regular mode is used.  The auto setting is only
+          effective in the aligned and wrapped formats.  In other formats, it
+          always behaves as if the expanded mode is off.
           </para>
           </listitem>
           </varlistentry>
@@ -2326,10 +2331,10 @@ lo_import 152801
 
 
       <varlistentry>
-        <term><literal>\x</literal></term>
+        <term><literal>\x [ <replaceable class="parameter">on</replaceable> | <replaceable class="parameter">off</replaceable> | <replaceable class="parameter">auto</replaceable> ]</literal></term>
         <listitem>
         <para>
-        Toggles expanded table formatting mode. As such it is equivalent to
+        Sets or toggles expanded table formatting mode. As such it is equivalent to
         <literal>\pset expanded</literal>.
        </para>
        </listitem>
@@ -3197,7 +3202,8 @@ $endif
      <para>
       If <literal>\pset columns</> is zero, controls the
       width for the <literal>wrapped</> format and width for determining
-      if wide output requires the pager.
+      if wide output requires the pager or should be switched to the
+      vertical format in expanded auto mode.
      </para>
     </listitem>
    </varlistentry>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 2c38902..daaed66 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -1343,7 +1343,7 @@ exec_command(const char *cmd,
 		free(fname);
 	}
 
-	/* \x -- toggle expanded table representation */
+	/* \x -- set or toggle expanded table representation */
 	else if (strcmp(cmd, "x") == 0)
 	{
 		char	   *opt = psql_scan_slash_option(scan_state,
@@ -2177,14 +2177,21 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 	/* set expanded/vertical mode */
 	else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
 	{
-		if (value)
+		if (value && pg_strcasecmp(value, "auto") == 0)
+			popt->topt.expanded = 2;
+		else if (value)
 			popt->topt.expanded = ParseVariableBool(value);
 		else
 			popt->topt.expanded = !popt->topt.expanded;
 		if (!quiet)
-			printf(popt->topt.expanded
-				   ? _("Expanded display is on.\n")
-				   : _("Expanded display is off.\n"));
+		{
+			if (popt->topt.expanded == 1)
+				printf(_("Expanded display is on.\n"));
+			else if (popt->topt.expanded == 2)
+				printf(_("Expanded display is used automatically.\n"));
+			else
+				printf(_("Expanded display is off.\n"));
+		}
 	}
 
 	/* locale-aware numeric output */
@@ -2344,7 +2351,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 			popt->topt.columns = atoi(value);
 
 		if (!quiet)
-			printf(_("Target width for \"wrapped\" format is %d.\n"), popt->topt.columns);
+			printf(_("Target width is %d.\n"), popt->topt.columns);
 	}
 
 	else
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 53e4cd0..4649e94 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -242,8 +242,8 @@ slashUsage(unsigned short int pager)
 	fprintf(output, _("  \\t [on|off]            show only rows (currently %s)\n"),
 			ON(pset.popt.topt.tuples_only));
 	fprintf(output, _("  \\T [STRING]            set HTML <table> tag attributes, or unset if none\n"));
-	fprintf(output, _("  \\x [on|off]            toggle expanded output (currently %s)\n"),
-			ON(pset.popt.topt.expanded));
+	fprintf(output, _("  \\x [on|off|auto]       toggle expanded output (currently %s)\n"),
+			pset.popt.topt.expanded == 2 ? "auto" : ON(pset.popt.topt.expanded));
 	fprintf(output, "\n");
 
 	fprintf(output, _("Connection\n"));
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index 0d18665..b19159d 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -122,9 +122,11 @@ const printTextFormat pg_utf8format =
 
 /* 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,
+static void IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded,
 			  FILE **fout, bool *is_pager);
 
+static void print_aligned_vertical(const printTableContent *cont, FILE *fout);
+
 
 static void *
 pg_local_malloc(size_t size)
@@ -713,6 +715,17 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 		}
 	}
 
+	/*
+	 * If in expanded auto mode, we have now calculated the expected width, so
+	 * we can now escape to vertical mode if necessary.
+	 */
+	if (cont->opt->expanded == 2 && output_columns > 0 &&
+		(output_columns < total_header_width || output_columns < width_total))
+	{
+		print_aligned_vertical(cont, fout);
+		return;
+	}
+
 	/* If we wrapped beyond the display width, use the pager */
 	if (!is_pager && fout == stdout && output_columns > 0 &&
 		(output_columns < total_header_width || output_columns < width_total))
@@ -756,7 +769,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 				extra_row_output_lines = 0;
 			}
 		}
-		IsPagerNeeded(cont, extra_output_lines, &fout, &is_pager);
+		IsPagerNeeded(cont, extra_output_lines, false, &fout, &is_pager);
 	}
 
 	/* time to output */
@@ -1125,6 +1138,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 				dformatsize = 0;
 	struct lineptr *hlineptr,
 			   *dlineptr;
+	bool		is_pager = false;
 
 	if (cancel_pressed)
 		return;
@@ -1139,6 +1153,13 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 		return;
 	}
 
+	/*
+	 * Deal with the pager here instead of in printTable(), because we could
+	 * get here via print_aligned_text() in expanded auto mode, and so we have
+	 * to recalcuate the pager requirement based on vertical output.
+	 */
+	IsPagerNeeded(cont, 0, true, &fout, &is_pager);
+
 	/* Find the maximum dimensions for the headers */
 	for (i = 0; i < cont->ncolumns; i++)
 	{
@@ -1295,6 +1316,9 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 	free(dlineptr->ptr);
 	free(hlineptr);
 	free(dlineptr);
+
+	if (is_pager)
+		ClosePager(fout);
 }
 
 
@@ -2265,14 +2289,14 @@ printTableCleanup(printTableContent *const content)
  * Setup pager if required
  */
 static void
-IsPagerNeeded(const printTableContent *cont, const int extra_lines, FILE **fout,
+IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded, FILE **fout,
 			  bool *is_pager)
 {
 	if (*fout == stdout)
 	{
 		int			lines;
 
-		if (cont->opt->expanded)
+		if (expanded)
 			lines = (cont->ncolumns + 1) * cont->nrows;
 		else
 			lines = cont->nrows + 1;
@@ -2310,11 +2334,10 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 	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_aligned_*() handles the pager themselves */
+	if (cont->opt->format != PRINT_ALIGNED &&
+		cont->opt->format != PRINT_WRAPPED)
+		IsPagerNeeded(cont, 0, (cont->opt->expanded == 1), &fout, &is_pager);
 
 	/* print the stuff */
 
@@ -2324,32 +2347,32 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 	switch (cont->opt->format)
 	{
 		case PRINT_UNALIGNED:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_unaligned_vertical(cont, fout);
 			else
 				print_unaligned_text(cont, fout);
 			break;
 		case PRINT_ALIGNED:
 		case PRINT_WRAPPED:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_aligned_vertical(cont, fout);
 			else
 				print_aligned_text(cont, fout);
 			break;
 		case PRINT_HTML:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_html_vertical(cont, fout);
 			else
 				print_html_text(cont, fout);
 			break;
 		case PRINT_LATEX:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_latex_vertical(cont, fout);
 			else
 				print_latex_text(cont, fout);
 			break;
 		case PRINT_TROFF_MS:
-			if (cont->opt->expanded)
+			if (cont->opt->expanded == 1)
 				print_troff_ms_vertical(cont, fout);
 			else
 				print_troff_ms_text(cont, fout);
diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h
index 35bb4cd..bb20613 100644
--- a/src/bin/psql/print.h
+++ b/src/bin/psql/print.h
@@ -70,8 +70,8 @@ typedef struct printTextFormat
 typedef struct printTableOpt
 {
 	enum printFormat format;	/* see enum above */
-	bool		expanded;		/* expanded/vertical output (if supported by
-								 * output format) */
+	unsigned short int expanded;/* expanded/vertical output (if supported by
+								 * output format); 0=no, 1=yes, 2=auto */
 	unsigned short int border;	/* Print a border around the table. 0=none,
 								 * 1=dividing lines, 2=full */
 	unsigned short int pager;	/* use pager for output (if to stdout and
#14Noah Misch
noah@leadboat.com
In reply to: Peter Eisentraut (#13)
Re: psql expanded auto

On Tue, Nov 08, 2011 at 06:36:52AM +0200, Peter Eisentraut wrote:

Here is an updated patch that addresses all the issues you pointed out.

Looks ready to me. Thanks.