LCOV - differential code coverage report
Current view: top level - src/backend/optimizer/prep - preptlist.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 89.4 % 151 135 16 135
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 4 4 4
Baseline: lcov-20250906-005545-baseline Branches: 87.5 % 128 112 16 112
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 16 16 16
(360..) days: 88.1 % 135 119 16 119
Function coverage date bins:
(30,360] days: 100.0 % 1 1 1
(360..) days: 100.0 % 3 3 3
Branch coverage date bins:
(30,360] days: 100.0 % 6 6 6
(360..) days: 86.9 % 122 106 16 106

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * preptlist.c
                                  4                 :                :  *    Routines to preprocess the parse tree target list
                                  5                 :                :  *
                                  6                 :                :  * For an INSERT, the targetlist must contain an entry for each attribute of
                                  7                 :                :  * the target relation in the correct order.
                                  8                 :                :  *
                                  9                 :                :  * For an UPDATE, the targetlist just contains the expressions for the new
                                 10                 :                :  * column values.
                                 11                 :                :  *
                                 12                 :                :  * For UPDATE and DELETE queries, the targetlist must also contain "junk"
                                 13                 :                :  * tlist entries needed to allow the executor to identify the rows to be
                                 14                 :                :  * updated or deleted; for example, the ctid of a heap row.  (The planner
                                 15                 :                :  * adds these; they're not in what we receive from the parser/rewriter.)
                                 16                 :                :  *
                                 17                 :                :  * For all query types, there can be additional junk tlist entries, such as
                                 18                 :                :  * sort keys, Vars needed for a RETURNING list, and row ID information needed
                                 19                 :                :  * for SELECT FOR UPDATE locking and/or EvalPlanQual checking.
                                 20                 :                :  *
                                 21                 :                :  * The query rewrite phase also does preprocessing of the targetlist (see
                                 22                 :                :  * rewriteTargetListIU).  The division of labor between here and there is
                                 23                 :                :  * partially historical, but it's not entirely arbitrary.  The stuff done
                                 24                 :                :  * here is closely connected to physical access to tables, whereas the
                                 25                 :                :  * rewriter's work is more concerned with SQL semantics.
                                 26                 :                :  *
                                 27                 :                :  *
                                 28                 :                :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
                                 29                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 30                 :                :  *
                                 31                 :                :  * IDENTIFICATION
                                 32                 :                :  *    src/backend/optimizer/prep/preptlist.c
                                 33                 :                :  *
                                 34                 :                :  *-------------------------------------------------------------------------
                                 35                 :                :  */
                                 36                 :                : 
                                 37                 :                : #include "postgres.h"
                                 38                 :                : 
                                 39                 :                : #include "access/table.h"
                                 40                 :                : #include "nodes/makefuncs.h"
                                 41                 :                : #include "optimizer/appendinfo.h"
                                 42                 :                : #include "optimizer/optimizer.h"
                                 43                 :                : #include "optimizer/prep.h"
                                 44                 :                : #include "optimizer/tlist.h"
                                 45                 :                : #include "parser/parse_coerce.h"
                                 46                 :                : #include "parser/parsetree.h"
                                 47                 :                : #include "utils/lsyscache.h"
                                 48                 :                : #include "utils/rel.h"
                                 49                 :                : 
                                 50                 :                : static List *expand_insert_targetlist(PlannerInfo *root, List *tlist,
                                 51                 :                :                                       Relation rel);
                                 52                 :                : 
                                 53                 :                : 
                                 54                 :                : /*
                                 55                 :                :  * preprocess_targetlist
                                 56                 :                :  *    Driver for preprocessing the parse tree targetlist.
                                 57                 :                :  *
                                 58                 :                :  * The preprocessed targetlist is returned in root->processed_tlist.
                                 59                 :                :  * Also, if this is an UPDATE, we return a list of target column numbers
                                 60                 :                :  * in root->update_colnos.  (Resnos in processed_tlist will be consecutive,
                                 61                 :                :  * so do not look at that to find out which columns are targets!)
                                 62                 :                :  */
                                 63                 :                : void
 2840 tgl@sss.pgh.pa.us          64                 :CBC      253353 : preprocess_targetlist(PlannerInfo *root)
                                 65                 :                : {
 7266 bruce@momjian.us           66                 :         253353 :     Query      *parse = root->parse;
                                 67                 :         253353 :     int         result_relation = parse->resultRelation;
                                 68                 :         253353 :     List       *range_table = parse->rtable;
                                 69                 :         253353 :     CmdType     command_type = parse->commandType;
 2840 tgl@sss.pgh.pa.us          70                 :         253353 :     RangeTblEntry *target_rte = NULL;
                                 71                 :         253353 :     Relation    target_relation = NULL;
                                 72                 :                :     List       *tlist;
                                 73                 :                :     ListCell   *lc;
                                 74                 :                : 
                                 75                 :                :     /*
                                 76                 :                :      * If there is a result relation, open it so we can look for missing
                                 77                 :                :      * columns and so on.  We assume that previous code already acquired at
                                 78                 :                :      * least AccessShareLock on the relation, so we need no lock here.
                                 79                 :                :      */
 9102                            80         [ +  + ]:         253353 :     if (result_relation)
                                 81                 :                :     {
 2840                            82                 :          43081 :         target_rte = rt_fetch(result_relation, range_table);
                                 83                 :                : 
                                 84                 :                :         /*
                                 85                 :                :          * Sanity check: it'd better be a real relation not, say, a subquery.
                                 86                 :                :          * Else parser or rewriter messed up.
                                 87                 :                :          */
                                 88         [ -  + ]:          43081 :         if (target_rte->rtekind != RTE_RELATION)
 2840 tgl@sss.pgh.pa.us          89         [ #  # ]:UBC           0 :             elog(ERROR, "result relation must be a regular relation");
                                 90                 :                : 
 2420 andres@anarazel.de         91                 :CBC       43081 :         target_relation = table_open(target_rte->relid, NoLock);
                                 92                 :                :     }
                                 93                 :                :     else
 2840 tgl@sss.pgh.pa.us          94         [ -  + ]:         210272 :         Assert(command_type == CMD_SELECT);
                                 95                 :                : 
                                 96                 :                :     /*
                                 97                 :                :      * In an INSERT, the executor expects the targetlist to match the exact
                                 98                 :                :      * order of the target table's attributes, including entries for
                                 99                 :                :      * attributes not mentioned in the source query.
                                100                 :                :      *
                                101                 :                :      * In an UPDATE, we don't rearrange the tlist order, but we need to make a
                                102                 :                :      * separate list of the target attribute numbers, in tlist order, and then
                                103                 :                :      * renumber the processed_tlist entries to be consecutive.
                                104                 :                :      */
                                105                 :         253353 :     tlist = parse->targetList;
 1620                           106         [ +  + ]:         253353 :     if (command_type == CMD_INSERT)
  220                           107                 :          33072 :         tlist = expand_insert_targetlist(root, tlist, target_relation);
 1620                           108         [ +  + ]:         220281 :     else if (command_type == CMD_UPDATE)
 1580                           109                 :           6962 :         root->update_colnos = extract_update_targetlist_colnos(tlist);
                                110                 :                : 
                                111                 :                :     /*
                                112                 :                :      * For non-inherited UPDATE/DELETE/MERGE, register any junk column(s)
                                113                 :                :      * needed to allow the executor to identify the rows to be updated or
                                114                 :                :      * deleted.  In the inheritance case, we do nothing now, leaving this to
                                115                 :                :      * be dealt with when expand_inherited_rtentry() makes the leaf target
                                116                 :                :      * relations.  (But there might not be any leaf target relations, in which
                                117                 :                :      * case we must do this in distribute_row_identity_vars().)
                                118                 :                :      */
 1243 alvherre@alvh.no-ip.      119   [ +  +  +  +  :         253353 :     if ((command_type == CMD_UPDATE || command_type == CMD_DELETE ||
                                              +  + ]
                                120                 :          10009 :          command_type == CMD_MERGE) &&
 1620 tgl@sss.pgh.pa.us         121         [ +  + ]:          10009 :         !target_rte->inh)
                                122                 :                :     {
                                123                 :                :         /* row-identity logic expects to add stuff to processed_tlist */
                                124                 :           8564 :         root->processed_tlist = tlist;
                                125                 :           8564 :         add_row_identity_columns(root, result_relation,
                                126                 :                :                                  target_rte, target_relation);
                                127                 :           8564 :         tlist = root->processed_tlist;
                                128                 :                :     }
                                129                 :                : 
                                130                 :                :     /*
                                131                 :                :      * For MERGE we also need to handle the target list for each INSERT and
                                132                 :                :      * UPDATE action separately.  In addition, we examine the qual of each
                                133                 :                :      * action and add any Vars there (other than those of the target rel) to
                                134                 :                :      * the subplan targetlist.
                                135                 :                :      */
 1258 alvherre@alvh.no-ip.      136         [ +  + ]:         253353 :     if (command_type == CMD_MERGE)
                                137                 :                :     {
                                138                 :                :         ListCell   *l;
                                139                 :                :         List       *vars;
                                140                 :                : 
                                141                 :                :         /*
                                142                 :                :          * For MERGE, handle targetlist of each MergeAction separately. Give
                                143                 :                :          * the same treatment to MergeAction->targetList as we would have
                                144                 :                :          * given to a regular INSERT.  For UPDATE, collect the column numbers
                                145                 :                :          * being modified.
                                146                 :                :          */
                                147   [ +  -  +  +  :           2292 :         foreach(l, parse->mergeActionList)
                                              +  + ]
                                148                 :                :         {
                                149                 :           1398 :             MergeAction *action = (MergeAction *) lfirst(l);
                                150                 :                :             ListCell   *l2;
                                151                 :                : 
                                152         [ +  + ]:           1398 :             if (action->commandType == CMD_INSERT)
  220 tgl@sss.pgh.pa.us         153                 :            457 :                 action->targetList = expand_insert_targetlist(root,
                                154                 :                :                                                               action->targetList,
                                155                 :                :                                                               target_relation);
 1258 alvherre@alvh.no-ip.      156         [ +  + ]:            941 :             else if (action->commandType == CMD_UPDATE)
                                157                 :            676 :                 action->updateColnos =
                                158                 :            676 :                     extract_update_targetlist_colnos(action->targetList);
                                159                 :                : 
                                160                 :                :             /*
                                161                 :                :              * Add resjunk entries for any Vars and PlaceHolderVars used in
                                162                 :                :              * each action's targetlist and WHEN condition that belong to
                                163                 :                :              * relations other than the target.  We don't expect to see any
                                164                 :                :              * aggregates or window functions here.
                                165                 :                :              */
 1243                           166                 :           1398 :             vars = pull_var_clause((Node *)
                                167                 :           1398 :                                    list_concat_copy((List *) action->qual,
                                168                 :           1398 :                                                     action->targetList),
                                169                 :                :                                    PVC_INCLUDE_PLACEHOLDERS);
                                170   [ +  +  +  +  :           3174 :             foreach(l2, vars)
                                              +  + ]
                                171                 :                :             {
                                172                 :           1776 :                 Var        *var = (Var *) lfirst(l2);
                                173                 :                :                 TargetEntry *tle;
                                174                 :                : 
                                175   [ +  +  +  + ]:           1776 :                 if (IsA(var, Var) && var->varno == result_relation)
                                176                 :            877 :                     continue;   /* don't need it */
                                177                 :                : 
                                178         [ +  + ]:            899 :                 if (tlist_member((Expr *) var, tlist))
                                179                 :            241 :                     continue;   /* already got it */
                                180                 :                : 
                                181                 :            658 :                 tle = makeTargetEntry((Expr *) var,
                                182                 :            658 :                                       list_length(tlist) + 1,
                                183                 :                :                                       NULL, true);
                                184                 :            658 :                 tlist = lappend(tlist, tle);
                                185                 :                :             }
                                186                 :           1398 :             list_free(vars);
                                187                 :                :         }
                                188                 :                : 
                                189                 :                :         /*
                                190                 :                :          * Add resjunk entries for any Vars and PlaceHolderVars used in the
                                191                 :                :          * join condition that belong to relations other than the target.  We
                                192                 :                :          * don't expect to see any aggregates or window functions here.
                                193                 :                :          */
  525 dean.a.rasheed@gmail      194                 :            894 :         vars = pull_var_clause(parse->mergeJoinCondition,
                                195                 :                :                                PVC_INCLUDE_PLACEHOLDERS);
                                196   [ +  +  +  +  :           1089 :         foreach(l, vars)
                                              +  + ]
                                197                 :                :         {
                                198                 :            195 :             Var        *var = (Var *) lfirst(l);
                                199                 :                :             TargetEntry *tle;
                                200                 :                : 
                                201   [ +  +  +  + ]:            195 :             if (IsA(var, Var) && var->varno == result_relation)
                                202                 :             66 :                 continue;       /* don't need it */
                                203                 :                : 
                                204         [ +  + ]:            129 :             if (tlist_member((Expr *) var, tlist))
                                205                 :             51 :                 continue;       /* already got it */
                                206                 :                : 
                                207                 :             78 :             tle = makeTargetEntry((Expr *) var,
                                208                 :             78 :                                   list_length(tlist) + 1,
                                209                 :                :                                   NULL, true);
                                210                 :             78 :             tlist = lappend(tlist, tle);
                                211                 :                :         }
                                212                 :                :     }
                                213                 :                : 
                                214                 :                :     /*
                                215                 :                :      * Add necessary junk columns for rowmarked rels.  These values are needed
                                216                 :                :      * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
                                217                 :                :      * rechecking.  See comments for PlanRowMark in plannodes.h.  If you
                                218                 :                :      * change this stanza, see also expand_inherited_rtentry(), which has to
                                219                 :                :      * be able to add on junk columns equivalent to these.
                                220                 :                :      *
                                221                 :                :      * (Someday it might be useful to fold these resjunk columns into the
                                222                 :                :      * row-identity-column management used for UPDATE/DELETE.  Today is not
                                223                 :                :      * that day, however.  One notable issue is that it seems important that
                                224                 :                :      * the whole-row Vars made here use the real table rowtype, not RECORD, so
                                225                 :                :      * that conversion to/from child relations' rowtypes will happen.  Also,
                                226                 :                :      * since these entries don't potentially bloat with more and more child
                                227                 :                :      * relations, there's not really much need for column sharing.)
                                228                 :                :      */
 5794 tgl@sss.pgh.pa.us         229   [ +  +  +  +  :         258729 :     foreach(lc, root->rowMarks)
                                              +  + ]
                                230                 :                :     {
                                231                 :           5376 :         PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
                                232                 :                :         Var        *var;
                                233                 :                :         char        resname[32];
                                234                 :                :         TargetEntry *tle;
                                235                 :                : 
                                236                 :                :         /* child rels use the same junk attrs as their parents */
                                237         [ -  + ]:           5376 :         if (rc->rti != rc->prti)
 5794 tgl@sss.pgh.pa.us         238                 :UBC           0 :             continue;
                                239                 :                : 
 3828 tgl@sss.pgh.pa.us         240         [ +  + ]:CBC        5376 :         if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
                                241                 :                :         {
                                242                 :                :             /* Need to fetch TID */
 7069                           243                 :           5011 :             var = makeVar(rc->rti,
                                244                 :                :                           SelfItemPointerAttributeNumber,
                                245                 :                :                           TIDOID,
                                246                 :                :                           -1,
                                247                 :                :                           InvalidOid,
                                248                 :                :                           0);
 5323                           249                 :           5011 :             snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
 7458                           250                 :           5011 :             tle = makeTargetEntry((Expr *) var,
                                251                 :           5011 :                                   list_length(tlist) + 1,
                                252                 :                :                                   pstrdup(resname),
                                253                 :                :                                   true);
                                254                 :           5011 :             tlist = lappend(tlist, tle);
                                255                 :                :         }
 3828                           256         [ +  + ]:           5376 :         if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
                                257                 :                :         {
                                258                 :                :             /* Need the whole row as a junk var */
 5436                           259                 :            365 :             var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
                                260                 :            365 :                                   rc->rti,
                                261                 :                :                                   0,
                                262                 :                :                                   false);
 5323                           263                 :            365 :             snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
 5794                           264                 :            365 :             tle = makeTargetEntry((Expr *) var,
                                265                 :            365 :                                   list_length(tlist) + 1,
                                266                 :                :                                   pstrdup(resname),
                                267                 :                :                                   true);
                                268                 :            365 :             tlist = lappend(tlist, tle);
                                269                 :                :         }
                                270                 :                : 
                                271                 :                :         /* If parent of inheritance tree, always fetch the tableoid too. */
 3790 sfrost@snowman.net        272         [ -  + ]:           5376 :         if (rc->isParent)
                                273                 :                :         {
 3790 sfrost@snowman.net        274                 :UBC           0 :             var = makeVar(rc->rti,
                                275                 :                :                           TableOidAttributeNumber,
                                276                 :                :                           OIDOID,
                                277                 :                :                           -1,
                                278                 :                :                           InvalidOid,
                                279                 :                :                           0);
                                280                 :              0 :             snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
                                281                 :              0 :             tle = makeTargetEntry((Expr *) var,
                                282                 :              0 :                                   list_length(tlist) + 1,
                                283                 :                :                                   pstrdup(resname),
                                284                 :                :                                   true);
                                285                 :              0 :             tlist = lappend(tlist, tle);
                                286                 :                :         }
                                287                 :                :     }
                                288                 :                : 
                                289                 :                :     /*
                                290                 :                :      * If the query has a RETURNING list, add resjunk entries for any Vars
                                291                 :                :      * used in RETURNING that belong to other relations.  We need to do this
                                292                 :                :      * to make these Vars available for the RETURNING calculation.  Vars that
                                293                 :                :      * belong to the result rel don't need to be added, because they will be
                                294                 :                :      * made to refer to the actual heap tuple.
                                295                 :                :      */
 6965 tgl@sss.pgh.pa.us         296   [ +  +  +  + ]:CBC      253353 :     if (parse->returningList && list_length(parse->rtable) > 1)
                                297                 :                :     {
                                298                 :                :         List       *vars;
                                299                 :                :         ListCell   *l;
                                300                 :                : 
 5984                           301                 :            888 :         vars = pull_var_clause((Node *) parse->returningList,
                                302                 :                :                                PVC_RECURSE_AGGREGATES |
                                303                 :                :                                PVC_RECURSE_WINDOWFUNCS |
                                304                 :                :                                PVC_INCLUDE_PLACEHOLDERS);
 6965                           305   [ +  +  +  +  :           4069 :         foreach(l, vars)
                                              +  + ]
                                306                 :                :         {
                                307                 :           3181 :             Var        *var = (Var *) lfirst(l);
                                308                 :                :             TargetEntry *tle;
                                309                 :                : 
 6164                           310         [ +  - ]:           3181 :             if (IsA(var, Var) &&
                                311         [ +  + ]:           3181 :                 var->varno == result_relation)
 6965                           312                 :           2869 :                 continue;       /* don't need it */
                                313                 :                : 
 3103 peter_e@gmx.net           314         [ +  + ]:            312 :             if (tlist_member((Expr *) var, tlist))
 6965 tgl@sss.pgh.pa.us         315                 :            118 :                 continue;       /* already got it */
                                316                 :                : 
                                317                 :            194 :             tle = makeTargetEntry((Expr *) var,
                                318                 :            194 :                                   list_length(tlist) + 1,
                                319                 :                :                                   NULL,
                                320                 :                :                                   true);
                                321                 :                : 
                                322                 :            194 :             tlist = lappend(tlist, tle);
                                323                 :                :         }
                                324                 :            888 :         list_free(vars);
                                325                 :                :     }
                                326                 :                : 
 1620                           327                 :         253353 :     root->processed_tlist = tlist;
                                328                 :                : 
 2840                           329         [ +  + ]:         253353 :     if (target_relation)
 2420 andres@anarazel.de        330                 :          43081 :         table_close(target_relation, NoLock);
 1620 tgl@sss.pgh.pa.us         331                 :         253353 : }
                                332                 :                : 
                                333                 :                : /*
                                334                 :                :  * extract_update_targetlist_colnos
                                335                 :                :  *      Extract a list of the target-table column numbers that
                                336                 :                :  *      an UPDATE's targetlist wants to assign to, then renumber.
                                337                 :                :  *
                                338                 :                :  * The convention in the parser and rewriter is that the resnos in an
                                339                 :                :  * UPDATE's non-resjunk TLE entries are the target column numbers
                                340                 :                :  * to assign to.  Here, we extract that info into a separate list, and
                                341                 :                :  * then convert the tlist to the sequential-numbering convention that's
                                342                 :                :  * used by all other query types.
                                343                 :                :  *
                                344                 :                :  * This is also applied to the tlist associated with INSERT ... ON CONFLICT
                                345                 :                :  * ... UPDATE, although not till much later in planning.
                                346                 :                :  */
                                347                 :                : List *
 1580                           348                 :           8548 : extract_update_targetlist_colnos(List *tlist)
                                349                 :                : {
 1620                           350                 :           8548 :     List       *update_colnos = NIL;
                                351                 :           8548 :     AttrNumber  nextresno = 1;
                                352                 :                :     ListCell   *lc;
                                353                 :                : 
                                354   [ +  +  +  +  :          19208 :     foreach(lc, tlist)
                                              +  + ]
                                355                 :                :     {
                                356                 :          10660 :         TargetEntry *tle = (TargetEntry *) lfirst(lc);
                                357                 :                : 
                                358         [ +  + ]:          10660 :         if (!tle->resjunk)
                                359                 :          10516 :             update_colnos = lappend_int(update_colnos, tle->resno);
                                360                 :          10660 :         tle->resno = nextresno++;
                                361                 :                :     }
                                362                 :           8548 :     return update_colnos;
                                363                 :                : }
                                364                 :                : 
                                365                 :                : 
                                366                 :                : /*****************************************************************************
                                367                 :                :  *
                                368                 :                :  *      TARGETLIST EXPANSION
                                369                 :                :  *
                                370                 :                :  *****************************************************************************/
                                371                 :                : 
                                372                 :                : /*
                                373                 :                :  * expand_insert_targetlist
                                374                 :                :  *    Given a target list as generated by the parser and a result relation,
                                375                 :                :  *    add targetlist entries for any missing attributes, and ensure the
                                376                 :                :  *    non-junk attributes appear in proper field order.
                                377                 :                :  *
                                378                 :                :  * Once upon a time we also did more or less this with UPDATE targetlists,
                                379                 :                :  * but now this code is only applied to INSERT targetlists.
                                380                 :                :  */
                                381                 :                : static List *
  220                           382                 :          33529 : expand_insert_targetlist(PlannerInfo *root, List *tlist, Relation rel)
                                383                 :                : {
 9443                           384                 :          33529 :     List       *new_tlist = NIL;
                                385                 :                :     ListCell   *tlist_item;
                                386                 :                :     int         attrno,
                                387                 :                :                 numattrs;
                                388                 :                : 
 7773 neilc@samurai.com         389                 :          33529 :     tlist_item = list_head(tlist);
                                390                 :                : 
                                391                 :                :     /*
                                392                 :                :      * The rewriter should have already ensured that the TLEs are in correct
                                393                 :                :      * order; but we have to insert TLEs for any missing attributes.
                                394                 :                :      *
                                395                 :                :      * Scan the tuple description in the relation's relcache entry to make
                                396                 :                :      * sure we have all the user attributes in the right order.
                                397                 :                :      */
 9443 tgl@sss.pgh.pa.us         398                 :          33529 :     numattrs = RelationGetNumberOfAttributes(rel);
                                399                 :                : 
                                400         [ +  + ]:         110056 :     for (attrno = 1; attrno <= numattrs; attrno++)
                                401                 :                :     {
 2939 andres@anarazel.de        402                 :          76527 :         Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1);
 9278 bruce@momjian.us          403                 :          76527 :         TargetEntry *new_tle = NULL;
                                404                 :                : 
 7773 neilc@samurai.com         405         [ +  + ]:          76527 :         if (tlist_item != NULL)
                                406                 :                :         {
                                407                 :          71356 :             TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
                                408                 :                : 
 7458 tgl@sss.pgh.pa.us         409   [ +  -  +  + ]:          71356 :             if (!old_tle->resjunk && old_tle->resno == attrno)
                                410                 :                :             {
 8555                           411                 :          66873 :                 new_tle = old_tle;
 2245                           412                 :          66873 :                 tlist_item = lnext(tlist, tlist_item);
                                413                 :                :             }
                                414                 :                :         }
                                415                 :                : 
 9443                           416         [ +  + ]:          76527 :         if (new_tle == NULL)
                                417                 :                :         {
                                418                 :                :             /*
                                419                 :                :              * Didn't find a matching tlist entry, so make one.
                                420                 :                :              *
                                421                 :                :              * INSERTs should insert NULL in this case.  (We assume the
                                422                 :                :              * rewriter would have inserted any available non-NULL default
                                423                 :                :              * value.)  Also, normally we must apply any domain constraints
                                424                 :                :              * that might exist --- this is to catch domain NOT NULL.
                                425                 :                :              *
                                426                 :                :              * When generating a NULL constant for a dropped column, we label
                                427                 :                :              * it INT4 (any other guaranteed-to-exist datatype would do as
                                428                 :                :              * well). We can't label it with the dropped column's datatype
                                429                 :                :              * since that might not exist anymore.  It does not really matter
                                430                 :                :              * what we claim the type is, since NULL is NULL --- its
                                431                 :                :              * representation is datatype-independent.  This could perhaps
                                432                 :                :              * confuse code comparing the finished plan to the target
                                433                 :                :              * relation, however.
                                434                 :                :              *
                                435                 :                :              * Another exception is that if the column is generated, the value
                                436                 :                :              * we produce here will be ignored, and we don't want to risk
                                437                 :                :              * throwing an error.  So in that case we *don't* want to apply
                                438                 :                :              * domain constraints, so we must produce a NULL of the base type.
                                439                 :                :              * Again, code comparing the finished plan to the target relation
                                440                 :                :              * must account for this.
                                441                 :                :              */
                                442                 :                :             Node       *new_expr;
                                443                 :                : 
  144                           444         [ +  + ]:           9654 :             if (att_tup->attisdropped)
                                445                 :                :             {
                                446                 :                :                 /* Insert NULL for dropped column */
 1578                           447                 :            314 :                 new_expr = (Node *) makeConst(INT4OID,
                                448                 :                :                                               -1,
                                449                 :                :                                               InvalidOid,
                                450                 :                :                                               sizeof(int32),
                                451                 :                :                                               (Datum) 0,
                                452                 :                :                                               true, /* isnull */
                                453                 :                :                                               true /* byval */ );
                                454                 :                :             }
  144                           455         [ +  + ]:           9340 :             else if (att_tup->attgenerated)
                                456                 :                :             {
                                457                 :                :                 /* Generated column, insert a NULL of the base type */
                                458                 :            559 :                 Oid         baseTypeId = att_tup->atttypid;
                                459                 :            559 :                 int32       baseTypeMod = att_tup->atttypmod;
                                460                 :                : 
                                461                 :            559 :                 baseTypeId = getBaseTypeAndTypmod(baseTypeId, &baseTypeMod);
                                462                 :            559 :                 new_expr = (Node *) makeConst(baseTypeId,
                                463                 :                :                                               baseTypeMod,
                                464                 :                :                                               att_tup->attcollation,
                                465                 :            559 :                                               att_tup->attlen,
                                466                 :                :                                               (Datum) 0,
                                467                 :                :                                               true, /* isnull */
                                468                 :            559 :                                               att_tup->attbyval);
                                469                 :                :             }
                                470                 :                :             else
                                471                 :                :             {
                                472                 :                :                 /* Normal column, insert a NULL of the column datatype */
                                473                 :           8781 :                 new_expr = coerce_null_to_domain(att_tup->atttypid,
                                474                 :                :                                                  att_tup->atttypmod,
                                475                 :                :                                                  att_tup->attcollation,
                                476                 :           8781 :                                                  att_tup->attlen,
                                477                 :           8781 :                                                  att_tup->attbyval);
                                478                 :                :                 /* Must run expression preprocessing on any non-const nodes */
                                479         [ +  + ]:           8781 :                 if (!IsA(new_expr, Const))
                                480                 :             33 :                     new_expr = eval_const_expressions(root, new_expr);
                                481                 :                :             }
                                482                 :                : 
 7458                           483                 :           9654 :             new_tle = makeTargetEntry((Expr *) new_expr,
                                484                 :                :                                       attrno,
 8403 bruce@momjian.us          485                 :           9654 :                                       pstrdup(NameStr(att_tup->attname)),
                                486                 :                :                                       false);
                                487                 :                :         }
                                488                 :                : 
 9443 tgl@sss.pgh.pa.us         489                 :          76527 :         new_tlist = lappend(new_tlist, new_tle);
                                490                 :                :     }
                                491                 :                : 
                                492                 :                :     /*
                                493                 :                :      * The remaining tlist entries should be resjunk; append them all to the
                                494                 :                :      * end of the new tlist, making sure they have resnos higher than the last
                                495                 :                :      * real attribute.  (Note: although the rewriter already did such
                                496                 :                :      * renumbering, we have to do it again here in case we added NULL entries
                                497                 :                :      * above.)
                                498                 :                :      */
 7773 neilc@samurai.com         499         [ -  + ]:          33529 :     while (tlist_item)
                                500                 :                :     {
 7773 neilc@samurai.com         501                 :UBC           0 :         TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
                                502                 :                : 
 7458 tgl@sss.pgh.pa.us         503         [ #  # ]:              0 :         if (!old_tle->resjunk)
 8079                           504         [ #  # ]:              0 :             elog(ERROR, "targetlist is not sorted correctly");
                                505                 :                :         /* Get the resno right, but don't copy unnecessarily */
 7458                           506         [ #  # ]:              0 :         if (old_tle->resno != attrno)
                                507                 :                :         {
                                508                 :              0 :             old_tle = flatCopyTargetEntry(old_tle);
                                509                 :              0 :             old_tle->resno = attrno;
                                510                 :                :         }
 8555                           511                 :              0 :         new_tlist = lappend(new_tlist, old_tle);
                                512                 :              0 :         attrno++;
 2245                           513                 :              0 :         tlist_item = lnext(tlist, tlist_item);
                                514                 :                :     }
                                515                 :                : 
 9443 tgl@sss.pgh.pa.us         516                 :CBC       33529 :     return new_tlist;
                                517                 :                : }
                                518                 :                : 
                                519                 :                : 
                                520                 :                : /*
                                521                 :                :  * Locate PlanRowMark for given RT index, or return NULL if none
                                522                 :                :  *
                                523                 :                :  * This probably ought to be elsewhere, but there's no very good place
                                524                 :                :  */
                                525                 :                : PlanRowMark *
 5794                           526                 :          11646 : get_plan_rowmark(List *rowmarks, Index rtindex)
                                527                 :                : {
                                528                 :                :     ListCell   *l;
                                529                 :                : 
                                530   [ +  +  +  +  :          12404 :     foreach(l, rowmarks)
                                              +  + ]
                                531                 :                :     {
                                532                 :           1929 :         PlanRowMark *rc = (PlanRowMark *) lfirst(l);
                                533                 :                : 
                                534         [ +  + ]:           1929 :         if (rc->rti == rtindex)
                                535                 :           1171 :             return rc;
                                536                 :                :     }
                                537                 :          10475 :     return NULL;
                                538                 :                : }
        

Generated by: LCOV version 2.4-beta