From 6a6bfb5ae89ae2399431f77a03d79961ded6d2df Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Sun, 5 Apr 2026 17:28:29 -0400 Subject: [PATCH v8-alt 5/7] Add EXPLAIN (IO) instrumentation for SeqScan --- .../postgres_fdw/expected/postgres_fdw.out | 8 +- contrib/postgres_fdw/sql/postgres_fdw.sql | 8 +- src/backend/commands/explain.c | 25 ++++ src/backend/executor/execParallel.c | 11 ++ src/backend/executor/nodeSeqscan.c | 116 ++++++++++++++++-- src/include/executor/instrument_node.h | 19 +++ src/include/executor/nodeSeqscan.h | 9 ++ src/include/nodes/execnodes.h | 1 + src/test/isolation/expected/merge-update.out | 2 +- src/test/isolation/specs/merge-update.spec | 5 +- src/test/regress/expected/explain.out | 26 +++- src/test/regress/expected/partition_prune.out | 34 ++--- src/test/regress/sql/explain.sql | 12 +- src/test/regress/sql/partition_prune.sql | 34 ++--- src/tools/pgindent/typedefs.list | 2 + 15 files changed, 247 insertions(+), 65 deletions(-) diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index cd22553236f..6b460a90158 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -11980,7 +11980,7 @@ SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c Filter: (async_pt_3.a = local_tbl.a) (15 rows) -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF, IO OFF) SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c = 'bar'; QUERY PLAN ---------------------------------------------------------------------------------- @@ -12226,7 +12226,7 @@ SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt W Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((a < 3000)) (20 rows) -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF, IO OFF) SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a; QUERY PLAN -------------------------------------------------------------------------------------------- @@ -12270,7 +12270,7 @@ SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1; Filter: (t1_3.b === 505) (14 rows) -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF, IO OFF) SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1; QUERY PLAN ---------------------------------------------------------------------------- @@ -12430,7 +12430,7 @@ DELETE FROM async_pt WHERE b = 0 RETURNING *; DELETE FROM async_p1; DELETE FROM async_p2; DELETE FROM async_p3; -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF, IO OFF) SELECT * FROM async_pt; QUERY PLAN ---------------------------------------------------------------------------- diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 59963e298b8..e8b96a16849 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -4093,7 +4093,7 @@ ALTER FOREIGN TABLE async_p2 OPTIONS (use_remote_estimate 'true'); EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c = 'bar'; -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF, IO OFF) SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c = 'bar'; SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c = 'bar'; @@ -4168,13 +4168,13 @@ ANALYZE local_tbl; EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a; -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF, IO OFF) SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a; SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a; EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1; -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF, IO OFF) SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1; SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1; @@ -4226,7 +4226,7 @@ DELETE FROM async_p1; DELETE FROM async_p2; DELETE FROM async_p3; -EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF, IO OFF) SELECT * FROM async_pt; -- Clean up diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 0fab21a5cfa..56c749c0d86 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -2031,6 +2031,7 @@ ExplainNode(PlanState *planstate, List *ancestors, planstate, es); if (IsA(plan, CteScan)) show_ctescan_info(castNode(CteScanState, planstate), es); + show_scan_io_usage((ScanState *) planstate, es); break; case T_Gather: { @@ -4085,6 +4086,30 @@ show_scan_io_usage(ScanState *planstate, ExplainState *es) } } + break; + } + case T_SeqScan: + { + SharedSeqScanInstrumentation *sinstrument + = ((SeqScanState *) planstate)->sinstrument; + + if (sinstrument) + { + for (int i = 0; i < sinstrument->num_workers; ++i) + { + SeqScanInstrumentation *winstrument = &sinstrument->sinstrument[i]; + + AccumulateIOStats(&stats, &winstrument->stats.io); + + if (!es->workers_state) + continue; + + ExplainOpenWorker(i, es); + print_io_usage(es, &winstrument->stats.io); + ExplainCloseWorker(i, es); + } + } + break; } default: diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index 8d5c69ec85e..8c2ee4cd463 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -253,6 +253,9 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e) if (planstate->plan->parallel_aware) ExecSeqScanEstimate((SeqScanState *) planstate, e->pcxt); + /* even when not parallel-aware, for EXPLAIN ANALYZE */ + ExecSeqScanInstrumentEstimate((SeqScanState *) planstate, + e->pcxt); break; case T_IndexScanState: if (planstate->plan->parallel_aware) @@ -496,6 +499,9 @@ ExecParallelInitializeDSM(PlanState *planstate, if (planstate->plan->parallel_aware) ExecSeqScanInitializeDSM((SeqScanState *) planstate, d->pcxt); + /* even when not parallel-aware, for EXPLAIN ANALYZE */ + ExecSeqScanInstrumentInitDSM((SeqScanState *) planstate, + d->pcxt); break; case T_IndexScanState: if (planstate->plan->parallel_aware) @@ -1144,6 +1150,9 @@ ExecParallelRetrieveInstrumentation(PlanState *planstate, case T_BitmapHeapScanState: ExecBitmapHeapRetrieveInstrumentation((BitmapHeapScanState *) planstate); break; + case T_SeqScanState: + ExecSeqScanRetrieveInstrumentation((SeqScanState *) planstate); + break; default: break; } @@ -1384,6 +1393,8 @@ ExecParallelInitializeWorker(PlanState *planstate, ParallelWorkerContext *pwcxt) case T_SeqScanState: if (planstate->plan->parallel_aware) ExecSeqScanInitializeWorker((SeqScanState *) planstate, pwcxt); + /* even when not parallel-aware, for EXPLAIN ANALYZE */ + ExecSeqScanInstrumentInitWorker((SeqScanState *) planstate, pwcxt); break; case T_IndexScanState: if (planstate->plan->parallel_aware) diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 04803b0e37d..d169cb6b3c2 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -29,6 +29,7 @@ #include "access/relscan.h" #include "access/tableam.h" +#include "executor/execParallel.h" #include "executor/execScan.h" #include "executor/executor.h" #include "executor/nodeSeqscan.h" @@ -65,15 +66,21 @@ SeqNext(SeqScanState *node) if (scandesc == NULL) { + uint32 flags = SO_NONE; + + if (ScanRelIsReadOnly(&node->ss)) + flags |= SO_HINT_REL_READ_ONLY; + + if (estate->es_instrument) + flags |= SO_SCAN_INSTRUMENT; + /* * We reach here if the scan is not parallel, or if we're serially * executing a scan that was planned to be parallel. */ scandesc = table_beginscan(node->ss.ss_currentRelation, estate->es_snapshot, - 0, NULL, - ScanRelIsReadOnly(&node->ss) ? - SO_HINT_REL_READ_ONLY : SO_NONE); + 0, NULL, flags); node->ss.ss_currentScanDesc = scandesc; } @@ -297,6 +304,24 @@ ExecEndSeqScan(SeqScanState *node) { TableScanDesc scanDesc; + /* + * Collect IO stats for this process into shared instrumentation. + */ + if (node->sinstrument != NULL && IsParallelWorker()) + { + SeqScanInstrumentation *si; + + Assert(ParallelWorkerNumber <= node->sinstrument->num_workers); + si = &node->sinstrument->sinstrument[ParallelWorkerNumber]; + + if (node->ss.ss_currentScanDesc && + node->ss.ss_currentScanDesc->rs_instrument) + { + AccumulateIOStats(&si->stats.io, + &node->ss.ss_currentScanDesc->rs_instrument->io); + } + } + /* * get information from node */ @@ -370,6 +395,13 @@ ExecSeqScanInitializeDSM(SeqScanState *node, { EState *estate = node->ss.ps.state; ParallelTableScanDesc pscan; + uint32 flags = SO_NONE; + + if (ScanRelIsReadOnly(&node->ss)) + flags |= SO_HINT_REL_READ_ONLY; + + if (estate->es_instrument) + flags |= SO_SCAN_INSTRUMENT; pscan = shm_toc_allocate(pcxt->toc, node->pscan_len); table_parallelscan_initialize(node->ss.ss_currentRelation, @@ -378,9 +410,7 @@ ExecSeqScanInitializeDSM(SeqScanState *node, shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan); node->ss.ss_currentScanDesc = - table_beginscan_parallel(node->ss.ss_currentRelation, pscan, - ScanRelIsReadOnly(&node->ss) ? - SO_HINT_REL_READ_ONLY : SO_NONE); + table_beginscan_parallel(node->ss.ss_currentRelation, pscan, flags); } /* ---------------------------------------------------------------- @@ -410,10 +440,78 @@ ExecSeqScanInitializeWorker(SeqScanState *node, ParallelWorkerContext *pwcxt) { ParallelTableScanDesc pscan; + uint32 flags = SO_NONE; + + if (ScanRelIsReadOnly(&node->ss)) + flags |= SO_HINT_REL_READ_ONLY; + + if (node->ss.ps.state->es_instrument) + flags |= SO_SCAN_INSTRUMENT; pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false); node->ss.ss_currentScanDesc = - table_beginscan_parallel(node->ss.ss_currentRelation, pscan, - ScanRelIsReadOnly(&node->ss) ? - SO_HINT_REL_READ_ONLY : SO_NONE); + table_beginscan_parallel(node->ss.ss_currentRelation, pscan, flags); +} + +void +ExecSeqScanInstrumentEstimate(SeqScanState *node, ParallelContext *pcxt) +{ + EState *estate = node->ss.ps.state; + + if (!estate->es_instrument || pcxt->nworkers == 0) + return; + + shm_toc_estimate_chunk(&pcxt->estimator, + offsetof(SharedSeqScanInstrumentation, sinstrument) + + sizeof(SeqScanInstrumentation) * pcxt->nworkers); + shm_toc_estimate_keys(&pcxt->estimator, 1); +} + +void +ExecSeqScanInstrumentInitDSM(SeqScanState *node, ParallelContext *pcxt) +{ + EState *estate = node->ss.ps.state; + SharedSeqScanInstrumentation *sinstrument; + Size size; + + if (!estate->es_instrument || pcxt->nworkers == 0) + return; + + size = offsetof(SharedSeqScanInstrumentation, sinstrument) + + sizeof(SeqScanInstrumentation) * pcxt->nworkers; + sinstrument = shm_toc_allocate(pcxt->toc, size); + memset(sinstrument, 0, size); + sinstrument->num_workers = pcxt->nworkers; + shm_toc_insert(pcxt->toc, + node->ss.ps.plan->plan_node_id + PARALLEL_KEY_SCAN_INSTRUMENT_OFFSET, + sinstrument); + node->sinstrument = sinstrument; +} + +void +ExecSeqScanInstrumentInitWorker(SeqScanState *node, + ParallelWorkerContext *pwcxt) +{ + if (!node->ss.ps.state->es_instrument) + return; + + node->sinstrument = shm_toc_lookup(pwcxt->toc, + node->ss.ps.plan->plan_node_id + PARALLEL_KEY_SCAN_INSTRUMENT_OFFSET, + true); +} + +void +ExecSeqScanRetrieveInstrumentation(SeqScanState *node) +{ + SharedSeqScanInstrumentation *sinstrument = node->sinstrument; + Size size; + + if (sinstrument == NULL) + return; + + size = offsetof(SharedSeqScanInstrumentation, sinstrument) + + sinstrument->num_workers * sizeof(SeqScanInstrumentation); + + node->sinstrument = palloc(size); + memcpy(node->sinstrument, sinstrument, size); } diff --git a/src/include/executor/instrument_node.h b/src/include/executor/instrument_node.h index 56a695304dd..b7226df6840 100644 --- a/src/include/executor/instrument_node.h +++ b/src/include/executor/instrument_node.h @@ -258,4 +258,23 @@ typedef struct SharedIncrementalSortInfo IncrementalSortInfo sinfo[FLEXIBLE_ARRAY_MEMBER]; } SharedIncrementalSortInfo; + +/* --------------------- + * Instrumentation information for sequential scans + * --------------------- + */ +typedef struct SeqScanInstrumentation +{ + TableScanInstrumentation stats; +} SeqScanInstrumentation; + +/* + * Shared memory container for per-worker information + */ +typedef struct SharedSeqScanInstrumentation +{ + int num_workers; + SeqScanInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]; +} SharedSeqScanInstrumentation; + #endif /* INSTRUMENT_NODE_H */ diff --git a/src/include/executor/nodeSeqscan.h b/src/include/executor/nodeSeqscan.h index 7a1490596fb..9c0ad4879d7 100644 --- a/src/include/executor/nodeSeqscan.h +++ b/src/include/executor/nodeSeqscan.h @@ -28,4 +28,13 @@ extern void ExecSeqScanReInitializeDSM(SeqScanState *node, ParallelContext *pcxt extern void ExecSeqScanInitializeWorker(SeqScanState *node, ParallelWorkerContext *pwcxt); +/* instrument support */ +extern void ExecSeqScanInstrumentEstimate(SeqScanState *node, + ParallelContext *pcxt); +extern void ExecSeqScanInstrumentInitDSM(SeqScanState *node, + ParallelContext *pcxt); +extern void ExecSeqScanInstrumentInitWorker(SeqScanState *node, + ParallelWorkerContext *pwcxt); +extern void ExecSeqScanRetrieveInstrumentation(SeqScanState *node); + #endif /* NODESEQSCAN_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 090cfccf65f..ee9ca731f70 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1666,6 +1666,7 @@ typedef struct SeqScanState { ScanState ss; /* its first field is NodeTag */ Size pscan_len; /* size of parallel heap scan descriptor */ + struct SharedSeqScanInstrumentation *sinstrument; } SeqScanState; /* ---------------- diff --git a/src/test/isolation/expected/merge-update.out b/src/test/isolation/expected/merge-update.out index 821565b4303..dd9c67c4dc1 100644 --- a/src/test/isolation/expected/merge-update.out +++ b/src/test/isolation/expected/merge-update.out @@ -358,7 +358,7 @@ step pa_merge1: step explain_pa_merge2a: SELECT explain_filter($$ - EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF, SUMMARY OFF, BUFFERS OFF) + EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF, SUMMARY OFF, BUFFERS OFF, IO OFF) MERGE INTO pa_target t USING (SELECT 1 as key, 'pa_merge2a' as val) s ON s.key = t.key diff --git a/src/test/isolation/specs/merge-update.spec b/src/test/isolation/specs/merge-update.spec index b902779edd6..cf387eccefc 100644 --- a/src/test/isolation/specs/merge-update.spec +++ b/src/test/isolation/specs/merge-update.spec @@ -33,6 +33,9 @@ setup FOR ln IN EXECUTE $1 LOOP -- Ignore hash memory usage because it varies depending on the system CONTINUE WHEN (ln ~ 'Memory Usage'); + -- Ignore prefetch and I/O because it varies depending on the system + CONTINUE WHEN (ln ~ 'Prefetch'); + CONTINUE WHEN (ln ~ 'I/O'); RETURN NEXT ln; END LOOP; END; @@ -165,7 +168,7 @@ step "pa_merge2a" step "explain_pa_merge2a" { SELECT explain_filter($$ - EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF, SUMMARY OFF, BUFFERS OFF) + EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF, SUMMARY OFF, BUFFERS OFF, IO OFF) MERGE INTO pa_target t USING (SELECT 1 as key, 'pa_merge2a' as val) s ON s.key = t.key diff --git a/src/test/regress/expected/explain.out b/src/test/regress/expected/explain.out index d7754c6f2cb..3e504911db4 100644 --- a/src/test/regress/expected/explain.out +++ b/src/test/regress/expected/explain.out @@ -85,7 +85,7 @@ select explain_filter('explain (analyze, buffers off, io off, verbose) select * Execution Time: N.N ms (4 rows) -select explain_filter('explain (analyze, buffers, format text) select * from int8_tbl i8'); +select explain_filter('explain (analyze, buffers, io off, format text) select * from int8_tbl i8'); explain_filter ------------------------------------------------------------------------------------------------- Seq Scan on int8_tbl i8 (cost=N.N..N.N rows=N width=N) (actual time=N.N..N.N rows=N.N loops=N) @@ -119,6 +119,13 @@ explain_filter N.N N false + N.N + N + N + N + N + N.N + N.N N N N @@ -166,6 +173,13 @@ explain_filter Actual Rows: N.N Actual Loops: N Disabled: false + Average Prefetch Distance: N.N + Max Prefetch Distance: N + Prefetch Capacity: N + I/O Count: N + I/O Waits: N + Average I/O Size: N.N + Average I/Os In Progress: N.N Shared Hit Blocks: N Shared Read Blocks: N Shared Dirtied Blocks: N @@ -286,7 +300,7 @@ select explain_filter('explain verbose select sum(unique1) over w1, sum(unique2) -- Check output including I/O timings. These fields are conditional -- but always set in JSON format, so check them only in this case. set track_io_timing = on; -select explain_filter('explain (analyze, buffers, format json) select * from int8_tbl i8'); +select explain_filter('explain (analyze, buffers, io off, format json) select * from int8_tbl i8'); explain_filter ------------------------------------- [ + @@ -421,7 +435,7 @@ select explain_filter('explain (memory, summary, format yaml) select * from int8 Planning Time: N.N (1 row) -select explain_filter('explain (memory, analyze, format json) select * from int8_tbl i8'); +select explain_filter('explain (memory, analyze, io off, format json) select * from int8_tbl i8'); explain_filter ------------------------------------ [ + @@ -524,7 +538,7 @@ set parallel_tuple_cost=0; set min_parallel_table_scan_size=0; set max_parallel_workers_per_gather=4; select jsonb_pretty( - explain_filter_to_json('explain (analyze, verbose, buffers, format json) + explain_filter_to_json('explain (analyze, verbose, buffers, io off, format json) select * from tenk1 order by tenthous') -- remove "Workers" node of the Seq Scan plan node #- '{0,Plan,Plans,0,Plans,0,Workers}' @@ -749,7 +763,7 @@ select explain_filter('explain (analyze,buffers off,io off,serialize) select * f Execution Time: N.N ms (4 rows) -select explain_filter('explain (analyze,serialize text,buffers,timing off) select * from int8_tbl i8'); +select explain_filter('explain (analyze,serialize text,buffers,io off,timing off) select * from int8_tbl i8'); explain_filter ----------------------------------------------------------------------------------- Seq Scan on int8_tbl i8 (cost=N.N..N.N rows=N width=N) (actual rows=N.N loops=N) @@ -758,7 +772,7 @@ select explain_filter('explain (analyze,serialize text,buffers,timing off) selec Execution Time: N.N ms (4 rows) -select explain_filter('explain (analyze,serialize binary,buffers,timing) select * from int8_tbl i8'); +select explain_filter('explain (analyze,serialize binary,buffers,io off,timing) select * from int8_tbl i8'); explain_filter ------------------------------------------------------------------------------------------------- Seq Scan on int8_tbl i8 (cost=N.N..N.N rows=N width=N) (actual time=N.N..N.N rows=N.N loops=N) diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index 1012be91689..6bd15f26aec 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -2315,7 +2315,7 @@ begin; -- Test run-time pruning using stable functions create function list_part_fn(int) returns int as $$ begin return $1; end;$$ language plpgsql stable; -- Ensure pruning works using a stable function containing no Vars -explain (analyze, costs off, summary off, timing off, buffers off) select * from list_part where a = list_part_fn(1); +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from list_part where a = list_part_fn(1); QUERY PLAN --------------------------------------------------------------------- Append (actual rows=1.00 loops=1) @@ -2325,7 +2325,7 @@ explain (analyze, costs off, summary off, timing off, buffers off) select * from (4 rows) -- Ensure pruning does not take place when the function has a Var parameter -explain (analyze, costs off, summary off, timing off, buffers off) select * from list_part where a = list_part_fn(a); +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from list_part where a = list_part_fn(a); QUERY PLAN --------------------------------------------------------------------- Append (actual rows=4.00 loops=1) @@ -2340,7 +2340,7 @@ explain (analyze, costs off, summary off, timing off, buffers off) select * from (9 rows) -- Ensure pruning does not take place when the expression contains a Var. -explain (analyze, costs off, summary off, timing off, buffers off) select * from list_part where a = list_part_fn(1) + a; +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from list_part where a = list_part_fn(1) + a; QUERY PLAN --------------------------------------------------------------------- Append (actual rows=0.00 loops=1) @@ -2376,7 +2376,7 @@ declare ln text; begin for ln in - execute format('explain (analyze, costs off, summary off, timing off, buffers off) %s', + execute format('explain (analyze, costs off, summary off, timing off, buffers off, io off) %s', $1) loop ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N'); @@ -2687,7 +2687,7 @@ reset parallel_tuple_cost; reset min_parallel_table_scan_size; reset max_parallel_workers_per_gather; -- Test run-time partition pruning with an initplan -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 from lprt_a); QUERY PLAN ---------------------------------------------------------------------------- @@ -2864,7 +2864,7 @@ union all select tableoid::regclass,a,b from ab ) ab where a = $1 and b = (select -10); -- Ensure the xy_1 subplan is not pruned. -explain (analyze, costs off, summary off, timing off, buffers off) execute ab_q6(1); +explain (analyze, costs off, summary off, timing off, buffers off, io off) execute ab_q6(1); QUERY PLAN ------------------------------------------------------------- Append (actual rows=0.00 loops=1) @@ -3019,7 +3019,7 @@ create index tprt6_idx on tprt_6 (col1); insert into tprt values (10), (20), (501), (502), (505), (1001), (4500); set enable_hashjoin = off; set enable_mergejoin = off; -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 join tprt on tbl1.col1 > tprt.col1; QUERY PLAN ----------------------------------------------------------------------------- @@ -3046,7 +3046,7 @@ select * from tbl1 join tprt on tbl1.col1 > tprt.col1; Index Searches: 0 (21 rows) -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; QUERY PLAN ----------------------------------------------------------------------------- @@ -3097,7 +3097,7 @@ order by tbl1.col1, tprt.col1; -- Multiple partitions insert into tbl1 values (1001), (1010), (1011); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; QUERY PLAN ----------------------------------------------------------------------------- @@ -3124,7 +3124,7 @@ select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; Index Searches: 0 (21 rows) -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 inner join tprt on tbl1.col1 = tprt.col1; QUERY PLAN ----------------------------------------------------------------------------- @@ -3194,7 +3194,7 @@ order by tbl1.col1, tprt.col1; -- Last partition delete from tbl1; insert into tbl1 values (4400); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 join tprt on tbl1.col1 < tprt.col1; QUERY PLAN ----------------------------------------------------------------------------- @@ -3232,7 +3232,7 @@ order by tbl1.col1, tprt.col1; -- No matching partition delete from tbl1; insert into tbl1 values (10000); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; QUERY PLAN ------------------------------------------------------------------- @@ -3478,7 +3478,7 @@ create table mc3p1 partition of mc3p create table mc3p2 partition of mc3p for values from (2, minvalue, minvalue) to (3, maxvalue, maxvalue); insert into mc3p values (0, 1, 1), (1, 1, 1), (2, 1, 1); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from mc3p where a < 3 and abs(b) = 1; QUERY PLAN ----------------------------------------------------------- @@ -3498,7 +3498,7 @@ select * from mc3p where a < 3 and abs(b) = 1; -- prepare ps1 as select * from mc3p where a = $1 and abs(b) < (select 3); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) execute ps1(1); QUERY PLAN ------------------------------------------------------------------ @@ -3513,7 +3513,7 @@ execute ps1(1); deallocate ps1; prepare ps2 as select * from mc3p where a <= $1 and abs(b) < (select 3); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) execute ps2(1); QUERY PLAN ------------------------------------------------------------------- @@ -3535,7 +3535,7 @@ insert into boolvalues values('t'),('f'); create table boolp (a bool) partition by list (a); create table boolp_t partition of boolp for values in('t'); create table boolp_f partition of boolp for values in('f'); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from boolp where a = (select value from boolvalues where value); QUERY PLAN -------------------------------------------------------------- @@ -3550,7 +3550,7 @@ select * from boolp where a = (select value from boolvalues where value); Filter: (a = (InitPlan expr_1).col1) (9 rows) -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from boolp where a = (select value from boolvalues where not value); QUERY PLAN -------------------------------------------------------------- diff --git a/src/test/regress/sql/explain.sql b/src/test/regress/sql/explain.sql index dbd210a07f2..b7907a228fa 100644 --- a/src/test/regress/sql/explain.sql +++ b/src/test/regress/sql/explain.sql @@ -65,7 +65,7 @@ explain (costs off) select 1 as a, 2 as b having false; select explain_filter('explain select * from int8_tbl i8'); select explain_filter('explain (analyze, buffers off, io off) select * from int8_tbl i8'); select explain_filter('explain (analyze, buffers off, io off, verbose) select * from int8_tbl i8'); -select explain_filter('explain (analyze, buffers, format text) select * from int8_tbl i8'); +select explain_filter('explain (analyze, buffers, io off, format text) select * from int8_tbl i8'); select explain_filter('explain (buffers, format text) select * from int8_tbl i8'); \a @@ -82,7 +82,7 @@ select explain_filter('explain verbose select sum(unique1) over w1, sum(unique2) -- Check output including I/O timings. These fields are conditional -- but always set in JSON format, so check them only in this case. set track_io_timing = on; -select explain_filter('explain (analyze, buffers, format json) select * from int8_tbl i8'); +select explain_filter('explain (analyze, buffers, io off, format json) select * from int8_tbl i8'); set track_io_timing = off; -- SETTINGS option @@ -107,7 +107,7 @@ select explain_filter('explain (analyze, generic_plan) select unique1 from tenk1 select explain_filter('explain (memory) select * from int8_tbl i8'); select explain_filter('explain (memory, analyze, buffers off, io off) select * from int8_tbl i8'); select explain_filter('explain (memory, summary, format yaml) select * from int8_tbl i8'); -select explain_filter('explain (memory, analyze, format json) select * from int8_tbl i8'); +select explain_filter('explain (memory, analyze, io off, format json) select * from int8_tbl i8'); prepare int8_query as select * from int8_tbl i8; select explain_filter('explain (memory) execute int8_query'); @@ -147,7 +147,7 @@ set min_parallel_table_scan_size=0; set max_parallel_workers_per_gather=4; select jsonb_pretty( - explain_filter_to_json('explain (analyze, verbose, buffers, format json) + explain_filter_to_json('explain (analyze, verbose, buffers, io off, format json) select * from tenk1 order by tenthous') -- remove "Workers" node of the Seq Scan plan node #- '{0,Plan,Plans,0,Plans,0,Workers}' @@ -178,8 +178,8 @@ select explain_filter('explain (verbose) create table test_ctas as select 1'); -- Test SERIALIZE option select explain_filter('explain (analyze,buffers off,io off,serialize) select * from int8_tbl i8'); -select explain_filter('explain (analyze,serialize text,buffers,timing off) select * from int8_tbl i8'); -select explain_filter('explain (analyze,serialize binary,buffers,timing) select * from int8_tbl i8'); +select explain_filter('explain (analyze,serialize text,buffers,io off,timing off) select * from int8_tbl i8'); +select explain_filter('explain (analyze,serialize binary,buffers,io off,timing) select * from int8_tbl i8'); -- this tests an edge case where we have no data to return select explain_filter('explain (analyze,buffers off,io off,serialize) create temp table explain_temp as select * from int8_tbl i8'); diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index 212de0e6285..c5968932aed 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -553,13 +553,13 @@ begin; create function list_part_fn(int) returns int as $$ begin return $1; end;$$ language plpgsql stable; -- Ensure pruning works using a stable function containing no Vars -explain (analyze, costs off, summary off, timing off, buffers off) select * from list_part where a = list_part_fn(1); +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from list_part where a = list_part_fn(1); -- Ensure pruning does not take place when the function has a Var parameter -explain (analyze, costs off, summary off, timing off, buffers off) select * from list_part where a = list_part_fn(a); +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from list_part where a = list_part_fn(a); -- Ensure pruning does not take place when the expression contains a Var. -explain (analyze, costs off, summary off, timing off, buffers off) select * from list_part where a = list_part_fn(1) + a; +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from list_part where a = list_part_fn(1) + a; rollback; @@ -582,7 +582,7 @@ declare ln text; begin for ln in - execute format('explain (analyze, costs off, summary off, timing off, buffers off) %s', + execute format('explain (analyze, costs off, summary off, timing off, buffers off, io off) %s', $1) loop ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N'); @@ -669,7 +669,7 @@ reset min_parallel_table_scan_size; reset max_parallel_workers_per_gather; -- Test run-time partition pruning with an initplan -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 from lprt_a); -- Test run-time partition pruning with UNION ALL parents @@ -697,7 +697,7 @@ union all ) ab where a = $1 and b = (select -10); -- Ensure the xy_1 subplan is not pruned. -explain (analyze, costs off, summary off, timing off, buffers off) execute ab_q6(1); +explain (analyze, costs off, summary off, timing off, buffers off, io off) execute ab_q6(1); -- Ensure we see just the xy_1 row. execute ab_q6(100); @@ -752,10 +752,10 @@ insert into tprt values (10), (20), (501), (502), (505), (1001), (4500); set enable_hashjoin = off; set enable_mergejoin = off; -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 join tprt on tbl1.col1 > tprt.col1; -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -768,10 +768,10 @@ order by tbl1.col1, tprt.col1; -- Multiple partitions insert into tbl1 values (1001), (1010), (1011); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 inner join tprt on tbl1.col1 > tprt.col1; -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 inner join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -785,7 +785,7 @@ order by tbl1.col1, tprt.col1; -- Last partition delete from tbl1; insert into tbl1 values (4400); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 join tprt on tbl1.col1 < tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -795,7 +795,7 @@ order by tbl1.col1, tprt.col1; -- No matching partition delete from tbl1; insert into tbl1 values (10000); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from tbl1 join tprt on tbl1.col1 = tprt.col1; select tbl1.col1, tprt.col1 from tbl1 @@ -917,7 +917,7 @@ create table mc3p2 partition of mc3p for values from (2, minvalue, minvalue) to (3, maxvalue, maxvalue); insert into mc3p values (0, 1, 1), (1, 1, 1), (2, 1, 1); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from mc3p where a < 3 and abs(b) = 1; -- @@ -927,12 +927,12 @@ select * from mc3p where a < 3 and abs(b) = 1; -- prepare ps1 as select * from mc3p where a = $1 and abs(b) < (select 3); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) execute ps1(1); deallocate ps1; prepare ps2 as select * from mc3p where a <= $1 and abs(b) < (select 3); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) execute ps2(1); deallocate ps2; @@ -946,10 +946,10 @@ create table boolp (a bool) partition by list (a); create table boolp_t partition of boolp for values in('t'); create table boolp_f partition of boolp for values in('f'); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from boolp where a = (select value from boolvalues where value); -explain (analyze, costs off, summary off, timing off, buffers off) +explain (analyze, costs off, summary off, timing off, buffers off, io off) select * from boolp where a = (select value from boolvalues where not value); drop table boolp; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index fce46f79ac2..0a9e5247634 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2793,6 +2793,7 @@ SelfJoinCandidate SemTPadded SemiAntiJoinFactors SeqScan +SeqScanInstrumentation SeqScanState SeqTable SeqTableData @@ -2857,6 +2858,7 @@ SharedMemoizeInfo SharedRecordTableEntry SharedRecordTableKey SharedRecordTypmodRegistry +SharedSeqScanInstrumentation SharedSortInfo SharedTuplestore SharedTuplestoreAccessor -- 2.43.0