Adjust interaction of libpq pipeline mode with errorMessage resets.
Since commit ffa2e4670, 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 ffa2e4670 came in. However I'm uncertain about whether it interacts with 618c16707. In the absence of user complaints, leave v14 alone. Discussion: https://postgr.es/m/1421785.1645723238@sss.pgh.pa.us
This commit is contained in:
parent
fbee60f6a4
commit
b15f254466
@ -1380,10 +1380,7 @@ pqAppendCmdQueueEntry(PGconn *conn, PGcmdQueueEntry *entry)
|
|||||||
* state, we don't have to do anything.
|
* state, we don't have to do anything.
|
||||||
*/
|
*/
|
||||||
if (conn->asyncStatus == PGASYNC_IDLE)
|
if (conn->asyncStatus == PGASYNC_IDLE)
|
||||||
{
|
|
||||||
pqClearConnErrorState(conn);
|
|
||||||
pqPipelineProcessQueue(conn);
|
pqPipelineProcessQueue(conn);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1730,8 +1727,10 @@ PQsendQueryStart(PGconn *conn, bool newQuery)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the beginning of a query cycle, reset the error state.
|
* If this is the beginning of a query cycle, reset the error state.
|
||||||
|
* However, in pipeline mode with something already queued, the error
|
||||||
|
* buffer belongs to that command and we shouldn't clear it.
|
||||||
*/
|
*/
|
||||||
if (newQuery)
|
if (newQuery && conn->cmd_queue_head == NULL)
|
||||||
pqClearConnErrorState(conn);
|
pqClearConnErrorState(conn);
|
||||||
|
|
||||||
/* Don't try to send if we know there's no live connection. */
|
/* Don't try to send if we know there's no live connection. */
|
||||||
@ -2149,11 +2148,8 @@ PQgetResult(PGconn *conn)
|
|||||||
/*
|
/*
|
||||||
* We're about to return the NULL that terminates the round of
|
* We're about to return the NULL that terminates the round of
|
||||||
* results from the current query; prepare to send the results
|
* results from the current query; prepare to send the results
|
||||||
* of the next query when we're called next. Also, since this
|
* of the next query when we're called next.
|
||||||
* is the start of the results of the next query, clear any
|
|
||||||
* prior error message.
|
|
||||||
*/
|
*/
|
||||||
pqClearConnErrorState(conn);
|
|
||||||
pqPipelineProcessQueue(conn);
|
pqPipelineProcessQueue(conn);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2362,6 +2358,14 @@ PQexecStart(PGconn *conn)
|
|||||||
if (!conn)
|
if (!conn)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since this is the beginning of a query cycle, reset the error state.
|
||||||
|
* However, in pipeline mode with something already queued, the error
|
||||||
|
* buffer belongs to that command and we shouldn't clear it.
|
||||||
|
*/
|
||||||
|
if (conn->cmd_queue_head == NULL)
|
||||||
|
pqClearConnErrorState(conn);
|
||||||
|
|
||||||
if (conn->pipelineStatus != PQ_PIPELINE_OFF)
|
if (conn->pipelineStatus != PQ_PIPELINE_OFF)
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&conn->errorMessage,
|
appendPQExpBufferStr(&conn->errorMessage,
|
||||||
@ -2369,11 +2373,6 @@ PQexecStart(PGconn *conn)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Since this is the beginning of a query cycle, reset the error state.
|
|
||||||
*/
|
|
||||||
pqClearConnErrorState(conn);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Silently discard any prior query result that application didn't eat.
|
* Silently discard any prior query result that application didn't eat.
|
||||||
* This is probably poor design, but it's here for backward compatibility.
|
* This is probably poor design, but it's here for backward compatibility.
|
||||||
@ -2928,7 +2927,10 @@ PQfn(PGconn *conn,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Since this is the beginning of a query cycle, reset the error state.
|
* Since this is the beginning of a query cycle, reset the error state.
|
||||||
|
* However, in pipeline mode with something already queued, the error
|
||||||
|
* buffer belongs to that command and we shouldn't clear it.
|
||||||
*/
|
*/
|
||||||
|
if (conn->cmd_queue_head == NULL)
|
||||||
pqClearConnErrorState(conn);
|
pqClearConnErrorState(conn);
|
||||||
|
|
||||||
if (conn->pipelineStatus != PQ_PIPELINE_OFF)
|
if (conn->pipelineStatus != PQ_PIPELINE_OFF)
|
||||||
@ -3099,6 +3101,12 @@ pqPipelineProcessQueue(PGconn *conn)
|
|||||||
conn->cmd_queue_head == NULL)
|
conn->cmd_queue_head == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset the error state. This and the next couple of steps correspond to
|
||||||
|
* what PQsendQueryStart didn't do for this query.
|
||||||
|
*/
|
||||||
|
pqClearConnErrorState(conn);
|
||||||
|
|
||||||
/* Initialize async result-accumulation state */
|
/* Initialize async result-accumulation state */
|
||||||
pqClearAsyncResult(conn);
|
pqClearAsyncResult(conn);
|
||||||
|
|
||||||
@ -3809,8 +3817,10 @@ PQsetnonblocking(PGconn *conn, int arg)
|
|||||||
* behavior. this is ok because either they are making a transition _from_
|
* behavior. this is ok because either they are making a transition _from_
|
||||||
* or _to_ blocking mode, either way we can block them.
|
* or _to_ blocking mode, either way we can block them.
|
||||||
*
|
*
|
||||||
* Clear error state in case pqFlush adds to it.
|
* Clear error state in case pqFlush adds to it, unless we're actively
|
||||||
|
* pipelining, in which case it seems best not to.
|
||||||
*/
|
*/
|
||||||
|
if (conn->cmd_queue_head == NULL)
|
||||||
pqClearConnErrorState(conn);
|
pqClearConnErrorState(conn);
|
||||||
|
|
||||||
/* if we are going from blocking to non-blocking flush here */
|
/* if we are going from blocking to non-blocking flush here */
|
||||||
@ -4003,6 +4013,7 @@ PQescapeStringConn(PGconn *conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conn->cmd_queue_head == NULL)
|
||||||
pqClearConnErrorState(conn);
|
pqClearConnErrorState(conn);
|
||||||
|
|
||||||
return PQescapeStringInternal(conn, to, from, length, error,
|
return PQescapeStringInternal(conn, to, from, length, error,
|
||||||
@ -4041,6 +4052,7 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
|
|||||||
if (!conn)
|
if (!conn)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (conn->cmd_queue_head == NULL)
|
||||||
pqClearConnErrorState(conn);
|
pqClearConnErrorState(conn);
|
||||||
|
|
||||||
/* Scan the string for characters that must be escaped. */
|
/* Scan the string for characters that must be escaped. */
|
||||||
@ -4306,6 +4318,7 @@ PQescapeByteaConn(PGconn *conn,
|
|||||||
if (!conn)
|
if (!conn)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (conn->cmd_queue_head == NULL)
|
||||||
pqClearConnErrorState(conn);
|
pqClearConnErrorState(conn);
|
||||||
|
|
||||||
return PQescapeByteaInternal(conn, from, from_length, to_length,
|
return PQescapeByteaInternal(conn, from, from_length, to_length,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user