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