LCOV - differential code coverage report
Current view: top level - src/backend/optimizer/prep - preptlist.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 88.1 % 135 119 16 119
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 4 4 4
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 88.1 % 135 119 16 119
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 100.0 % 4 4 4

 Age         Owner                  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-2023, 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/rel.h"
                                 48                 : 
                                 49                 : static List *expand_insert_targetlist(List *tlist, Relation rel);
                                 50                 : 
                                 51                 : 
                                 52                 : /*
                                 53                 :  * preprocess_targetlist
                                 54                 :  *    Driver for preprocessing the parse tree targetlist.
                                 55                 :  *
                                 56                 :  * The preprocessed targetlist is returned in root->processed_tlist.
                                 57                 :  * Also, if this is an UPDATE, we return a list of target column numbers
                                 58                 :  * in root->update_colnos.  (Resnos in processed_tlist will be consecutive,
                                 59                 :  * so do not look at that to find out which columns are targets!)
                                 60                 :  */
                                 61                 : void
 1959 tgl                        62 CBC      222898 : preprocess_targetlist(PlannerInfo *root)
                                 63                 : {
 6385 bruce                      64          222898 :     Query      *parse = root->parse;
                                 65          222898 :     int         result_relation = parse->resultRelation;
                                 66          222898 :     List       *range_table = parse->rtable;
                                 67          222898 :     CmdType     command_type = parse->commandType;
 1959 tgl                        68          222898 :     RangeTblEntry *target_rte = NULL;
                                 69          222898 :     Relation    target_relation = NULL;
                                 70                 :     List       *tlist;
                                 71                 :     ListCell   *lc;
                                 72                 : 
                                 73                 :     /*
                                 74                 :      * If there is a result relation, open it so we can look for missing
                                 75                 :      * columns and so on.  We assume that previous code already acquired at
                                 76                 :      * least AccessShareLock on the relation, so we need no lock here.
                                 77                 :      */
 8221                            78          222898 :     if (result_relation)
                                 79                 :     {
 1959                            80           52265 :         target_rte = rt_fetch(result_relation, range_table);
                                 81                 : 
                                 82                 :         /*
                                 83                 :          * Sanity check: it'd better be a real relation not, say, a subquery.
                                 84                 :          * Else parser or rewriter messed up.
                                 85                 :          */
                                 86           52265 :         if (target_rte->rtekind != RTE_RELATION)
 1959 tgl                        87 UBC           0 :             elog(ERROR, "result relation must be a regular relation");
                                 88                 : 
 1539 andres                     89 CBC       52265 :         target_relation = table_open(target_rte->relid, NoLock);
                                 90                 :     }
                                 91                 :     else
 1959 tgl                        92          170633 :         Assert(command_type == CMD_SELECT);
                                 93                 : 
                                 94                 :     /*
                                 95                 :      * In an INSERT, the executor expects the targetlist to match the exact
                                 96                 :      * order of the target table's attributes, including entries for
                                 97                 :      * attributes not mentioned in the source query.
                                 98                 :      *
                                 99                 :      * In an UPDATE, we don't rearrange the tlist order, but we need to make a
                                100                 :      * separate list of the target attribute numbers, in tlist order, and then
                                101                 :      * renumber the processed_tlist entries to be consecutive.
                                102                 :      */
                                103          222898 :     tlist = parse->targetList;
  739                           104          222898 :     if (command_type == CMD_INSERT)
  699                           105           42251 :         tlist = expand_insert_targetlist(tlist, target_relation);
  739                           106          180647 :     else if (command_type == CMD_UPDATE)
  699                           107            7582 :         root->update_colnos = extract_update_targetlist_colnos(tlist);
                                108                 : 
                                109                 :     /*
                                110                 :      * For non-inherited UPDATE/DELETE/MERGE, register any junk column(s)
                                111                 :      * needed to allow the executor to identify the rows to be updated or
                                112                 :      * deleted.  In the inheritance case, we do nothing now, leaving this to
                                113                 :      * be dealt with when expand_inherited_rtentry() makes the leaf target
                                114                 :      * relations.  (But there might not be any leaf target relations, in which
                                115                 :      * case we must do this in distribute_row_identity_vars().)
                                116                 :      */
  362 alvherre                  117          222898 :     if ((command_type == CMD_UPDATE || command_type == CMD_DELETE ||
                                118           10014 :          command_type == CMD_MERGE) &&
  739 tgl                       119           10014 :         !target_rte->inh)
                                120                 :     {
                                121                 :         /* row-identity logic expects to add stuff to processed_tlist */
                                122            8848 :         root->processed_tlist = tlist;
                                123            8848 :         add_row_identity_columns(root, result_relation,
                                124                 :                                  target_rte, target_relation);
                                125            8848 :         tlist = root->processed_tlist;
                                126                 :     }
                                127                 : 
                                128                 :     /*
                                129                 :      * For MERGE we also need to handle the target list for each INSERT and
                                130                 :      * UPDATE action separately.  In addition, we examine the qual of each
                                131                 :      * action and add any Vars there (other than those of the target rel) to
                                132                 :      * the subplan targetlist.
                                133                 :      */
  377 alvherre                  134          222898 :     if (command_type == CMD_MERGE)
                                135                 :     {
                                136                 :         ListCell   *l;
                                137                 : 
                                138                 :         /*
                                139                 :          * For MERGE, handle targetlist of each MergeAction separately. Give
                                140                 :          * the same treatment to MergeAction->targetList as we would have
                                141                 :          * given to a regular INSERT.  For UPDATE, collect the column numbers
                                142                 :          * being modified.
                                143                 :          */
                                144            1176 :         foreach(l, parse->mergeActionList)
                                145                 :         {
                                146             711 :             MergeAction *action = (MergeAction *) lfirst(l);
                                147                 :             List       *vars;
                                148                 :             ListCell   *l2;
                                149                 : 
                                150             711 :             if (action->commandType == CMD_INSERT)
                                151             277 :                 action->targetList = expand_insert_targetlist(action->targetList,
                                152                 :                                                               target_relation);
                                153             434 :             else if (action->commandType == CMD_UPDATE)
                                154             322 :                 action->updateColnos =
                                155             322 :                     extract_update_targetlist_colnos(action->targetList);
                                156                 : 
                                157                 :             /*
                                158                 :              * Add resjunk entries for any Vars and PlaceHolderVars used in
                                159                 :              * each action's targetlist and WHEN condition that belong to
                                160                 :              * relations other than the target.  We don't expect to see any
                                161                 :              * aggregates or window functions here.
                                162                 :              */
  362                           163             711 :             vars = pull_var_clause((Node *)
                                164             711 :                                    list_concat_copy((List *) action->qual,
                                165             711 :                                                     action->targetList),
                                166                 :                                    PVC_INCLUDE_PLACEHOLDERS);
                                167            1705 :             foreach(l2, vars)
                                168                 :             {
                                169             994 :                 Var        *var = (Var *) lfirst(l2);
                                170                 :                 TargetEntry *tle;
                                171                 : 
                                172             994 :                 if (IsA(var, Var) && var->varno == result_relation)
                                173             452 :                     continue;   /* don't need it */
                                174                 : 
                                175             542 :                 if (tlist_member((Expr *) var, tlist))
                                176             128 :                     continue;   /* already got it */
                                177                 : 
                                178             414 :                 tle = makeTargetEntry((Expr *) var,
                                179             414 :                                       list_length(tlist) + 1,
                                180                 :                                       NULL, true);
                                181             414 :                 tlist = lappend(tlist, tle);
                                182                 :             }
                                183             711 :             list_free(vars);
                                184                 :         }
                                185                 :     }
                                186                 : 
                                187                 :     /*
                                188                 :      * Add necessary junk columns for rowmarked rels.  These values are needed
                                189                 :      * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
                                190                 :      * rechecking.  See comments for PlanRowMark in plannodes.h.  If you
                                191                 :      * change this stanza, see also expand_inherited_rtentry(), which has to
                                192                 :      * be able to add on junk columns equivalent to these.
                                193                 :      *
                                194                 :      * (Someday it might be useful to fold these resjunk columns into the
                                195                 :      * row-identity-column management used for UPDATE/DELETE.  Today is not
                                196                 :      * that day, however.  One notable issue is that it seems important that
                                197                 :      * the whole-row Vars made here use the real table rowtype, not RECORD, so
                                198                 :      * that conversion to/from child relations' rowtypes will happen.  Also,
                                199                 :      * since these entries don't potentially bloat with more and more child
                                200                 :      * relations, there's not really much need for column sharing.)
                                201                 :      */
 4913 tgl                       202          227068 :     foreach(lc, root->rowMarks)
                                203                 :     {
                                204            4170 :         PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
                                205                 :         Var        *var;
                                206                 :         char        resname[32];
                                207                 :         TargetEntry *tle;
                                208                 : 
                                209                 :         /* child rels use the same junk attrs as their parents */
                                210            4170 :         if (rc->rti != rc->prti)
 4913 tgl                       211 UBC           0 :             continue;
                                212                 : 
 2947 tgl                       213 CBC        4170 :         if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
                                214                 :         {
                                215                 :             /* Need to fetch TID */
 6188                           216            3991 :             var = makeVar(rc->rti,
                                217                 :                           SelfItemPointerAttributeNumber,
                                218                 :                           TIDOID,
                                219                 :                           -1,
                                220                 :                           InvalidOid,
                                221                 :                           0);
 4442                           222            3991 :             snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
 6577                           223            3991 :             tle = makeTargetEntry((Expr *) var,
                                224            3991 :                                   list_length(tlist) + 1,
                                225                 :                                   pstrdup(resname),
                                226                 :                                   true);
                                227            3991 :             tlist = lappend(tlist, tle);
                                228                 :         }
 2947                           229            4170 :         if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
                                230                 :         {
                                231                 :             /* Need the whole row as a junk var */
 4555                           232             179 :             var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
                                233             179 :                                   rc->rti,
                                234                 :                                   0,
                                235                 :                                   false);
 4442                           236             179 :             snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
 4913                           237             179 :             tle = makeTargetEntry((Expr *) var,
                                238             179 :                                   list_length(tlist) + 1,
                                239                 :                                   pstrdup(resname),
                                240                 :                                   true);
                                241             179 :             tlist = lappend(tlist, tle);
                                242                 :         }
                                243                 : 
                                244                 :         /* If parent of inheritance tree, always fetch the tableoid too. */
 2909 sfrost                    245            4170 :         if (rc->isParent)
                                246                 :         {
 2909 sfrost                    247 UBC           0 :             var = makeVar(rc->rti,
                                248                 :                           TableOidAttributeNumber,
                                249                 :                           OIDOID,
                                250                 :                           -1,
                                251                 :                           InvalidOid,
                                252                 :                           0);
                                253               0 :             snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
                                254               0 :             tle = makeTargetEntry((Expr *) var,
                                255               0 :                                   list_length(tlist) + 1,
                                256                 :                                   pstrdup(resname),
                                257                 :                                   true);
                                258               0 :             tlist = lappend(tlist, tle);
                                259                 :         }
                                260                 :     }
                                261                 : 
                                262                 :     /*
                                263                 :      * If the query has a RETURNING list, add resjunk entries for any Vars
                                264                 :      * used in RETURNING that belong to other relations.  We need to do this
                                265                 :      * to make these Vars available for the RETURNING calculation.  Vars that
                                266                 :      * belong to the result rel don't need to be added, because they will be
                                267                 :      * made to refer to the actual heap tuple.
                                268                 :      */
 6084 tgl                       269 CBC      222898 :     if (parse->returningList && list_length(parse->rtable) > 1)
                                270                 :     {
                                271                 :         List       *vars;
                                272                 :         ListCell   *l;
                                273                 : 
 5103                           274             667 :         vars = pull_var_clause((Node *) parse->returningList,
                                275                 :                                PVC_RECURSE_AGGREGATES |
                                276                 :                                PVC_RECURSE_WINDOWFUNCS |
                                277                 :                                PVC_INCLUDE_PLACEHOLDERS);
 6084                           278            2444 :         foreach(l, vars)
                                279                 :         {
                                280            1777 :             Var        *var = (Var *) lfirst(l);
                                281                 :             TargetEntry *tle;
                                282                 : 
 5283                           283            1777 :             if (IsA(var, Var) &&
                                284            1777 :                 var->varno == result_relation)
 6084                           285            1596 :                 continue;       /* don't need it */
                                286                 : 
 2222 peter_e                   287             181 :             if (tlist_member((Expr *) var, tlist))
 6084 tgl                       288              29 :                 continue;       /* already got it */
                                289                 : 
                                290             152 :             tle = makeTargetEntry((Expr *) var,
                                291             152 :                                   list_length(tlist) + 1,
                                292                 :                                   NULL,
                                293                 :                                   true);
                                294                 : 
                                295             152 :             tlist = lappend(tlist, tle);
                                296                 :         }
                                297             667 :         list_free(vars);
                                298                 :     }
                                299                 : 
  739                           300          222898 :     root->processed_tlist = tlist;
                                301                 : 
 1959                           302          222898 :     if (target_relation)
 1539 andres                    303           52265 :         table_close(target_relation, NoLock);
  739 tgl                       304          222898 : }
                                305                 : 
                                306                 : /*
                                307                 :  * extract_update_targetlist_colnos
                                308                 :  *      Extract a list of the target-table column numbers that
                                309                 :  *      an UPDATE's targetlist wants to assign to, then renumber.
                                310                 :  *
                                311                 :  * The convention in the parser and rewriter is that the resnos in an
                                312                 :  * UPDATE's non-resjunk TLE entries are the target column numbers
                                313                 :  * to assign to.  Here, we extract that info into a separate list, and
                                314                 :  * then convert the tlist to the sequential-numbering convention that's
                                315                 :  * used by all other query types.
                                316                 :  *
                                317                 :  * This is also applied to the tlist associated with INSERT ... ON CONFLICT
                                318                 :  * ... UPDATE, although not till much later in planning.
                                319                 :  */
                                320                 : List *
  699                           321            8619 : extract_update_targetlist_colnos(List *tlist)
                                322                 : {
  739                           323            8619 :     List       *update_colnos = NIL;
                                324            8619 :     AttrNumber  nextresno = 1;
                                325                 :     ListCell   *lc;
                                326                 : 
                                327           19341 :     foreach(lc, tlist)
                                328                 :     {
                                329           10722 :         TargetEntry *tle = (TargetEntry *) lfirst(lc);
                                330                 : 
                                331           10722 :         if (!tle->resjunk)
                                332           10590 :             update_colnos = lappend_int(update_colnos, tle->resno);
                                333           10722 :         tle->resno = nextresno++;
                                334                 :     }
                                335            8619 :     return update_colnos;
                                336                 : }
                                337                 : 
                                338                 : 
                                339                 : /*****************************************************************************
                                340                 :  *
                                341                 :  *      TARGETLIST EXPANSION
                                342                 :  *
                                343                 :  *****************************************************************************/
                                344                 : 
                                345                 : /*
                                346                 :  * expand_insert_targetlist
                                347                 :  *    Given a target list as generated by the parser and a result relation,
                                348                 :  *    add targetlist entries for any missing attributes, and ensure the
                                349                 :  *    non-junk attributes appear in proper field order.
                                350                 :  *
                                351                 :  * Once upon a time we also did more or less this with UPDATE targetlists,
                                352                 :  * but now this code is only applied to INSERT targetlists.
                                353                 :  */
                                354                 : static List *
  699                           355           42528 : expand_insert_targetlist(List *tlist, Relation rel)
                                356                 : {
 8562                           357           42528 :     List       *new_tlist = NIL;
                                358                 :     ListCell   *tlist_item;
                                359                 :     int         attrno,
                                360                 :                 numattrs;
                                361                 : 
 6892 neilc                     362           42528 :     tlist_item = list_head(tlist);
                                363                 : 
                                364                 :     /*
                                365                 :      * The rewriter should have already ensured that the TLEs are in correct
                                366                 :      * order; but we have to insert TLEs for any missing attributes.
                                367                 :      *
                                368                 :      * Scan the tuple description in the relation's relcache entry to make
                                369                 :      * sure we have all the user attributes in the right order.
                                370                 :      */
 8562 tgl                       371           42528 :     numattrs = RelationGetNumberOfAttributes(rel);
                                372                 : 
                                373          182926 :     for (attrno = 1; attrno <= numattrs; attrno++)
                                374                 :     {
 2058 andres                    375          140398 :         Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1);
 8397 bruce                     376          140398 :         TargetEntry *new_tle = NULL;
                                377                 : 
 6892 neilc                     378          140398 :         if (tlist_item != NULL)
                                379                 :         {
                                380          135647 :             TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
                                381                 : 
 6577 tgl                       382          135647 :             if (!old_tle->resjunk && old_tle->resno == attrno)
                                383                 :             {
 7674                           384          131206 :                 new_tle = old_tle;
 1364                           385          131206 :                 tlist_item = lnext(tlist, tlist_item);
                                386                 :             }
                                387                 :         }
                                388                 : 
 8562                           389          140398 :         if (new_tle == NULL)
                                390                 :         {
                                391                 :             /*
                                392                 :              * Didn't find a matching tlist entry, so make one.
                                393                 :              *
                                394                 :              * INSERTs should insert NULL in this case.  (We assume the
                                395                 :              * rewriter would have inserted any available non-NULL default
                                396                 :              * value.)  Also, if the column isn't dropped, apply any domain
                                397                 :              * constraints that might exist --- this is to catch domain NOT
                                398                 :              * NULL.
                                399                 :              *
                                400                 :              * When generating a NULL constant for a dropped column, we label
                                401                 :              * it INT4 (any other guaranteed-to-exist datatype would do as
                                402                 :              * well). We can't label it with the dropped column's datatype
                                403                 :              * since that might not exist anymore.  It does not really matter
                                404                 :              * what we claim the type is, since NULL is NULL --- its
                                405                 :              * representation is datatype-independent.  This could perhaps
                                406                 :              * confuse code comparing the finished plan to the target
                                407                 :              * relation, however.
                                408                 :              */
                                409            9192 :             Oid         atttype = att_tup->atttypid;
 4443 peter_e                   410            9192 :             Oid         attcollation = att_tup->attcollation;
                                411                 :             Node       *new_expr;
                                412                 : 
  697 tgl                       413            9192 :             if (!att_tup->attisdropped)
                                414                 :             {
                                415            8885 :                 new_expr = (Node *) makeConst(atttype,
                                416                 :                                               -1,
                                417                 :                                               attcollation,
                                418            8885 :                                               att_tup->attlen,
                                419                 :                                               (Datum) 0,
                                420                 :                                               true, /* isnull */
                                421            8885 :                                               att_tup->attbyval);
                                422            8885 :                 new_expr = coerce_to_domain(new_expr,
                                423                 :                                             InvalidOid, -1,
                                424                 :                                             atttype,
                                425                 :                                             COERCION_IMPLICIT,
                                426                 :                                             COERCE_IMPLICIT_CAST,
                                427                 :                                             -1,
                                428                 :                                             false);
                                429                 :             }
                                430                 :             else
                                431                 :             {
                                432                 :                 /* Insert NULL for dropped column */
                                433             307 :                 new_expr = (Node *) makeConst(INT4OID,
                                434                 :                                               -1,
                                435                 :                                               InvalidOid,
                                436                 :                                               sizeof(int32),
                                437                 :                                               (Datum) 0,
                                438                 :                                               true, /* isnull */
                                439                 :                                               true /* byval */ );
                                440                 :             }
                                441                 : 
 6577                           442            9192 :             new_tle = makeTargetEntry((Expr *) new_expr,
                                443                 :                                       attrno,
 7522 bruce                     444            9192 :                                       pstrdup(NameStr(att_tup->attname)),
                                445                 :                                       false);
                                446                 :         }
                                447                 : 
 8562 tgl                       448          140398 :         new_tlist = lappend(new_tlist, new_tle);
                                449                 :     }
                                450                 : 
                                451                 :     /*
                                452                 :      * The remaining tlist entries should be resjunk; append them all to the
                                453                 :      * end of the new tlist, making sure they have resnos higher than the last
                                454                 :      * real attribute.  (Note: although the rewriter already did such
                                455                 :      * renumbering, we have to do it again here in case we added NULL entries
                                456                 :      * above.)
                                457                 :      */
 6892 neilc                     458           42528 :     while (tlist_item)
                                459                 :     {
 6892 neilc                     460 UBC           0 :         TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
                                461                 : 
 6577 tgl                       462               0 :         if (!old_tle->resjunk)
 7198                           463               0 :             elog(ERROR, "targetlist is not sorted correctly");
                                464                 :         /* Get the resno right, but don't copy unnecessarily */
 6577                           465               0 :         if (old_tle->resno != attrno)
                                466                 :         {
                                467               0 :             old_tle = flatCopyTargetEntry(old_tle);
                                468               0 :             old_tle->resno = attrno;
                                469                 :         }
 7674                           470               0 :         new_tlist = lappend(new_tlist, old_tle);
                                471               0 :         attrno++;
 1364                           472               0 :         tlist_item = lnext(tlist, tlist_item);
                                473                 :     }
                                474                 : 
 8562 tgl                       475 CBC       42528 :     return new_tlist;
                                476                 : }
                                477                 : 
                                478                 : 
                                479                 : /*
                                480                 :  * Locate PlanRowMark for given RT index, or return NULL if none
                                481                 :  *
                                482                 :  * This probably ought to be elsewhere, but there's no very good place
                                483                 :  */
                                484                 : PlanRowMark *
 4913                           485            9630 : get_plan_rowmark(List *rowmarks, Index rtindex)
                                486                 : {
                                487                 :     ListCell   *l;
                                488                 : 
                                489           10229 :     foreach(l, rowmarks)
                                490                 :     {
                                491            1592 :         PlanRowMark *rc = (PlanRowMark *) lfirst(l);
                                492                 : 
                                493            1592 :         if (rc->rti == rtindex)
                                494             993 :             return rc;
                                495                 :     }
                                496            8637 :     return NULL;
                                497                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a