32
32
33
33
static bool DescribeQuery (const char * query ,double * elapsed_msec );
34
34
static bool ExecQueryUsingCursor (const char * query ,double * elapsed_msec );
35
- static int ExecQueryAndProcessResults (const char * query ,double * elapsed_msec ,bool * svpt_gone_p ,
36
- bool is_watch ,const printQueryOpt * opt ,FILE * printQueryFout );
35
+ static int ExecQueryAndProcessResults (const char * query ,
36
+ double * elapsed_msec ,
37
+ bool * svpt_gone_p ,
38
+ bool is_watch ,
39
+ const printQueryOpt * opt ,
40
+ FILE * printQueryFout );
37
41
static bool command_no_begin (const char * query );
38
42
static bool is_select_command (const char * query );
39
43
@@ -662,49 +666,27 @@ PrintNotifications(void)
662
666
/*
663
667
* PrintQueryTuples: assuming query result is OK, print its tuples
664
668
*
669
+ * We use the options given by opt unless that's NULL, in which case
670
+ * we use pset.popt.
671
+ *
672
+ * Output is to printQueryFout unless that's NULL, in which case
673
+ * we use pset.queryFout.
674
+ *
665
675
* Returns true if successful, false otherwise.
666
676
*/
667
677
static bool
668
- PrintQueryTuples (const PGresult * result ,const printQueryOpt * opt ,FILE * printQueryFout )
678
+ PrintQueryTuples (const PGresult * result ,const printQueryOpt * opt ,
679
+ FILE * printQueryFout )
669
680
{
670
681
bool ok = true;
682
+ FILE * fout = printQueryFout ?printQueryFout :pset .queryFout ;
671
683
672
- /* write output to \g argument, if any */
673
- if (pset .gfname )
684
+ printQuery (result ,opt ?opt :& pset .popt ,fout , false,pset .logfile );
685
+ fflush (fout );
686
+ if (ferror (fout ))
674
687
{
675
- FILE * fout ;
676
- bool is_pipe ;
677
-
678
- if (!openQueryOutputFile (pset .gfname ,& fout ,& is_pipe ))
679
- return false;
680
- if (is_pipe )
681
- disable_sigpipe_trap ();
682
-
683
- printQuery (result ,& pset .popt ,fout , false,pset .logfile );
684
- if (ferror (fout ))
685
- {
686
- pg_log_error ("could not print result table: %m" );
687
- ok = false;
688
- }
689
-
690
- if (is_pipe )
691
- {
692
- pclose (fout );
693
- restore_sigpipe_trap ();
694
- }
695
- else
696
- fclose (fout );
697
- }
698
- else
699
- {
700
- FILE * fout = printQueryFout ?printQueryFout :pset .queryFout ;
701
-
702
- printQuery (result ,opt ?opt :& pset .popt ,fout , false,pset .logfile );
703
- if (ferror (fout ))
704
- {
705
- pg_log_error ("could not print result table: %m" );
706
- ok = false;
707
- }
688
+ pg_log_error ("could not print result table: %m" );
689
+ ok = false;
708
690
}
709
691
710
692
return ok ;
@@ -845,26 +827,24 @@ ExecQueryTuples(const PGresult *result)
845
827
846
828
847
829
/*
848
- * Marshal the COPY data. Eithersubroutine will get the
830
+ * Marshal the COPY data. Eitherpath will get the
849
831
* connection out of its COPY state, then call PQresultStatus()
850
832
* once and report any error. Return whether all was ok.
851
833
*
852
- * For COPY OUT, direct the output to pset.copyStream if it's set,
853
- * otherwise to pset.gfname if it's set, otherwise to queryFout.
834
+ * For COPY OUT, direct the output to copystream, or discard if that's NULL.
854
835
* For COPY IN, use pset.copyStream as data source if it's set,
855
836
* otherwise cur_cmd_source.
856
837
*
857
- * Updateresult if further processing is necessary, or NULL otherwise.
838
+ * Update*resultp if further processing is necessary; set to NULL otherwise.
858
839
* Return a result when queryFout can safely output a result status: on COPY
859
840
* IN, or on COPY OUT if written to something other than pset.queryFout.
860
841
* Returning NULL prevents the command status from being printed, which we
861
842
* want if the status line doesn't get taken as part of the COPY data.
862
843
*/
863
844
static bool
864
- HandleCopyResult (PGresult * * resultp )
845
+ HandleCopyResult (PGresult * * resultp , FILE * copystream )
865
846
{
866
847
bool success ;
867
- FILE * copystream ;
868
848
PGresult * copy_result ;
869
849
ExecStatusType result_status = PQresultStatus (* resultp );
870
850
@@ -875,33 +855,6 @@ HandleCopyResult(PGresult **resultp)
875
855
876
856
if (result_status == PGRES_COPY_OUT )
877
857
{
878
- bool need_close = false;
879
- bool is_pipe = false;
880
-
881
- if (pset .copyStream )
882
- {
883
- /* invoked by \copy */
884
- copystream = pset .copyStream ;
885
- }
886
- else if (pset .gfname )
887
- {
888
- /* invoked by \g */
889
- if (openQueryOutputFile (pset .gfname ,
890
- & copystream ,& is_pipe ))
891
- {
892
- need_close = true;
893
- if (is_pipe )
894
- disable_sigpipe_trap ();
895
- }
896
- else
897
- copystream = NULL ;/* discard COPY data entirely */
898
- }
899
- else
900
- {
901
- /* fall back to the generic query output stream */
902
- copystream = pset .queryFout ;
903
- }
904
-
905
858
success = handleCopyOut (pset .db ,
906
859
copystream ,
907
860
& copy_result )
@@ -917,24 +870,11 @@ HandleCopyResult(PGresult **resultp)
917
870
PQclear (copy_result );
918
871
copy_result = NULL ;
919
872
}
920
-
921
- if (need_close )
922
- {
923
- /* close \g argument file/pipe */
924
- if (is_pipe )
925
- {
926
- pclose (copystream );
927
- restore_sigpipe_trap ();
928
- }
929
- else
930
- {
931
- fclose (copystream );
932
- }
933
- }
934
873
}
935
874
else
936
875
{
937
876
/* COPY IN */
877
+ /* Ignore the copystream argument passed to the function */
938
878
copystream = pset .copyStream ?pset .copyStream :pset .cur_cmd_source ;
939
879
success = handleCopyIn (pset .db ,
940
880
copystream ,
@@ -974,6 +914,7 @@ PrintQueryStatus(PGresult *result, FILE *printQueryFout)
974
914
}
975
915
else
976
916
fprintf (fout ,"%s\n" ,PQcmdStatus (result ));
917
+ fflush (fout );
977
918
}
978
919
979
920
if (pset .logfile )
@@ -989,10 +930,16 @@ PrintQueryStatus(PGresult *result, FILE *printQueryFout)
989
930
*
990
931
* Note: Utility function for use by SendQuery() only.
991
932
*
933
+ * last is true if this is the last result of a command string.
934
+ * opt and printQueryFout are defined as for PrintQueryTuples.
935
+ * printStatusFout is where to send command status; NULL means pset.queryFout.
936
+ *
992
937
* Returns true if the query executed successfully, false otherwise.
993
938
*/
994
939
static bool
995
- PrintQueryResult (PGresult * result ,bool last ,bool is_watch ,const printQueryOpt * opt ,FILE * printQueryFout )
940
+ PrintQueryResult (PGresult * result ,bool last ,
941
+ const printQueryOpt * opt ,FILE * printQueryFout ,
942
+ FILE * printStatusFout )
996
943
{
997
944
bool success ;
998
945
const char * cmdstatus ;
@@ -1022,14 +969,14 @@ PrintQueryResult(PGresult *result, bool last, bool is_watch, const printQueryOpt
1022
969
if (strncmp (cmdstatus ,"INSERT" ,6 )== 0 ||
1023
970
strncmp (cmdstatus ,"UPDATE" ,6 )== 0 ||
1024
971
strncmp (cmdstatus ,"DELETE" ,6 )== 0 )
1025
- PrintQueryStatus (result ,printQueryFout );
972
+ PrintQueryStatus (result ,printStatusFout );
1026
973
}
1027
974
1028
975
break ;
1029
976
1030
977
case PGRES_COMMAND_OK :
1031
978
if (last || pset .show_all_results )
1032
- PrintQueryStatus (result ,printQueryFout );
979
+ PrintQueryStatus (result ,printStatusFout );
1033
980
success = true;
1034
981
break ;
1035
982
@@ -1056,8 +1003,6 @@ PrintQueryResult(PGresult *result, bool last, bool is_watch, const printQueryOpt
1056
1003
break ;
1057
1004
}
1058
1005
1059
- fflush (printQueryFout ?printQueryFout :pset .queryFout );
1060
-
1061
1006
return success ;
1062
1007
}
1063
1008
@@ -1399,7 +1344,7 @@ DescribeQuery(const char *query, double *elapsed_msec)
1399
1344
}
1400
1345
1401
1346
if (OK && result )
1402
- OK = PrintQueryResult (result , true,false ,NULL ,NULL );
1347
+ OK = PrintQueryResult (result , true,NULL ,NULL ,NULL );
1403
1348
1404
1349
termPQExpBuffer (& buf );
1405
1350
}
@@ -1421,10 +1366,9 @@ DescribeQuery(const char *query, double *elapsed_msec)
1421
1366
*
1422
1367
* Sends query and cycles through PGresult objects.
1423
1368
*
1424
- * When not under \watch and if our command string contained a COPY FROM STDIN
1425
- * or COPY TO STDOUT, the PGresult associated with these commands must be
1426
- * processed by providing an input or output stream. In that event, we'll
1427
- * marshal data for the COPY.
1369
+ * If our command string contained a COPY FROM STDIN or COPY TO STDOUT, the
1370
+ * PGresult associated with these commands must be processed by providing an
1371
+ * input or output stream. In that event, we'll marshal data for the COPY.
1428
1372
*
1429
1373
* For other commands, the results are processed normally, depending on their
1430
1374
* status.
@@ -1437,14 +1381,18 @@ DescribeQuery(const char *query, double *elapsed_msec)
1437
1381
* committed.
1438
1382
*/
1439
1383
static int
1440
- ExecQueryAndProcessResults (const char * query ,double * elapsed_msec ,bool * svpt_gone_p ,
1441
- bool is_watch ,const printQueryOpt * opt ,FILE * printQueryFout )
1384
+ ExecQueryAndProcessResults (const char * query ,
1385
+ double * elapsed_msec ,bool * svpt_gone_p ,
1386
+ bool is_watch ,
1387
+ const printQueryOpt * opt ,FILE * printQueryFout )
1442
1388
{
1443
1389
bool timing = pset .timing ;
1444
1390
bool success ;
1445
1391
instr_time before ,
1446
1392
after ;
1447
1393
PGresult * result ;
1394
+ FILE * gfile_fout = NULL ;
1395
+ bool gfile_is_pipe = false;
1448
1396
1449
1397
if (timing )
1450
1398
INSTR_TIME_SET_CURRENT (before );
@@ -1555,14 +1503,57 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
1555
1503
if (result_status == PGRES_COPY_IN ||
1556
1504
result_status == PGRES_COPY_OUT )
1557
1505
{
1558
- if (is_watch )
1506
+ FILE * copy_stream = NULL ;
1507
+
1508
+ /*
1509
+ * For COPY OUT, direct the output to the default place (probably
1510
+ * a pager pipe) for \watch, or to pset.copyStream for \copy,
1511
+ * otherwise to pset.gfname if that's set, otherwise to
1512
+ * pset.queryFout.
1513
+ */
1514
+ if (result_status == PGRES_COPY_OUT )
1559
1515
{
1560
- ClearOrSaveAllResults ();
1561
- pg_log_error ("\\watch cannot be used with COPY" );
1562
- return -1 ;
1516
+ if (is_watch )
1517
+ {
1518
+ /* invoked by \watch */
1519
+ copy_stream = printQueryFout ?printQueryFout :pset .queryFout ;
1520
+ }
1521
+ else if (pset .copyStream )
1522
+ {
1523
+ /* invoked by \copy */
1524
+ copy_stream = pset .copyStream ;
1525
+ }
1526
+ else if (pset .gfname )
1527
+ {
1528
+ /* send to \g file, which we may have opened already */
1529
+ if (gfile_fout == NULL )
1530
+ {
1531
+ if (openQueryOutputFile (pset .gfname ,
1532
+ & gfile_fout ,& gfile_is_pipe ))
1533
+ {
1534
+ if (gfile_is_pipe )
1535
+ disable_sigpipe_trap ();
1536
+ copy_stream = gfile_fout ;
1537
+ }
1538
+ else
1539
+ success = false;
1540
+ }
1541
+ else
1542
+ copy_stream = gfile_fout ;
1543
+ }
1544
+ else
1545
+ {
1546
+ /* fall back to the generic query output stream */
1547
+ copy_stream = pset .queryFout ;
1548
+ }
1563
1549
}
1564
1550
1565
- success &=HandleCopyResult (& result );
1551
+ /*
1552
+ * Even if the output stream could not be opened, we call
1553
+ * HandleCopyResult() with a NULL output stream to collect and
1554
+ * discard the COPY data.
1555
+ */
1556
+ success &=HandleCopyResult (& result ,copy_stream );
1566
1557
}
1567
1558
1568
1559
/*
@@ -1594,7 +1585,36 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
1594
1585
1595
1586
/* this may or may not print something depending on settings */
1596
1587
if (result != NULL )
1597
- success &=PrintQueryResult (result ,last , false,opt ,printQueryFout );
1588
+ {
1589
+ /*
1590
+ * If results need to be printed into the file specified by \g,
1591
+ * open it, unless we already did. Note that when pset.gfname is
1592
+ * set, the passed-in value of printQueryFout is not used for
1593
+ * tuple output, but it's still used for status output.
1594
+ */
1595
+ FILE * tuples_fout = printQueryFout ;
1596
+ bool do_print = true;
1597
+
1598
+ if (PQresultStatus (result )== PGRES_TUPLES_OK &&
1599
+ pset .gfname )
1600
+ {
1601
+ if (gfile_fout == NULL )
1602
+ {
1603
+ if (openQueryOutputFile (pset .gfname ,
1604
+ & gfile_fout ,& gfile_is_pipe ))
1605
+ {
1606
+ if (gfile_is_pipe )
1607
+ disable_sigpipe_trap ();
1608
+ }
1609
+ else
1610
+ success = do_print = false;
1611
+ }
1612
+ tuples_fout = gfile_fout ;
1613
+ }
1614
+ if (do_print )
1615
+ success &=PrintQueryResult (result ,last ,opt ,
1616
+ tuples_fout ,printQueryFout );
1617
+ }
1598
1618
1599
1619
/* set variables on last result if all went well */
1600
1620
if (!is_watch && last && success )
@@ -1610,6 +1630,18 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
1610
1630
}
1611
1631
}
1612
1632
1633
+ /* close \g file if we opened it */
1634
+ if (gfile_fout )
1635
+ {
1636
+ if (gfile_is_pipe )
1637
+ {
1638
+ pclose (gfile_fout );
1639
+ restore_sigpipe_trap ();
1640
+ }
1641
+ else
1642
+ fclose (gfile_fout );
1643
+ }
1644
+
1613
1645
/* may need this to recover from conn loss during COPY */
1614
1646
if (!CheckConnection ())
1615
1647
return -1 ;