Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b15f254

Browse files
committed
Adjust interaction of libpq pipeline mode with errorMessage resets.
Since commit ffa2e46, libpq resets conn->errorMessage only when starting a new query. However, the later introduction of pipelining requires a further refinement: the "start of query" isn't necessarily when it's submitted to PQsendQueryStart. If we clear at that point then we risk dropping text for an error that the application has not noticed yet. Instead, when queuing a query while a previous query is still in flight, leave errorMessage alone; reset it when we begin to process the next query in pqPipelineProcessQueue. Perhaps this should be back-patched to v14 where ffa2e46 came in. However I'm uncertain about whether it interacts with 618c167. In the absence of user complaints, leave v14 alone. Discussion: https://postgr.es/m/1421785.1645723238@sss.pgh.pa.us
1 parent fbee60f commit b15f254

File tree

1 file changed

+32
-19
lines changed

1 file changed

+32
-19
lines changed

src/interfaces/libpq/fe-exec.c

+32-19
Original file line numberDiff line numberDiff line change
@@ -1380,10 +1380,7 @@ pqAppendCmdQueueEntry(PGconn *conn, PGcmdQueueEntry *entry)
13801380
* state, we don't have to do anything.
13811381
*/
13821382
if (conn->asyncStatus == PGASYNC_IDLE)
1383-
{
1384-
pqClearConnErrorState(conn);
13851383
pqPipelineProcessQueue(conn);
1386-
}
13871384
break;
13881385
}
13891386
}
@@ -1730,8 +1727,10 @@ PQsendQueryStart(PGconn *conn, bool newQuery)
17301727

17311728
/*
17321729
* If this is the beginning of a query cycle, reset the error state.
1730+
* However, in pipeline mode with something already queued, the error
1731+
* buffer belongs to that command and we shouldn't clear it.
17331732
*/
1734-
if (newQuery)
1733+
if (newQuery && conn->cmd_queue_head == NULL)
17351734
pqClearConnErrorState(conn);
17361735

17371736
/* Don't try to send if we know there's no live connection. */
@@ -2149,11 +2148,8 @@ PQgetResult(PGconn *conn)
21492148
/*
21502149
* We're about to return the NULL that terminates the round of
21512150
* results from the current query; prepare to send the results
2152-
* of the next query when we're called next. Also, since this
2153-
* is the start of the results of the next query, clear any
2154-
* prior error message.
2151+
* of the next query when we're called next.
21552152
*/
2156-
pqClearConnErrorState(conn);
21572153
pqPipelineProcessQueue(conn);
21582154
}
21592155
break;
@@ -2362,18 +2358,21 @@ PQexecStart(PGconn *conn)
23622358
if (!conn)
23632359
return false;
23642360

2361+
/*
2362+
* Since this is the beginning of a query cycle, reset the error state.
2363+
* However, in pipeline mode with something already queued, the error
2364+
* buffer belongs to that command and we shouldn't clear it.
2365+
*/
2366+
if (conn->cmd_queue_head == NULL)
2367+
pqClearConnErrorState(conn);
2368+
23652369
if (conn->pipelineStatus != PQ_PIPELINE_OFF)
23662370
{
23672371
appendPQExpBufferStr(&conn->errorMessage,
23682372
libpq_gettext("synchronous command execution functions are not allowed in pipeline mode\n"));
23692373
return false;
23702374
}
23712375

2372-
/*
2373-
* Since this is the beginning of a query cycle, reset the error state.
2374-
*/
2375-
pqClearConnErrorState(conn);
2376-
23772376
/*
23782377
* Silently discard any prior query result that application didn't eat.
23792378
* This is probably poor design, but it's here for backward compatibility.
@@ -2928,8 +2927,11 @@ PQfn(PGconn *conn,
29282927

29292928
/*
29302929
* Since this is the beginning of a query cycle, reset the error state.
2930+
* However, in pipeline mode with something already queued, the error
2931+
* buffer belongs to that command and we shouldn't clear it.
29312932
*/
2932-
pqClearConnErrorState(conn);
2933+
if (conn->cmd_queue_head == NULL)
2934+
pqClearConnErrorState(conn);
29332935

29342936
if (conn->pipelineStatus != PQ_PIPELINE_OFF)
29352937
{
@@ -3099,6 +3101,12 @@ pqPipelineProcessQueue(PGconn *conn)
30993101
conn->cmd_queue_head == NULL)
31003102
return;
31013103

3104+
/*
3105+
* Reset the error state. This and the next couple of steps correspond to
3106+
* what PQsendQueryStart didn't do for this query.
3107+
*/
3108+
pqClearConnErrorState(conn);
3109+
31023110
/* Initialize async result-accumulation state */
31033111
pqClearAsyncResult(conn);
31043112

@@ -3809,9 +3817,11 @@ PQsetnonblocking(PGconn *conn, int arg)
38093817
* behavior. this is ok because either they are making a transition _from_
38103818
* or _to_ blocking mode, either way we can block them.
38113819
*
3812-
* Clear error state in case pqFlush adds to it.
3820+
* Clear error state in case pqFlush adds to it, unless we're actively
3821+
* pipelining, in which case it seems best not to.
38133822
*/
3814-
pqClearConnErrorState(conn);
3823+
if (conn->cmd_queue_head == NULL)
3824+
pqClearConnErrorState(conn);
38153825

38163826
/* if we are going from blocking to non-blocking flush here */
38173827
if (pqFlush(conn))
@@ -4003,7 +4013,8 @@ PQescapeStringConn(PGconn *conn,
40034013
return 0;
40044014
}
40054015

4006-
pqClearConnErrorState(conn);
4016+
if (conn->cmd_queue_head == NULL)
4017+
pqClearConnErrorState(conn);
40074018

40084019
return PQescapeStringInternal(conn, to, from, length, error,
40094020
conn->client_encoding,
@@ -4041,7 +4052,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
40414052
if (!conn)
40424053
return NULL;
40434054

4044-
pqClearConnErrorState(conn);
4055+
if (conn->cmd_queue_head == NULL)
4056+
pqClearConnErrorState(conn);
40454057

40464058
/* Scan the string for characters that must be escaped. */
40474059
for (s = str; (s - str) < len && *s != '\0'; ++s)
@@ -4306,7 +4318,8 @@ PQescapeByteaConn(PGconn *conn,
43064318
if (!conn)
43074319
return NULL;
43084320

4309-
pqClearConnErrorState(conn);
4321+
if (conn->cmd_queue_head == NULL)
4322+
pqClearConnErrorState(conn);
43104323

43114324
return PQescapeByteaInternal(conn, from, from_length, to_length,
43124325
conn->std_strings,

0 commit comments

Comments
 (0)