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

Commitb71a9cb

Browse files
committed
Fix libpq state machine in pipeline mode
The original coding required that PQpipelineSync had been called beforethe first call to PQgetResult, and failure to do that would result in anunexpected NULL result being returned. Fix by setting the right statewhen a query is sent, rather than leaving it unchanged and havingPQpipelineSync apply the necessary state change.A new test case to verify the behavior is added, which relies on the newPQsendFlushRequest() function added by commita719232.Backpatch to 14, where pipeline mode was added.Reported-by: Boris Kolpackov <boris@codesynthesis.com>Author: Álvaro Herrera <alvherre@alvh.no-ip.org>Discussion:https://postgr.es/m/boris.20210616110321@codesynthesis.com
1 parenta719232 commitb71a9cb

File tree

4 files changed

+188
-15
lines changed

4 files changed

+188
-15
lines changed

‎src/interfaces/libpq/fe-exec.c

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,8 +1375,7 @@ PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery)
13751375

13761376
/* OK, it's launched! */
13771377
pqAppendCmdQueueEntry(conn,entry);
1378-
if (conn->pipelineStatus==PQ_PIPELINE_OFF)
1379-
conn->asyncStatus=PGASYNC_BUSY;
1378+
conn->asyncStatus=PGASYNC_BUSY;
13801379
return1;
13811380

13821381
sendFailed:
@@ -1513,8 +1512,7 @@ PQsendPrepare(PGconn *conn,
15131512

15141513
pqAppendCmdQueueEntry(conn,entry);
15151514

1516-
if (conn->pipelineStatus==PQ_PIPELINE_OFF)
1517-
conn->asyncStatus=PGASYNC_BUSY;
1515+
conn->asyncStatus=PGASYNC_BUSY;
15181516

15191517
/*
15201518
* Give the data a push (in pipeline mode, only if we're past the size
@@ -1817,8 +1815,7 @@ PQsendQueryGuts(PGconn *conn,
18171815

18181816
/* OK, it's launched! */
18191817
pqAppendCmdQueueEntry(conn,entry);
1820-
if (conn->pipelineStatus==PQ_PIPELINE_OFF)
1821-
conn->asyncStatus=PGASYNC_BUSY;
1818+
conn->asyncStatus=PGASYNC_BUSY;
18221819
return1;
18231820

18241821
sendFailed:
@@ -2448,8 +2445,7 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
24482445

24492446
/* OK, it's launched! */
24502447
pqAppendCmdQueueEntry(conn,entry);
2451-
if (conn->pipelineStatus==PQ_PIPELINE_OFF)
2452-
conn->asyncStatus=PGASYNC_BUSY;
2448+
conn->asyncStatus=PGASYNC_BUSY;
24532449
return1;
24542450

24552451
sendFailed:
@@ -3084,12 +3080,7 @@ PQpipelineSync(PGconn *conn)
30843080
*/
30853081
if (PQflush(conn)<0)
30863082
gotosendFailed;
3087-
3088-
/*
3089-
* Call pqPipelineProcessQueue so the user can call start calling
3090-
* PQgetResult.
3091-
*/
3092-
pqPipelineProcessQueue(conn);
3083+
conn->asyncStatus=PGASYNC_BUSY;
30933084

30943085
return1;
30953086

‎src/test/modules/libpq_pipeline/libpq_pipeline.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,93 @@ test_multi_pipelines(PGconn *conn)
230230
fprintf(stderr,"ok\n");
231231
}
232232

233+
/*
234+
* Test behavior when a pipeline dispatches a number of commands that are
235+
* not flushed by a sync point.
236+
*/
237+
staticvoid
238+
test_nosync(PGconn*conn)
239+
{
240+
intnumqueries=10;
241+
intresults=0;
242+
intsock=PQsocket(conn);
243+
244+
fprintf(stderr,"nosync... ");
245+
246+
if (sock<0)
247+
pg_fatal("invalid socket");
248+
249+
if (PQenterPipelineMode(conn)!=1)
250+
pg_fatal("could not enter pipeline mode");
251+
for (inti=0;i<numqueries;i++)
252+
{
253+
fd_setinput_mask;
254+
structtimevaltv;
255+
256+
if (PQsendQueryParams(conn,"SELECT repeat('xyzxz', 12)",
257+
0,NULL,NULL,NULL,NULL,0)!=1)
258+
pg_fatal("error sending select: %s",PQerrorMessage(conn));
259+
PQflush(conn);
260+
261+
/*
262+
* If the server has written anything to us, read (some of) it now.
263+
*/
264+
FD_ZERO(&input_mask);
265+
FD_SET(sock,&input_mask);
266+
tv.tv_sec=0;
267+
tv.tv_usec=0;
268+
if (select(sock+1,&input_mask,NULL,NULL,&tv)<0)
269+
{
270+
fprintf(stderr,"select() failed: %s\n",strerror(errno));
271+
exit_nicely(conn);
272+
}
273+
if (FD_ISSET(sock,&input_mask)&&PQconsumeInput(conn)!=1)
274+
pg_fatal("failed to read from server: %s",PQerrorMessage(conn));
275+
}
276+
277+
/* tell server to flush its output buffer */
278+
if (PQsendFlushRequest(conn)!=1)
279+
pg_fatal("failed to send flush request");
280+
PQflush(conn);
281+
282+
/* Now read all results */
283+
for (;;)
284+
{
285+
PGresult*res;
286+
287+
res=PQgetResult(conn);
288+
289+
/* NULL results are only expected after TUPLES_OK */
290+
if (res==NULL)
291+
pg_fatal("got unexpected NULL result after %d results",results);
292+
293+
/* We expect exactly one TUPLES_OK result for each query we sent */
294+
if (PQresultStatus(res)==PGRES_TUPLES_OK)
295+
{
296+
PGresult*res2;
297+
298+
/* and one NULL result should follow each */
299+
res2=PQgetResult(conn);
300+
if (res2!=NULL)
301+
pg_fatal("expected NULL, got %s",
302+
PQresStatus(PQresultStatus(res2)));
303+
PQclear(res);
304+
results++;
305+
306+
/* if we're done, we're done */
307+
if (results==numqueries)
308+
break;
309+
310+
continue;
311+
}
312+
313+
/* anything else is unexpected */
314+
pg_fatal("got unexpected %s\n",PQresStatus(PQresultStatus(res)));
315+
}
316+
317+
fprintf(stderr,"ok\n");
318+
}
319+
233320
/*
234321
* When an operation in a pipeline fails the rest of the pipeline is flushed. We
235322
* still have to get results for each pipeline item, but the item will just be
@@ -1237,6 +1324,7 @@ print_test_list(void)
12371324
{
12381325
printf("disallowed_in_pipeline\n");
12391326
printf("multi_pipelines\n");
1327+
printf("nosync\n");
12401328
printf("pipeline_abort\n");
12411329
printf("pipelined_insert\n");
12421330
printf("prepared\n");
@@ -1334,6 +1422,8 @@ main(int argc, char **argv)
13341422
test_disallowed_in_pipeline(conn);
13351423
elseif (strcmp(testname,"multi_pipelines")==0)
13361424
test_multi_pipelines(conn);
1425+
elseif (strcmp(testname,"nosync")==0)
1426+
test_nosync(conn);
13371427
elseif (strcmp(testname,"pipeline_abort")==0)
13381428
test_pipeline_abort(conn);
13391429
elseif (strcmp(testname,"pipelined_insert")==0)

‎src/test/modules/libpq_pipeline/t/001_libpq_pipeline.pl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
{
2727
my@extraargs = ('-r',$numrows);
2828
my$cmptrace =grep(/^$testname$/,
29-
qw(simple_pipeline multi_pipelines prepared singlerow
29+
qw(simple_pipelinenosyncmulti_pipelines prepared singlerow
3030
pipeline_abort transaction disallowed_in_pipeline)) > 0;
3131

3232
# For a bunch of tests, generate a libpq trace file too.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
F34Parse "" "SELECT repeat('xyzxz', 12)" 0
2+
F14Bind "" "" 0 0 1 0
3+
F6Describe P ""
4+
F9Execute "" 0
5+
F34Parse "" "SELECT repeat('xyzxz', 12)" 0
6+
F14Bind "" "" 0 0 1 0
7+
F6Describe P ""
8+
F9Execute "" 0
9+
F34Parse "" "SELECT repeat('xyzxz', 12)" 0
10+
F14Bind "" "" 0 0 1 0
11+
F6Describe P ""
12+
F9Execute "" 0
13+
F34Parse "" "SELECT repeat('xyzxz', 12)" 0
14+
F14Bind "" "" 0 0 1 0
15+
F6Describe P ""
16+
F9Execute "" 0
17+
F34Parse "" "SELECT repeat('xyzxz', 12)" 0
18+
F14Bind "" "" 0 0 1 0
19+
F6Describe P ""
20+
F9Execute "" 0
21+
F34Parse "" "SELECT repeat('xyzxz', 12)" 0
22+
F14Bind "" "" 0 0 1 0
23+
F6Describe P ""
24+
F9Execute "" 0
25+
F34Parse "" "SELECT repeat('xyzxz', 12)" 0
26+
F14Bind "" "" 0 0 1 0
27+
F6Describe P ""
28+
F9Execute "" 0
29+
F34Parse "" "SELECT repeat('xyzxz', 12)" 0
30+
F14Bind "" "" 0 0 1 0
31+
F6Describe P ""
32+
F9Execute "" 0
33+
F34Parse "" "SELECT repeat('xyzxz', 12)" 0
34+
F14Bind "" "" 0 0 1 0
35+
F6Describe P ""
36+
F9Execute "" 0
37+
F34Parse "" "SELECT repeat('xyzxz', 12)" 0
38+
F14Bind "" "" 0 0 1 0
39+
F6Describe P ""
40+
F9Execute "" 0
41+
F4Flush
42+
B4ParseComplete
43+
B4BindComplete
44+
B31RowDescription 1 "repeat" NNNN 0 NNNN 65535 -1 0
45+
B70DataRow 1 60 'xyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxz'
46+
B13CommandComplete "SELECT 1"
47+
B4ParseComplete
48+
B4BindComplete
49+
B31RowDescription 1 "repeat" NNNN 0 NNNN 65535 -1 0
50+
B70DataRow 1 60 'xyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxz'
51+
B13CommandComplete "SELECT 1"
52+
B4ParseComplete
53+
B4BindComplete
54+
B31RowDescription 1 "repeat" NNNN 0 NNNN 65535 -1 0
55+
B70DataRow 1 60 'xyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxz'
56+
B13CommandComplete "SELECT 1"
57+
B4ParseComplete
58+
B4BindComplete
59+
B31RowDescription 1 "repeat" NNNN 0 NNNN 65535 -1 0
60+
B70DataRow 1 60 'xyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxz'
61+
B13CommandComplete "SELECT 1"
62+
B4ParseComplete
63+
B4BindComplete
64+
B31RowDescription 1 "repeat" NNNN 0 NNNN 65535 -1 0
65+
B70DataRow 1 60 'xyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxz'
66+
B13CommandComplete "SELECT 1"
67+
B4ParseComplete
68+
B4BindComplete
69+
B31RowDescription 1 "repeat" NNNN 0 NNNN 65535 -1 0
70+
B70DataRow 1 60 'xyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxz'
71+
B13CommandComplete "SELECT 1"
72+
B4ParseComplete
73+
B4BindComplete
74+
B31RowDescription 1 "repeat" NNNN 0 NNNN 65535 -1 0
75+
B70DataRow 1 60 'xyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxz'
76+
B13CommandComplete "SELECT 1"
77+
B4ParseComplete
78+
B4BindComplete
79+
B31RowDescription 1 "repeat" NNNN 0 NNNN 65535 -1 0
80+
B70DataRow 1 60 'xyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxz'
81+
B13CommandComplete "SELECT 1"
82+
B4ParseComplete
83+
B4BindComplete
84+
B31RowDescription 1 "repeat" NNNN 0 NNNN 65535 -1 0
85+
B70DataRow 1 60 'xyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxz'
86+
B13CommandComplete "SELECT 1"
87+
B4ParseComplete
88+
B4BindComplete
89+
B31RowDescription 1 "repeat" NNNN 0 NNNN 65535 -1 0
90+
B70DataRow 1 60 'xyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxzxyzxz'
91+
B13CommandComplete "SELECT 1"
92+
F4Terminate

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp