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

Commit1171c6e

Browse files
committed
Fix handling of errors in libpq pipelines
The logic to keep the libpq command queue in sync with queries that havebeen processed had a bug when errors were returned for reasons otherthan problems in queries -- for example, when a connection is lost. Weincorrectly consumed an element from the command queue every time, butthis is wrong and can lead to the queue becoming empty ahead of time,leading to later malfunction: PQgetResult would return nothing,potentially causing the calling application to enter a busy loop.Fix by making the SYNC queue element a barrier that can only be consumedwhen a SYNC message is received.Backpatch to 14.Reported by: Иван Трофимов (Ivan Trofimov) <i.trofimow@yandex.ru>Discussion:https://postgr.es/m/17948-fcace7557e449957@postgresql.org
1 parent25f2a43 commit1171c6e

File tree

3 files changed

+44
-29
lines changed

3 files changed

+44
-29
lines changed

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

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,29 +2119,21 @@ PQgetResult(PGconn *conn)
21192119

21202120
/*
21212121
* We're about to return the NULL that terminates the round of
2122-
* results from the current query; prepare to send the results
2123-
* of the next query, if any, when we're called next. If there's
2124-
* no next element in the command queue, this gets us in IDLE
2125-
* state.
2122+
* results from the current query; prepare to send the results of
2123+
* the next query, if any, when we're called next. If there's no
2124+
* next element in the command queue, this gets us in IDLE state.
21262125
*/
21272126
pqPipelineProcessQueue(conn);
21282127
res=NULL;/* query is complete */
21292128
break;
21302129

21312130
casePGASYNC_READY:
2132-
2133-
/*
2134-
* For any query type other than simple query protocol, we advance
2135-
* the command queue here. This is because for simple query
2136-
* protocol we can get the READY state multiple times before the
2137-
* command is actually complete, since the command string can
2138-
* contain many queries. In simple query protocol, the queue
2139-
* advance is done by fe-protocol3 when it receives ReadyForQuery.
2140-
*/
2141-
if (conn->cmd_queue_head&&
2142-
conn->cmd_queue_head->queryclass!=PGQUERY_SIMPLE)
2143-
pqCommandQueueAdvance(conn);
21442131
res=pqPrepareAsyncResult(conn);
2132+
2133+
/* Advance the queue as appropriate */
2134+
pqCommandQueueAdvance(conn, false,
2135+
res->resultStatus==PGRES_PIPELINE_SYNC);
2136+
21452137
if (conn->pipelineStatus!=PQ_PIPELINE_OFF)
21462138
{
21472139
/*
@@ -3040,26 +3032,52 @@ PQexitPipelineMode(PGconn *conn)
30403032

30413033
/*
30423034
* pqCommandQueueAdvance
3043-
*Remove one query from the command queue, when we receive
3044-
*all results from the server that pertain to it.
3035+
*Remove one query from the command queue, if appropriate.
3036+
*
3037+
* If we have received all results corresponding to the head element
3038+
* in the command queue, remove it.
3039+
*
3040+
* In simple query protocol we must not advance the command queue until the
3041+
* ReadyForQuery message has been received. This is because in simple mode a
3042+
* command can have multiple queries, and we must process result for all of
3043+
* them before moving on to the next command.
3044+
*
3045+
* Another consideration is synchronization during error processing in
3046+
* extended query protocol: we refuse to advance the queue past a SYNC queue
3047+
* element, unless the result we've received is also a SYNC. In particular
3048+
* this protects us from advancing when an error is received at an
3049+
* inappropriate moment.
30453050
*/
30463051
void
3047-
pqCommandQueueAdvance(PGconn*conn)
3052+
pqCommandQueueAdvance(PGconn*conn,boolisReadyForQuery,boolgotSync)
30483053
{
30493054
PGcmdQueueEntry*prevquery;
30503055

30513056
if (conn->cmd_queue_head==NULL)
30523057
return;
30533058

3054-
/* delink from queue */
3059+
/*
3060+
* If processing a query of simple query protocol, we only advance the
3061+
* queue when we receive the ReadyForQuery message for it.
3062+
*/
3063+
if (conn->cmd_queue_head->queryclass==PGQUERY_SIMPLE&& !isReadyForQuery)
3064+
return;
3065+
3066+
/*
3067+
* If we're waiting for a SYNC, don't advance the queue until we get one.
3068+
*/
3069+
if (conn->cmd_queue_head->queryclass==PGQUERY_SYNC&& !gotSync)
3070+
return;
3071+
3072+
/* delink element from queue */
30553073
prevquery=conn->cmd_queue_head;
30563074
conn->cmd_queue_head=conn->cmd_queue_head->next;
30573075

30583076
/* If the queue is now empty, reset the tail too */
30593077
if (conn->cmd_queue_head==NULL)
30603078
conn->cmd_queue_tail=NULL;
30613079

3062-
/* and makeit recyclable */
3080+
/* and makethe queue element recyclable */
30633081
prevquery->next=NULL;
30643082
pqRecycleCmdQueueEntry(conn,prevquery);
30653083
}
@@ -3083,6 +3101,7 @@ pqPipelineProcessQueue(PGconn *conn)
30833101
return;
30843102

30853103
casePGASYNC_IDLE:
3104+
30863105
/*
30873106
* If we're in IDLE mode and there's some command in the queue,
30883107
* get us into PIPELINE_IDLE mode and process normally. Otherwise

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,8 @@ pqParseInput3(PGconn *conn)
240240
}
241241
else
242242
{
243-
/*
244-
* In simple query protocol, advance the command queue
245-
* (see PQgetResult).
246-
*/
247-
if (conn->cmd_queue_head&&
248-
conn->cmd_queue_head->queryclass==PGQUERY_SIMPLE)
249-
pqCommandQueueAdvance(conn);
243+
/* Advance the command queue and set us idle */
244+
pqCommandQueueAdvance(conn, true, false);
250245
conn->asyncStatus=PGASYNC_IDLE;
251246
}
252247
break;

‎src/interfaces/libpq/libpq-int.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,8 @@ extern void pqSaveMessageField(PGresult *res, char code,
673673
externvoidpqSaveParameterStatus(PGconn*conn,constchar*name,
674674
constchar*value);
675675
externintpqRowProcessor(PGconn*conn,constchar**errmsgp);
676-
externvoidpqCommandQueueAdvance(PGconn*conn);
676+
externvoidpqCommandQueueAdvance(PGconn*conn,boolisReadyForQuery,
677+
boolgotSync);
677678
externintPQsendQueryContinue(PGconn*conn,constchar*query);
678679

679680
/* === in fe-protocol3.c === */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp