2626#include "mbprint.h"
2727
2828
29-
3029static bool ExecQueryUsingCursor (const char * query , double * elapsed_msec );
3130static bool command_no_begin (const char * query );
3231static bool is_select_command (const char * 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 */
4245bool
43- setQFout (const char * fname )
46+ openQueryOutputFile (const char * fname , FILE * * fout , bool * is_pipe )
4447{
45- bool status = 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 else if (* 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- #ifndef WIN32
83- pqsignal (SIGPIPE , pset .queryFoutPipe ? SIG_IGN : SIG_DFL );
84- #endif
85-
86- return status ;
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 (const char * fname )
82+ {
83+ FILE * fout ;
84+ bool is_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 */
96114void
97115psql_error (const char * 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- bool queryFoutPipe_copy = pset .queryFoutPipe ;
617-
618- pset .queryFout = stdout ; /* so it doesn't get closed */
632+ FILE * fout ;
633+ bool is_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 PQExpBufferData buf ;
12011215 printQueryOpt my_popt = pset .popt ;
1202- FILE * queryFout_copy = pset .queryFout ;
1203- bool queryFoutPipe_copy = pset .queryFoutPipe ;
1216+ FILE * fout ;
1217+ bool is_pipe ;
1218+ bool is_pager = false;
12041219 bool started_txn = false;
1205- bool did_pager = false;
12061220 int ntuples ;
12071221 int fetch_count ;
12081222 char fetch_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 goto cleanup ;
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- else if (pset . queryFout == stdout && !did_pager )
1347+ else if (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- else if (did_pager )
1396+ else if (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
13881402cleanup :
0 commit comments