aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execTuples.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execTuples.c')
-rw-r--r--src/backend/executor/execTuples.c1526
1 files changed, 781 insertions, 745 deletions
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 0d5e7fda9fb..287f75699af 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -1,119 +1,119 @@
/*-------------------------------------------------------------------------
*
* execTuples.c--
- * Routines dealing with the executor tuple tables. These are used to
- * ensure that the executor frees copies of tuples (made by
- * ExecTargetList) properly.
+ * Routines dealing with the executor tuple tables. These are used to
+ * ensure that the executor frees copies of tuples (made by
+ * ExecTargetList) properly.
+ *
+ * Routines dealing with the type information for tuples. Currently,
+ * the type information for a tuple is an array of FormData_pg_attribute.
+ * This information is needed by routines manipulating tuples
+ * (getattribute, formtuple, etc.).
*
- * Routines dealing with the type information for tuples. Currently,
- * the type information for a tuple is an array of FormData_pg_attribute.
- * This information is needed by routines manipulating tuples
- * (getattribute, formtuple, etc.).
- *
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.6 1997/08/19 21:31:05 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.7 1997/09/07 04:41:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
*
- * TABLE CREATE/DELETE
- * ExecCreateTupleTable - create a new tuple table
- * ExecDestroyTupleTable - destroy a table
+ * TABLE CREATE/DELETE
+ * ExecCreateTupleTable - create a new tuple table
+ * ExecDestroyTupleTable - destroy a table
*
- * SLOT RESERVERATION
- * ExecAllocTableSlot - find an available slot in the table
+ * SLOT RESERVERATION
+ * ExecAllocTableSlot - find an available slot in the table
*
- * SLOT ACCESSORS
- * ExecStoreTuple - store a tuple in the table
- * ExecFetchTuple - fetch a tuple from the table
- * ExecClearTuple - clear contents of a table slot
- * ExecSlotPolicy - return slot's tuple pfree policy
- * ExecSetSlotPolicy - diddle the slot policy
- * ExecSlotDescriptor - type of tuple in a slot
- * ExecSetSlotDescriptor - set a slot's tuple descriptor
- * ExecSetSlotDescriptorIsNew - diddle the slot-desc-is-new flag
- * ExecSetNewSlotDescriptor - set a desc and the is-new-flag all at once
- * ExecSlotBuffer - return buffer of tuple in slot
- * ExecSetSlotBuffer - set the buffer for tuple in slot
- * ExecIncrSlotBufferRefcnt - bump the refcnt of the slot buffer
+ * SLOT ACCESSORS
+ * ExecStoreTuple - store a tuple in the table
+ * ExecFetchTuple - fetch a tuple from the table
+ * ExecClearTuple - clear contents of a table slot
+ * ExecSlotPolicy - return slot's tuple pfree policy
+ * ExecSetSlotPolicy - diddle the slot policy
+ * ExecSlotDescriptor - type of tuple in a slot
+ * ExecSetSlotDescriptor - set a slot's tuple descriptor
+ * ExecSetSlotDescriptorIsNew - diddle the slot-desc-is-new flag
+ * ExecSetNewSlotDescriptor - set a desc and the is-new-flag all at once
+ * ExecSlotBuffer - return buffer of tuple in slot
+ * ExecSetSlotBuffer - set the buffer for tuple in slot
+ * ExecIncrSlotBufferRefcnt - bump the refcnt of the slot buffer
*
- * SLOT STATUS PREDICATES
- * TupIsNull - true when slot contains no tuple
- * ExecSlotDescriptorIsNew - true if we're now storing a different
- * type of tuple in a slot
+ * SLOT STATUS PREDICATES
+ * TupIsNull - true when slot contains no tuple
+ * ExecSlotDescriptorIsNew - true if we're now storing a different
+ * type of tuple in a slot
*
- * CONVENIENCE INITIALIZATION ROUTINES
- * ExecInitResultTupleSlot \ convience routines to initialize
- * ExecInitScanTupleSlot \ the various tuple slots for nodes
- * ExecInitMarkedTupleSlot / which store copies of tuples.
- * ExecInitOuterTupleSlot /
- * ExecInitHashTupleSlot /
+ * CONVENIENCE INITIALIZATION ROUTINES
+ * ExecInitResultTupleSlot \ convience routines to initialize
+ * ExecInitScanTupleSlot \ the various tuple slots for nodes
+ * ExecInitMarkedTupleSlot / which store copies of tuples.
+ * ExecInitOuterTupleSlot /
+ * ExecInitHashTupleSlot /
*
- * old routines:
- * ExecGetTupType - get type of tuple returned by this node
- * ExecTypeFromTL - form a TupleDesc from a target list
+ * old routines:
+ * ExecGetTupType - get type of tuple returned by this node
+ * ExecTypeFromTL - form a TupleDesc from a target list
*
- * EXAMPLE OF HOW TABLE ROUTINES WORK
- * Suppose we have a query such as retrieve (EMP.name) and we have
- * a single SeqScan node in the query plan.
+ * EXAMPLE OF HOW TABLE ROUTINES WORK
+ * Suppose we have a query such as retrieve (EMP.name) and we have
+ * a single SeqScan node in the query plan.
*
- * At ExecStart()
- * ----------------
- * - InitPlan() calls ExecCreateTupleTable() to create the tuple
- * table which will hold tuples processed by the executor.
+ * At ExecStart()
+ * ----------------
+ * - InitPlan() calls ExecCreateTupleTable() to create the tuple
+ * table which will hold tuples processed by the executor.
*
- * - ExecInitSeqScan() calls ExecInitScanTupleSlot() and
- * ExecInitResultTupleSlot() to reserve places in the tuple
- * table for the tuples returned by the access methods and the
- * tuples resulting from preforming target list projections.
+ * - ExecInitSeqScan() calls ExecInitScanTupleSlot() and
+ * ExecInitResultTupleSlot() to reserve places in the tuple
+ * table for the tuples returned by the access methods and the
+ * tuples resulting from preforming target list projections.
*
- * During ExecRun()
- * ----------------
- * - SeqNext() calls ExecStoreTuple() to place the tuple returned
- * by the access methods into the scan tuple slot.
+ * During ExecRun()
+ * ----------------
+ * - SeqNext() calls ExecStoreTuple() to place the tuple returned
+ * by the access methods into the scan tuple slot.
*
- * - ExecSeqScan() calls ExecStoreTuple() to take the result
- * tuple from ExecTargetList() and place it into the result tuple
- * slot.
+ * - ExecSeqScan() calls ExecStoreTuple() to take the result
+ * tuple from ExecTargetList() and place it into the result tuple
+ * slot.
*
- * - ExecutePlan() calls ExecRetrieve() which gets the tuple out of
- * the slot passed to it by calling ExecFetchTuple(). this tuple
- * is then returned.
+ * - ExecutePlan() calls ExecRetrieve() which gets the tuple out of
+ * the slot passed to it by calling ExecFetchTuple(). this tuple
+ * is then returned.
*
- * At ExecEnd()
- * ----------------
- * - EndPlan() calls ExecDestroyTupleTable() to clean up any remaining
- * tuples left over from executing the query.
+ * At ExecEnd()
+ * ----------------
+ * - EndPlan() calls ExecDestroyTupleTable() to clean up any remaining
+ * tuples left over from executing the query.
*
- * The important thing to watch in the executor code is how pointers
- * to the slots containing tuples are passed instead of the tuples
- * themselves. This facilitates the communication of related information
- * (such as whether or not a tuple should be pfreed, what buffer contains
- * this tuple, the tuple's tuple descriptor, etc). Note that much of
- * this information is also kept in the ExprContext of each node.
- * Soon the executor will be redesigned and ExprContext's will contain
- * only slot pointers. -cim 3/14/91
+ * The important thing to watch in the executor code is how pointers
+ * to the slots containing tuples are passed instead of the tuples
+ * themselves. This facilitates the communication of related information
+ * (such as whether or not a tuple should be pfreed, what buffer contains
+ * this tuple, the tuple's tuple descriptor, etc). Note that much of
+ * this information is also kept in the ExprContext of each node.
+ * Soon the executor will be redesigned and ExprContext's will contain
+ * only slot pointers. -cim 3/14/91
*
- * NOTES
- * The tuple table stuff is relatively new, put here to alleviate
- * the process growth problems in the executor. The other routines
- * are old (from the original lisp system) and may someday become
- * obsolete. -cim 6/23/90
+ * NOTES
+ * The tuple table stuff is relatively new, put here to alleviate
+ * the process growth problems in the executor. The other routines
+ * are old (from the original lisp system) and may someday become
+ * obsolete. -cim 6/23/90
*
- * In the implementation of nested-dot queries such as
- * "retrieve (EMP.hobbies.all)", a single scan may return tuples
- * of many types, so now we return pointers to tuple descriptors
- * along with tuples returned via the tuple table. This means
- * we now have a bunch of routines to diddle the slot descriptors
- * too. -cim 1/18/90
+ * In the implementation of nested-dot queries such as
+ * "retrieve (EMP.hobbies.all)", a single scan may return tuples
+ * of many types, so now we return pointers to tuple descriptors
+ * along with tuples returned via the tuple table. This means
+ * we now have a bunch of routines to diddle the slot descriptors
+ * too. -cim 1/18/90
*
- * The tuple table stuff depends on the executor/tuptable.h macros,
- * and the TupleTableSlot node in execnodes.h.
+ * The tuple table stuff depends on the executor/tuptable.h macros,
+ * and the TupleTableSlot node in execnodes.h.
*
*/
#include <string.h>
@@ -131,902 +131,938 @@
#include "parser/catalog_utils.h"
#include "catalog/pg_type.h"
-static TupleTableSlot *NodeGetResultTupleSlot(Plan *node);
+static TupleTableSlot *NodeGetResultTupleSlot(Plan * node);
/* ----------------------------------------------------------------
- * tuple table create/delete functions
+ * tuple table create/delete functions
* ----------------------------------------------------------------
*/
/* --------------------------------
- * ExecCreateTupleTable
+ * ExecCreateTupleTable
*
- * This creates a new tuple table of the specified initial
- * size. If the size is insufficient, ExecAllocTableSlot()
- * will grow the table as necessary.
+ * This creates a new tuple table of the specified initial
+ * size. If the size is insufficient, ExecAllocTableSlot()
+ * will grow the table as necessary.
*
- * This should be used by InitPlan() to allocate the table.
- * The table's address will be stored in the EState structure.
+ * This should be used by InitPlan() to allocate the table.
+ * The table's address will be stored in the EState structure.
* --------------------------------
*/
-TupleTable /* return: address of table */
-ExecCreateTupleTable(int initialSize) /* initial number of slots in table */
+TupleTable /* return: address of table */
+ExecCreateTupleTable(int initialSize) /* initial number of slots
+ * in table */
{
- TupleTable newtable; /* newly allocated table */
- TupleTableSlot* array; /* newly allocated slot array */
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(initialSize >= 1);
-
- /* ----------------
- * Now allocate our new table along with space for the pointers
- * to the tuples.
- */
-
- newtable = (TupleTable) palloc(sizeof(TupleTableData));
- array = (TupleTableSlot*) palloc(initialSize * sizeof(TupleTableSlot));
-
- /* ----------------
- * clean out the slots we just allocated
- * ----------------
- */
- memset(array, 0, initialSize * sizeof(TupleTableSlot));
-
- /* ----------------
- * initialize the new table and return it to the caller.
- * ----------------
- */
- newtable->size = initialSize;
- newtable->next = 0;
- newtable->array = array;
-
- return newtable;
+ TupleTable newtable; /* newly allocated table */
+ TupleTableSlot *array; /* newly allocated slot array */
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(initialSize >= 1);
+
+ /* ----------------
+ * Now allocate our new table along with space for the pointers
+ * to the tuples.
+ */
+
+ newtable = (TupleTable) palloc(sizeof(TupleTableData));
+ array = (TupleTableSlot *) palloc(initialSize * sizeof(TupleTableSlot));
+
+ /* ----------------
+ * clean out the slots we just allocated
+ * ----------------
+ */
+ memset(array, 0, initialSize * sizeof(TupleTableSlot));
+
+ /* ----------------
+ * initialize the new table and return it to the caller.
+ * ----------------
+ */
+ newtable->size = initialSize;
+ newtable->next = 0;
+ newtable->array = array;
+
+ return newtable;
}
/* --------------------------------
- * ExecDestroyTupleTable
+ * ExecDestroyTupleTable
*
- * This pfrees the storage assigned to the tuple table and
- * optionally pfrees the contents of the table also.
- * It is expected that this routine be called by EndPlan().
+ * This pfrees the storage assigned to the tuple table and
+ * optionally pfrees the contents of the table also.
+ * It is expected that this routine be called by EndPlan().
* --------------------------------
*/
void
-ExecDestroyTupleTable(TupleTable table, /* tuple table */
- bool shouldFree) /* true if we should free slot contents */
+ExecDestroyTupleTable(TupleTable table, /* tuple table */
+ bool shouldFree) /* true if we should free slot
+ * contents */
{
- int next; /* next avaliable slot */
- TupleTableSlot *array; /* start of table array */
- int i; /* counter */
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(table != NULL);
-
- /* ----------------
- * get information from the table
- * ----------------
- */
- array = table->array;
- next = table->next;
-
- /* ----------------
- * first free all the valid pointers in the tuple array
- * if that's what the caller wants..
- *
- * Note: we do nothing about the Buffer and Tuple Descriptor's
- * we store in the slots. This may have to change (ex: we should
- * probably worry about pfreeing tuple descs too) -cim 3/14/91
- * ----------------
- */
- if (shouldFree)
- for (i = 0; i < next; i++) {
- TupleTableSlot slot;
- HeapTuple tuple;
-
- slot = array[i];
- tuple = slot.val;
-
- if (tuple != NULL) {
- slot.val = (HeapTuple)NULL;
- if (slot.ttc_shouldFree) {
- /* ----------------
- * since a tuple may contain a pointer to
- * lock information allocated along with the
- * tuple, we have to be careful to free any
- * rule locks also -cim 1/17/90
- * ----------------
- */
- pfree(tuple);
+ int next; /* next avaliable slot */
+ TupleTableSlot *array; /* start of table array */
+ int i; /* counter */
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(table != NULL);
+
+ /* ----------------
+ * get information from the table
+ * ----------------
+ */
+ array = table->array;
+ next = table->next;
+
+ /* ----------------
+ * first free all the valid pointers in the tuple array
+ * if that's what the caller wants..
+ *
+ * Note: we do nothing about the Buffer and Tuple Descriptor's
+ * we store in the slots. This may have to change (ex: we should
+ * probably worry about pfreeing tuple descs too) -cim 3/14/91
+ * ----------------
+ */
+ if (shouldFree)
+ for (i = 0; i < next; i++)
+ {
+ TupleTableSlot slot;
+ HeapTuple tuple;
+
+ slot = array[i];
+ tuple = slot.val;
+
+ if (tuple != NULL)
+ {
+ slot.val = (HeapTuple) NULL;
+ if (slot.ttc_shouldFree)
+ {
+ /* ----------------
+ * since a tuple may contain a pointer to
+ * lock information allocated along with the
+ * tuple, we have to be careful to free any
+ * rule locks also -cim 1/17/90
+ * ----------------
+ */
+ pfree(tuple);
+ }
+ }
}
- }
- }
-
- /* ----------------
- * finally free the tuple array and the table itself.
- * ----------------
- */
- pfree(array);
- pfree(table);
-
+
+ /* ----------------
+ * finally free the tuple array and the table itself.
+ * ----------------
+ */
+ pfree(array);
+ pfree(table);
+
}
/* ----------------------------------------------------------------
- * tuple table slot reservation functions
+ * tuple table slot reservation functions
* ----------------------------------------------------------------
*/
/* --------------------------------
- * ExecAllocTableSlot
+ * ExecAllocTableSlot
*
- * This routine is used to reserve slots in the table for
- * use by the various plan nodes. It is expected to be
- * called by the node init routines (ex: ExecInitNestLoop).
- * once per slot needed by the node. Not all nodes need
- * slots (some just pass tuples around).
+ * This routine is used to reserve slots in the table for
+ * use by the various plan nodes. It is expected to be
+ * called by the node init routines (ex: ExecInitNestLoop).
+ * once per slot needed by the node. Not all nodes need
+ * slots (some just pass tuples around).
* --------------------------------
*/
-TupleTableSlot* /* return: the slot allocated in the tuple table */
+TupleTableSlot * /* return: the slot allocated in the tuple
+ * table */
ExecAllocTableSlot(TupleTable table)
{
- int slotnum; /* new slot number */
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(table != NULL);
-
- /* ----------------
- * if our table is full we have to allocate a larger
- * size table. Since ExecAllocTableSlot() is only called
- * before the table is ever used to store tuples, we don't
- * have to worry about the contents of the old table.
- * If this changes, then we will have to preserve the contents.
- * -cim 6/23/90
- *
- * Unfortunately, we *cannot* do this. All of the nodes in
- * the plan that have already initialized their slots will have
- * pointers into _freed_ memory. This leads to bad ends. We
- * now count the number of slots we will need and create all the
- * slots we will need ahead of time. The if below should never
- * happen now. Give a WARN if it does. -mer 4 Aug 1992
- * ----------------
- */
- if (table->next >= table->size) {
- /*
- * int newsize = NewTableSize(table->size);
+ int slotnum; /* new slot number */
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(table != NULL);
+
+ /* ----------------
+ * if our table is full we have to allocate a larger
+ * size table. Since ExecAllocTableSlot() is only called
+ * before the table is ever used to store tuples, we don't
+ * have to worry about the contents of the old table.
+ * If this changes, then we will have to preserve the contents.
+ * -cim 6/23/90
*
- * pfree(table->array);
- * table->array = (Pointer) palloc(newsize * TableSlotSize);
- * bzero(table->array, newsize * TableSlotSize);
- * table->size = newsize;
+ * Unfortunately, we *cannot* do this. All of the nodes in
+ * the plan that have already initialized their slots will have
+ * pointers into _freed_ memory. This leads to bad ends. We
+ * now count the number of slots we will need and create all the
+ * slots we will need ahead of time. The if below should never
+ * happen now. Give a WARN if it does. -mer 4 Aug 1992
+ * ----------------
*/
- elog(NOTICE, "Plan requires more slots than are available");
- elog(WARN, "send mail to your local executor guru to fix this");
- }
-
- /* ----------------
- * at this point, space in the table is guaranteed so we
- * reserve the next slot, initialize and return it.
- * ----------------
- */
- slotnum = table->next;
- table->next++;
-
- table->array[slotnum].type = T_TupleTableSlot;
-
- return &(table->array[slotnum]);
+ if (table->next >= table->size)
+ {
+
+ /*
+ * int newsize = NewTableSize(table->size);
+ *
+ * pfree(table->array); table->array = (Pointer) palloc(newsize *
+ * TableSlotSize); bzero(table->array, newsize * TableSlotSize);
+ * table->size = newsize;
+ */
+ elog(NOTICE, "Plan requires more slots than are available");
+ elog(WARN, "send mail to your local executor guru to fix this");
+ }
+
+ /* ----------------
+ * at this point, space in the table is guaranteed so we
+ * reserve the next slot, initialize and return it.
+ * ----------------
+ */
+ slotnum = table->next;
+ table->next++;
+
+ table->array[slotnum].type = T_TupleTableSlot;
+
+ return &(table->array[slotnum]);
}
/* ----------------------------------------------------------------
- * tuple table slot accessor functions
+ * tuple table slot accessor functions
* ----------------------------------------------------------------
*/
/* --------------------------------
- * ExecStoreTuple
+ * ExecStoreTuple
*
- * This function is used to store a tuple into a specified
- * slot in the tuple table. Note: the only slots which should
- * be called with shouldFree == false are those slots used to
- * store tuples not allocated with pfree(). Currently the
- * seqscan and indexscan nodes use this for the tuples returned
- * by amgetattr, which are actually pointers onto disk pages.
+ * This function is used to store a tuple into a specified
+ * slot in the tuple table. Note: the only slots which should
+ * be called with shouldFree == false are those slots used to
+ * store tuples not allocated with pfree(). Currently the
+ * seqscan and indexscan nodes use this for the tuples returned
+ * by amgetattr, which are actually pointers onto disk pages.
* --------------------------------
*/
-TupleTableSlot* /* return: slot passed */
-ExecStoreTuple(HeapTuple tuple, /* tuple to store */
- TupleTableSlot* slot, /* slot in which to store tuple */
- Buffer buffer, /* buffer associated with tuple */
- bool shouldFree) /* true if we call pfree() when we gc. */
+TupleTableSlot * /* return: slot passed */
+ExecStoreTuple(HeapTuple tuple, /* tuple to store */
+ TupleTableSlot * slot, /* slot in which to store tuple */
+ Buffer buffer, /* buffer associated with tuple */
+ bool shouldFree) /* true if we call pfree() when we gc. */
{
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(slot != NULL);
-
- /* clear out the slot first */
- ExecClearTuple(slot);
-
- /* ----------------
- * store the new tuple into the specified slot and
- * return the slot into which we stored the tuple.
- * ----------------
- */
- slot->val = tuple;
- slot->ttc_buffer = buffer;
- slot->ttc_shouldFree = shouldFree;
-
- return slot;
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(slot != NULL);
+
+ /* clear out the slot first */
+ ExecClearTuple(slot);
+
+ /* ----------------
+ * store the new tuple into the specified slot and
+ * return the slot into which we stored the tuple.
+ * ----------------
+ */
+ slot->val = tuple;
+ slot->ttc_buffer = buffer;
+ slot->ttc_shouldFree = shouldFree;
+
+ return slot;
}
/* --------------------------------
- * ExecClearTuple
+ * ExecClearTuple
*
- * This function is used to clear out a slot in the tuple table.
+ * This function is used to clear out a slot in the tuple table.
* --------------------------------
*/
-TupleTableSlot* /* return: slot passed */
-ExecClearTuple(TupleTableSlot* slot) /* slot in which to store tuple */
+TupleTableSlot * /* return: slot passed */
+ExecClearTuple(TupleTableSlot * slot) /* slot in which to store tuple */
{
- HeapTuple oldtuple; /* prior contents of slot */
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(slot != NULL);
-
- /* ----------------
- * get information from the tuple table
- * ----------------
- */
- oldtuple = slot->val;
-
- /* ----------------
- * free the old contents of the specified slot if necessary.
- * ----------------
- */
- if (slot->ttc_shouldFree && oldtuple != NULL) {
+ HeapTuple oldtuple; /* prior contents of slot */
+
/* ----------------
- * since a tuple may contain a pointer to
- * lock information allocated along with the
- * tuple, we have to be careful to free any
- * rule locks also -cim 1/17/90
+ * sanity checks
* ----------------
*/
- pfree(oldtuple);
- }
-
- /* ----------------
- * store NULL into the specified slot and return the slot.
- * - also set buffer to InvalidBuffer -cim 3/14/91
- * ----------------
- */
- slot->val = (HeapTuple)NULL;
-
- if (BufferIsValid(slot->ttc_buffer))
- ReleaseBuffer(slot->ttc_buffer);
-
- slot->ttc_buffer = InvalidBuffer;
- slot->ttc_shouldFree = true;
-
- return slot;
+ Assert(slot != NULL);
+
+ /* ----------------
+ * get information from the tuple table
+ * ----------------
+ */
+ oldtuple = slot->val;
+
+ /* ----------------
+ * free the old contents of the specified slot if necessary.
+ * ----------------
+ */
+ if (slot->ttc_shouldFree && oldtuple != NULL)
+ {
+ /* ----------------
+ * since a tuple may contain a pointer to
+ * lock information allocated along with the
+ * tuple, we have to be careful to free any
+ * rule locks also -cim 1/17/90
+ * ----------------
+ */
+ pfree(oldtuple);
+ }
+
+ /* ----------------
+ * store NULL into the specified slot and return the slot.
+ * - also set buffer to InvalidBuffer -cim 3/14/91
+ * ----------------
+ */
+ slot->val = (HeapTuple) NULL;
+
+ if (BufferIsValid(slot->ttc_buffer))
+ ReleaseBuffer(slot->ttc_buffer);
+
+ slot->ttc_buffer = InvalidBuffer;
+ slot->ttc_shouldFree = true;
+
+ return slot;
}
/* --------------------------------
- * ExecSlotPolicy
+ * ExecSlotPolicy
*
- * This function is used to get the call/don't call pfree
- * setting of a slot. Most executor routines don't need this.
- * It's only when you do tricky things like marking tuples for
- * merge joins that you need to diddle the slot policy.
+ * This function is used to get the call/don't call pfree
+ * setting of a slot. Most executor routines don't need this.
+ * It's only when you do tricky things like marking tuples for
+ * merge joins that you need to diddle the slot policy.
* --------------------------------
*/
#ifdef NOT_USED
-bool /* return: slot policy */
-ExecSlotPolicy(TupleTableSlot* slot) /* slot to inspect */
+bool /* return: slot policy */
+ExecSlotPolicy(TupleTableSlot * slot) /* slot to inspect */
{
- return slot->ttc_shouldFree;
+ return slot->ttc_shouldFree;
}
+
#endif
/* --------------------------------
- * ExecSetSlotPolicy
+ * ExecSetSlotPolicy
*
- * This function is used to change the call/don't call pfree
- * setting of a slot. Most executor routines don't need this.
- * It's only when you do tricky things like marking tuples for
- * merge joins that you need to diddle the slot policy.
+ * This function is used to change the call/don't call pfree
+ * setting of a slot. Most executor routines don't need this.
+ * It's only when you do tricky things like marking tuples for
+ * merge joins that you need to diddle the slot policy.
* --------------------------------
*/
-bool /* return: old slot policy */
-ExecSetSlotPolicy(TupleTableSlot* slot, /* slot to change */
- bool shouldFree) /* true if we call pfree() when we gc. */
+bool /* return: old slot policy */
+ExecSetSlotPolicy(TupleTableSlot * slot, /* slot to change */
+ bool shouldFree) /* true if we call pfree() when we
+ * gc. */
{
- bool old_shouldFree = slot->ttc_shouldFree;
- slot->ttc_shouldFree = shouldFree;
+ bool old_shouldFree = slot->ttc_shouldFree;
- return old_shouldFree;
+ slot->ttc_shouldFree = shouldFree;
+
+ return old_shouldFree;
}
/* --------------------------------
- * ExecSlotDescriptor
+ * ExecSlotDescriptor
*
- * This function is used to get the tuple descriptor associated
- * with the slot's tuple.
+ * This function is used to get the tuple descriptor associated
+ * with the slot's tuple.
*
* Now a macro in tuptable.h -mer 5 March 1992
* --------------------------------
*/
/* --------------------------------
- * ExecSetSlotDescriptor
+ * ExecSetSlotDescriptor
*
- * This function is used to set the tuple descriptor associated
- * with the slot's tuple.
+ * This function is used to set the tuple descriptor associated
+ * with the slot's tuple.
* --------------------------------
*/
-TupleDesc /* return: old slot tuple descriptor */
-ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
- TupleDesc tupdesc) /* tuple descriptor */
+TupleDesc /* return: old slot tuple descriptor */
+ExecSetSlotDescriptor(TupleTableSlot * slot, /* slot to change */
+ TupleDesc tupdesc) /* tuple descriptor */
{
- TupleDesc old_tupdesc = slot->ttc_tupleDescriptor;
+ TupleDesc old_tupdesc = slot->ttc_tupleDescriptor;
- slot->ttc_tupleDescriptor = tupdesc;
- return old_tupdesc;
+ slot->ttc_tupleDescriptor = tupdesc;
+ return old_tupdesc;
}
/* --------------------------------
- * ExecSetSlotDescriptorIsNew
+ * ExecSetSlotDescriptorIsNew
*
- * This function is used to change the setting of the "isNew" flag
+ * This function is used to change the setting of the "isNew" flag
* --------------------------------
*/
void
-ExecSetSlotDescriptorIsNew(TupleTableSlot *slot,/* slot to change */
- bool isNew) /* "isNew" setting */
+ExecSetSlotDescriptorIsNew(TupleTableSlot * slot, /* slot to change */
+ bool isNew) /* "isNew" setting */
{
- slot->ttc_descIsNew = isNew;
+ slot->ttc_descIsNew = isNew;
}
/* --------------------------------
- * ExecSetNewSlotDescriptor
+ * ExecSetNewSlotDescriptor
*
- * This function is used to set the tuple descriptor associated
- * with the slot's tuple, and set the "isNew" flag at the same time.
+ * This function is used to set the tuple descriptor associated
+ * with the slot's tuple, and set the "isNew" flag at the same time.
* --------------------------------
*/
#ifdef NOT_USED
-TupleDesc /* return: old slot tuple descriptor */
-ExecSetNewSlotDescriptor(TupleTableSlot *slot, /* slot to change */
- TupleDesc tupdesc) /* tuple descriptor */
+TupleDesc /* return: old slot tuple descriptor */
+ExecSetNewSlotDescriptor(TupleTableSlot * slot, /* slot to change */
+ TupleDesc tupdesc) /* tuple descriptor */
{
- TupleDesc old_tupdesc = slot->ttc_tupleDescriptor;
- slot->ttc_tupleDescriptor = tupdesc;
- slot->ttc_descIsNew = true;
-
- return old_tupdesc;
+ TupleDesc old_tupdesc = slot->ttc_tupleDescriptor;
+
+ slot->ttc_tupleDescriptor = tupdesc;
+ slot->ttc_descIsNew = true;
+
+ return old_tupdesc;
}
+
#endif
/* --------------------------------
- * ExecSlotBuffer
+ * ExecSlotBuffer
*
- * This function is used to get the tuple descriptor associated
- * with the slot's tuple. Be very careful with this as it does not
- * balance the reference counts. If the buffer returned is stored
- * someplace else, then also use ExecIncrSlotBufferRefcnt().
+ * This function is used to get the tuple descriptor associated
+ * with the slot's tuple. Be very careful with this as it does not
+ * balance the reference counts. If the buffer returned is stored
+ * someplace else, then also use ExecIncrSlotBufferRefcnt().
*
* Now a macro in tuptable.h
* --------------------------------
*/
/* --------------------------------
- * ExecSetSlotBuffer
+ * ExecSetSlotBuffer
*
- * This function is used to set the tuple descriptor associated
- * with the slot's tuple. Be very careful with this as it does not
- * balance the reference counts. If we're using this then we should
- * also use ExecIncrSlotBufferRefcnt().
+ * This function is used to set the tuple descriptor associated
+ * with the slot's tuple. Be very careful with this as it does not
+ * balance the reference counts. If we're using this then we should
+ * also use ExecIncrSlotBufferRefcnt().
* --------------------------------
*/
#ifdef NOT_USED
-Buffer /* return: old slot buffer */
-ExecSetSlotBuffer(TupleTableSlot *slot, /* slot to change */
- Buffer b) /* tuple descriptor */
+Buffer /* return: old slot buffer */
+ExecSetSlotBuffer(TupleTableSlot * slot, /* slot to change */
+ Buffer b) /* tuple descriptor */
{
- Buffer oldb = slot->ttc_buffer;
- slot->ttc_buffer = b;
-
- return oldb;
+ Buffer oldb = slot->ttc_buffer;
+
+ slot->ttc_buffer = b;
+
+ return oldb;
}
+
#endif
/* --------------------------------
- * ExecIncrSlotBufferRefcnt
+ * ExecIncrSlotBufferRefcnt
*
- * When we pass around buffers in the tuple table, we have to
- * be careful to increment reference counts appropriately.
- * This is used mainly in the mergejoin code.
+ * When we pass around buffers in the tuple table, we have to
+ * be careful to increment reference counts appropriately.
+ * This is used mainly in the mergejoin code.
* --------------------------------
*/
void
-ExecIncrSlotBufferRefcnt(TupleTableSlot *slot) /* slot to bump refcnt */
+ExecIncrSlotBufferRefcnt(TupleTableSlot * slot) /* slot to bump refcnt */
{
-/* Buffer b = SlotBuffer((TupleTableSlot*) slot); */
- Buffer b = slot->ttc_buffer;
- if (BufferIsValid(b))
- IncrBufferRefCount(b);
+/* Buffer b = SlotBuffer((TupleTableSlot*) slot); */
+ Buffer b = slot->ttc_buffer;
+
+ if (BufferIsValid(b))
+ IncrBufferRefCount(b);
}
/* ----------------------------------------------------------------
- * tuple table slot status predicates
+ * tuple table slot status predicates
* ----------------------------------------------------------------
*/
/* ----------------
- * TupIsNull
+ * TupIsNull
*
- * This is used mainly to detect when there are no more
- * tuples to process.
+ * This is used mainly to detect when there are no more
+ * tuples to process.
* ----------------
*/
-bool /* return: true if tuple in slot is NULL */
-TupIsNull(TupleTableSlot* slot) /* slot to check */
+bool /* return: true if tuple in slot is NULL */
+TupIsNull(TupleTableSlot * slot) /* slot to check */
{
- HeapTuple tuple; /* contents of slot (returned) */
-
- /* ----------------
- * if the slot itself is null then we return true
- * ----------------
- */
- if (slot == NULL)
- return true;
-
- /* ----------------
- * get information from the slot and return true or
- * false depending on the contents of the slot.
- * ----------------
- */
- tuple = slot->val;
-
- return
- (tuple == NULL ? true : false);
+ HeapTuple tuple; /* contents of slot (returned) */
+
+ /* ----------------
+ * if the slot itself is null then we return true
+ * ----------------
+ */
+ if (slot == NULL)
+ return true;
+
+ /* ----------------
+ * get information from the slot and return true or
+ * false depending on the contents of the slot.
+ * ----------------
+ */
+ tuple = slot->val;
+
+ return
+ (tuple == NULL ? true : false);
}
/* --------------------------------
- * ExecSlotDescriptorIsNew
+ * ExecSlotDescriptorIsNew
*
- * This function is used to check if the tuple descriptor
- * associated with this slot has just changed. ie: we are
- * now storing a new type of tuple in this slot
+ * This function is used to check if the tuple descriptor
+ * associated with this slot has just changed. ie: we are
+ * now storing a new type of tuple in this slot
* --------------------------------
*/
#ifdef NOT_USED
-bool /* return: descriptor "is new" */
-ExecSlotDescriptorIsNew(TupleTableSlot *slot) /* slot to inspect */
+bool /* return: descriptor "is new" */
+ExecSlotDescriptorIsNew(TupleTableSlot * slot) /* slot to inspect */
{
-/* bool isNew = SlotTupleDescriptorIsNew((TupleTableSlot*) slot);
- return isNew; */
- return slot->ttc_descIsNew;
+/* bool isNew = SlotTupleDescriptorIsNew((TupleTableSlot*) slot);
+ return isNew; */
+ return slot->ttc_descIsNew;
}
+
#endif
/* ----------------------------------------------------------------
- * convenience initialization routines
+ * convenience initialization routines
* ----------------------------------------------------------------
*/
/* --------------------------------
- * ExecInit{Result,Scan,Raw,Marked,Outer,Hash}TupleSlot
+ * ExecInit{Result,Scan,Raw,Marked,Outer,Hash}TupleSlot
*
- * These are convenience routines to initialize the specfied slot
- * in nodes inheriting the appropriate state.
+ * These are convenience routines to initialize the specfied slot
+ * in nodes inheriting the appropriate state.
* --------------------------------
*/
#define INIT_SLOT_DEFS \
- TupleTable tupleTable; \
- TupleTableSlot* slot
-
+ TupleTable tupleTable; \
+ TupleTableSlot* slot
+
#define INIT_SLOT_ALLOC \
- tupleTable = (TupleTable) estate->es_tupleTable; \
- slot = ExecAllocTableSlot(tupleTable); \
- slot->val = (HeapTuple)NULL; \
- slot->ttc_shouldFree = true; \
- slot->ttc_tupleDescriptor = (TupleDesc)NULL; \
- slot->ttc_whichplan = -1;\
- slot->ttc_descIsNew = true;
+ tupleTable = (TupleTable) estate->es_tupleTable; \
+ slot = ExecAllocTableSlot(tupleTable); \
+ slot->val = (HeapTuple)NULL; \
+ slot->ttc_shouldFree = true; \
+ slot->ttc_tupleDescriptor = (TupleDesc)NULL; \
+ slot->ttc_whichplan = -1;\
+ slot->ttc_descIsNew = true;
/* ----------------
- * ExecInitResultTupleSlot
+ * ExecInitResultTupleSlot
* ----------------
*/
void
-ExecInitResultTupleSlot(EState *estate, CommonState *commonstate)
+ExecInitResultTupleSlot(EState * estate, CommonState * commonstate)
{
- INIT_SLOT_DEFS;
- INIT_SLOT_ALLOC;
- commonstate->cs_ResultTupleSlot = (TupleTableSlot *) slot;
+ INIT_SLOT_DEFS;
+ INIT_SLOT_ALLOC;
+ commonstate->cs_ResultTupleSlot = (TupleTableSlot *) slot;
}
/* ----------------
- * ExecInitScanTupleSlot
+ * ExecInitScanTupleSlot
* ----------------
*/
void
-ExecInitScanTupleSlot(EState *estate, CommonScanState *commonscanstate)
+ExecInitScanTupleSlot(EState * estate, CommonScanState * commonscanstate)
{
- INIT_SLOT_DEFS;
- INIT_SLOT_ALLOC;
- commonscanstate->css_ScanTupleSlot = (TupleTableSlot *)slot;
+ INIT_SLOT_DEFS;
+ INIT_SLOT_ALLOC;
+ commonscanstate->css_ScanTupleSlot = (TupleTableSlot *) slot;
}
/* ----------------
- * ExecInitMarkedTupleSlot
+ * ExecInitMarkedTupleSlot
* ----------------
*/
void
-ExecInitMarkedTupleSlot(EState *estate, MergeJoinState *mergestate)
+ExecInitMarkedTupleSlot(EState * estate, MergeJoinState * mergestate)
{
- INIT_SLOT_DEFS;
- INIT_SLOT_ALLOC;
- mergestate->mj_MarkedTupleSlot = (TupleTableSlot *) slot;
+ INIT_SLOT_DEFS;
+ INIT_SLOT_ALLOC;
+ mergestate->mj_MarkedTupleSlot = (TupleTableSlot *) slot;
}
/* ----------------
- * ExecInitOuterTupleSlot
+ * ExecInitOuterTupleSlot
* ----------------
*/
void
-ExecInitOuterTupleSlot(EState *estate, HashJoinState *hashstate)
+ExecInitOuterTupleSlot(EState * estate, HashJoinState * hashstate)
{
- INIT_SLOT_DEFS;
- INIT_SLOT_ALLOC;
- hashstate->hj_OuterTupleSlot = slot;
+ INIT_SLOT_DEFS;
+ INIT_SLOT_ALLOC;
+ hashstate->hj_OuterTupleSlot = slot;
}
/* ----------------
- * ExecInitHashTupleSlot
+ * ExecInitHashTupleSlot
* ----------------
*/
#ifdef NOT_USED
void
-ExecInitHashTupleSlot(EState *estate, HashJoinState *hashstate)
+ExecInitHashTupleSlot(EState * estate, HashJoinState * hashstate)
{
- INIT_SLOT_DEFS;
- INIT_SLOT_ALLOC;
- hashstate->hj_HashTupleSlot = slot;
+ INIT_SLOT_DEFS;
+ INIT_SLOT_ALLOC;
+ hashstate->hj_HashTupleSlot = slot;
}
+
#endif
static TupleTableSlot *
-NodeGetResultTupleSlot(Plan *node)
+NodeGetResultTupleSlot(Plan * node)
{
- TupleTableSlot *slot;
-
- switch(nodeTag(node)) {
-
- case T_Result:
- {
- ResultState *resstate = ((Result *)node)->resstate;
- slot = resstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_SeqScan:
- {
- CommonScanState *scanstate = ((SeqScan *)node)->scanstate;
- slot = scanstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_NestLoop:
- {
- NestLoopState *nlstate = ((NestLoop *)node)->nlstate;
- slot = nlstate->jstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Append:
- {
- Append *n = (Append *)node;
- AppendState *unionstate;
- List *unionplans;
- int whichplan;
- Plan *subplan;
-
- unionstate = n->unionstate;
- unionplans = n->unionplans;
- whichplan = unionstate->as_whichplan;
-
- subplan = (Plan*) nth(whichplan, unionplans);
- slot = NodeGetResultTupleSlot(subplan);
- break;
- }
-
- case T_IndexScan:
- {
- CommonScanState *scanstate = ((IndexScan *)node)->scan.scanstate;
- slot = scanstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Material:
- {
- MaterialState *matstate = ((Material *)node)->matstate;
- slot = matstate->csstate.css_ScanTupleSlot;
- }
- break;
-
- case T_Sort:
- {
- SortState *sortstate = ((Sort *)node)->sortstate;
- slot = sortstate->csstate.css_ScanTupleSlot;
- }
- break;
-
- case T_Agg:
- {
- AggState *aggstate = ((Agg *)node)->aggstate;
- slot = aggstate->csstate.cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Group:
- {
- GroupState *grpstate = ((Group *)node)->grpstate;
- slot = grpstate->csstate.cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Hash:
- {
- HashState *hashstate = ((Hash *)node)->hashstate;
- slot = hashstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Unique:
- {
- UniqueState *uniquestate = ((Unique *)node)->uniquestate;
- slot = uniquestate->cs_ResultTupleSlot;
- }
- break;
-
- case T_MergeJoin:
- {
- MergeJoinState *mergestate = ((MergeJoin *)node)->mergestate;
- slot = mergestate->jstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_HashJoin:
+ TupleTableSlot *slot;
+
+ switch (nodeTag(node))
{
- HashJoinState *hashjoinstate = ((HashJoin *)node)->hashjoinstate;
- slot = hashjoinstate->jstate.cs_ResultTupleSlot;
+
+ case T_Result:
+ {
+ ResultState *resstate = ((Result *) node)->resstate;
+
+ slot = resstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_SeqScan:
+ {
+ CommonScanState *scanstate = ((SeqScan *) node)->scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_NestLoop:
+ {
+ NestLoopState *nlstate = ((NestLoop *) node)->nlstate;
+
+ slot = nlstate->jstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Append:
+ {
+ Append *n = (Append *) node;
+ AppendState *unionstate;
+ List *unionplans;
+ int whichplan;
+ Plan *subplan;
+
+ unionstate = n->unionstate;
+ unionplans = n->unionplans;
+ whichplan = unionstate->as_whichplan;
+
+ subplan = (Plan *) nth(whichplan, unionplans);
+ slot = NodeGetResultTupleSlot(subplan);
+ break;
+ }
+
+ case T_IndexScan:
+ {
+ CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Material:
+ {
+ MaterialState *matstate = ((Material *) node)->matstate;
+
+ slot = matstate->csstate.css_ScanTupleSlot;
+ }
+ break;
+
+ case T_Sort:
+ {
+ SortState *sortstate = ((Sort *) node)->sortstate;
+
+ slot = sortstate->csstate.css_ScanTupleSlot;
+ }
+ break;
+
+ case T_Agg:
+ {
+ AggState *aggstate = ((Agg *) node)->aggstate;
+
+ slot = aggstate->csstate.cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Group:
+ {
+ GroupState *grpstate = ((Group *) node)->grpstate;
+
+ slot = grpstate->csstate.cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Hash:
+ {
+ HashState *hashstate = ((Hash *) node)->hashstate;
+
+ slot = hashstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Unique:
+ {
+ UniqueState *uniquestate = ((Unique *) node)->uniquestate;
+
+ slot = uniquestate->cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_MergeJoin:
+ {
+ MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate;
+
+ slot = mergestate->jstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_HashJoin:
+ {
+ HashJoinState *hashjoinstate = ((HashJoin *) node)->hashjoinstate;
+
+ slot = hashjoinstate->jstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Tee:
+ {
+ TeeState *teestate = ((Tee *) node)->teestate;
+
+ slot = teestate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ default:
+ /* ----------------
+ * should never get here
+ * ----------------
+ */
+ elog(WARN, "NodeGetResultTupleSlot: node not yet supported: %d ",
+ nodeTag(node));
+
+ return NULL;
}
- break;
-
- case T_Tee:
- {
- TeeState *teestate = ((Tee*)node)->teestate;
- slot = teestate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- default:
- /* ----------------
- * should never get here
- * ----------------
- */
- elog(WARN, "NodeGetResultTupleSlot: node not yet supported: %d ",
- nodeTag(node));
-
- return NULL;
- }
- return slot;
+ return slot;
}
/* ----------------------------------------------------------------
- * ExecGetTupType
+ * ExecGetTupType
*
- * this gives you the tuple descriptor for tuples returned
- * by this node. I really wish I could ditch this routine,
- * but since not all nodes store their type info in the same
- * place, we have to do something special for each node type.
+ * this gives you the tuple descriptor for tuples returned
+ * by this node. I really wish I could ditch this routine,
+ * but since not all nodes store their type info in the same
+ * place, we have to do something special for each node type.
*
- * Soon, the system will have to adapt to deal with changing
- * tuple descriptors as we deal with dynamic tuple types
- * being returned from procedure nodes. Perhaps then this
- * routine can be retired. -cim 6/3/91
+ * Soon, the system will have to adapt to deal with changing
+ * tuple descriptors as we deal with dynamic tuple types
+ * being returned from procedure nodes. Perhaps then this
+ * routine can be retired. -cim 6/3/91
*
* old comments
- * This routine just gets the type information out of the
- * node's state. If you already have a node's state, you
- * can get this information directly, but this is a useful
- * routine if you want to get the type information from
- * the node's inner or outer subplan easily without having
- * to inspect the subplan.. -cim 10/16/89
+ * This routine just gets the type information out of the
+ * node's state. If you already have a node's state, you
+ * can get this information directly, but this is a useful
+ * routine if you want to get the type information from
+ * the node's inner or outer subplan easily without having
+ * to inspect the subplan.. -cim 10/16/89
*
- * Assume that for existential nodes, we get the targetlist out
- * of the right node's targetlist
+ * Assume that for existential nodes, we get the targetlist out
+ * of the right node's targetlist
* ----------------------------------------------------------------
*/
TupleDesc
-ExecGetTupType(Plan *node)
+ExecGetTupType(Plan * node)
{
- TupleTableSlot *slot;
- TupleDesc tupType;
-
- if (node == NULL)
- return NULL;
-
- slot = NodeGetResultTupleSlot(node);
- tupType = slot->ttc_tupleDescriptor;
- return tupType;
+ TupleTableSlot *slot;
+ TupleDesc tupType;
+
+ if (node == NULL)
+ return NULL;
+
+ slot = NodeGetResultTupleSlot(node);
+ tupType = slot->ttc_tupleDescriptor;
+ return tupType;
}
/*
TupleDesc
-ExecCopyTupType(TupleDesc td, int natts)
+ExecCopyTupType(TupleDesc td, int natts)
{
- TupleDesc newTd;
- int i;
-
- newTd = CreateTemplateTupleDesc(natts);
- i = 0;
- while (i < natts)
- {
- newTd[i] =
- (AttributeTupleForm)palloc(sizeof(FormData_pg_attribute));
- memmove(newTd[i], td[i], sizeof(FormData_pg_attribute));
- i++;
- }
- return newTd;
+ TupleDesc newTd;
+ int i;
+
+ newTd = CreateTemplateTupleDesc(natts);
+ i = 0;
+ while (i < natts)
+ {
+ newTd[i] =
+ (AttributeTupleForm)palloc(sizeof(FormData_pg_attribute));
+ memmove(newTd[i], td[i], sizeof(FormData_pg_attribute));
+ i++;
+ }
+ return newTd;
}
*/
/* ----------------------------------------------------------------
- * ExecTypeFromTL
- *
- * Currently there are about 4 different places where we create
- * TupleDescriptors. They should all be merged, or perhaps
- * be rewritten to call BuildDesc().
- *
- * old comments
- * Forms attribute type info from the target list in the node.
- * It assumes all domains are individually specified in the target list.
- * It fails if the target list contains something like Emp.all
- * which represents all the attributes from EMP relation.
- *
- * Conditions:
- * The inner and outer subtrees should be initialized because it
- * might be necessary to know the type infos of the subtrees.
+ * ExecTypeFromTL
+ *
+ * Currently there are about 4 different places where we create
+ * TupleDescriptors. They should all be merged, or perhaps
+ * be rewritten to call BuildDesc().
+ *
+ * old comments
+ * Forms attribute type info from the target list in the node.
+ * It assumes all domains are individually specified in the target list.
+ * It fails if the target list contains something like Emp.all
+ * which represents all the attributes from EMP relation.
+ *
+ * Conditions:
+ * The inner and outer subtrees should be initialized because it
+ * might be necessary to know the type infos of the subtrees.
* ----------------------------------------------------------------
*/
TupleDesc
-ExecTypeFromTL(List *targetList)
+ExecTypeFromTL(List * targetList)
{
- List *tlcdr;
- TupleDesc typeInfo;
- Resdom *resdom;
- Oid restype;
- int len;
-
- /* ----------------
- * examine targetlist - if empty then return NULL
- * ----------------
- */
- len = ExecTargetListLength(targetList);
-
- if (len == 0)
- return NULL;
-
- /* ----------------
- * allocate a new typeInfo
- * ----------------
- */
- typeInfo = CreateTemplateTupleDesc(len);
-
- /* ----------------
- * notes: get resdom from (resdom expr)
- * get_typbyval comes from src/lib/l-lisp/lsyscache.c
- * ----------------
- */
- tlcdr = targetList;
- while (tlcdr != NIL) {
- TargetEntry *tle = lfirst(tlcdr);
- if (tle->resdom != NULL) {
- resdom = tle->resdom;
- restype = resdom->restype;
-
- TupleDescInitEntry(typeInfo,
- resdom->resno,
- resdom->resname,
- /* fix for SELECT NULL ... */
- get_id_typname(restype?restype:UNKNOWNOID),
- 0,
- false);
+ List *tlcdr;
+ TupleDesc typeInfo;
+ Resdom *resdom;
+ Oid restype;
+ int len;
+
+ /* ----------------
+ * examine targetlist - if empty then return NULL
+ * ----------------
+ */
+ len = ExecTargetListLength(targetList);
+
+ if (len == 0)
+ return NULL;
+
+ /* ----------------
+ * allocate a new typeInfo
+ * ----------------
+ */
+ typeInfo = CreateTemplateTupleDesc(len);
+
+ /* ----------------
+ * notes: get resdom from (resdom expr)
+ * get_typbyval comes from src/lib/l-lisp/lsyscache.c
+ * ----------------
+ */
+ tlcdr = targetList;
+ while (tlcdr != NIL)
+ {
+ TargetEntry *tle = lfirst(tlcdr);
+
+ if (tle->resdom != NULL)
+ {
+ resdom = tle->resdom;
+ restype = resdom->restype;
+
+ TupleDescInitEntry(typeInfo,
+ resdom->resno,
+ resdom->resname,
+ /* fix for SELECT NULL ... */
+ get_id_typname(restype ? restype : UNKNOWNOID),
+ 0,
+ false);
/*
- ExecSetTypeInfo(resdom->resno - 1,
- typeInfo,
- (Oid) restype,
- resdom->resno,
- resdom->reslen,
- resdom->resname->data,
- get_typbyval(restype),
- get_typalign(restype));
+ ExecSetTypeInfo(resdom->resno - 1,
+ typeInfo,
+ (Oid) restype,
+ resdom->resno,
+ resdom->reslen,
+ resdom->resname->data,
+ get_typbyval(restype),
+ get_typalign(restype));
*/
- }
- else {
- Resdom *fjRes;
- List *fjTlistP;
- List *fjList = lfirst(tlcdr);
+ }
+ else
+ {
+ Resdom *fjRes;
+ List *fjTlistP;
+ List *fjList = lfirst(tlcdr);
+
#ifdef SETS_FIXED
- TargetEntry *tle;
- Fjoin *fjNode = ((TargetEntry *)lfirst(fjList))->fjoin;
+ TargetEntry *tle;
+ Fjoin *fjNode = ((TargetEntry *) lfirst(fjList))->fjoin;
- tle = fjNode->fj_innerNode; /* ??? */
+ tle = fjNode->fj_innerNode; /* ??? */
#endif
- fjRes = tle->resdom;
- restype = fjRes->restype;
-
- TupleDescInitEntry(typeInfo,
- fjRes->resno,
- fjRes->resname,
- get_id_typname(restype),
- 0,
- false);
+ fjRes = tle->resdom;
+ restype = fjRes->restype;
+
+ TupleDescInitEntry(typeInfo,
+ fjRes->resno,
+ fjRes->resname,
+ get_id_typname(restype),
+ 0,
+ false);
/*
- ExecSetTypeInfo(fjRes->resno - 1,
- typeInfo,
- (Oid) restype,
- fjRes->resno,
- fjRes->reslen,
- (char *) fjRes->resname,
- get_typbyval(restype),
- get_typalign(restype));
+ ExecSetTypeInfo(fjRes->resno - 1,
+ typeInfo,
+ (Oid) restype,
+ fjRes->resno,
+ fjRes->reslen,
+ (char *) fjRes->resname,
+ get_typbyval(restype),
+ get_typalign(restype));
*/
-
- foreach(fjTlistP, lnext(fjList)) {
- TargetEntry *fjTle = lfirst(fjTlistP);
-
- fjRes = fjTle->resdom;
-
- TupleDescInitEntry(typeInfo,
- fjRes->resno,
- fjRes->resname,
- get_id_typname(restype),
- 0,
- false);
-
+
+ foreach(fjTlistP, lnext(fjList))
+ {
+ TargetEntry *fjTle = lfirst(fjTlistP);
+
+ fjRes = fjTle->resdom;
+
+ TupleDescInitEntry(typeInfo,
+ fjRes->resno,
+ fjRes->resname,
+ get_id_typname(restype),
+ 0,
+ false);
+
/*
- ExecSetTypeInfo(fjRes->resno - 1,
- typeInfo,
- (Oid) fjRes->restype,
- fjRes->resno,
- fjRes->reslen,
- (char *) fjRes->resname,
- get_typbyval(fjRes->restype),
- get_typalign(fjRes->restype));
+ ExecSetTypeInfo(fjRes->resno - 1,
+ typeInfo,
+ (Oid) fjRes->restype,
+ fjRes->resno,
+ fjRes->reslen,
+ (char *) fjRes->resname,
+ get_typbyval(fjRes->restype),
+ get_typalign(fjRes->restype));
*/
- }
- }
-
- tlcdr = lnext(tlcdr);
- }
-
- return typeInfo;
-}
+ }
+ }
+ tlcdr = lnext(tlcdr);
+ }
+ return typeInfo;
+}