diff --git a/src/backend/distributed/planner/multi_explain.c b/src/backend/distributed/planner/multi_explain.c index 25523b5eb..cb7906ae9 100644 --- a/src/backend/distributed/planner/multi_explain.c +++ b/src/backend/distributed/planner/multi_explain.c @@ -72,7 +72,7 @@ typedef struct RemoteExplainPlan /* Explain functions for distributed queries */ -static void ExplainSubPlans(List *subPlanList, ExplainState *es); +static void ExplainSubPlans(DistributedPlan *distributedPlan, ExplainState *es); static void ExplainJob(Job *job, ExplainState *es); static void ExplainMapMergeJob(MapMergeJob *mapMergeJob, ExplainState *es); static void ExplainTaskList(List *taskList, ExplainState *es); @@ -127,7 +127,7 @@ CitusExplainScan(CustomScanState *node, List *ancestors, struct ExplainState *es if (distributedPlan->subPlanList != NIL) { - ExplainSubPlans(distributedPlan->subPlanList, es); + ExplainSubPlans(distributedPlan, es); } ExplainJob(distributedPlan->workerJob, es); @@ -179,20 +179,14 @@ CoordinatorInsertSelectExplainScan(CustomScanState *node, List *ancestors, * planning time and set it to 0. */ static void -ExplainSubPlans(List *subPlanList, ExplainState *es) +ExplainSubPlans(DistributedPlan *distributedPlan, ExplainState *es) { ListCell *subPlanCell = NULL; + uint64 planId = distributedPlan->planId; ExplainOpenGroup("Subplans", "Subplans", false, es); - if (es->format == EXPLAIN_FORMAT_TEXT) - { - appendStringInfoSpaces(es->str, es->indent * 2); - appendStringInfo(es->str, "-> Distributed Subplan\n"); - es->indent += 3; - } - - foreach(subPlanCell, subPlanList) + foreach(subPlanCell, distributedPlan->subPlanList) { DistributedSubPlan *subPlan = (DistributedSubPlan *) lfirst(subPlanCell); PlannedStmt *plan = subPlan->plan; @@ -201,6 +195,15 @@ ExplainSubPlans(List *subPlanList, ExplainState *es) char *queryString = NULL; instr_time planduration; + if (es->format == EXPLAIN_FORMAT_TEXT) + { + char *resultId = GenerateResultId(planId, subPlan->subPlanId); + + appendStringInfoSpaces(es->str, es->indent * 2); + appendStringInfo(es->str, "-> Distributed Subplan %s\n", resultId); + es->indent += 3; + } + /* set the planning time to 0 */ INSTR_TIME_SET_CURRENT(planduration); INSTR_TIME_SUBTRACT(planduration, planduration); @@ -210,11 +213,11 @@ ExplainSubPlans(List *subPlanList, ExplainState *es) #else ExplainOnePlan(plan, into, es, queryString, params, &planduration); #endif - } - if (es->format == EXPLAIN_FORMAT_TEXT) - { - es->indent -= 3; + if (es->format == EXPLAIN_FORMAT_TEXT) + { + es->indent -= 3; + } } ExplainCloseGroup("Subplans", "Subplans", false, es); diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index b0f765e71..73d36bb5a 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -140,6 +140,17 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, DeferredErrorMessage *error = NULL; RecursivePlanningContext context; + context.level = 0; + context.planId = planId; + context.subPlanList = NIL; + context.plannerRestrictionContext = plannerRestrictionContext; + + error = RecursivelyPlanCTEs(query, &context); + if (error != NULL) + { + return error; + } + if (SubqueryPushdown) { /* @@ -155,17 +166,6 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, return NULL; } - context.level = 0; - context.planId = planId; - context.subPlanList = NIL; - context.plannerRestrictionContext = plannerRestrictionContext; - - error = RecursivelyPlanCTEs(query, &context); - if (error != NULL) - { - return error; - } - /* XXX: plan subqueries */ *subPlanList = context.subPlanList; diff --git a/src/test/regress/expected/multi_explain.out b/src/test/regress/expected/multi_explain.out index 442ad999d..887b3ed19 100644 --- a/src/test/regress/expected/multi_explain.out +++ b/src/test/regress/expected/multi_explain.out @@ -713,6 +713,7 @@ Limit Sort Key: events.event_time DESC -> Seq Scan on events_1400029 events Filter: (composite_id = users.composite_id) +RESET citus.subquery_pushdown; -- Test all tasks output SET citus.explain_all_tasks TO on; EXPLAIN (COSTS FALSE) @@ -1115,3 +1116,75 @@ Custom Scan (Citus INSERT ... SELECT via coordinator) -> Append -> Function Scan on generate_series s -> Function Scan on generate_series s_1 +-- explain with recursive planning +EXPLAIN (COSTS OFF, VERBOSE true) +WITH keys AS ( + SELECT DISTINCT l_orderkey FROM lineitem_hash_part +), +series AS ( + SELECT s FROM generate_series(1,10) s +) +SELECT l_orderkey FROM series JOIN keys ON (s = l_orderkey) +ORDER BY s; +Custom Scan (Citus Router) + Output: remote_scan.l_orderkey + -> Distributed Subplan 54_1 + -> HashAggregate + Output: remote_scan.l_orderkey + Group Key: remote_scan.l_orderkey + -> Custom Scan (Citus Real-Time) + Output: remote_scan.l_orderkey + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=57637 dbname=regression + -> HashAggregate + Output: l_orderkey + Group Key: lineitem_hash_part.l_orderkey + -> Seq Scan on public.lineitem_hash_part_360038 lineitem_hash_part + Output: l_orderkey, l_partkey, l_suppkey, l_linenumber, l_quantity, l_extendedprice, l_discount, l_tax, l_returnflag, l_linestatus, l_shipdate, l_commitdate, l_receiptdate, l_shipinstruct, l_shipmode, l_comment + -> Distributed Subplan 54_2 + -> Function Scan on pg_catalog.generate_series s + Output: s + Function Call: generate_series(1, 10) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=57638 dbname=regression + -> Merge Join + Output: intermediate_result_1.l_orderkey, intermediate_result.s + Merge Cond: (intermediate_result.s = intermediate_result_1.l_orderkey) + -> Sort + Output: intermediate_result.s + Sort Key: intermediate_result.s + -> Function Scan on pg_catalog.read_intermediate_result intermediate_result + Output: intermediate_result.s + Function Call: read_intermediate_result('54_2'::text, 'binary'::citus_copy_format) + -> Sort + Output: intermediate_result_1.l_orderkey + Sort Key: intermediate_result_1.l_orderkey + -> Function Scan on pg_catalog.read_intermediate_result intermediate_result_1 + Output: intermediate_result_1.l_orderkey + Function Call: read_intermediate_result('54_1'::text, 'binary'::citus_copy_format) +SELECT true AS valid FROM explain_json($$ + WITH result AS ( + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity + ), + series AS ( + SELECT s FROM generate_series(1,10) s + ) + SELECT * FROM result JOIN series ON (s = count_quantity) JOIN orders_hash_part ON (s = o_orderkey) +$$); +t +SELECT true AS valid FROM explain_xml($$ + WITH result AS ( + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity + ), + series AS ( + SELECT s FROM generate_series(1,10) s + ) + SELECT * FROM result JOIN series ON (s = l_quantity) JOIN orders_hash_part ON (s = o_orderkey) +$$); +t diff --git a/src/test/regress/expected/multi_explain_0.out b/src/test/regress/expected/multi_explain_0.out index 88e921635..18061e8fd 100644 --- a/src/test/regress/expected/multi_explain_0.out +++ b/src/test/regress/expected/multi_explain_0.out @@ -713,6 +713,7 @@ Limit Sort Key: events.event_time DESC -> Seq Scan on events_1400029 events Filter: (composite_id = users.composite_id) +RESET citus.subquery_pushdown; -- Test all tasks output SET citus.explain_all_tasks TO on; EXPLAIN (COSTS FALSE) @@ -1115,3 +1116,75 @@ Custom Scan (Citus INSERT ... SELECT via coordinator) -> Append -> Function Scan on generate_series s -> Function Scan on generate_series s_1 +-- explain with recursive planning +EXPLAIN (COSTS OFF, VERBOSE true) +WITH keys AS ( + SELECT DISTINCT l_orderkey FROM lineitem_hash_part +), +series AS ( + SELECT s FROM generate_series(1,10) s +) +SELECT l_orderkey FROM series JOIN keys ON (s = l_orderkey) +ORDER BY s; +Custom Scan (Citus Router) + Output: remote_scan.l_orderkey + -> Distributed Subplan 54_1 + -> HashAggregate + Output: remote_scan.l_orderkey + Group Key: remote_scan.l_orderkey + -> Custom Scan (Citus Real-Time) + Output: remote_scan.l_orderkey + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=57637 dbname=regression + -> HashAggregate + Output: l_orderkey + Group Key: lineitem_hash_part.l_orderkey + -> Seq Scan on public.lineitem_hash_part_360038 lineitem_hash_part + Output: l_orderkey, l_partkey, l_suppkey, l_linenumber, l_quantity, l_extendedprice, l_discount, l_tax, l_returnflag, l_linestatus, l_shipdate, l_commitdate, l_receiptdate, l_shipinstruct, l_shipmode, l_comment + -> Distributed Subplan 54_2 + -> Function Scan on pg_catalog.generate_series s + Output: s + Function Call: generate_series(1, 10) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=57638 dbname=regression + -> Merge Join + Output: intermediate_result_1.l_orderkey, intermediate_result.s + Merge Cond: (intermediate_result.s = intermediate_result_1.l_orderkey) + -> Sort + Output: intermediate_result.s + Sort Key: intermediate_result.s + -> Function Scan on pg_catalog.read_intermediate_result intermediate_result + Output: intermediate_result.s + Function Call: read_intermediate_result('54_2'::text, 'binary'::citus_copy_format) + -> Sort + Output: intermediate_result_1.l_orderkey + Sort Key: intermediate_result_1.l_orderkey + -> Function Scan on pg_catalog.read_intermediate_result intermediate_result_1 + Output: intermediate_result_1.l_orderkey + Function Call: read_intermediate_result('54_1'::text, 'binary'::citus_copy_format) +SELECT true AS valid FROM explain_json($$ + WITH result AS ( + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity + ), + series AS ( + SELECT s FROM generate_series(1,10) s + ) + SELECT * FROM result JOIN series ON (s = count_quantity) JOIN orders_hash_part ON (s = o_orderkey) +$$); +t +SELECT true AS valid FROM explain_xml($$ + WITH result AS ( + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity + ), + series AS ( + SELECT s FROM generate_series(1,10) s + ) + SELECT * FROM result JOIN series ON (s = l_quantity) JOIN orders_hash_part ON (s = o_orderkey) +$$); +t diff --git a/src/test/regress/sql/multi_explain.sql b/src/test/regress/sql/multi_explain.sql index 50174ea11..43693adb4 100644 --- a/src/test/regress/sql/multi_explain.sql +++ b/src/test/regress/sql/multi_explain.sql @@ -356,6 +356,8 @@ ORDER BY LIMIT 10; +RESET citus.subquery_pushdown; + -- Test all tasks output SET citus.explain_all_tasks TO on; @@ -519,3 +521,36 @@ EXPLAIN (COSTS OFF) INSERT INTO lineitem_hash_part ( SELECT s FROM generate_series(1,5) s) UNION ( SELECT s FROM generate_series(5,10) s); + +-- explain with recursive planning +EXPLAIN (COSTS OFF, VERBOSE true) +WITH keys AS ( + SELECT DISTINCT l_orderkey FROM lineitem_hash_part +), +series AS ( + SELECT s FROM generate_series(1,10) s +) +SELECT l_orderkey FROM series JOIN keys ON (s = l_orderkey) +ORDER BY s; + +SELECT true AS valid FROM explain_json($$ + WITH result AS ( + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity + ), + series AS ( + SELECT s FROM generate_series(1,10) s + ) + SELECT * FROM result JOIN series ON (s = count_quantity) JOIN orders_hash_part ON (s = o_orderkey) +$$); + +SELECT true AS valid FROM explain_xml($$ + WITH result AS ( + SELECT l_quantity, count(*) count_quantity FROM lineitem + GROUP BY l_quantity ORDER BY count_quantity, l_quantity + ), + series AS ( + SELECT s FROM generate_series(1,10) s + ) + SELECT * FROM result JOIN series ON (s = l_quantity) JOIN orders_hash_part ON (s = o_orderkey) +$$);