Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0a48050

Browse files
committed
Expand partitioned table RTEs level by level, without flattening.
Flattening the partitioning hierarchy at this stage makes various desirable optimizations difficult. The original use case for this patch was partition-wise join, which wants to match up the partitions in one partitioning hierarchy with those in another such hierarchy. However, it now seems that it will also be useful in making partition pruning work using the PartitionDesc rather than constraint exclusion, because with a flattened expansion, we have no easy way to figure out which PartitionDescs apply to which leaf tables in a multi-level partition hierarchy. As it turns out, we end up creating both rte->inh and !rte->inh RTEs for each intermediate partitioned table, just as we previously did for the root table. This seems unnecessary since the partitioned tables have no storage and are not scanned. We might want to go back and rejigger things so that no partitioned tables (including the parent) need !rte->inh RTEs, but that seems to require some adjustments not related to the core purpose of this patch. Ashutosh Bapat, reviewed by me and by Amit Langote. Some final adjustments by me. Discussion: http://postgr.es/m/CAFjFpRd=1venqLL7oGU=C1dEkuvk2DJgvF+7uKbnPHaum1mvHQ@mail.gmail.com
1 parent 0c4b879 commit 0a48050

File tree

9 files changed

+350
-137
lines changed

9 files changed

+350
-137
lines changed

src/backend/optimizer/path/allpaths.c

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "catalog/pg_operator.h"
2525
#include "catalog/pg_proc.h"
2626
#include "foreign/fdwapi.h"
27+
#include "miscadmin.h"
2728
#include "nodes/makefuncs.h"
2829
#include "nodes/nodeFuncs.h"
2930
#ifdef OPTIMIZER_DEBUG
@@ -352,8 +353,8 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
352353
else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
353354
{
354355
/*
355-
* A partitioned table without leaf partitions is marked
356-
* as a dummy rel.
356+
* A partitioned table without any partitions is marked as
357+
* a dummy rel.
357358
*/
358359
set_dummy_rel_pathlist(rel);
359360
}
@@ -867,6 +868,9 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
867868
int nattrs;
868869
ListCell *l;
869870

871+
/* Guard against stack overflow due to overly deep inheritance tree. */
872+
check_stack_depth();
873+
870874
Assert(IS_SIMPLE_REL(rel));
871875

872876
/*
@@ -1290,25 +1294,23 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
12901294
bool build_partitioned_rels = false;
12911295

12921296
/*
1293-
* A plain relation will already have a PartitionedChildRelInfo if it is
1294-
* partitioned. For a subquery RTE, no PartitionedChildRelInfo exists; we
1295-
* collect all partitioned_rels associated with any child. (This assumes
1296-
* that we don't need to look through multiple levels of subquery RTEs; if
1297-
* we ever do, we could create a PartitionedChildRelInfo with the
1298-
* accumulated list of partitioned_rels which would then be found when
1299-
* populated our parent rel with paths. For the present, that appears to
1300-
* be unnecessary.)
1297+
* A root partition will already have a PartitionedChildRelInfo, and a
1298+
* non-root partitioned table doesn't need one, because its Append paths
1299+
* will get flattened into the parent anyway. For a subquery RTE, no
1300+
* PartitionedChildRelInfo exists; we collect all partitioned_rels
1301+
* associated with any child. (This assumes that we don't need to look
1302+
* through multiple levels of subquery RTEs; if we ever do, we could
1303+
* create a PartitionedChildRelInfo with the accumulated list of
1304+
* partitioned_rels which would then be found when populated our parent
1305+
* rel with paths. For the present, that appears to be unnecessary.)
13011306
*/
13021307
rte = planner_rt_fetch(rel->relid, root);
13031308
switch (rte->rtekind)
13041309
{
13051310
case RTE_RELATION:
13061311
if (rte->relkind == RELKIND_PARTITIONED_TABLE)
1307-
{
13081312
partitioned_rels =
13091313
get_partitioned_child_rels(root, rel->relid);
1310-
Assert(list_length(partitioned_rels) >= 1);
1311-
}
13121314
break;
13131315
case RTE_SUBQUERY:
13141316
build_partitioned_rels = true;

src/backend/optimizer/plan/initsplan.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "postgres.h"
1616

1717
#include "catalog/pg_type.h"
18+
#include "catalog/pg_class.h"
1819
#include "nodes/nodeFuncs.h"
1920
#include "optimizer/clauses.h"
2021
#include "optimizer/cost.h"
@@ -629,11 +630,28 @@ create_lateral_join_info(PlannerInfo *root)
629630
for (rti = 1; rti < root->simple_rel_array_size; rti++)
630631
{
631632
RelOptInfo *brel = root->simple_rel_array[rti];
633+
RangeTblEntry *brte = root->simple_rte_array[rti];
632634

633-
if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
635+
if (brel == NULL)
636+
continue;
637+
638+
/*
639+
* In the case of table inheritance, the parent RTE is directly linked
640+
* to every child table via an AppendRelInfo. In the case of table
641+
* partitioning, the inheritance hierarchy is expanded one level at a
642+
* time rather than flattened. Therefore, an other member rel that is
643+
* a partitioned table may have children of its own, and must
644+
* therefore be marked with the appropriate lateral info so that those
645+
* children eventually get marked also.
646+
*/
647+
Assert(IS_SIMPLE_REL(brel));
648+
Assert(brte);
649+
if (brel->reloptkind == RELOPT_OTHER_MEMBER_REL &&
650+
(brte->rtekind != RTE_RELATION ||
651+
brte->relkind != RELKIND_PARTITIONED_TABLE))
634652
continue;
635653

636-
if (root->simple_rte_array[rti]->inh)
654+
if (brte->inh)
637655
{
638656
foreach(lc, root->append_rel_list)
639657
{

src/backend/optimizer/plan/planner.c

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,7 @@ static void
10381038
inheritance_planner(PlannerInfo *root)
10391039
{
10401040
Query *parse = root->parse;
1041-
int parentRTindex = parse->resultRelation;
1041+
int top_parentRTindex = parse->resultRelation;
10421042
Bitmapset *subqueryRTindexes;
10431043
Bitmapset *modifiableARIindexes;
10441044
int nominalRelation = -1;
@@ -1056,6 +1056,10 @@ inheritance_planner(PlannerInfo *root)
10561056
Index rti;
10571057
RangeTblEntry *parent_rte;
10581058
List *partitioned_rels = NIL;
1059+
PlannerInfo *parent_root;
1060+
Query *parent_parse;
1061+
Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex);
1062+
PlannerInfo **parent_roots = NULL;
10591063

10601064
Assert(parse->commandType != CMD_INSERT);
10611065

@@ -1119,11 +1123,31 @@ inheritance_planner(PlannerInfo *root)
11191123
* (including the root parent) as child members of the inheritance set do
11201124
* not appear anywhere else in the plan. The situation is exactly the
11211125
* opposite in the case of non-partitioned inheritance parent as described
1122-
* below.
1126+
* below. For the same reason, collect the list of descendant partitioned
1127+
* tables to be saved in ModifyTable node, so that executor can lock those
1128+
* as well.
11231129
*/
1124-
parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
1130+
parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
11251131
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
1126-
nominalRelation = parentRTindex;
1132+
{
1133+
nominalRelation = top_parentRTindex;
1134+
partitioned_rels = get_partitioned_child_rels(root, top_parentRTindex);
1135+
/* The root partitioned table is included as a child rel */
1136+
Assert(list_length(partitioned_rels) >= 1);
1137+
}
1138+
1139+
/*
1140+
* The PlannerInfo for each child is obtained by translating the relevant
1141+
* members of the PlannerInfo for its immediate parent, which we find
1142+
* using the parent_relid in its AppendRelInfo. We save the PlannerInfo
1143+
* for each parent in an array indexed by relid for fast retrieval. Since
1144+
* the maximum number of parents is limited by the number of RTEs in the
1145+
* query, we use that number to allocate the array. An extra entry is
1146+
* needed since relids start from 1.
1147+
*/
1148+
parent_roots = (PlannerInfo **) palloc0((list_length(parse->rtable) + 1) *
1149+
sizeof(PlannerInfo *));
1150+
parent_roots[top_parentRTindex] = root;
11271151

11281152
/*
11291153
* And now we can get on with generating a plan for each child table.
@@ -1137,15 +1161,24 @@ inheritance_planner(PlannerInfo *root)
11371161
Path *subpath;
11381162

11391163
/* append_rel_list contains all append rels; ignore others */
1140-
if (appinfo->parent_relid != parentRTindex)
1164+
if (!bms_is_member(appinfo->parent_relid, parent_relids))
11411165
continue;
11421166

1167+
/*
1168+
* expand_inherited_rtentry() always processes a parent before any of
1169+
* that parent's children, so the parent_root for this relation should
1170+
* already be available.
1171+
*/
1172+
parent_root = parent_roots[appinfo->parent_relid];
1173+
Assert(parent_root != NULL);
1174+
parent_parse = parent_root->parse;
1175+
11431176
/*
11441177
* We need a working copy of the PlannerInfo so that we can control
11451178
* propagation of information back to the main copy.
11461179
*/
11471180
subroot = makeNode(PlannerInfo);
1148-
memcpy(subroot, root, sizeof(PlannerInfo));
1181+
memcpy(subroot, parent_root, sizeof(PlannerInfo));
11491182

11501183
/*
11511184
* Generate modified query with this rel as target. We first apply
@@ -1154,15 +1187,15 @@ inheritance_planner(PlannerInfo *root)
11541187
* then fool around with subquery RTEs.
11551188
*/
11561189
subroot->parse = (Query *)
1157-
adjust_appendrel_attrs(root,
1158-
(Node *) parse,
1190+
adjust_appendrel_attrs(parent_root,
1191+
(Node *) parent_parse,
11591192
1, &appinfo);
11601193

11611194
/*
11621195
* If there are securityQuals attached to the parent, move them to the
11631196
* child rel (they've already been transformed properly for that).
11641197
*/
1165-
parent_rte = rt_fetch(parentRTindex, subroot->parse->rtable);
1198+
parent_rte = rt_fetch(appinfo->parent_relid, subroot->parse->rtable);
11661199
child_rte = rt_fetch(appinfo->child_relid, subroot->parse->rtable);
11671200
child_rte->securityQuals = parent_rte->securityQuals;
11681201
parent_rte->securityQuals = NIL;
@@ -1173,7 +1206,7 @@ inheritance_planner(PlannerInfo *root)
11731206
* executor doesn't need to see the modified copies --- we can just
11741207
* pass it the original rowMarks list.)
11751208
*/
1176-
subroot->rowMarks = copyObject(root->rowMarks);
1209+
subroot->rowMarks = copyObject(parent_root->rowMarks);
11771210

11781211
/*
11791212
* The append_rel_list likewise might contain references to subquery
@@ -1190,7 +1223,7 @@ inheritance_planner(PlannerInfo *root)
11901223
ListCell *lc2;
11911224

11921225
subroot->append_rel_list = NIL;
1193-
foreach(lc2, root->append_rel_list)
1226+
foreach(lc2, parent_root->append_rel_list)
11941227
{
11951228
AppendRelInfo *appinfo2 = lfirst_node(AppendRelInfo, lc2);
11961229

@@ -1225,7 +1258,7 @@ inheritance_planner(PlannerInfo *root)
12251258
ListCell *lr;
12261259

12271260
rti = 1;
1228-
foreach(lr, parse->rtable)
1261+
foreach(lr, parent_parse->rtable)
12291262
{
12301263
RangeTblEntry *rte = lfirst_node(RangeTblEntry, lr);
12311264

@@ -1272,6 +1305,22 @@ inheritance_planner(PlannerInfo *root)
12721305
/* hack to mark target relation as an inheritance partition */
12731306
subroot->hasInheritedTarget = true;
12741307

1308+
/*
1309+
* If the child is further partitioned, remember it as a parent. Since
1310+
* a partitioned table does not have any data, we don't need to create
1311+
* a plan for it. We do, however, need to remember the PlannerInfo for
1312+
* use when processing its children.
1313+
*/
1314+
if (child_rte->inh)
1315+
{
1316+
Assert(child_rte->relkind == RELKIND_PARTITIONED_TABLE);
1317+
parent_relids =
1318+
bms_add_member(parent_relids, appinfo->child_relid);
1319+
parent_roots[appinfo->child_relid] = subroot;
1320+
1321+
continue;
1322+
}
1323+
12751324
/* Generate Path(s) for accessing this result relation */
12761325
grouping_planner(subroot, true, 0.0 /* retrieve all tuples */ );
12771326

@@ -1368,13 +1417,6 @@ inheritance_planner(PlannerInfo *root)
13681417
Assert(!parse->onConflict);
13691418
}
13701419

1371-
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
1372-
{
1373-
partitioned_rels = get_partitioned_child_rels(root, parentRTindex);
1374-
/* The root partitioned table is included as a child rel */
1375-
Assert(list_length(partitioned_rels) >= 1);
1376-
}
1377-
13781420
/* Result path must go into outer query's FINAL upperrel */
13791421
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
13801422

0 commit comments

Comments
 (0)