LCOV - differential code coverage report
Current view: top level - src/backend/optimizer/util - appendinfo.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 95.2 % 334 318 16 1 317 2
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 14 14 1 13
Baseline: 16@8cea358b128 Branches: 68.6 % 264 181 83 4 177
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 100.0 % 1 1 1
(240..) days: 95.2 % 333 317 16 317
Function coverage date bins:
(240..) days: 100.0 % 14 14 1 13
Branch coverage date bins:
[..60] days: 100.0 % 4 4 4
(240..) days: 68.1 % 260 177 83 177

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

Generated by: LCOV version 2.1-beta2-3-g6141622