]> granicus.if.org Git - postgresql/blob - src/backend/executor/execTuples.c
First cut at full support for OUTER JOINs. There are still a few loose
[postgresql] / src / backend / executor / execTuples.c
1 /*-------------------------------------------------------------------------
2  *
3  * execTuples.c
4  *        Routines dealing with the executor tuple tables.      These are used to
5  *        ensure that the executor frees copies of tuples (made by
6  *        ExecTargetList) properly.
7  *
8  *        Routines dealing with the type information for tuples. Currently,
9  *        the type information for a tuple is an array of FormData_pg_attribute.
10  *        This information is needed by routines manipulating tuples
11  *        (getattribute, formtuple, etc.).
12  *
13  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
14  * Portions Copyright (c) 1994, Regents of the University of California
15  *
16  *
17  * IDENTIFICATION
18  *        $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.39 2000/09/12 21:06:48 tgl Exp $
19  *
20  *-------------------------------------------------------------------------
21  */
22 /*
23  * INTERFACE ROUTINES
24  *
25  *       TABLE CREATE/DELETE
26  *              ExecCreateTupleTable    - create a new tuple table
27  *              ExecDropTupleTable      - destroy a table
28  *
29  *       SLOT RESERVERATION
30  *              ExecAllocTableSlot              - find an available slot in the table
31  *
32  *       SLOT ACCESSORS
33  *              ExecStoreTuple                  - store a tuple in the table
34  *              ExecFetchTuple                  - fetch a tuple from the table
35  *              ExecClearTuple                  - clear contents of a table slot
36  *              ExecSlotPolicy                  - return slot's tuple pfree policy
37  *              ExecSetSlotPolicy               - diddle the slot policy
38  *              ExecSlotDescriptor              - type of tuple in a slot
39  *              ExecSetSlotDescriptor   - set a slot's tuple descriptor
40  *              ExecSetSlotDescriptorIsNew - diddle the slot-desc-is-new flag
41  *              ExecSetNewSlotDescriptor - set a desc and the is-new-flag all at once
42  *
43  *       SLOT STATUS PREDICATES
44  *              TupIsNull                               - true when slot contains no tuple(Macro)
45  *              ExecSlotDescriptorIsNew - true if we're now storing a different
46  *                                                                type of tuple in a slot
47  *
48  *       CONVENIENCE INITIALIZATION ROUTINES
49  *              ExecInitResultTupleSlot    \    convenience routines to initialize
50  *              ExecInitScanTupleSlot           \       the various tuple slots for nodes
51  *              ExecInitExtraTupleSlot          /       which store copies of tuples.
52  *              ExecInitNullTupleSlot      /
53  *
54  *       old routines:
55  *              ExecGetTupType                  - get type of tuple returned by this node
56  *              ExecTypeFromTL                  - form a TupleDesc from a target list
57  *
58  *       EXAMPLE OF HOW TABLE ROUTINES WORK
59  *              Suppose we have a query such as retrieve (EMP.name) and we have
60  *              a single SeqScan node in the query plan.
61  *
62  *              At ExecStart()
63  *              ----------------
64  *              - InitPlan() calls ExecCreateTupleTable() to create the tuple
65  *                table which will hold tuples processed by the executor.
66  *
67  *              - ExecInitSeqScan() calls ExecInitScanTupleSlot() and
68  *                ExecInitResultTupleSlot() to reserve places in the tuple
69  *                table for the tuples returned by the access methods and the
70  *                tuples resulting from preforming target list projections.
71  *
72  *              During ExecRun()
73  *              ----------------
74  *              - SeqNext() calls ExecStoreTuple() to place the tuple returned
75  *                by the access methods into the scan tuple slot.
76  *
77  *              - ExecSeqScan() calls ExecStoreTuple() to take the result
78  *                tuple from ExecProject() and place it into the result tuple slot.
79  *
80  *              - ExecutePlan() calls ExecRetrieve() which gets the tuple out of
81  *                the slot passed to it by calling ExecFetchTuple().  this tuple
82  *                is then returned.
83  *
84  *              At ExecEnd()
85  *              ----------------
86  *              - EndPlan() calls ExecDropTupleTable() to clean up any remaining
87  *                tuples left over from executing the query.
88  *
89  *              The important thing to watch in the executor code is how pointers
90  *              to the slots containing tuples are passed instead of the tuples
91  *              themselves.  This facilitates the communication of related information
92  *              (such as whether or not a tuple should be pfreed, what buffer contains
93  *              this tuple, the tuple's tuple descriptor, etc).   Note that much of
94  *              this information is also kept in the ExprContext of each node.
95  *              Soon the executor will be redesigned and ExprContext's will contain
96  *              only slot pointers.  -cim 3/14/91
97  *
98  *       NOTES
99  *              The tuple table stuff is relatively new, put here to alleviate
100  *              the process growth problems in the executor.  The other routines
101  *              are old (from the original lisp system) and may someday become
102  *              obsolete.  -cim 6/23/90
103  *
104  *              In the implementation of nested-dot queries such as
105  *              "retrieve (EMP.hobbies.all)", a single scan may return tuples
106  *              of many types, so now we return pointers to tuple descriptors
107  *              along with tuples returned via the tuple table.  This means
108  *              we now have a bunch of routines to diddle the slot descriptors
109  *              too.  -cim 1/18/90
110  *
111  *              The tuple table stuff depends on the executor/tuptable.h macros,
112  *              and the TupleTableSlot node in execnodes.h.
113  *
114  */
115
116 #include "postgres.h"
117 #include "executor/executor.h"
118
119 #undef ExecStoreTuple
120
121 #include "catalog/pg_type.h"
122 #include "access/heapam.h"
123
124 static TupleTableSlot *NodeGetResultTupleSlot(Plan *node);
125
126
127 /* ----------------------------------------------------------------
128  *                                tuple table create/delete functions
129  * ----------------------------------------------------------------
130  */
131 /* --------------------------------
132  *              ExecCreateTupleTable
133  *
134  *              This creates a new tuple table of the specified initial
135  *              size.  If the size is insufficient, ExecAllocTableSlot()
136  *              will grow the table as necessary.
137  *
138  *              This should be used by InitPlan() to allocate the table.
139  *              The table's address will be stored in the EState structure.
140  * --------------------------------
141  */
142 TupleTable                                              /* return: address of table */
143 ExecCreateTupleTable(int initialSize)   /* initial number of slots in
144                                                                                  * table */
145 {
146         TupleTable      newtable;               /* newly allocated table */
147         TupleTableSlot *array;          /* newly allocated slot array */
148
149         /* ----------------
150          *      sanity checks
151          * ----------------
152          */
153         Assert(initialSize >= 1);
154
155         /* ----------------
156          *      Now allocate our new table along with space for the pointers
157          *      to the tuples.
158          */
159
160         newtable = (TupleTable) palloc(sizeof(TupleTableData));
161         array = (TupleTableSlot *) palloc(initialSize * sizeof(TupleTableSlot));
162
163         /* ----------------
164          *      clean out the slots we just allocated
165          * ----------------
166          */
167         MemSet(array, 0, initialSize * sizeof(TupleTableSlot));
168
169         /* ----------------
170          *      initialize the new table and return it to the caller.
171          * ----------------
172          */
173         newtable->size = initialSize;
174         newtable->next = 0;
175         newtable->array = array;
176
177         return newtable;
178 }
179
180 /* --------------------------------
181  *              ExecDropTupleTable
182  *
183  *              This frees the storage used by the tuple table itself
184  *              and optionally frees the contents of the table also.
185  *              It is expected that this routine be called by EndPlan().
186  * --------------------------------
187  */
188 void
189 ExecDropTupleTable(TupleTable table,    /* tuple table */
190                                    bool shouldFree)             /* true if we should free slot
191                                                                                  * contents */
192 {
193         int                     next;                   /* next available slot */
194         TupleTableSlot *array;          /* start of table array */
195         int                     i;                              /* counter */
196
197         /* ----------------
198          *      sanity checks
199          * ----------------
200          */
201         Assert(table != NULL);
202
203         /* ----------------
204          *      get information from the table
205          * ----------------
206          */
207         array = table->array;
208         next = table->next;
209
210         /* ----------------
211          *      first free all the valid pointers in the tuple array
212          *      and drop refcounts of any referenced buffers,
213          *      if that's what the caller wants.  (There is probably
214          *      no good reason for the caller ever not to want it!)
215          *
216          *      Note: we do nothing about the Tuple Descriptor's
217          *      we store in the slots.  This may have to change (ex: we should
218          *      probably worry about pfreeing tuple descs too) -cim 3/14/91
219          *
220          *      Right now, the handling of tuple pointers and buffer refcounts
221          *      is clean, but the handling of tuple descriptors is NOT; they
222          *      are copied around with wild abandon.  It would take some work
223          *      to make tuple descs pfree'able.  Fortunately, since they're
224          *      normally only made once per scan, it's probably not worth
225          *      worrying about...  tgl 9/21/99
226          * ----------------
227          */
228         if (shouldFree)
229         {
230                 for (i = 0; i < next; i++)
231                         ExecClearTuple(&array[i]);
232         }
233
234         /* ----------------
235          *      finally free the tuple array and the table itself.
236          * ----------------
237          */
238         pfree(array);
239         pfree(table);
240 }
241
242
243 /* ----------------------------------------------------------------
244  *                                tuple table slot reservation functions
245  * ----------------------------------------------------------------
246  */
247 /* --------------------------------
248  *              ExecAllocTableSlot
249  *
250  *              This routine is used to reserve slots in the table for
251  *              use by the various plan nodes.  It is expected to be
252  *              called by the node init routines (ex: ExecInitNestLoop)
253  *              once per slot needed by the node.  Not all nodes need
254  *              slots (some just pass tuples around).
255  * --------------------------------
256  */
257 TupleTableSlot *
258 ExecAllocTableSlot(TupleTable table)
259 {
260         int                     slotnum;                /* new slot number */
261         TupleTableSlot *slot;
262
263         /* ----------------
264          *      sanity checks
265          * ----------------
266          */
267         Assert(table != NULL);
268
269         /* ----------------
270          *      if our table is full we have to allocate a larger
271          *      size table.  Since ExecAllocTableSlot() is only called
272          *      before the table is ever used to store tuples, we don't
273          *      have to worry about the contents of the old table.
274          *      If this changes, then we will have to preserve the contents.
275          *      -cim 6/23/90
276          *
277          *      Unfortunately, we *cannot* do this.  All of the nodes in
278          *      the plan that have already initialized their slots will have
279          *      pointers into _freed_ memory.  This leads to bad ends.  We
280          *      now count the number of slots we will need and create all the
281          *      slots we will need ahead of time.  The if below should never
282          *      happen now.  Fail if it does.  -mer 4 Aug 1992
283          * ----------------
284          */
285         if (table->next >= table->size)
286                 elog(ERROR, "Plan requires more slots than are available"
287                          "\n\tsend mail to your local executor guru to fix this");
288
289         /* ----------------
290          *      at this point, space in the table is guaranteed so we
291          *      reserve the next slot, initialize and return it.
292          * ----------------
293          */
294         slotnum = table->next;
295         table->next++;
296
297         slot = &(table->array[slotnum]);
298
299         /* Make sure the allocated slot is valid (and empty) */
300         slot->type = T_TupleTableSlot;
301         slot->val = (HeapTuple) NULL;
302         slot->ttc_shouldFree = true;
303         slot->ttc_descIsNew = true;
304         slot->ttc_tupleDescriptor = (TupleDesc) NULL;
305         slot->ttc_buffer = InvalidBuffer;
306         slot->ttc_whichplan = -1;
307
308         return slot;
309 }
310
311 /* ----------------------------------------------------------------
312  *                                tuple table slot accessor functions
313  * ----------------------------------------------------------------
314  */
315
316 /* --------------------------------
317  *              ExecStoreTuple
318  *
319  *              This function is used to store a tuple into a specified
320  *              slot in the tuple table.
321  *
322  *              tuple:  tuple to store
323  *              slot:   slot to store it in
324  *              buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
325  *              shouldFree: true if ExecClearTuple should pfree() the tuple
326  *                                      when done with it
327  *
328  * If 'buffer' is not InvalidBuffer, the tuple table code acquires a pin
329  * on the buffer which is held until the slot is cleared, so that the tuple
330  * won't go away on us.
331  *
332  * shouldFree is normally set 'true' for tuples constructed on-the-fly.
333  * It must always be 'false' for tuples that are stored in disk pages,
334  * since we don't want to try to pfree those.
335  *
336  * Another case where it is 'false' is when the referenced tuple is held
337  * in a tuple table slot belonging to a lower-level executor Proc node.
338  * In this case the lower-level slot retains ownership and responsibility
339  * for eventually releasing the tuple.  When this method is used, we must
340  * be certain that the upper-level Proc node will lose interest in the tuple
341  * sooner than the lower-level one does!  If you're not certain, copy the
342  * lower-level tuple with heap_copytuple and let the upper-level table
343  * slot assume ownership of the copy!
344  *
345  * Return value is just the passed-in slot pointer.
346  * --------------------------------
347  */
348 TupleTableSlot *
349 ExecStoreTuple(HeapTuple tuple,
350                            TupleTableSlot *slot,
351                            Buffer buffer,
352                            bool shouldFree)
353 {
354         /* ----------------
355          *      sanity checks
356          * ----------------
357          */
358         Assert(slot != NULL);
359         /* passing shouldFree=true for a tuple on a disk page is not sane */
360         Assert(BufferIsValid(buffer) ? (!shouldFree) : true);
361
362         /* clear out any old contents of the slot */
363         ExecClearTuple(slot);
364
365         /* ----------------
366          *      store the new tuple into the specified slot and
367          *      return the slot into which we stored the tuple.
368          * ----------------
369          */
370         slot->val = tuple;
371         slot->ttc_buffer = buffer;
372         slot->ttc_shouldFree = shouldFree;
373
374         /*
375          * If tuple is on a disk page, keep the page pinned as long as we hold
376          * a pointer into it.
377          */
378         if (BufferIsValid(buffer))
379                 IncrBufferRefCount(buffer);
380
381         return slot;
382 }
383
384 /* --------------------------------
385  *              ExecClearTuple
386  *
387  *              This function is used to clear out a slot in the tuple table.
388  * --------------------------------
389  */
390 TupleTableSlot *                                /* return: slot passed */
391 ExecClearTuple(TupleTableSlot *slot)    /* slot in which to store tuple */
392 {
393         HeapTuple       oldtuple;               /* prior contents of slot */
394
395         /* ----------------
396          *      sanity checks
397          * ----------------
398          */
399         Assert(slot != NULL);
400
401         /* ----------------
402          *      get information from the tuple table
403          * ----------------
404          */
405         oldtuple = slot->val;
406
407         /* ----------------
408          *      free the old contents of the specified slot if necessary.
409          * ----------------
410          */
411         if (slot->ttc_shouldFree && oldtuple != NULL)
412                 heap_freetuple(oldtuple);
413
414         slot->val = (HeapTuple) NULL;
415
416         slot->ttc_shouldFree = true;    /* probably useless code... */
417
418         /* ----------------
419          *      Drop the pin on the referenced buffer, if there is one.
420          * ----------------
421          */
422         if (BufferIsValid(slot->ttc_buffer))
423                 ReleaseBuffer(slot->ttc_buffer);
424
425         slot->ttc_buffer = InvalidBuffer;
426
427         return slot;
428 }
429
430
431 /* --------------------------------
432  *              ExecSlotPolicy
433  *
434  *              This function is used to get the call/don't call pfree
435  *              setting of a slot.      Most executor routines don't need this.
436  *              It's only when you do tricky things like marking tuples for
437  *              merge joins that you need to diddle the slot policy.
438  * --------------------------------
439  */
440 #ifdef NOT_USED
441 bool                                                    /* return: slot policy */
442 ExecSlotPolicy(TupleTableSlot *slot)    /* slot to inspect */
443 {
444         return slot->ttc_shouldFree;
445 }
446
447
448 /* --------------------------------
449  *              ExecSetSlotPolicy
450  *
451  *              This function is used to change the call/don't call pfree
452  *              setting of a slot.      Most executor routines don't need this.
453  *              It's only when you do tricky things like marking tuples for
454  *              merge joins that you need to diddle the slot policy.
455  * --------------------------------
456  */
457 bool                                                    /* return: old slot policy */
458 ExecSetSlotPolicy(TupleTableSlot *slot, /* slot to change */
459                                   bool shouldFree)              /* true if we call pfree() when we
460                                                                                  * gc. */
461 {
462         bool            old_shouldFree = slot->ttc_shouldFree;
463
464         slot->ttc_shouldFree = shouldFree;
465
466         return old_shouldFree;
467 }
468
469 #endif
470
471 /* --------------------------------
472  *              ExecSlotDescriptor
473  *
474  *              This function is used to get the tuple descriptor associated
475  *              with the slot's tuple.
476  *
477  * Now a macro in tuptable.h  -mer 5 March 1992
478  * --------------------------------
479  */
480
481 /* --------------------------------
482  *              ExecSetSlotDescriptor
483  *
484  *              This function is used to set the tuple descriptor associated
485  *              with the slot's tuple.
486  * --------------------------------
487  */
488 TupleDesc                                               /* return: old slot tuple descriptor */
489 ExecSetSlotDescriptor(TupleTableSlot *slot,             /* slot to change */
490                                           TupleDesc tupdesc)            /* tuple descriptor */
491 {
492         TupleDesc       old_tupdesc = slot->ttc_tupleDescriptor;
493
494         slot->ttc_tupleDescriptor = tupdesc;
495         return old_tupdesc;
496 }
497
498 /* --------------------------------
499  *              ExecSetSlotDescriptorIsNew
500  *
501  *              This function is used to change the setting of the "isNew" flag
502  * --------------------------------
503  */
504 void
505 ExecSetSlotDescriptorIsNew(TupleTableSlot *slot,                /* slot to change */
506                                                    bool isNew)  /* "isNew" setting */
507 {
508         slot->ttc_descIsNew = isNew;
509 }
510
511 /* --------------------------------
512  *              ExecSetNewSlotDescriptor
513  *
514  *              This function is used to set the tuple descriptor associated
515  *              with the slot's tuple, and set the "isNew" flag at the same time.
516  * --------------------------------
517  */
518 #ifdef NOT_USED
519 TupleDesc                                               /* return: old slot tuple descriptor */
520 ExecSetNewSlotDescriptor(TupleTableSlot *slot,  /* slot to change */
521                                                  TupleDesc tupdesc)             /* tuple descriptor */
522 {
523         TupleDesc       old_tupdesc = slot->ttc_tupleDescriptor;
524
525         slot->ttc_tupleDescriptor = tupdesc;
526         slot->ttc_descIsNew = true;
527
528         return old_tupdesc;
529 }
530
531 #endif
532
533 /* ----------------------------------------------------------------
534  *                                tuple table slot status predicates
535  * ----------------------------------------------------------------
536  */
537
538 /* --------------------------------
539  *              ExecSlotDescriptorIsNew
540  *
541  *              This function is used to check if the tuple descriptor
542  *              associated with this slot has just changed.  ie: we are
543  *              now storing a new type of tuple in this slot
544  * --------------------------------
545  */
546 #ifdef NOT_USED
547 bool                                                    /* return: descriptor "is new" */
548 ExecSlotDescriptorIsNew(TupleTableSlot *slot)   /* slot to inspect */
549 {
550 /*        bool isNew = SlotTupleDescriptorIsNew((TupleTableSlot*) slot);
551         return isNew; */
552         return slot->ttc_descIsNew;
553 }
554
555 #endif
556
557 /* ----------------------------------------------------------------
558  *                              convenience initialization routines
559  * ----------------------------------------------------------------
560  */
561 /* --------------------------------
562  *              ExecInit{Result,Scan,Extra}TupleSlot
563  *
564  *              These are convenience routines to initialize the specified slot
565  *              in nodes inheriting the appropriate state.  ExecInitExtraTupleSlot
566  *              is used for initializing special-purpose slots.
567  * --------------------------------
568  */
569 #define INIT_SLOT_DEFS \
570         TupleTable         tupleTable; \
571         TupleTableSlot*   slot
572
573 #define INIT_SLOT_ALLOC \
574         tupleTable = (TupleTable) estate->es_tupleTable; \
575         slot =           ExecAllocTableSlot(tupleTable);
576
577 /* ----------------
578  *              ExecInitResultTupleSlot
579  * ----------------
580  */
581 void
582 ExecInitResultTupleSlot(EState *estate, CommonState *commonstate)
583 {
584         INIT_SLOT_DEFS;
585         INIT_SLOT_ALLOC;
586         commonstate->cs_ResultTupleSlot = slot;
587 }
588
589 /* ----------------
590  *              ExecInitScanTupleSlot
591  * ----------------
592  */
593 void
594 ExecInitScanTupleSlot(EState *estate, CommonScanState *commonscanstate)
595 {
596         INIT_SLOT_DEFS;
597         INIT_SLOT_ALLOC;
598         commonscanstate->css_ScanTupleSlot = slot;
599 }
600
601 /* ----------------
602  *              ExecInitExtraTupleSlot
603  * ----------------
604  */
605 TupleTableSlot *
606 ExecInitExtraTupleSlot(EState *estate)
607 {
608         INIT_SLOT_DEFS;
609         INIT_SLOT_ALLOC;
610         return slot;
611 }
612
613 /* ----------------
614  *              ExecInitNullTupleSlot
615  *
616  * Build a slot containing an all-nulls tuple of the given type.
617  * This is used as a substitute for an input tuple when performing an
618  * outer join.
619  * ----------------
620  */
621 TupleTableSlot *
622 ExecInitNullTupleSlot(EState *estate, TupleDesc tupType)
623 {
624         TupleTableSlot*   slot = ExecInitExtraTupleSlot(estate);
625         /*
626          * Since heap_getattr() will treat attributes beyond a tuple's t_natts
627          * as being NULL, we can make an all-nulls tuple just by making it be of
628          * zero length.  However, the slot descriptor must match the real tupType.
629          */
630         HeapTuple       nullTuple;
631         Datum           values[1];
632         char            nulls[1];
633         static struct tupleDesc NullTupleDesc;          /* we assume this inits to
634                                                                                                  * zeroes */
635
636         ExecSetSlotDescriptor(slot, tupType);
637
638         nullTuple = heap_formtuple(&NullTupleDesc, values, nulls);
639
640         return ExecStoreTuple(nullTuple, slot, InvalidBuffer, true);
641 }
642
643
644 static TupleTableSlot *
645 NodeGetResultTupleSlot(Plan *node)
646 {
647         TupleTableSlot *slot;
648
649         switch (nodeTag(node))
650         {
651
652                 case T_Result:
653                         {
654                                 ResultState *resstate = ((Result *) node)->resstate;
655
656                                 slot = resstate->cstate.cs_ResultTupleSlot;
657                         }
658                         break;
659
660                 case T_SeqScan:
661                         {
662                                 CommonScanState *scanstate = ((SeqScan *) node)->scanstate;
663
664                                 slot = scanstate->cstate.cs_ResultTupleSlot;
665                         }
666                         break;
667
668                 case T_NestLoop:
669                         {
670                                 NestLoopState *nlstate = ((NestLoop *) node)->nlstate;
671
672                                 slot = nlstate->jstate.cs_ResultTupleSlot;
673                         }
674                         break;
675
676                 case T_Append:
677                         {
678                                 Append     *n = (Append *) node;
679                                 AppendState *appendstate;
680                                 List       *appendplans;
681                                 int                     whichplan;
682                                 Plan       *subplan;
683
684                                 appendstate = n->appendstate;
685                                 appendplans = n->appendplans;
686                                 whichplan = appendstate->as_whichplan;
687
688                                 subplan = (Plan *) nth(whichplan, appendplans);
689                                 slot = NodeGetResultTupleSlot(subplan);
690                                 break;
691                         }
692
693                 case T_IndexScan:
694                         {
695                                 CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
696
697                                 slot = scanstate->cstate.cs_ResultTupleSlot;
698                         }
699                         break;
700
701                 case T_Material:
702                         {
703                                 MaterialState *matstate = ((Material *) node)->matstate;
704
705                                 slot = matstate->csstate.css_ScanTupleSlot;
706                         }
707                         break;
708
709                 case T_Sort:
710                         {
711                                 SortState  *sortstate = ((Sort *) node)->sortstate;
712
713                                 slot = sortstate->csstate.css_ScanTupleSlot;
714                         }
715                         break;
716
717                 case T_Agg:
718                         {
719                                 AggState   *aggstate = ((Agg *) node)->aggstate;
720
721                                 slot = aggstate->csstate.cstate.cs_ResultTupleSlot;
722                         }
723                         break;
724
725                 case T_Group:
726                         {
727                                 GroupState *grpstate = ((Group *) node)->grpstate;
728
729                                 slot = grpstate->csstate.cstate.cs_ResultTupleSlot;
730                         }
731                         break;
732
733                 case T_Hash:
734                         {
735                                 HashState  *hashstate = ((Hash *) node)->hashstate;
736
737                                 slot = hashstate->cstate.cs_ResultTupleSlot;
738                         }
739                         break;
740
741                 case T_Unique:
742                         {
743                                 UniqueState *uniquestate = ((Unique *) node)->uniquestate;
744
745                                 slot = uniquestate->cstate.cs_ResultTupleSlot;
746                         }
747                         break;
748
749                 case T_MergeJoin:
750                         {
751                                 MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate;
752
753                                 slot = mergestate->jstate.cs_ResultTupleSlot;
754                         }
755                         break;
756
757                 case T_HashJoin:
758                         {
759                                 HashJoinState *hashjoinstate = ((HashJoin *) node)->hashjoinstate;
760
761                                 slot = hashjoinstate->jstate.cs_ResultTupleSlot;
762                         }
763                         break;
764
765                 case T_TidScan:
766                         {
767                                 CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
768
769                                 slot = scanstate->cstate.cs_ResultTupleSlot;
770                         }
771                         break;
772
773                 default:
774                         /* ----------------
775                          *        should never get here
776                          * ----------------
777                          */
778                         elog(ERROR, "NodeGetResultTupleSlot: node not yet supported: %d ",
779                                  nodeTag(node));
780
781                         return NULL;
782         }
783         return slot;
784 }
785
786 /* ----------------------------------------------------------------
787  *              ExecGetTupType
788  *
789  *              this gives you the tuple descriptor for tuples returned
790  *              by this node.  I really wish I could ditch this routine,
791  *              but since not all nodes store their type info in the same
792  *              place, we have to do something special for each node type.
793  *
794  *              Soon, the system will have to adapt to deal with changing
795  *              tuple descriptors as we deal with dynamic tuple types
796  *              being returned from procedure nodes.  Perhaps then this
797  *              routine can be retired.  -cim 6/3/91
798  *
799  * old comments
800  *              This routine just gets the type information out of the
801  *              node's state.  If you already have a node's state, you
802  *              can get this information directly, but this is a useful
803  *              routine if you want to get the type information from
804  *              the node's inner or outer subplan easily without having
805  *              to inspect the subplan.. -cim 10/16/89
806  *
807  * ----------------------------------------------------------------
808  */
809
810 TupleDesc
811 ExecGetTupType(Plan *node)
812 {
813         TupleTableSlot *slot;
814         TupleDesc       tupType;
815
816         if (node == NULL)
817                 return NULL;
818
819         slot = NodeGetResultTupleSlot(node);
820         tupType = slot->ttc_tupleDescriptor;
821         return tupType;
822 }
823
824 /*
825 TupleDesc
826 ExecCopyTupType(TupleDesc td, int natts)
827 {
828         TupleDesc newTd;
829         int                             i;
830
831         newTd = CreateTemplateTupleDesc(natts);
832         i = 0;
833         while (i < natts)
834                 {
835                         newTd[i] = (Form_pg_attribute)palloc(sizeof(FormData_pg_attribute));
836                         memmove(newTd[i], td[i], sizeof(FormData_pg_attribute));
837                         i++;
838                 }
839         return newTd;
840 }
841 */
842
843 /* ----------------------------------------------------------------
844  *              ExecTypeFromTL
845  *
846  *              Currently there are about 4 different places where we create
847  *              TupleDescriptors.  They should all be merged, or perhaps
848  *              be rewritten to call BuildDesc().
849  *
850  *      old comments
851  *              Forms attribute type info from the target list in the node.
852  *              It assumes all domains are individually specified in the target list.
853  *              It fails if the target list contains something like Emp.all
854  *              which represents all the attributes from EMP relation.
855  *
856  *              Conditions:
857  *                      The inner and outer subtrees should be initialized because it
858  *                      might be necessary to know the type infos of the subtrees.
859  * ----------------------------------------------------------------
860  */
861 TupleDesc
862 ExecTypeFromTL(List *targetList)
863 {
864         List       *tlcdr;
865         TupleDesc       typeInfo;
866         Resdom     *resdom;
867         Oid                     restype;
868         int                     len;
869
870         /* ----------------
871          *      examine targetlist - if empty then return NULL
872          * ----------------
873          */
874         len = ExecTargetListLength(targetList);
875
876         if (len == 0)
877                 return NULL;
878
879         /* ----------------
880          *      allocate a new typeInfo
881          * ----------------
882          */
883         typeInfo = CreateTemplateTupleDesc(len);
884
885         /* ----------------
886          * notes: get resdom from (resdom expr)
887          *                get_typbyval comes from src/lib/l-lisp/lsyscache.c
888          * ----------------
889          */
890         tlcdr = targetList;
891         while (tlcdr != NIL)
892         {
893                 TargetEntry *tle = lfirst(tlcdr);
894
895                 if (tle->resdom != NULL)
896                 {
897                         resdom = tle->resdom;
898                         restype = resdom->restype;
899
900                         TupleDescInitEntry(typeInfo,
901                                                            resdom->resno,
902                                                            resdom->resname,
903                         /* fix for SELECT NULL ... */
904                                                            (restype ? restype : UNKNOWNOID),
905                                                            resdom->restypmod,
906                                                            0,
907                                                            false);
908
909 /*
910                         ExecSetTypeInfo(resdom->resno - 1,
911                                                         typeInfo,
912                                                         (Oid) restype,
913                                                         resdom->resno,
914                                                         resdom->reslen,
915                                                         NameStr(*resdom->resname),
916                                                         get_typbyval(restype),
917                                                         get_typalign(restype));
918 */
919                 }
920                 else
921                 {
922                         Resdom     *fjRes;
923                         List       *fjTlistP;
924                         List       *fjList = lfirst(tlcdr);
925
926 #ifdef SETS_FIXED
927                         TargetEntry *tle;
928                         Fjoin      *fjNode = ((TargetEntry *) lfirst(fjList))->fjoin;
929
930                         tle = fjNode->fj_innerNode; /* ??? */
931 #endif
932                         fjRes = tle->resdom;
933                         restype = fjRes->restype;
934
935                         TupleDescInitEntry(typeInfo,
936                                                            fjRes->resno,
937                                                            fjRes->resname,
938                                                            restype,
939                                                            fjRes->restypmod,
940                                                            0,
941                                                            false);
942 /*
943                         ExecSetTypeInfo(fjRes->resno - 1,
944                                                         typeInfo,
945                                                         (Oid) restype,
946                                                         fjRes->resno,
947                                                         fjRes->reslen,
948                                                         (char *) fjRes->resname,
949                                                         get_typbyval(restype),
950                                                         get_typalign(restype));
951 */
952
953                         foreach(fjTlistP, lnext(fjList))
954                         {
955                                 TargetEntry *fjTle = lfirst(fjTlistP);
956
957                                 fjRes = fjTle->resdom;
958
959                                 TupleDescInitEntry(typeInfo,
960                                                                    fjRes->resno,
961                                                                    fjRes->resname,
962                                                                    restype,
963                                                                    fjRes->restypmod,
964                                                                    0,
965                                                                    false);
966
967 /*
968                                 ExecSetTypeInfo(fjRes->resno - 1,
969                                                                 typeInfo,
970                                                                 (Oid) fjRes->restype,
971                                                                 fjRes->resno,
972                                                                 fjRes->reslen,
973                                                                 (char *) fjRes->resname,
974                                                                 get_typbyval(fjRes->restype),
975                                                                 get_typalign(fjRes->restype));
976 */
977                         }
978                 }
979
980                 tlcdr = lnext(tlcdr);
981         }
982
983         return typeInfo;
984 }