]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeUnique.c
Postgres95 1.01 Distribution - Virgin Sources
[postgresql] / src / backend / executor / nodeUnique.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeUnique.c--
4  *    Routines to handle unique'ing of queries where appropriate
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *    $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.1.1.1 1996/07/09 06:21:27 scrappy Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  * INTERFACE ROUTINES
16  *      ExecUnique      - generate a unique'd temporary relation
17  *      ExecInitUnique  - initialize node and subnodes..
18  *      ExecEndUnique   - shutdown node and subnodes
19  *
20  * NOTES
21  *      Assumes tuples returned from subplan arrive in
22  *      sorted order.
23  *
24  */
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()*/
30
31 /* ----------------------------------------------------------------
32  *      ExecIdenticalTuples
33  *
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  * ----------------------------------------------------------------
43  */
44 static bool     /* true if tuples are identical, false otherwise */
45 ExecIdenticalTuples(TupleTableSlot *t1, TupleTableSlot *t2)
46 {
47     HeapTuple   h1;
48     HeapTuple   h2;
49     char        *d1;
50     char        *d2;
51     int         len;
52     
53     h1 = t1->val;
54     h2 = t2->val;
55     
56     /* ----------------
57      *  if tuples aren't the same length then they are 
58      *  obviously different (one may have null attributes).
59      * ----------------
60      */
61     if (h1->t_len != h2->t_len)
62         return false;
63     
64     /* ----------------
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!!
70      * ----------------
71      */
72     if (h1->t_hoff != h2->t_hoff)
73         return false;
74     
75     /* ----------------
76      *  ok, now get the pointers to the data and the
77      *  size of the attribute portion of the tuple.
78      * ----------------
79      */
80     d1 = (char *) GETSTRUCT(h1);
81     d2 = (char *) GETSTRUCT(h2);
82     len = (int) h1->t_len - (int) h1->t_hoff;
83     
84     /* ----------------
85      *  byte compare the data areas and return the result.
86      * ----------------
87      */
88     if (memcmp(d1, d2, len) != 0)
89         return false;
90     
91     return true;
92 }
93
94 /* ----------------------------------------------------------------
95  *      ExecUnique
96  *
97  *      This is a very simple node which filters out duplicate
98  *      tuples from a stream of sorted tuples from a subplan.
99  *
100  *      XXX see comments below regarding freeing tuples.
101  * ----------------------------------------------------------------
102  */
103 TupleTableSlot *                /* return: a tuple or NULL */
104 ExecUnique(Unique *node)
105 {
106     UniqueState         *uniquestate;
107     TupleTableSlot      *resultTupleSlot;
108     TupleTableSlot      *slot;
109     Plan                *outerPlan;
110     char                *uniqueAttr;
111     AttrNumber          uniqueAttrNum;
112     TupleDesc           tupDesc;
113     Oid                 typoutput;
114     
115     /* ----------------
116      *  get information from the node
117      * ----------------
118      */
119     uniquestate =       node->uniquestate;
120     outerPlan =         outerPlan((Plan *) node);
121     resultTupleSlot =   uniquestate->cs_ResultTupleSlot;
122     uniqueAttr  =       node->uniqueAttr;
123     uniqueAttrNum =     node->uniqueAttrNum;
124
125     if (uniqueAttr) {
126       tupDesc = ExecGetResultType(uniquestate);
127       typoutput = typtoout((Oid)tupDesc->attrs[uniqueAttrNum]->atttypid);
128     }
129       
130     /* ----------------
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.
134      * ----------------
135      */
136     for (;;) {
137         /* ----------------
138          *   fetch a tuple from the outer subplan
139          * ----------------
140          */
141         slot = ExecProcNode(outerPlan, (Plan*)node);
142         if (TupIsNull(slot))
143             return NULL;
144         
145         /* ----------------
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.  
150          * ----------------
151          */
152         if (TupIsNull(resultTupleSlot))
153             break;
154         
155         /* ----------------
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.
159          * ----------------
160          */
161
162         if (uniqueAttr) {
163           /* to check equality, we check to see if the typoutput
164              of the attributes are equal */
165           bool isNull1,isNull2;
166           char *attr1, *attr2;
167           char *val1, *val2;
168
169           attr1 = heap_getattr(slot->val, InvalidBuffer, 
170                                uniqueAttrNum, tupDesc,&isNull1);
171           attr2 = heap_getattr(resultTupleSlot->val, InvalidBuffer, 
172                                uniqueAttrNum, tupDesc,&isNull2);
173
174           if (isNull1 == isNull2) {
175             if (isNull1) /* both are null, they are equal */
176               continue;
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 */
182               continue;
183             else
184               break;
185           }
186           else /* one is null and the other isn't, they aren't equal */
187             break;
188               
189         }
190         else { 
191           if (! ExecIdenticalTuples(slot, resultTupleSlot))
192             break;
193         }
194           
195     }
196     
197     /* ----------------
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.
201      * ----------------
202      */
203     ExecStoreTuple(heap_copytuple(slot->val),
204                    resultTupleSlot,
205                    InvalidBuffer,
206                    true);
207     
208     return resultTupleSlot;
209 }
210
211 /* ----------------------------------------------------------------
212  *      ExecInitUnique
213  *
214  *      This initializes the unique node state structures and
215  *      the node's subplan.
216  * ----------------------------------------------------------------
217  */
218 bool    /* return: initialization status */
219 ExecInitUnique(Unique *node, EState *estate, Plan *parent)
220 {
221     UniqueState     *uniquestate;
222     Plan            *outerPlan;
223     char *uniqueAttr;
224     
225     /* ----------------
226      *  assign execution state to node
227      * ----------------
228      */
229     node->plan.state = estate;
230     
231     /* ----------------
232      *  create new UniqueState for node
233      * ----------------
234      */
235     uniquestate = makeNode(UniqueState);
236     node->uniquestate = uniquestate;
237     uniqueAttr = node->uniqueAttr;
238
239     /* ----------------
240      *  Miscellanious initialization
241      *
242      *       +  assign node's base_id
243      *       +  assign debugging hooks and
244      *
245      *  Unique nodes have no ExprContext initialization because
246      *  they never call ExecQual or ExecTargetList.
247      * ----------------
248      */
249     ExecAssignNodeBaseInfo(estate, uniquestate, parent);
250     
251 #define UNIQUE_NSLOTS 1
252     /* ------------
253      * Tuple table initialization
254      * ------------
255      */
256     ExecInitResultTupleSlot(estate, uniquestate);
257     
258     /* ----------------
259      *  then initialize outer plan
260      * ----------------
261      */
262     outerPlan = outerPlan((Plan *) node);
263     ExecInitNode(outerPlan, estate, (Plan *) node);
264     
265     /* ----------------
266      *  unique nodes do no projections, so initialize
267      *  projection info for this node appropriately
268      * ----------------
269      */
270     ExecAssignResultTypeFromOuterPlan((Plan *)node,uniquestate);
271     uniquestate->cs_ProjInfo = NULL;
272
273     if (uniqueAttr) {
274       TupleDesc tupDesc;
275       int i = 0;
276
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)
280         i++;
281       node->uniqueAttrNum = i+1; /* attribute numbers start from 1 */
282     }
283     else
284       node->uniqueAttrNum = InvalidAttrNumber;
285
286     /* ----------------
287      *  all done.
288      * ----------------
289      */
290     return TRUE;
291 }
292
293 int
294 ExecCountSlotsUnique(Unique *node)
295 {
296     return ExecCountSlotsNode(outerPlan(node)) +
297         ExecCountSlotsNode(innerPlan(node)) +
298             UNIQUE_NSLOTS;
299 }
300
301 /* ----------------------------------------------------------------
302  *      ExecEndUnique
303  *
304  *      This shuts down the subplan and frees resources allocated
305  *      to this node.
306  * ----------------------------------------------------------------
307  */
308 void
309 ExecEndUnique(Unique *node)
310 {
311     UniqueState     *uniquestate;
312     
313     uniquestate = node->uniquestate;
314     ExecEndNode(outerPlan((Plan *) node), (Plan*)node);
315     ExecClearTuple(uniquestate->cs_ResultTupleSlot);
316