LCOV - code coverage report
Current view: top level - src/backend/parser - parse_merge.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 97.5 % 159 155
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 3 3
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 72.0 % 118 85

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * parse_merge.c
       4                 :             :  *        handle merge-statement in parser
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/backend/parser/parse_merge.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : 
      16                 :             : #include "postgres.h"
      17                 :             : 
      18                 :             : #include "access/sysattr.h"
      19                 :             : #include "nodes/makefuncs.h"
      20                 :             : #include "parser/analyze.h"
      21                 :             : #include "parser/parse_clause.h"
      22                 :             : #include "parser/parse_collate.h"
      23                 :             : #include "parser/parse_cte.h"
      24                 :             : #include "parser/parse_expr.h"
      25                 :             : #include "parser/parse_merge.h"
      26                 :             : #include "parser/parse_relation.h"
      27                 :             : #include "parser/parse_target.h"
      28                 :             : #include "parser/parsetree.h"
      29                 :             : #include "utils/rel.h"
      30                 :             : 
      31                 :             : static void setNamespaceForMergeWhen(ParseState *pstate,
      32                 :             :                                                                          MergeWhenClause *mergeWhenClause,
      33                 :             :                                                                          Index targetRTI,
      34                 :             :                                                                          Index sourceRTI);
      35                 :             : static void setNamespaceVisibilityForRTE(List *namespace, RangeTblEntry *rte,
      36                 :             :                                                                                  bool rel_visible,
      37                 :             :                                                                                  bool cols_visible);
      38                 :             : 
      39                 :             : /*
      40                 :             :  * Make appropriate changes to the namespace visibility while transforming
      41                 :             :  * individual action's quals and targetlist expressions. In particular, for
      42                 :             :  * INSERT actions we must only see the source relation (since INSERT action is
      43                 :             :  * invoked for NOT MATCHED [BY TARGET] tuples and hence there is no target
      44                 :             :  * tuple to deal with). On the other hand, UPDATE and DELETE actions can see
      45                 :             :  * both source and target relations, unless invoked for NOT MATCHED BY SOURCE.
      46                 :             :  *
      47                 :             :  * Also, since the internal join node can hide the source and target
      48                 :             :  * relations, we must explicitly make the respective relation as visible so
      49                 :             :  * that columns can be referenced unqualified from these relations.
      50                 :             :  */
      51                 :             : static void
      52                 :         458 : setNamespaceForMergeWhen(ParseState *pstate, MergeWhenClause *mergeWhenClause,
      53                 :             :                                                  Index targetRTI, Index sourceRTI)
      54                 :             : {
      55                 :         458 :         RangeTblEntry *targetRelRTE,
      56                 :             :                            *sourceRelRTE;
      57                 :             : 
      58                 :         458 :         targetRelRTE = rt_fetch(targetRTI, pstate->p_rtable);
      59                 :         458 :         sourceRelRTE = rt_fetch(sourceRTI, pstate->p_rtable);
      60                 :             : 
      61         [ +  + ]:         458 :         if (mergeWhenClause->matchKind == MERGE_WHEN_MATCHED)
      62                 :             :         {
      63   [ +  +  +  +  :         281 :                 Assert(mergeWhenClause->commandType == CMD_UPDATE ||
                   +  - ]
      64                 :             :                            mergeWhenClause->commandType == CMD_DELETE ||
      65                 :             :                            mergeWhenClause->commandType == CMD_NOTHING);
      66                 :             : 
      67                 :             :                 /* MATCHED actions can see both target and source relations. */
      68                 :         562 :                 setNamespaceVisibilityForRTE(pstate->p_namespace,
      69                 :         281 :                                                                          targetRelRTE, true, true);
      70                 :         562 :                 setNamespaceVisibilityForRTE(pstate->p_namespace,
      71                 :         281 :                                                                          sourceRelRTE, true, true);
      72                 :         281 :         }
      73         [ +  + ]:         177 :         else if (mergeWhenClause->matchKind == MERGE_WHEN_NOT_MATCHED_BY_SOURCE)
      74                 :             :         {
      75                 :             :                 /*
      76                 :             :                  * NOT MATCHED BY SOURCE actions can see the target relation, but they
      77                 :             :                  * can't see the source relation.
      78                 :             :                  */
      79   [ +  +  -  +  :          22 :                 Assert(mergeWhenClause->commandType == CMD_UPDATE ||
                   #  # ]
      80                 :             :                            mergeWhenClause->commandType == CMD_DELETE ||
      81                 :             :                            mergeWhenClause->commandType == CMD_NOTHING);
      82                 :          44 :                 setNamespaceVisibilityForRTE(pstate->p_namespace,
      83                 :          22 :                                                                          targetRelRTE, true, true);
      84                 :          44 :                 setNamespaceVisibilityForRTE(pstate->p_namespace,
      85                 :          22 :                                                                          sourceRelRTE, false, false);
      86                 :          22 :         }
      87                 :             :         else                                            /* MERGE_WHEN_NOT_MATCHED_BY_TARGET */
      88                 :             :         {
      89                 :             :                 /*
      90                 :             :                  * NOT MATCHED [BY TARGET] actions can't see target relation, but they
      91                 :             :                  * can see source relation.
      92                 :             :                  */
      93   [ +  +  +  - ]:         155 :                 Assert(mergeWhenClause->commandType == CMD_INSERT ||
      94                 :             :                            mergeWhenClause->commandType == CMD_NOTHING);
      95                 :         310 :                 setNamespaceVisibilityForRTE(pstate->p_namespace,
      96                 :         155 :                                                                          targetRelRTE, false, false);
      97                 :         310 :                 setNamespaceVisibilityForRTE(pstate->p_namespace,
      98                 :         155 :                                                                          sourceRelRTE, true, true);
      99                 :             :         }
     100                 :         458 : }
     101                 :             : 
     102                 :             : /*
     103                 :             :  * transformMergeStmt -
     104                 :             :  *        transforms a MERGE statement
     105                 :             :  */
     106                 :             : Query *
     107                 :         317 : transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
     108                 :             : {
     109                 :         317 :         Query      *qry = makeNode(Query);
     110                 :         317 :         ListCell   *l;
     111                 :         317 :         AclMode         targetPerms = ACL_NO_RIGHTS;
     112                 :         317 :         bool            is_terminal[NUM_MERGE_MATCH_KINDS];
     113                 :         317 :         Index           sourceRTI;
     114                 :         317 :         List       *mergeActionList;
     115                 :         317 :         ParseNamespaceItem *nsitem;
     116                 :             : 
     117                 :             :         /* There can't be any outer WITH to worry about */
     118         [ +  - ]:         317 :         Assert(pstate->p_ctenamespace == NIL);
     119                 :             : 
     120                 :         317 :         qry->commandType = CMD_MERGE;
     121                 :         317 :         qry->hasRecursive = false;
     122                 :             : 
     123                 :             :         /* process the WITH clause independently of all else */
     124         [ +  + ]:         317 :         if (stmt->withClause)
     125                 :             :         {
     126         [ +  + ]:           9 :                 if (stmt->withClause->recursive)
     127   [ +  -  +  - ]:           1 :                         ereport(ERROR,
     128                 :             :                                         (errcode(ERRCODE_SYNTAX_ERROR),
     129                 :             :                                          errmsg("WITH RECURSIVE is not supported for MERGE statement")));
     130                 :             : 
     131                 :           8 :                 qry->cteList = transformWithClause(pstate, stmt->withClause);
     132                 :           8 :                 qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
     133                 :           8 :         }
     134                 :             : 
     135                 :             :         /*
     136                 :             :          * Check WHEN clauses for permissions and sanity
     137                 :             :          */
     138                 :         316 :         is_terminal[MERGE_WHEN_MATCHED] = false;
     139                 :         316 :         is_terminal[MERGE_WHEN_NOT_MATCHED_BY_SOURCE] = false;
     140                 :         316 :         is_terminal[MERGE_WHEN_NOT_MATCHED_BY_TARGET] = false;
     141   [ +  -  +  +  :         780 :         foreach(l, stmt->mergeWhenClauses)
                   +  + ]
     142                 :             :         {
     143                 :         465 :                 MergeWhenClause *mergeWhenClause = (MergeWhenClause *) lfirst(l);
     144                 :             : 
     145                 :             :                 /*
     146                 :             :                  * Collect permissions to check, according to action types. We require
     147                 :             :                  * SELECT privileges for DO NOTHING because it'd be irregular to have
     148                 :             :                  * a target relation with zero privileges checked, in case DO NOTHING
     149                 :             :                  * is the only action.  There's no damage from that: any meaningful
     150                 :             :                  * MERGE command requires at least some access to the table anyway.
     151                 :             :                  */
     152   [ +  +  +  +  :         465 :                 switch (mergeWhenClause->commandType)
                      - ]
     153                 :             :                 {
     154                 :             :                         case CMD_INSERT:
     155                 :         154 :                                 targetPerms |= ACL_INSERT;
     156                 :         154 :                                 break;
     157                 :             :                         case CMD_UPDATE:
     158                 :         211 :                                 targetPerms |= ACL_UPDATE;
     159                 :         211 :                                 break;
     160                 :             :                         case CMD_DELETE:
     161                 :          85 :                                 targetPerms |= ACL_DELETE;
     162                 :          85 :                                 break;
     163                 :             :                         case CMD_NOTHING:
     164                 :          15 :                                 targetPerms |= ACL_SELECT;
     165                 :          15 :                                 break;
     166                 :             :                         default:
     167   [ #  #  #  # ]:           0 :                                 elog(ERROR, "unknown action in MERGE WHEN clause");
     168                 :           0 :                 }
     169                 :             : 
     170                 :             :                 /*
     171                 :             :                  * Check for unreachable WHEN clauses
     172                 :             :                  */
     173         [ +  + ]:         465 :                 if (is_terminal[mergeWhenClause->matchKind])
     174   [ +  -  +  - ]:           1 :                         ereport(ERROR,
     175                 :             :                                         (errcode(ERRCODE_SYNTAX_ERROR),
     176                 :             :                                          errmsg("unreachable WHEN clause specified after unconditional WHEN clause")));
     177         [ +  + ]:         464 :                 if (mergeWhenClause->condition == NULL)
     178                 :         348 :                         is_terminal[mergeWhenClause->matchKind] = true;
     179                 :         464 :         }
     180                 :             : 
     181                 :             :         /*
     182                 :             :          * Set up the MERGE target table.  The target table is added to the
     183                 :             :          * namespace below and to joinlist in transform_MERGE_to_join, so don't do
     184                 :             :          * it here.
     185                 :             :          *
     186                 :             :          * Initially mergeTargetRelation is the same as resultRelation, so data is
     187                 :             :          * read from the table being updated.  However, that might be changed by
     188                 :             :          * the rewriter, if the target is a trigger-updatable view, to allow
     189                 :             :          * target data to be read from the expanded view query while updating the
     190                 :             :          * original view relation.
     191                 :             :          */
     192                 :         630 :         qry->resultRelation = setTargetTable(pstate, stmt->relation,
     193                 :         315 :                                                                                  stmt->relation->inh,
     194                 :         315 :                                                                                  false, targetPerms);
     195                 :         315 :         qry->mergeTargetRelation = qry->resultRelation;
     196                 :             : 
     197                 :             :         /* The target relation must be a table or a view */
     198         [ +  + ]:         315 :         if (pstate->p_target_relation->rd_rel->relkind != RELKIND_RELATION &&
     199   [ +  +  +  + ]:         134 :                 pstate->p_target_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
     200                 :         117 :                 pstate->p_target_relation->rd_rel->relkind != RELKIND_VIEW)
     201   [ +  -  +  - ]:           1 :                 ereport(ERROR,
     202                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     203                 :             :                                  errmsg("cannot execute MERGE on relation \"%s\"",
     204                 :             :                                                 RelationGetRelationName(pstate->p_target_relation)),
     205                 :             :                                  errdetail_relkind_not_supported(pstate->p_target_relation->rd_rel->relkind)));
     206                 :             : 
     207                 :             :         /* Now transform the source relation to produce the source RTE. */
     208                 :         628 :         transformFromClause(pstate,
     209                 :         314 :                                                 list_make1(stmt->sourceRelation));
     210                 :         314 :         sourceRTI = list_length(pstate->p_rtable);
     211                 :         314 :         nsitem = GetNSItemByRangeTablePosn(pstate, sourceRTI, 0);
     212                 :             : 
     213                 :             :         /*
     214                 :             :          * Check that the target table doesn't conflict with the source table.
     215                 :             :          * This would typically be a checkNameSpaceConflicts call, but we want a
     216                 :             :          * more specific error message.
     217                 :             :          */
     218                 :         628 :         if (strcmp(pstate->p_target_nsitem->p_names->aliasname,
     219   [ +  +  +  + ]:         628 :                            nsitem->p_names->aliasname) == 0)
     220   [ +  -  +  - ]:           1 :                 ereport(ERROR,
     221                 :             :                                 errcode(ERRCODE_DUPLICATE_ALIAS),
     222                 :             :                                 errmsg("name \"%s\" specified more than once",
     223                 :             :                                            pstate->p_target_nsitem->p_names->aliasname),
     224                 :             :                                 errdetail("The name is used both as MERGE target table and data source."));
     225                 :             : 
     226                 :             :         /*
     227                 :             :          * There's no need for a targetlist here; it'll be set up by
     228                 :             :          * preprocess_targetlist later.
     229                 :             :          */
     230                 :         313 :         qry->targetList = NIL;
     231                 :         313 :         qry->rtable = pstate->p_rtable;
     232                 :         313 :         qry->rteperminfos = pstate->p_rteperminfos;
     233                 :             : 
     234                 :             :         /*
     235                 :             :          * Transform the join condition.  This includes references to the target
     236                 :             :          * side, so add that to the namespace.
     237                 :             :          */
     238                 :         313 :         addNSItemToQuery(pstate, pstate->p_target_nsitem, false, true, true);
     239                 :         313 :         qry->mergeJoinCondition = transformExpr(pstate, stmt->joinCondition,
     240                 :             :                                                                                         EXPR_KIND_JOIN_ON);
     241                 :             : 
     242                 :             :         /*
     243                 :             :          * Create the temporary query's jointree using the joinlist we built using
     244                 :             :          * just the source relation; the target relation is not included. The join
     245                 :             :          * will be constructed fully by transform_MERGE_to_join.
     246                 :             :          */
     247                 :         313 :         qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
     248                 :             : 
     249                 :             :         /* Transform the RETURNING list, if any */
     250                 :         313 :         transformReturningClause(pstate, qry, stmt->returningClause,
     251                 :             :                                                          EXPR_KIND_MERGE_RETURNING);
     252                 :             : 
     253                 :             :         /*
     254                 :             :          * We now have a good query shape, so now look at the WHEN conditions and
     255                 :             :          * action targetlists.
     256                 :             :          *
     257                 :             :          * Overall, the MERGE Query's targetlist is NIL.
     258                 :             :          *
     259                 :             :          * Each individual action has its own targetlist that needs separate
     260                 :             :          * transformation. These transforms don't do anything to the overall
     261                 :             :          * targetlist, since that is only used for resjunk columns.
     262                 :             :          *
     263                 :             :          * We can reference any column in Target or Source, which is OK because
     264                 :             :          * both of those already have RTEs. There is nothing like the EXCLUDED
     265                 :             :          * pseudo-relation for INSERT ON CONFLICT.
     266                 :             :          */
     267                 :         313 :         mergeActionList = NIL;
     268   [ +  -  +  +  :         764 :         foreach(l, stmt->mergeWhenClauses)
                   +  + ]
     269                 :             :         {
     270                 :         451 :                 MergeWhenClause *mergeWhenClause = lfirst_node(MergeWhenClause, l);
     271                 :         451 :                 MergeAction *action;
     272                 :             : 
     273                 :         451 :                 action = makeNode(MergeAction);
     274                 :         451 :                 action->commandType = mergeWhenClause->commandType;
     275                 :         451 :                 action->matchKind = mergeWhenClause->matchKind;
     276                 :             : 
     277                 :             :                 /*
     278                 :             :                  * Set namespace for the specific action. This must be done before
     279                 :             :                  * analyzing the WHEN quals and the action targetlist.
     280                 :             :                  */
     281                 :         902 :                 setNamespaceForMergeWhen(pstate, mergeWhenClause,
     282                 :         451 :                                                                  qry->resultRelation,
     283                 :         451 :                                                                  sourceRTI);
     284                 :             : 
     285                 :             :                 /*
     286                 :             :                  * Transform the WHEN condition.
     287                 :             :                  *
     288                 :             :                  * Note that these quals are NOT added to the join quals; instead they
     289                 :             :                  * are evaluated separately during execution to decide which of the
     290                 :             :                  * WHEN MATCHED or WHEN NOT MATCHED actions to execute.
     291                 :             :                  */
     292                 :         451 :                 action->qual = transformWhereClause(pstate, mergeWhenClause->condition,
     293                 :             :                                                                                         EXPR_KIND_MERGE_WHEN, "WHEN");
     294                 :             : 
     295                 :             :                 /*
     296                 :             :                  * Transform target lists for each INSERT and UPDATE action stmt
     297                 :             :                  */
     298   [ +  +  +  +  :         451 :                 switch (action->commandType)
                      - ]
     299                 :             :                 {
     300                 :             :                         case CMD_INSERT:
     301                 :             :                                 {
     302                 :         150 :                                         List       *exprList = NIL;
     303                 :         150 :                                         ListCell   *lc;
     304                 :         150 :                                         RTEPermissionInfo *perminfo;
     305                 :         150 :                                         ListCell   *icols;
     306                 :         150 :                                         ListCell   *attnos;
     307                 :         150 :                                         List       *icolumns;
     308                 :         150 :                                         List       *attrnos;
     309                 :             : 
     310                 :         150 :                                         pstate->p_is_insert = true;
     311                 :             : 
     312                 :         300 :                                         icolumns = checkInsertTargets(pstate,
     313                 :         150 :                                                                                                   mergeWhenClause->targetList,
     314                 :             :                                                                                                   &attrnos);
     315         [ -  + ]:         150 :                                         Assert(list_length(icolumns) == list_length(attrnos));
     316                 :             : 
     317                 :         150 :                                         action->override = mergeWhenClause->override;
     318                 :             : 
     319                 :             :                                         /*
     320                 :             :                                          * Handle INSERT much like in transformInsertStmt
     321                 :             :                                          */
     322         [ +  + ]:         150 :                                         if (mergeWhenClause->values == NIL)
     323                 :             :                                         {
     324                 :             :                                                 /*
     325                 :             :                                                  * We have INSERT ... DEFAULT VALUES.  We can handle
     326                 :             :                                                  * this case by emitting an empty targetlist --- all
     327                 :             :                                                  * columns will be defaulted when the planner expands
     328                 :             :                                                  * the targetlist.
     329                 :             :                                                  */
     330                 :           4 :                                                 exprList = NIL;
     331                 :           4 :                                         }
     332                 :             :                                         else
     333                 :             :                                         {
     334                 :             :                                                 /*
     335                 :             :                                                  * Process INSERT ... VALUES with a single VALUES
     336                 :             :                                                  * sublist.  We treat this case separately for
     337                 :             :                                                  * efficiency.  The sublist is just computed directly
     338                 :             :                                                  * as the Query's targetlist, with no VALUES RTE.  So
     339                 :             :                                                  * it works just like a SELECT without any FROM.
     340                 :             :                                                  */
     341                 :             : 
     342                 :             :                                                 /*
     343                 :             :                                                  * Do basic expression transformation (same as a ROW()
     344                 :             :                                                  * expr, but allow SetToDefault at top level)
     345                 :             :                                                  */
     346                 :         292 :                                                 exprList = transformExpressionList(pstate,
     347                 :         146 :                                                                                                                    mergeWhenClause->values,
     348                 :             :                                                                                                                    EXPR_KIND_VALUES_SINGLE,
     349                 :             :                                                                                                                    true);
     350                 :             : 
     351                 :             :                                                 /* Prepare row for assignment to target table */
     352                 :         292 :                                                 exprList = transformInsertRow(pstate, exprList,
     353                 :         146 :                                                                                                           mergeWhenClause->targetList,
     354                 :         146 :                                                                                                           icolumns, attrnos,
     355                 :             :                                                                                                           false);
     356                 :             :                                         }
     357                 :             : 
     358                 :             :                                         /*
     359                 :             :                                          * Generate action's target list using the computed list
     360                 :             :                                          * of expressions. Also, mark all the target columns as
     361                 :             :                                          * needing insert permissions.
     362                 :             :                                          */
     363                 :         150 :                                         perminfo = pstate->p_target_nsitem->p_perminfo;
     364   [ +  +  +  +  :         481 :                                         forthree(lc, exprList, icols, icolumns, attnos, attrnos)
          +  -  +  +  +  
          -  +  +  +  +  
             -  +  +  + ]
     365                 :             :                                         {
     366                 :         331 :                                                 Expr       *expr = (Expr *) lfirst(lc);
     367                 :         331 :                                                 ResTarget  *col = lfirst_node(ResTarget, icols);
     368                 :         331 :                                                 AttrNumber      attr_num = (AttrNumber) lfirst_int(attnos);
     369                 :         331 :                                                 TargetEntry *tle;
     370                 :             : 
     371                 :         662 :                                                 tle = makeTargetEntry(expr,
     372                 :         331 :                                                                                           attr_num,
     373                 :         331 :                                                                                           col->name,
     374                 :             :                                                                                           false);
     375                 :         331 :                                                 action->targetList = lappend(action->targetList, tle);
     376                 :             : 
     377                 :         331 :                                                 perminfo->insertedCols =
     378                 :         662 :                                                         bms_add_member(perminfo->insertedCols,
     379                 :         331 :                                                                                    attr_num - FirstLowInvalidHeapAttributeNumber);
     380                 :         331 :                                         }
     381                 :         150 :                                 }
     382                 :         150 :                                 break;
     383                 :             :                         case CMD_UPDATE:
     384                 :             :                                 {
     385                 :         209 :                                         pstate->p_is_insert = false;
     386                 :         209 :                                         action->targetList =
     387                 :         418 :                                                 transformUpdateTargetList(pstate,
     388                 :         209 :                                                                                                   mergeWhenClause->targetList);
     389                 :             :                                 }
     390                 :         209 :                                 break;
     391                 :             :                         case CMD_DELETE:
     392                 :             :                                 break;
     393                 :             : 
     394                 :             :                         case CMD_NOTHING:
     395                 :          14 :                                 action->targetList = NIL;
     396                 :          14 :                                 break;
     397                 :             :                         default:
     398   [ #  #  #  # ]:           0 :                                 elog(ERROR, "unknown action in MERGE WHEN clause");
     399                 :           0 :                 }
     400                 :             : 
     401                 :         451 :                 mergeActionList = lappend(mergeActionList, action);
     402                 :         451 :         }
     403                 :             : 
     404                 :         313 :         qry->mergeActionList = mergeActionList;
     405                 :             : 
     406                 :         313 :         qry->hasTargetSRFs = false;
     407                 :         313 :         qry->hasSubLinks = pstate->p_hasSubLinks;
     408                 :             : 
     409                 :         313 :         assign_query_collations(pstate, qry);
     410                 :             : 
     411                 :         626 :         return qry;
     412                 :         313 : }
     413                 :             : 
     414                 :             : static void
     415                 :         916 : setNamespaceVisibilityForRTE(List *namespace, RangeTblEntry *rte,
     416                 :             :                                                          bool rel_visible,
     417                 :             :                                                          bool cols_visible)
     418                 :             : {
     419                 :         916 :         ListCell   *lc;
     420                 :             : 
     421   [ +  -  -  +  :        2354 :         foreach(lc, namespace)
                   +  - ]
     422                 :             :         {
     423                 :        1438 :                 ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(lc);
     424                 :             : 
     425         [ +  + ]:        1438 :                 if (nsitem->p_rte == rte)
     426                 :             :                 {
     427                 :         916 :                         nsitem->p_rel_visible = rel_visible;
     428                 :         916 :                         nsitem->p_cols_visible = cols_visible;
     429                 :         916 :                         break;
     430                 :             :                 }
     431         [ +  + ]:        1438 :         }
     432                 :         916 : }
        

Generated by: LCOV version 2.3.2-1