Skip to content

Commit

Permalink
Change the way static Partition Selector nodes are printed in EXPLAIN
Browse files Browse the repository at this point in the history
The printablePredicate of a static PartitionSelector node contains Var nodes
with varno=INNER. That's bogus, because the PartitionSelector node doesn't
actually have any child nodes, but works at execution time because the
printablePredicate is not only used by EXPLAIN. In most cases, it still
worked, because most Var nodes carry a varnoold field, which is used by
EXPLAIN for the lookup, but there was one case of "bogus varno" error even
memorized in the expected output of the regression suite. (PostgreSQL 8.3
changed the way EXPLAIN resolves the printable name so that varnoold no
longer saves the bacon, and you would get a lot more of those errors)

To fix, teach the EXPLAIN of a Sequence node to also reach into the
static PartitionSelector node, and print the printablePredicate as if that
qual was part of the Sequence node directly.

The user-visible effect of this is that the static Partition Selector
expression now appears in EXPLAIN output as a direct attribute of the
Sequence node, not as a separate child node. Also, if a static Partition
Selector doesn't have a "printablePredicate", i.e. it doesn't actually
do any selection, it's not printed at all.
  • Loading branch information
hlinnaka committed Jun 15, 2016
1 parent 84286b9 commit 5dc7dda
Show file tree
Hide file tree
Showing 16 changed files with 243 additions and 178 deletions.
41 changes: 34 additions & 7 deletions src/backend/commands/explain.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ show_motion_keys(Plan *plan, List *hashExpr, int nkeys, AttrNumber *keycols,
const char *qlabel,
StringInfo str, int indent, ExplainState *es);
static void
show_static_part_selection(Plan *plan, int indent, StringInfo str);
show_static_part_selection(PartitionSelector *ps, Sequence *parent, StringInfo str, int indent, ExplainState *es);

static const char *explain_get_index_name(Oid indexId);

Expand Down Expand Up @@ -1667,7 +1667,24 @@ explain_outNode(StringInfo str,
NULL, outerPlan(plan),
NULL, NULL,
str, indent, es);
show_static_part_selection(plan, indent, str);
if (((PartitionSelector *) plan)->staticSelection)
{
/*
* We should not encounter static selectors as part of the
* normal plan traversal: they are handled specially, as
* part of a Sequence node.
*/
elog(WARNING, "unexpected static PartitionSelector");
}
}
break;
case T_Sequence:
{
Sequence *s = (Sequence *) plan;

if (s->static_selector)
show_static_part_selection(s->static_selector, s,
str, indent, es);
}
break;
default:
Expand Down Expand Up @@ -2291,15 +2308,25 @@ show_motion_keys(Plan *plan, List *hashExpr, int nkeys, AttrNumber *keycols,

/*
* Show the number of statically selected partitions if available.
*
* This is similar to show_upper_qual(), but the "printablePredicate" produced
* by ORCA is a bit special: INNER Vars refer to the child of the Sequence node
* we are part of.
*/
static void
show_static_part_selection(Plan *plan, int indent, StringInfo str)
show_static_part_selection(PartitionSelector *ps, Sequence *parent,
StringInfo str, int indent, ExplainState *es)
{
PartitionSelector *ps = (PartitionSelector *) plan;
if (!ps->staticSelection)
return;

if (! ps->staticSelection)
if (ps->printablePredicate)
{
return;
show_upper_qual(list_make1(ps->printablePredicate),
"Partition Selector",
NULL, NULL,
NULL, (Plan *) parent,
str, indent, es);
}

int nPartsSelected = list_length(ps->staticPartOids);
Expand All @@ -2309,7 +2336,7 @@ show_static_part_selection(Plan *plan, int indent, StringInfo str)
appendStringInfoString(str, " ");
}

appendStringInfo(str, " Partitions selected: %d (out of %d)\n", nPartsSelected, nPartsTotal);
appendStringInfo(str, " Partitions selected: %d (out of %d)\n", nPartsSelected, nPartsTotal);
}

/*
Expand Down
19 changes: 18 additions & 1 deletion src/backend/executor/nodeSequence.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ ExecInitSequence(Sequence *node, EState *estate, int eflags)
Assert(numSubplans >= 1);
sequenceState->subplans = (PlanState **)palloc0(numSubplans * sizeof(PlanState *));
sequenceState->numSubplans = numSubplans;


/* Initialize static partition selector, if any */
if (node->static_selector)
{
sequenceState->static_selector =
(PartitionSelectorState *) ExecInitNode((Plan *) node->static_selector, estate, eflags);
}

/* Initialize subplans */
ListCell *lc;
int no = 0;
Expand Down Expand Up @@ -110,6 +117,16 @@ ExecSequence(SequenceState *node)
*/
if (node->initState)
{
/*
* Run the static partition selector first (XXX: Didn't we do this
* at plan time already?)
*/
if (node->static_selector)
{
completeSubplan((PlanState *) node->static_selector);
CHECK_FOR_INTERRUPTS();
}

for(int no = 0; no < node->numSubplans - 1; no++)
{
completeSubplan(node->subplans[no]);
Expand Down
26 changes: 25 additions & 1 deletion src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4174,7 +4174,31 @@ CTranslatorDXLToPlStmt::PplanSequence

Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);

psequence->subplans = gpdb::PlAppendElement(psequence->subplans, pplanChild);
/*
* When the plan comes out from ORCA, a "static" partition
* selection is represented by a subplan that looks like this:
*
* Sequence
* -> Partition Selector
* -> Dynamic Table Scan
*
* The Partition Selector node is a bit special though, as it
* modifies the behaviour of its sibling Dynamic Table Scan
* node, and the printablePredicate can contain Vars that
* refer to a child of the Sequence node, rather than
* children of the PartititionSelector node itself. So in the
* Plan tree, we want to put it in the dedicated
* static_selector field, rather than having it as just
* another child node of the Sequence.
*/
if (IsA(pplanChild, PartitionSelector))
{
psequence->static_selector = (PartitionSelector *) pplanChild;
}
else
{
psequence->subplans = gpdb::PlAppendElement(psequence->subplans, pplanChild);
}
pplan->nMotionNodes += pplanChild->nMotionNodes;
}

Expand Down
1 change: 1 addition & 0 deletions src/backend/nodes/copyfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ _copySequence(Sequence *from)
Sequence *newnode = makeNode(Sequence);
CopyPlanFields((Plan *) from, (Plan *) newnode);
COPY_NODE_FIELD(subplans);
COPY_NODE_FIELD(static_selector);

return newnode;
}
Expand Down
1 change: 1 addition & 0 deletions src/backend/nodes/outfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ _outSequence(StringInfo str, Sequence *node)
WRITE_NODE_TYPE("SEQUENCE");
_outPlanInfo(str, (Plan *)node);
WRITE_NODE_FIELD(subplans);
WRITE_NODE_FIELD(static_selector);
}

static void
Expand Down
1 change: 1 addition & 0 deletions src/backend/nodes/readfast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1528,6 +1528,7 @@ _readSequence(void)
READ_LOCALS(Sequence);
readPlanInfo((Plan *)local_node);
READ_NODE_FIELD(subplans);
READ_NODE_FIELD(static_selector);
READ_DONE();
}

Expand Down
4 changes: 4 additions & 0 deletions src/include/nodes/execnodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ struct FileScanDescData;
struct MirroredBufferPoolBulkLoadInfo;
struct SliceTable;

typedef struct PartitionSelectorState PartitionSelectorState;

/* ----------------
* IndexInfo information
*
Expand Down Expand Up @@ -1525,6 +1527,8 @@ typedef struct SequenceState
PlanState **subplans;
int numSubplans;

PartitionSelectorState *static_selector;

/*
* True if no subplan has been executed.
*/
Expand Down
4 changes: 4 additions & 0 deletions src/include/nodes/plannodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "nodes/primnodes.h"
#include "storage/itemptr.h"

typedef struct PartitionSelector PartitionSelector;

typedef struct DirectDispatchInfo
{
/**
Expand Down Expand Up @@ -378,6 +380,8 @@ typedef struct Sequence
{
Plan plan;
List *subplans;

PartitionSelector *static_selector;
} Sequence;

/* ----------------
Expand Down
11 changes: 5 additions & 6 deletions src/test/regress/expected/bfv_index_optimizer.out
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ explain SELECT count(*)
FROM bfv_tab2_facttable1 ft, bfv_tab2_dimdate dt, bfv_tab2_dimtabl1 dt1
WHERE ft.wk_id = dt.wk_id
AND ft.id = dt1.id;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=0.00..862.16 rows=1 width=8)
-> Gather Motion 3:1 (slice3; segments: 3) (cost=0.00..862.16 rows=1 width=8)
-> Aggregate (cost=0.00..862.16 rows=1 width=8)
Expand All @@ -153,15 +153,14 @@ AND ft.id = dt1.id;
-> Broadcast Motion 3:3 (slice1; segments: 3) (cost=0.00..431.00 rows=7 width=4)
-> Table Scan on bfv_tab2_dimtabl1 (cost=0.00..431.00 rows=3 width=4)
-> Sequence (cost=0.00..0.16 rows=1 width=2)
-> Partition Selector for bfv_tab2_facttable1 (dynamic scan id: 1) (cost=10.00..100.00 rows=34 width=4)
Partitions selected: 20 (out of 20)
Partitions selected: 20 (out of 20)
-> Bitmap Table Scan on bfv_tab2_facttable1 (dynamic scan id: 1) (cost=0.00..0.16 rows=1 width=2)
Recheck Cond: bfv_tab2_facttable1.id = bfv_tab2_dimtabl1.id
-> Bitmap Index Scan on idx_bfv_tab2_facttable1_1_prt_dflt (cost=0.00..0.00 rows=0 width=0)
Index Cond: bfv_tab2_facttable1.id = bfv_tab2_dimtabl1.id
Settings: optimizer=on
Optimizer status: PQO version 1.621
(22 rows)
Optimizer status: PQO version 1.633
(21 rows)

-- start_ignore
create language plpythonu;
Expand Down
5 changes: 1 addition & 4 deletions src/test/regress/expected/bfv_partition_optimizer.out
Original file line number Diff line number Diff line change
Expand Up @@ -1565,9 +1565,6 @@ select * from pp where b=2 and c=2;
(0 rows)

select count_operator('explain select * from pp where b=2 and c=2;','Partition Selector');
WARNING: bogus var: varno=65000 varattno=2 (ruleutils.c:3186)
CONTEXT: SQL statement "explain select * from pp where b=2 and c=2;"
PL/Python function "count_operator"
count_operator
----------------
1
Expand Down Expand Up @@ -1664,7 +1661,7 @@ select * from ds_4 a1,ds_4 a2 where a1.month_id = a2.month_id and a1.month_id >
select count_operator('explain select * from ds_4 a1,ds_4 a2 where a1.month_id = a2.month_id and a1.month_id > E''200800'';','Partition Selector');
count_operator
----------------
2
1
(1 row)

-- CLEANUP
Expand Down
54 changes: 20 additions & 34 deletions src/test/regress/expected/gp_optimizer.out
Original file line number Diff line number Diff line change
Expand Up @@ -8137,17 +8137,15 @@ select * from orca.t order by 1,2;
explain select * from orca.t order by 1,2;
QUERY PLAN
-----------------------------------------------------------------------------------------------------
Gather Motion 2:1 (slice1; segments: 2) (cost=0.00..431.00 rows=1 width=32)
Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..431.00 rows=1 width=32)
Merge Key: timest, user_id
-> Sequence (cost=0.00..431.00 rows=1 width=32)
-> Partition Selector for t (dynamic scan id: 1) (cost=10.00..100.00 rows=50 width=4)
Partitions selected: 6 (out of 6)
-> Sort (cost=0.00..431.00 rows=1 width=32)
Sort Key: timest, user_id
-> Dynamic Table Scan on t (dynamic scan id: 1) (cost=0.00..431.00 rows=1 width=32)
Settings: optimizer=on; optimizer_segments=3
Optimizer status: PQO version 1.630
(10 rows)
Optimizer status: PQO version 1.633
(8 rows)

select tag2, tag1 from orca.t order by 1, 2;;
tag2 | tag1
Expand Down Expand Up @@ -8226,19 +8224,17 @@ set optimizer_plan_id = 2;
explain select * from orca.t_date where user_id=9;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Gather Motion 2:1 (slice1; segments: 2) (cost=0.00..437.00 rows=1 width=28)
Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..437.00 rows=1 width=28)
-> Sequence (cost=0.00..437.00 rows=1 width=28)
-> Partition Selector for t_date (dynamic scan id: 1) (cost=10.00..100.00 rows=50 width=4)
Partitions selected: 6 (out of 6)
-> Result (cost=0.00..437.00 rows=1 width=28)
-> Append (cost=0.00..437.00 rows=1 width=28)
-> Dynamic Index Scan on t_date (dynamic scan id: 1) (cost=0.00..6.00 rows=1 width=58)
Index Cond: user_id = 9::numeric
-> Dynamic Table Scan on t_date (dynamic scan id: 1) (cost=0.00..431.00 rows=1 width=58)
Filter: user_id = 9::numeric
Settings: optimizer=on; optimizer_segments=3
Optimizer status: PQO version 1.602
(12 rows)
Optimizer status: PQO version 1.633
(10 rows)

select * from orca.t_date where user_id=9;
timest | user_id | tag1 | tag2
Expand Down Expand Up @@ -8281,19 +8277,17 @@ set optimizer_plan_id = 2;
explain select * from orca.t_text where user_id=9;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Gather Motion 2:1 (slice1; segments: 2) (cost=0.00..437.00 rows=1 width=28)
Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..437.00 rows=1 width=28)
-> Sequence (cost=0.00..437.00 rows=1 width=28)
-> Partition Selector for t_text (dynamic scan id: 1) (cost=10.00..100.00 rows=50 width=4)
Partitions selected: 3 (out of 3)
-> Result (cost=0.00..437.00 rows=1 width=28)
-> Append (cost=0.00..437.00 rows=1 width=28)
-> Dynamic Index Scan on t_text (dynamic scan id: 1) (cost=0.00..6.00 rows=1 width=58)
Index Cond: user_id = 9::numeric
-> Dynamic Table Scan on t_text (dynamic scan id: 1) (cost=0.00..431.00 rows=1 width=58)
Filter: user_id = 9::numeric
Settings: optimizer=on; optimizer_segments=3
Optimizer status: PQO version 1.602
(12 rows)
Optimizer status: PQO version 1.633
(10 rows)

select * from orca.t_text where user_id=9;
timest | user_id | tag1 | tag2
Expand Down Expand Up @@ -8348,17 +8342,15 @@ select disable_xform('CXformDynamicGet2DynamicTableScan');
(1 row)

explain select * from orca.t_employee where user_id = 2;
QUERY PLAN
----------------------------------------------------------------------------------------------------------
QUERY PLAN
------------------------------------------------------------------------------------------------------
Gather Motion 1:1 (slice1; segments: 1) (cost=0.00..6.00 rows=1 width=28)
-> Sequence (cost=0.00..6.00 rows=1 width=28)
-> Partition Selector for t_employee (dynamic scan id: 1) (cost=10.00..100.00 rows=50 width=4)
Partitions selected: 2 (out of 2)
-> Dynamic Index Scan on t_employee (dynamic scan id: 1) (cost=0.00..6.00 rows=1 width=28)
Index Cond: user_id = 2::numeric
Settings: optimizer=on; optimizer_segments=3
Optimizer status: PQO version 1.602
(8 rows)
Optimizer status: PQO version 1.633
(6 rows)

select * from orca.t_employee where user_id = 2;
timest | user_id | tag1 | emp
Expand Down Expand Up @@ -8401,19 +8393,17 @@ set optimizer_plan_id = 2;
explain select * from orca.t_ceeval_ints where user_id=4;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------
Gather Motion 2:1 (slice1; segments: 2) (cost=0.00..437.00 rows=1 width=28)
Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..437.00 rows=1 width=28)
-> Sequence (cost=0.00..437.00 rows=1 width=28)
-> Partition Selector for t_ceeval_ints (dynamic scan id: 1) (cost=10.00..100.00 rows=50 width=4)
Partitions selected: 3 (out of 3)
-> Result (cost=0.00..437.00 rows=1 width=28)
-> Append (cost=0.00..437.00 rows=1 width=28)
-> Dynamic Index Scan on t_ceeval_ints (dynamic scan id: 1) (cost=0.00..6.00 rows=1 width=58)
Index Cond: user_id = 4::numeric
-> Dynamic Table Scan on t_ceeval_ints (dynamic scan id: 1) (cost=0.00..431.00 rows=1 width=58)
Filter: user_id = 4::numeric
Settings: optimizer=on; optimizer_segments=3
Optimizer status: PQO version 1.602
(12 rows)
Optimizer status: PQO version 1.633
(10 rows)

select * from orca.t_ceeval_ints where user_id=4;
user_id | category_id | tag1 | tag2
Expand Down Expand Up @@ -9213,20 +9203,18 @@ insert into orca.bm_dyn_test values(2, 5, '2');
set optimizer_enable_bitmapscan=on;
-- gather on 1 segment because of direct dispatch
explain select * from orca.bm_dyn_test where i=2 and t='2';
QUERY PLAN
-----------------------------------------------------------------------------------------------------------
QUERY PLAN
------------------------------------------------------------------------------------------------------
Gather Motion 1:1 (slice1; segments: 1) (cost=0.00..0.00 rows=1 width=16)
-> Sequence (cost=0.00..0.00 rows=1 width=16)
-> Partition Selector for bm_dyn_test (dynamic scan id: 1) (cost=10.00..100.00 rows=50 width=4)
Partitions selected: 6 (out of 6)
-> Bitmap Table Scan on bm_dyn_test (dynamic scan id: 1) (cost=0.00..0.00 rows=1 width=16)
Recheck Cond: i = 2
Filter: i = 2 AND t = '2'::text
-> Bitmap Index Scan on bm_dyn_test_idx_1_prt_part0 (cost=0.00..0.00 rows=0 width=0)
Index Cond: i = 2
Settings: optimizer=on
Optimizer status: PQO version 1.602
(11 rows)
Optimizer status: PQO version 1.633
(9 rows)

select * from orca.bm_dyn_test where i=2 and t='2';
i | j | t
Expand Down Expand Up @@ -9750,8 +9738,6 @@ ORDER BY 1 asc ;
-> Materialize (cost=0.00..431.00 rows=1 width=1)
-> Table Scan on my_tt_agg_opt (cost=0.00..431.00 rows=1 width=62)
-> Sequence (cost=0.00..874.01 rows=1 width=8)
-> Partition Selector for my_tq_agg_opt_part (dynamic scan id: 1) (cost=10.00..100.00 rows=50 width=4)
Partitions selected: 2 (out of 2)
-> Result (cost=0.00..874.01 rows=1 width=8)
-> Append (cost=0.00..874.01 rows=1 width=8)
-> Nested Loop (cost=0.00..437.00 rows=1 width=132)
Expand Down
Loading

0 comments on commit 5dc7dda

Please sign in to comment.