Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b0d8f2d

Browse filesBrowse files
committed
Add SHELL_ERROR and SHELL_EXIT_CODE magic variables to psql.
These are set after a \! command or a backtick substitution. SHELL_ERROR is just "true" for error (nonzero exit status) or "false" for success, while SHELL_EXIT_CODE records the actual exit status following standard shell/system(3) conventions. Corey Huinker, reviewed by Maxim Orlov and myself Discussion: https://postgr.es/m/CADkLM=cWao2x2f+UDw15W1JkVFr_bsxfstw=NGea7r9m4j-7rQ@mail.gmail.com
1 parent 0f85db9 commit b0d8f2d
Copy full SHA for b0d8f2d

File tree

6 files changed

+88
-3
lines changed
Filter options

6 files changed

+88
-3
lines changed

‎doc/src/sgml/ref/psql-ref.sgml

Copy file name to clipboardExpand all lines: doc/src/sgml/ref/psql-ref.sgml
+28Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4267,6 +4267,34 @@ bar
42674267
</listitem>
42684268
</varlistentry>
42694269

4270+
<varlistentry id="app-psql-variables-shell-error">
4271+
<term><varname>SHELL_ERROR</varname></term>
4272+
<listitem>
4273+
<para>
4274+
<literal>true</literal> if the last shell command
4275+
failed, <literal>false</literal> if it succeeded.
4276+
This applies to shell commands invoked via the <literal>\!</literal>
4277+
meta-command or backquote (<literal>`</literal>) expansion.
4278+
See also <varname>SHELL_EXIT_CODE</varname>.
4279+
</para>
4280+
</listitem>
4281+
</varlistentry>
4282+
4283+
<varlistentry id="app-psql-variables-shell-exit-code">
4284+
<term><varname>SHELL_EXIT_CODE</varname></term>
4285+
<listitem>
4286+
<para>
4287+
The exit status returned by the last shell command.
4288+
0&ndash;127 represent program exit codes, 128&ndash;255
4289+
indicate termination by a signal, and -1 indicates failure
4290+
to launch a program or to collect its exit status.
4291+
This applies to shell commands invoked via the <literal>\!</literal>
4292+
meta-command or backquote (<literal>`</literal>) expansion.
4293+
See also <varname>SHELL_ERROR</varname>.
4294+
</para>
4295+
</listitem>
4296+
</varlistentry>
4297+
42704298
<varlistentry id="app-psql-variables-show-all-results">
42714299
<term><varname>SHOW_ALL_RESULTS</varname></term>
42724300
<listitem>

‎src/bin/psql/command.c

Copy file name to clipboardExpand all lines: src/bin/psql/command.c
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5041,6 +5041,21 @@ do_shell(const char *command)
50415041
else
50425042
result = system(command);
50435043

5044+
if (result == 0)
5045+
{
5046+
SetVariable(pset.vars, "SHELL_EXIT_CODE", "0");
5047+
SetVariable(pset.vars, "SHELL_ERROR", "false");
5048+
}
5049+
else
5050+
{
5051+
int exit_code = wait_result_to_exit_code(result);
5052+
char buf[32];
5053+
5054+
snprintf(buf, sizeof(buf), "%d", exit_code);
5055+
SetVariable(pset.vars, "SHELL_EXIT_CODE", buf);
5056+
SetVariable(pset.vars, "SHELL_ERROR", "true");
5057+
}
5058+
50445059
if (result == 127 || result == -1)
50455060
{
50465061
pg_log_error("\\!: failed");

‎src/bin/psql/help.c

Copy file name to clipboardExpand all lines: src/bin/psql/help.c
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,10 @@ helpVariables(unsigned short int pager)
451451
HELP0(" SERVER_VERSION_NAME\n"
452452
" SERVER_VERSION_NUM\n"
453453
" server's version (in short string or numeric format)\n");
454+
HELP0(" SHELL_ERROR\n"
455+
" true if the last shell command failed, false if it succeeded\n");
456+
HELP0(" SHELL_EXIT_CODE\n"
457+
" exit status of the last shell command\n");
454458
HELP0(" SHOW_ALL_RESULTS\n"
455459
" show all results of a combined query (\\;) instead of only the last\n");
456460
HELP0(" SHOW_CONTEXT\n"

‎src/bin/psql/psqlscanslash.l

Copy file name to clipboardExpand all lines: src/bin/psql/psqlscanslash.l
+21-3Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "postgres_fe.h"
2020

2121
#include "psqlscanslash.h"
22+
#include "settings.h"
23+
2224
#include "common/logging.h"
2325
#include "fe_utils/conditional.h"
2426

@@ -772,6 +774,7 @@ evaluate_backtick(PsqlScanState state)
772774
PQExpBufferData cmd_output;
773775
FILE *fd;
774776
bool error = false;
777+
int exit_code = 0;
775778
char buf[512];
776779
size_t result;
777780

@@ -783,6 +786,7 @@ evaluate_backtick(PsqlScanState state)
783786
{
784787
pg_log_error("%s: %m", cmd);
785788
error = true;
789+
exit_code = -1;
786790
}
787791

788792
if (!error)
@@ -800,10 +804,19 @@ evaluate_backtick(PsqlScanState state)
800804
} while (!feof(fd));
801805
}
802806

803-
if (fd && pclose(fd) == -1)
807+
if (fd)
804808
{
805-
pg_log_error("%s: %m", cmd);
806-
error = true;
809+
/*
810+
* Although pclose's result always sets SHELL_EXIT_CODE, we
811+
* historically have abandoned the backtick substitution only if it
812+
* returns -1.
813+
*/
814+
exit_code = pclose(fd);
815+
if (exit_code == -1)
816+
{
817+
pg_log_error("%s: %m", cmd);
818+
error = true;
819+
}
807820
}
808821

809822
if (PQExpBufferDataBroken(cmd_output))
@@ -826,5 +839,10 @@ evaluate_backtick(PsqlScanState state)
826839
appendBinaryPQExpBuffer(output_buf, cmd_output.data, cmd_output.len);
827840
}
828841

842+
/* And finally, set the shell error variables */
843+
snprintf(buf, sizeof(buf), "%d", wait_result_to_exit_code(exit_code));
844+
SetVariable(pset.vars, "SHELL_EXIT_CODE", buf);
845+
SetVariable(pset.vars, "SHELL_ERROR", (exit_code == 0) ? "false" : "true");
846+
829847
termPQExpBuffer(&cmd_output);
830848
}

‎src/common/wait_error.c

Copy file name to clipboardExpand all lines: src/common/wait_error.c
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,22 @@ wait_result_is_any_signal(int exit_status, bool include_command_not_found)
127127
return true;
128128
return false;
129129
}
130+
131+
/*
132+
* Return the shell exit code (normally 0 to 255) that corresponds to the
133+
* given wait status. The argument is a wait status as returned by wait(2)
134+
* or waitpid(2), which also applies to pclose(3) and system(3). To support
135+
* the latter two cases, we pass through "-1" unchanged.
136+
*/
137+
int
138+
wait_result_to_exit_code(int exit_status)
139+
{
140+
if (exit_status == -1)
141+
return -1; /* failure of pclose() or system() */
142+
if (WIFEXITED(exit_status))
143+
return WEXITSTATUS(exit_status);
144+
if (WIFSIGNALED(exit_status))
145+
return 128 + WTERMSIG(exit_status);
146+
/* On many systems, this is unreachable */
147+
return -1;
148+
}

‎src/include/port.h

Copy file name to clipboardExpand all lines: src/include/port.h
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@ extern char *escape_single_quotes_ascii(const char *src);
495495
extern char *wait_result_to_str(int exitstatus);
496496
extern bool wait_result_is_signal(int exit_status, int signum);
497497
extern bool wait_result_is_any_signal(int exit_status, bool include_command_not_found);
498+
extern int wait_result_to_exit_code(int exit_status);
498499

499500
/*
500501
* Interfaces that we assume all Unix system have. We retain individual macros

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.