*** ./src/backend/access/common/heaptuple.c.orig	Thu Oct 28 14:27:35 2004
--- ./src/backend/access/common/heaptuple.c	Fri Oct 29 10:53:43 2004
***************
*** 731,741 ****
  }
  
  /* ----------------
!  *		heap_deformtuple
   *
   *		Given a tuple, extract data into values/nulls arrays; this is
   *		the inverse of heap_formtuple.
   *
   *		Storage for the values/nulls arrays is provided by the caller;
   *		it should be sized according to tupleDesc->natts not tuple->t_natts.
   *
--- 731,744 ----
  }
  
  /* ----------------
!  *		heap_deformtuple_incr
   *
   *		Given a tuple, extract data into values/nulls arrays; this is
   *		the inverse of heap_formtuple.
   *
+  *		This function can extract attributes of tupple, incrementally.
+  *		When you want all attributes, use heap_deformtuple().
+  *
   *		Storage for the values/nulls arrays is provided by the caller;
   *		it should be sized according to tupleDesc->natts not tuple->t_natts.
   *
***************
*** 746,783 ****
   *		this routine will be significantly quicker than a loop around
   *		heap_getattr; the loop will become O(N^2) as soon as any
   *		noncacheable attribute offsets are involved.
   * ----------------
   */
  void
! heap_deformtuple(HeapTuple tuple,
  				 TupleDesc tupleDesc,
  				 Datum *values,
! 				 char *nulls)
  {
  	HeapTupleHeader tup = tuple->t_data;
  	Form_pg_attribute *att = tupleDesc->attrs;
- 	int			tdesc_natts = tupleDesc->natts;
  	int			natts;			/* number of atts to extract */
  	int			attnum;
  	char	   *tp;				/* ptr to tuple data */
  	long		off;			/* offset in tuple data */
  	bits8	   *bp = tup->t_bits;		/* ptr to null bitmask in tuple */
! 	bool		slow = false;	/* can we use/set attcacheoff? */
! 
! 	natts = tup->t_natts;
  
  	/*
  	 * In inheritance situations, it is possible that the given tuple
  	 * actually has more fields than the caller is expecting.  Don't run
  	 * off the end of the caller's arrays.
  	 */
! 	natts = Min(natts, tdesc_natts);
  
! 	tp = (char *) tup + tup->t_hoff;
  
! 	off = 0;
  
! 	for (attnum = 0; attnum < natts; attnum++)
  	{
  		if (HeapTupleHasNulls(tuple) && att_isnull(attnum, bp))
  		{
--- 749,808 ----
   *		this routine will be significantly quicker than a loop around
   *		heap_getattr; the loop will become O(N^2) as soon as any
   *		noncacheable attribute offsets are involved.
+  *
+  *		Fills the values/nulls arrays up to end_attnum.
+  *		DeformTupleState is used in order to keep the running state of
+  *		this function.
+  *
+  *		Example: The tupple has 100 columns.
+  *		 - first call to get col5 will fill first 5 positions in the array.
+  *	   	 - next call to get col75 will fill starts from 5 and up to 75.
+  *		 - next call to get col60 will do nothing, because already extracted.
   * ----------------
   */
  void
! heap_deformtuple_incr(HeapTuple tuple,
  				 TupleDesc tupleDesc,
  				 Datum *values,
! 				 char *nulls,
! 				 DeformTupleState *state,
! 				 int end_attnum)
  {
  	HeapTupleHeader tup = tuple->t_data;
  	Form_pg_attribute *att = tupleDesc->attrs;
  	int			natts;			/* number of atts to extract */
  	int			attnum;
  	char	   *tp;				/* ptr to tuple data */
  	long		off;			/* offset in tuple data */
  	bits8	   *bp = tup->t_bits;		/* ptr to null bitmask in tuple */
! 	bool		slow;			/* can we use/set attcacheoff? */
  
  	/*
  	 * In inheritance situations, it is possible that the given tuple
  	 * actually has more fields than the caller is expecting.  Don't run
  	 * off the end of the caller's arrays.
  	 */
! 	natts = Min(tup->t_natts, end_attnum);
  
! 	if (state) {
! 		/*
! 		 * Restore state of previous execution.
! 		 * Before the first execution of each tuple, state must
! 		 * initialize by using InitDeformTupleState().
! 		 */
! 		attnum = state->natts;
! 		off = state->off;
! 		slow = state->slow;
! 	} else {
! 		/* start from the first attribute */
! 		attnum = 0;
! 		off = 0;
! 		slow = false;
! 	}
  
! 	tp = (char *) tup + tup->t_hoff;
  
! 	for (; attnum < natts; attnum++)
  	{
  		if (HeapTupleHasNulls(tuple) && att_isnull(attnum, bp))
  		{
***************
*** 811,821 ****
  	 * If tuple doesn't have all the atts indicated by tupleDesc, read the
  	 * rest as null
  	 */
! 	for (; attnum < tdesc_natts; attnum++)
  	{
  		values[attnum] = (Datum) 0;
  		nulls[attnum] = 'n';
  	}
  }
  
  /* ----------------
--- 836,872 ----
  	 * If tuple doesn't have all the atts indicated by tupleDesc, read the
  	 * rest as null
  	 */
! 	for (; attnum < end_attnum; attnum++)
  	{
  		values[attnum] = (Datum) 0;
  		nulls[attnum] = 'n';
  	}
+ 
+ 	if (state) {
+ 		/* Save state for next execution */
+ 		state->natts = attnum;
+ 		state->off = off;
+ 		state->slow = slow;
+ 	}
+ }
+ 
+ /* ----------------
+  *		heap_deformtuple
+  *
+  *		Given a tuple, extract data into values/nulls arrays; this is
+  *		the inverse of heap_formtuple.
+  *
+  *		more information, see also heap_deformtuple_incr.
+  * ----------------
+  */
+ void
+ heap_deformtuple(HeapTuple tuple,
+ 				 TupleDesc tupleDesc,
+ 				 Datum *values,
+ 				 char *nulls)
+ {
+     heap_deformtuple_incr(tuple, tupleDesc, values, nulls,
+ 		NULL, tupleDesc->natts);
  }
  
  /* ----------------
*** ./src/backend/executor/execQual.c.orig	Fri Oct 29 13:33:24 2004
--- ./src/backend/executor/execQual.c	Fri Oct 29 16:19:28 2004
***************
*** 512,517 ****
--- 512,556 ----
  		 * been zeroed.
  		 */
  		Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid);
+ 
+ 		/*
+ 		 * Try not to use nocachegetattr().
+ 		 *
+ 		 * If tuple has many columns, and it has varlen column or null data,
+ 		 * time spent in nocachegetattr() is O(N^2) in the number of fields.
+ 		 * When heap_deformtuple_incr() is used in place of nocachegetattr(),
+ 		 * would reduce the time from O(N^2) to O(N).
+ 		 */
+ 		/*
+ 		 * Check whether can use deformtuple_cache of TupleTableSlot.
+ 		 */
+ 		if (DeformTupleCacheIsValid(slot)) {
+ 			/*
+ 			 * Check whether the attribute was extracted already.
+ 			 */
+ 			if (!AttributeIsDeformed(&(slot->deformtuple_cache.state),
+ 									 attnum)) {
+ 				/*
+ 				 * Fills the values/nulls arrays up to attnum.
+ 				 */
+ 				heap_deformtuple_incr(heapTuple,
+ 					tuple_type,
+ 					slot->deformtuple_cache.values,
+ 					slot->deformtuple_cache.nulls,
+ 					&(slot->deformtuple_cache.state),
+ 					attnum);
+ 			}
+ 
+ 			/*
+ 			 * The result is acquired from deformtuple_cache.
+ 			 */
+ 			if (slot->deformtuple_cache.nulls[attnum - 1] == 'n') {
+ 				*isNull = true;
+ 				return (Datum)NULL;
+ 			}
+ 			*isNull = false;
+ 			return slot->deformtuple_cache.values[attnum - 1];
+ 		}
  	}
  
  	result = heap_getattr(heapTuple,	/* tuple containing attribute */
*** ./src/backend/executor/execTuples.c.orig	Fri Oct 29 13:05:04 2004
--- ./src/backend/executor/execTuples.c	Fri Oct 29 16:29:02 2004
***************
*** 121,126 ****
--- 121,174 ----
  
  
  /* ----------------------------------------------------------------
+  *				  deformtuple_cache create/delete functions
+  * ----------------------------------------------------------------
+  */
+ /* --------------------------------
+  * 		ExecCreateDeformTupleCache
+  *
+  *		This allocates values/null arrays for caching result of
+  *		heap_defromtuple_incr().
+  * --------------------------------
+  */
+ static void
+ ExecCreateDeformTupleCache(TupleTableSlot *slot)
+ {
+ 	MemoryContext   oldcxt;
+ 	int             natts;
+ 
+ 	if (slot->deformtuple_cache.mcxt == NULL) return;
+ 
+ 	oldcxt = MemoryContextSwitchTo(slot->deformtuple_cache.mcxt);
+ 
+ 	natts = slot->ttc_tupleDescriptor->natts;
+ 
+ 	slot->deformtuple_cache.values = palloc(natts * sizeof(Datum));
+ 	slot->deformtuple_cache.nulls = palloc(natts * sizeof(char));
+ 
+ 	MemoryContextSwitchTo(oldcxt);
+ }
+ 
+ /* --------------------------------
+  * 		ExecDeleteDeformTupleCache
+  *
+  *		This frees values/null arrays use by deformtuple_cache.
+  * --------------------------------
+  */
+ static void
+ ExecDeleteDeformTupleCache(TupleTableSlot *slot)
+ {
+ 	if (slot->deformtuple_cache.values) {
+ 		pfree(slot->deformtuple_cache.values);
+ 		slot->deformtuple_cache.values = NULL;
+ 	}
+ 	if (slot->deformtuple_cache.nulls) {
+ 		pfree(slot->deformtuple_cache.nulls);
+ 		slot->deformtuple_cache.nulls = NULL;
+ 	}
+ }
+ 
+ /* ----------------------------------------------------------------
   *				  tuple table create/delete functions
   * ----------------------------------------------------------------
   */
***************
*** 161,166 ****
--- 209,215 ----
  	newtable->size = initialSize;
  	newtable->next = 0;
  	newtable->array = array;
+ 	newtable->mcxt = CurrentMemoryContext;
  
  	return newtable;
  }
***************
*** 204,209 ****
--- 253,259 ----
  		for (i = 0; i < next; i++)
  		{
  			ExecClearTuple(&array[i]);
+ 			ExecDeleteDeformTupleCache(&array[i]);
  			if (array[i].ttc_shouldFreeDesc &&
  				array[i].ttc_tupleDescriptor != NULL)
  				FreeTupleDesc(array[i].ttc_tupleDescriptor);
***************
*** 222,227 ****
--- 272,301 ----
   *				  tuple table slot reservation functions
   * ----------------------------------------------------------------
   */
+ 
+ /* --------------------------------
+  *		InitTupleTableSlot
+  *
+  *		Initializes member of TupleTableSlot.
+  * --------------------------------
+  */
+ static void
+ InitTupleTableSlot(TupleTableSlot *slot)
+ {
+     slot->val = NULL;
+     slot->ttc_shouldFree = true;
+     slot->ttc_descIsNew = true;
+     slot->ttc_shouldFreeDesc = true;
+     slot->ttc_tupleDescriptor = NULL;
+     slot->ttc_buffer = InvalidBuffer;
+ 
+     slot->deformtuple_cache.mcxt = NULL;
+     slot->deformtuple_cache.values = NULL;
+     slot->deformtuple_cache.nulls = NULL;
+ 
+ 	InitDeformTupleState(&(slot->deformtuple_cache.state));
+ }
+ 
  /* --------------------------------
   *		ExecAllocTableSlot
   *
***************
*** 271,282 ****
  
  	/* Make sure the allocated slot is valid (and empty) */
  	slot->type = T_TupleTableSlot;
! 	slot->val = NULL;
! 	slot->ttc_shouldFree = true;
! 	slot->ttc_descIsNew = true;
! 	slot->ttc_shouldFreeDesc = true;
! 	slot->ttc_tupleDescriptor = NULL;
! 	slot->ttc_buffer = InvalidBuffer;
  
  	return slot;
  }
--- 345,354 ----
  
  	/* Make sure the allocated slot is valid (and empty) */
  	slot->type = T_TupleTableSlot;
! 	InitTupleTableSlot(slot);
! 
! 	/* Set MemoryContext for allocates values/null array. */
! 	slot->deformtuple_cache.mcxt = table->mcxt;
  
  	return slot;
  }
***************
*** 295,307 ****
  {
  	TupleTableSlot *slot = makeNode(TupleTableSlot);
  
! 	/* This should match ExecAllocTableSlot() */
! 	slot->val = NULL;
! 	slot->ttc_shouldFree = true;
! 	slot->ttc_descIsNew = true;
! 	slot->ttc_shouldFreeDesc = true;
! 	slot->ttc_tupleDescriptor = NULL;
! 	slot->ttc_buffer = InvalidBuffer;
  
  	return slot;
  }
--- 367,374 ----
  {
  	TupleTableSlot *slot = makeNode(TupleTableSlot);
  
! 	/* Make sure the allocated slot is valid (and empty) */
! 	InitTupleTableSlot(slot);
  
  	return slot;
  }
***************
*** 418,423 ****
--- 485,495 ----
  
  	slot->ttc_buffer = InvalidBuffer;
  
+ 	/*
+ 	 * Reset the DeformTupleState for heap_deformtuple_incr().
+ 	 */
+ 	InitDeformTupleState(&(slot->deformtuple_cache.state));
+ 
  	return slot;
  }
  
***************
*** 439,444 ****
--- 511,522 ----
  
  	slot->ttc_tupleDescriptor = tupdesc;
  	slot->ttc_shouldFreeDesc = shouldFree;
+ 
+ 	/* Deletes the old deformtuple_cache */
+ 	ExecDeleteDeformTupleCache(slot);
+ 
+ 	/* Creates the deformtuple_cache from the provided tupledesc */
+ 	ExecCreateDeformTupleCache(slot);
  }
  
  /* --------------------------------
*** ./src/include/access/heapam.h.orig	Fri Oct 29 10:52:55 2004
--- ./src/include/access/heapam.h	Fri Oct 29 10:53:36 2004
***************
*** 202,207 ****
--- 202,210 ----
  				 char *replActions);
  extern void heap_deformtuple(HeapTuple tuple, TupleDesc tupleDesc,
  				 Datum *values, char *nulls);
+ extern void heap_deformtuple_incr(HeapTuple tuple, TupleDesc tupleDesc,
+ 				 Datum *values, char *nulls,
+ 				 DeformTupleState *state, int end_attnum);
  extern void heap_freetuple(HeapTuple tuple);
  extern HeapTuple heap_addheader(int natts, bool withoid, Size structlen, void *structure);
  
*** ./src/include/access/htup.h.orig	Thu Oct 28 11:06:05 2004
--- ./src/include/access/htup.h	Fri Oct 29 15:06:59 2004
***************
*** 498,501 ****
--- 498,525 ----
  
  #define SizeOfHeapNewpage	(offsetof(xl_heap_newpage, blkno) + sizeof(BlockNumber))
  
+ /*
+  * DeformTupleState keeps the running state of heap_deformtuple_incr().
+  * heap_deformtuple_incr() can extract attributes of tupple, incrementally.
+  * When we would like to execute this incrementally, it is necessary to
+  * keep the running state of that function.
+  */
+ typedef struct DeformTupleState
+ {
+ 	int		natts;	/* number of attributes which was extracted */
+ 	long	off;
+ 	bool	slow;
+ } DeformTupleState;
+ 
+ /* Initialize or reset a DeformTupleState. */
+ #define InitDeformTupleState(state) \
+ do { \
+ 	(state)->natts = 0; \
+ 	(state)->off = 0; \
+ 	(state)->slow = false; \
+ } while(0)
+ 
+ /* Check whether the attribute was extracted already. */
+ #define AttributeIsDeformed(state, attnum) ((state)->natts >= (attnum))
+ 
  #endif   /* HTUP_H */
*** ./src/include/executor/executor.h.orig	Fri Oct 29 13:28:47 2004
--- ./src/include/executor/executor.h	Fri Oct 29 13:32:32 2004
***************
*** 36,41 ****
--- 36,49 ----
  #define ExecEvalExpr(expr, econtext, isNull, isDone) \
  	((*(expr)->evalfunc) (expr, econtext, isNull, isDone))
  
+ /*
+  * DeformTupleCacheIsValid
+  *
+  *	Check whether the deformtuple_cache of TableTupleSlot is valid.
+  */
+ #define DeformTupleCacheIsValid(slot) \
+ 	(slot->deformtuple_cache.values != NULL)
+ 
  
  /*
   * prototypes from functions in execAmi.c
*** ./src/include/executor/tuptable.h.orig	Fri Oct 29 11:14:06 2004
--- ./src/include/executor/tuptable.h	Fri Oct 29 13:47:06 2004
***************
*** 32,37 ****
--- 32,38 ----
   *			tupleDescriptor		type information for the tuple data
   *			shouldFreeDesc		boolean - should we free tupleDescriptor
   *			buffer				the buffer for tuples pointing to disk pages
+  *			deformtuple_cache	result of heap_deformtuple_incr()
   *
   *		The executor stores pointers to tuples in a ``tuple table''
   *		which is composed of TupleTableSlots.  Sometimes the tuples
***************
*** 55,60 ****
--- 56,64 ----
   *		See executor.h for decls of functions defined in execTuples.c
   *		-jolly
   *
+  *		deformtuple_cache is for caching result of heap_deformtuple_incr().
+  *		It is used in ExecEvalVar() for try not to use nocachegetattr().
+  *		more information, see ExecEvalVar().
   * ----------------
   */
  typedef struct TupleTableSlot
***************
*** 66,71 ****
--- 70,83 ----
  	bool		ttc_shouldFreeDesc;
  	TupleDesc	ttc_tupleDescriptor;
  	Buffer		ttc_buffer;
+ 
+ 	struct {
+ 		MemoryContext   	mcxt;		/* for values/nulls allocation */
+ 		DeformTupleState	state;		/* running state of
+ 										   heap_deformtuple_incr() */
+ 		Datum   			*values;
+ 		char   				*nulls;
+ 	} deformtuple_cache;
  } TupleTableSlot;
  
  /* ----------------
***************
*** 77,82 ****
--- 89,95 ----
  	int			size;			/* size of the table */
  	int			next;			/* next available slot number */
  	TupleTableSlot *array;		/* array of TupleTableSlot's */
+ 	MemoryContext  	mcxt;		/* for deformtuple_cache of TupleTableSlot */
  } TupleTableData;
  
  typedef TupleTableData *TupleTable;
