LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - appendinfo.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 237 252 94.0 %
Date: 2019-09-19 02:07:14 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * appendinfo.c
       4             :  *    Routines for mapping between append parent(s) and children
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/optimizer/path/appendinfo.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "access/htup_details.h"
      18             : #include "nodes/makefuncs.h"
      19             : #include "nodes/nodeFuncs.h"
      20             : #include "optimizer/appendinfo.h"
      21             : #include "parser/parsetree.h"
      22             : #include "utils/lsyscache.h"
      23             : #include "utils/rel.h"
      24             : #include "utils/syscache.h"
      25             : 
      26             : 
      27             : typedef struct
      28             : {
      29             :     PlannerInfo *root;
      30             :     int         nappinfos;
      31             :     AppendRelInfo **appinfos;
      32             : } adjust_appendrel_attrs_context;
      33             : 
      34             : static void make_inh_translation_list(Relation oldrelation,
      35             :                                       Relation newrelation,
      36             :                                       Index newvarno,
      37             :                                       List **translated_vars);
      38             : static Node *adjust_appendrel_attrs_mutator(Node *node,
      39             :                                             adjust_appendrel_attrs_context *context);
      40             : static List *adjust_inherited_tlist(List *tlist,
      41             :                                     AppendRelInfo *context);
      42             : 
      43             : 
      44             : /*
      45             :  * make_append_rel_info
      46             :  *    Build an AppendRelInfo for the parent-child pair
      47             :  */
      48             : AppendRelInfo *
      49       18462 : make_append_rel_info(Relation parentrel, Relation childrel,
      50             :                      Index parentRTindex, Index childRTindex)
      51             : {
      52       18462 :     AppendRelInfo *appinfo = makeNode(AppendRelInfo);
      53             : 
      54       18462 :     appinfo->parent_relid = parentRTindex;
      55       18462 :     appinfo->child_relid = childRTindex;
      56       18462 :     appinfo->parent_reltype = parentrel->rd_rel->reltype;
      57       18462 :     appinfo->child_reltype = childrel->rd_rel->reltype;
      58       18462 :     make_inh_translation_list(parentrel, childrel, childRTindex,
      59             :                               &appinfo->translated_vars);
      60       18460 :     appinfo->parent_reloid = RelationGetRelid(parentrel);
      61             : 
      62       18460 :     return appinfo;
      63             : }
      64             : 
      65             : /*
      66             :  * make_inh_translation_list
      67             :  *    Build the list of translations from parent Vars to child Vars for
      68             :  *    an inheritance child.
      69             :  *
      70             :  * For paranoia's sake, we match type/collation as well as attribute name.
      71             :  */
      72             : static void
      73       18462 : make_inh_translation_list(Relation oldrelation, Relation newrelation,
      74             :                           Index newvarno,
      75             :                           List **translated_vars)
      76             : {
      77       18462 :     List       *vars = NIL;
      78       18462 :     TupleDesc   old_tupdesc = RelationGetDescr(oldrelation);
      79       18462 :     TupleDesc   new_tupdesc = RelationGetDescr(newrelation);
      80       18462 :     Oid         new_relid = RelationGetRelid(newrelation);
      81       18462 :     int         oldnatts = old_tupdesc->natts;
      82       18462 :     int         newnatts = new_tupdesc->natts;
      83             :     int         old_attno;
      84       18462 :     int         new_attno = 0;
      85             : 
      86       65324 :     for (old_attno = 0; old_attno < oldnatts; old_attno++)
      87             :     {
      88             :         Form_pg_attribute att;
      89             :         char       *attname;
      90             :         Oid         atttypid;
      91             :         int32       atttypmod;
      92             :         Oid         attcollation;
      93             : 
      94       46864 :         att = TupleDescAttr(old_tupdesc, old_attno);
      95       46864 :         if (att->attisdropped)
      96             :         {
      97             :             /* Just put NULL into this list entry */
      98        2140 :             vars = lappend(vars, NULL);
      99        2140 :             continue;
     100             :         }
     101       44724 :         attname = NameStr(att->attname);
     102       44724 :         atttypid = att->atttypid;
     103       44724 :         atttypmod = att->atttypmod;
     104       44724 :         attcollation = att->attcollation;
     105             : 
     106             :         /*
     107             :          * When we are generating the "translation list" for the parent table
     108             :          * of an inheritance set, no need to search for matches.
     109             :          */
     110       44724 :         if (oldrelation == newrelation)
     111             :         {
     112        4104 :             vars = lappend(vars, makeVar(newvarno,
     113        4104 :                                          (AttrNumber) (old_attno + 1),
     114             :                                          atttypid,
     115             :                                          atttypmod,
     116             :                                          attcollation,
     117             :                                          0));
     118        4104 :             continue;
     119             :         }
     120             : 
     121             :         /*
     122             :          * Otherwise we have to search for the matching column by name.
     123             :          * There's no guarantee it'll have the same column position, because
     124             :          * of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
     125             :          * However, in simple cases, the relative order of columns is mostly
     126             :          * the same in both relations, so try the column of newrelation that
     127             :          * follows immediately after the one that we just found, and if that
     128             :          * fails, let syscache handle it.
     129             :          */
     130       80098 :         if (new_attno >= newnatts ||
     131       78482 :             (att = TupleDescAttr(new_tupdesc, new_attno))->attisdropped ||
     132       39004 :             strcmp(attname, NameStr(att->attname)) != 0)
     133             :         {
     134             :             HeapTuple   newtup;
     135             : 
     136        4122 :             newtup = SearchSysCacheAttName(new_relid, attname);
     137        4122 :             if (!HeapTupleIsValid(newtup))
     138           0 :                 elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
     139             :                      attname, RelationGetRelationName(newrelation));
     140        4122 :             new_attno = ((Form_pg_attribute) GETSTRUCT(newtup))->attnum - 1;
     141        4122 :             ReleaseSysCache(newtup);
     142             : 
     143        4122 :             att = TupleDescAttr(new_tupdesc, new_attno);
     144             :         }
     145             : 
     146             :         /* Found it, check type and collation match */
     147       40620 :         if (atttypid != att->atttypid || atttypmod != att->atttypmod)
     148           2 :             elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
     149             :                  attname, RelationGetRelationName(newrelation));
     150       40618 :         if (attcollation != att->attcollation)
     151           0 :             elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
     152             :                  attname, RelationGetRelationName(newrelation));
     153             : 
     154       40618 :         vars = lappend(vars, makeVar(newvarno,
     155       40618 :                                      (AttrNumber) (new_attno + 1),
     156             :                                      atttypid,
     157             :                                      atttypmod,
     158             :                                      attcollation,
     159             :                                      0));
     160       40618 :         new_attno++;
     161             :     }
     162             : 
     163       18460 :     *translated_vars = vars;
     164       18460 : }
     165             : 
     166             : /*
     167             :  * adjust_appendrel_attrs
     168             :  *    Copy the specified query or expression and translate Vars referring to a
     169             :  *    parent rel to refer to the corresponding child rel instead.  We also
     170             :  *    update rtindexes appearing outside Vars, such as resultRelation and
     171             :  *    jointree relids.
     172             :  *
     173             :  * Note: this is only applied after conversion of sublinks to subplans,
     174             :  * so we don't need to cope with recursion into sub-queries.
     175             :  *
     176             :  * Note: this is not hugely different from what pullup_replace_vars() does;
     177             :  * maybe we should try to fold the two routines together.
     178             :  */
     179             : Node *
     180      112698 : adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos,
     181             :                        AppendRelInfo **appinfos)
     182             : {
     183             :     Node       *result;
     184             :     adjust_appendrel_attrs_context context;
     185             : 
     186      112698 :     context.root = root;
     187      112698 :     context.nappinfos = nappinfos;
     188      112698 :     context.appinfos = appinfos;
     189             : 
     190             :     /* If there's nothing to adjust, don't call this function. */
     191             :     Assert(nappinfos >= 1 && appinfos != NULL);
     192             : 
     193             :     /*
     194             :      * Must be prepared to start with a Query or a bare expression tree.
     195             :      */
     196      112698 :     if (node && IsA(node, Query))
     197        2466 :     {
     198             :         Query      *newnode;
     199             :         int         cnt;
     200             : 
     201        2466 :         newnode = query_tree_mutator((Query *) node,
     202             :                                      adjust_appendrel_attrs_mutator,
     203             :                                      (void *) &context,
     204             :                                      QTW_IGNORE_RC_SUBQUERIES);
     205        2466 :         for (cnt = 0; cnt < nappinfos; cnt++)
     206             :         {
     207        2466 :             AppendRelInfo *appinfo = appinfos[cnt];
     208             : 
     209        2466 :             if (newnode->resultRelation == appinfo->parent_relid)
     210             :             {
     211        2466 :                 newnode->resultRelation = appinfo->child_relid;
     212             :                 /* Fix tlist resnos too, if it's inherited UPDATE */
     213        2466 :                 if (newnode->commandType == CMD_UPDATE)
     214        1912 :                     newnode->targetList =
     215        1912 :                         adjust_inherited_tlist(newnode->targetList,
     216             :                                                appinfo);
     217        2466 :                 break;
     218             :             }
     219             :         }
     220             : 
     221        2466 :         result = (Node *) newnode;
     222             :     }
     223             :     else
     224      110232 :         result = adjust_appendrel_attrs_mutator(node, &context);
     225             : 
     226      112698 :     return result;
     227             : }
     228             : 
     229             : static Node *
     230      508372 : adjust_appendrel_attrs_mutator(Node *node,
     231             :                                adjust_appendrel_attrs_context *context)
     232             : {
     233      508372 :     AppendRelInfo **appinfos = context->appinfos;
     234      508372 :     int         nappinfos = context->nappinfos;
     235             :     int         cnt;
     236             : 
     237      508372 :     if (node == NULL)
     238      106790 :         return NULL;
     239      401582 :     if (IsA(node, Var))
     240             :     {
     241      155350 :         Var        *var = (Var *) copyObject(node);
     242      155350 :         AppendRelInfo *appinfo = NULL;
     243             : 
     244      181916 :         for (cnt = 0; cnt < nappinfos; cnt++)
     245             :         {
     246      166834 :             if (var->varno == appinfos[cnt]->parent_relid)
     247             :             {
     248      140268 :                 appinfo = appinfos[cnt];
     249      140268 :                 break;
     250             :             }
     251             :         }
     252             : 
     253      155350 :         if (var->varlevelsup == 0 && appinfo)
     254             :         {
     255      140268 :             var->varno = appinfo->child_relid;
     256      140268 :             var->varnoold = appinfo->child_relid;
     257      140268 :             if (var->varattno > 0)
     258             :             {
     259             :                 Node       *newnode;
     260             : 
     261      132180 :                 if (var->varattno > list_length(appinfo->translated_vars))
     262           0 :                     elog(ERROR, "attribute %d of relation \"%s\" does not exist",
     263             :                          var->varattno, get_rel_name(appinfo->parent_reloid));
     264      132180 :                 newnode = copyObject(list_nth(appinfo->translated_vars,
     265             :                                               var->varattno - 1));
     266      132180 :                 if (newnode == NULL)
     267           0 :                     elog(ERROR, "attribute %d of relation \"%s\" does not exist",
     268             :                          var->varattno, get_rel_name(appinfo->parent_reloid));
     269      132180 :                 return newnode;
     270             :             }
     271        8088 :             else if (var->varattno == 0)
     272             :             {
     273             :                 /*
     274             :                  * Whole-row Var: if we are dealing with named rowtypes, we
     275             :                  * can use a whole-row Var for the child table plus a coercion
     276             :                  * step to convert the tuple layout to the parent's rowtype.
     277             :                  * Otherwise we have to generate a RowExpr.
     278             :                  */
     279         852 :                 if (OidIsValid(appinfo->child_reltype))
     280             :                 {
     281             :                     Assert(var->vartype == appinfo->parent_reltype);
     282         700 :                     if (appinfo->parent_reltype != appinfo->child_reltype)
     283             :                     {
     284         562 :                         ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
     285             : 
     286         562 :                         r->arg = (Expr *) var;
     287         562 :                         r->resulttype = appinfo->parent_reltype;
     288         562 :                         r->convertformat = COERCE_IMPLICIT_CAST;
     289         562 :                         r->location = -1;
     290             :                         /* Make sure the Var node has the right type ID, too */
     291         562 :                         var->vartype = appinfo->child_reltype;
     292         562 :                         return (Node *) r;
     293             :                     }
     294             :                 }
     295             :                 else
     296             :                 {
     297             :                     /*
     298             :                      * Build a RowExpr containing the translated variables.
     299             :                      *
     300             :                      * In practice var->vartype will always be RECORDOID here,
     301             :                      * so we need to come up with some suitable column names.
     302             :                      * We use the parent RTE's column names.
     303             :                      *
     304             :                      * Note: we can't get here for inheritance cases, so there
     305             :                      * is no need to worry that translated_vars might contain
     306             :                      * some dummy NULLs.
     307             :                      */
     308             :                     RowExpr    *rowexpr;
     309             :                     List       *fields;
     310             :                     RangeTblEntry *rte;
     311             : 
     312         152 :                     rte = rt_fetch(appinfo->parent_relid,
     313             :                                    context->root->parse->rtable);
     314         152 :                     fields = copyObject(appinfo->translated_vars);
     315         152 :                     rowexpr = makeNode(RowExpr);
     316         152 :                     rowexpr->args = fields;
     317         152 :                     rowexpr->row_typeid = var->vartype;
     318         152 :                     rowexpr->row_format = COERCE_IMPLICIT_CAST;
     319         152 :                     rowexpr->colnames = copyObject(rte->eref->colnames);
     320         152 :                     rowexpr->location = -1;
     321             : 
     322         152 :                     return (Node *) rowexpr;
     323             :                 }
     324             :             }
     325             :             /* system attributes don't need any other translation */
     326             :         }
     327       22456 :         return (Node *) var;
     328             :     }
     329      246232 :     if (IsA(node, CurrentOfExpr))
     330             :     {
     331         248 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
     332             : 
     333         248 :         for (cnt = 0; cnt < nappinfos; cnt++)
     334             :         {
     335         248 :             AppendRelInfo *appinfo = appinfos[cnt];
     336             : 
     337         248 :             if (cexpr->cvarno == appinfo->parent_relid)
     338             :             {
     339         248 :                 cexpr->cvarno = appinfo->child_relid;
     340         248 :                 break;
     341             :             }
     342             :         }
     343         248 :         return (Node *) cexpr;
     344             :     }
     345      245984 :     if (IsA(node, RangeTblRef))
     346             :     {
     347        2902 :         RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
     348             : 
     349        3338 :         for (cnt = 0; cnt < nappinfos; cnt++)
     350             :         {
     351        2902 :             AppendRelInfo *appinfo = appinfos[cnt];
     352             : 
     353        2902 :             if (rtr->rtindex == appinfo->parent_relid)
     354             :             {
     355        2466 :                 rtr->rtindex = appinfo->child_relid;
     356        2466 :                 break;
     357             :             }
     358             :         }
     359        2902 :         return (Node *) rtr;
     360             :     }
     361      243082 :     if (IsA(node, JoinExpr))
     362             :     {
     363             :         /* Copy the JoinExpr node with correct mutation of subnodes */
     364             :         JoinExpr   *j;
     365             :         AppendRelInfo *appinfo;
     366             : 
     367          64 :         j = (JoinExpr *) expression_tree_mutator(node,
     368             :                                                  adjust_appendrel_attrs_mutator,
     369             :                                                  (void *) context);
     370             :         /* now fix JoinExpr's rtindex (probably never happens) */
     371         128 :         for (cnt = 0; cnt < nappinfos; cnt++)
     372             :         {
     373          64 :             appinfo = appinfos[cnt];
     374             : 
     375          64 :             if (j->rtindex == appinfo->parent_relid)
     376             :             {
     377           0 :                 j->rtindex = appinfo->child_relid;
     378           0 :                 break;
     379             :             }
     380             :         }
     381          64 :         return (Node *) j;
     382             :     }
     383      243018 :     if (IsA(node, PlaceHolderVar))
     384             :     {
     385             :         /* Copy the PlaceHolderVar node with correct mutation of subnodes */
     386             :         PlaceHolderVar *phv;
     387             : 
     388        1816 :         phv = (PlaceHolderVar *) expression_tree_mutator(node,
     389             :                                                          adjust_appendrel_attrs_mutator,
     390             :                                                          (void *) context);
     391             :         /* now fix PlaceHolderVar's relid sets */
     392        1816 :         if (phv->phlevelsup == 0)
     393        1816 :             phv->phrels = adjust_child_relids(phv->phrels, context->nappinfos,
     394             :                                               context->appinfos);
     395        1816 :         return (Node *) phv;
     396             :     }
     397             :     /* Shouldn't need to handle planner auxiliary nodes here */
     398             :     Assert(!IsA(node, SpecialJoinInfo));
     399             :     Assert(!IsA(node, AppendRelInfo));
     400             :     Assert(!IsA(node, PlaceHolderInfo));
     401             :     Assert(!IsA(node, MinMaxAggInfo));
     402             : 
     403             :     /*
     404             :      * We have to process RestrictInfo nodes specially.  (Note: although
     405             :      * set_append_rel_pathlist will hide RestrictInfos in the parent's
     406             :      * baserestrictinfo list from us, it doesn't hide those in joininfo.)
     407             :      */
     408      241202 :     if (IsA(node, RestrictInfo))
     409             :     {
     410       11434 :         RestrictInfo *oldinfo = (RestrictInfo *) node;
     411       11434 :         RestrictInfo *newinfo = makeNode(RestrictInfo);
     412             : 
     413             :         /* Copy all flat-copiable fields */
     414       11434 :         memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
     415             : 
     416             :         /* Recursively fix the clause itself */
     417       11434 :         newinfo->clause = (Expr *)
     418       11434 :             adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
     419             : 
     420             :         /* and the modified version, if an OR clause */
     421       11434 :         newinfo->orclause = (Expr *)
     422       11434 :             adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
     423             : 
     424             :         /* adjust relid sets too */
     425       11434 :         newinfo->clause_relids = adjust_child_relids(oldinfo->clause_relids,
     426             :                                                      context->nappinfos,
     427             :                                                      context->appinfos);
     428       11434 :         newinfo->required_relids = adjust_child_relids(oldinfo->required_relids,
     429             :                                                        context->nappinfos,
     430             :                                                        context->appinfos);
     431       11434 :         newinfo->outer_relids = adjust_child_relids(oldinfo->outer_relids,
     432             :                                                     context->nappinfos,
     433             :                                                     context->appinfos);
     434       11434 :         newinfo->nullable_relids = adjust_child_relids(oldinfo->nullable_relids,
     435             :                                                        context->nappinfos,
     436             :                                                        context->appinfos);
     437       11434 :         newinfo->left_relids = adjust_child_relids(oldinfo->left_relids,
     438             :                                                    context->nappinfos,
     439             :                                                    context->appinfos);
     440       11434 :         newinfo->right_relids = adjust_child_relids(oldinfo->right_relids,
     441             :                                                     context->nappinfos,
     442             :                                                     context->appinfos);
     443             : 
     444             :         /*
     445             :          * Reset cached derivative fields, since these might need to have
     446             :          * different values when considering the child relation.  Note we
     447             :          * don't reset left_ec/right_ec: each child variable is implicitly
     448             :          * equivalent to its parent, so still a member of the same EC if any.
     449             :          */
     450       11434 :         newinfo->eval_cost.startup = -1;
     451       11434 :         newinfo->norm_selec = -1;
     452       11434 :         newinfo->outer_selec = -1;
     453       11434 :         newinfo->left_em = NULL;
     454       11434 :         newinfo->right_em = NULL;
     455       11434 :         newinfo->scansel_cache = NIL;
     456       11434 :         newinfo->left_bucketsize = -1;
     457       11434 :         newinfo->right_bucketsize = -1;
     458       11434 :         newinfo->left_mcvfreq = -1;
     459       11434 :         newinfo->right_mcvfreq = -1;
     460             : 
     461       11434 :         return (Node *) newinfo;
     462             :     }
     463             : 
     464             :     /*
     465             :      * NOTE: we do not need to recurse into sublinks, because they should
     466             :      * already have been converted to subplans before we see them.
     467             :      */
     468             :     Assert(!IsA(node, SubLink));
     469             :     Assert(!IsA(node, Query));
     470             : 
     471      229768 :     return expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
     472             :                                    (void *) context);
     473             : }
     474             : 
     475             : /*
     476             :  * adjust_appendrel_attrs_multilevel
     477             :  *    Apply Var translations from a toplevel appendrel parent down to a child.
     478             :  *
     479             :  * In some cases we need to translate expressions referencing a parent relation
     480             :  * to reference an appendrel child that's multiple levels removed from it.
     481             :  */
     482             : Node *
     483       13956 : adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
     484             :                                   Relids child_relids,
     485             :                                   Relids top_parent_relids)
     486             : {
     487             :     AppendRelInfo **appinfos;
     488       13956 :     Bitmapset  *parent_relids = NULL;
     489             :     int         nappinfos;
     490             :     int         cnt;
     491             : 
     492             :     Assert(bms_num_members(child_relids) == bms_num_members(top_parent_relids));
     493             : 
     494       13956 :     appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
     495             : 
     496             :     /* Construct relids set for the immediate parent of given child. */
     497       28356 :     for (cnt = 0; cnt < nappinfos; cnt++)
     498             :     {
     499       14400 :         AppendRelInfo *appinfo = appinfos[cnt];
     500             : 
     501       14400 :         parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
     502             :     }
     503             : 
     504             :     /* Recurse if immediate parent is not the top parent. */
     505       13956 :     if (!bms_equal(parent_relids, top_parent_relids))
     506        5160 :         node = adjust_appendrel_attrs_multilevel(root, node, parent_relids,
     507             :                                                  top_parent_relids);
     508             : 
     509             :     /* Now translate for this child */
     510       13956 :     node = adjust_appendrel_attrs(root, node, nappinfos, appinfos);
     511             : 
     512       13956 :     pfree(appinfos);
     513             : 
     514       13956 :     return node;
     515             : }
     516             : 
     517             : /*
     518             :  * Substitute child relids for parent relids in a Relid set.  The array of
     519             :  * appinfos specifies the substitutions to be performed.
     520             :  */
     521             : Relids
     522       79080 : adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
     523             : {
     524       79080 :     Bitmapset  *result = NULL;
     525             :     int         cnt;
     526             : 
     527      185800 :     for (cnt = 0; cnt < nappinfos; cnt++)
     528             :     {
     529      106720 :         AppendRelInfo *appinfo = appinfos[cnt];
     530             : 
     531             :         /* Remove parent, add child */
     532      106720 :         if (bms_is_member(appinfo->parent_relid, relids))
     533             :         {
     534             :             /* Make a copy if we are changing the set. */
     535       52190 :             if (!result)
     536       45822 :                 result = bms_copy(relids);
     537             : 
     538       52190 :             result = bms_del_member(result, appinfo->parent_relid);
     539       52190 :             result = bms_add_member(result, appinfo->child_relid);
     540             :         }
     541             :     }
     542             : 
     543             :     /* If we made any changes, return the modified copy. */
     544       79080 :     if (result)
     545       45822 :         return result;
     546             : 
     547             :     /* Otherwise, return the original set without modification. */
     548       33258 :     return relids;
     549             : }
     550             : 
     551             : /*
     552             :  * Replace any relid present in top_parent_relids with its child in
     553             :  * child_relids. Members of child_relids can be multiple levels below top
     554             :  * parent in the partition hierarchy.
     555             :  */
     556             : Relids
     557        2132 : adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
     558             :                                Relids child_relids, Relids top_parent_relids)
     559             : {
     560             :     AppendRelInfo **appinfos;
     561             :     int         nappinfos;
     562        2132 :     Relids      parent_relids = NULL;
     563             :     Relids      result;
     564        2132 :     Relids      tmp_result = NULL;
     565             :     int         cnt;
     566             : 
     567             :     /*
     568             :      * If the given relids set doesn't contain any of the top parent relids,
     569             :      * it will remain unchanged.
     570             :      */
     571        2132 :     if (!bms_overlap(relids, top_parent_relids))
     572           0 :         return relids;
     573             : 
     574        2132 :     appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
     575             : 
     576             :     /* Construct relids set for the immediate parent of the given child. */
     577        4616 :     for (cnt = 0; cnt < nappinfos; cnt++)
     578             :     {
     579        2484 :         AppendRelInfo *appinfo = appinfos[cnt];
     580             : 
     581        2484 :         parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
     582             :     }
     583             : 
     584             :     /* Recurse if immediate parent is not the top parent. */
     585        2132 :     if (!bms_equal(parent_relids, top_parent_relids))
     586             :     {
     587          96 :         tmp_result = adjust_child_relids_multilevel(root, relids,
     588             :                                                     parent_relids,
     589             :                                                     top_parent_relids);
     590          96 :         relids = tmp_result;
     591             :     }
     592             : 
     593        2132 :     result = adjust_child_relids(relids, nappinfos, appinfos);
     594             : 
     595             :     /* Free memory consumed by any intermediate result. */
     596        2132 :     if (tmp_result)
     597          96 :         bms_free(tmp_result);
     598        2132 :     bms_free(parent_relids);
     599        2132 :     pfree(appinfos);
     600             : 
     601        2132 :     return result;
     602             : }
     603             : 
     604             : /*
     605             :  * Adjust the targetlist entries of an inherited UPDATE operation
     606             :  *
     607             :  * The expressions have already been fixed, but we have to make sure that
     608             :  * the target resnos match the child table (they may not, in the case of
     609             :  * a column that was added after-the-fact by ALTER TABLE).  In some cases
     610             :  * this can force us to re-order the tlist to preserve resno ordering.
     611             :  * (We do all this work in special cases so that preptlist.c is fast for
     612             :  * the typical case.)
     613             :  *
     614             :  * The given tlist has already been through expression_tree_mutator;
     615             :  * therefore the TargetEntry nodes are fresh copies that it's okay to
     616             :  * scribble on.
     617             :  *
     618             :  * Note that this is not needed for INSERT because INSERT isn't inheritable.
     619             :  */
     620             : static List *
     621        1912 : adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
     622             : {
     623        1912 :     bool        changed_it = false;
     624             :     ListCell   *tl;
     625             :     List       *new_tlist;
     626             :     bool        more;
     627             :     int         attrno;
     628             : 
     629             :     /* This should only happen for an inheritance case, not UNION ALL */
     630             :     Assert(OidIsValid(context->parent_reloid));
     631             : 
     632             :     /* Scan tlist and update resnos to match attnums of child rel */
     633        4080 :     foreach(tl, tlist)
     634             :     {
     635        2168 :         TargetEntry *tle = (TargetEntry *) lfirst(tl);
     636             :         Var        *childvar;
     637             : 
     638        2168 :         if (tle->resjunk)
     639           0 :             continue;           /* ignore junk items */
     640             : 
     641             :         /* Look up the translation of this column: it must be a Var */
     642        4336 :         if (tle->resno <= 0 ||
     643        2168 :             tle->resno > list_length(context->translated_vars))
     644           0 :             elog(ERROR, "attribute %d of relation \"%s\" does not exist",
     645             :                  tle->resno, get_rel_name(context->parent_reloid));
     646        2168 :         childvar = (Var *) list_nth(context->translated_vars, tle->resno - 1);
     647        2168 :         if (childvar == NULL || !IsA(childvar, Var))
     648           0 :             elog(ERROR, "attribute %d of relation \"%s\" does not exist",
     649             :                  tle->resno, get_rel_name(context->parent_reloid));
     650             : 
     651        2168 :         if (tle->resno != childvar->varattno)
     652             :         {
     653         692 :             tle->resno = childvar->varattno;
     654         692 :             changed_it = true;
     655             :         }
     656             :     }
     657             : 
     658             :     /*
     659             :      * If we changed anything, re-sort the tlist by resno, and make sure
     660             :      * resjunk entries have resnos above the last real resno.  The sort
     661             :      * algorithm is a bit stupid, but for such a seldom-taken path, small is
     662             :      * probably better than fast.
     663             :      */
     664        1912 :     if (!changed_it)
     665        1296 :         return tlist;
     666             : 
     667         616 :     new_tlist = NIL;
     668         616 :     more = true;
     669        2652 :     for (attrno = 1; more; attrno++)
     670             :     {
     671        2036 :         more = false;
     672        4488 :         foreach(tl, tlist)
     673             :         {
     674        2452 :             TargetEntry *tle = (TargetEntry *) lfirst(tl);
     675             : 
     676        2452 :             if (tle->resjunk)
     677           0 :                 continue;       /* ignore junk items */
     678             : 
     679        2452 :             if (tle->resno == attrno)
     680         700 :                 new_tlist = lappend(new_tlist, tle);
     681        1752 :             else if (tle->resno > attrno)
     682        1628 :                 more = true;
     683             :         }
     684             :     }
     685             : 
     686        1316 :     foreach(tl, tlist)
     687             :     {
     688         700 :         TargetEntry *tle = (TargetEntry *) lfirst(tl);
     689             : 
     690         700 :         if (!tle->resjunk)
     691         700 :             continue;           /* here, ignore non-junk items */
     692             : 
     693           0 :         tle->resno = attrno;
     694           0 :         new_tlist = lappend(new_tlist, tle);
     695           0 :         attrno++;
     696             :     }
     697             : 
     698         616 :     return new_tlist;
     699             : }
     700             : 
     701             : /*
     702             :  * find_appinfos_by_relids
     703             :  *      Find AppendRelInfo structures for all relations specified by relids.
     704             :  *
     705             :  * The AppendRelInfos are returned in an array, which can be pfree'd by the
     706             :  * caller. *nappinfos is set to the number of entries in the array.
     707             :  */
     708             : AppendRelInfo **
     709       33370 : find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
     710             : {
     711             :     AppendRelInfo **appinfos;
     712       33370 :     int         cnt = 0;
     713             :     int         i;
     714             : 
     715       33370 :     *nappinfos = bms_num_members(relids);
     716       33370 :     appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
     717             : 
     718       33370 :     i = -1;
     719      106590 :     while ((i = bms_next_member(relids, i)) >= 0)
     720             :     {
     721       39850 :         AppendRelInfo *appinfo = root->append_rel_array[i];
     722             : 
     723       39850 :         if (!appinfo)
     724           0 :             elog(ERROR, "child rel %d not found in append_rel_array", i);
     725             : 
     726       39850 :         appinfos[cnt++] = appinfo;
     727             :     }
     728       33370 :     return appinfos;
     729             : }

Generated by: LCOV version 1.13