diff --git a/src/backend/distributed/planner/multi_explain.c b/src/backend/distributed/planner/multi_explain.c index 17c2a5683..de1e444ff 100644 --- a/src/backend/distributed/planner/multi_explain.c +++ b/src/backend/distributed/planner/multi_explain.c @@ -1512,8 +1512,16 @@ WrapQueryForExplainAnalyze(const char *queryString, TupleDesc tupleDesc) ExplainFormatStr(CurrentDistributedQueryExplainOptions.format)); StringInfo wrappedQuery = makeStringInfo(); + + /* + * We do not include dummy column if original query didn't return any columns. + * Otherwise, number of columns that original query returned wouldn't match + * number of columns returned by worker_save_query_explain_analyze. + */ + char *workerSaveQueryFetchCols = (tupleDesc->natts == 0) ? "" : "*"; appendStringInfo(wrappedQuery, - "SELECT * FROM worker_save_query_explain_analyze(%s, %s) AS (%s)", + "SELECT %s FROM worker_save_query_explain_analyze(%s, %s) AS (%s)", + workerSaveQueryFetchCols, quote_literal_cstr(queryString), quote_literal_cstr(explainOptions->data), columnDef->data); diff --git a/src/test/regress/expected/multi_explain.out b/src/test/regress/expected/multi_explain.out index 897deaf4c..b0d8ca433 100644 --- a/src/test/regress/expected/multi_explain.out +++ b/src/test/regress/expected/multi_explain.out @@ -2956,3 +2956,78 @@ Custom Scan (Citus Adaptive) (actual rows=1 loops=1) -- reset back reset citus.explain_analyze_sort_method; DROP TABLE explain_analyze_execution_time; +CREATE SCHEMA multi_explain; +SET search_path TO multi_explain; +-- test EXPLAIN ANALYZE when original query returns no columns +CREATE TABLE reference_table(a int); +SELECT create_reference_table('reference_table'); + +INSERT INTO reference_table VALUES (1); +EXPLAIN :default_analyze_flags SELECT FROM reference_table; +Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on reference_table_570031 reference_table (actual rows=1 loops=1) +CREATE TABLE distributed_table_1(a int, b int); +SELECT create_distributed_table('distributed_table_1','a'); + +INSERT INTO distributed_table_1 values (1,1); +EXPLAIN :default_analyze_flags SELECT row_number() OVER() AS r FROM distributed_table_1; +WindowAgg (actual rows=1 loops=1) + -> Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + Task Count: 2 + Tasks Shown: One of 2 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on distributed_table_1_570032 distributed_table_xxx (actual rows=1 loops=1) +CREATE TABLE distributed_table_2(a int, b int); +SELECT create_distributed_table('distributed_table_2','a'); + +INSERT INTO distributed_table_2 VALUES (1,1); +EXPLAIN :default_analyze_flags +WITH r AS (SELECT row_number() OVER () AS r FROM distributed_table_1) +SELECT * FROM distributed_table_2 +JOIN r ON (r = distributed_table_2.b) +LIMIT 3; +Limit (actual rows=1 loops=1) + -> Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + -> Distributed Subplan XXX_1 + Intermediate Data Size: 14 bytes + Result destination: Send to 2 nodes + -> WindowAgg (actual rows=1 loops=1) + -> Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + Task Count: 2 + Tasks Shown: One of 2 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on distributed_table_1_570032 distributed_table_xxx (actual rows=1 loops=1) + Task Count: 2 + Tuple data received from nodes: 3 bytes + Tasks Shown: One of 2 + -> Task + Tuple data received from node: 3 bytes + Node: host=localhost port=xxxxx dbname=regression + -> Limit (actual rows=1 loops=1) + -> Nested Loop (actual rows=1 loops=1) + Join Filter: (distributed_table_2.b = intermediate_result.r) + -> Function Scan on read_intermediate_result intermediate_result (actual rows=1 loops=1) + -> Seq Scan on distributed_table_2_570034 distributed_table_xxx (actual rows=1 loops=1) +EXPLAIN :default_analyze_flags SELECT FROM (SELECT * FROM reference_table) subquery; +Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + Task Count: 1 + Tasks Shown: All + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on reference_table_570031 reference_table (actual rows=1 loops=1) +PREPARE dummy_prep_stmt(int) AS SELECT FROM distributed_table_1; +EXPLAIN :default_analyze_flags EXECUTE dummy_prep_stmt(50); +Custom Scan (Citus Adaptive) (actual rows=1 loops=1) + Task Count: 2 + Tasks Shown: One of 2 + -> Task + Node: host=localhost port=xxxxx dbname=regression + -> Seq Scan on distributed_table_1_570032 distributed_table_xxx (actual rows=1 loops=1) +SET client_min_messages TO ERROR; +DROP SCHEMA multi_explain CASCADE; diff --git a/src/test/regress/sql/multi_explain.sql b/src/test/regress/sql/multi_explain.sql index 2f0c9ac45..3a12c7093 100644 --- a/src/test/regress/sql/multi_explain.sql +++ b/src/test/regress/sql/multi_explain.sql @@ -1052,3 +1052,37 @@ EXPLAIN (COSTS FALSE, ANALYZE TRUE, TIMING FALSE, SUMMARY FALSE) select a, CASE -- reset back reset citus.explain_analyze_sort_method; DROP TABLE explain_analyze_execution_time; + +CREATE SCHEMA multi_explain; +SET search_path TO multi_explain; + +-- test EXPLAIN ANALYZE when original query returns no columns +CREATE TABLE reference_table(a int); +SELECT create_reference_table('reference_table'); +INSERT INTO reference_table VALUES (1); + +EXPLAIN :default_analyze_flags SELECT FROM reference_table; + +CREATE TABLE distributed_table_1(a int, b int); +SELECT create_distributed_table('distributed_table_1','a'); +INSERT INTO distributed_table_1 values (1,1); + +EXPLAIN :default_analyze_flags SELECT row_number() OVER() AS r FROM distributed_table_1; + +CREATE TABLE distributed_table_2(a int, b int); +SELECT create_distributed_table('distributed_table_2','a'); +INSERT INTO distributed_table_2 VALUES (1,1); + +EXPLAIN :default_analyze_flags +WITH r AS (SELECT row_number() OVER () AS r FROM distributed_table_1) +SELECT * FROM distributed_table_2 +JOIN r ON (r = distributed_table_2.b) +LIMIT 3; + +EXPLAIN :default_analyze_flags SELECT FROM (SELECT * FROM reference_table) subquery; + +PREPARE dummy_prep_stmt(int) AS SELECT FROM distributed_table_1; +EXPLAIN :default_analyze_flags EXECUTE dummy_prep_stmt(50); + +SET client_min_messages TO ERROR; +DROP SCHEMA multi_explain CASCADE;