From 74d38c91f9c37f8c6ede2a1a63ae3fec6731a10d Mon Sep 17 00:00:00 2001 From: Ashutosh Bapat Date: Fri, 3 Feb 2017 17:22:52 +0530 Subject: [PATCH 03/11] Refactor adjust_appendrel_attrs. adjust_appendrel_attrs() is used to translate nodes for a parent relation to those for a child relation by replacing the parent specific nodes like Var nodes with corresponding nodes specific to the child. Right now this function works with a single parent-child pair. For partition-wise join and partition-wise aggregation/grouping, we require to translate nodes for multiple parent-child pairs. This patch modifies adjust_appendrel_attrs() to work with multiple parent-child pairs. --- src/backend/optimizer/path/allpaths.c | 7 +- src/backend/optimizer/path/equivclass.c | 2 +- src/backend/optimizer/plan/planner.c | 2 +- src/backend/optimizer/prep/prepunion.c | 161 ++++++++++++++++++++++--------- src/include/optimizer/prep.h | 2 +- 5 files changed, 121 insertions(+), 53 deletions(-) diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index d797d6a..d8fac14 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -862,6 +862,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, ListCell *parentvars; ListCell *childvars; ListCell *lc; + List *appinfo_list = list_make1(appinfo); /* append_rel_list contains all append rels; ignore others */ if (appinfo->parent_relid != parentRTindex) @@ -903,7 +904,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, Assert(IsA(rinfo, RestrictInfo)); childqual = adjust_appendrel_attrs(root, (Node *) rinfo->clause, - appinfo); + appinfo_list); childqual = eval_const_expressions(root, childqual); /* check for flat-out constant */ if (childqual && IsA(childqual, Const)) @@ -1022,11 +1023,11 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, childrel->joininfo = (List *) adjust_appendrel_attrs(root, (Node *) rel->joininfo, - appinfo); + appinfo_list); childrel->reltarget->exprs = (List *) adjust_appendrel_attrs(root, (Node *) rel->reltarget->exprs, - appinfo); + appinfo_list); /* * We have to make child entries in the EquivalenceClass data diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index a329dd1..bcce142 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -2111,7 +2111,7 @@ add_child_rel_equivalences(PlannerInfo *root, child_expr = (Expr *) adjust_appendrel_attrs(root, (Node *) cur_em->em_expr, - appinfo); + list_make1(appinfo)); /* * Transform em_relids to match. Note we do *not* do diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 881742f..24a48b8 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -1085,7 +1085,7 @@ inheritance_planner(PlannerInfo *root) subroot->parse = (Query *) adjust_appendrel_attrs(root, (Node *) parse, - appinfo); + list_make1(appinfo)); /* * If there are securityQuals attached to the parent, move them to the diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 06e843d..6f41979 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -55,7 +55,7 @@ typedef struct { PlannerInfo *root; - AppendRelInfo *appinfo; + List *appinfos; } adjust_appendrel_attrs_context; static Path *recurse_set_operations(Node *setOp, PlannerInfo *root, @@ -107,9 +107,9 @@ static Bitmapset *translate_col_privs(const Bitmapset *parent_privs, List *translated_vars); static Node *adjust_appendrel_attrs_mutator(Node *node, adjust_appendrel_attrs_context *context); -static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid); static List *adjust_inherited_tlist(List *tlist, AppendRelInfo *context); +static Relids adjust_relid_set(Relids relids, List *append_rel_infos); /* @@ -1719,10 +1719,10 @@ translate_col_privs(const Bitmapset *parent_privs, /* * adjust_appendrel_attrs - * Copy the specified query or expression and translate Vars referring - * to the parent rel of the specified AppendRelInfo to refer to the - * child rel instead. We also update rtindexes appearing outside Vars, - * such as resultRelation and jointree relids. + * Copy the specified query or expression and translate Vars referring to + * the parent rels of the specified in the given list of AppendRelInfos to + * refer to the corresponding child rel instead. We also update rtindexes + * appearing outside Vars, such as resultRelation and jointree relids. * * Note: this is only applied after conversion of sublinks to subplans, * so we don't need to cope with recursion into sub-queries. @@ -1731,13 +1731,20 @@ translate_col_privs(const Bitmapset *parent_privs, * maybe we should try to fold the two routines together. */ Node * -adjust_appendrel_attrs(PlannerInfo *root, Node *node, AppendRelInfo *appinfo) +adjust_appendrel_attrs(PlannerInfo *root, Node *node, List *appinfos) { Node *result; adjust_appendrel_attrs_context context; + ListCell *lc; context.root = root; - context.appinfo = appinfo; + context.appinfos = appinfos; + + /* + * Catch a caller who wants to adjust expressions, but doesn't pass any + * AppendRelInfo. + */ + Assert(appinfos && list_length(appinfos) >= 1); /* * Must be prepared to start with a Query or a bare expression tree. @@ -1745,20 +1752,28 @@ adjust_appendrel_attrs(PlannerInfo *root, Node *node, AppendRelInfo *appinfo) if (node && IsA(node, Query)) { Query *newnode; + AppendRelInfo *appinfo; newnode = query_tree_mutator((Query *) node, adjust_appendrel_attrs_mutator, (void *) &context, QTW_IGNORE_RC_SUBQUERIES); - if (newnode->resultRelation == appinfo->parent_relid) + foreach (lc, appinfos) { - newnode->resultRelation = appinfo->child_relid; - /* Fix tlist resnos too, if it's inherited UPDATE */ - if (newnode->commandType == CMD_UPDATE) - newnode->targetList = - adjust_inherited_tlist(newnode->targetList, - appinfo); + appinfo = lfirst(lc); + + if (newnode->resultRelation == appinfo->parent_relid) + { + newnode->resultRelation = appinfo->child_relid; + /* Fix tlist resnos too, if it's inherited UPDATE */ + if (newnode->commandType == CMD_UPDATE) + newnode->targetList = + adjust_inherited_tlist(newnode->targetList, + appinfo); + break; + } } + result = (Node *) newnode; } else @@ -1771,13 +1786,29 @@ static Node * adjust_appendrel_attrs_mutator(Node *node, adjust_appendrel_attrs_context *context) { - AppendRelInfo *appinfo = context->appinfo; + List *appinfos = context->appinfos; + ListCell *lc; + + /* + * Catch a caller who wants to adjust expressions, but doesn't pass any + * AppendRelInfo. + */ + Assert(appinfos && list_length(appinfos) >= 1); if (node == NULL) return NULL; if (IsA(node, Var)) { Var *var = (Var *) copyObject(node); + AppendRelInfo *appinfo; + + foreach (lc, appinfos) + { + appinfo = lfirst(lc); + + if (var->varno == appinfo->parent_relid) + break; + } if (var->varlevelsup == 0 && var->varno == appinfo->parent_relid) @@ -1860,29 +1891,54 @@ adjust_appendrel_attrs_mutator(Node *node, { CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node); - if (cexpr->cvarno == appinfo->parent_relid) - cexpr->cvarno = appinfo->child_relid; + foreach (lc, appinfos) + { + AppendRelInfo *appinfo = lfirst(lc); + + if (cexpr->cvarno == appinfo->parent_relid) + { + cexpr->cvarno = appinfo->child_relid; + break; + } + } return (Node *) cexpr; } if (IsA(node, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) copyObject(node); - if (rtr->rtindex == appinfo->parent_relid) - rtr->rtindex = appinfo->child_relid; + foreach (lc, appinfos) + { + AppendRelInfo *appinfo = lfirst(lc); + + if (rtr->rtindex == appinfo->parent_relid) + { + rtr->rtindex = appinfo->child_relid; + break; + } + } return (Node *) rtr; } if (IsA(node, JoinExpr)) { /* Copy the JoinExpr node with correct mutation of subnodes */ JoinExpr *j; + AppendRelInfo *appinfo; j = (JoinExpr *) expression_tree_mutator(node, adjust_appendrel_attrs_mutator, (void *) context); /* now fix JoinExpr's rtindex (probably never happens) */ - if (j->rtindex == appinfo->parent_relid) - j->rtindex = appinfo->child_relid; + foreach (lc, appinfos) + { + appinfo = lfirst(lc); + + if (j->rtindex == appinfo->parent_relid) + { + j->rtindex = appinfo->child_relid; + break; + } + } return (Node *) j; } if (IsA(node, PlaceHolderVar)) @@ -1895,9 +1951,7 @@ adjust_appendrel_attrs_mutator(Node *node, (void *) context); /* now fix PlaceHolderVar's relid sets */ if (phv->phlevelsup == 0) - phv->phrels = adjust_relid_set(phv->phrels, - appinfo->parent_relid, - appinfo->child_relid); + phv->phrels = adjust_relid_set(phv->phrels, context->appinfos); return (Node *) phv; } /* Shouldn't need to handle planner auxiliary nodes here */ @@ -1929,23 +1983,17 @@ adjust_appendrel_attrs_mutator(Node *node, /* adjust relid sets too */ newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids, - appinfo->parent_relid, - appinfo->child_relid); + context->appinfos); newinfo->required_relids = adjust_relid_set(oldinfo->required_relids, - appinfo->parent_relid, - appinfo->child_relid); + context->appinfos); newinfo->outer_relids = adjust_relid_set(oldinfo->outer_relids, - appinfo->parent_relid, - appinfo->child_relid); + context->appinfos); newinfo->nullable_relids = adjust_relid_set(oldinfo->nullable_relids, - appinfo->parent_relid, - appinfo->child_relid); + context->appinfos); newinfo->left_relids = adjust_relid_set(oldinfo->left_relids, - appinfo->parent_relid, - appinfo->child_relid); + context->appinfos); newinfo->right_relids = adjust_relid_set(oldinfo->right_relids, - appinfo->parent_relid, - appinfo->child_relid); + context->appinfos); /* * Reset cached derivative fields, since these might need to have @@ -1977,19 +2025,38 @@ adjust_appendrel_attrs_mutator(Node *node, } /* - * Substitute newrelid for oldrelid in a Relid set + * Replace parent relids by child relids in the copy of given relid set + * according to the given list of AppendRelInfos. The given relid set is + * returned as is if it contains no parent in the given list, otherwise, the + * given relid set is not changed. */ -static Relids -adjust_relid_set(Relids relids, Index oldrelid, Index newrelid) +Relids +adjust_relid_set(Relids relids, List *append_rel_infos) { - if (bms_is_member(oldrelid, relids)) + ListCell *lc; + Bitmapset *result = NULL; + + foreach (lc, append_rel_infos) { - /* Ensure we have a modifiable copy */ - relids = bms_copy(relids); - /* Remove old, add new */ - relids = bms_del_member(relids, oldrelid); - relids = bms_add_member(relids, newrelid); + AppendRelInfo *appinfo = lfirst(lc); + + /* Remove parent, add child */ + if (bms_is_member(appinfo->parent_relid, relids)) + { + /* Make a copy if we are changing the set. */ + if (!result) + result = bms_copy(relids); + + result = bms_del_member(result, appinfo->parent_relid); + result = bms_add_member(result, appinfo->child_relid); + } } + + /* Return new set if we modified the given set. */ + if (result) + return result; + + /* Else return the given relids set as is. */ return relids; } @@ -2110,5 +2177,5 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, else Assert(parent_rel->reloptkind == RELOPT_BASEREL); /* Now translate for this child */ - return adjust_appendrel_attrs(root, node, appinfo); + return adjust_appendrel_attrs(root, node, list_make1(appinfo)); } diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index 2b20b36..a02e06a 100644 --- a/src/include/optimizer/prep.h +++ b/src/include/optimizer/prep.h @@ -53,7 +53,7 @@ extern RelOptInfo *plan_set_operations(PlannerInfo *root); extern void expand_inherited_tables(PlannerInfo *root); extern Node *adjust_appendrel_attrs(PlannerInfo *root, Node *node, - AppendRelInfo *appinfo); + List *appinfos); extern Node *adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *child_rel); -- 1.7.9.5