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

Generated by: LCOV version 1.13