From 0b11ae47f741f2ea6219e5d4c4697d5583f56c97 Mon Sep 17 00:00:00 2001 From: amit Date: Mon, 4 Mar 2019 15:10:29 +0900 Subject: [PATCH v27 2/6] Delay adding inheritance child tables until query_planner Inheritance child tables are now added by add_other_rels_to_query, which is called by query_planner. This replaces expand_inherited_tables called by subquery_planner as the method of adding child tables. At the point when add_other_rels_to_query is called, restriction clauses have already been assigned to individual base relations, so it will now be possible to perform partition pruning so that we know exact child tables to add in that case. This commit however doesn't change when pruning is performed. Since we're now adding children (and so any PlanRowMarks for them) much later, preprocess_targetlist cannot conclude which junk columns to add for a given "parent" PlanRowMark, because it depends on the value of allMarkTypes field of PlanRowMarks. The correct value of it cannot be determined until after we've seen all the child tables that will be scanned, so we must delay adding junk columns based on "parent" PlanRowMarks too. inheritance_planner now adds the child target tables on its own, because subquery_planner doesn't. Also, since it calls query_planner once for every child relation, source inheritance child tables are added multiple times. This both slows down queries when there are inherited tables in UPDATE/DELETE's FROM clause (source inheritance) and changes the EXPLAIN output a bit because source inheritance child tables' aliases come out different for every targer child subplan. Another patch will fix both these issues. --- contrib/postgres_fdw/expected/postgres_fdw.out | 24 ++--- src/backend/optimizer/plan/planner.c | 57 +++++++--- src/backend/optimizer/prep/preptlist.c | 131 ++++++++++++++--------- src/backend/optimizer/util/inherit.c | 141 +++++++++++++++++-------- src/backend/optimizer/util/plancat.c | 3 +- src/backend/optimizer/util/relnode.c | 61 ++++++++++- src/include/optimizer/inherit.h | 4 +- src/include/optimizer/pathnode.h | 1 + src/include/optimizer/prep.h | 2 + src/test/regress/expected/partition_prune.out | 12 +-- src/test/regress/expected/rowsecurity.out | 16 +-- 11 files changed, 314 insertions(+), 138 deletions(-) diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 42108bd3d4..4d31cfed5d 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -7128,15 +7128,15 @@ select * from bar where f1 in (select f1 from foo) for update; Output: bar2.f1, bar2.f2, bar2.ctid, bar2.*, bar2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE -> Hash - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> HashAggregate - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid Group Key: foo.f1 -> Append -> Seq Scan on public.foo - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> Foreign Scan on public.foo2 - Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1 + Output: foo2.f1, foo2.ctid, foo2.*, foo2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1 (23 rows) @@ -7166,15 +7166,15 @@ select * from bar where f1 in (select f1 from foo) for share; Output: bar2.f1, bar2.f2, bar2.ctid, bar2.*, bar2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR SHARE -> Hash - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> HashAggregate - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid Group Key: foo.f1 -> Append -> Seq Scan on public.foo - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> Foreign Scan on public.foo2 - Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1 + Output: foo2.f1, foo2.ctid, foo2.*, foo2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1 (23 rows) @@ -7203,15 +7203,15 @@ update bar set f2 = f2 + 100 where f1 in (select f1 from foo); -> Seq Scan on public.bar Output: bar.f1, bar.f2, bar.ctid -> Hash - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> HashAggregate - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid Group Key: foo.f1 -> Append -> Seq Scan on public.foo - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> Foreign Scan on public.foo2 - Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1 + Output: foo2.f1, foo2.ctid, foo2.*, foo2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1 -> Hash Join Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, foo.ctid, foo.*, foo.tableoid diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index bc81535905..261c4e5661 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -25,6 +25,7 @@ #include "access/table.h" #include "access/xact.h" #include "catalog/pg_constraint.h" +#include "catalog/pg_inherits.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "executor/executor.h" @@ -714,27 +715,24 @@ subquery_planner(PlannerGlobal *glob, Query *parse, } if (rte->lateral) root->hasLateralRTEs = true; + + /* + * While at it, also update the inh status. If the relation doesn't + * or can't have any children, there is no point in letting inh be set + * to true. Note that we do this before processing rowmarks, so that + * the correct information for setting isParent field of PlanRowMarks. + */ + if (rte->rtekind == RTE_RELATION) + rte->inh = rte->inh && has_subclass(rte->relid); } /* * Preprocess RowMark information. We need to do this after subquery - * pullup (so that all non-inherited RTEs are present) and before - * inheritance expansion (so that the info is available for - * expand_inherited_tables to examine and modify). + * pullup (so that all non-inherited RTEs are present). */ preprocess_rowmarks(root); /* - * Expand any rangetable entries that are inheritance sets into "append - * relations". This can add entries to the rangetable, but they must be - * plain RTE_RELATION entries, so it's OK (and marginally more efficient) - * to do it after checking for joins and other special RTEs. We must do - * this after pulling up subqueries, else we'd fail to handle inherited - * tables in subqueries. - */ - expand_inherited_tables(root); - - /* * Set hasHavingQual to remember if HAVING clause is present. Needed * because preprocess_expression will reduce a constant-true condition to * an empty qual list ... but "HAVING TRUE" is not a semantic no-op. @@ -1210,10 +1208,35 @@ inheritance_planner(PlannerInfo *root) Query *parent_parse; Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex); PlannerInfo **parent_roots = NULL; + List *orig_append_rel_list = list_copy(root->append_rel_list); Assert(parse->commandType != CMD_INSERT); /* + * Add child target relations. Note that this only adds the children of + * the query's target relation and no other. Especially, children of any + * source relations are added when the loop below calls grouping_planner + * on the *1st* child target relation. + */ + parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable); + + expand_inherited_rtentry(root, parent_rte, top_parentRTindex); + + /* + * If parent no longer has any children, then treat this as an update of + * a single table. + */ + if (!parent_rte->inh) + { + /* + * We'll be retrieving all tuples to modify, so passing 0.0 for + * tuple_fraction. + */ + grouping_planner(root, false, 0.0); + return; + } + + /* * We generate a modified instance of the original Query for each target * relation, plan that, and put all the plans into a list that will be * controlled by a single ModifyTable node. All the instances share the @@ -1274,7 +1297,6 @@ inheritance_planner(PlannerInfo *root) * not appear anywhere else in the plan, so the confusion explained below * for non-partitioning inheritance cases is not possible. */ - parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable); if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE) { nominalRelation = top_parentRTindex; @@ -1325,6 +1347,9 @@ inheritance_planner(PlannerInfo *root) subroot = makeNode(PlannerInfo); memcpy(subroot, parent_root, sizeof(PlannerInfo)); + /* grouping_planner doesn't need to see the target children. */ + subroot->append_rel_list = list_copy(orig_append_rel_list); + /* * Generate modified query with this rel as target. We first apply * adjust_appendrel_attrs, which copies the Query and changes @@ -2618,7 +2643,7 @@ preprocess_rowmarks(PlannerInfo *root) newrc->allMarkTypes = (1 << newrc->markType); newrc->strength = rc->strength; newrc->waitPolicy = rc->waitPolicy; - newrc->isParent = false; + newrc->isParent = rte->inh; prowmarks = lappend(prowmarks, newrc); } @@ -2643,7 +2668,7 @@ preprocess_rowmarks(PlannerInfo *root) newrc->allMarkTypes = (1 << newrc->markType); newrc->strength = LCS_NONE; newrc->waitPolicy = LockWaitBlock; /* doesn't matter */ - newrc->isParent = false; + newrc->isParent = rte->rtekind == RTE_RELATION ? rte->inh : false; prowmarks = lappend(prowmarks, newrc); } diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 5392d1a561..41578f2653 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -126,61 +126,23 @@ preprocess_targetlist(PlannerInfo *root) foreach(lc, root->rowMarks) { PlanRowMark *rc = (PlanRowMark *) lfirst(lc); - Var *var; - char resname[32]; - TargetEntry *tle; + List *junk_tles; /* child rels use the same junk attrs as their parents */ if (rc->rti != rc->prti) continue; - if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY)) - { - /* Need to fetch TID */ - var = makeVar(rc->rti, - SelfItemPointerAttributeNumber, - TIDOID, - -1, - InvalidOid, - 0); - snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId); - tle = makeTargetEntry((Expr *) var, - list_length(tlist) + 1, - pstrdup(resname), - true); - tlist = lappend(tlist, tle); - } - if (rc->allMarkTypes & (1 << ROW_MARK_COPY)) - { - /* Need the whole row as a junk var */ - var = makeWholeRowVar(rt_fetch(rc->rti, range_table), - rc->rti, - 0, - false); - snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId); - tle = makeTargetEntry((Expr *) var, - list_length(tlist) + 1, - pstrdup(resname), - true); - tlist = lappend(tlist, tle); - } - - /* If parent of inheritance tree, always fetch the tableoid too. */ + /* + * For inheritance parent row marks, we defer adding junk columns + * until we've added child row marks, because some children might + * require different row mark types which will change the parent row + * mark's allMarkTypes fields. + */ if (rc->isParent) - { - var = makeVar(rc->rti, - TableOidAttributeNumber, - OIDOID, - -1, - InvalidOid, - 0); - snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId); - tle = makeTargetEntry((Expr *) var, - list_length(tlist) + 1, - pstrdup(resname), - true); - tlist = lappend(tlist, tle); - } + continue; + + junk_tles = get_rowmark_junk_tles(root, tlist, rc); + tlist = list_concat(tlist, junk_tles); } /* @@ -434,3 +396,74 @@ get_plan_rowmark(List *rowmarks, Index rtindex) } return NULL; } + +/* + * get_rowmark_junk_tles + * Returns TLEs for junk columns necessary for implementing given + * PlanRowMark + * + * These TLEs are needed for locking of rels selected FOR UPDATE/SHARE, and + * to do EvalPlanQual rechecking. See comments for PlanRowMark. + */ +List * +get_rowmark_junk_tles(PlannerInfo *root, List *tlist, PlanRowMark *rc) +{ + List *range_table = root->parse->rtable; + int tlist_len = list_length(tlist); + List *junk_tles = NIL; + Var *var; + char resname[32]; + TargetEntry *tle; + + if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY)) + { + /* Need to fetch TID */ + var = makeVar(rc->rti, + SelfItemPointerAttributeNumber, + TIDOID, + -1, + InvalidOid, + 0); + snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId); + tle = makeTargetEntry((Expr *) var, + tlist_len + 1, + pstrdup(resname), + true); + junk_tles = lappend(junk_tles, tle); + tlist_len++; + } + if (rc->allMarkTypes & (1 << ROW_MARK_COPY)) + { + /* Need the whole row as a junk var */ + var = makeWholeRowVar(rt_fetch(rc->rti, range_table), + rc->rti, + 0, + false); + snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId); + tle = makeTargetEntry((Expr *) var, + tlist_len + 1, + pstrdup(resname), + true); + junk_tles = lappend(junk_tles, tle); + tlist_len++; + } + + /* For inheritance cases, always fetch the tableoid too. */ + if (rc->isParent) + { + var = makeVar(rc->rti, + TableOidAttributeNumber, + OIDOID, + -1, + InvalidOid, + 0); + snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId); + tle = makeTargetEntry((Expr *) var, + tlist_len + 1, + pstrdup(resname), + true); + junk_tles = lappend(junk_tles, tle); + } + + return junk_tles; +} diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c index a014a12060..697de74505 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -21,14 +21,14 @@ #include "miscadmin.h" #include "optimizer/appendinfo.h" #include "optimizer/inherit.h" +#include "optimizer/pathnode.h" +#include "optimizer/planmain.h" #include "optimizer/planner.h" #include "optimizer/prep.h" #include "partitioning/partdesc.h" #include "utils/rel.h" -static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, - Index rti); static void expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, @@ -45,36 +45,6 @@ static Bitmapset *translate_col_privs(const Bitmapset *parent_privs, /* - * expand_inherited_tables - * Expand each rangetable entry that represents an inheritance set - * into an "append relation". At the conclusion of this process, - * the "inh" flag is set in all and only those RTEs that are append - * relation parents. - */ -void -expand_inherited_tables(PlannerInfo *root) -{ - Index nrtes; - Index rti; - ListCell *rl; - - /* - * expand_inherited_rtentry may add RTEs to parse->rtable. The function is - * expected to recursively handle any RTEs that it creates with inh=true. - * So just scan as far as the original end of the rtable list. - */ - nrtes = list_length(root->parse->rtable); - rl = list_head(root->parse->rtable); - for (rti = 1; rti <= nrtes; rti++) - { - RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl); - - expand_inherited_rtentry(root, rte, rti); - rl = lnext(rl); - } -} - -/* * expand_inherited_rtentry * Check whether a rangetable entry represents an inheritance set. * If so, add entries for all the child tables to the query's @@ -94,7 +64,7 @@ expand_inherited_tables(PlannerInfo *root) * Since a partitioned table is not scanned, it might have only one associated * AppendRelInfo. */ -static void +void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) { Oid parentOID; @@ -160,6 +130,8 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) List *appinfos = NIL; RangeTblEntry *childrte; Index childRTindex; + bool is_source_inh_expansion; + RelOptInfo *rel = NULL; /* Scan for all members of inheritance set, acquire needed locks */ inhOIDs = find_all_inheritors(parentOID, lockmode, NULL); @@ -178,6 +150,20 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) } /* + * If parent is a source relation of the query, we'd need to + * add the child RelOptInfos as well in addition to RangeTblEntry's + * and AppendRelInfo's. We can tell it's source relation by noticing + * that simple_rel_array has been set up by query_planner. + */ + is_source_inh_expansion = (root->simple_rel_array_size > 0); + if (is_source_inh_expansion) + { + rel = find_base_rel(root, rti); + /* Expand various arrays in PlannerInfo to hold child object. */ + expand_planner_arrays(root, list_length(inhOIDs)); + } + + /* * This table has no partitions. Expand any plain inheritance * children in the order the OIDs were returned by * find_all_inheritors. @@ -210,6 +196,10 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) &appinfos, &childrte, &childRTindex); + /* Create the otherrel RelOptInfo too. */ + if (is_source_inh_expansion) + (void) build_simple_rel(root, childRTindex, rel); + /* Close child relations, but keep locks */ if (childOID != parentOID) table_close(newrelation, NoLock); @@ -230,6 +220,19 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) } + /* + * Add junk columns needed by the row mark if any and also add the + * relevant expressions to the root parent's reltarget. + */ + if (oldrc) + { + List *tlist = root->processed_tlist; + List *junk_tles = get_rowmark_junk_tles(root, tlist, oldrc); + + build_base_rel_tlists(root, junk_tles); + root->processed_tlist = list_concat(root->processed_tlist, junk_tles); + } + table_close(oldrelation, NoLock); } @@ -247,6 +250,8 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte, RangeTblEntry *childrte; Index childRTindex; PartitionDesc partdesc = RelationGetPartitionDesc(parentrel); + RelOptInfo *rel = NULL; + bool is_source_inh_expansion; check_stack_depth(); @@ -266,6 +271,35 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte, root->partColsUpdated = has_partition_attrs(parentrel, parentrte->updatedCols, NULL); + /* + * If parent is a source relation of the query, we'd need to + * add the child RelOptInfos as well in addition to RangeTblEntry's + * and AppendRelInfo's. We can tell it's source relation by noticing + * that simple_rel_array has been set up by query_planner. + */ + is_source_inh_expansion = (root->simple_rel_array_size > 0); + if (is_source_inh_expansion) + { + rel = find_base_rel(root, parentRTindex); + + /* + * Expand simple_rel_array and friends to hold child objects. + * + * We'll need nparts + 1 new slots, because we also consider parent + * as a child relation. FIXME: no longer add the parent as child + */ + expand_planner_arrays(root, partdesc->nparts + 1); + + /* + * We also store partition RelOptInfo pointers in the parent + * relation. + */ + Assert(rel->part_rels == NULL); + if (partdesc->nparts > 0) + rel->part_rels = (RelOptInfo **) palloc0(rel->nparts * + sizeof(RelOptInfo *)); + } + /* First expand the partitioned table itself. */ expand_single_inheritance_child(root, parentrte, parentRTindex, parentrel, top_parentrc, parentrel, @@ -301,8 +335,12 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte, parentrel, top_parentrc, childrel, appinfos, &childrte, &childRTindex); + /* Create the otherrel RelOptInfo too. */ + if (is_source_inh_expansion) + rel->part_rels[i] = build_simple_rel(root, childRTindex, rel); + /* If this child is itself partitioned, recurse */ - if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + if (childrte->inh) expand_partitioned_rtentry(root, childrte, childRTindex, childrel, top_parentrc, lockmode, appinfos); @@ -345,7 +383,8 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, Oid childOID = RelationGetRelid(childrel); RangeTblEntry *childrte; Index childRTindex; - AppendRelInfo *appinfo; + AppendRelInfo *appinfo = NULL; + PartitionDesc childrel_partdesc = RelationGetPartitionDesc(childrel); /* * Build an RTE for the child, and attach to query's rangetable list. We @@ -363,9 +402,14 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, *childrte_p = childrte; childrte->relid = childOID; childrte->relkind = childrel->rd_rel->relkind; - /* A partitioned child will need to be expanded further. */ + /* + * A partitioned child will need to be expanded further, but only if it + * actually has partitions. A partitioned table with zero children is + * specially handled in set_rel_size(). + */ if (childOID != parentOID && - childrte->relkind == RELKIND_PARTITIONED_TABLE) + childrte->relkind == RELKIND_PARTITIONED_TABLE && + childrel_partdesc->nparts > 0) childrte->inh = true; else childrte->inh = false; @@ -376,13 +420,11 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, *childRTindex_p = childRTindex; /* - * We need an AppendRelInfo if paths will be built for the child RTE. If - * childrte->inh is true, then we'll always need to generate append paths - * for it. If childrte->inh is false, we must scan it if it's not a - * partitioned table; but if it is a partitioned table, then it never has - * any data of its own and need not be scanned. + * Don't need an AppendRelInfo for duplicate RTEs we create for + * partitioned table parent rels. */ - if (childrte->relkind != RELKIND_PARTITIONED_TABLE || childrte->inh) + if (childrte->relid != parentOID || + childrte->relkind != RELKIND_PARTITIONED_TABLE) { appinfo = make_append_rel_info(parentrel, childrel, parentRTindex, childRTindex); @@ -409,6 +451,19 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, } /* + * Store the RTE and appinfo in the PlannerInfo, which the caller must + * already have allocated space for. + */ + if (root->simple_rel_array_size > 0) + { + Assert(childRTindex < root->simple_rel_array_size); + Assert(root->simple_rte_array[childRTindex] == NULL); + root->simple_rte_array[childRTindex] = childrte; + Assert(root->append_rel_array[childRTindex] == NULL); + root->append_rel_array[childRTindex] = appinfo; + } + + /* * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE. */ if (top_parentrc) diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 78a96b4ee2..549af9dc6e 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -2090,7 +2090,8 @@ set_relation_partition_info(PlannerInfo *root, RelOptInfo *rel, partkey = RelationGetPartitionKey(relation); rel->part_scheme = find_partition_scheme(root, relation); Assert(partdesc != NULL && rel->part_scheme != NULL); - rel->boundinfo = partition_bounds_copy(partdesc->boundinfo, partkey); + if (partdesc->nparts > 0) + rel->boundinfo = partition_bounds_copy(partdesc->boundinfo, partkey); rel->nparts = partdesc->nparts; set_baserel_partition_key_exprs(relation, rel); rel->partition_qual = RelationGetPartitionQual(relation); diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index a618950f88..58b19307af 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -139,6 +139,50 @@ setup_append_rel_array(PlannerInfo *root) } /* + * expand_planner_arrays + * Expand the PlannerInfo arrays by add_size members and initialize the + * the newly added bytes with zero + */ +void +expand_planner_arrays(PlannerInfo *root, int add_size) +{ + int new_size; + + Assert(add_size > 0); + + new_size = root->simple_rel_array_size + add_size; + + /* Expand various arrays and 0-initialize added bytes. */ + root->simple_rte_array = (RangeTblEntry **) + repalloc(root->simple_rte_array, + sizeof(RangeTblEntry *) * new_size); + MemSet(root->simple_rte_array + root->simple_rel_array_size, + 0, sizeof(RangeTblEntry *) * add_size); + root->simple_rel_array = (RelOptInfo **) + repalloc(root->simple_rel_array, + sizeof(RelOptInfo *) * new_size); + MemSet(root->simple_rel_array + root->simple_rel_array_size, + 0, sizeof(RelOptInfo *) * add_size); + + if (root->append_rel_array) + { + root->append_rel_array = (AppendRelInfo **) + repalloc(root->append_rel_array, + sizeof(AppendRelInfo *) * new_size); + MemSet(root->append_rel_array + root->simple_rel_array_size, + 0, sizeof(AppendRelInfo *) * add_size); + } + else + { + root->append_rel_array = (AppendRelInfo **) + palloc0(sizeof(AppendRelInfo *) * + new_size); + } + + root->simple_rel_array_size = new_size; +} + +/* * build_simple_rel * Construct a new RelOptInfo for a base relation or 'other' relation. */ @@ -297,6 +341,18 @@ add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti) RelOptInfo *rel; int i; + /* + * Add inheritance children to the query. For child tables that are + * themselves partitioned, their children will be added recursively. + */ + if (rte->rtekind == RTE_RELATION) + { + expand_inherited_rtentry(root, rte, rti); + return; + } + + /* Add other rels of flattened UNION ALL children. */ + Assert(rte->rtekind == RTE_SUBQUERY); rel = find_base_rel(root, rti); /* @@ -304,8 +360,11 @@ add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti) * rel->part_rels array too. */ if (rel->part_scheme) + { + Assert(rel->nparts > 0); rel->part_rels = (RelOptInfo **) palloc0(sizeof(RelOptInfo *) * rel->nparts); + } i = 0; foreach(l, root->append_rel_list) @@ -331,7 +390,7 @@ add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti) */ if (rel->part_scheme != NULL) { - Assert(rel->nparts > 0 && i < rel->nparts); + Assert(i < rel->nparts); rel->part_rels[i] = childrel; } diff --git a/src/include/optimizer/inherit.h b/src/include/optimizer/inherit.h index d2418f15cf..427c1d0abe 100644 --- a/src/include/optimizer/inherit.h +++ b/src/include/optimizer/inherit.h @@ -16,7 +16,7 @@ #include "nodes/pathnodes.h" - -extern void expand_inherited_tables(PlannerInfo *root); +extern void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, + Index rti); #endif /* INHERIT_H */ diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 1a07963a7d..60361507d2 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -277,6 +277,7 @@ extern Path *reparameterize_path_by_child(PlannerInfo *root, Path *path, */ extern void setup_simple_rel_arrays(PlannerInfo *root); extern void setup_append_rel_array(PlannerInfo *root); +extern void expand_planner_arrays(PlannerInfo *root, int add_size); extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent); extern void add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index a9b2c9026c..5979c9885e 100644 --- a/src/include/optimizer/prep.h +++ b/src/include/optimizer/prep.h @@ -37,6 +37,8 @@ extern Relids get_relids_for_join(Query *query, int joinrelid); extern List *preprocess_targetlist(PlannerInfo *root); extern PlanRowMark *get_plan_rowmark(List *rowmarks, Index rtindex); +extern List *get_rowmark_junk_tles(PlannerInfo *root, List *tlist, + PlanRowMark *rc); /* * prototypes for prepunion.c diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index 30946f77b6..71942394ba 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -2559,16 +2559,16 @@ update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; Index Cond: (a = 1) -> Nested Loop (actual rows=1 loops=1) -> Append (actual rows=1 loops=1) - -> Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_1 (actual rows=0 loops=1) + -> Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_2 (actual rows=0 loops=1) Recheck Cond: (a = 1) -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_1 (actual rows=1 loops=1) + -> Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_2 (actual rows=1 loops=1) Recheck Cond: (a = 1) Heap Blocks: exact=1 -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_1 (actual rows=0 loops=1) + -> Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_2 (actual rows=0 loops=1) Recheck Cond: (a = 1) -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) @@ -2580,16 +2580,16 @@ update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; Index Cond: (a = 1) -> Nested Loop (actual rows=0 loops=1) -> Append (actual rows=1 loops=1) - -> Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_1 (actual rows=0 loops=1) + -> Bitmap Heap Scan on ab_a1_b1 ab_a1_b1_3 (actual rows=0 loops=1) Recheck Cond: (a = 1) -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_1 (actual rows=1 loops=1) + -> Bitmap Heap Scan on ab_a1_b2 ab_a1_b2_3 (actual rows=1 loops=1) Recheck Cond: (a = 1) Heap Blocks: exact=1 -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_1 (actual rows=0 loops=1) + -> Bitmap Heap Scan on ab_a1_b3 ab_a1_b3_3 (actual rows=0 loops=1) Recheck Cond: (a = 1) -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out index 2e170497c9..a6a499ed4a 100644 --- a/src/test/regress/expected/rowsecurity.out +++ b/src/test/regress/expected/rowsecurity.out @@ -1815,26 +1815,26 @@ AND f_leak(t1_1.b) AND f_leak(t1_2.b) RETURNING *, t1_1, t1_2; -> Seq Scan on t3 t1_2_2 Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) -> Nested Loop - Join Filter: (t1_1_1.b = t1_2.b) + Join Filter: (t1_1_1.b = t1_2_3.b) -> Seq Scan on t2 t1_1_1 Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) -> Append - -> Seq Scan on t1 t1_2 + -> Seq Scan on t1 t1_2_3 Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) - -> Seq Scan on t2 t1_2_1 + -> Seq Scan on t2 t1_2_4 Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) - -> Seq Scan on t3 t1_2_2 + -> Seq Scan on t3 t1_2_5 Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) -> Nested Loop - Join Filter: (t1_1_2.b = t1_2.b) + Join Filter: (t1_1_2.b = t1_2_6.b) -> Seq Scan on t3 t1_1_2 Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) -> Append - -> Seq Scan on t1 t1_2 + -> Seq Scan on t1 t1_2_6 Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) - -> Seq Scan on t2 t1_2_1 + -> Seq Scan on t2 t1_2_7 Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) - -> Seq Scan on t3 t1_2_2 + -> Seq Scan on t3 t1_2_8 Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) (37 rows) -- 2.11.0