psql: Add \gx command

It can often be useful to use expanded mode output (\x) for just a
single query.  Introduce a \gx which acts exactly like \g except that it
will force expanded output mode for that one \gx call.  This is simpler
than having to use \x as a toggle and also means that the user doesn't
have to worry about the current state of the expanded variable, or
resetting it later, to ensure a given query is always returned in
expanded mode.

Primairly Christoph's patch, though I did tweak the documentation and help
text a bit, and re-indented the tab completion section.

Author: Christoph Berg
Reviewed By: Daniel Verite
Discussion: https://postgr.es/m/20170127132737.6skslelaf4txs6iw%40msg.credativ.de
This commit is contained in:
Stephen Frost 2017-03-07 09:31:52 -05:00
parent 9a83d56b38
commit b2678efd43
8 changed files with 64 additions and 7 deletions

View File

@ -1890,6 +1890,18 @@ Tue Oct 26 21:40:57 CEST 1999
</varlistentry>
<varlistentry>
<term><literal>\gx [ <replaceable class="parameter">filename</replaceable> ]</literal></term>
<term><literal>\gx [ |<replaceable class="parameter">command</replaceable> ]</literal></term>
<listitem>
<para>
<literal>\gx</literal> is equivalent to <literal>\g</literal>, but
forces expanded output mode for this query. See <literal>\x</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>\gexec</literal></term>

View File

@ -906,8 +906,11 @@ exec_command(const char *cmd,
free(fname);
}
/* \g [filename] -- send query, optionally with output to file/pipe */
else if (strcmp(cmd, "g") == 0)
/*
* \g [filename] -- send query, optionally with output to file/pipe
* \gx [filename] -- same as \g, with expanded mode forced
*/
else if (strcmp(cmd, "g") == 0 || strcmp(cmd, "gx") == 0)
{
char *fname = psql_scan_slash_option(scan_state,
OT_FILEPIPE, NULL, false);
@ -920,6 +923,8 @@ exec_command(const char *cmd,
pset.gfname = pg_strdup(fname);
}
free(fname);
if (strcmp(cmd, "gx") == 0)
pset.g_expanded = true;
status = PSQL_CMD_SEND;
}

View File

@ -770,6 +770,10 @@ PrintQueryTuples(const PGresult *results)
{
printQueryOpt my_popt = pset.popt;
/* one-shot expanded output requested via \gx */
if (pset.g_expanded)
my_popt.topt.expanded = 1;
/* write output to \g argument, if any */
if (pset.gfname)
{
@ -1410,6 +1414,9 @@ sendquery_cleanup:
pset.gfname = NULL;
}
/* reset \gx's expanded-mode flag */
pset.g_expanded = false;
/* reset \gset trigger */
if (pset.gset_prefix)
{

View File

@ -173,6 +173,7 @@ slashUsage(unsigned short int pager)
fprintf(output, _(" \\copyright show PostgreSQL usage and distribution terms\n"));
fprintf(output, _(" \\errverbose show most recent error message at maximum verbosity\n"));
fprintf(output, _(" \\g [FILE] or ; execute query (and send results to file or |pipe)\n"));
fprintf(output, _(" \\gx [FILE] as \\g, but forces expanded output mode\n"));
fprintf(output, _(" \\gexec execute query, then execute each value in its result\n"));
fprintf(output, _(" \\gset [PREFIX] execute query and store results in psql variables\n"));
fprintf(output, _(" \\q quit psql\n"));

View File

@ -91,6 +91,7 @@ typedef struct _psqlSettings
printQueryOpt popt;
char *gfname; /* one-shot file output argument for \g */
bool g_expanded; /* one-shot expanded output requested via \gx */
char *gset_prefix; /* one-shot prefix argument for \gset */
bool gexec_flag; /* one-shot flag to execute query's results */
bool crosstab_flag; /* one-shot request to crosstab results */

View File

@ -1375,11 +1375,12 @@ psql_completion(const char *text, int start, int end)
"\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\drds", "\\ds", "\\dS",
"\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dy",
"\\e", "\\echo", "\\ef", "\\encoding", "\\errverbose", "\\ev",
"\\f", "\\g", "\\gexec", "\\gset", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l",
"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
"\\s", "\\set", "\\setenv", "\\sf", "\\sv", "\\t", "\\T",
"\\timing", "\\unset", "\\x", "\\w", "\\watch", "\\z", "\\!", NULL
"\\f", "\\g", "\\gexec", "\\gset", "\\gx", "\\h", "\\help", "\\H",
"\\i", "\\ir", "\\l", "\\lo_import", "\\lo_export", "\\lo_list",
"\\lo_unlink", "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q",
"\\qecho", "\\r", "\\s", "\\set", "\\setenv", "\\sf", "\\sv", "\\t",
"\\T", "\\timing", "\\unset", "\\x", "\\w", "\\watch", "\\z", "\\!",
NULL
};
(void) end; /* "end" is not used */

View File

@ -28,6 +28,29 @@ on
\unset ON_ERROR_ROLLBACK
\echo :ON_ERROR_ROLLBACK
off
-- \g and \gx
SELECT 1 as one, 2 as two \g
one | two
-----+-----
1 | 2
(1 row)
\gx
-[ RECORD 1 ]
one | 1
two | 2
SELECT 3 as three, 4 as four \gx
-[ RECORD 1 ]
three | 3
four | 4
\g
three | four
-------+------
3 | 4
(1 row)
-- \gset
select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_
\echo :pref01_test01 :pref01_test02 :pref01_test03

View File

@ -21,6 +21,13 @@
\unset ON_ERROR_ROLLBACK
\echo :ON_ERROR_ROLLBACK
-- \g and \gx
SELECT 1 as one, 2 as two \g
\gx
SELECT 3 as three, 4 as four \gx
\g
-- \gset
select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_