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-2017, 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 #include "utils/memutils.h"
40 
41 
42 /* ----------------------------------------------------------------
43  *		ExecUnique
44  * ----------------------------------------------------------------
45  */
46 static TupleTableSlot *			/* return: a tuple or NULL */
ExecUnique(PlanState * pstate)47 ExecUnique(PlanState *pstate)
48 {
49 	UniqueState *node = castNode(UniqueState, pstate);
50 	Unique	   *plannode = (Unique *) node->ps.plan;
51 	TupleTableSlot *resultTupleSlot;
52 	TupleTableSlot *slot;
53 	PlanState  *outerPlan;
54 
55 	CHECK_FOR_INTERRUPTS();
56 
57 	/*
58 	 * get information from the node
59 	 */
60 	outerPlan = outerPlanState(node);
61 	resultTupleSlot = node->ps.ps_ResultTupleSlot;
62 
63 	/*
64 	 * now loop, returning only non-duplicate tuples. We assume that the
65 	 * tuples arrive in sorted order so we can detect duplicates easily. The
66 	 * first tuple of each group is returned.
67 	 */
68 	for (;;)
69 	{
70 		/*
71 		 * fetch a tuple from the outer subplan
72 		 */
73 		slot = ExecProcNode(outerPlan);
74 		if (TupIsNull(slot))
75 		{
76 			/* end of subplan, so we're done */
77 			ExecClearTuple(resultTupleSlot);
78 			return NULL;
79 		}
80 
81 		/*
82 		 * Always return the first tuple from the subplan.
83 		 */
84 		if (TupIsNull(resultTupleSlot))
85 			break;
86 
87 		/*
88 		 * Else test if the new tuple and the previously returned tuple match.
89 		 * If so then we loop back and fetch another new tuple from the
90 		 * subplan.
91 		 */
92 		if (!execTuplesMatch(slot, resultTupleSlot,
93 							 plannode->numCols, plannode->uniqColIdx,
94 							 node->eqfunctions,
95 							 node->tempContext))
96 			break;
97 	}
98 
99 	/*
100 	 * We have a new tuple different from the previous saved tuple (if any).
101 	 * Save it and return it.  We must copy it because the source subplan
102 	 * won't guarantee that this source tuple is still accessible after
103 	 * fetching the next source tuple.
104 	 */
105 	return ExecCopySlot(resultTupleSlot, slot);
106 }
107 
108 /* ----------------------------------------------------------------
109  *		ExecInitUnique
110  *
111  *		This initializes the unique node state structures and
112  *		the node's subplan.
113  * ----------------------------------------------------------------
114  */
115 UniqueState *
ExecInitUnique(Unique * node,EState * estate,int eflags)116 ExecInitUnique(Unique *node, EState *estate, int eflags)
117 {
118 	UniqueState *uniquestate;
119 
120 	/* check for unsupported flags */
121 	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
122 
123 	/*
124 	 * create state structure
125 	 */
126 	uniquestate = makeNode(UniqueState);
127 	uniquestate->ps.plan = (Plan *) node;
128 	uniquestate->ps.state = estate;
129 	uniquestate->ps.ExecProcNode = ExecUnique;
130 
131 	/*
132 	 * Miscellaneous initialization
133 	 *
134 	 * Unique nodes have no ExprContext initialization because they never call
135 	 * ExecQual or ExecProject.  But they do need a per-tuple memory context
136 	 * anyway for calling execTuplesMatch.
137 	 */
138 	uniquestate->tempContext =
139 		AllocSetContextCreate(CurrentMemoryContext,
140 							  "Unique",
141 							  ALLOCSET_DEFAULT_SIZES);
142 
143 	/*
144 	 * Tuple table initialization
145 	 */
146 	ExecInitResultTupleSlot(estate, &uniquestate->ps);
147 
148 	/*
149 	 * then initialize outer plan
150 	 */
151 	outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags);
152 
153 	/*
154 	 * unique nodes do no projections, so initialize projection info for this
155 	 * node appropriately
156 	 */
157 	ExecAssignResultTypeFromTL(&uniquestate->ps);
158 	uniquestate->ps.ps_ProjInfo = NULL;
159 
160 	/*
161 	 * Precompute fmgr lookup data for inner loop
162 	 */
163 	uniquestate->eqfunctions =
164 		execTuplesMatchPrepare(node->numCols,
165 							   node->uniqOperators);
166 
167 	return uniquestate;
168 }
169 
170 /* ----------------------------------------------------------------
171  *		ExecEndUnique
172  *
173  *		This shuts down the subplan and frees resources allocated
174  *		to this node.
175  * ----------------------------------------------------------------
176  */
177 void
ExecEndUnique(UniqueState * node)178 ExecEndUnique(UniqueState *node)
179 {
180 	/* clean up tuple table */
181 	ExecClearTuple(node->ps.ps_ResultTupleSlot);
182 
183 	MemoryContextDelete(node->tempContext);
184 
185 	ExecEndNode(outerPlanState(node));
186 }
187 
188 
189 void
ExecReScanUnique(UniqueState * node)190 ExecReScanUnique(UniqueState *node)
191 {
192 	/* must clear result tuple so first input tuple is returned */
193 	ExecClearTuple(node->ps.ps_ResultTupleSlot);
194 
195 	/*
196 	 * if chgParam of subnode is not null then plan will be re-scanned by
197 	 * first ExecProcNode.
198 	 */
199 	if (node->ps.lefttree->chgParam == NULL)
200 		ExecReScan(node->ps.lefttree);
201 }
202