Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

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

Sign up
Appearance settings

Commit344cdff

Browse files
committed
Clean up some psql issues around handling of the query output file.
Formerly, if "psql -o foo" failed to open the output file "foo", it wouldprint an error message but then carry on as though -o had not beenspecified at all. This seems contrary to expectation: a program thatcannot open its output file normally fails altogether. Make psql doexit(1) after reporting the error.If "\o foo" failed to open "foo", it would print an error message but thenreset the output file to stdout, as if the argument had been omitted.This is likewise pretty surprising behavior. Make it keep the previousoutput state, instead.psql keeps SIGPIPE interrupts disabled when it is writing to a pipe, eithera pipe specified by -o/\o or a transient pipe opened for purposes such asusing a pager on query output. The logic for this was too simple and couldsometimes re-enable SIGPIPE when a -o pipe was still active, thus possiblyleading to an unexpected psql crash later.Fixing the last point required getting rid of the kluge in PrintQueryTuplesand ExecQueryUsingCursor whereby they'd transiently change the globalqueryFout state, but that seems like good cleanup anyway.Back-patch to 9.5 but not further; these are minor-enough issues thatchanging the behavior in stable branches doesn't seem appropriate.
1 parentf15b820 commit344cdff

File tree

7 files changed

+178
-106
lines changed

7 files changed

+178
-106
lines changed

‎src/bin/psql/command.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,6 +1531,7 @@ exec_command(const char *cmd,
15311531
if (fname[0]=='|')
15321532
{
15331533
is_pipe= true;
1534+
disable_sigpipe_trap();
15341535
fd=popen(&fname[1],"w");
15351536
}
15361537
else
@@ -1565,6 +1566,9 @@ exec_command(const char *cmd,
15651566
}
15661567
}
15671568

1569+
if (is_pipe)
1570+
restore_sigpipe_trap();
1571+
15681572
free(fname);
15691573
}
15701574

‎src/bin/psql/common.c

Lines changed: 99 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -26,72 +26,90 @@
2626
#include"mbprint.h"
2727

2828

29-
3029
staticboolExecQueryUsingCursor(constchar*query,double*elapsed_msec);
3130
staticboolcommand_no_begin(constchar*query);
3231
staticboolis_select_command(constchar*query);
3332

33+
3434
/*
35-
* setQFout
36-
* -- handler for -o command line option and \o command
35+
* openQueryOutputFile --- attempt to open a query output file
3736
*
38-
* Tries to open file fname (or pipe if fname starts with '|')
39-
* and stores the file handle in pset)
40-
* Upon failure, sets stdout and returns false.
37+
* fname == NULL selects stdout, else an initial '|' selects a pipe,
38+
* else plain file.
39+
*
40+
* Returns output file pointer into *fout, and is-a-pipe flag into *is_pipe.
41+
* Caller is responsible for adjusting SIGPIPE state if it's a pipe.
42+
*
43+
* On error, reports suitable error message and returns FALSE.
4144
*/
4245
bool
43-
setQFout(constchar*fname)
46+
openQueryOutputFile(constchar*fname,FILE**fout,bool*is_pipe)
4447
{
45-
boolstatus= true;
46-
47-
/* Close old file/pipe */
48-
if (pset.queryFout&&pset.queryFout!=stdout&&pset.queryFout!=stderr)
49-
{
50-
if (pset.queryFoutPipe)
51-
pclose(pset.queryFout);
52-
else
53-
fclose(pset.queryFout);
54-
}
55-
56-
/* If no filename, set stdout */
5748
if (!fname||fname[0]=='\0')
5849
{
59-
pset.queryFout=stdout;
60-
pset.queryFoutPipe= false;
50+
*fout=stdout;
51+
*is_pipe= false;
6152
}
6253
elseif (*fname=='|')
6354
{
64-
pset.queryFout=popen(fname+1,"w");
65-
pset.queryFoutPipe= true;
55+
*fout=popen(fname+1,"w");
56+
*is_pipe= true;
6657
}
6758
else
6859
{
69-
pset.queryFout=fopen(fname,"w");
70-
pset.queryFoutPipe= false;
60+
*fout=fopen(fname,"w");
61+
*is_pipe= false;
7162
}
7263

73-
if (!(pset.queryFout))
64+
if (*fout==NULL)
7465
{
7566
psql_error("%s: %s\n",fname,strerror(errno));
76-
pset.queryFout=stdout;
77-
pset.queryFoutPipe= false;
78-
status= false;
67+
return false;
7968
}
8069

81-
/* Direct signals */
82-
#ifndefWIN32
83-
pqsignal(SIGPIPE,pset.queryFoutPipe ?SIG_IGN :SIG_DFL);
84-
#endif
85-
86-
returnstatus;
70+
return true;
8771
}
8872

73+
/*
74+
* setQFout
75+
* -- handler for -o command line option and \o command
76+
*
77+
* On success, updates pset with the new output file and returns true.
78+
* On failure, returns false without changing pset state.
79+
*/
80+
bool
81+
setQFout(constchar*fname)
82+
{
83+
FILE*fout;
84+
boolis_pipe;
85+
86+
/* First make sure we can open the new output file/pipe */
87+
if (!openQueryOutputFile(fname,&fout,&is_pipe))
88+
return false;
89+
90+
/* Close old file/pipe */
91+
if (pset.queryFout&&pset.queryFout!=stdout&&pset.queryFout!=stderr)
92+
{
93+
if (pset.queryFoutPipe)
94+
pclose(pset.queryFout);
95+
else
96+
fclose(pset.queryFout);
97+
}
98+
99+
pset.queryFout=fout;
100+
pset.queryFoutPipe=is_pipe;
101+
102+
/* Adjust SIGPIPE handling appropriately: ignore signal if is_pipe */
103+
set_sigpipe_trap_state(is_pipe);
104+
restore_sigpipe_trap();
105+
106+
return true;
107+
}
89108

90109

91110
/*
92111
* Error reporting for scripts. Errors should look like
93112
* psql:filename:lineno: message
94-
*
95113
*/
96114
void
97115
psql_error(constchar*fmt,...)
@@ -611,27 +629,23 @@ PrintQueryTuples(const PGresult *results)
611629
/* write output to \g argument, if any */
612630
if (pset.gfname)
613631
{
614-
/* keep this code in sync with ExecQueryUsingCursor */
615-
FILE*queryFout_copy=pset.queryFout;
616-
boolqueryFoutPipe_copy=pset.queryFoutPipe;
617-
618-
pset.queryFout=stdout;/* so it doesn't get closed */
632+
FILE*fout;
633+
boolis_pipe;
619634

620-
/* open file/pipe */
621-
if (!setQFout(pset.gfname))
622-
{
623-
pset.queryFout=queryFout_copy;
624-
pset.queryFoutPipe=queryFoutPipe_copy;
635+
if (!openQueryOutputFile(pset.gfname,&fout,&is_pipe))
625636
return false;
626-
}
627-
628-
printQuery(results,&my_popt,pset.queryFout, false,pset.logfile);
637+
if (is_pipe)
638+
disable_sigpipe_trap();
629639

630-
/* close file/pipe, restore old setting */
631-
setQFout(NULL);
640+
printQuery(results,&my_popt,fout, false,pset.logfile);
632641

633-
pset.queryFout=queryFout_copy;
634-
pset.queryFoutPipe=queryFoutPipe_copy;
642+
if (is_pipe)
643+
{
644+
pclose(fout);
645+
restore_sigpipe_trap();
646+
}
647+
else
648+
fclose(fout);
635649
}
636650
else
637651
printQuery(results,&my_popt,pset.queryFout, false,pset.logfile);
@@ -1199,10 +1213,10 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
11991213
PGresult*results;
12001214
PQExpBufferDatabuf;
12011215
printQueryOptmy_popt=pset.popt;
1202-
FILE*queryFout_copy=pset.queryFout;
1203-
boolqueryFoutPipe_copy=pset.queryFoutPipe;
1216+
FILE*fout;
1217+
boolis_pipe;
1218+
boolis_pager= false;
12041219
boolstarted_txn= false;
1205-
booldid_pager= false;
12061220
intntuples;
12071221
intfetch_count;
12081222
charfetch_cmd[64];
@@ -1268,21 +1282,22 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
12681282
/* prepare to write output to \g argument, if any */
12691283
if (pset.gfname)
12701284
{
1271-
/* keep this code in sync with PrintQueryTuples */
1272-
pset.queryFout=stdout;/* so it doesn't get closed */
1273-
1274-
/* open file/pipe */
1275-
if (!setQFout(pset.gfname))
1285+
if (!openQueryOutputFile(pset.gfname,&fout,&is_pipe))
12761286
{
1277-
pset.queryFout=queryFout_copy;
1278-
pset.queryFoutPipe=queryFoutPipe_copy;
12791287
OK= false;
12801288
gotocleanup;
12811289
}
1290+
if (is_pipe)
1291+
disable_sigpipe_trap();
1292+
}
1293+
else
1294+
{
1295+
fout=pset.queryFout;
1296+
is_pipe= false;/* doesn't matter */
12821297
}
12831298

12841299
/* clear any pre-existing error indication on the output stream */
1285-
clearerr(pset.queryFout);
1300+
clearerr(fout);
12861301

12871302
for (;;)
12881303
{
@@ -1302,12 +1317,10 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
13021317
if (PQresultStatus(results)!=PGRES_TUPLES_OK)
13031318
{
13041319
/* shut down pager before printing error message */
1305-
if (did_pager)
1320+
if (is_pager)
13061321
{
1307-
ClosePager(pset.queryFout);
1308-
pset.queryFout=queryFout_copy;
1309-
pset.queryFoutPipe=queryFoutPipe_copy;
1310-
did_pager= false;
1322+
ClosePager(fout);
1323+
is_pager= false;
13111324
}
13121325

13131326
OK=AcceptResult(results);
@@ -1331,17 +1344,17 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
13311344
/* this is the last result set, so allow footer decoration */
13321345
my_popt.topt.stop_table= true;
13331346
}
1334-
elseif (pset.queryFout==stdout&& !did_pager)
1347+
elseif (fout==stdout&& !is_pager)
13351348
{
13361349
/*
13371350
* If query requires multiple result sets, hack to ensure that
13381351
* only one pager instance is used for the whole mess
13391352
*/
1340-
pset.queryFout=PageOutput(INT_MAX,&(my_popt.topt));
1341-
did_pager= true;
1353+
fout=PageOutput(INT_MAX,&(my_popt.topt));
1354+
is_pager= true;
13421355
}
13431356

1344-
printQuery(results,&my_popt,pset.queryFout,did_pager,pset.logfile);
1357+
printQuery(results,&my_popt,fout,is_pager,pset.logfile);
13451358

13461359
PQclear(results);
13471360

@@ -1355,7 +1368,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
13551368
* the pager dies/exits/etc, there's no sense throwing more data at
13561369
* it.
13571370
*/
1358-
flush_error=fflush(pset.queryFout);
1371+
flush_error=fflush(fout);
13591372

13601373
/*
13611374
* Check if we are at the end, if a cancel was pressed, or if there
@@ -1365,24 +1378,25 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
13651378
* stop bothering to pull down more data.
13661379
*/
13671380
if (ntuples<fetch_count||cancel_pressed||flush_error||
1368-
ferror(pset.queryFout))
1381+
ferror(fout))
13691382
break;
13701383
}
13711384

1372-
/* close \g argument file/pipe, restore old setting */
13731385
if (pset.gfname)
13741386
{
1375-
/* keep this code in sync with PrintQueryTuples */
1376-
setQFout(NULL);
1377-
1378-
pset.queryFout=queryFout_copy;
1379-
pset.queryFoutPipe=queryFoutPipe_copy;
1387+
/* close \g argument file/pipe */
1388+
if (is_pipe)
1389+
{
1390+
pclose(fout);
1391+
restore_sigpipe_trap();
1392+
}
1393+
else
1394+
fclose(fout);
13801395
}
1381-
elseif (did_pager)
1396+
elseif (is_pager)
13821397
{
1383-
ClosePager(pset.queryFout);
1384-
pset.queryFout=queryFout_copy;
1385-
pset.queryFoutPipe=queryFoutPipe_copy;
1398+
/* close transient pager */
1399+
ClosePager(fout);
13861400
}
13871401

13881402
cleanup:

‎src/bin/psql/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#defineatooid(x) ((Oid) strtoul((x), NULL, 10))
1818

19+
externboolopenQueryOutputFile(constchar*fname,FILE**fout,bool*is_pipe);
1920
externboolsetQFout(constchar*fname);
2021

2122
externvoidpsql_error(constchar*fmt,...)pg_attribute_printf(1,2);

‎src/bin/psql/copy.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* where 'filename' can be one of the following:
3838
*'<file path>' | PROGRAM '<command>' | stdin | stdout | pstdout | pstdout
3939
* and 'query' can be one of the following:
40-
*SELECT | UPDATE | INSERT | DELETE
40+
*SELECT | UPDATE | INSERT | DELETE
4141
*
4242
* An undocumented fact is that you can still write BINARY before the
4343
* tablename; this is a hangover from the pre-7.3 syntax. The options
@@ -312,9 +312,7 @@ do_copy(const char *args)
312312
fflush(stdout);
313313
fflush(stderr);
314314
errno=0;
315-
#ifndefWIN32
316-
pqsignal(SIGPIPE,SIG_IGN);
317-
#endif
315+
disable_sigpipe_trap();
318316
copystream=popen(options->file,PG_BINARY_W);
319317
}
320318
else
@@ -399,9 +397,7 @@ do_copy(const char *args)
399397
}
400398
success= false;
401399
}
402-
#ifndefWIN32
403-
pqsignal(SIGPIPE,SIG_DFL);
404-
#endif
400+
restore_sigpipe_trap();
405401
}
406402
else
407403
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp