diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index ae58708aaea..2a9c4120205 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1890,6 +1890,18 @@ Tue Oct 26 21:40:57 CEST 1999
+
+ \gx [ filename ]
+ \gx [ |command ]
+
+
+ \gx is equivalent to \g, but
+ forces expanded output mode for this query. See \x.
+
+
+
+
+
\gexec
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index a52adc8186f..07efc27a697 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -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;
}
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 5349c394115..1aa56ab3a2f 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -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)
{
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 91cf0be46a6..ba14df0344d 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -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"));
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index 195f5a11843..70ff1812c8f 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -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 */
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 4a65ff5b620..121a492e6d8 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -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 */
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 026a4f0c833..eb7f197b122 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -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
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index d823d11b958..8f8e17a87cd 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -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_