Doc: clarify behavior of timestamptz input some more.
[pgsql.git] / src / backend / executor / nodeUnique.c
blob3854ad285c4eb2988e179f847c0e2146f362c0c0
1 /*-------------------------------------------------------------------------
3 * nodeUnique.c
4 * Routines to handle unique'ing of queries where appropriate
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.)
14 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
18 * IDENTIFICATION
19 * src/backend/executor/nodeUnique.c
21 *-------------------------------------------------------------------------
24 * INTERFACE ROUTINES
25 * ExecUnique - generate a unique'd temporary relation
26 * ExecInitUnique - initialize node and subnodes
27 * ExecEndUnique - shutdown node and subnodes
29 * NOTES
30 * Assumes tuples returned from subplan arrive in
31 * sorted order.
34 #include "postgres.h"
36 #include "executor/executor.h"
37 #include "executor/nodeUnique.h"
38 #include "miscadmin.h"
41 /* ----------------------------------------------------------------
42 * ExecUnique
43 * ----------------------------------------------------------------
45 static TupleTableSlot * /* return: a tuple or NULL */
46 ExecUnique(PlanState *pstate)
48 UniqueState *node = castNode(UniqueState, pstate);
49 ExprContext *econtext = node->ps.ps_ExprContext;
50 TupleTableSlot *resultTupleSlot;
51 TupleTableSlot *slot;
52 PlanState *outerPlan;
54 CHECK_FOR_INTERRUPTS();
57 * get information from the node
59 outerPlan = outerPlanState(node);
60 resultTupleSlot = node->ps.ps_ResultTupleSlot;
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.
67 for (;;)
70 * fetch a tuple from the outer subplan
72 slot = ExecProcNode(outerPlan);
73 if (TupIsNull(slot))
75 /* end of subplan, so we're done */
76 ExecClearTuple(resultTupleSlot);
77 return NULL;
81 * Always return the first tuple from the subplan.
83 if (TupIsNull(resultTupleSlot))
84 break;
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.
91 econtext->ecxt_innertuple = slot;
92 econtext->ecxt_outertuple = resultTupleSlot;
93 if (!ExecQualAndReset(node->eqfunction, econtext))
94 break;
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.
103 return ExecCopySlot(resultTupleSlot, slot);
106 /* ----------------------------------------------------------------
107 * ExecInitUnique
109 * This initializes the unique node state structures and
110 * the node's subplan.
111 * ----------------------------------------------------------------
113 UniqueState *
114 ExecInitUnique(Unique *node, EState *estate, int eflags)
116 UniqueState *uniquestate;
118 /* check for unsupported flags */
119 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
122 * create state structure
124 uniquestate = makeNode(UniqueState);
125 uniquestate->ps.plan = (Plan *) node;
126 uniquestate->ps.state = estate;
127 uniquestate->ps.ExecProcNode = ExecUnique;
130 * create expression context
132 ExecAssignExprContext(estate, &uniquestate->ps);
135 * then initialize outer plan
137 outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags);
140 * Initialize result slot and type. Unique nodes do no projections, so
141 * initialize projection info for this node appropriately.
143 ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple);
144 uniquestate->ps.ps_ProjInfo = NULL;
147 * Precompute fmgr lookup data for inner loop
149 uniquestate->eqfunction =
150 execTuplesMatchPrepare(ExecGetResultType(outerPlanState(uniquestate)),
151 node->numCols,
152 node->uniqColIdx,
153 node->uniqOperators,
154 node->uniqCollations,
155 &uniquestate->ps);
157 return uniquestate;
160 /* ----------------------------------------------------------------
161 * ExecEndUnique
163 * This shuts down the subplan and frees resources allocated
164 * to this node.
165 * ----------------------------------------------------------------
167 void
168 ExecEndUnique(UniqueState *node)
170 ExecEndNode(outerPlanState(node));
174 void
175 ExecReScanUnique(UniqueState *node)
177 PlanState *outerPlan = outerPlanState(node);
179 /* must clear result tuple so first input tuple is returned */
180 ExecClearTuple(node->ps.ps_ResultTupleSlot);
183 * if chgParam of subnode is not null then plan will be re-scanned by
184 * first ExecProcNode.
186 if (outerPlan->chgParam == NULL)
187 ExecReScan(outerPlan);