1 /*-------------------------------------------------------------------------
4 * Routines to handle unique'ing of queries where appropriate
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.1.1.1 1996/07/09 06:21:27 scrappy Exp $
12 *-------------------------------------------------------------------------
16 * ExecUnique - generate a unique'd temporary relation
17 * ExecInitUnique - initialize node and subnodes..
18 * ExecEndUnique - shutdown node and subnodes
21 * Assumes tuples returned from subplan arrive in
25 #include "executor/executor.h"
26 #include "executor/nodeUnique.h"
27 #include "optimizer/clauses.h"
28 #include "access/printtup.h" /* for typtoout() */
29 #include "utils/builtins.h" /* for namecpy()*/
31 /* ----------------------------------------------------------------
34 * This is a hack function used by ExecUnique to see if
35 * two tuples are identical. This should be provided
36 * by the heap tuple code but isn't. The real problem
37 * is that we assume we can byte compare tuples to determine
38 * if they are "equal". In fact, if we have user defined
39 * types there may be problems because it's possible that
40 * an ADT may have multiple representations with the
41 * same ADT value. -cim
42 * ----------------------------------------------------------------
44 static bool /* true if tuples are identical, false otherwise */
45 ExecIdenticalTuples(TupleTableSlot *t1, TupleTableSlot *t2)
57 * if tuples aren't the same length then they are
58 * obviously different (one may have null attributes).
61 if (h1->t_len != h2->t_len)
65 * if the tuples have different header offsets then
66 * they are different. This will prevent us from returning
67 * true when comparing tuples of one attribute where one of
68 * two we're looking at is null (t_len - t_hoff == 0).
69 * THE t_len FIELDS CAN BE THE SAME IN THIS CASE!!
72 if (h1->t_hoff != h2->t_hoff)
76 * ok, now get the pointers to the data and the
77 * size of the attribute portion of the tuple.
80 d1 = (char *) GETSTRUCT(h1);
81 d2 = (char *) GETSTRUCT(h2);
82 len = (int) h1->t_len - (int) h1->t_hoff;
85 * byte compare the data areas and return the result.
88 if (memcmp(d1, d2, len) != 0)
94 /* ----------------------------------------------------------------
97 * This is a very simple node which filters out duplicate
98 * tuples from a stream of sorted tuples from a subplan.
100 * XXX see comments below regarding freeing tuples.
101 * ----------------------------------------------------------------
103 TupleTableSlot * /* return: a tuple or NULL */
104 ExecUnique(Unique *node)
106 UniqueState *uniquestate;
107 TupleTableSlot *resultTupleSlot;
108 TupleTableSlot *slot;
111 AttrNumber uniqueAttrNum;
116 * get information from the node
119 uniquestate = node->uniquestate;
120 outerPlan = outerPlan((Plan *) node);
121 resultTupleSlot = uniquestate->cs_ResultTupleSlot;
122 uniqueAttr = node->uniqueAttr;
123 uniqueAttrNum = node->uniqueAttrNum;
126 tupDesc = ExecGetResultType(uniquestate);
127 typoutput = typtoout((Oid)tupDesc->attrs[uniqueAttrNum]->atttypid);
131 * now loop, returning only non-duplicate tuples.
132 * We assume that the tuples arrive in sorted order
133 * so we can detect duplicates easily.
138 * fetch a tuple from the outer subplan
141 slot = ExecProcNode(outerPlan, (Plan*)node);
146 * we use the result tuple slot to hold our saved tuples.
147 * if we haven't a saved tuple to compare our new tuple with,
148 * then we exit the loop. This new tuple as the saved tuple
149 * the next time we get here.
152 if (TupIsNull(resultTupleSlot))
156 * now test if the new tuple and the previous
157 * tuple match. If so then we loop back and fetch
158 * another new tuple from the subplan.
163 /* to check equality, we check to see if the typoutput
164 of the attributes are equal */
165 bool isNull1,isNull2;
169 attr1 = heap_getattr(slot->val, InvalidBuffer,
170 uniqueAttrNum, tupDesc,&isNull1);
171 attr2 = heap_getattr(resultTupleSlot->val, InvalidBuffer,
172 uniqueAttrNum, tupDesc,&isNull2);
174 if (isNull1 == isNull2) {
175 if (isNull1) /* both are null, they are equal */
177 val1 = fmgr(typoutput, attr1, gettypelem(tupDesc->attrs[uniqueAttrNum]->atttypid));
178 val2 = fmgr(typoutput, attr2, gettypelem(tupDesc->attrs[uniqueAttrNum]->atttypid));
179 /* now, val1 and val2 are ascii representations so we can
180 use strcmp for comparison */
181 if (strcmp(val1,val2) == 0) /* they are equal */
186 else /* one is null and the other isn't, they aren't equal */
191 if (! ExecIdenticalTuples(slot, resultTupleSlot))
198 * we have a new tuple different from the previous saved tuple
199 * so we save it in the saved tuple slot. We copy the tuple
200 * so we don't increment the buffer ref count.
203 ExecStoreTuple(heap_copytuple(slot->val),
208 return resultTupleSlot;
211 /* ----------------------------------------------------------------
214 * This initializes the unique node state structures and
215 * the node's subplan.
216 * ----------------------------------------------------------------
218 bool /* return: initialization status */
219 ExecInitUnique(Unique *node, EState *estate, Plan *parent)
221 UniqueState *uniquestate;
226 * assign execution state to node
229 node->plan.state = estate;
232 * create new UniqueState for node
235 uniquestate = makeNode(UniqueState);
236 node->uniquestate = uniquestate;
237 uniqueAttr = node->uniqueAttr;
240 * Miscellanious initialization
242 * + assign node's base_id
243 * + assign debugging hooks and
245 * Unique nodes have no ExprContext initialization because
246 * they never call ExecQual or ExecTargetList.
249 ExecAssignNodeBaseInfo(estate, uniquestate, parent);
251 #define UNIQUE_NSLOTS 1
253 * Tuple table initialization
256 ExecInitResultTupleSlot(estate, uniquestate);
259 * then initialize outer plan
262 outerPlan = outerPlan((Plan *) node);
263 ExecInitNode(outerPlan, estate, (Plan *) node);
266 * unique nodes do no projections, so initialize
267 * projection info for this node appropriately
270 ExecAssignResultTypeFromOuterPlan((Plan *)node,uniquestate);
271 uniquestate->cs_ProjInfo = NULL;
277 tupDesc = ExecGetResultType(uniquestate);
278 /* the parser should have ensured that uniqueAttr is a legal attribute name*/
279 while ( strcmp((tupDesc->attrs[i]->attname).data, uniqueAttr) != 0)
281 node->uniqueAttrNum = i+1; /* attribute numbers start from 1 */
284 node->uniqueAttrNum = InvalidAttrNumber;
294 ExecCountSlotsUnique(Unique *node)
296 return ExecCountSlotsNode(outerPlan(node)) +
297 ExecCountSlotsNode(innerPlan(node)) +
301 /* ----------------------------------------------------------------
304 * This shuts down the subplan and frees resources allocated
306 * ----------------------------------------------------------------
309 ExecEndUnique(Unique *node)
311 UniqueState *uniquestate;
313 uniquestate = node->uniquestate;
314 ExecEndNode(outerPlan((Plan *) node), (Plan*)node);
315 ExecClearTuple(uniquestate->cs_ResultTupleSlot);