LCOV - differential code coverage report
Current view: top level - src/backend/optimizer/util - appendinfo.c (source / functions) Coverage Total Hit UNC UBC GNC CBC
Current: a2387c32f2f8a1643c7d71b951587e6bcb2d4744 vs 371a302eecdc82274b0ae2967d18fd726a0aa6a1 Lines: 95.0 % 361 343 18 22 321
Current Date: 2025-10-26 12:31:50 -0700 Functions: 100.0 % 14 14 1 13
Baseline: lcov-20251027-010456-baseline Branches: 67.6 % 278 188 1 89 5 183
Baseline Date: 2025-10-26 11:01:32 +1300 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 22 22 22
(30,360] days: 62.5 % 8 5 3 5
(360..) days: 95.5 % 331 316 15 316
Function coverage date bins:
(360..) days: 100.0 % 14 14 1 13
Branch coverage date bins:
(7,30] days: 83.3 % 6 5 1 5
(30,360] days: 25.0 % 12 3 9 3
(360..) days: 69.2 % 260 180 80 180

 Age         Owner                    Branch data    TLA  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-2025, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *    src/backend/optimizer/util/appendinfo.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include "access/htup_details.h"
                                 18                 :                : #include "access/table.h"
                                 19                 :                : #include "foreign/fdwapi.h"
                                 20                 :                : #include "nodes/makefuncs.h"
                                 21                 :                : #include "nodes/nodeFuncs.h"
                                 22                 :                : #include "optimizer/appendinfo.h"
                                 23                 :                : #include "optimizer/pathnode.h"
                                 24                 :                : #include "optimizer/planmain.h"
                                 25                 :                : #include "parser/parsetree.h"
                                 26                 :                : #include "utils/lsyscache.h"
                                 27                 :                : #include "utils/rel.h"
                                 28                 :                : #include "utils/syscache.h"
                                 29                 :                : 
                                 30                 :                : 
                                 31                 :                : typedef struct
                                 32                 :                : {
                                 33                 :                :     PlannerInfo *root;
                                 34                 :                :     int         nappinfos;
                                 35                 :                :     AppendRelInfo **appinfos;
                                 36                 :                : } adjust_appendrel_attrs_context;
                                 37                 :                : 
                                 38                 :                : static void make_inh_translation_list(Relation oldrelation,
                                 39                 :                :                                       Relation newrelation,
                                 40                 :                :                                       Index newvarno,
                                 41                 :                :                                       AppendRelInfo *appinfo);
                                 42                 :                : static Node *adjust_appendrel_attrs_mutator(Node *node,
                                 43                 :                :                                             adjust_appendrel_attrs_context *context);
                                 44                 :                : 
                                 45                 :                : 
                                 46                 :                : /*
                                 47                 :                :  * make_append_rel_info
                                 48                 :                :  *    Build an AppendRelInfo for the parent-child pair
                                 49                 :                :  */
                                 50                 :                : AppendRelInfo *
 2482 alvherre@alvh.no-ip.       51                 :CBC       21161 : make_append_rel_info(Relation parentrel, Relation childrel,
                                 52                 :                :                      Index parentRTindex, Index childRTindex)
                                 53                 :                : {
                                 54                 :          21161 :     AppendRelInfo *appinfo = makeNode(AppendRelInfo);
                                 55                 :                : 
                                 56                 :          21161 :     appinfo->parent_relid = parentRTindex;
                                 57                 :          21161 :     appinfo->child_relid = childRTindex;
                                 58                 :          21161 :     appinfo->parent_reltype = parentrel->rd_rel->reltype;
                                 59                 :          21161 :     appinfo->child_reltype = childrel->rd_rel->reltype;
 2156 tgl@sss.pgh.pa.us          60                 :          21161 :     make_inh_translation_list(parentrel, childrel, childRTindex, appinfo);
 2482 alvherre@alvh.no-ip.       61                 :          21160 :     appinfo->parent_reloid = RelationGetRelid(parentrel);
                                 62                 :                : 
                                 63                 :          21160 :     return appinfo;
                                 64                 :                : }
                                 65                 :                : 
                                 66                 :                : /*
                                 67                 :                :  * make_inh_translation_list
                                 68                 :                :  *    Build the list of translations from parent Vars to child Vars for
                                 69                 :                :  *    an inheritance child, as well as a reverse-translation array.
                                 70                 :                :  *
                                 71                 :                :  * The reverse-translation array has an entry for each child relation
                                 72                 :                :  * column, which is either the 1-based index of the corresponding parent
                                 73                 :                :  * column, or 0 if there's no match (that happens for dropped child columns,
                                 74                 :                :  * as well as child columns beyond those of the parent, which are allowed in
                                 75                 :                :  * traditional inheritance though not partitioning).
                                 76                 :                :  *
                                 77                 :                :  * For paranoia's sake, we match type/collation as well as attribute name.
                                 78                 :                :  */
                                 79                 :                : static void
                                 80                 :          21161 : make_inh_translation_list(Relation oldrelation, Relation newrelation,
                                 81                 :                :                           Index newvarno,
                                 82                 :                :                           AppendRelInfo *appinfo)
                                 83                 :                : {
                                 84                 :          21161 :     List       *vars = NIL;
                                 85                 :                :     AttrNumber *pcolnos;
                                 86                 :          21161 :     TupleDesc   old_tupdesc = RelationGetDescr(oldrelation);
                                 87                 :          21161 :     TupleDesc   new_tupdesc = RelationGetDescr(newrelation);
                                 88                 :          21161 :     Oid         new_relid = RelationGetRelid(newrelation);
                                 89                 :          21161 :     int         oldnatts = old_tupdesc->natts;
                                 90                 :          21161 :     int         newnatts = new_tupdesc->natts;
                                 91                 :                :     int         old_attno;
                                 92                 :          21161 :     int         new_attno = 0;
                                 93                 :                : 
                                 94                 :                :     /* Initialize reverse-translation array with all entries zero */
 2156 tgl@sss.pgh.pa.us          95                 :          21161 :     appinfo->num_child_cols = newnatts;
                                 96                 :          21161 :     appinfo->parent_colnos = pcolnos =
                                 97                 :          21161 :         (AttrNumber *) palloc0(newnatts * sizeof(AttrNumber));
                                 98                 :                : 
 2482 alvherre@alvh.no-ip.       99         [ +  + ]:          78162 :     for (old_attno = 0; old_attno < oldnatts; old_attno++)
                                100                 :                :     {
                                101                 :                :         Form_pg_attribute att;
                                102                 :                :         char       *attname;
                                103                 :                :         Oid         atttypid;
                                104                 :                :         int32       atttypmod;
                                105                 :                :         Oid         attcollation;
                                106                 :                : 
                                107                 :          57002 :         att = TupleDescAttr(old_tupdesc, old_attno);
                                108         [ +  + ]:          57002 :         if (att->attisdropped)
                                109                 :                :         {
                                110                 :                :             /* Just put NULL into this list entry */
                                111                 :           1581 :             vars = lappend(vars, NULL);
                                112                 :           1581 :             continue;
                                113                 :                :         }
                                114                 :          55421 :         attname = NameStr(att->attname);
                                115                 :          55421 :         atttypid = att->atttypid;
                                116                 :          55421 :         atttypmod = att->atttypmod;
                                117                 :          55421 :         attcollation = att->attcollation;
                                118                 :                : 
                                119                 :                :         /*
                                120                 :                :          * When we are generating the "translation list" for the parent table
                                121                 :                :          * of an inheritance set, no need to search for matches.
                                122                 :                :          */
                                123         [ +  + ]:          55421 :         if (oldrelation == newrelation)
                                124                 :                :         {
                                125                 :           3430 :             vars = lappend(vars, makeVar(newvarno,
                                126                 :           3430 :                                          (AttrNumber) (old_attno + 1),
                                127                 :                :                                          atttypid,
                                128                 :                :                                          atttypmod,
                                129                 :                :                                          attcollation,
                                130                 :                :                                          0));
 2156 tgl@sss.pgh.pa.us         131                 :           3430 :             pcolnos[old_attno] = old_attno + 1;
 2482 alvherre@alvh.no-ip.      132                 :           3430 :             continue;
                                133                 :                :         }
                                134                 :                : 
                                135                 :                :         /*
                                136                 :                :          * Otherwise we have to search for the matching column by name.
                                137                 :                :          * There's no guarantee it'll have the same column position, because
                                138                 :                :          * of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
                                139                 :                :          * However, in simple cases, the relative order of columns is mostly
                                140                 :                :          * the same in both relations, so try the column of newrelation that
                                141                 :                :          * follows immediately after the one that we just found, and if that
                                142                 :                :          * fails, let syscache handle it.
                                143                 :                :          */
                                144         [ +  + ]:          51991 :         if (new_attno >= newnatts ||
                                145         [ +  + ]:          50862 :             (att = TupleDescAttr(new_tupdesc, new_attno))->attisdropped ||
                                146         [ +  + ]:          50392 :             strcmp(attname, NameStr(att->attname)) != 0)
                                147                 :                :         {
                                148                 :                :             HeapTuple   newtup;
                                149                 :                : 
                                150                 :           4193 :             newtup = SearchSysCacheAttName(new_relid, attname);
 2367 tgl@sss.pgh.pa.us         151         [ -  + ]:           4193 :             if (!HeapTupleIsValid(newtup))
 2482 alvherre@alvh.no-ip.      152         [ #  # ]:UBC           0 :                 elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
                                153                 :                :                      attname, RelationGetRelationName(newrelation));
 2482 alvherre@alvh.no-ip.      154                 :CBC        4193 :             new_attno = ((Form_pg_attribute) GETSTRUCT(newtup))->attnum - 1;
 2156 tgl@sss.pgh.pa.us         155   [ +  -  -  + ]:           4193 :             Assert(new_attno >= 0 && new_attno < newnatts);
 2482 alvherre@alvh.no-ip.      156                 :           4193 :             ReleaseSysCache(newtup);
                                157                 :                : 
                                158                 :           4193 :             att = TupleDescAttr(new_tupdesc, new_attno);
                                159                 :                :         }
                                160                 :                : 
                                161                 :                :         /* Found it, check type and collation match */
                                162   [ +  +  -  + ]:          51991 :         if (atttypid != att->atttypid || atttypmod != att->atttypmod)
  480 michael@paquier.xyz       163         [ +  - ]:              1 :             ereport(ERROR,
                                164                 :                :                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                                165                 :                :                      errmsg("attribute \"%s\" of relation \"%s\" does not match parent's type",
                                166                 :                :                             attname, RelationGetRelationName(newrelation))));
 2482 alvherre@alvh.no-ip.      167         [ -  + ]:          51990 :         if (attcollation != att->attcollation)
  480 michael@paquier.xyz       168         [ #  # ]:UBC           0 :             ereport(ERROR,
                                169                 :                :                     (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                                170                 :                :                      errmsg("attribute \"%s\" of relation \"%s\" does not match parent's collation",
                                171                 :                :                             attname, RelationGetRelationName(newrelation))));
                                172                 :                : 
 2482 alvherre@alvh.no-ip.      173                 :CBC       51990 :         vars = lappend(vars, makeVar(newvarno,
                                174                 :          51990 :                                      (AttrNumber) (new_attno + 1),
                                175                 :                :                                      atttypid,
                                176                 :                :                                      atttypmod,
                                177                 :                :                                      attcollation,
                                178                 :                :                                      0));
 2156 tgl@sss.pgh.pa.us         179                 :          51990 :         pcolnos[new_attno] = old_attno + 1;
 2482 alvherre@alvh.no-ip.      180                 :          51990 :         new_attno++;
                                181                 :                :     }
                                182                 :                : 
 2156 tgl@sss.pgh.pa.us         183                 :          21160 :     appinfo->translated_vars = vars;
 2482 alvherre@alvh.no-ip.      184                 :          21160 : }
                                185                 :                : 
                                186                 :                : /*
                                187                 :                :  * adjust_appendrel_attrs
                                188                 :                :  *    Copy the specified query or expression and translate Vars referring to a
                                189                 :                :  *    parent rel to refer to the corresponding child rel instead.  We also
                                190                 :                :  *    update rtindexes appearing outside Vars, such as resultRelation and
                                191                 :                :  *    jointree relids.
                                192                 :                :  *
                                193                 :                :  * Note: this is only applied after conversion of sublinks to subplans,
                                194                 :                :  * so we don't need to cope with recursion into sub-queries.
                                195                 :                :  *
                                196                 :                :  * Note: this is not hugely different from what pullup_replace_vars() does;
                                197                 :                :  * maybe we should try to fold the two routines together.
                                198                 :                :  */
                                199                 :                : Node *
                                200                 :         146986 : adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos,
                                201                 :                :                        AppendRelInfo **appinfos)
                                202                 :                : {
                                203                 :                :     adjust_appendrel_attrs_context context;
                                204                 :                : 
                                205                 :         146986 :     context.root = root;
                                206                 :         146986 :     context.nappinfos = nappinfos;
                                207                 :         146986 :     context.appinfos = appinfos;
                                208                 :                : 
                                209                 :                :     /* If there's nothing to adjust, don't call this function. */
                                210   [ +  -  -  + ]:         146986 :     Assert(nappinfos >= 1 && appinfos != NULL);
                                211                 :                : 
                                212                 :                :     /* Should never be translating a Query tree. */
 1671 tgl@sss.pgh.pa.us         213   [ +  +  -  + ]:         146986 :     Assert(node == NULL || !IsA(node, Query));
                                214                 :                : 
                                215                 :         146986 :     return adjust_appendrel_attrs_mutator(node, &context);
                                216                 :                : }
                                217                 :                : 
                                218                 :                : static Node *
 2482 alvherre@alvh.no-ip.      219                 :         760676 : adjust_appendrel_attrs_mutator(Node *node,
                                220                 :                :                                adjust_appendrel_attrs_context *context)
                                221                 :                : {
                                222                 :         760676 :     AppendRelInfo **appinfos = context->appinfos;
                                223                 :         760676 :     int         nappinfos = context->nappinfos;
                                224                 :                :     int         cnt;
                                225                 :                : 
                                226         [ +  + ]:         760676 :     if (node == NULL)
                                227                 :         141727 :         return NULL;
                                228         [ +  + ]:         618949 :     if (IsA(node, Var))
                                229                 :                :     {
                                230                 :         277805 :         Var        *var = (Var *) copyObject(node);
                                231                 :         277805 :         AppendRelInfo *appinfo = NULL;
                                232                 :                : 
 2118 tgl@sss.pgh.pa.us         233         [ -  + ]:         277805 :         if (var->varlevelsup != 0)
 2118 tgl@sss.pgh.pa.us         234                 :UBC           0 :             return (Node *) var;    /* no changes needed */
                                235                 :                : 
                                236                 :                :         /*
                                237                 :                :          * You might think we need to adjust var->varnullingrels, but that
                                238                 :                :          * shouldn't need any changes.  It will contain outer-join relids,
                                239                 :                :          * while the transformation we are making affects only baserels.
                                240                 :                :          * Below, we just propagate var->varnullingrels into the translated
                                241                 :                :          * Var.
                                242                 :                :          *
                                243                 :                :          * If var->varnullingrels isn't empty, and the translation wouldn't be
                                244                 :                :          * a Var, we have to fail.  One could imagine wrapping the translated
                                245                 :                :          * expression in a PlaceHolderVar, but that won't work because this is
                                246                 :                :          * typically used after freezing placeholders.  Fortunately, the case
                                247                 :                :          * appears unreachable at the moment.  We can see nonempty
                                248                 :                :          * var->varnullingrels here, but only in cases involving partitionwise
                                249                 :                :          * joining, and in such cases the translations will always be Vars.
                                250                 :                :          * (Non-Var translations occur only for appendrels made by flattening
                                251                 :                :          * UNION ALL subqueries.)  Should we need to make this work in future,
                                252                 :                :          * a possible fix is to mandate that prepjointree.c create PHVs for
                                253                 :                :          * all non-Var outputs of such subqueries, and then we could look up
                                254                 :                :          * the pre-existing PHV here.  Or perhaps just wrap the translations
                                255                 :                :          * that way to begin with?
                                256                 :                :          *
                                257                 :                :          * If var->varreturningtype is not VAR_RETURNING_DEFAULT, then that
                                258                 :                :          * also needs to be copied to the translated Var.  That too would fail
                                259                 :                :          * if the translation wasn't a Var, but that should never happen since
                                260                 :                :          * a non-default var->varreturningtype is only used for Vars referring
                                261                 :                :          * to the result relation, which should never be a flattened UNION ALL
                                262                 :                :          * subquery.
                                263                 :                :          */
                                264                 :                : 
 2482 alvherre@alvh.no-ip.      265         [ +  + ]:CBC      347149 :         for (cnt = 0; cnt < nappinfos; cnt++)
                                266                 :                :         {
                                267         [ +  + ]:         326658 :             if (var->varno == appinfos[cnt]->parent_relid)
                                268                 :                :             {
                                269                 :         257314 :                 appinfo = appinfos[cnt];
                                270                 :         257314 :                 break;
                                271                 :                :             }
                                272                 :                :         }
                                273                 :                : 
 2118 tgl@sss.pgh.pa.us         274         [ +  + ]:         277805 :         if (appinfo)
                                275                 :                :         {
 2482 alvherre@alvh.no-ip.      276                 :         257314 :             var->varno = appinfo->child_relid;
                                277                 :                :             /* it's now a generated Var, so drop any syntactic labeling */
 2118 tgl@sss.pgh.pa.us         278                 :         257314 :             var->varnosyn = 0;
                                279                 :         257314 :             var->varattnosyn = 0;
 2482 alvherre@alvh.no-ip.      280         [ +  + ]:         257314 :             if (var->varattno > 0)
                                281                 :                :             {
                                282                 :                :                 Node       *newnode;
                                283                 :                : 
                                284         [ -  + ]:         248287 :                 if (var->varattno > list_length(appinfo->translated_vars))
 2482 alvherre@alvh.no-ip.      285         [ #  # ]:UBC           0 :                     elog(ERROR, "attribute %d of relation \"%s\" does not exist",
                                286                 :                :                          var->varattno, get_rel_name(appinfo->parent_reloid));
 2482 alvherre@alvh.no-ip.      287                 :CBC      248287 :                 newnode = copyObject(list_nth(appinfo->translated_vars,
                                288                 :                :                                               var->varattno - 1));
                                289         [ -  + ]:         248287 :                 if (newnode == NULL)
 2482 alvherre@alvh.no-ip.      290         [ #  # ]:UBC           0 :                     elog(ERROR, "attribute %d of relation \"%s\" does not exist",
                                291                 :                :                          var->varattno, get_rel_name(appinfo->parent_reloid));
 1001 tgl@sss.pgh.pa.us         292         [ +  + ]:CBC      248287 :                 if (IsA(newnode, Var))
                                293                 :                :                 {
  284 dean.a.rasheed@gmail      294                 :         243863 :                     ((Var *) newnode)->varreturningtype = var->varreturningtype;
 1001 tgl@sss.pgh.pa.us         295                 :         243863 :                     ((Var *) newnode)->varnullingrels = var->varnullingrels;
                                296                 :                :                 }
                                297                 :                :                 else
                                298                 :                :                 {
  284 dean.a.rasheed@gmail      299         [ -  + ]:           4424 :                     if (var->varreturningtype != VAR_RETURNING_DEFAULT)
  284 dean.a.rasheed@gmail      300         [ #  # ]:UBC           0 :                         elog(ERROR, "failed to apply returningtype to a non-Var");
  284 dean.a.rasheed@gmail      301         [ -  + ]:CBC        4424 :                     if (var->varnullingrels != NULL)
  284 dean.a.rasheed@gmail      302         [ #  # ]:UBC           0 :                         elog(ERROR, "failed to apply nullingrels to a non-Var");
                                303                 :                :                 }
 2482 alvherre@alvh.no-ip.      304                 :CBC      248287 :                 return newnode;
                                305                 :                :             }
                                306         [ +  + ]:           9027 :             else if (var->varattno == 0)
                                307                 :                :             {
                                308                 :                :                 /*
                                309                 :                :                  * Whole-row Var: if we are dealing with named rowtypes, we
                                310                 :                :                  * can use a whole-row Var for the child table plus a coercion
                                311                 :                :                  * step to convert the tuple layout to the parent's rowtype.
                                312                 :                :                  * Otherwise we have to generate a RowExpr.
                                313                 :                :                  */
                                314         [ +  + ]:            545 :                 if (OidIsValid(appinfo->child_reltype))
                                315                 :                :                 {
                                316         [ -  + ]:            517 :                     Assert(var->vartype == appinfo->parent_reltype);
                                317         [ +  + ]:            517 :                     if (appinfo->parent_reltype != appinfo->child_reltype)
                                318                 :                :                     {
                                319                 :            421 :                         ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
                                320                 :                : 
                                321                 :            421 :                         r->arg = (Expr *) var;
                                322                 :            421 :                         r->resulttype = appinfo->parent_reltype;
                                323                 :            421 :                         r->convertformat = COERCE_IMPLICIT_CAST;
                                324                 :            421 :                         r->location = -1;
                                325                 :                :                         /* Make sure the Var node has the right type ID, too */
                                326                 :            421 :                         var->vartype = appinfo->child_reltype;
                                327                 :            421 :                         return (Node *) r;
                                328                 :                :                     }
                                329                 :                :                 }
                                330                 :                :                 else
                                331                 :                :                 {
                                332                 :                :                     /*
                                333                 :                :                      * Build a RowExpr containing the translated variables.
                                334                 :                :                      *
                                335                 :                :                      * In practice var->vartype will always be RECORDOID here,
                                336                 :                :                      * so we need to come up with some suitable column names.
                                337                 :                :                      * We use the parent RTE's column names.
                                338                 :                :                      *
                                339                 :                :                      * Note: we can't get here for inheritance cases, so there
                                340                 :                :                      * is no need to worry that translated_vars might contain
                                341                 :                :                      * some dummy NULLs.
                                342                 :                :                      */
                                343                 :                :                     RowExpr    *rowexpr;
                                344                 :                :                     List       *fields;
                                345                 :                :                     RangeTblEntry *rte;
                                346                 :                : 
                                347                 :             28 :                     rte = rt_fetch(appinfo->parent_relid,
                                348                 :                :                                    context->root->parse->rtable);
                                349                 :             28 :                     fields = copyObject(appinfo->translated_vars);
                                350                 :             28 :                     rowexpr = makeNode(RowExpr);
                                351                 :             28 :                     rowexpr->args = fields;
                                352                 :             28 :                     rowexpr->row_typeid = var->vartype;
                                353                 :             28 :                     rowexpr->row_format = COERCE_IMPLICIT_CAST;
                                354                 :             28 :                     rowexpr->colnames = copyObject(rte->eref->colnames);
                                355                 :             28 :                     rowexpr->location = -1;
                                356                 :                : 
  284 dean.a.rasheed@gmail      357         [ -  + ]:             28 :                     if (var->varreturningtype != VAR_RETURNING_DEFAULT)
  284 dean.a.rasheed@gmail      358         [ #  # ]:UBC           0 :                         elog(ERROR, "failed to apply returningtype to a non-Var");
 1001 tgl@sss.pgh.pa.us         359         [ -  + ]:CBC          28 :                     if (var->varnullingrels != NULL)
 1001 tgl@sss.pgh.pa.us         360         [ #  # ]:UBC           0 :                         elog(ERROR, "failed to apply nullingrels to a non-Var");
                                361                 :                : 
 2482 alvherre@alvh.no-ip.      362                 :CBC          28 :                     return (Node *) rowexpr;
                                363                 :                :                 }
                                364                 :                :             }
                                365                 :                :             /* system attributes don't need any other translation */
                                366                 :                :         }
 1671 tgl@sss.pgh.pa.us         367         [ +  + ]:          20491 :         else if (var->varno == ROWID_VAR)
                                368                 :                :         {
                                369                 :                :             /*
                                370                 :                :              * If it's a ROWID_VAR placeholder, see if we've reached a leaf
                                371                 :                :              * target rel, for which we can translate the Var to a specific
                                372                 :                :              * instantiation.  We should never be asked to translate to a set
                                373                 :                :              * of relids containing more than one leaf target rel, so the
                                374                 :                :              * answer will be unique.  If we're still considering non-leaf
                                375                 :                :              * inheritance levels, return the ROWID_VAR Var as-is.
                                376                 :                :              */
                                377                 :           9663 :             Relids      leaf_result_relids = context->root->leaf_result_relids;
                                378                 :           9663 :             Index       leaf_relid = 0;
                                379                 :                : 
                                380         [ +  + ]:          19326 :             for (cnt = 0; cnt < nappinfos; cnt++)
                                381                 :                :             {
                                382         [ +  + ]:           9663 :                 if (bms_is_member(appinfos[cnt]->child_relid,
                                383                 :                :                                   leaf_result_relids))
                                384                 :                :                 {
                                385         [ -  + ]:           8573 :                     if (leaf_relid)
 1671 tgl@sss.pgh.pa.us         386         [ #  # ]:UBC           0 :                         elog(ERROR, "cannot translate to multiple leaf relids");
 1671 tgl@sss.pgh.pa.us         387                 :CBC        8573 :                     leaf_relid = appinfos[cnt]->child_relid;
                                388                 :                :                 }
                                389                 :                :             }
                                390                 :                : 
                                391         [ +  + ]:           9663 :             if (leaf_relid)
                                392                 :                :             {
                                393                 :                :                 RowIdentityVarInfo *ridinfo = (RowIdentityVarInfo *)
  892                           394                 :           8573 :                     list_nth(context->root->row_identity_vars, var->varattno - 1);
                                395                 :                : 
 1671                           396         [ +  + ]:           8573 :                 if (bms_is_member(leaf_relid, ridinfo->rowidrels))
                                397                 :                :                 {
                                398                 :                :                     /* Substitute the Var given in the RowIdentityVarInfo */
                                399                 :           8527 :                     var = copyObject(ridinfo->rowidvar);
                                400                 :                :                     /* ... but use the correct relid */
                                401                 :           8527 :                     var->varno = leaf_relid;
                                402                 :                :                     /* identity vars shouldn't have nulling rels */
 1001                           403         [ -  + ]:           8527 :                     Assert(var->varnullingrels == NULL);
                                404                 :                :                     /* varnosyn in the RowIdentityVarInfo is probably wrong */
 1671                           405                 :           8527 :                     var->varnosyn = 0;
                                406                 :           8527 :                     var->varattnosyn = 0;
                                407                 :                :                 }
                                408                 :                :                 else
                                409                 :                :                 {
                                410                 :                :                     /*
                                411                 :                :                      * This leaf rel can't return the desired value, so
                                412                 :                :                      * substitute a NULL of the correct type.
                                413                 :                :                      */
                                414                 :             46 :                     return (Node *) makeNullConst(var->vartype,
                                415                 :                :                                                   var->vartypmod,
                                416                 :                :                                                   var->varcollid);
                                417                 :                :                 }
                                418                 :                :             }
                                419                 :                :         }
 2482 alvherre@alvh.no-ip.      420                 :          29023 :         return (Node *) var;
                                421                 :                :     }
                                422         [ +  + ]:         341144 :     if (IsA(node, CurrentOfExpr))
                                423                 :                :     {
                                424                 :             92 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
                                425                 :                : 
                                426         [ +  - ]:             92 :         for (cnt = 0; cnt < nappinfos; cnt++)
                                427                 :                :         {
                                428                 :             92 :             AppendRelInfo *appinfo = appinfos[cnt];
                                429                 :                : 
                                430         [ +  - ]:             92 :             if (cexpr->cvarno == appinfo->parent_relid)
                                431                 :                :             {
                                432                 :             92 :                 cexpr->cvarno = appinfo->child_relid;
                                433                 :             92 :                 break;
                                434                 :                :             }
                                435                 :                :         }
                                436                 :             92 :         return (Node *) cexpr;
                                437                 :                :     }
                                438         [ +  + ]:         341052 :     if (IsA(node, PlaceHolderVar))
                                439                 :                :     {
                                440                 :                :         /* Copy the PlaceHolderVar node with correct mutation of subnodes */
                                441                 :                :         PlaceHolderVar *phv;
                                442                 :                : 
                                443                 :           1404 :         phv = (PlaceHolderVar *) expression_tree_mutator(node,
                                444                 :                :                                                          adjust_appendrel_attrs_mutator,
                                445                 :                :                                                          context);
                                446                 :                :         /* now fix PlaceHolderVar's relid sets */
                                447         [ +  - ]:           1404 :         if (phv->phlevelsup == 0)
                                448                 :                :         {
 1001 tgl@sss.pgh.pa.us         449                 :           1404 :             phv->phrels = adjust_child_relids(phv->phrels,
                                450                 :                :                                               nappinfos, appinfos);
                                451                 :                :             /* as above, we needn't touch phnullingrels */
                                452                 :                :         }
 2482 alvherre@alvh.no-ip.      453                 :           1404 :         return (Node *) phv;
                                454                 :                :     }
                                455                 :                :     /* Shouldn't need to handle planner auxiliary nodes here */
                                456         [ -  + ]:         339648 :     Assert(!IsA(node, SpecialJoinInfo));
                                457         [ -  + ]:         339648 :     Assert(!IsA(node, AppendRelInfo));
                                458         [ -  + ]:         339648 :     Assert(!IsA(node, PlaceHolderInfo));
                                459         [ -  + ]:         339648 :     Assert(!IsA(node, MinMaxAggInfo));
                                460                 :                : 
                                461                 :                :     /*
                                462                 :                :      * We have to process RestrictInfo nodes specially.  (Note: although
                                463                 :                :      * set_append_rel_pathlist will hide RestrictInfos in the parent's
                                464                 :                :      * baserestrictinfo list from us, it doesn't hide those in joininfo.)
                                465                 :                :      */
                                466         [ +  + ]:         339648 :     if (IsA(node, RestrictInfo))
                                467                 :                :     {
                                468                 :          19717 :         RestrictInfo *oldinfo = (RestrictInfo *) node;
                                469                 :          19717 :         RestrictInfo *newinfo = makeNode(RestrictInfo);
                                470                 :                : 
                                471                 :                :         /* Copy all flat-copiable fields, notably including rinfo_serial */
                                472                 :          19717 :         memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
                                473                 :                : 
                                474                 :                :         /* Recursively fix the clause itself */
                                475                 :          19717 :         newinfo->clause = (Expr *)
                                476                 :          19717 :             adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
                                477                 :                : 
                                478                 :                :         /* and the modified version, if an OR clause */
                                479                 :          19717 :         newinfo->orclause = (Expr *)
                                480                 :          19717 :             adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
                                481                 :                : 
                                482                 :                :         /* adjust relid sets too */
                                483                 :          19717 :         newinfo->clause_relids = adjust_child_relids(oldinfo->clause_relids,
                                484                 :                :                                                      context->nappinfos,
                                485                 :                :                                                      context->appinfos);
                                486                 :          19717 :         newinfo->required_relids = adjust_child_relids(oldinfo->required_relids,
                                487                 :                :                                                        context->nappinfos,
                                488                 :                :                                                        context->appinfos);
                                489                 :          19717 :         newinfo->outer_relids = adjust_child_relids(oldinfo->outer_relids,
                                490                 :                :                                                     context->nappinfos,
                                491                 :                :                                                     context->appinfos);
                                492                 :          19717 :         newinfo->left_relids = adjust_child_relids(oldinfo->left_relids,
                                493                 :                :                                                    context->nappinfos,
                                494                 :                :                                                    context->appinfos);
                                495                 :          19717 :         newinfo->right_relids = adjust_child_relids(oldinfo->right_relids,
                                496                 :                :                                                     context->nappinfos,
                                497                 :                :                                                     context->appinfos);
                                498                 :                : 
                                499                 :                :         /*
                                500                 :                :          * Reset cached derivative fields, since these might need to have
                                501                 :                :          * different values when considering the child relation.  Note we
                                502                 :                :          * don't reset left_ec/right_ec: each child variable is implicitly
                                503                 :                :          * equivalent to its parent, so still a member of the same EC if any.
                                504                 :                :          */
                                505                 :          19717 :         newinfo->eval_cost.startup = -1;
                                506                 :          19717 :         newinfo->norm_selec = -1;
                                507                 :          19717 :         newinfo->outer_selec = -1;
                                508                 :          19717 :         newinfo->left_em = NULL;
                                509                 :          19717 :         newinfo->right_em = NULL;
                                510                 :          19717 :         newinfo->scansel_cache = NIL;
                                511                 :          19717 :         newinfo->left_bucketsize = -1;
                                512                 :          19717 :         newinfo->right_bucketsize = -1;
                                513                 :          19717 :         newinfo->left_mcvfreq = -1;
                                514                 :          19717 :         newinfo->right_mcvfreq = -1;
                                515                 :                : 
                                516                 :          19717 :         return (Node *) newinfo;
                                517                 :                :     }
                                518                 :                : 
                                519                 :                :     /*
                                520                 :                :      * We have to process RelAggInfo nodes specially.
                                521                 :                :      */
   19 rguo@postgresql.org       522         [ +  + ]:GNC      319931 :     if (IsA(node, RelAggInfo))
                                523                 :                :     {
                                524                 :           9300 :         RelAggInfo *oldinfo = (RelAggInfo *) node;
                                525                 :           9300 :         RelAggInfo *newinfo = makeNode(RelAggInfo);
                                526                 :                : 
                                527                 :           9300 :         newinfo->target = (PathTarget *)
                                528                 :           9300 :             adjust_appendrel_attrs_mutator((Node *) oldinfo->target,
                                529                 :                :                                            context);
                                530                 :                : 
                                531                 :           9300 :         newinfo->agg_input = (PathTarget *)
                                532                 :           9300 :             adjust_appendrel_attrs_mutator((Node *) oldinfo->agg_input,
                                533                 :                :                                            context);
                                534                 :                : 
                                535                 :           9300 :         newinfo->group_clauses = oldinfo->group_clauses;
                                536                 :                : 
                                537                 :           9300 :         newinfo->group_exprs = (List *)
                                538                 :           9300 :             adjust_appendrel_attrs_mutator((Node *) oldinfo->group_exprs,
                                539                 :                :                                            context);
                                540                 :                : 
                                541                 :           9300 :         return (Node *) newinfo;
                                542                 :                :     }
                                543                 :                : 
                                544                 :                :     /*
                                545                 :                :      * We have to process PathTarget nodes specially.
                                546                 :                :      */
                                547         [ +  + ]:         310631 :     if (IsA(node, PathTarget))
                                548                 :                :     {
                                549                 :          18600 :         PathTarget *oldtarget = (PathTarget *) node;
                                550                 :          18600 :         PathTarget *newtarget = makeNode(PathTarget);
                                551                 :                : 
                                552                 :                :         /* Copy all flat-copiable fields */
                                553                 :          18600 :         memcpy(newtarget, oldtarget, sizeof(PathTarget));
                                554                 :                : 
                                555                 :          18600 :         newtarget->exprs = (List *)
                                556                 :          18600 :             adjust_appendrel_attrs_mutator((Node *) oldtarget->exprs,
                                557                 :                :                                            context);
                                558                 :                : 
                                559         [ +  - ]:          18600 :         if (oldtarget->sortgrouprefs)
                                560                 :                :         {
                                561                 :          18600 :             Size        nbytes = list_length(oldtarget->exprs) * sizeof(Index);
                                562                 :                : 
                                563                 :          18600 :             newtarget->sortgrouprefs = (Index *) palloc(nbytes);
                                564                 :          18600 :             memcpy(newtarget->sortgrouprefs, oldtarget->sortgrouprefs, nbytes);
                                565                 :                :         }
                                566                 :                : 
                                567                 :          18600 :         return (Node *) newtarget;
                                568                 :                :     }
                                569                 :                : 
                                570                 :                :     /*
                                571                 :                :      * NOTE: we do not need to recurse into sublinks, because they should
                                572                 :                :      * already have been converted to subplans before we see them.
                                573                 :                :      */
 2482 alvherre@alvh.no-ip.      574         [ -  + ]:CBC      292031 :     Assert(!IsA(node, SubLink));
                                575         [ -  + ]:         292031 :     Assert(!IsA(node, Query));
                                576                 :                :     /* We should never see these Query substructures, either. */
 1671 tgl@sss.pgh.pa.us         577         [ -  + ]:         292031 :     Assert(!IsA(node, RangeTblRef));
                                578         [ -  + ]:         292031 :     Assert(!IsA(node, JoinExpr));
                                579                 :                : 
  333 peter@eisentraut.org      580                 :         292031 :     return expression_tree_mutator(node, adjust_appendrel_attrs_mutator, context);
                                581                 :                : }
                                582                 :                : 
                                583                 :                : /*
                                584                 :                :  * adjust_appendrel_attrs_multilevel
                                585                 :                :  *    Apply Var translations from an appendrel parent down to a child.
                                586                 :                :  *
                                587                 :                :  * Replace Vars in the "node" expression that reference "parentrel" with
                                588                 :                :  * the appropriate Vars for "childrel".  childrel can be more than one
                                589                 :                :  * inheritance level removed from parentrel.
                                590                 :                :  */
                                591                 :                : Node *
 2476 alvherre@alvh.no-ip.      592                 :          23832 : adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
                                593                 :                :                                   RelOptInfo *childrel,
                                594                 :                :                                   RelOptInfo *parentrel)
                                595                 :                : {
                                596                 :                :     AppendRelInfo **appinfos;
                                597                 :                :     int         nappinfos;
                                598                 :                : 
                                599                 :                :     /* Recurse if immediate parent is not the top parent. */
 1166 tgl@sss.pgh.pa.us         600         [ +  + ]:          23832 :     if (childrel->parent != parentrel)
                                601                 :                :     {
                                602         [ +  - ]:           8168 :         if (childrel->parent)
                                603                 :           8168 :             node = adjust_appendrel_attrs_multilevel(root, node,
                                604                 :           8168 :                                                      childrel->parent,
                                605                 :                :                                                      parentrel);
                                606                 :                :         else
 1166 tgl@sss.pgh.pa.us         607         [ #  # ]:UBC           0 :             elog(ERROR, "childrel is not a child of parentrel");
                                608                 :                :     }
                                609                 :                : 
                                610                 :                :     /* Now translate for this child. */
 1166 tgl@sss.pgh.pa.us         611                 :CBC       23832 :     appinfos = find_appinfos_by_relids(root, childrel->relids, &nappinfos);
                                612                 :                : 
 2476 alvherre@alvh.no-ip.      613                 :          23832 :     node = adjust_appendrel_attrs(root, node, nappinfos, appinfos);
                                614                 :                : 
                                615                 :          23832 :     pfree(appinfos);
                                616                 :                : 
                                617                 :          23832 :     return node;
                                618                 :                : }
                                619                 :                : 
                                620                 :                : /*
                                621                 :                :  * Substitute child relids for parent relids in a Relid set.  The array of
                                622                 :                :  * appinfos specifies the substitutions to be performed.
                                623                 :                :  */
                                624                 :                : Relids
 2482                           625                 :         125828 : adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
                                626                 :                : {
                                627                 :         125828 :     Bitmapset  *result = NULL;
                                628                 :                :     int         cnt;
                                629                 :                : 
                                630         [ +  + ]:         345524 :     for (cnt = 0; cnt < nappinfos; cnt++)
                                631                 :                :     {
                                632                 :         219696 :         AppendRelInfo *appinfo = appinfos[cnt];
                                633                 :                : 
                                634                 :                :         /* Remove parent, add child */
                                635         [ +  + ]:         219696 :         if (bms_is_member(appinfo->parent_relid, relids))
                                636                 :                :         {
                                637                 :                :             /* Make a copy if we are changing the set. */
                                638         [ +  + ]:         147793 :             if (!result)
                                639                 :         100890 :                 result = bms_copy(relids);
                                640                 :                : 
                                641                 :         147793 :             result = bms_del_member(result, appinfo->parent_relid);
                                642                 :         147793 :             result = bms_add_member(result, appinfo->child_relid);
                                643                 :                :         }
                                644                 :                :     }
                                645                 :                : 
                                646                 :                :     /* If we made any changes, return the modified copy. */
                                647         [ +  + ]:         125828 :     if (result)
                                648                 :         100890 :         return result;
                                649                 :                : 
                                650                 :                :     /* Otherwise, return the original set without modification. */
                                651                 :          24938 :     return relids;
                                652                 :                : }
                                653                 :                : 
                                654                 :                : /*
                                655                 :                :  * Substitute child's relids for parent's relids in a Relid set.
                                656                 :                :  * The childrel can be multiple inheritance levels below the parent.
                                657                 :                :  */
                                658                 :                : Relids
                                659                 :            585 : adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
                                660                 :                :                                RelOptInfo *childrel,
                                661                 :                :                                RelOptInfo *parentrel)
                                662                 :                : {
                                663                 :                :     AppendRelInfo **appinfos;
                                664                 :                :     int         nappinfos;
                                665                 :                : 
                                666                 :                :     /*
                                667                 :                :      * If the given relids set doesn't contain any of the parent relids, it
                                668                 :                :      * will remain unchanged.
                                669                 :                :      */
 1166 tgl@sss.pgh.pa.us         670         [ -  + ]:            585 :     if (!bms_overlap(relids, parentrel->relids))
 2482 alvherre@alvh.no-ip.      671                 :UBC           0 :         return relids;
                                672                 :                : 
                                673                 :                :     /* Recurse if immediate parent is not the top parent. */
 1166 tgl@sss.pgh.pa.us         674         [ +  + ]:CBC         585 :     if (childrel->parent != parentrel)
                                675                 :                :     {
                                676         [ +  - ]:             72 :         if (childrel->parent)
                                677                 :             72 :             relids = adjust_child_relids_multilevel(root, relids,
                                678                 :             72 :                                                     childrel->parent,
                                679                 :                :                                                     parentrel);
                                680                 :                :         else
 1166 tgl@sss.pgh.pa.us         681         [ #  # ]:UBC           0 :             elog(ERROR, "childrel is not a child of parentrel");
                                682                 :                :     }
                                683                 :                : 
                                684                 :                :     /* Now translate for this child. */
 1166 tgl@sss.pgh.pa.us         685                 :CBC         585 :     appinfos = find_appinfos_by_relids(root, childrel->relids, &nappinfos);
                                686                 :                : 
                                687                 :            585 :     relids = adjust_child_relids(relids, nappinfos, appinfos);
                                688                 :                : 
 2482 alvherre@alvh.no-ip.      689                 :            585 :     pfree(appinfos);
                                690                 :                : 
 1166 tgl@sss.pgh.pa.us         691                 :            585 :     return relids;
                                692                 :                : }
                                693                 :                : 
                                694                 :                : /*
                                695                 :                :  * adjust_inherited_attnums
                                696                 :                :  *    Translate an integer list of attribute numbers from parent to child.
                                697                 :                :  */
                                698                 :                : List *
 1671                           699                 :           2568 : adjust_inherited_attnums(List *attnums, AppendRelInfo *context)
                                700                 :                : {
                                701                 :           2568 :     List       *result = NIL;
                                702                 :                :     ListCell   *lc;
                                703                 :                : 
                                704                 :                :     /* This should only happen for an inheritance case, not UNION ALL */
 2482 alvherre@alvh.no-ip.      705         [ -  + ]:           2568 :     Assert(OidIsValid(context->parent_reloid));
                                706                 :                : 
                                707                 :                :     /* Look up each attribute in the AppendRelInfo's translated_vars list */
 1671 tgl@sss.pgh.pa.us         708   [ +  -  +  +  :           5731 :     foreach(lc, attnums)
                                              +  + ]
                                709                 :                :     {
                                710                 :           3163 :         AttrNumber  parentattno = lfirst_int(lc);
                                711                 :                :         Var        *childvar;
                                712                 :                : 
                                713                 :                :         /* Look up the translation of this column: it must be a Var */
                                714   [ +  -  -  + ]:           6326 :         if (parentattno <= 0 ||
                                715                 :           3163 :             parentattno > list_length(context->translated_vars))
 2482 alvherre@alvh.no-ip.      716         [ #  # ]:UBC           0 :             elog(ERROR, "attribute %d of relation \"%s\" does not exist",
                                717                 :                :                  parentattno, get_rel_name(context->parent_reloid));
 1671 tgl@sss.pgh.pa.us         718                 :CBC        3163 :         childvar = (Var *) list_nth(context->translated_vars, parentattno - 1);
 2482 alvherre@alvh.no-ip.      719   [ +  -  -  + ]:           3163 :         if (childvar == NULL || !IsA(childvar, Var))
 2482 alvherre@alvh.no-ip.      720         [ #  # ]:UBC           0 :             elog(ERROR, "attribute %d of relation \"%s\" does not exist",
                                721                 :                :                  parentattno, get_rel_name(context->parent_reloid));
                                722                 :                : 
 1671 tgl@sss.pgh.pa.us         723                 :CBC        3163 :         result = lappend_int(result, childvar->varattno);
                                724                 :                :     }
                                725                 :           2568 :     return result;
                                726                 :                : }
                                727                 :                : 
                                728                 :                : /*
                                729                 :                :  * adjust_inherited_attnums_multilevel
                                730                 :                :  *    As above, but traverse multiple inheritance levels as needed.
                                731                 :                :  */
                                732                 :                : List *
                                733                 :           2568 : adjust_inherited_attnums_multilevel(PlannerInfo *root, List *attnums,
                                734                 :                :                                     Index child_relid, Index top_parent_relid)
                                735                 :                : {
                                736                 :           2568 :     AppendRelInfo *appinfo = root->append_rel_array[child_relid];
                                737                 :                : 
                                738         [ -  + ]:           2568 :     if (!appinfo)
 1671 tgl@sss.pgh.pa.us         739         [ #  # ]:UBC           0 :         elog(ERROR, "child rel %d not found in append_rel_array", child_relid);
                                740                 :                : 
                                741                 :                :     /* Recurse if immediate parent is not the top parent. */
 1671 tgl@sss.pgh.pa.us         742         [ +  + ]:CBC        2568 :     if (appinfo->parent_relid != top_parent_relid)
                                743                 :            404 :         attnums = adjust_inherited_attnums_multilevel(root, attnums,
                                744                 :                :                                                       appinfo->parent_relid,
                                745                 :                :                                                       top_parent_relid);
                                746                 :                : 
                                747                 :                :     /* Now translate for this child */
                                748                 :           2568 :     return adjust_inherited_attnums(attnums, appinfo);
                                749                 :                : }
                                750                 :                : 
                                751                 :                : /*
                                752                 :                :  * get_translated_update_targetlist
                                753                 :                :  *    Get the processed_tlist of an UPDATE query, translated as needed to
                                754                 :                :  *    match a child target relation.
                                755                 :                :  *
                                756                 :                :  * Optionally also return the list of target column numbers translated
                                757                 :                :  * to this target relation.  (The resnos in processed_tlist MUST NOT be
                                758                 :                :  * relied on for this purpose.)
                                759                 :                :  */
                                760                 :                : void
                                761                 :             50 : get_translated_update_targetlist(PlannerInfo *root, Index relid,
                                762                 :                :                                  List **processed_tlist, List **update_colnos)
                                763                 :                : {
                                764                 :                :     /* This is pretty meaningless for commands other than UPDATE. */
                                765         [ -  + ]:             50 :     Assert(root->parse->commandType == CMD_UPDATE);
                                766         [ +  + ]:             50 :     if (relid == root->parse->resultRelation)
                                767                 :                :     {
                                768                 :                :         /*
                                769                 :                :          * Non-inheritance case, so it's easy.  The caller might be expecting
                                770                 :                :          * a tree it can scribble on, though, so copy.
                                771                 :                :          */
                                772                 :             33 :         *processed_tlist = copyObject(root->processed_tlist);
                                773         [ +  - ]:             33 :         if (update_colnos)
                                774                 :             33 :             *update_colnos = copyObject(root->update_colnos);
                                775                 :                :     }
                                776                 :                :     else
                                777                 :                :     {
                                778         [ -  + ]:             17 :         Assert(bms_is_member(relid, root->all_result_relids));
                                779                 :             17 :         *processed_tlist = (List *)
                                780                 :             17 :             adjust_appendrel_attrs_multilevel(root,
                                781                 :             17 :                                               (Node *) root->processed_tlist,
                                782                 :                :                                               find_base_rel(root, relid),
 1166                           783                 :             17 :                                               find_base_rel(root, root->parse->resultRelation));
 1671                           784         [ +  - ]:             17 :         if (update_colnos)
                                785                 :             17 :             *update_colnos =
                                786                 :             17 :                 adjust_inherited_attnums_multilevel(root, root->update_colnos,
                                787                 :                :                                                     relid,
                                788                 :             17 :                                                     root->parse->resultRelation);
                                789                 :                :     }
 2482 alvherre@alvh.no-ip.      790                 :             50 : }
                                791                 :                : 
                                792                 :                : /*
                                793                 :                :  * find_appinfos_by_relids
                                794                 :                :  *      Find AppendRelInfo structures for base relations listed in relids.
                                795                 :                :  *
                                796                 :                :  * The relids argument is typically a join relation's relids, which can
                                797                 :                :  * include outer-join RT indexes in addition to baserels.  We silently
                                798                 :                :  * ignore the outer joins.
                                799                 :                :  *
                                800                 :                :  * The AppendRelInfos are returned in an array, which can be pfree'd by the
                                801                 :                :  * caller. *nappinfos is set to the number of entries in the array.
                                802                 :                :  */
                                803                 :                : AppendRelInfo **
                                804                 :          50231 : find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
                                805                 :                : {
                                806                 :                :     AppendRelInfo **appinfos;
                                807                 :          50231 :     int         cnt = 0;
                                808                 :                :     int         i;
                                809                 :                : 
                                810                 :                :     /* Allocate an array that's certainly big enough */
                                811                 :                :     appinfos = (AppendRelInfo **)
 1001 tgl@sss.pgh.pa.us         812                 :          50231 :         palloc(sizeof(AppendRelInfo *) * bms_num_members(relids));
                                813                 :                : 
 2482 alvherre@alvh.no-ip.      814                 :          50231 :     i = -1;
                                815         [ +  + ]:         126317 :     while ((i = bms_next_member(relids, i)) >= 0)
                                816                 :                :     {
                                817                 :          76086 :         AppendRelInfo *appinfo = root->append_rel_array[i];
                                818                 :                : 
                                819         [ +  + ]:          76086 :         if (!appinfo)
                                820                 :                :         {
                                821                 :                :             /* Probably i is an OJ index, but let's check */
 1001 tgl@sss.pgh.pa.us         822         [ +  - ]:           1788 :             if (find_base_rel_ignore_join(root, i) == NULL)
                                823                 :           1788 :                 continue;
                                824                 :                :             /* It's a base rel, but we lack an append_rel_array entry */
 2482 alvherre@alvh.no-ip.      825         [ #  # ]:UBC           0 :             elog(ERROR, "child rel %d not found in append_rel_array", i);
                                826                 :                :         }
                                827                 :                : 
 2482 alvherre@alvh.no-ip.      828                 :CBC       74298 :         appinfos[cnt++] = appinfo;
                                829                 :                :     }
 1001 tgl@sss.pgh.pa.us         830                 :          50231 :     *nappinfos = cnt;
 2482 alvherre@alvh.no-ip.      831                 :          50231 :     return appinfos;
                                832                 :                : }
                                833                 :                : 
                                834                 :                : 
                                835                 :                : /*****************************************************************************
                                836                 :                :  *
                                837                 :                :  *      ROW-IDENTITY VARIABLE MANAGEMENT
                                838                 :                :  *
                                839                 :                :  * This code lacks a good home, perhaps.  We choose to keep it here because
                                840                 :                :  * adjust_appendrel_attrs_mutator() is its principal co-conspirator.  That
                                841                 :                :  * function does most of what is needed to expand ROWID_VAR Vars into the
                                842                 :                :  * right things.
                                843                 :                :  *
                                844                 :                :  *****************************************************************************/
                                845                 :                : 
                                846                 :                : /*
                                847                 :                :  * add_row_identity_var
                                848                 :                :  *    Register a row-identity column to be used in UPDATE/DELETE/MERGE.
                                849                 :                :  *
                                850                 :                :  * The Var must be equal(), aside from varno, to any other row-identity
                                851                 :                :  * column with the same rowid_name.  Thus, for example, "wholerow"
                                852                 :                :  * row identities had better use vartype == RECORDOID.
                                853                 :                :  *
                                854                 :                :  * rtindex is currently redundant with rowid_var->varno, but we specify
                                855                 :                :  * it as a separate parameter in case this is ever generalized to support
                                856                 :                :  * non-Var expressions.  (We could reasonably handle expressions over
                                857                 :                :  * Vars of the specified rtindex, but for now that seems unnecessary.)
                                858                 :                :  */
                                859                 :                : void
 1671 tgl@sss.pgh.pa.us         860                 :          14152 : add_row_identity_var(PlannerInfo *root, Var *orig_var,
                                861                 :                :                      Index rtindex, const char *rowid_name)
                                862                 :                : {
                                863                 :                :     TargetEntry *tle;
                                864                 :                :     Var        *rowid_var;
                                865                 :                :     RowIdentityVarInfo *ridinfo;
                                866                 :                :     ListCell   *lc;
                                867                 :                : 
                                868                 :                :     /* For now, the argument must be just a Var of the given rtindex */
                                869         [ -  + ]:          14152 :     Assert(IsA(orig_var, Var));
                                870         [ -  + ]:          14152 :     Assert(orig_var->varno == rtindex);
                                871         [ -  + ]:          14152 :     Assert(orig_var->varlevelsup == 0);
 1001                           872         [ -  + ]:          14152 :     Assert(orig_var->varnullingrels == NULL);
                                873                 :                : 
                                874                 :                :     /*
                                875                 :                :      * If we're doing non-inherited UPDATE/DELETE/MERGE, there's little need
                                876                 :                :      * for ROWID_VAR shenanigans.  Just shove the presented Var into the
                                877                 :                :      * processed_tlist, and we're done.
                                878                 :                :      */
 1671                           879         [ +  + ]:          14152 :     if (rtindex == root->parse->resultRelation)
                                880                 :                :     {
                                881                 :           8599 :         tle = makeTargetEntry((Expr *) orig_var,
                                882                 :           8599 :                               list_length(root->processed_tlist) + 1,
                                883                 :                :                               pstrdup(rowid_name),
                                884                 :                :                               true);
                                885                 :           8599 :         root->processed_tlist = lappend(root->processed_tlist, tle);
                                886                 :           8599 :         return;
                                887                 :                :     }
                                888                 :                : 
                                889                 :                :     /*
                                890                 :                :      * Otherwise, rtindex should reference a leaf target relation that's being
                                891                 :                :      * added to the query during expand_inherited_rtentry().
                                892                 :                :      */
                                893         [ -  + ]:           5553 :     Assert(bms_is_member(rtindex, root->leaf_result_relids));
                                894         [ -  + ]:           5553 :     Assert(root->append_rel_array[rtindex] != NULL);
                                895                 :                : 
                                896                 :                :     /*
                                897                 :                :      * We have to find a matching RowIdentityVarInfo, or make one if there is
                                898                 :                :      * none.  To allow using equal() to match the vars, change the varno to
                                899                 :                :      * ROWID_VAR, leaving all else alone.
                                900                 :                :      */
                                901                 :           5553 :     rowid_var = copyObject(orig_var);
                                902                 :                :     /* This could eventually become ChangeVarNodes() */
                                903                 :           5553 :     rowid_var->varno = ROWID_VAR;
                                904                 :                : 
                                905                 :                :     /* Look for an existing row-id column of the same name */
                                906   [ +  +  +  +  :           8393 :     foreach(lc, root->row_identity_vars)
                                              +  + ]
                                907                 :                :     {
                                908                 :           5478 :         ridinfo = (RowIdentityVarInfo *) lfirst(lc);
                                909         [ +  + ]:           5478 :         if (strcmp(rowid_name, ridinfo->rowidname) != 0)
                                910                 :           2840 :             continue;
                                911         [ +  - ]:           2638 :         if (equal(rowid_var, ridinfo->rowidvar))
                                912                 :                :         {
                                913                 :                :             /* Found a match; we need only record that rtindex needs it too */
                                914                 :           2638 :             ridinfo->rowidrels = bms_add_member(ridinfo->rowidrels, rtindex);
                                915                 :           2638 :             return;
                                916                 :                :         }
                                917                 :                :         else
                                918                 :                :         {
                                919                 :                :             /* Ooops, can't handle this */
 1671 tgl@sss.pgh.pa.us         920         [ #  # ]:UBC           0 :             elog(ERROR, "conflicting uses of row-identity name \"%s\"",
                                921                 :                :                  rowid_name);
                                922                 :                :         }
                                923                 :                :     }
                                924                 :                : 
                                925                 :                :     /* No request yet, so add a new RowIdentityVarInfo */
 1671 tgl@sss.pgh.pa.us         926                 :CBC        2915 :     ridinfo = makeNode(RowIdentityVarInfo);
                                927                 :           2915 :     ridinfo->rowidvar = copyObject(rowid_var);
                                928                 :                :     /* for the moment, estimate width using just the datatype info */
                                929                 :           2915 :     ridinfo->rowidwidth = get_typavgwidth(exprType((Node *) rowid_var),
                                930                 :                :                                           exprTypmod((Node *) rowid_var));
                                931                 :           2915 :     ridinfo->rowidname = pstrdup(rowid_name);
                                932                 :           2915 :     ridinfo->rowidrels = bms_make_singleton(rtindex);
                                933                 :                : 
                                934                 :           2915 :     root->row_identity_vars = lappend(root->row_identity_vars, ridinfo);
                                935                 :                : 
                                936                 :                :     /* Change rowid_var into a reference to this row_identity_vars entry */
                                937                 :           2915 :     rowid_var->varattno = list_length(root->row_identity_vars);
                                938                 :                : 
                                939                 :                :     /* Push the ROWID_VAR reference variable into processed_tlist */
                                940                 :           2915 :     tle = makeTargetEntry((Expr *) rowid_var,
                                941                 :           2915 :                           list_length(root->processed_tlist) + 1,
                                942                 :                :                           pstrdup(rowid_name),
                                943                 :                :                           true);
                                944                 :           2915 :     root->processed_tlist = lappend(root->processed_tlist, tle);
                                945                 :                : }
                                946                 :                : 
                                947                 :                : /*
                                948                 :                :  * add_row_identity_columns
                                949                 :                :  *
                                950                 :                :  * This function adds the row identity columns needed by the core code.
                                951                 :                :  * FDWs might call add_row_identity_var() for themselves to add nonstandard
                                952                 :                :  * columns.  (Duplicate requests are fine.)
                                953                 :                :  */
                                954                 :                : void
                                955                 :          11432 : add_row_identity_columns(PlannerInfo *root, Index rtindex,
                                956                 :                :                          RangeTblEntry *target_rte,
                                957                 :                :                          Relation target_relation)
                                958                 :                : {
                                959                 :          11432 :     CmdType     commandType = root->parse->commandType;
                                960                 :          11432 :     char        relkind = target_relation->rd_rel->relkind;
                                961                 :                :     Var        *var;
                                962                 :                : 
 1309 alvherre@alvh.no-ip.      963   [ +  +  +  +  :          11432 :     Assert(commandType == CMD_UPDATE || commandType == CMD_DELETE || commandType == CMD_MERGE);
                                              -  + ]
                                964                 :                : 
  606 dean.a.rasheed@gmail      965   [ +  +  +  + ]:          11432 :     if (relkind == RELKIND_RELATION ||
 1671 tgl@sss.pgh.pa.us         966         [ +  + ]:            358 :         relkind == RELKIND_MATVIEW ||
                                967                 :                :         relkind == RELKIND_PARTITIONED_TABLE)
                                968                 :                :     {
                                969                 :                :         /*
                                970                 :                :          * Emit CTID so that executor can find the row to merge, update or
                                971                 :                :          * delete.
                                972                 :                :          */
                                973                 :          11092 :         var = makeVar(rtindex,
                                974                 :                :                       SelfItemPointerAttributeNumber,
                                975                 :                :                       TIDOID,
                                976                 :                :                       -1,
                                977                 :                :                       InvalidOid,
                                978                 :                :                       0);
                                979                 :          11092 :         add_row_identity_var(root, var, rtindex, "ctid");
                                980                 :                :     }
                                981         [ +  + ]:            340 :     else if (relkind == RELKIND_FOREIGN_TABLE)
                                982                 :                :     {
                                983                 :                :         /*
                                984                 :                :          * Let the foreign table's FDW add whatever junk TLEs it wants.
                                985                 :                :          */
                                986                 :                :         FdwRoutine *fdwroutine;
                                987                 :                : 
                                988                 :            193 :         fdwroutine = GetFdwRoutineForRelation(target_relation, false);
                                989                 :                : 
                                990         [ +  + ]:            193 :         if (fdwroutine->AddForeignUpdateTargets != NULL)
                                991                 :            189 :             fdwroutine->AddForeignUpdateTargets(root, rtindex,
                                992                 :                :                                                 target_rte, target_relation);
                                993                 :                : 
                                994                 :                :         /*
                                995                 :                :          * For UPDATE, we need to make the FDW fetch unchanged columns by
                                996                 :                :          * asking it to fetch a whole-row Var.  That's because the top-level
                                997                 :                :          * targetlist only contains entries for changed columns, but
                                998                 :                :          * ExecUpdate will need to build the complete new tuple.  (Actually,
                                999                 :                :          * we only really need this in UPDATEs that are not pushed to the
                               1000                 :                :          * remote side, but it's hard to tell if that will be the case at the
                               1001                 :                :          * point when this function is called.)
                               1002                 :                :          *
                               1003                 :                :          * We will also need the whole row if there are any row triggers, so
                               1004                 :                :          * that the executor will have the "old" row to pass to the trigger.
                               1005                 :                :          * Alas, this misses system columns.
                               1006                 :                :          */
                               1007         [ +  + ]:            193 :         if (commandType == CMD_UPDATE ||
                               1008         [ +  + ]:             86 :             (target_relation->trigdesc &&
                               1009         [ +  + ]:             15 :              (target_relation->trigdesc->trig_delete_after_row ||
                               1010         [ +  + ]:              9 :               target_relation->trigdesc->trig_delete_before_row)))
                               1011                 :                :         {
                               1012                 :            115 :             var = makeVar(rtindex,
                               1013                 :                :                           InvalidAttrNumber,
                               1014                 :                :                           RECORDOID,
                               1015                 :                :                           -1,
                               1016                 :                :                           InvalidOid,
                               1017                 :                :                           0);
                               1018                 :            115 :             add_row_identity_var(root, var, rtindex, "wholerow");
                               1019                 :                :         }
                               1020                 :                :     }
                               1021                 :          11432 : }
                               1022                 :                : 
                               1023                 :                : /*
                               1024                 :                :  * distribute_row_identity_vars
                               1025                 :                :  *
                               1026                 :                :  * After we have finished identifying all the row identity columns
                               1027                 :                :  * needed by an inherited UPDATE/DELETE/MERGE query, make sure that
                               1028                 :                :  * these columns will be generated by all the target relations.
                               1029                 :                :  *
                               1030                 :                :  * This is more or less like what build_base_rel_tlists() does,
                               1031                 :                :  * except that it would not understand what to do with ROWID_VAR Vars.
                               1032                 :                :  * Since that function runs before inheritance relations are expanded,
                               1033                 :                :  * it will never see any such Vars anyway.
                               1034                 :                :  */
                               1035                 :                : void
                               1036                 :         162950 : distribute_row_identity_vars(PlannerInfo *root)
                               1037                 :                : {
                               1038                 :         162950 :     Query      *parse = root->parse;
                               1039                 :         162950 :     int         result_relation = parse->resultRelation;
                               1040                 :                :     RangeTblEntry *target_rte;
                               1041                 :                :     RelOptInfo *target_rel;
                               1042                 :                :     ListCell   *lc;
                               1043                 :                : 
                               1044                 :                :     /*
                               1045                 :                :      * There's nothing to do if this isn't an inherited UPDATE/DELETE/MERGE.
                               1046                 :                :      */
 1309 alvherre@alvh.no-ip.     1047   [ +  +  +  + ]:         162950 :     if (parse->commandType != CMD_UPDATE && parse->commandType != CMD_DELETE &&
                               1048         [ +  + ]:         153732 :         parse->commandType != CMD_MERGE)
                               1049                 :                :     {
 1671 tgl@sss.pgh.pa.us        1050         [ -  + ]:         152841 :         Assert(root->row_identity_vars == NIL);
                               1051                 :         152841 :         return;
                               1052                 :                :     }
                               1053                 :          10109 :     target_rte = rt_fetch(result_relation, parse->rtable);
                               1054         [ +  + ]:          10109 :     if (!target_rte->inh)
                               1055                 :                :     {
                               1056         [ -  + ]:           8657 :         Assert(root->row_identity_vars == NIL);
                               1057                 :           8657 :         return;
                               1058                 :                :     }
                               1059                 :                : 
                               1060                 :                :     /*
                               1061                 :                :      * Ordinarily, we expect that leaf result relation(s) will have added some
                               1062                 :                :      * ROWID_VAR Vars to the query.  However, it's possible that constraint
                               1063                 :                :      * exclusion suppressed every leaf relation.  The executor will get upset
                               1064                 :                :      * if the plan has no row identity columns at all, even though it will
                               1065                 :                :      * certainly process no rows.  Handle this edge case by re-opening the top
                               1066                 :                :      * result relation and adding the row identity columns it would have used,
                               1067                 :                :      * as preprocess_targetlist() would have done if it weren't marked "inh".
                               1068                 :                :      * Then re-run build_base_rel_tlists() to ensure that the added columns
                               1069                 :                :      * get propagated to the relation's reltarget.  (This is a bit ugly, but
                               1070                 :                :      * it seems better to confine the ugliness and extra cycles to this
                               1071                 :                :      * unusual corner case.)
                               1072                 :                :      */
                               1073         [ +  + ]:           1452 :     if (root->row_identity_vars == NIL)
                               1074                 :                :     {
                               1075                 :                :         Relation    target_relation;
                               1076                 :                : 
                               1077                 :             15 :         target_relation = table_open(target_rte->relid, NoLock);
                               1078                 :             15 :         add_row_identity_columns(root, result_relation,
                               1079                 :                :                                  target_rte, target_relation);
                               1080                 :             15 :         table_close(target_relation, NoLock);
  944                          1081                 :             15 :         build_base_rel_tlists(root, root->processed_tlist);
                               1082                 :                :         /* There are no ROWID_VAR Vars in this case, so we're done. */
 1671                          1083                 :             15 :         return;
                               1084                 :                :     }
                               1085                 :                : 
                               1086                 :                :     /*
                               1087                 :                :      * Dig through the processed_tlist to find the ROWID_VAR reference Vars,
                               1088                 :                :      * and forcibly copy them into the reltarget list of the topmost target
                               1089                 :                :      * relation.  That's sufficient because they'll be copied to the
                               1090                 :                :      * individual leaf target rels (with appropriate translation) later,
                               1091                 :                :      * during appendrel expansion --- see set_append_rel_size().
                               1092                 :                :      */
                               1093                 :           1437 :     target_rel = find_base_rel(root, result_relation);
                               1094                 :                : 
                               1095   [ +  -  +  +  :           6028 :     foreach(lc, root->processed_tlist)
                                              +  + ]
                               1096                 :                :     {
                               1097                 :           4591 :         TargetEntry *tle = lfirst(lc);
                               1098                 :           4591 :         Var        *var = (Var *) tle->expr;
                               1099                 :                : 
                               1100   [ +  -  +  +  :           4591 :         if (var && IsA(var, Var) && var->varno == ROWID_VAR)
                                              +  + ]
                               1101                 :                :         {
                               1102                 :           2915 :             target_rel->reltarget->exprs =
                               1103                 :           2915 :                 lappend(target_rel->reltarget->exprs, copyObject(var));
                               1104                 :                :             /* reltarget cost and width will be computed later */
                               1105                 :                :         }
                               1106                 :                :     }
                               1107                 :                : }
        

Generated by: LCOV version 2.4-beta