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

Commit878aa41

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 parent419cac0 commit878aa41

File tree

3 files changed

+40
-25
lines changed

3 files changed

+40
-25
lines changed

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

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,19 +2112,12 @@ PQgetResult(PGconn *conn)
21122112
break;
21132113

21142114
casePGASYNC_READY:
2115-
2116-
/*
2117-
* For any query type other than simple query protocol, we advance
2118-
* the command queue here. This is because for simple query
2119-
* protocol we can get the READY state multiple times before the
2120-
* command is actually complete, since the command string can
2121-
* contain many queries. In simple query protocol, the queue
2122-
* advance is done by fe-protocol3 when it receives ReadyForQuery.
2123-
*/
2124-
if (conn->cmd_queue_head&&
2125-
conn->cmd_queue_head->queryclass!=PGQUERY_SIMPLE)
2126-
pqCommandQueueAdvance(conn);
21272115
res=pqPrepareAsyncResult(conn);
2116+
2117+
/* Advance the queue as appropriate */
2118+
pqCommandQueueAdvance(conn, false,
2119+
res->resultStatus==PGRES_PIPELINE_SYNC);
2120+
21282121
if (conn->pipelineStatus!=PQ_PIPELINE_OFF)
21292122
{
21302123
/*
@@ -3007,26 +3000,52 @@ PQexitPipelineMode(PGconn *conn)
30073000

30083001
/*
30093002
* pqCommandQueueAdvance
3010-
*Remove one query from the command queue, when we receive
3011-
*all results from the server that pertain to it.
3003+
*Remove one query from the command queue, if appropriate.
3004+
*
3005+
* If we have received all results corresponding to the head element
3006+
* in the command queue, remove it.
3007+
*
3008+
* In simple query protocol we must not advance the command queue until the
3009+
* ReadyForQuery message has been received. This is because in simple mode a
3010+
* command can have multiple queries, and we must process result for all of
3011+
* them before moving on to the next command.
3012+
*
3013+
* Another consideration is synchronization during error processing in
3014+
* extended query protocol: we refuse to advance the queue past a SYNC queue
3015+
* element, unless the result we've received is also a SYNC. In particular
3016+
* this protects us from advancing when an error is received at an
3017+
* inappropriate moment.
30123018
*/
30133019
void
3014-
pqCommandQueueAdvance(PGconn*conn)
3020+
pqCommandQueueAdvance(PGconn*conn,boolisReadyForQuery,boolgotSync)
30153021
{
30163022
PGcmdQueueEntry*prevquery;
30173023

30183024
if (conn->cmd_queue_head==NULL)
30193025
return;
30203026

3021-
/* delink from queue */
3027+
/*
3028+
* If processing a query of simple query protocol, we only advance the
3029+
* queue when we receive the ReadyForQuery message for it.
3030+
*/
3031+
if (conn->cmd_queue_head->queryclass==PGQUERY_SIMPLE&& !isReadyForQuery)
3032+
return;
3033+
3034+
/*
3035+
* If we're waiting for a SYNC, don't advance the queue until we get one.
3036+
*/
3037+
if (conn->cmd_queue_head->queryclass==PGQUERY_SYNC&& !gotSync)
3038+
return;
3039+
3040+
/* delink element from queue */
30223041
prevquery=conn->cmd_queue_head;
30233042
conn->cmd_queue_head=conn->cmd_queue_head->next;
30243043

30253044
/* If the queue is now empty, reset the tail too */
30263045
if (conn->cmd_queue_head==NULL)
30273046
conn->cmd_queue_tail=NULL;
30283047

3029-
/* and makeit recyclable */
3048+
/* and makethe queue element recyclable */
30303049
prevquery->next=NULL;
30313050
pqRecycleCmdQueueEntry(conn,prevquery);
30323051
}

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,13 +236,8 @@ pqParseInput3(PGconn *conn)
236236
}
237237
else
238238
{
239-
/*
240-
* In simple query protocol, advance the command queue
241-
* (see PQgetResult).
242-
*/
243-
if (conn->cmd_queue_head&&
244-
conn->cmd_queue_head->queryclass==PGQUERY_SIMPLE)
245-
pqCommandQueueAdvance(conn);
239+
/* Advance the command queue and set us idle */
240+
pqCommandQueueAdvance(conn, true, false);
246241
conn->asyncStatus=PGASYNC_IDLE;
247242
}
248243
break;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,8 @@ extern void pqSaveMessageField(PGresult *res, char code,
705705
externvoidpqSaveParameterStatus(PGconn*conn,constchar*name,
706706
constchar*value);
707707
externintpqRowProcessor(PGconn*conn,constchar**errmsgp);
708-
externvoidpqCommandQueueAdvance(PGconn*conn);
708+
externvoidpqCommandQueueAdvance(PGconn*conn,boolisReadyForQuery,
709+
boolgotSync);
709710
externintPQsendQueryContinue(PGconn*conn,constchar*query);
710711

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp