⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exectuples.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * 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.). * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.88.2.1 2005/11/22 18:23:08 momjian Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES * *	 TABLE CREATE/DELETE *		ExecCreateTupleTable	- create a new tuple table *		ExecDropTupleTable		- destroy a table * *	 SLOT RESERVATION *		ExecAllocTableSlot		- find an available slot in the table * *	 SLOT ACCESSORS *		ExecSetSlotDescriptor	- set a slot's tuple descriptor *		ExecStoreTuple			- store a physical tuple in the slot *		ExecClearTuple			- clear contents of a slot *		ExecStoreVirtualTuple	- mark slot as containing a virtual tuple *		ExecCopySlotTuple		- build a physical tuple from a slot *		ExecMaterializeSlot		- convert virtual to physical storage *		ExecCopySlot			- copy one slot's contents to another * *	 CONVENIENCE INITIALIZATION ROUTINES *		ExecInitResultTupleSlot    \	convenience routines to initialize *		ExecInitScanTupleSlot		\	the various tuple slots for nodes *		ExecInitExtraTupleSlot		/	which store copies of tuples. *		ExecInitNullTupleSlot	   / * *	 Routines that probably belong somewhere else: *		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 ExecutorStart() *		---------------- *		- 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 performing target list projections. * *		During ExecutorRun() *		---------------- *		- 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 ExecProject() and place it into the result tuple slot. * *		- ExecutePlan() calls ExecSelect(), which passes the result slot *		  to printtup(), which uses slot_getallattrs() to extract the *		  individual Datums for printing. * *		At ExecutorEnd() *		---------------- *		- EndPlan() calls ExecDropTupleTable() 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).  It also allows us *		to avoid physically constructing projection tuples in many cases. */#include "postgres.h"#include "funcapi.h"#include "access/heapam.h"#include "catalog/pg_type.h"#include "executor/executor.h"#include "parser/parse_expr.h"#include "utils/lsyscache.h"#include "utils/typcache.h"static TupleDesc ExecTypeFromTLInternal(List *targetList,					   bool hasoid, bool skipjunk);/* ---------------------------------------------------------------- *				  tuple table create/delete functions * ---------------------------------------------------------------- *//* -------------------------------- *		ExecCreateTupleTable * *		This creates a new tuple table of the specified size. * *		This should be used by InitPlan() to allocate the table. *		The table's address will be stored in the EState structure. * -------------------------------- */TupleTableExecCreateTupleTable(int tableSize){	TupleTable	newtable;	int			i;	/*	 * sanity checks	 */	Assert(tableSize >= 1);	/*	 * allocate the table itself	 */	newtable = (TupleTable) palloc(sizeof(TupleTableData) +								   (tableSize - 1) *sizeof(TupleTableSlot));	newtable->size = tableSize;	newtable->next = 0;	/*	 * initialize all the slots to empty states	 */	for (i = 0; i < tableSize; i++)	{		TupleTableSlot *slot = &(newtable->array[i]);		slot->type = T_TupleTableSlot;		slot->tts_isempty = true;		slot->tts_shouldFree = false;		slot->tts_shouldFreeDesc = false;		slot->tts_tuple = NULL;		slot->tts_tupleDescriptor = NULL;		slot->tts_mcxt = CurrentMemoryContext;		slot->tts_buffer = InvalidBuffer;		slot->tts_nvalid = 0;		slot->tts_values = NULL;		slot->tts_isnull = NULL;	}	return newtable;}/* -------------------------------- *		ExecDropTupleTable * *		This frees the storage used by the tuple table itself *		and optionally frees the contents of the table also. *		It is expected that this routine be called by EndPlan(). * -------------------------------- */voidExecDropTupleTable(TupleTable table,	/* tuple table */				   bool shouldFree)		/* true if we should free slot										 * contents */{	/*	 * sanity checks	 */	Assert(table != NULL);	/*	 * first free all the valid pointers in the tuple array and drop refcounts	 * of any referenced buffers, if that's what the caller wants.  (There is	 * probably no good reason for the caller ever not to want it!)	 */	if (shouldFree)	{		int			next = table->next;		int			i;		for (i = 0; i < next; i++)		{			TupleTableSlot *slot = &(table->array[i]);			ExecClearTuple(slot);			if (slot->tts_shouldFreeDesc)				FreeTupleDesc(slot->tts_tupleDescriptor);			if (slot->tts_values)				pfree(slot->tts_values);			if (slot->tts_isnull)				pfree(slot->tts_isnull);		}	}	/*	 * finally free the tuple table itself.	 */	pfree(table);}/* -------------------------------- *		MakeSingleTupleTableSlot * *		This is a convenience routine for operations that need a *		standalone TupleTableSlot not gotten from the main executor *		tuple table.  It makes a single slot and initializes it as *		though by ExecSetSlotDescriptor(slot, tupdesc, false). * -------------------------------- */TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc){	TupleTableSlot *slot = makeNode(TupleTableSlot);	/* This should match ExecCreateTupleTable() */	slot->tts_isempty = true;	slot->tts_shouldFree = false;	slot->tts_shouldFreeDesc = false;	slot->tts_tuple = NULL;	slot->tts_tupleDescriptor = NULL;	slot->tts_mcxt = CurrentMemoryContext;	slot->tts_buffer = InvalidBuffer;	slot->tts_nvalid = 0;	slot->tts_values = NULL;	slot->tts_isnull = NULL;	ExecSetSlotDescriptor(slot, tupdesc, false);	return slot;}/* -------------------------------- *		ExecDropSingleTupleTableSlot * *		Release a TupleTableSlot made with MakeSingleTupleTableSlot. * -------------------------------- */voidExecDropSingleTupleTableSlot(TupleTableSlot *slot){	/*	 * sanity checks	 */	Assert(slot != NULL);	ExecClearTuple(slot);	if (slot->tts_shouldFreeDesc)		FreeTupleDesc(slot->tts_tupleDescriptor);	if (slot->tts_values)		pfree(slot->tts_values);	if (slot->tts_isnull)		pfree(slot->tts_isnull);	pfree(slot);}/* ---------------------------------------------------------------- *				  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 *ExecAllocTableSlot(TupleTable table){	int			slotnum;		/* new slot number */	/*	 * sanity checks	 */	Assert(table != NULL);	/*	 * We expect that the table was made big enough to begin with. We cannot	 * reallocate it on the fly since previous plan nodes have already got	 * pointers to individual entries.	 */	if (table->next >= table->size)		elog(ERROR, "plan requires more slots than are available");	slotnum = table->next;	table->next++;	return &(table->array[slotnum]);}/* ---------------------------------------------------------------- *				  tuple table slot accessor functions * ---------------------------------------------------------------- *//* -------------------------------- *		ExecSetSlotDescriptor * *		This function is used to set the tuple descriptor associated *		with the slot's tuple. * -------------------------------- */voidExecSetSlotDescriptor(TupleTableSlot *slot,		/* slot to change */					  TupleDesc tupdesc,		/* new tuple descriptor */					  bool shouldFree)	/* is desc owned by slot? */{	/* For safety, make sure slot is empty before changing it */	ExecClearTuple(slot);	/*	 * Release any old descriptor.	Also release old Datum/isnull arrays if	 * present (we don't bother to check if they could be re-used).	 */	if (slot->tts_shouldFreeDesc)		FreeTupleDesc(slot->tts_tupleDescriptor);	if (slot->tts_values)		pfree(slot->tts_values);	if (slot->tts_isnull)		pfree(slot->tts_isnull);	/*	 * Set up the new descriptor	 */	slot->tts_tupleDescriptor = tupdesc;	slot->tts_shouldFreeDesc = shouldFree;	/*	 * Allocate Datum/isnull arrays of the appropriate size.  These must have	 * the same lifetime as the slot, so allocate in the slot's own context.	 */	slot->tts_values = (Datum *)		MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(Datum));	slot->tts_isnull = (bool *)		MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(bool));}/* -------------------------------- *		ExecStoreTuple * *		This function is used to store a physical tuple into a specified *		slot in the tuple table. * *		tuple:	tuple to store *		slot:	slot to store it in *		buffer: disk buffer if tuple is in a disk page, else InvalidBuffer *		shouldFree: true if ExecClearTuple should pfree() the tuple *					when done with it * * If 'buffer' is not InvalidBuffer, the tuple table code acquires a pin * on the buffer which is held until the slot is cleared, so that the tuple * won't go away on us. * * shouldFree is normally set 'true' for tuples constructed on-the-fly. * It must always be 'false' for tuples that are stored in disk pages, * since we don't want to try to pfree those. * * Another case where it is 'false' is when the referenced tuple is held * in a tuple table slot belonging to a lower-level executor Proc node. * In this case the lower-level slot retains ownership and responsibility * for eventually releasing the tuple.	When this method is used, we must * be certain that the upper-level Proc node will lose interest in the tuple * sooner than the lower-level one does!  If you're not certain, copy the * lower-level tuple with heap_copytuple and let the upper-level table * slot assume ownership of the copy! * * Return value is just the passed-in slot pointer. * * NOTE: before PostgreSQL 8.1, this function would accept a NULL tuple * pointer and effectively behave like ExecClearTuple (though you could * still specify a buffer to pin, which would be an odd combination). * This saved a couple lines of code in a few places, but seemed more likely * to mask logic errors than to be really useful, so it's now disallowed. * -------------------------------- */TupleTableSlot *ExecStoreTuple(HeapTuple tuple,			   TupleTableSlot *slot,			   Buffer buffer,			   bool shouldFree){	/*	 * sanity checks	 */	Assert(tuple != NULL);	Assert(slot != NULL);	Assert(slot->tts_tupleDescriptor != NULL);	/* passing shouldFree=true for a tuple on a disk page is not sane */	Assert(BufferIsValid(buffer) ? (!shouldFree) : true);	/*	 * clear out any old contents of the slot	 */	if (!slot->tts_isempty)		ExecClearTuple(slot);	/*	 * store the new tuple into the specified slot.	 */	slot->tts_isempty = false;	slot->tts_shouldFree = shouldFree;	slot->tts_tuple = tuple;	/*	 * If tuple is on a disk page, keep the page pinned as long as we hold a	 * pointer into it.  We assume the caller already has such a pin.	 */	slot->tts_buffer = buffer;	if (BufferIsValid(buffer))		IncrBufferRefCount(buffer);	/* Mark extracted state invalid */	slot->tts_nvalid = 0;	return slot;}/* -------------------------------- *		ExecClearTuple * *		This function is used to clear out a slot in the tuple table. * *		NB: only the tuple is cleared, not the tuple descriptor (if any). * -------------------------------- */TupleTableSlot *				/* return: slot passed */ExecClearTuple(TupleTableSlot *slot)	/* slot in which to store tuple */{	/*	 * sanity checks	 */	Assert(slot != NULL);	/*	 * Free the old physical tuple if necessary.	 */	if (slot->tts_shouldFree)		heap_freetuple(slot->tts_tuple);	slot->tts_tuple = NULL;	slot->tts_shouldFree = false;	/*	 * Drop the pin on the referenced buffer, if there is one.	 */	if (BufferIsValid(slot->tts_buffer))		ReleaseBuffer(slot->tts_buffer);	slot->tts_buffer = InvalidBuffer;	/*	 * Mark it empty.	 */	slot->tts_isempty = true;	slot->tts_nvalid = 0;	return slot;}/* -------------------------------- *		ExecStoreVirtualTuple *			Mark a slot as containing a virtual tuple. * * The protocol for loading a slot with virtual tuple data is: *		* Call ExecClearTuple to mark the slot empty. *		* Store data into the Datum/isnull arrays. *		* Call ExecStoreVirtualTuple to mark the slot valid. * This is a bit unclean but it avoids one round of data copying. * -------------------------------- */TupleTableSlot *ExecStoreVirtualTuple(TupleTableSlot *slot){	/*	 * sanity checks	 */	Assert(slot != NULL);	Assert(slot->tts_tupleDescriptor != NULL);	Assert(slot->tts_isempty);	slot->tts_isempty = false;	slot->tts_nvalid = slot->tts_tupleDescriptor->natts;	return slot;}/* -------------------------------- *		ExecStoreAllNullTuple *			Set up the slot to contain a null in every column. * * At first glance this might sound just like ExecClearTuple, but it's * entirely different: the slot ends up full, not empty. * -------------------------------- */TupleTableSlot *ExecStoreAllNullTuple(TupleTableSlot *slot){	/*	 * sanity checks	 */	Assert(slot != NULL);	Assert(slot->tts_tupleDescriptor != NULL);	/* Clear any old contents */	ExecClearTuple(slot);	/*	 * Fill all the columns of the virtual tuple with nulls	 */	MemSet(slot->tts_values, 0,		   slot->tts_tupleDescriptor->natts * sizeof(Datum));	memset(slot->tts_isnull, true,		   slot->tts_tupleDescriptor->natts * sizeof(bool));	return ExecStoreVirtualTuple(slot);}/* -------------------------------- *		ExecCopySlotTuple

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -