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

Commit4a79fd1

Browse files
committed
Fix psql's behavior with \g for a multiple-command string.
The pre-v15 behavior was to discard all but the last result,but with the new behavior of printing all results by default,we will send each such result to the \g file. However,we're still opening and closing the \g file for each result,so you lose all but the last result anyway. Move the output-filestate up to ExecQueryAndProcessResults so that we open/close the\g file only once per command string.To support this without changing other behavior, we mustadjust PrintQueryResult to have separate FILE * argumentsfor query and status output (since status output has nevergone to the \g file). That in turn makes it a good ideato push the responsibility for fflush'ing output down toPrintQueryTuples and PrintQueryStatus.Also fix an infinite loop if COPY IN/OUT is attempted in \watch.We used to reject that, but that error exit path got brokensomewhere along the line in v15. There seems no real reasonto reject it anyway as the code now stands, so just removethe error exit and make sure that COPY OUT data goes to theright place.Also remove PrintQueryResult's unused is_watch parameter,and make some other cosmetic cleanups (adjust obsoletecomments, break some overly-long lines).Daniel Vérité and Tom LaneDiscussion:https://postgr.es/m/4333844c-2244-4d6e-a49a-1d483fbe304f@manitou-mail.org
1 parent0ae5db2 commit4a79fd1

File tree

1 file changed

+135
-103
lines changed

1 file changed

+135
-103
lines changed

‎src/bin/psql/common.c

Lines changed: 135 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,12 @@
3232

3333
staticboolDescribeQuery(constchar*query,double*elapsed_msec);
3434
staticboolExecQueryUsingCursor(constchar*query,double*elapsed_msec);
35-
staticintExecQueryAndProcessResults(constchar*query,double*elapsed_msec,bool*svpt_gone_p,
36-
boolis_watch,constprintQueryOpt*opt,FILE*printQueryFout);
35+
staticintExecQueryAndProcessResults(constchar*query,
36+
double*elapsed_msec,
37+
bool*svpt_gone_p,
38+
boolis_watch,
39+
constprintQueryOpt*opt,
40+
FILE*printQueryFout);
3741
staticboolcommand_no_begin(constchar*query);
3842
staticboolis_select_command(constchar*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
*/
667677
staticbool
668-
PrintQueryTuples(constPGresult*result,constprintQueryOpt*opt,FILE*printQueryFout)
678+
PrintQueryTuples(constPGresult*result,constprintQueryOpt*opt,
679+
FILE*printQueryFout)
669680
{
670681
boolok= 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-
boolis_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
returnok;
@@ -845,26 +827,24 @@ ExecQueryTuples(const PGresult *result)
845827

846828

847829
/*
848-
* Marshal the COPY data. Eithersubroutine will get the
830+
* Marshal the COPY data. Eitherpath 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-
* Updateresult 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
*/
863844
staticbool
864-
HandleCopyResult(PGresult**resultp)
845+
HandleCopyResult(PGresult**resultp,FILE*copystream)
865846
{
866847
boolsuccess;
867-
FILE*copystream;
868848
PGresult*copy_result;
869849
ExecStatusTyperesult_status=PQresultStatus(*resultp);
870850

@@ -875,33 +855,6 @@ HandleCopyResult(PGresult **resultp)
875855

876856
if (result_status==PGRES_COPY_OUT)
877857
{
878-
boolneed_close= false;
879-
boolis_pipe= false;
880-
881-
if (pset.copyStream)
882-
{
883-
/* invoked by \copy */
884-
copystream=pset.copyStream;
885-
}
886-
elseif (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
*/
994939
staticbool
995-
PrintQueryResult(PGresult*result,boollast,boolis_watch,constprintQueryOpt*opt,FILE*printQueryFout)
940+
PrintQueryResult(PGresult*result,boollast,
941+
constprintQueryOpt*opt,FILE*printQueryFout,
942+
FILE*printStatusFout)
996943
{
997944
boolsuccess;
998945
constchar*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
casePGRES_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
returnsuccess;
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
*/
14391383
staticint
1440-
ExecQueryAndProcessResults(constchar*query,double*elapsed_msec,bool*svpt_gone_p,
1441-
boolis_watch,constprintQueryOpt*opt,FILE*printQueryFout)
1384+
ExecQueryAndProcessResults(constchar*query,
1385+
double*elapsed_msec,bool*svpt_gone_p,
1386+
boolis_watch,
1387+
constprintQueryOpt*opt,FILE*printQueryFout)
14421388
{
14431389
booltiming=pset.timing;
14441390
boolsuccess;
14451391
instr_timebefore,
14461392
after;
14471393
PGresult*result;
1394+
FILE*gfile_fout=NULL;
1395+
boolgfile_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+
elseif (pset.copyStream)
1522+
{
1523+
/* invoked by \copy */
1524+
copy_stream=pset.copyStream;
1525+
}
1526+
elseif (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+
booldo_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

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp