Commit b925a00f authored by Tom Lane's avatar Tom Lane

Fix "force_parallel_mode = regress" to work with ANALYZE + VERBOSE.

force_parallel_mode = regress is supposed to force use of a Gather
node without having any impact on EXPLAIN output.  But it failed to
accomplish that if both ANALYZE and VERBOSE are given, because that
enables per-worker output data that you wouldn't see if the Gather
hadn't been inserted.  Improve the logic so that we suppress the
per-worker data too.

This allows putting the new test case added by commit 5935917c
back into the originally intended form (cf. 776a2c88, 22864f6e).
We can also get rid of a kluge in subselect.sql, which previously
had to clean up after force_parallel_mode's failure to do what it
said on the tin.

Discussion: https://postgr.es/m/18445.1576177309@sss.pgh.pa.us
parent 9067b839
...@@ -695,13 +695,19 @@ ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc) ...@@ -695,13 +695,19 @@ ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
/* /*
* Sometimes we mark a Gather node as "invisible", which means that it's * Sometimes we mark a Gather node as "invisible", which means that it's
* not displayed in EXPLAIN output. The purpose of this is to allow * not to be displayed in EXPLAIN output. The purpose of this is to allow
* running regression tests with force_parallel_mode=regress to get the * running regression tests with force_parallel_mode=regress to get the
* same results as running the same tests with force_parallel_mode=off. * same results as running the same tests with force_parallel_mode=off.
* Such marking is currently only supported on a Gather at the top of the
* plan. We skip that node, and we must also hide per-worker detail data
* further down in the plan tree.
*/ */
ps = queryDesc->planstate; ps = queryDesc->planstate;
if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible) if (IsA(ps, GatherState) &&((Gather *) ps->plan)->invisible)
{
ps = outerPlanState(ps); ps = outerPlanState(ps);
es->hide_workers = true;
}
ExplainNode(ps, NIL, NULL, NULL, es); ExplainNode(ps, NIL, NULL, NULL, es);
/* /*
...@@ -806,6 +812,10 @@ ExplainPrintJIT(ExplainState *es, int jit_flags, ...@@ -806,6 +812,10 @@ ExplainPrintJIT(ExplainState *es, int jit_flags,
if (!ji || ji->created_functions == 0) if (!ji || ji->created_functions == 0)
return; return;
/* don't print per-worker info if we're supposed to hide that */
if (for_workers && es->hide_workers)
return;
/* calculate total time */ /* calculate total time */
INSTR_TIME_SET_ZERO(total_time); INSTR_TIME_SET_ZERO(total_time);
INSTR_TIME_ADD(total_time, ji->generation_counter); INSTR_TIME_ADD(total_time, ji->generation_counter);
...@@ -1877,7 +1887,8 @@ ExplainNode(PlanState *planstate, List *ancestors, ...@@ -1877,7 +1887,8 @@ ExplainNode(PlanState *planstate, List *ancestors,
show_buffer_usage(es, &planstate->instrument->bufusage); show_buffer_usage(es, &planstate->instrument->bufusage);
/* Show worker detail */ /* Show worker detail */
if (es->analyze && es->verbose && planstate->worker_instrument) if (es->analyze && es->verbose && !es->hide_workers &&
planstate->worker_instrument)
{ {
WorkerInstrumentation *w = planstate->worker_instrument; WorkerInstrumentation *w = planstate->worker_instrument;
bool opened_group = false; bool opened_group = false;
...@@ -2574,6 +2585,12 @@ show_sort_info(SortState *sortstate, ExplainState *es) ...@@ -2574,6 +2585,12 @@ show_sort_info(SortState *sortstate, ExplainState *es)
} }
} }
/*
* You might think we should just skip this stanza entirely when
* es->hide_workers is true, but then we'd get no sort-method output at
* all. We have to make it look like worker 0's data is top-level data.
* Currently, we only bother with that for text-format output.
*/
if (sortstate->shared_info != NULL) if (sortstate->shared_info != NULL)
{ {
int n; int n;
...@@ -2596,9 +2613,11 @@ show_sort_info(SortState *sortstate, ExplainState *es) ...@@ -2596,9 +2613,11 @@ show_sort_info(SortState *sortstate, ExplainState *es)
if (es->format == EXPLAIN_FORMAT_TEXT) if (es->format == EXPLAIN_FORMAT_TEXT)
{ {
appendStringInfoSpaces(es->str, es->indent * 2); appendStringInfoSpaces(es->str, es->indent * 2);
if (n > 0 || !es->hide_workers)
appendStringInfo(es->str, "Worker %d: ", n);
appendStringInfo(es->str, appendStringInfo(es->str,
"Worker %d: Sort Method: %s %s: %ldkB\n", "Sort Method: %s %s: %ldkB\n",
n, sortMethod, spaceType, spaceUsed); sortMethod, spaceType, spaceUsed);
} }
else else
{ {
......
...@@ -46,6 +46,7 @@ typedef struct ExplainState ...@@ -46,6 +46,7 @@ typedef struct ExplainState
List *rtable_names; /* alias names for RTEs */ List *rtable_names; /* alias names for RTEs */
List *deparse_cxt; /* context list for deparsing expressions */ List *deparse_cxt; /* context list for deparsing expressions */
Bitmapset *printed_subplans; /* ids of SubPlans we've printed */ Bitmapset *printed_subplans; /* ids of SubPlans we've printed */
bool hide_workers; /* set if we find an invisible Gather */
} ExplainState; } ExplainState;
/* Hook for plugins to get control in ExplainOneQuery() */ /* Hook for plugins to get control in ExplainOneQuery() */
......
...@@ -3163,12 +3163,12 @@ execute mt_q1(35); ...@@ -3163,12 +3163,12 @@ execute mt_q1(35);
deallocate mt_q1; deallocate mt_q1;
prepare mt_q2 (int) as select * from ma_test where a >= $1 order by b limit 1; prepare mt_q2 (int) as select * from ma_test where a >= $1 order by b limit 1;
-- Ensure output list looks sane when the MergeAppend has no subplans. -- Ensure output list looks sane when the MergeAppend has no subplans.
explain (verbose, costs off) execute mt_q2 (35); explain (analyze, verbose, costs off, summary off, timing off) execute mt_q2 (35);
QUERY PLAN QUERY PLAN
-------------------------------- --------------------------------------------
Limit Limit (actual rows=0 loops=1)
Output: ma_test.a, ma_test.b Output: ma_test.a, ma_test.b
-> Merge Append -> Merge Append (actual rows=0 loops=1)
Sort Key: ma_test.b Sort Key: ma_test.b
Subplans Removed: 3 Subplans Removed: 3
(5 rows) (5 rows)
......
...@@ -1166,8 +1166,6 @@ begin ...@@ -1166,8 +1166,6 @@ begin
select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3 select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3
loop loop
ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx'); ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx');
-- this case might occur if force_parallel_mode is on:
ln := regexp_replace(ln, 'Worker 0: Sort Method', 'Sort Method');
return next ln; return next ln;
end loop; end loop;
end; end;
......
...@@ -841,7 +841,7 @@ deallocate mt_q1; ...@@ -841,7 +841,7 @@ deallocate mt_q1;
prepare mt_q2 (int) as select * from ma_test where a >= $1 order by b limit 1; prepare mt_q2 (int) as select * from ma_test where a >= $1 order by b limit 1;
-- Ensure output list looks sane when the MergeAppend has no subplans. -- Ensure output list looks sane when the MergeAppend has no subplans.
explain (verbose, costs off) execute mt_q2 (35); explain (analyze, verbose, costs off, summary off, timing off) execute mt_q2 (35);
deallocate mt_q2; deallocate mt_q2;
......
...@@ -631,8 +631,6 @@ begin ...@@ -631,8 +631,6 @@ begin
select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3 select * from (select pk,c2 from sq_limit order by c1,pk) as x limit 3
loop loop
ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx'); ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx');
-- this case might occur if force_parallel_mode is on:
ln := regexp_replace(ln, 'Worker 0: Sort Method', 'Sort Method');
return next ln; return next ln;
end loop; end loop;
end; end;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment