3232
3333static bool DescribeQuery (const char * query , double * elapsed_msec );
3434static 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 );
3741static bool command_no_begin (const char * query );
3842static bool is_select_command (const char * query );
3943
@@ -662,49 +666,27 @@ PrintNotifications(void)
662666/*
663667 * PrintQueryTuples: assuming query result is OK, print its tuples
664668 *
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+ *
665675 * Returns true if successful, false otherwise.
666676 */
667677static bool
668- PrintQueryTuples (const PGresult * result , const printQueryOpt * opt , FILE * printQueryFout )
678+ PrintQueryTuples (const PGresult * result , const printQueryOpt * opt ,
679+ FILE * printQueryFout )
669680{
670681 bool ok = true;
682+ FILE * fout = printQueryFout ? printQueryFout : pset .queryFout ;
671683
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 ))
674687 {
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;
708690 }
709691
710692 return ok ;
@@ -845,26 +827,24 @@ ExecQueryTuples(const PGresult *result)
845827
846828
847829/*
848- * Marshal the COPY data. Either subroutine will get the
830+ * Marshal the COPY data. Either path will get the
849831 * connection out of its COPY state, then call PQresultStatus()
850832 * once and report any error. Return whether all was ok.
851833 *
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.
854835 * For COPY IN, use pset.copyStream as data source if it's set,
855836 * otherwise cur_cmd_source.
856837 *
857- * Update result if further processing is necessary, or NULL otherwise.
838+ * Update *resultp if further processing is necessary; set to NULL otherwise.
858839 * Return a result when queryFout can safely output a result status: on COPY
859840 * IN, or on COPY OUT if written to something other than pset.queryFout.
860841 * Returning NULL prevents the command status from being printed, which we
861842 * want if the status line doesn't get taken as part of the COPY data.
862843 */
863844static bool
864- HandleCopyResult (PGresult * * resultp )
845+ HandleCopyResult (PGresult * * resultp , FILE * copystream )
865846{
866847 bool success ;
867- FILE * copystream ;
868848 PGresult * copy_result ;
869849 ExecStatusType result_status = PQresultStatus (* resultp );
870850
@@ -875,33 +855,6 @@ HandleCopyResult(PGresult **resultp)
875855
876856 if (result_status == PGRES_COPY_OUT )
877857 {
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-
905858 success = handleCopyOut (pset .db ,
906859 copystream ,
907860 & copy_result )
@@ -917,24 +870,11 @@ HandleCopyResult(PGresult **resultp)
917870 PQclear (copy_result );
918871 copy_result = NULL ;
919872 }
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- }
934873 }
935874 else
936875 {
937876 /* COPY IN */
877+ /* Ignore the copystream argument passed to the function */
938878 copystream = pset .copyStream ? pset .copyStream : pset .cur_cmd_source ;
939879 success = handleCopyIn (pset .db ,
940880 copystream ,
@@ -974,6 +914,7 @@ PrintQueryStatus(PGresult *result, FILE *printQueryFout)
974914 }
975915 else
976916 fprintf (fout , "%s\n" , PQcmdStatus (result ));
917+ fflush (fout );
977918 }
978919
979920 if (pset .logfile )
@@ -989,10 +930,16 @@ PrintQueryStatus(PGresult *result, FILE *printQueryFout)
989930 *
990931 * Note: Utility function for use by SendQuery() only.
991932 *
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+ *
992937 * Returns true if the query executed successfully, false otherwise.
993938 */
994939static 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 )
996943{
997944 bool success ;
998945 const char * cmdstatus ;
@@ -1022,14 +969,14 @@ PrintQueryResult(PGresult *result, bool last, bool is_watch, const printQueryOpt
1022969 if (strncmp (cmdstatus , "INSERT" , 6 ) == 0 ||
1023970 strncmp (cmdstatus , "UPDATE" , 6 ) == 0 ||
1024971 strncmp (cmdstatus , "DELETE" , 6 ) == 0 )
1025- PrintQueryStatus (result , printQueryFout );
972+ PrintQueryStatus (result , printStatusFout );
1026973 }
1027974
1028975 break ;
1029976
1030977 case PGRES_COMMAND_OK :
1031978 if (last || pset .show_all_results )
1032- PrintQueryStatus (result , printQueryFout );
979+ PrintQueryStatus (result , printStatusFout );
1033980 success = true;
1034981 break ;
1035982
@@ -1056,8 +1003,6 @@ PrintQueryResult(PGresult *result, bool last, bool is_watch, const printQueryOpt
10561003 break ;
10571004 }
10581005
1059- fflush (printQueryFout ? printQueryFout : pset .queryFout );
1060-
10611006 return success ;
10621007}
10631008
@@ -1399,7 +1344,7 @@ DescribeQuery(const char *query, double *elapsed_msec)
13991344 }
14001345
14011346 if (OK && result )
1402- OK = PrintQueryResult (result , true, false , NULL , NULL );
1347+ OK = PrintQueryResult (result , true, NULL , NULL , NULL );
14031348
14041349 termPQExpBuffer (& buf );
14051350 }
@@ -1421,10 +1366,9 @@ DescribeQuery(const char *query, double *elapsed_msec)
14211366 *
14221367 * Sends query and cycles through PGresult objects.
14231368 *
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.
14281372 *
14291373 * For other commands, the results are processed normally, depending on their
14301374 * status.
@@ -1437,14 +1381,18 @@ DescribeQuery(const char *query, double *elapsed_msec)
14371381 * committed.
14381382 */
14391383static 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 )
14421388{
14431389 bool timing = pset .timing ;
14441390 bool success ;
14451391 instr_time before ,
14461392 after ;
14471393 PGresult * result ;
1394+ FILE * gfile_fout = NULL ;
1395+ bool gfile_is_pipe = false;
14481396
14491397 if (timing )
14501398 INSTR_TIME_SET_CURRENT (before );
@@ -1555,14 +1503,57 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
15551503 if (result_status == PGRES_COPY_IN ||
15561504 result_status == PGRES_COPY_OUT )
15571505 {
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 )
15591515 {
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+ }
15631549 }
15641550
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 );
15661557 }
15671558
15681559 /*
@@ -1594,7 +1585,36 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
15941585
15951586 /* this may or may not print something depending on settings */
15961587 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+ }
15981618
15991619 /* set variables on last result if all went well */
16001620 if (!is_watch && last && success )
@@ -1610,6 +1630,18 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
16101630 }
16111631 }
16121632
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+
16131645 /* may need this to recover from conn loss during COPY */
16141646 if (!CheckConnection ())
16151647 return -1 ;
0 commit comments