Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 101d6ae

Browse files
committed
Prevent "\g filename" from affecting subsequent commands after an error.
In the previous coding, psql's state variable saying that output should go to a file was only reset after successful completion of a query returning tuples. Thus for example, regression=# select 1/0 regression-# \g somefile ERROR: division by zero regression=# select 1/2; regression=# ... huh, I wonder where that output went. Even more oddly, the state was not reset even if it's the file that's causing the failure: regression=# select 1/2 \g /foo /foo: Permission denied regression=# select 1/2; /foo: Permission denied regression=# select 1/2; /foo: Permission denied This seems to me not to satisfy the principle of least surprise. \g is certainly not documented in a way that suggests its effects are at all persistent. To fix, adjust the code so that the flag is reset at exit from SendQuery no matter what happened. Noted while reviewing the \gset patch, which had comparable issues. Arguably this is a bug fix, but I'll refrain from back-patching for now.
1 parent 84725aa commit 101d6ae

File tree

3 files changed

+27
-17
lines changed

3 files changed

+27
-17
lines changed

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

+7-3
Original file line numberDiff line numberDiff line change
@@ -1608,9 +1608,13 @@ Tue Oct 26 21:40:57 CEST 1999
16081608
optionally stores the query's output in <replaceable
16091609
class="parameter">filename</replaceable> or pipes the output
16101610
into a separate Unix shell executing <replaceable
1611-
class="parameter">command</replaceable>. A bare
1612-
<literal>\g</literal> is virtually equivalent to a semicolon. A
1613-
<literal>\g</literal> with argument is a <quote>one-shot</quote>
1611+
class="parameter">command</replaceable>. The file or command is
1612+
written to only if the query successfully returns zero or more tuples,
1613+
not if the query fails or is a non-data-returning SQL command.
1614+
</para>
1615+
<para>
1616+
A bare <literal>\g</literal> is essentially equivalent to a semicolon.
1617+
A <literal>\g</literal> with argument is a <quote>one-shot</quote>
16141618
alternative to the <command>\o</command> command.
16151619
</para>
16161620
</listitem>

src/bin/psql/command.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ exec_command(const char *cmd,
731731
free(fname);
732732
}
733733

734-
/* \g means send query */
734+
/* \g [filename] means send query, optionally with output to file/pipe */
735735
else if (strcmp(cmd, "g") == 0)
736736
{
737737
char *fname = psql_scan_slash_option(scan_state,

src/bin/psql/common.c

+19-13
Original file line numberDiff line numberDiff line change
@@ -607,9 +607,6 @@ PrintQueryTuples(const PGresult *results)
607607

608608
pset.queryFout = queryFout_copy;
609609
pset.queryFoutPipe = queryFoutPipe_copy;
610-
611-
free(pset.gfname);
612-
pset.gfname = NULL;
613610
}
614611
else
615612
printQuery(results, &my_popt, pset.queryFout, pset.logfile);
@@ -835,14 +832,14 @@ SendQuery(const char *query)
835832
PGresult *results;
836833
PGTransactionStatusType transaction_status;
837834
double elapsed_msec = 0;
838-
bool OK,
839-
on_error_rollback_savepoint = false;
835+
bool OK = false;
836+
bool on_error_rollback_savepoint = false;
840837
static bool on_error_rollback_warning = false;
841838

842839
if (!pset.db)
843840
{
844841
psql_error("You are currently not connected to a database.\n");
845-
return false;
842+
goto sendquery_cleanup;
846843
}
847844

848845
if (pset.singlestep)
@@ -856,7 +853,7 @@ SendQuery(const char *query)
856853
fflush(stdout);
857854
if (fgets(buf, sizeof(buf), stdin) != NULL)
858855
if (buf[0] == 'x')
859-
return false;
856+
goto sendquery_cleanup;
860857
}
861858
else if (pset.echo == PSQL_ECHO_QUERIES)
862859
{
@@ -887,7 +884,7 @@ SendQuery(const char *query)
887884
psql_error("%s", PQerrorMessage(pset.db));
888885
PQclear(results);
889886
ResetCancelConn();
890-
return false;
887+
goto sendquery_cleanup;
891888
}
892889
PQclear(results);
893890
transaction_status = PQtransactionStatus(pset.db);
@@ -912,7 +909,7 @@ SendQuery(const char *query)
912909
psql_error("%s", PQerrorMessage(pset.db));
913910
PQclear(results);
914911
ResetCancelConn();
915-
return false;
912+
goto sendquery_cleanup;
916913
}
917914
PQclear(results);
918915
on_error_rollback_savepoint = true;
@@ -1008,10 +1005,11 @@ SendQuery(const char *query)
10081005
{
10091006
psql_error("%s", PQerrorMessage(pset.db));
10101007
PQclear(svptres);
1008+
OK = false;
10111009

10121010
PQclear(results);
10131011
ResetCancelConn();
1014-
return false;
1012+
goto sendquery_cleanup;
10151013
}
10161014
PQclear(svptres);
10171015
}
@@ -1037,6 +1035,17 @@ SendQuery(const char *query)
10371035

10381036
PrintNotifications();
10391037

1038+
/* perform cleanup that should occur after any attempted query */
1039+
1040+
sendquery_cleanup:
1041+
1042+
/* reset \g's output-to-filename trigger */
1043+
if (pset.gfname)
1044+
{
1045+
free(pset.gfname);
1046+
pset.gfname = NULL;
1047+
}
1048+
10401049
return OK;
10411050
}
10421051

@@ -1218,9 +1227,6 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
12181227

12191228
pset.queryFout = queryFout_copy;
12201229
pset.queryFoutPipe = queryFoutPipe_copy;
1221-
1222-
free(pset.gfname);
1223-
pset.gfname = NULL;
12241230
}
12251231
else if (did_pager)
12261232
{

0 commit comments

Comments
 (0)