26
26
#include "mbprint.h"
27
27
28
28
29
-
30
29
static bool ExecQueryUsingCursor (const char * query , double * elapsed_msec );
31
30
static bool command_no_begin (const char * query );
32
31
static bool is_select_command (const char * query );
33
32
33
+
34
34
/*
35
- * setQFout
36
- * -- handler for -o command line option and \o command
35
+ * openQueryOutputFile --- attempt to open a query output file
37
36
*
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.
41
44
*/
42
45
bool
43
- setQFout (const char * fname )
46
+ openQueryOutputFile (const char * fname , FILE * * fout , bool * is_pipe )
44
47
{
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 */
57
48
if (!fname || fname [0 ] == '\0' )
58
49
{
59
- pset . queryFout = stdout ;
60
- pset . queryFoutPipe = false;
50
+ * fout = stdout ;
51
+ * is_pipe = false;
61
52
}
62
53
else if (* fname == '|' )
63
54
{
64
- pset . queryFout = popen (fname + 1 , "w" );
65
- pset . queryFoutPipe = true;
55
+ * fout = popen (fname + 1 , "w" );
56
+ * is_pipe = true;
66
57
}
67
58
else
68
59
{
69
- pset . queryFout = fopen (fname , "w" );
70
- pset . queryFoutPipe = false;
60
+ * fout = fopen (fname , "w" );
61
+ * is_pipe = false;
71
62
}
72
63
73
- if (!( pset . queryFout ) )
64
+ if (* fout == NULL )
74
65
{
75
66
psql_error ("%s: %s\n" , fname , strerror (errno ));
76
- pset .queryFout = stdout ;
77
- pset .queryFoutPipe = false;
78
- status = false;
67
+ return false;
79
68
}
80
69
81
- /* Direct signals */
82
- #ifndef WIN32
83
- pqsignal (SIGPIPE , pset .queryFoutPipe ? SIG_IGN : SIG_DFL );
84
- #endif
85
-
86
- return status ;
70
+ return true;
87
71
}
88
72
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
+ }
89
108
90
109
91
110
/*
92
111
* Error reporting for scripts. Errors should look like
93
112
* psql:filename:lineno: message
94
- *
95
113
*/
96
114
void
97
115
psql_error (const char * fmt ,...)
@@ -611,27 +629,23 @@ PrintQueryTuples(const PGresult *results)
611
629
/* write output to \g argument, if any */
612
630
if (pset .gfname )
613
631
{
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 ;
619
634
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 ))
625
636
return false;
626
- }
627
-
628
- printQuery (results , & my_popt , pset .queryFout , false, pset .logfile );
637
+ if (is_pipe )
638
+ disable_sigpipe_trap ();
629
639
630
- /* close file/pipe, restore old setting */
631
- setQFout (NULL );
640
+ printQuery (results , & my_popt , fout , false, pset .logfile );
632
641
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 );
635
649
}
636
650
else
637
651
printQuery (results , & my_popt , pset .queryFout , false, pset .logfile );
@@ -1199,10 +1213,10 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
1199
1213
PGresult * results ;
1200
1214
PQExpBufferData buf ;
1201
1215
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;
1204
1219
bool started_txn = false;
1205
- bool did_pager = false;
1206
1220
int ntuples ;
1207
1221
int fetch_count ;
1208
1222
char fetch_cmd [64 ];
@@ -1268,21 +1282,22 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
1268
1282
/* prepare to write output to \g argument, if any */
1269
1283
if (pset .gfname )
1270
1284
{
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 ))
1276
1286
{
1277
- pset .queryFout = queryFout_copy ;
1278
- pset .queryFoutPipe = queryFoutPipe_copy ;
1279
1287
OK = false;
1280
1288
goto cleanup ;
1281
1289
}
1290
+ if (is_pipe )
1291
+ disable_sigpipe_trap ();
1292
+ }
1293
+ else
1294
+ {
1295
+ fout = pset .queryFout ;
1296
+ is_pipe = false; /* doesn't matter */
1282
1297
}
1283
1298
1284
1299
/* clear any pre-existing error indication on the output stream */
1285
- clearerr (pset . queryFout );
1300
+ clearerr (fout );
1286
1301
1287
1302
for (;;)
1288
1303
{
@@ -1302,12 +1317,10 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
1302
1317
if (PQresultStatus (results ) != PGRES_TUPLES_OK )
1303
1318
{
1304
1319
/* shut down pager before printing error message */
1305
- if (did_pager )
1320
+ if (is_pager )
1306
1321
{
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;
1311
1324
}
1312
1325
1313
1326
OK = AcceptResult (results );
@@ -1331,17 +1344,17 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
1331
1344
/* this is the last result set, so allow footer decoration */
1332
1345
my_popt .topt .stop_table = true;
1333
1346
}
1334
- else if (pset . queryFout == stdout && !did_pager )
1347
+ else if (fout == stdout && !is_pager )
1335
1348
{
1336
1349
/*
1337
1350
* If query requires multiple result sets, hack to ensure that
1338
1351
* only one pager instance is used for the whole mess
1339
1352
*/
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;
1342
1355
}
1343
1356
1344
- printQuery (results , & my_popt , pset . queryFout , did_pager , pset .logfile );
1357
+ printQuery (results , & my_popt , fout , is_pager , pset .logfile );
1345
1358
1346
1359
PQclear (results );
1347
1360
@@ -1355,7 +1368,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
1355
1368
* the pager dies/exits/etc, there's no sense throwing more data at
1356
1369
* it.
1357
1370
*/
1358
- flush_error = fflush (pset . queryFout );
1371
+ flush_error = fflush (fout );
1359
1372
1360
1373
/*
1361
1374
* 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)
1365
1378
* stop bothering to pull down more data.
1366
1379
*/
1367
1380
if (ntuples < fetch_count || cancel_pressed || flush_error ||
1368
- ferror (pset . queryFout ))
1381
+ ferror (fout ))
1369
1382
break ;
1370
1383
}
1371
1384
1372
- /* close \g argument file/pipe, restore old setting */
1373
1385
if (pset .gfname )
1374
1386
{
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 );
1380
1395
}
1381
- else if (did_pager )
1396
+ else if (is_pager )
1382
1397
{
1383
- ClosePager (pset .queryFout );
1384
- pset .queryFout = queryFout_copy ;
1385
- pset .queryFoutPipe = queryFoutPipe_copy ;
1398
+ /* close transient pager */
1399
+ ClosePager (fout );
1386
1400
}
1387
1401
1388
1402
cleanup :
0 commit comments