Skip to content

Commit 1d477a9

Browse files
committed
Fix row tracking in pg_stat_statements with extended query protocol
pg_stat_statements relies on EState->es_processed to count the number of rows processed by ExecutorRun(). This proves to be a problem under the extended query protocol when the result of a query is fetched through more than one call of ExecutorRun(), as es_processed is reset each time ExecutorRun() is called. This causes pg_stat_statements to report the number of rows calculated in the last execute fetch, rather than the global sum of all the rows processed. As pquery.c tells, this is a problem when a portal does not use holdStore. For example, DMLs with RETURNING would report a correct tuple count as these do one execution cycle when the query is first executed to fill in the portal's store with one ExecutorRun(), feeding on the portal's store for each follow-up execute fetch depending on the fetch size requested by the client. The fix proposed for this issue is simple with the addition of an extra counter in EState that's preserved across multiple ExecutorRun() calls, incremented with the value calculated in es_processed. This approach is not back-patchable, unfortunately. Note that libpq does not currently give any way to control the fetch size when using the extended v3 protocol, meaning that in-core testing is not possible yet. This issue can be easily verified with the JDBC driver, though, with *autocommit disabled*. Hence, having in-core tests requires more features, left for future discussion: - At least two new libpq routines splitting PQsendQueryGuts(), one for the bind/describe and a second for a series of execute fetches with a custom fetch size, likely in a fashion similar to what JDBC does. - A psql meta-command for the execute phase. This part is not strictly mandatory, still it could be handy. Reported-by: Andrew Dunstan (original discovery by Simon Siggs) Author: Sami Imseih Reviewed-by: Tom Lane, Michael Paquier Discussion: https://postgr.es/m/EBE6C507-9EB6-4142-9E4D-38B1673363A7@amazon.com Discussion: https://postgr.es/m/c90890e7-9c89-c34f-d3c5-d5c763a34bd8@dunslane.net
1 parent 31966b1 commit 1d477a9

File tree

4 files changed

+14
-3
lines changed

4 files changed

+14
-3
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
10601060
queryDesc->plannedstmt->stmt_len,
10611061
PGSS_EXEC,
10621062
queryDesc->totaltime->total * 1000.0, /* convert to msec */
1063-
queryDesc->estate->es_processed,
1063+
queryDesc->estate->es_total_processed,
10641064
&queryDesc->totaltime->bufusage,
10651065
&queryDesc->totaltime->walusage,
10661066
queryDesc->estate->es_jit ? &queryDesc->estate->es_jit->instr : NULL,

src/backend/executor/execMain.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,8 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
289289
* There is no return value, but output tuples (if any) are sent to
290290
* the destination receiver specified in the QueryDesc; and the number
291291
* of tuples processed at the top level can be found in
292-
* estate->es_processed.
292+
* estate->es_processed. The total number of tuples processed in all
293+
* the ExecutorRun calls can be found in estate->es_total_processed.
293294
*
294295
* We provide a function hook variable that lets loadable plugins
295296
* get control when ExecutorRun is called. Such a plugin would
@@ -372,6 +373,12 @@ standard_ExecutorRun(QueryDesc *queryDesc,
372373
execute_once);
373374
}
374375

376+
/*
377+
* Update es_total_processed to keep track of the number of tuples
378+
* processed across multiple ExecutorRun() calls.
379+
*/
380+
estate->es_total_processed += estate->es_processed;
381+
375382
/*
376383
* shutdown tuple receiver, if we started it
377384
*/

src/backend/executor/execUtils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ CreateExecutorState(void)
147147
estate->es_tupleTable = NIL;
148148

149149
estate->es_processed = 0;
150+
estate->es_total_processed = 0;
150151

151152
estate->es_top_eflags = 0;
152153
estate->es_instrument = 0;

src/include/nodes/execnodes.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,10 @@ typedef struct EState
661661

662662
List *es_tupleTable; /* List of TupleTableSlots */
663663

664-
uint64 es_processed; /* # of tuples processed */
664+
uint64 es_processed; /* # of tuples processed during one
665+
* ExecutorRun() call. */
666+
uint64 es_total_processed; /* total # of tuples aggregated across all
667+
* ExecutorRun() calls. */
665668

666669
int es_top_eflags; /* eflags passed to ExecutorStart */
667670
int es_instrument; /* OR of InstrumentOption flags */

0 commit comments

Comments
 (0)