]> granicus.if.org Git - postgresql/commitdiff
Teach adjust_appendrel_attrs(_multilevel) to do multiple translations.
authorRobert Haas <rhaas@postgresql.org>
Tue, 15 Aug 2017 14:49:06 +0000 (10:49 -0400)
committerRobert Haas <rhaas@postgresql.org>
Tue, 15 Aug 2017 14:49:06 +0000 (10:49 -0400)
Currently, child relations are always base relations, so when we
translate parent relids to child relids, we only need to translate
a singler relid.  However, the proposed partition-wise join feature
will create child joins, which will mean we need to translate a set
of parent relids to the corresponding child relids.  This is
preliminary refactoring to make that possible.

Ashutosh Bapat.  Review and testing of the larger patch set of which
this is a part by Amit Langote, Rajkumar Raghuwanshi, Rafia Sabih,
Thomas Munro, Dilip Kumar, and me.  Some adjustments, mostly
cosmetic, by me.

Discussion: http://postgr.es/m/CA+TgmobQK80vtXjAsPZWWXd7c8u13G86gmuLupN+uUJjA+i4nA@mail.gmail.com

src/backend/optimizer/path/allpaths.c
src/backend/optimizer/path/equivclass.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/prep/prepunion.c
src/include/optimizer/prep.h

index f087ddb61db8ae75781b674ba8f9cafb37621346..2d7e1d84d099818f6e5d622d5397b7261cce4d49 100644 (file)
@@ -942,7 +942,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
                        Assert(IsA(rinfo, RestrictInfo));
                        childqual = adjust_appendrel_attrs(root,
                                                                                           (Node *) rinfo->clause,
-                                                                                          appinfo);
+                                                                                          1, &appinfo);
                        childqual = eval_const_expressions(root, childqual);
                        /* check for flat-out constant */
                        if (childqual && IsA(childqual, Const))
@@ -1061,11 +1061,11 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
                childrel->joininfo = (List *)
                        adjust_appendrel_attrs(root,
                                                                   (Node *) rel->joininfo,
-                                                                  appinfo);
+                                                                  1, &appinfo);
                childrel->reltarget->exprs = (List *)
                        adjust_appendrel_attrs(root,
                                                                   (Node *) rel->reltarget->exprs,
-                                                                  appinfo);
+                                                                  1, &appinfo);
 
                /*
                 * We have to make child entries in the EquivalenceClass data
index 9a3f606df078264dda85ee34e4a77be5a6230fb4..7997f50c18d6fbf4d9db40b5dc50b49413ec1601 100644 (file)
@@ -1329,7 +1329,8 @@ generate_join_implied_equalities_broken(PlannerInfo *root,
        if (IS_OTHER_REL(inner_rel) && result != NIL)
                result = (List *) adjust_appendrel_attrs_multilevel(root,
                                                                                                                        (Node *) result,
-                                                                                                                       inner_rel);
+                                                                                                                       inner_rel->relids,
+                                                                                                                       inner_rel->top_parent_relids);
 
        return result;
 }
@@ -2112,7 +2113,7 @@ add_child_rel_equivalences(PlannerInfo *root,
                                child_expr = (Expr *)
                                        adjust_appendrel_attrs(root,
                                                                                   (Node *) cur_em->em_expr,
-                                                                                  appinfo);
+                                                                                  1, &appinfo);
 
                                /*
                                 * Transform em_relids to match.  Note we do *not* do
index 2988c1181b906a00aa24f9880e9781c47c65fb44..407df9ae79db4fea76e8d035a3e5562e2f527efd 100644 (file)
@@ -1142,7 +1142,7 @@ inheritance_planner(PlannerInfo *root)
                subroot->parse = (Query *)
                        adjust_appendrel_attrs(root,
                                                                   (Node *) parse,
-                                                                  appinfo);
+                                                                  1, &appinfo);
 
                /*
                 * If there are securityQuals attached to the parent, move them to the
index fb283184c580360eb618d71b4fe427e8435e0ee8..9c6c47a1b9bb8ae3573ecda9963ee01ce152eb02 100644 (file)
@@ -55,7 +55,8 @@
 typedef struct
 {
        PlannerInfo *root;
-       AppendRelInfo *appinfo;
+       int                     nappinfos;
+       AppendRelInfo **appinfos;
 } adjust_appendrel_attrs_context;
 
 static Path *recurse_set_operations(Node *setOp, PlannerInfo *root,
@@ -107,7 +108,8 @@ 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 Relids adjust_child_relids(Relids relids, int nappinfos,
+                                       AppendRelInfo **appinfos);
 static List *adjust_inherited_tlist(List *tlist,
                                           AppendRelInfo *context);
 
@@ -1775,10 +1777,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 a
+ *       parent rel 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.
@@ -1787,13 +1789,18 @@ 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, int nappinfos,
+                                          AppendRelInfo **appinfos)
 {
        Node       *result;
        adjust_appendrel_attrs_context context;
 
        context.root = root;
-       context.appinfo = appinfo;
+       context.nappinfos = nappinfos;
+       context.appinfos = appinfos;
+
+       /* If there's nothing to adjust, don't call this function. */
+       Assert(nappinfos >= 1 && appinfos != NULL);
 
        /*
         * Must be prepared to start with a Query or a bare expression tree.
@@ -1801,20 +1808,28 @@ adjust_appendrel_attrs(PlannerInfo *root, Node *node, AppendRelInfo *appinfo)
        if (node && IsA(node, Query))
        {
                Query      *newnode;
+               int                     cnt;
 
                newnode = query_tree_mutator((Query *) node,
                                                                         adjust_appendrel_attrs_mutator,
                                                                         (void *) &context,
                                                                         QTW_IGNORE_RC_SUBQUERIES);
-               if (newnode->resultRelation == appinfo->parent_relid)
+               for (cnt = 0; cnt < nappinfos; cnt++)
                {
-                       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);
+                       AppendRelInfo *appinfo = appinfos[cnt];
+
+                       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
@@ -1827,16 +1842,27 @@ static Node *
 adjust_appendrel_attrs_mutator(Node *node,
                                                           adjust_appendrel_attrs_context *context)
 {
-       AppendRelInfo *appinfo = context->appinfo;
+       AppendRelInfo **appinfos = context->appinfos;
+       int                     nappinfos = context->nappinfos;
+       int                     cnt;
 
        if (node == NULL)
                return NULL;
        if (IsA(node, Var))
        {
                Var                *var = (Var *) copyObject(node);
+               AppendRelInfo *appinfo = NULL;
 
-               if (var->varlevelsup == 0 &&
-                       var->varno == appinfo->parent_relid)
+               for (cnt = 0; cnt < nappinfos; cnt++)
+               {
+                       if (var->varno == appinfos[cnt]->parent_relid)
+                       {
+                               appinfo = appinfos[cnt];
+                               break;
+                       }
+               }
+
+               if (var->varlevelsup == 0 && appinfo)
                {
                        var->varno = appinfo->child_relid;
                        var->varnoold = appinfo->child_relid;
@@ -1916,29 +1942,54 @@ adjust_appendrel_attrs_mutator(Node *node,
        {
                CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
 
-               if (cexpr->cvarno == appinfo->parent_relid)
-                       cexpr->cvarno = appinfo->child_relid;
+               for (cnt = 0; cnt < nappinfos; cnt++)
+               {
+                       AppendRelInfo *appinfo = appinfos[cnt];
+
+                       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;
+               for (cnt = 0; cnt < nappinfos; cnt++)
+               {
+                       AppendRelInfo *appinfo = appinfos[cnt];
+
+                       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;
+               for (cnt = 0; cnt < nappinfos; cnt++)
+               {
+                       appinfo = appinfos[cnt];
+
+                       if (j->rtindex == appinfo->parent_relid)
+                       {
+                               j->rtindex = appinfo->child_relid;
+                               break;
+                       }
+               }
                return (Node *) j;
        }
        if (IsA(node, PlaceHolderVar))
@@ -1951,9 +2002,8 @@ 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_child_relids(phv->phrels, context->nappinfos,
+                                                                                         context->appinfos);
                return (Node *) phv;
        }
        /* Shouldn't need to handle planner auxiliary nodes here */
@@ -1984,24 +2034,24 @@ adjust_appendrel_attrs_mutator(Node *node,
                        adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
 
                /* adjust relid sets too */
-               newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
-                                                                                                 appinfo->parent_relid,
-                                                                                                 appinfo->child_relid);
-               newinfo->required_relids = adjust_relid_set(oldinfo->required_relids,
-                                                                                                       appinfo->parent_relid,
-                                                                                                       appinfo->child_relid);
-               newinfo->outer_relids = adjust_relid_set(oldinfo->outer_relids,
-                                                                                                appinfo->parent_relid,
-                                                                                                appinfo->child_relid);
-               newinfo->nullable_relids = adjust_relid_set(oldinfo->nullable_relids,
-                                                                                                       appinfo->parent_relid,
-                                                                                                       appinfo->child_relid);
-               newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
-                                                                                               appinfo->parent_relid,
-                                                                                               appinfo->child_relid);
-               newinfo->right_relids = adjust_relid_set(oldinfo->right_relids,
-                                                                                                appinfo->parent_relid,
-                                                                                                appinfo->child_relid);
+               newinfo->clause_relids = adjust_child_relids(oldinfo->clause_relids,
+                                                                                                        context->nappinfos,
+                                                                                                        context->appinfos);
+               newinfo->required_relids = adjust_child_relids(oldinfo->required_relids,
+                                                                                                          context->nappinfos,
+                                                                                                          context->appinfos);
+               newinfo->outer_relids = adjust_child_relids(oldinfo->outer_relids,
+                                                                                                       context->nappinfos,
+                                                                                                       context->appinfos);
+               newinfo->nullable_relids = adjust_child_relids(oldinfo->nullable_relids,
+                                                                                                          context->nappinfos,
+                                                                                                          context->appinfos);
+               newinfo->left_relids = adjust_child_relids(oldinfo->left_relids,
+                                                                                                  context->nappinfos,
+                                                                                                  context->appinfos);
+               newinfo->right_relids = adjust_child_relids(oldinfo->right_relids,
+                                                                                                       context->nappinfos,
+                                                                                                       context->appinfos);
 
                /*
                 * Reset cached derivative fields, since these might need to have
@@ -2033,19 +2083,36 @@ adjust_appendrel_attrs_mutator(Node *node,
 }
 
 /*
- * Substitute newrelid for oldrelid in a Relid set
+ * Substitute child relids for parent relids in a Relid set.  The array of
+ * appinfos specifies the substitutions to be performed.
  */
-static Relids
-adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
+Relids
+adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
 {
-       if (bms_is_member(oldrelid, relids))
+       Bitmapset  *result = NULL;
+       int                     cnt;
+
+       for (cnt = 0; cnt < nappinfos; cnt++)
        {
-               /* 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 = appinfos[cnt];
+
+               /* 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);
+               }
        }
+
+       /* If we made any changes, return the modified copy. */
+       if (result)
+               return result;
+
+       /* Otherwise, return the original set without modification. */
        return relids;
 }
 
@@ -2150,21 +2217,77 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
  * adjust_appendrel_attrs_multilevel
  *       Apply Var translations from a toplevel appendrel parent down to a child.
  *
- * In some cases we need to translate expressions referencing a baserel
+ * In some cases we need to translate expressions referencing a parent relation
  * to reference an appendrel child that's multiple levels removed from it.
  */
 Node *
 adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
-                                                                 RelOptInfo *child_rel)
+                                                                 Relids child_relids,
+                                                                 Relids top_parent_relids)
 {
-       AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, child_rel);
-       RelOptInfo *parent_rel = find_base_rel(root, appinfo->parent_relid);
+       AppendRelInfo **appinfos;
+       Bitmapset  *parent_relids = NULL;
+       int                     nappinfos;
+       int                     cnt;
+
+       Assert(bms_num_members(child_relids) == bms_num_members(top_parent_relids));
+
+       appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
+
+       /* Construct relids set for the immediate parent of given child. */
+       for (cnt = 0; cnt < nappinfos; cnt++)
+       {
+               AppendRelInfo *appinfo = appinfos[cnt];
+
+               parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
+       }
+
+       /* Recurse if immediate parent is not the top parent. */
+       if (!bms_equal(parent_relids, top_parent_relids))
+               node = adjust_appendrel_attrs_multilevel(root, node, parent_relids,
+                                                                                                top_parent_relids);
 
-       /* If parent is also a child, first recurse to apply its translations */
-       if (IS_OTHER_REL(parent_rel))
-               node = adjust_appendrel_attrs_multilevel(root, node, parent_rel);
-       else
-               Assert(parent_rel->reloptkind == RELOPT_BASEREL);
        /* Now translate for this child */
-       return adjust_appendrel_attrs(root, node, appinfo);
+       node = adjust_appendrel_attrs(root, node, nappinfos, appinfos);
+
+       pfree(appinfos);
+
+       return node;
+}
+
+/*
+ * find_appinfos_by_relids
+ *             Find AppendRelInfo structures for all relations specified by relids.
+ *
+ * The AppendRelInfos are returned in an array, which can be pfree'd by the
+ * caller. *nappinfos is set to the the number of entries in the array.
+ */
+AppendRelInfo **
+find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
+{
+       ListCell   *lc;
+       AppendRelInfo **appinfos;
+       int                     cnt = 0;
+
+       *nappinfos = bms_num_members(relids);
+       appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
+
+       foreach(lc, root->append_rel_list)
+       {
+               AppendRelInfo *appinfo = lfirst(lc);
+
+               if (bms_is_member(appinfo->child_relid, relids))
+               {
+                       appinfos[cnt] = appinfo;
+                       cnt++;
+
+                       /* Stop when we have gathered all the AppendRelInfos. */
+                       if (cnt == *nappinfos)
+                               return appinfos;
+               }
+       }
+
+       /* Should have found the entries ... */
+       elog(ERROR, "did not find all requested child rels in append_rel_list");
+       return NULL;                            /* not reached */
 }
index faad46b5e4e33570af17d41224f309841800c0cf..4be0afd566022323d54367f04d0eeb155293d819 100644 (file)
@@ -53,9 +53,13 @@ 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);
+                                          int nappinfos, AppendRelInfo **appinfos);
 
 extern Node *adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
-                                                                 RelOptInfo *child_rel);
+                                                                 Relids child_relids,
+                                                                 Relids top_parent_relids);
+
+extern AppendRelInfo **find_appinfos_by_relids(PlannerInfo *root,
+                                               Relids relids, int *nappinfos);
 
 #endif                                                 /* PREP_H */