Coverage Report

Created: 2026-08-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/executor/nodeUnique.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * nodeUnique.c
4
 *    Routines to handle unique'ing of queries where appropriate
5
 *
6
 * Unique is a very simple node type that just filters out duplicate
7
 * tuples from a stream of sorted tuples from its subplan.  It's essentially
8
 * a dumbed-down form of Group: the duplicate-removal functionality is
9
 * identical.  However, Unique doesn't do projection nor qual checking,
10
 * so it's marginally more efficient for cases where neither is needed.
11
 * (It's debatable whether the savings justifies carrying two plan node
12
 * types, though.)
13
 *
14
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
15
 * Portions Copyright (c) 1994, Regents of the University of California
16
 *
17
 *
18
 * IDENTIFICATION
19
 *    src/backend/executor/nodeUnique.c
20
 *
21
 *-------------------------------------------------------------------------
22
 */
23
/*
24
 * INTERFACE ROUTINES
25
 *    ExecUnique    - generate a unique'd temporary relation
26
 *    ExecInitUnique  - initialize node and subnodes
27
 *    ExecEndUnique - shutdown node and subnodes
28
 *
29
 * NOTES
30
 *    Assumes tuples returned from subplan arrive in
31
 *    sorted order.
32
 */
33
34
#include "postgres.h"
35
36
#include "executor/executor.h"
37
#include "executor/nodeUnique.h"
38
#include "miscadmin.h"
39
40
41
/* ----------------------------------------------------------------
42
 *    ExecUnique
43
 * ----------------------------------------------------------------
44
 */
45
static TupleTableSlot *     /* return: a tuple or NULL */
46
ExecUnique(PlanState *pstate)
47
0
{
48
0
  UniqueState *node = castNode(UniqueState, pstate);
49
0
  ExprContext *econtext = node->ps.ps_ExprContext;
50
0
  TupleTableSlot *resultTupleSlot;
51
0
  TupleTableSlot *slot;
52
0
  PlanState  *outerPlan;
53
54
0
  CHECK_FOR_INTERRUPTS();
55
56
  /*
57
   * get information from the node
58
   */
59
0
  outerPlan = outerPlanState(node);
60
0
  resultTupleSlot = node->ps.ps_ResultTupleSlot;
61
62
  /*
63
   * now loop, returning only non-duplicate tuples. We assume that the
64
   * tuples arrive in sorted order so we can detect duplicates easily. The
65
   * first tuple of each group is returned.
66
   */
67
0
  for (;;)
68
0
  {
69
    /*
70
     * fetch a tuple from the outer subplan
71
     */
72
0
    slot = ExecProcNode(outerPlan);
73
0
    if (TupIsNull(slot))
74
0
    {
75
      /* end of subplan, so we're done */
76
0
      ExecClearTuple(resultTupleSlot);
77
0
      return NULL;
78
0
    }
79
80
    /*
81
     * Always return the first tuple from the subplan.
82
     */
83
0
    if (TupIsNull(resultTupleSlot))
84
0
      break;
85
86
    /*
87
     * Else test if the new tuple and the previously returned tuple match.
88
     * If so then we loop back and fetch another new tuple from the
89
     * subplan.
90
     */
91
0
    econtext->ecxt_innertuple = slot;
92
0
    econtext->ecxt_outertuple = resultTupleSlot;
93
0
    if (!ExecQualAndReset(node->eqfunction, econtext))
94
0
      break;
95
0
  }
96
97
  /*
98
   * We have a new tuple different from the previous saved tuple (if any).
99
   * Save it and return it.  We must copy it because the source subplan
100
   * won't guarantee that this source tuple is still accessible after
101
   * fetching the next source tuple.
102
   */
103
0
  return ExecCopySlot(resultTupleSlot, slot);
104
0
}
105
106
/* ----------------------------------------------------------------
107
 *    ExecInitUnique
108
 *
109
 *    This initializes the unique node state structures and
110
 *    the node's subplan.
111
 * ----------------------------------------------------------------
112
 */
113
UniqueState *
114
ExecInitUnique(Unique *node, EState *estate, int eflags)
115
0
{
116
0
  UniqueState *uniquestate;
117
118
  /* check for unsupported flags */
119
0
  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
120
121
  /*
122
   * create state structure
123
   */
124
0
  uniquestate = makeNode(UniqueState);
125
0
  uniquestate->ps.plan = (Plan *) node;
126
0
  uniquestate->ps.state = estate;
127
0
  uniquestate->ps.ExecProcNode = ExecUnique;
128
129
  /*
130
   * create expression context
131
   */
132
0
  ExecAssignExprContext(estate, &uniquestate->ps);
133
134
  /*
135
   * then initialize outer plan
136
   */
137
0
  outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags);
138
139
  /*
140
   * Initialize result slot and type. Unique nodes do no projections, so
141
   * initialize projection info for this node appropriately.
142
   */
143
0
  ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple);
144
0
  uniquestate->ps.ps_ProjInfo = NULL;
145
146
  /*
147
   * Precompute fmgr lookup data for inner loop
148
   */
149
0
  uniquestate->eqfunction =
150
0
    execTuplesMatchPrepare(ExecGetResultType(outerPlanState(uniquestate)),
151
0
                 node->numCols,
152
0
                 node->uniqColIdx,
153
0
                 node->uniqOperators,
154
0
                 node->uniqCollations,
155
0
                 &uniquestate->ps);
156
157
0
  return uniquestate;
158
0
}
159
160
/* ----------------------------------------------------------------
161
 *    ExecEndUnique
162
 *
163
 *    This shuts down the subplan and frees resources allocated
164
 *    to this node.
165
 * ----------------------------------------------------------------
166
 */
167
void
168
ExecEndUnique(UniqueState *node)
169
0
{
170
0
  ExecEndNode(outerPlanState(node));
171
0
}
172
173
174
void
175
ExecReScanUnique(UniqueState *node)
176
0
{
177
0
  PlanState  *outerPlan = outerPlanState(node);
178
179
  /* must clear result tuple so first input tuple is returned */
180
0
  ExecClearTuple(node->ps.ps_ResultTupleSlot);
181
182
  /*
183
   * if chgParam of subnode is not null then plan will be re-scanned by
184
   * first ExecProcNode.
185
   */
186
0
  if (outerPlan->chgParam == NULL)
187
0
    ExecReScan(outerPlan);
188
0
}