📄 exectuples.c
字号:
/*------------------------------------------------------------------------- * * 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 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: /usr/local/cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.25 1999/05/25 16:08:39 momjian Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES * * TABLE CREATE/DELETE * ExecCreateTupleTable - create a new tuple table * ExecDestroyTupleTable - destroy a 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(Macro) * * SLOT STATUS PREDICATES * TupIsNull - true when slot contains no tuple(Macro) * 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 / * * 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. * * 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. * * 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. * * - 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. * * 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 * * 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. * */#include <string.h>#include "postgres.h"#include "executor/executor.h"#undef ExecStoreTuple#include "access/tupdesc.h"#include "catalog/pg_type.h"#include "parser/parse_type.h"#include "storage/bufmgr.h"#include "utils/palloc.h"#include "utils/lsyscache.h"static TupleTableSlot *NodeGetResultTupleSlot(Plan *node);/* ---------------------------------------------------------------- * tuple table create/delete functions * ---------------------------------------------------------------- *//* -------------------------------- * 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 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 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 * * 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(). * -------------------------------- */voidExecDestroyTupleTable(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); } } } /* ---------------- * finally free the tuple array and the table itself. * ---------------- */ pfree(array); pfree(table);}/* ---------------------------------------------------------------- * tuple table slot reservation functions * ---------------------------------------------------------------- *//* -------------------------------- * 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). * -------------------------------- */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); * * 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(ERROR, "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 * ---------------------------------------------------------------- *//* -------------------------------- * 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. * -------------------------------- */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;}/* -------------------------------- * ExecClearTuple * * 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 */{ 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) { /* ---------------- * 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 * * 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_USEDbool /* return: slot policy */ExecSlotPolicy(TupleTableSlot *slot) /* slot to inspect */{ return slot->ttc_shouldFree;}/* -------------------------------- * 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. * -------------------------------- */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; return old_shouldFree;}#endif/* -------------------------------- * ExecSlotDescriptor * * 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 * * 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 old_tupdesc = slot->ttc_tupleDescriptor; slot->ttc_tupleDescriptor = tupdesc; return old_tupdesc;}/* -------------------------------- * ExecSetSlotDescriptorIsNew * * This function is used to change the setting of the "isNew" flag * -------------------------------- */voidExecSetSlotDescriptorIsNew(TupleTableSlot *slot, /* slot to change */ bool isNew) /* "isNew" setting */{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -