*** postgresql-8.3beta1/src/include/access/relscan.h	Thu Sep 20 13:56:32 2007
--- postgresql-8.3patch/src/include/access/relscan.h	Tue Oct 23 13:05:54 2007
***************
*** 15,20 ****
--- 15,21 ----
  #define RELSCAN_H
  
  #include "access/skey.h"
+ #include "executor/tuptable.h"
  #include "storage/bufpage.h"
  #include "utils/tqual.h"
  
***************
*** 52,57 ****
--- 53,72 ----
  
  typedef HeapScanDescData *HeapScanDesc;
  
+ 
+ typedef struct SnapshotIndexParamsData
+ {
+ 	bool	     isIndexOnlyScan;
+ 	bool	     cache_stack;
+ 	CmdType      operation;
+ 	HeapTuple    htup;
+ 	ScanKey      insertion_skey;  /* Insertion Scan Key */
+ 	void*      stack;
+ 	TupleTableSlot* slot;
+ } SnapshotIndexParamsData;
+ 
+ typedef SnapshotIndexParamsData *SnapshotIndexParams;
+ 
  /*
   * We use the same IndexScanDescData structure for both amgettuple-based
   * and amgetmulti-based index scans.  Some fields are only relevant in
***************
*** 74,79 ****
--- 89,96 ----
  	/* index access method's private state */
  	void	   *opaque;			/* access-method-specific info */
  
+ 	SnapshotIndexParams  sindex_params;    /* Parameters specific to Indexes with Snapshot */
+ 
  	/*
  	 * xs_ctup/xs_cbuf are valid after a successful index_getnext. After
  	 * index_getnext_indexitem, xs_ctup.t_self contains the heap tuple TID
*** postgresql-8.3beta1/src/include/access/nbtree.h	Wed Apr 11 16:47:38 2007
--- postgresql-8.3patch/src/include/access/nbtree.h	Tue Oct 23 13:07:42 2007
***************
*** 17,22 ****
--- 17,23 ----
  #include "access/itup.h"
  #include "access/relscan.h"
  #include "access/sdir.h"
+ #include "access/skey.h"
  #include "access/xlogutils.h"
  
  
***************
*** 222,227 ****
--- 223,229 ----
  #define XLOG_BTREE_NEWROOT		0xA0	/* new root page */
  #define XLOG_BTREE_DELETE_PAGE_HALF 0xB0		/* page deletion that makes
  												 * parent half-dead */
+ #define XLOG_BTREE_UPDATE   0xC0
  
  /*
   * All that we need to find changed index tuple
***************
*** 243,248 ****
--- 245,260 ----
  	uint32		fastlevel;
  } xl_btree_metadata;
  
+ typedef struct xl_btree_update
+ {
+ 	SnapshotFieldsData snpfd;
+ 	xl_btreetid target;         /* to be updated tuple id */
+ } xl_btree_update;
+ 
+ #define SizeOfBtreeUpdate        (offsetof(xl_btreetid ,tid) + SizeOfIptrData)
+ 
+ 
+ 
  /*
   * This is what we need to know about simple (without split) insert.
   *
***************
*** 478,483 ****
--- 490,496 ----
  	/* keep these last in struct for efficiency */
  	BTScanPosData currPos;		/* current position data */
  	BTScanPosData markPos;		/* marked position, if any */
+ 	List   	      *index_cache;     /* currently used for index_only_scans in Indexes with snapshots */
  } BTScanOpaqueData;
  
  typedef BTScanOpaqueData *BTScanOpaque;
***************
*** 513,519 ****
   * prototypes for functions in nbtinsert.c
   */
  extern void _bt_doinsert(Relation rel, IndexTuple itup,
! 			 bool index_is_unique, Relation heapRel);
  extern Buffer _bt_getstackbuf(Relation rel, BTStack stack, int access);
  extern void _bt_insert_parent(Relation rel, Buffer buf, Buffer rbuf,
  				  BTStack stack, bool is_root, bool is_only);
--- 526,532 ----
   * prototypes for functions in nbtinsert.c
   */
  extern void _bt_doinsert(Relation rel, IndexTuple itup,
! 			 bool index_is_unique, Relation heapRel, BTStack stack);
  extern Buffer _bt_getstackbuf(Relation rel, BTStack stack, int access);
  extern void _bt_insert_parent(Relation rel, Buffer buf, Buffer rbuf,
  				  BTStack stack, bool is_root, bool is_only);
***************
*** 551,556 ****
--- 564,571 ----
  extern bool _bt_first(IndexScanDesc scan, ScanDirection dir);
  extern bool _bt_next(IndexScanDesc scan, ScanDirection dir);
  extern Buffer _bt_get_endpoint(Relation rel, uint32 level, bool rightmost);
+ extern void StoreMinimalIndexTuple(IndexScanDesc scan, IndexTuple itup);
+ extern void   GetNextMinimalIndexTuple(IndexScanDesc scan, bool should_free_prev);
  
  /*
   * prototypes for functions in nbtutils.c
*** postgresql-8.3beta1/src/include/access/genam.h	Wed May 30 16:12:02 2007
--- postgresql-8.3patch/src/include/access/genam.h	Thu Oct 18 03:07:55 2007
***************
*** 14,19 ****
--- 14,20 ----
  #ifndef GENAM_H
  #define GENAM_H
  
+ #include "access/nbtree.h"
  #include "access/relscan.h"
  #include "access/sdir.h"
  #include "nodes/primnodes.h"
***************
*** 93,99 ****
  			 Datum *values, bool *isnull,
  			 ItemPointer heap_t_ctid,
  			 Relation heapRelation,
! 			 bool check_uniqueness);
  
  extern IndexScanDesc index_beginscan(Relation heapRelation,
  				Relation indexRelation,
--- 94,101 ----
  			 Datum *values, bool *isnull,
  			 ItemPointer heap_t_ctid,
  			 Relation heapRelation,
! 			 bool check_uniqueness,
! 			 BTStack stack);
  
  extern IndexScanDesc index_beginscan(Relation heapRelation,
  				Relation indexRelation,
*** postgresql-8.3beta1/src/include/access/skey.h	Fri Apr  6 18:33:42 2007
--- postgresql-8.3patch/src/include/access/skey.h	Tue Oct 23 13:08:28 2007
***************
*** 39,44 ****
--- 39,46 ----
  
  #define BTMaxStrategyNumber				5
  
+ #define SK_INSERTION      'I'
+ #define SK_SEARCH         'S'
  
  /*
   * A ScanKey represents the application of a comparison operator between
*** postgresql-8.3beta1/src/include/access/itup.h	Fri Jan  5 17:19:51 2007
--- postgresql-8.3patch/src/include/access/itup.h	Fri Oct 19 22:56:47 2007
***************
*** 18,24 ****
--- 18,30 ----
  #include "access/tupmacs.h"
  #include "storage/bufpage.h"
  #include "storage/itemptr.h"
+ #include "utils/tqual.h"
  
+ #define NORMAL_INDEX 'N'   /* Normal Index without Snapshot */
+ #define INDEX_WITH_SNAPSHOT 'S'  /* Thick B-Tree indexes with Snapshot information */
+ #define MINIMAL_INDEX 'M'  /* This is a In-Memory version of Values Array for Index-Only Scans */
+ #define OTHER_INDEXES 'O'
+ 
  /*
   * Index tuple header structure
   *
***************
*** 59,64 ****
--- 65,88 ----
  
  typedef IndexAttributeBitMapData *IndexAttributeBitMap;
  
+ typedef struct SnapshotFieldsData
+ {
+ 	TransactionId t_xmin;
+ 	TransactionId t_xmax;
+ 	TransactionId t_cid;
+ 	uint16 infomask;
+ } SnapshotFieldsData;
+ 
+ typedef SnapshotFieldsData *SnapshotFields;
+ 
+ typedef struct MinimalIndexTupleData
+ {
+ 	bool  has_null;
+ } MinimalIndexTupleData;
+ /* Null Bitmap (if present) and Values Array follows */
+ 
+ typedef MinimalIndexTupleData *MinimalIndexTuple;
+ 
  /*
   * t_info manipulation macros
   */
***************
*** 89,94 ****
--- 113,123 ----
  	) \
  )
  
+ #define IndexInfoSnapshotSize() \
+ ( \
+         (Size) MAXALIGN(sizeof(SnapshotFieldsData)) \
+ )
+ 
  /* ----------------
   *		index_getattr
   *
***************
*** 97,103 ****
   *
   * ----------------
   */
! #define index_getattr(tup, attnum, tupleDesc, isnull) \
  ( \
  	AssertMacro(PointerIsValid(isnull) && (attnum) > 0), \
  	*(isnull) = false, \
--- 126,132 ----
   *
   * ----------------
   */
! #define allindex_getattr(tup, attnum, tupleDesc, isnull, type) \
  ( \
  	AssertMacro(PointerIsValid(isnull) && (attnum) > 0), \
  	*(isnull) = false, \
***************
*** 106,116 ****
  		(tupleDesc)->attrs[(attnum)-1]->attcacheoff >= 0 ? \
  		( \
  			fetchatt((tupleDesc)->attrs[(attnum)-1], \
! 			(char *) (tup) + IndexInfoFindDataOffset((tup)->t_info) \
  			+ (tupleDesc)->attrs[(attnum)-1]->attcacheoff) \
  		) \
  		: \
! 			nocache_index_getattr((tup), (attnum), (tupleDesc), (isnull)) \
  	) \
  	: \
  	( \
--- 135,145 ----
  		(tupleDesc)->attrs[(attnum)-1]->attcacheoff >= 0 ? \
  		( \
  			fetchatt((tupleDesc)->attrs[(attnum)-1], \
! 			(char *) (tup) + AllIndexInfoFindDataOffset((tup)->t_info, type) \
  			+ (tupleDesc)->attrs[(attnum)-1]->attcacheoff) \
  		) \
  		: \
! 			nocache_index_getattr((tup), (attnum), (tupleDesc), (isnull), type) \
  	) \
  	: \
  	( \
***************
*** 121,131 ****
  		) \
  		: \
  		( \
! 			nocache_index_getattr((tup), (attnum), (tupleDesc), (isnull)) \
  		) \
  	) \
  )
  
  /*
   * MaxIndexTuplesPerPage is an upper bound on the number of tuples that can
   * fit on one index page.  An index tuple must have either data or a null
--- 150,171 ----
  		) \
  		: \
  		( \
! 			nocache_index_getattr((tup), (attnum), (tupleDesc), (isnull), type) \
  		) \
  	) \
  )
  
+ #define index_getattr(tup,attnum,tupDesc,isnull)  allindex_getattr(tup, attnum, tupDesc, isnull, OTHER_INDEXES)
+ 
+ #define GetIndexSnapshotFields(tuple) \
+ 	(SnapshotFields)((char *)tuple + sizeof(IndexTupleData))
+ 
+ #define SnapshotFieldsGetXmin(snpf) snpf->t_xmin
+ 
+ #define SnapshotFieldsGetXmax(snpf) snpf->t_xmax
+ 
+ #define SnapshotFieldsGetRawCommandId(snpf) snpf->t_cid
+ 
  /*
   * MaxIndexTuplesPerPage is an upper bound on the number of tuples that can
   * fit on one index page.  An index tuple must have either data or a null
***************
*** 140,148 ****
  
  /* routines in indextuple.c */
  extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor,
! 				 Datum *values, bool *isnull);
  extern Datum nocache_index_getattr(IndexTuple tup, int attnum,
! 					  TupleDesc tupleDesc, bool *isnull);
  extern IndexTuple CopyIndexTuple(IndexTuple source);
  
! #endif   /* ITUP_H */
--- 180,201 ----
  
  /* routines in indextuple.c */
  extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor,
! 				 Datum *values, bool *isnull, bool withSnapshot);
  extern Datum nocache_index_getattr(IndexTuple tup, int attnum,
! 					  TupleDesc tupleDesc, bool *isnull, char type);
  extern IndexTuple CopyIndexTuple(IndexTuple source);
  
! extern int AllIndexInfoFindDataOffset(uint16 t_info, char type);
! 
! extern char get_index_type(Relation relation);
! 
! extern HTSV_Result IndexTupleSatisfiesVacuum(IndexTuple tuple, TransactionId OldestXmin,
!                                                  Buffer buffer);
! 
! extern CommandId SnapshotFieldsGetCmin(SnapshotFields snpf);
! 
! extern CommandId SnapshotFieldsGetCmax(SnapshotFields snpf);
! 
! 
! #endif
!    /* ITUP_H */
*** postgresql-8.3beta1/src/include/access/htup.h	Thu Sep 20 13:56:32 2007
--- postgresql-8.3patch/src/include/access/htup.h	Tue Oct 16 22:59:26 2007
***************
*** 122,128 ****
  	Oid			datum_typeid;	/* composite type OID, or RECORDOID */
  
  	/*
! 	 * Note: field ordering is chosen with thought that Oid might someday
  	 * widen to 64 bits.
  	 */
  } DatumTupleFields;
--- 122,128 ----
  	Oid			datum_typeid;	/* composite type OID, or RECORDOID */
  
  	/*
! 	 * Notep: field ordering is chosen with thought that Oid might someday
  	 * widen to 64 bits.
  	 */
  } DatumTupleFields;
*** postgresql-8.3beta1/src/include/commands/defrem.h	Tue Aug 21 21:39:46 2007
--- postgresql-8.3patch/src/include/commands/defrem.h	Sat Oct 13 00:36:13 2007
***************
*** 34,40 ****
  			bool check_rights,
  			bool skip_build,
  			bool quiet,
! 			bool concurrent);
  extern void RemoveIndex(RangeVar *relation, DropBehavior behavior);
  extern void ReindexIndex(RangeVar *indexRelation);
  extern void ReindexTable(RangeVar *relation);
--- 34,41 ----
  			bool check_rights,
  			bool skip_build,
  			bool quiet,
! 			bool concurrent,
! 			bool withSnapshot);
  extern void RemoveIndex(RangeVar *relation, DropBehavior behavior);
  extern void ReindexIndex(RangeVar *indexRelation);
  extern void ReindexTable(RangeVar *relation);
*** postgresql-8.3beta1/src/include/catalog/pg_attribute.h	Thu Sep 20 13:56:32 2007
--- postgresql-8.3patch/src/include/catalog/pg_attribute.h	Sat Oct 13 15:53:45 2007
***************
*** 473,482 ****
  { 0, {"indisvalid"},		16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 0, {"indcheckxmin"},		16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 0, {"indisready"},		16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
! { 0, {"indkey"},			22, -1, -1, 10, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
! { 0, {"indclass"},			30, -1, -1, 11, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
! { 0, {"indoption"},			22, -1, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
! { 0, {"indexprs"},			25, -1, -1, 13, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
! { 0, {"indpred"},			25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
  
  #endif   /* PG_ATTRIBUTE_H */
--- 473,483 ----
  { 0, {"indisvalid"},		16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 0, {"indcheckxmin"},		16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 0, {"indisready"},		16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
! { 0, {"indhassnapshot"},		16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
! { 0, {"indkey"},			22, -1, -1, 11, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
! { 0, {"indclass"},			30, -1, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
! { 0, {"indoption"},			22, -1, -1, 13, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
! { 0, {"indexprs"},			25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
! { 0, {"indpred"},			25, -1, -1, 15, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
  
  #endif   /* PG_ATTRIBUTE_H */
*** postgresql-8.3beta1/src/include/catalog/pg_index.h	Thu Sep 20 13:56:32 2007
--- postgresql-8.3patch/src/include/catalog/pg_index.h	Sat Oct 13 13:36:28 2007
***************
*** 44,49 ****
--- 44,50 ----
  	bool		indisvalid;		/* is this index valid for use by queries? */
  	bool		indcheckxmin;	/* must we wait for xmin to be old? */
  	bool		indisready;		/* is this index ready for inserts? */
+ 	bool		indhassnapshot;
  
  	/* VARIABLE LENGTH FIELDS: */
  	int2vector	indkey;			/* column numbers of indexed cols, or 0 */
***************
*** 67,73 ****
   *		compiler constants for pg_index
   * ----------------
   */
! #define Natts_pg_index					14
  #define Anum_pg_index_indexrelid		1
  #define Anum_pg_index_indrelid			2
  #define Anum_pg_index_indnatts			3
--- 68,74 ----
   *		compiler constants for pg_index
   * ----------------
   */
! #define Natts_pg_index					15
  #define Anum_pg_index_indexrelid		1
  #define Anum_pg_index_indrelid			2
  #define Anum_pg_index_indnatts			3
***************
*** 77,87 ****
  #define Anum_pg_index_indisvalid		7
  #define Anum_pg_index_indcheckxmin		8
  #define Anum_pg_index_indisready		9
! #define Anum_pg_index_indkey			10
! #define Anum_pg_index_indclass			11
! #define Anum_pg_index_indoption			12
! #define Anum_pg_index_indexprs			13
! #define Anum_pg_index_indpred			14
  
  /*
   * Index AMs that support ordered scans must support these two indoption
--- 78,89 ----
  #define Anum_pg_index_indisvalid		7
  #define Anum_pg_index_indcheckxmin		8
  #define Anum_pg_index_indisready		9
! #define Anum_pg_index_indhassnapshot            10 
! #define Anum_pg_index_indkey			11
! #define Anum_pg_index_indclass			12
! #define Anum_pg_index_indoption			13
! #define Anum_pg_index_indexprs			14
! #define Anum_pg_index_indpred			15
  
  /*
   * Index AMs that support ordered scans must support these two indoption
*** postgresql-8.3beta1/src/include/optimizer/cost.h	Sat Sep 22 17:36:40 2007
--- postgresql-8.3patch/src/include/optimizer/cost.h	Thu Oct 18 17:24:25 2007
***************
*** 23,28 ****
--- 23,29 ----
  /* If you change these, update backend/utils/misc/postgresql.sample.conf */
  #define DEFAULT_SEQ_PAGE_COST  1.0
  #define DEFAULT_RANDOM_PAGE_COST  4.0
+ #define DEFAULT_INDEX_ONLY_SCAN_FACTOR 3.0
  #define DEFAULT_CPU_TUPLE_COST	0.01
  #define DEFAULT_CPU_INDEX_TUPLE_COST 0.005
  #define DEFAULT_CPU_OPERATOR_COST  0.0025
*** postgresql-8.3beta1/src/include/parser/parse_func.h	Fri Jan  5 17:19:57 2007
--- postgresql-8.3patch/src/include/parser/parse_func.h	Tue Oct 16 23:50:28 2007
***************
*** 78,82 ****
--- 78,89 ----
  						bool noError);
  extern Oid LookupAggNameTypeNames(List *aggname, List *argtypes,
  					   bool noError);
+ extern  Oid	binary_oper_exact(List *opname, Oid arg1, Oid arg2);
+ extern FuncDetailCode oper_select_candidate(int nargs,
+ 					  Oid *input_typeids,
+ 					  FuncCandidateList candidates,
+ 					  Oid *operOid);
  
+ 
+ 
  #endif   /* PARSE_FUNC_H */
*** postgresql-8.3beta1/src/include/pg_config_manual.h	Fri Jun  8 14:23:53 2007
--- postgresql-8.3patch/src/include/pg_config_manual.h	Sat Oct 13 20:33:19 2007
***************
*** 94,99 ****
--- 94,108 ----
   */
  #define INDEX_MAX_KEYS		32
  
+  /* For the sake of storing snapshot information with indexes, we pass the 
+   * snapshot information in the values array. It currently is 
+   * xmin, xmax, cid/xvac, flags. Flags may have some free space.
+   * The Index Tuple Data structure can be optimized by removing the size part of it
+   * Also instead of maintaining INDEX_MAX_KEYS bits for null bitmap, we can make it 
+   * arbitrary. That might result in saving a few bytes, after MAXALIGN
+   */
+ #define SNAPSHOT_KEYS		4
+ 
  /*
   * Number of spare LWLocks to allocate for user-defined add-on code.
   */
*** postgresql-8.3beta1/src/include/nodes/parsenodes.h	Mon Sep  3 14:46:30 2007
--- postgresql-8.3patch/src/include/nodes/parsenodes.h	Sat Oct 13 00:13:54 2007
***************
*** 1546,1551 ****
--- 1546,1552 ----
  	bool		primary;		/* is index on primary key? */
  	bool		isconstraint;	/* is it from a CONSTRAINT clause? */
  	bool		concurrent;		/* should this be a concurrent index build? */
+ 	bool		withSnapshot;   /* Is Snapshot Information included? */
  } IndexStmt;
  
  /* ----------------------
*** postgresql-8.3beta1/src/include/nodes/execnodes.h	Thu Sep 20 13:56:32 2007
--- postgresql-8.3patch/src/include/nodes/execnodes.h	Sat Oct 13 15:54:30 2007
***************
*** 58,63 ****
--- 58,64 ----
  	bool		ii_ReadyForInserts;
  	bool		ii_Concurrent;
  	bool		ii_BrokenHotChain;
+ 	bool		ii_WithSnapshot;
  } IndexInfo;
  
  /* ----------------
*** postgresql-8.3beta1/src/include/nodes/relation.h	Thu Sep 20 13:56:32 2007
--- postgresql-8.3patch/src/include/nodes/relation.h	Thu Oct 18 16:09:02 2007
***************
*** 420,425 ****
--- 420,426 ----
  	bool		unique;			/* true if a unique index */
  	bool		amoptionalkey;	/* can query omit key for the first column? */
  	bool		amsearchnulls;	/* can AM search for NULL index entries? */
+ 	bool		has_snapshot; /* Whether the index stores the snapshot information */
  } IndexOptInfo;
  
  
***************
*** 600,605 ****
--- 601,607 ----
  	List	   *indexclauses;
  	List	   *indexquals;
  	bool		isjoininner;
+ 	bool		index_only_scan;
  	ScanDirection indexscandir;
  	Cost		indextotalcost;
  	Selectivity indexselectivity;
*** postgresql-8.3beta1/src/include/nodes/plannodes.h	Thu Sep 20 13:56:32 2007
--- postgresql-8.3patch/src/include/nodes/plannodes.h	Thu Oct 18 17:57:53 2007
***************
*** 254,259 ****
--- 254,260 ----
  	List	   *indexstrategy;	/* integer list of strategy numbers */
  	List	   *indexsubtype;	/* OID list of strategy subtypes */
  	ScanDirection indexorderdir;	/* forward or backward or don't care */
+ 	bool       indexOnlyScan;
  } IndexScan;
  
  /* ----------------
*** postgresql-8.3beta1/src/include/executor/executor.h	Wed Aug 15 17:39:50 2007
--- postgresql-8.3patch/src/include/executor/executor.h	Thu Oct 18 03:10:12 2007
***************
*** 286,292 ****
--- 286,305 ----
  extern void ExecCloseIndices(ResultRelInfo *resultRelInfo);
  extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
  					  EState *estate, bool is_vacuum);
+ extern void
+ ExecDeleteIndexTuples(TupleTableSlot *slot,
+ 					  ItemPointer tupleid,
+ 					  EState *estate,
+ 					  bool is_vacuum);
  
+ void
+ ExecUpdateIndexTuples(TupleTableSlot *oldslot, TupleTableSlot *newslot,
+ 					  ItemPointer tupleid,
+ 					  EState *estate,
+ 					  bool is_vacuum,
+ 					  bool is_HOT_Tuple);
+ 
+ 
  extern void RegisterExprContextCallback(ExprContext *econtext,
  							ExprContextCallbackFunction function,
  							Datum arg);
*** postgresql-8.3beta1/src/backend/access/gin/ginentrypage.c	Thu Sep 20 13:56:30 2007
--- postgresql-8.3patch/src/backend/access/gin/ginentrypage.c	Sat Oct 13 16:33:18 2007
***************
*** 42,48 ****
  	bool		isnull = FALSE;
  	IndexTuple	itup;
  
! 	itup = index_form_tuple(ginstate->tupdesc, &key, &isnull);
  
  	GinSetOrigSizePosting(itup, IndexTupleSize(itup));
  
--- 42,48 ----
  	bool		isnull = FALSE;
  	IndexTuple	itup;
  
! 	itup = index_form_tuple(ginstate->tupdesc, &key, &isnull, false);
  
  	GinSetOrigSizePosting(itup, IndexTupleSize(itup));
  
*** postgresql-8.3beta1/src/backend/access/index/genam.c	Thu Sep 20 13:56:30 2007
--- postgresql-8.3patch/src/backend/access/index/genam.c	Fri Oct 19 01:38:30 2007
***************
*** 100,105 ****
--- 100,114 ----
  	scan->xs_next_hot = InvalidOffsetNumber;
  	scan->xs_hot_dead = false;
  
+ 	if(indexRelation->rd_index->indhassnapshot)
+ 	{
+ 		scan->sindex_params = palloc0(sizeof(SnapshotIndexParamsData));
+ 		scan->sindex_params->operation = CMD_SELECT; //For Update and Delete, this is changed again;
+ 	}
+ 	else
+ 		scan->sindex_params = NULL;
+ 
+ 
  	/*
  	 * Let the AM fill in the key and any opaque data it wants.
  	 */
***************
*** 126,131 ****
--- 135,142 ----
  	if (scan->keyData != NULL)
  		pfree(scan->keyData);
  
+ 	if(scan->sindex_params != NULL)
+ 		pfree(scan->sindex_params);
  	pfree(scan);
  }
  
*** postgresql-8.3beta1/src/backend/access/index/indexam.c	Thu Sep 20 13:56:30 2007
--- postgresql-8.3patch/src/backend/access/index/indexam.c	Tue Oct 23 13:11:58 2007
***************
*** 64,69 ****
--- 64,70 ----
  
  #include "access/genam.h"
  #include "access/heapam.h"
+ #include "access/nbtree.h"
  #include "access/transam.h"
  #include "pgstat.h"
  #include "utils/relcache.h"
***************
*** 182,188 ****
  			 bool *isnull,
  			 ItemPointer heap_t_ctid,
  			 Relation heapRelation,
! 			 bool check_uniqueness)
  {
  	FmgrInfo   *procedure;
  
--- 183,190 ----
  			 bool *isnull,
  			 ItemPointer heap_t_ctid,
  			 Relation heapRelation,
! 			 bool check_uniqueness,
! 			 BTStack stack)
  {
  	FmgrInfo   *procedure;
  
***************
*** 192,204 ****
  	/*
  	 * have the am's insert proc do all the work.
  	 */
! 	return DatumGetBool(FunctionCall6(procedure,
  									  PointerGetDatum(indexRelation),
  									  PointerGetDatum(values),
  									  PointerGetDatum(isnull),
  									  PointerGetDatum(heap_t_ctid),
  									  PointerGetDatum(heapRelation),
! 									  BoolGetDatum(check_uniqueness)));
  }
  
  /*
--- 194,207 ----
  	/*
  	 * have the am's insert proc do all the work.
  	 */
! 	return DatumGetBool(FunctionCall7(procedure,
  									  PointerGetDatum(indexRelation),
  									  PointerGetDatum(values),
  									  PointerGetDatum(isnull),
  									  PointerGetDatum(heap_t_ctid),
  									  PointerGetDatum(heapRelation),
! 									  BoolGetDatum(check_uniqueness),
! 									  PointerGetDatum(stack)));
  }
  
  /*
***************
*** 474,479 ****
--- 477,486 ----
  
  			pgstat_count_index_tuples(scan->indexRelation, 1);
  
+ 			/* Handle the Index Only Scans here */
+ 			if(scan->sindex_params && scan->sindex_params->isIndexOnlyScan)
+ 				return &scan->xs_ctup;  /* This is Dummy */
+ 
  			/* Switch to correct buffer if we don't have it already */
  			prev_buf = scan->xs_cbuf;
  			scan->xs_cbuf = ReleaseAndReadBuffer(scan->xs_cbuf,
***************
*** 540,546 ****
  			ItemPointerSetOffsetNumber(tid, offnum);
  			heapTuple->t_tableOid = RelationGetRelid(scan->heapRelation);
  			ctid = &heapTuple->t_data->t_ctid;
! 
  			/*
  			 * Shouldn't see a HEAP_ONLY tuple at chain start.  (This test
  			 * should be unnecessary, since the chain root can't be removed
--- 547,553 ----
  			ItemPointerSetOffsetNumber(tid, offnum);
  			heapTuple->t_tableOid = RelationGetRelid(scan->heapRelation);
  			ctid = &heapTuple->t_data->t_ctid;
! 					
  			/*
  			 * Shouldn't see a HEAP_ONLY tuple at chain start.  (This test
  			 * should be unnecessary, since the chain root can't be removed
*** postgresql-8.3beta1/src/backend/access/heap/tuptoaster.c	Mon Oct  1 12:25:56 2007
--- postgresql-8.3patch/src/backend/access/heap/tuptoaster.c	Thu Oct 18 02:34:07 2007
***************
*** 1186,1192 ****
  		 */
  		index_insert(toastidx, t_values, t_isnull,
  					 &(toasttup->t_self),
! 					 toastrel, toastidx->rd_index->indisunique);
  
  		/*
  		 * Free memory
--- 1186,1192 ----
  		 */
  		index_insert(toastidx, t_values, t_isnull,
  					 &(toasttup->t_self),
! 					 toastrel, toastidx->rd_index->indisunique, NULL);
  
  		/*
  		 * Free memory
*** postgresql-8.3beta1/src/backend/access/gist/gistutil.c	Thu Sep 20 13:56:30 2007
--- postgresql-8.3patch/src/backend/access/gist/gistutil.c	Sat Oct 13 16:33:30 2007
***************
*** 518,524 ****
  		}
  	}
  
! 	res = index_form_tuple(giststate->tupdesc, compatt, isnull);
  	GistTupleSetValid(res);
  	return res;
  }
--- 518,524 ----
  		}
  	}
  
! 	res = index_form_tuple(giststate->tupdesc, compatt, isnull,false);
  	GistTupleSetValid(res);
  	return res;
  }
*** postgresql-8.3beta1/src/backend/access/nbtree/nbtutils.c	Wed Sep 12 18:10:26 2007
--- postgresql-8.3patch/src/backend/access/nbtree/nbtutils.c	Tue Oct 16 23:50:25 2007
***************
*** 34,40 ****
  static void _bt_mark_scankey_required(ScanKey skey);
  static bool _bt_check_rowcompare(ScanKey skey,
  					 IndexTuple tuple, TupleDesc tupdesc,
! 					 ScanDirection dir, bool *continuescan);
  
  
  /*
--- 34,40 ----
  static void _bt_mark_scankey_required(ScanKey skey);
  static bool _bt_check_rowcompare(ScanKey skey,
  					 IndexTuple tuple, TupleDesc tupdesc,
! 					 ScanDirection dir, bool *continuescan, char index_type);
  
  
  /*
***************
*** 65,70 ****
--- 65,71 ----
  		Datum		arg;
  		bool		null;
  		int			flags;
+ 		char         index_type = get_index_type(rel);
  
  		/*
  		 * We can use the cached (default) support procs since no cross-type
***************
*** 71,77 ****
  		 * comparison can be needed.
  		 */
  		procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
! 		arg = index_getattr(itup, i + 1, itupdesc, &null);
  		flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
  		ScanKeyEntryInitializeWithInfo(&skey[i],
  									   flags,
--- 72,78 ----
  		 * comparison can be needed.
  		 */
  		procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
! 		arg = allindex_getattr(itup, i + 1, itupdesc, &null,index_type);
  		flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
  		ScanKeyEntryInitializeWithInfo(&skey[i],
  									   flags,
***************
*** 778,787 ****
  	int			keysz;
  	int			ikey;
  	ScanKey		key;
  
  	*continuescan = true;		/* default assumption */
  
! 	/*
  	 * If the scan specifies not to return killed tuples, then we treat a
  	 * killed tuple as not passing the qual.  Most of the time, it's a win to
  	 * not bother examining the tuple's index keys, but just return
--- 779,791 ----
  	int			keysz;
  	int			ikey;
  	ScanKey		key;
+ 	char 		index_type;
  
  	*continuescan = true;		/* default assumption */
+ 	
+ 	index_type = get_index_type(scan->indexRelation);
  
! 		/*
  	 * If the scan specifies not to return killed tuples, then we treat a
  	 * killed tuple as not passing the qual.  Most of the time, it's a win to
  	 * not bother examining the tuple's index keys, but just return
***************
*** 831,845 ****
  		/* row-comparison keys need special processing */
  		if (key->sk_flags & SK_ROW_HEADER)
  		{
! 			if (_bt_check_rowcompare(key, tuple, tupdesc, dir, continuescan))
  				continue;
  			return false;
  		}
  
! 		datum = index_getattr(tuple,
  							  key->sk_attno,
  							  tupdesc,
! 							  &isNull);
  
  		if (key->sk_flags & SK_ISNULL)
  		{
--- 835,850 ----
  		/* row-comparison keys need special processing */
  		if (key->sk_flags & SK_ROW_HEADER)
  		{
! 			if (_bt_check_rowcompare(key, tuple, tupdesc, dir, continuescan, index_type))
  				continue;
  			return false;
  		}
  
! 		datum = allindex_getattr(tuple,
  							  key->sk_attno,
  							  tupdesc,
! 							  &isNull,
! 							  index_type);
  
  		if (key->sk_flags & SK_ISNULL)
  		{
***************
*** 948,954 ****
   */
  static bool
  _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, TupleDesc tupdesc,
! 					 ScanDirection dir, bool *continuescan)
  {
  	ScanKey		subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
  	int32		cmpresult = 0;
--- 953,959 ----
   */
  static bool
  _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, TupleDesc tupdesc,
! 					 ScanDirection dir, bool *continuescan, char index_type)
  {
  	ScanKey		subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
  	int32		cmpresult = 0;
***************
*** 965,974 ****
  
  		Assert(subkey->sk_flags & SK_ROW_MEMBER);
  
! 		datum = index_getattr(tuple,
  							  subkey->sk_attno,
  							  tupdesc,
! 							  &isNull);
  
  		if (isNull)
  		{
--- 970,980 ----
  
  		Assert(subkey->sk_flags & SK_ROW_MEMBER);
  
! 		datum = allindex_getattr(tuple,
  							  subkey->sk_attno,
  							  tupdesc,
! 							  &isNull, 
! 							  index_type);
  
  		if (isNull)
  		{
*** postgresql-8.3beta1/src/backend/access/nbtree/nbtinsert.c	Thu Sep 20 13:56:30 2007
--- postgresql-8.3patch/src/backend/access/nbtree/nbtinsert.c	Thu Oct 18 02:32:12 2007
***************
*** 73,79 ****
  			 Size itemsize, IndexTuple itup,
  			 OffsetNumber itup_off, const char *where);
  static bool _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
! 			int keysz, ScanKey scankey);
  static void _bt_vacuum_one_page(Relation rel, Buffer buffer);
  
  
--- 73,79 ----
  			 Size itemsize, IndexTuple itup,
  			 OffsetNumber itup_off, const char *where);
  static bool _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
! 			int keysz, ScanKey scankey, char index_type);
  static void _bt_vacuum_one_page(Relation rel, Buffer buffer);
  
  
***************
*** 85,95 ****
   */
  void
  _bt_doinsert(Relation rel, IndexTuple itup,
! 			 bool index_is_unique, Relation heapRel)
  {
  	int			natts = rel->rd_rel->relnatts;
  	ScanKey		itup_scankey;
- 	BTStack		stack;
  	Buffer		buf;
  	OffsetNumber offset;
  
--- 85,94 ----
   */
  void
  _bt_doinsert(Relation rel, IndexTuple itup,
! 			 bool index_is_unique, Relation heapRel, BTStack stack)
  {
  	int			natts = rel->rd_rel->relnatts;
  	ScanKey		itup_scankey;
  	Buffer		buf;
  	OffsetNumber offset;
  
***************
*** 98,104 ****
  
  top:
  	/* find the first page containing this key */
! 	stack = _bt_search(rel, natts, itup_scankey, false, &buf, BT_WRITE);
  
  	offset = InvalidOffsetNumber;
  
--- 97,104 ----
  
  top:
  	/* find the first page containing this key */
! 	if(stack == NULL)
! 		stack = _bt_search(rel, natts, itup_scankey, false, &buf, BT_WRITE);
  
  	offset = InvalidOffsetNumber;
  
***************
*** 181,186 ****
--- 181,187 ----
  	Page		page;
  	BTPageOpaque opaque;
  	Buffer		nbuf = InvalidBuffer;
+ 	char index_type = get_index_type(rel);
  
  	InitDirtySnapshot(SnapshotDirty);
  
***************
*** 230,236 ****
  				 * in real comparison, but only for ordering/finding items on
  				 * pages. - vadim 03/24/97
  				 */
! 				if (!_bt_isequal(itupdesc, page, offset, natts, itup_scankey))
  					break;		/* we're past all the equal tuples */
  
  				/* okay, we gotta fetch the heap tuple ... */
--- 231,237 ----
  				 * in real comparison, but only for ordering/finding items on
  				 * pages. - vadim 03/24/97
  				 */
! 				if (!_bt_isequal(itupdesc, page, offset, natts, itup_scankey, index_type))
  					break;		/* we're past all the equal tuples */
  
  				/* okay, we gotta fetch the heap tuple ... */
***************
*** 325,331 ****
  			if (P_RIGHTMOST(opaque))
  				break;
  			if (!_bt_isequal(itupdesc, page, P_HIKEY,
! 							 natts, itup_scankey))
  				break;
  			/* Advance to next non-dead page --- there must be one */
  			for (;;)
--- 326,332 ----
  			if (P_RIGHTMOST(opaque))
  				break;
  			if (!_bt_isequal(itupdesc, page, P_HIKEY,
! 							 natts, itup_scankey, index_type))
  				break;
  			/* Advance to next non-dead page --- there must be one */
  			for (;;)
***************
*** 1817,1823 ****
   */
  static bool
  _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
! 			int keysz, ScanKey scankey)
  {
  	IndexTuple	itup;
  	int			i;
--- 1818,1824 ----
   */
  static bool
  _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
! 			int keysz, ScanKey scankey, char index_type)
  {
  	IndexTuple	itup;
  	int			i;
***************
*** 1836,1842 ****
  
  		attno = scankey->sk_attno;
  		Assert(attno == i);
! 		datum = index_getattr(itup, attno, itupdesc, &isNull);
  
  		/* NULLs are never equal to anything */
  		if (isNull || (scankey->sk_flags & SK_ISNULL))
--- 1837,1843 ----
  
  		attno = scankey->sk_attno;
  		Assert(attno == i);
! 		datum = allindex_getattr(itup, attno, itupdesc, &isNull, index_type);
  
  		/* NULLs are never equal to anything */
  		if (isNull || (scankey->sk_flags & SK_ISNULL))
*** postgresql-8.3beta1/src/backend/access/nbtree/nbtsort.c	Thu Sep 20 13:56:30 2007
--- postgresql-8.3patch/src/backend/access/nbtree/nbtsort.c	Tue Oct 16 22:55:27 2007
***************
*** 671,676 ****
--- 671,677 ----
  				should_free2,
  				load1;
  	TupleDesc	tupdes = RelationGetDescr(wstate->index);
+ 	char		index_type = get_index_type(wstate->index);
  	int			i,
  				keysz = RelationGetNumberOfAttributes(wstate->index);
  	ScanKey		indexScanKey = NULL;
***************
*** 709,716 ****
  					int32		compare;
  
  					entry = indexScanKey + i - 1;
! 					attrDatum1 = index_getattr(itup, i, tupdes, &isNull1);
! 					attrDatum2 = index_getattr(itup2, i, tupdes, &isNull2);
  					if (isNull1)
  					{
  						if (isNull2)
--- 710,717 ----
  					int32		compare;
  
  					entry = indexScanKey + i - 1;
! 					attrDatum1 = allindex_getattr(itup, i, tupdes, &isNull1, index_type);
! 					attrDatum2 = allindex_getattr(itup2, i, tupdes, &isNull2, index_type);
  					if (isNull1)
  					{
  						if (isNull2)
*** postgresql-8.3beta1/src/backend/access/nbtree/nbtree.c	Wed May 30 16:11:53 2007
--- postgresql-8.3patch/src/backend/access/nbtree/nbtree.c	Fri Oct 19 01:57:28 2007
***************
*** 179,185 ****
  	IndexTuple	itup;
  
  	/* form an index tuple and point it at the heap tuple */
! 	itup = index_form_tuple(RelationGetDescr(index), values, isnull);
  	itup->t_tid = htup->t_self;
  
  	/*
--- 179,185 ----
  	IndexTuple	itup;
  
  	/* form an index tuple and point it at the heap tuple */
! 	itup = index_form_tuple(RelationGetDescr(index), values, isnull, index->rd_index->indhassnapshot);
  	itup->t_tid = htup->t_self;
  
  	/*
***************
*** 215,227 ****
  	ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
  	Relation	heapRel = (Relation) PG_GETARG_POINTER(4);
  	bool		checkUnique = PG_GETARG_BOOL(5);
  	IndexTuple	itup;
  
  	/* generate an index tuple */
! 	itup = index_form_tuple(RelationGetDescr(rel), values, isnull);
  	itup->t_tid = *ht_ctid;
  
! 	_bt_doinsert(rel, itup, checkUnique, heapRel);
  
  	pfree(itup);
  
--- 215,230 ----
  	ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
  	Relation	heapRel = (Relation) PG_GETARG_POINTER(4);
  	bool		checkUnique = PG_GETARG_BOOL(5);
+ 	BTStack         stack       = PG_GETARG_POINTER(6);
  	IndexTuple	itup;
+ 	bool		withSnapshot = rel->rd_index->indhassnapshot;
  
  	/* generate an index tuple */
! 	itup = index_form_tuple(RelationGetDescr(rel), values, isnull, withSnapshot);
! 	
  	itup->t_tid = *ht_ctid;
  
! 	_bt_doinsert(rel, itup, checkUnique, heapRel, stack);
  
  	pfree(itup);
  
***************
*** 375,380 ****
--- 378,384 ----
  			so->keyData = NULL;
  		so->killedItems = NULL; /* until needed */
  		so->numKilled = 0;
+ 		so->index_cache = NULL;
  		scan->opaque = so;
  	}
  
*** postgresql-8.3beta1/src/backend/access/nbtree/nbtxlog.c	Thu Sep 20 13:56:30 2007
--- postgresql-8.3patch/src/backend/access/nbtree/nbtxlog.c	Wed Oct 17 23:22:59 2007
***************
*** 44,49 ****
--- 44,50 ----
  
  static List *incomplete_actions;
  
+ static void btree_xlog_update(XLogRecPtr lsn, XLogRecord *record);
  
  static void
  log_incomplete_split(RelFileNode node, BlockNumber leftblk,
***************
*** 742,747 ****
--- 743,751 ----
  		case XLOG_BTREE_NEWROOT:
  			btree_xlog_newroot(lsn, record);
  			break;
+ 		case XLOG_BTREE_UPDATE:
+ 			btree_xlog_update(lsn,record);
+ 			break;
  		default:
  			elog(PANIC, "btree_redo: unknown op code %u", info);
  	}
***************
*** 940,942 ****
--- 944,998 ----
  		return false;
  	return true;
  }
+ 
+ static void
+ btree_xlog_update(XLogRecPtr lsn, XLogRecord *record)
+ {
+ 	xl_btree_update *xlrec = (xl_btree_update *) XLogRecGetData(record);
+ 	Relation	reln;
+ 	Buffer		buffer;
+ 	Page		page;
+ 	OffsetNumber offnum;
+ 	ItemId		lp = NULL;
+ 	SnapshotFields  snpf;	
+ 	IndexTuple itup;
+ 	char index_type;
+ 
+ 	if (record->xl_info & XLR_BKP_BLOCK_1)
+ 		return;
+ 
+ 	reln = XLogOpenRelation(xlrec->target.node);
+ 	index_type = get_index_type(reln);
+ 	buffer = XLogReadBuffer(reln,
+ 							ItemPointerGetBlockNumber(&(xlrec->target.tid)),
+ 							false);
+ 	if (!BufferIsValid(buffer))
+ 		return;
+ 	page = (Page) BufferGetPage(buffer);
+ 
+ 	if (XLByteLE(lsn, PageGetLSN(page)))		/* changes are applied */
+ 	{
+ 		UnlockReleaseBuffer(buffer);
+ 		return;
+ 	}
+ 
+ 	offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
+ 	if (PageGetMaxOffsetNumber(page) >= offnum)
+ 		lp = PageGetItemId(page, offnum);
+ 
+ 	if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp))
+ 		elog(PANIC, "iot_delete_redo: invalid lp");
+ 
+ 	itup = (IndexTuple) PageGetItem(page,lp);
+ 	snpf = (SnapshotFields)((char*) itup +  sizeof(IndexTupleData));
+ 			
+ 	snpf->infomask = xlrec->snpfd.infomask;
+ 	snpf->t_xmax     = xlrec->snpfd.t_xmax;
+ 	snpf->t_cid     = xlrec->snpfd.t_cid;
+ 	/* Make sure there is no forward chain link in t_ctid */
+ 	PageSetLSN(page, lsn);
+ 	PageSetTLI(page, ThisTimeLineID);
+ 	MarkBufferDirty(buffer);
+ 	UnlockReleaseBuffer(buffer);
+ }
+ 
*** postgresql-8.3beta1/src/backend/access/nbtree/nbtsearch.c	Sat May 26 23:50:39 2007
--- postgresql-8.3patch/src/backend/access/nbtree/nbtsearch.c	Fri Oct 19 14:03:31 2007
***************
*** 17,22 ****
--- 17,24 ----
  
  #include "access/genam.h"
  #include "access/nbtree.h"
+ #include "access/transam.h"
+ #include "miscadmin.h"
  #include "pgstat.h"
  #include "utils/lsyscache.h"
  
***************
*** 26,31 ****
--- 28,34 ----
  static bool _bt_steppage(IndexScanDesc scan, ScanDirection dir);
  static Buffer _bt_walk_left(Relation rel, Buffer buf);
  static bool _bt_endpoint(IndexScanDesc scan, ScanDirection dir);
+ static bool SnapshotIndexDeleteTuple(IndexScanDesc scan, IndexTuple itup, ScanDirection dir); 
  
  
  /*
***************
*** 341,346 ****
--- 344,350 ----
  	BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  	IndexTuple	itup;
  	int			i;
+ 	char 		index_type = get_index_type(rel);
  
  	/*
  	 * Force result ">" if target item is first data item on an internal page
***************
*** 369,375 ****
  		bool		isNull;
  		int32		result;
  
! 		datum = index_getattr(itup, scankey->sk_attno, itupdesc, &isNull);
  
  		/* see comments about NULLs handling in btbuild */
  		if (scankey->sk_flags & SK_ISNULL)		/* key is NULL */
--- 373,379 ----
  		bool		isNull;
  		int32		result;
  
! 		datum = allindex_getattr(itup, scankey->sk_attno, itupdesc, &isNull, index_type);
  
  		/* see comments about NULLs handling in btbuild */
  		if (scankey->sk_flags & SK_ISNULL)		/* key is NULL */
***************
*** 832,839 ****
  	 */
  	stack = _bt_search(rel, keysCount, scankeys, nextkey, &buf, BT_READ);
  
! 	/* don't need to keep the stack around... */
! 	_bt_freestack(stack);
  
  	/* remember which buffer we have pinned, if any */
  	so->currPos.buf = buf;
--- 836,848 ----
  	 */
  	stack = _bt_search(rel, keysCount, scankeys, nextkey, &buf, BT_READ);
  
! 	if(rel->rd_index->indhassnapshot && scan->sindex_params->cache_stack)
! 		scan->sindex_params->stack = stack;
! 	else
! 	{
! 		/* don't need to keep the stack around... */
! 		_bt_freestack(stack);
! 	}
  
  	/* remember which buffer we have pinned, if any */
  	so->currPos.buf = buf;
***************
*** 901,906 ****
--- 910,918 ----
  	/* OK, itemIndex says what to return */
  	scan->xs_ctup.t_self = so->currPos.items[so->currPos.itemIndex].heapTid;
  
+ 	if(scan->sindex_params && scan->sindex_params->isIndexOnlyScan)
+ 		GetNextMinimalIndexTuple(scan, false); /* Should not pfree the List Index_cache the very first time */
+ 
  	return true;
  }
  
***************
*** 956,961 ****
--- 968,976 ----
  	/* OK, itemIndex says what to return */
  	scan->xs_ctup.t_self = so->currPos.items[so->currPos.itemIndex].heapTid;
  
+ 	if(scan->sindex_params && scan->sindex_params->isIndexOnlyScan)
+ 		GetNextMinimalIndexTuple(scan, true);
+ 
  	return true;
  }
  
***************
*** 1013,1021 ****
  			{
  				/* tuple passes all scan key conditions, so remember it */
  				/* _bt_checkkeys put the heap ptr into scan->xs_ctup.t_self */
! 				so->currPos.items[itemIndex].heapTid = scan->xs_ctup.t_self;
! 				so->currPos.items[itemIndex].indexOffset = offnum;
! 				itemIndex++;
  			}
  			if (!continuescan)
  			{
--- 1028,1067 ----
  			{
  				/* tuple passes all scan key conditions, so remember it */
  				/* _bt_checkkeys put the heap ptr into scan->xs_ctup.t_self */
!                                 char index_type = get_index_type(scan->indexRelation);
!                                 if(index_type == INDEX_WITH_SNAPSHOT)
!                                 {
!                                     ItemId iid = PageGetItemId(page,offnum);
!                                     IndexTuple itup = (IndexTuple) PageGetItem(page,iid);
! 				    CmdType oper = scan->sindex_params->operation;
! 
! 				    if(IndexTupleSatisfiesMVCC(itup, ActiveSnapshot, so->currPos.buf))
!                                     {
! 					bool result;
! 					if(oper == CMD_DELETE || oper == CMD_UPDATE)
! 						result = SnapshotIndexDeleteTuple(scan, itup, dir);
! 					if(oper == CMD_SELECT) 
! 					{
! 						so->currPos.items[itemIndex].heapTid = scan->xs_ctup.t_self;
!                                         	so->currPos.items[itemIndex].indexOffset = offnum;
!                                         	itemIndex++;
! 						if(scan->sindex_params->isIndexOnlyScan)
! 							StoreMinimalIndexTuple(scan, itup);
! 					}
!                                     }
! 				    else if(IndexTupleSatisfiesVacuum(itup, ActiveSnapshot, so->currPos.buf) == HEAPTUPLE_DEAD)
! 				    {
! 					iid->lp_flags |= LP_DEAD;
! 					so->numKilled++;
! 				    }
! 
!                                 }
!                                 else
!                                 {
!                                     so->currPos.items[itemIndex].heapTid = scan->xs_ctup.t_self;
!                                     so->currPos.items[itemIndex].indexOffset = offnum;
!                                     itemIndex++;
!                                 }
  			}
  			if (!continuescan)
  			{
***************
*** 1043,1048 ****
--- 1089,1119 ----
  		{
  			if (_bt_checkkeys(scan, page, offnum, dir, &continuescan))
  			{
+ 				char index_type  = get_index_type(scan->indexRelation);
+                                 if(index_type == INDEX_WITH_SNAPSHOT)
+                                 {
+                                     ItemId iid = PageGetItemId(page,offnum);
+                                     IndexTuple itup = (IndexTuple) PageGetItem(page,iid);
+ 				    
+                                     if(IndexTupleSatisfiesMVCC(itup, ActiveSnapshot, so->currPos.buf))
+                                     {
+                                         CmdType oper = scan->sindex_params->operation;
+ 					if(oper == CMD_SELECT)
+ 					{
+ 						so->currPos.items[itemIndex].heapTid = scan->xs_ctup.t_self;
+                                         	so->currPos.items[itemIndex].indexOffset = offnum;
+                                         	itemIndex++;
+ 					}
+                                     }
+ 				    else if(IndexTupleSatisfiesVacuum(itup, ActiveSnapshot, so->currPos.buf) == HEAPTUPLE_DEAD)
+ 				    {
+ 					iid->lp_flags |= LP_DEAD;
+ 					so->numKilled++;
+ 				    }
+ 
+                                 }
+ 
+ 				
  				/* tuple passes all scan key conditions, so remember it */
  				/* _bt_checkkeys put the heap ptr into scan->xs_ctup.t_self */
  				itemIndex--;
***************
*** 1064,1069 ****
--- 1135,1146 ----
  		so->currPos.lastItem = MaxIndexTuplesPerPage - 1;
  		so->currPos.itemIndex = MaxIndexTuplesPerPage - 1;
  	}
+ 	if (so->numKilled > 0 && scan->sindex_params)
+ 	{
+ 		opaque->btpo_flags |= BTP_HAS_GARBAGE;
+ 		SetBufferCommitInfoNeedsSave(so->currPos.buf);
+ 		so->numKilled = 0;
+ 	}
  
  	return (so->currPos.firstItem <= so->currPos.lastItem);
  }
***************
*** 1488,1490 ****
--- 1565,1678 ----
  
  	return true;
  }
+ 
+ static bool SnapshotIndexDeleteTuple(IndexScanDesc scan, IndexTuple itup, ScanDirection dir) 
+ {
+ 	BTScanOpaque so = (BTScanOpaque) scan->opaque;
+ 	Page		page;
+ 	BTPageOpaque opaque;
+ 	OffsetNumber minoff;
+ 	OffsetNumber maxoff;
+ 	bool		continuescan;
+ 	ItemId		iid;
+ 	OffsetNumber offnum;
+ 	PageHeader dp;
+ 	HeapTupleHeader  htup = scan->sindex_params->htup->t_data;
+ 	SnapshotFields snpf = GetIndexSnapshotFields(itup);
+ 	if(ItemPointerEquals(&itup->t_tid, &scan->sindex_params->htup->t_self) &&
+ 			 TransactionIdEquals(HeapTupleHeaderGetXmin(htup), snpf->t_xmin))
+ 	{
+ 		/* Read Lock is changed into Write Lock and after the snapshot update
+ 	  	   it is again changed to Read Lock.  */
+ 		LockBuffer(so->currPos.buf, BUFFER_LOCK_UNLOCK);
+ 		//check whether you need to move right and find the position
+ 		LockBuffer(so->currPos.buf, BT_WRITE);
+ 		so->currPos.buf = _bt_moveright(scan->indexRelation, so->currPos.buf, scan->numberOfKeys, 
+ 							scan->sindex_params->insertion_skey, false, BT_WRITE);
+ 		page = BufferGetPage(so->currPos.buf);
+ 		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ 		maxoff = PageGetMaxOffsetNumber(page);
+ 		offnum = _bt_binsrch(scan->indexRelation, so->currPos.buf, scan->numberOfKeys,
+ 						scan->sindex_params->insertion_skey, false);
+ 		iid = PageGetItemId(page,offnum);
+ 		itup = (IndexTuple) PageGetItem(page, iid);
+ 		for(;;)
+ 		{
+ 			if (_bt_checkkeys(scan, page, offnum, dir, &continuescan))
+ 			{
+ 				if(ItemPointerEquals(&itup->t_tid, &scan->sindex_params->htup->t_self) &&
+ 				 			TransactionIdEquals(HeapTupleHeaderGetXmin(htup), snpf->t_xmin))
+ 					break;
+ 				offnum = OffsetNumberNext(offnum);
+ 				if(!continuescan)
+ 					return false; //The Index has become corupted
+ 				if(offnum >maxoff)
+ 				{
+ 					if(!_bt_steppage(scan,dir))
+ 						return false; // The Index has got corrupted
+ 					so = (BTScanOpaque) scan->opaque;
+ 					page = BufferGetPage(so->currPos.buf);
+ 					opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ 					minoff = P_FIRSTDATAKEY(opaque);
+ 					maxoff = PageGetMaxOffsetNumber(page);
+ 					offnum = minoff;
+ 				}
+                                 if(!continuescan)
+                                     return false;
+ 			}
+                        
+ 		}
+ 
+ 		START_CRIT_SECTION();
+ 
+ 		snpf = GetIndexSnapshotFields(itup);
+ 		snpf->t_xmax = HeapTupleHeaderGetXmax(htup);
+ 		snpf->t_cid = HeapTupleHeaderGetRawCommandId(htup);
+ 		snpf->infomask = htup->t_infomask;
+ 
+ 		MarkBufferDirty(so->currPos.buf);
+ 
+ 		//xlog for this 
+ 		{
+ 			xl_btree_update xlrec;
+ 			XLogRecPtr      recptr;
+ 			XLogRecData     rdata[2];
+ 
+ 			dp = (PageHeader) BufferGetPage(so->currPos.buf);	
+ 		
+ 			xlrec.target.node = scan->indexRelation->rd_node;
+ 			ItemPointerSet(&xlrec.target.tid, BufferGetBlockNumber(so->currPos.buf) ,offnum);
+ 
+ 			xlrec.snpfd = *snpf;
+ 
+ 			rdata[0].data = (char *) &xlrec;
+ 			rdata[0].len = SizeOfBtreeUpdate;
+ 			rdata[0].buffer = InvalidBuffer;
+ 			rdata[0].next = &(rdata[1]);
+ 
+ 			/*
+ 			 * The target-offsets array is not in the buffer, but pretend
+ 			 * that it is.  When XLogInsert stores the whole buffer, the
+ 			 * offsets array need not be stored too.
+ 			 */
+ 			rdata[1].data = NULL;
+ 			rdata[1].len = 0;
+ 
+ 			rdata[1].buffer = so->currPos.buf;
+ 			rdata[1].buffer_std = true;
+ 			rdata[1].next = NULL;
+ 
+ 			recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_UPDATE, rdata);
+ 			PageSetLSN(dp, recptr);
+ 			PageSetTLI(dp, ThisTimeLineID);
+ 		}
+ 		
+ 		END_CRIT_SECTION();
+ 		LockBuffer(so->currPos.buf, BUFFER_LOCK_UNLOCK);
+ 		LockBuffer(so->currPos.buf, BT_READ);
+ 		return true;
+ 	}
+ 	return false;
+ }
+                                     
+ 
*** postgresql-8.3beta1/src/backend/access/common/indextuple.c	Fri Apr  6 00:21:41 2007
--- postgresql-8.3patch/src/backend/access/common/indextuple.c	Sat Oct 20 23:15:16 2007
***************
*** 18,26 ****
--- 18,34 ----
  
  #include "access/heapam.h"
  #include "access/itup.h"
+ #include "access/nbtree.h"
  #include "access/tuptoaster.h"
  
  
+ static Datum
+ minidx_getattr(MinimalIndexTuple tup,
+ 					  int attnum,
+ 					  TupleDesc tupleDesc,
+ 					  bool *isnull);
+ 
+ 
  /* ----------------------------------------------------------------
   *				  index_ tuple interface routines
   * ----------------------------------------------------------------
***************
*** 33,39 ****
  IndexTuple
  index_form_tuple(TupleDesc tupleDescriptor,
  				 Datum *values,
! 				 bool *isnull)
  {
  	char	   *tp;				/* tuple pointer */
  	IndexTuple	tuple;			/* return tuple */
--- 41,48 ----
  IndexTuple
  index_form_tuple(TupleDesc tupleDescriptor,
  				 Datum *values,
! 				 bool *isnull,
! 				 bool withSnapshot)
  {
  	char	   *tp;				/* tuple pointer */
  	IndexTuple	tuple;			/* return tuple */
***************
*** 45,50 ****
--- 54,61 ----
  	bool		hasnull = false;
  	uint16		tupmask = 0;
  	int			numberOfAttributes = tupleDescriptor->natts;
+ 	char 		index_type;
+ 	int 		null_offset;
  
  #ifdef TOAST_INDEX_HACK
  	Datum		untoasted_values[INDEX_MAX_KEYS];
***************
*** 114,121 ****
  
  	if (hasnull)
  		infomask |= INDEX_NULL_MASK;
! 
! 	hoff = IndexInfoFindDataOffset(infomask);
  #ifdef TOAST_INDEX_HACK
  	data_size = heap_compute_data_size(tupleDescriptor,
  									   untoasted_values, isnull);
--- 125,145 ----
  
  	if (hasnull)
  		infomask |= INDEX_NULL_MASK;
! 	
! 	if(withSnapshot)
! 	{
! 		index_type = INDEX_WITH_SNAPSHOT;
! 		null_offset = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(sizeof(SnapshotFieldsData));
! 	}
! 	else
! 	{
! 		index_type = NORMAL_INDEX;
! 		null_offset = sizeof(IndexTupleData);
! 	}
! 	null_offset = MAXALIGN(null_offset);
! 	hoff = AllIndexInfoFindDataOffset(infomask, index_type);
! 	
! 	
  #ifdef TOAST_INDEX_HACK
  	data_size = heap_compute_data_size(tupleDescriptor,
  									   untoasted_values, isnull);
***************
*** 123,132 ****
--- 147,168 ----
  	data_size = heap_compute_data_size(tupleDescriptor,
  									   values, isnull);
  #endif
+ 
  	size = hoff + data_size;
  	size = MAXALIGN(size);		/* be conservative */
  
  	tp = (char *) palloc0(size);
+         
+         if(withSnapshot)
+ 	{
+ 		SnapshotFields snpf = (SnapshotFields) ((char *) tp + MAXALIGN(sizeof(IndexTupleData)));
+                 
+ 		snpf->t_xmin = DatumGetTransactionId(values[INDEX_MAX_KEYS]);
+ 		snpf->t_xmax = DatumGetTransactionId(values[INDEX_MAX_KEYS+1]);
+ 		snpf->t_cid = DatumGetCommandId(values[INDEX_MAX_KEYS+2]);
+ 		snpf->infomask = DatumGetUInt16(values[INDEX_MAX_KEYS+3]);	
+ 	}
+         
  	tuple = (IndexTuple) tp;
  
  	heap_fill_tuple(tupleDescriptor,
***************
*** 139,145 ****
  					(char *) tp + hoff,
  					data_size,
  					&tupmask,
! 					(hasnull ? (bits8 *) tp + sizeof(IndexTupleData) : NULL));
  
  #ifdef TOAST_INDEX_HACK
  	for (i = 0; i < numberOfAttributes; i++)
--- 175,181 ----
  					(char *) tp + hoff,
  					data_size,
  					&tupmask,
! 					(hasnull ? (bits8 *) tp + null_offset : NULL));
  
  #ifdef TOAST_INDEX_HACK
  	for (i = 0; i < numberOfAttributes; i++)
***************
*** 201,207 ****
  nocache_index_getattr(IndexTuple tup,
  					  int attnum,
  					  TupleDesc tupleDesc,
! 					  bool *isnull)
  {
  	Form_pg_attribute *att = tupleDesc->attrs;
  	char	   *tp;				/* ptr to data part of tuple */
--- 237,244 ----
  nocache_index_getattr(IndexTuple tup,
  					  int attnum,
  					  TupleDesc tupleDesc,
! 					  bool *isnull,
! 					  char type)
  {
  	Form_pg_attribute *att = tupleDesc->attrs;
  	char	   *tp;				/* ptr to data part of tuple */
***************
*** 212,217 ****
--- 249,256 ----
  
  	(void) isnull;				/* not used */
  
+ 			
+ 
  	/* ----------------
  	 *	 Three cases:
  	 *
***************
*** 229,235 ****
  	*isnull = false;
  #endif
  
! 	data_off = IndexInfoFindDataOffset(tup->t_info);
  
  	attnum--;
  
--- 268,274 ----
  	*isnull = false;
  #endif
  
! 	data_off = AllIndexInfoFindDataOffset(tup->t_info, type);
  
  	attnum--;
  
***************
*** 446,448 ****
--- 485,640 ----
  	memcpy(result, source, size);
  	return result;
  }
+ 
+ int AllIndexInfoFindDataOffset(uint16 t_info, char type)
+ {
+ 	int offset;
+ 	switch(type)
+ 	{
+ 		case INDEX_WITH_SNAPSHOT:
+ 			offset = IndexInfoSnapshotSize();
+                         break;
+ 		default:
+ 			offset = 0;
+                         break;
+ 	}
+ 	if(!((t_info) & INDEX_NULL_MASK))
+ 	{
+ 		offset += (Size)MAXALIGN(sizeof(IndexTupleData));
+ 	}
+ 	else
+ 	{
+ 		offset += (Size)MAXALIGN(sizeof(IndexTupleData) + sizeof(IndexAttributeBitMapData));
+ 	}
+ 	return offset;
+ }
+ 
+ char get_index_type(Relation relation)
+ {
+ 	char index_type;	
+ 	if(relation->rd_index->indhassnapshot)
+ 		index_type = INDEX_WITH_SNAPSHOT;
+ 	else
+ 		index_type = NORMAL_INDEX;
+ 	return index_type;
+ }
+ 
+ 
+ /* The idea of storing HeapTuple is ruled out to save some memory. But it is worth trying out */
+ void StoreMinimalIndexTuple(IndexScanDesc scan, IndexTuple itup)
+ {
+ 	BTScanOpaque so = (BTScanOpaque) scan->opaque;
+ 	Size required_size = MAXALIGN(sizeof(MinimalIndexTupleData)) + MAXALIGN(IndexTupleSize(itup)) -
+ 				MAXALIGN(sizeof(IndexTupleData)) - MAXALIGN(sizeof(SnapshotFieldsData));
+ 	 Size copy_size;
+          MinimalIndexTuple mitup;
+          char *src, *dst;
+         required_size = MAXALIGN(required_size);
+         mitup = palloc(required_size);
+ 	mitup->has_null = IndexTupleHasNulls(itup);
+ 	dst = (char *)mitup + MAXALIGN(sizeof(MinimalIndexTupleData));
+ 	src = (char *)itup + MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(sizeof(SnapshotFieldsData));
+ 	copy_size = required_size - MAXALIGN(sizeof(MinimalIndexTupleData));
+ 	memcpy(dst, src, copy_size);
+ 	so->index_cache = lappend(so->index_cache, mitup);
+ }
+ 
+ void   GetNextMinimalIndexTuple(IndexScanDesc scan, bool should_free_prev)
+ {
+ 	BTScanOpaque so = (BTScanOpaque) scan->opaque;
+ 	MinimalIndexTuple mitup;
+ 	int i;
+ 	bool isNull;
+ 
+ 	TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
+ 	TupleDesc htupdesc = RelationGetDescr(scan->heapRelation);
+ 	TupleTableSlot *slot = scan->sindex_params->slot;
+         List  *l   = so->index_cache;
+ 
+ 	if(should_free_prev)
+ 		list_delete_first(l);
+ 	mitup = (MinimalIndexTuple) linitial(l);
+ 
+ 	for(i=0;i<htupdesc->natts; i++)
+ 	{
+ 		slot->tts_values[i] = (Datum) 0;
+ 		slot->tts_isnull[i] = true;
+ 	}
+ 	
+ 	for(i=0; i <scan->indexRelation->rd_index->indnatts; i++)
+ 	{
+ 		int key_location = scan->indexRelation->rd_index->indkey.values[i];
+ 		slot->tts_values[key_location-1]  = minidx_getattr(mitup, i+1, tupdesc, &isNull);
+ 		slot->tts_isnull[key_location-1] = isNull;
+ 	}
+ 	slot->tts_nvalid = htupdesc->natts;
+ 	slot->tts_tuple = heap_form_tuple(htupdesc, slot->tts_values, slot->tts_isnull);
+ 	slot->tts_isempty = false;
+ }
+ 
+ static Datum
+ minidx_getattr(MinimalIndexTuple tup,
+ 					  int attnum,
+ 					  TupleDesc tupleDesc,
+ 					  bool *isnull)
+ {
+ 	Form_pg_attribute *att = tupleDesc->attrs;
+ 	char	   *tp;				/* ptr to data part of tuple */
+ 	bits8	   *bp = NULL;		/* ptr to null bitmap in tuple */
+ 	int			data_off;		/* tuple data offset */
+ 	int			off;			/* current offset within data */
+ 	int 			i;
+         int natts  = tupleDesc->natts;
+ 
+ 	(void) isnull;				/* not used */
+ 
+ 	Assert(PointerIsValid(isnull));
+ 	Assert(attnum > 0);
+ 
+ 	*isnull = false;
+ 
+ 	data_off = MAXALIGN(sizeof(MinimalIndexTupleData));
+ 
+ 	if(tup->has_null)
+ 		data_off+=sizeof(IndexAttributeBitMapData);
+ 
+ 	attnum--;
+ 
+ 	/* XXX "knows" t_bits are just after fixed tuple header! */
+ 	bp = (bits8 *) ((char *) tup + MAXALIGN(sizeof(MinimalIndexTupleData)));
+ 
+ 	if (tup->has_null && att_isnull(attnum, bp))
+ 	{
+ 		*isnull = true;
+ 		return (Datum) NULL;
+ 	}
+ 
+ 	tp = (char *) tup + data_off;
+ 	off = 0;
+ 		for (i = 0; i<natts; i++)			/* loop exit is at "break" */
+ 		{
+ 			if (tup->has_null && att_isnull(i, bp))
+ 				continue;			/* this cannot be the target att */
+ 
+ 			if (att[i]->attlen == -1)
+ 			{
+ 				off = att_align_pointer(off, att[i]->attalign, -1,
+ 											tp + off);
+ 			}
+ 			else
+ 			{
+ 				/* not varlena, so safe to use att_align_nominal */
+ 				off = att_align_nominal(off, att[i]->attalign);
+ 
+ 			}
+ 
+ 			if (i == attnum)
+ 				break;
+ 
+ 			off = att_addlength_pointer(off, att[i]->attlen, tp + off);
+ 
+ 		}
+ 
+ 	return fetchatt(att[attnum], tp + off);
+ }
+ 
*** postgresql-8.3beta1/src/backend/access/hash/hash.c	Wed Sep 12 18:10:25 2007
--- postgresql-8.3patch/src/backend/access/hash/hash.c	Sat Oct 13 16:33:50 2007
***************
*** 95,101 ****
  	IndexTuple	itup;
  
  	/* form an index tuple and point it at the heap tuple */
! 	itup = index_form_tuple(RelationGetDescr(index), values, isnull);
  	itup->t_tid = htup->t_self;
  
  	/* Hash indexes don't index nulls, see notes in hashinsert */
--- 95,101 ----
  	IndexTuple	itup;
  
  	/* form an index tuple and point it at the heap tuple */
! 	itup = index_form_tuple(RelationGetDescr(index), values, isnull, false);
  	itup->t_tid = htup->t_self;
  
  	/* Hash indexes don't index nulls, see notes in hashinsert */
***************
*** 133,139 ****
  	IndexTuple	itup;
  
  	/* generate an index tuple */
! 	itup = index_form_tuple(RelationGetDescr(rel), values, isnull);
  	itup->t_tid = *ht_ctid;
  
  	/*
--- 133,139 ----
  	IndexTuple	itup;
  
  	/* generate an index tuple */
! 	itup = index_form_tuple(RelationGetDescr(rel), values, isnull, false);
  	itup->t_tid = *ht_ctid;
  
  	/*
*** postgresql-8.3beta1/src/backend/storage/buffer/bufmgr.c	Tue Sep 25 18:11:48 2007
--- postgresql-8.3patch/src/backend/storage/buffer/bufmgr.c	Fri Oct 19 23:18:36 2007
***************
*** 1470,1477 ****
  		localhitrate = (float) LocalBufferHitCount *100.0 / ReadLocalBufferCount;
  
  	appendStringInfo(&str,
! 	"!\tShared blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
! 				ReadBufferCount - BufferHitCount, BufferFlushCount, hitrate);
  	appendStringInfo(&str,
  	"!\tLocal  blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
  					 ReadLocalBufferCount - LocalBufferHitCount, LocalBufferFlushCount, localhitrate);
--- 1470,1477 ----
  		localhitrate = (float) LocalBufferHitCount *100.0 / ReadLocalBufferCount;
  
  	appendStringInfo(&str,
! 	"!\tShared blocks: %10ld Logical Reads, %10ld Physical Reads, %10ld written, buffer hit rate = %.2f%%\n",
! 				ReadBufferCount, ReadBufferCount - BufferHitCount, BufferFlushCount, hitrate);
  	appendStringInfo(&str,
  	"!\tLocal  blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
  					 ReadLocalBufferCount - LocalBufferHitCount, LocalBufferFlushCount, localhitrate);
*** postgresql-8.3beta1/src/backend/commands/indexcmds.c	Thu Sep 20 13:56:31 2007
--- postgresql-8.3patch/src/backend/commands/indexcmds.c	Sat Oct 13 15:57:00 2007
***************
*** 111,117 ****
  			bool check_rights,
  			bool skip_build,
  			bool quiet,
! 			bool concurrent)
  {
  	Oid		   *classObjectId;
  	Oid			accessMethodId;
--- 111,118 ----
  			bool check_rights,
  			bool skip_build,
  			bool quiet,
! 			bool concurrent,
! 			bool withSnapshot)
  {
  	Oid		   *classObjectId;
  	Oid			accessMethodId;
***************
*** 425,430 ****
--- 426,432 ----
  	indexInfo->ii_ReadyForInserts = !concurrent;
  	indexInfo->ii_Concurrent = concurrent;
  	indexInfo->ii_BrokenHotChain = false;
+         indexInfo->ii_WithSnapshot = withSnapshot;
  
  	classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
  	coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
*** postgresql-8.3beta1/src/backend/commands/tablecmds.c	Sat Sep 29 13:18:58 2007
--- postgresql-8.3patch/src/backend/commands/tablecmds.c	Sat Oct 13 00:38:19 2007
***************
*** 3805,3810 ****
--- 3805,3811 ----
  				check_rights,
  				skip_build,
  				quiet,
+ 				false,
  				false);
  }
  
*** postgresql-8.3beta1/src/backend/catalog/toasting.c	Thu Sep 20 13:56:30 2007
--- postgresql-8.3patch/src/backend/catalog/toasting.c	Sat Oct 13 15:56:10 2007
***************
*** 228,233 ****
--- 228,234 ----
  	indexInfo->ii_ReadyForInserts = true;
  	indexInfo->ii_Concurrent = false;
  	indexInfo->ii_BrokenHotChain = false;
+ 	indexInfo->ii_WithSnapshot = false;
  
  	classObjectId[0] = OID_BTREE_OPS_OID;
  	classObjectId[1] = INT4_BTREE_OPS_OID;
*** postgresql-8.3beta1/src/backend/catalog/indexing.c	Thu Sep 20 13:56:30 2007
--- postgresql-8.3patch/src/backend/catalog/indexing.c	Thu Oct 18 02:35:00 2007
***************
*** 134,140 ****
  					 isnull,	/* is-null flags */
  					 &(heapTuple->t_self),		/* tid of heap tuple */
  					 heapRelation,
! 					 relationDescs[i]->rd_index->indisunique);
  	}
  
  	ExecDropSingleTupleTableSlot(slot);
--- 134,141 ----
  					 isnull,	/* is-null flags */
  					 &(heapTuple->t_self),		/* tid of heap tuple */
  					 heapRelation,
! 					 relationDescs[i]->rd_index->indisunique,
! 					 NULL);
  	}
  
  	ExecDropSingleTupleTableSlot(slot);
*** postgresql-8.3beta1/src/backend/catalog/index.c	Thu Sep 20 13:56:30 2007
--- postgresql-8.3patch/src/backend/catalog/index.c	Fri Oct 19 02:58:40 2007
***************
*** 422,427 ****
--- 422,428 ----
  	values[Anum_pg_index_indpred - 1] = predDatum;
  	if (predDatum == (Datum) 0)
  		nulls[Anum_pg_index_indpred - 1] = 'n';
+         values[Anum_pg_index_indhassnapshot - 1 ] = BoolGetDatum(indexInfo->ii_WithSnapshot);
  
  	tuple = heap_formtuple(RelationGetDescr(pg_index), values, nulls);
  
***************
*** 952,957 ****
--- 953,959 ----
  	/* initialize index-build state to default */
  	ii->ii_Concurrent = false;
  	ii->ii_BrokenHotChain = false;
+ 	ii->ii_WithSnapshot =  indexStruct->indhassnapshot;
  
  	return ii;
  }
***************
*** 1028,1033 ****
--- 1030,1045 ----
  		isnull[i] = isNull;
  	}
  
+ 	if(indexInfo->ii_WithSnapshot)
+ 	{
+ 		HeapTupleHeader htuph = slot->tts_tuple->t_data;
+ 		HeapTupleFields *htupf = &(htuph->t_choice.t_heap);
+ 		values[INDEX_MAX_KEYS] = TransactionIdGetDatum(htupf->t_xmin);
+ 		values[INDEX_MAX_KEYS+1] = TransactionIdGetDatum(htupf->t_xmax);
+ 		values[INDEX_MAX_KEYS+2] = CommandIdGetDatum(htupf->t_field3.t_cid);
+ 		values[INDEX_MAX_KEYS+3] = UInt16GetDatum(htuph->t_infomask);
+ 	}
+ 
  	if (indexpr_item != NULL)
  		elog(ERROR, "wrong number of index expressions");
  }
***************
*** 1397,1404 ****
  {
  	HeapScanDesc scan;
  	HeapTuple	heapTuple;
! 	Datum		values[INDEX_MAX_KEYS];
! 	bool		isnull[INDEX_MAX_KEYS];
  	double		reltuples;
  	List	   *predicate;
  	TupleTableSlot *slot;
--- 1409,1416 ----
  {
  	HeapScanDesc scan;
  	HeapTuple	heapTuple;
! 	Datum		values[INDEX_MAX_KEYS + SNAPSHOT_KEYS];
! 	bool		isnull[INDEX_MAX_KEYS + SNAPSHOT_KEYS];
  	double		reltuples;
  	List	   *predicate;
  	TupleTableSlot *slot;
***************
*** 2073,2079 ****
  						 isnull,
  						 &rootTuple,
  						 heapRelation,
! 						 indexInfo->ii_Unique);
  
  			state->tups_inserted += 1;
  		}
--- 2085,2092 ----
  						 isnull,
  						 &rootTuple,
  						 heapRelation,
! 						 indexInfo->ii_Unique,
! 						 NULL);
  
  			state->tups_inserted += 1;
  		}
*** postgresql-8.3beta1/src/backend/utils/sort/tuplesort.c	Sat Sep  1 14:47:39 2007
--- postgresql-8.3patch/src/backend/utils/sort/tuplesort.c	Tue Oct 16 23:53:44 2007
***************
*** 2688,2695 ****
  		bool		isnull1,
  					isnull2;
  
! 		datum1 = index_getattr(tuple1, nkey, tupDes, &isnull1);
! 		datum2 = index_getattr(tuple2, nkey, tupDes, &isnull2);
  
  		compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
  										  datum1, isnull1,
--- 2688,2695 ----
  		bool		isnull1,
  					isnull2;
  
! 		datum1 = allindex_getattr(tuple1, nkey, tupDes, &isnull1, get_index_type(state->indexRel));
! 		datum2 = allindex_getattr(tuple2, nkey, tupDes, &isnull2, get_index_type(state->indexRel));
  
  		compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
  										  datum1, isnull1,
***************
*** 2760,2769 ****
  	USEMEM(state, GetMemoryChunkSpace(newtuple));
  	stup->tuple = (void *) newtuple;
  	/* set up first-column key value */
! 	stup->datum1 = index_getattr(newtuple,
  								 1,
  								 RelationGetDescr(state->indexRel),
! 								 &stup->isnull1);
  }
  
  static void
--- 2760,2770 ----
  	USEMEM(state, GetMemoryChunkSpace(newtuple));
  	stup->tuple = (void *) newtuple;
  	/* set up first-column key value */
! 	stup->datum1 = allindex_getattr(newtuple,
  								 1,
  								 RelationGetDescr(state->indexRel),
! 								 &stup->isnull1,
! 								 get_index_type(state->indexRel));
  }
  
  static void
***************
*** 2802,2811 ****
  			elog(ERROR, "unexpected end of data");
  	stup->tuple = (void *) tuple;
  	/* set up first-column key value */
! 	stup->datum1 = index_getattr(tuple,
  								 1,
  								 RelationGetDescr(state->indexRel),
! 								 &stup->isnull1);
  }
  
  static void
--- 2803,2813 ----
  			elog(ERROR, "unexpected end of data");
  	stup->tuple = (void *) tuple;
  	/* set up first-column key value */
! 	stup->datum1 = allindex_getattr(tuple,
  								 1,
  								 RelationGetDescr(state->indexRel),
! 								 &stup->isnull1, 
! 								 get_index_type(state->indexRel));
  }
  
  static void
*** postgresql-8.3beta1/src/backend/utils/time/tqual.c	Fri Sep 21 14:24:28 2007
--- postgresql-8.3patch/src/backend/utils/time/tqual.c	Fri Oct 19 23:01:56 2007
***************
*** 38,43 ****
--- 38,44 ----
  
  #include "postgres.h"
  
+ #include "access/itup.h"
  #include "access/multixact.h"
  #include "access/subtrans.h"
  #include "access/transam.h"
***************
*** 126,131 ****
--- 127,150 ----
  	SetBufferCommitInfoNeedsSave(buffer);
  }
  
+ static inline void 
+ SetIndexHintBits(SnapshotFields snpf, Buffer buffer,
+ 			uint16 infomask, TransactionId xid)
+ {
+ 	if (TransactionIdIsValid(xid))
+ 	{
+ 		/* NB: xid must be known committed here! */
+ 		XLogRecPtr  commitLSN = TransactionIdGetCommitLSN(xid);
+ 
+ 		if (XLogNeedsFlush(commitLSN))
+ 			return;				/* not flushed yet, so don't set hint */
+ 	}
+ 
+ 	snpf->infomask |= infomask;
+ 	SetBufferCommitInfoNeedsSave(buffer);
+ }
+ 
+ 
  /*
   * HeapTupleSetHintBits --- exported version of SetHintBits()
   *
***************
*** 1044,1050 ****
--- 1063,1171 ----
  	return false;
  }
  
+ bool IndexTupleSatisfiesMVCC(IndexTuple tuple, Snapshot snapshot,
+ 					   Buffer buffer)
+ {
+ 	SnapshotFields snpf = GetIndexSnapshotFields(tuple);
+ 	if (!(snpf->infomask & HEAP_XMIN_COMMITTED))
+ 	{
+ 		if (snpf->infomask & HEAP_XMIN_INVALID)
+ 			return false;
  
+ 		if (TransactionIdIsCurrentTransactionId(SnapshotFieldsGetXmin(snpf)))
+ 		{
+ 			if (SnapshotFieldsGetCmin(snpf) >= snapshot->curcid)
+ 				return false;	/* inserted after scan started */
+ 
+ 			if (snpf->infomask & HEAP_XMAX_INVALID)	/* xid invalid */
+ 				return true;
+ 
+ 			Assert(!(snpf->infomask & HEAP_XMAX_IS_MULTI));
+ 
+ 			if (!TransactionIdIsCurrentTransactionId(SnapshotFieldsGetXmax(snpf)))
+ 			{
+ 				/* deleting subtransaction must have aborted */
+ 				SetIndexHintBits(snpf, buffer, HEAP_XMAX_INVALID,
+ 							InvalidTransactionId);
+ 				return true;
+ 			}
+ 
+ 			if (SnapshotFieldsGetCmax(snpf) >= snapshot->curcid)
+ 				return true;	/* deleted after scan started */
+ 			else
+ 				return false;	/* deleted before scan started */
+ 		}
+ 		else if (TransactionIdIsInProgress(SnapshotFieldsGetXmin(snpf)))
+ 			return false;
+ 		else if (TransactionIdDidCommit(SnapshotFieldsGetXmin(snpf)))
+ 			SetIndexHintBits(snpf, buffer, HEAP_XMIN_COMMITTED,
+ 						SnapshotFieldsGetXmin(snpf));
+ 		else
+ 		{
+ 			/* it must have aborted or crashed */
+ 			SetIndexHintBits(snpf, buffer, HEAP_XMIN_INVALID,
+ 						InvalidTransactionId);
+ 			return false;
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * By here, the inserting transaction has committed - have to check
+ 	 * when...
+ 	 */
+ 	if (XidInMVCCSnapshot(SnapshotFieldsGetXmin(snpf), snapshot))
+ 		return false;			/* treat as still in progress */
+ 
+ 	if (snpf->infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
+ 		return true;
+ 
+ 	if (snpf->infomask & HEAP_IS_LOCKED)
+ 		return true;
+ 
+ 	if (snpf->infomask & HEAP_XMAX_IS_MULTI)
+ 	{
+ 		/* MultiXacts are currently only allowed to lock tuples */
+ 		Assert(snpf->infomask & HEAP_IS_LOCKED);
+ 		return true;
+ 	}
+ 
+ 	if (!(snpf->infomask & HEAP_XMAX_COMMITTED))
+ 	{
+ 		if (TransactionIdIsCurrentTransactionId(SnapshotFieldsGetXmax(snpf)))
+ 		{
+ 			if (SnapshotFieldsGetCmax(snpf) >= snapshot->curcid)
+ 				return true;	/* deleted after scan started */
+ 			else
+ 				return false;	/* deleted before scan started */
+ 		}
+ 
+ 		if (TransactionIdIsInProgress(SnapshotFieldsGetXmax(snpf)))
+ 			return true;
+ 
+ 		if (!TransactionIdDidCommit(SnapshotFieldsGetXmax(snpf)))
+ 		{
+ 			/* it must have aborted or crashed */
+ 			SetIndexHintBits(snpf, buffer, HEAP_XMAX_INVALID,
+ 						InvalidTransactionId);
+ 			return true;
+ 		}
+ 
+ 		/* xmax transaction committed */
+ 		SetIndexHintBits(snpf, buffer, HEAP_XMAX_COMMITTED,
+ 					SnapshotFieldsGetXmax(snpf));
+ 	}
+ 
+ 	/*
+ 	 * OK, the deleting transaction committed too ... but when?
+ 	 */
+ 	if (XidInMVCCSnapshot(SnapshotFieldsGetXmax(snpf), snapshot))
+ 		return true;			/* treat as still in progress */
+ 
+ 	return false;
+ }
+ 
+ 
+ 
  /*
   * HeapTupleSatisfiesVacuum
   *
***************
*** 1427,1429 ****
--- 1548,1650 ----
  
  	return false;
  }
+ HTSV_Result
+ IndexTupleSatisfiesVacuum(IndexTuple tuple, TransactionId OldestXmin,
+ 						 Buffer buffer)
+ {
+ 	SnapshotFields snpf = GetIndexSnapshotFields(tuple);	
+ 	/*
+ 	 * Has inserting transaction committed?
+ 	 *
+ 	 * If the inserting transaction aborted, then the tuple was never visible
+ 	 * to any other transaction, so we can delete it immediately.
+ 	 */
+ 	if (!(snpf->infomask & HEAP_XMIN_COMMITTED))
+ 	{
+ 		if (snpf->infomask & HEAP_XMIN_INVALID)
+ 			return HEAPTUPLE_DEAD;
+ 		else if (TransactionIdIsInProgress(SnapshotFieldsGetXmin(snpf)))
+ 		{
+ 			if (snpf->infomask & HEAP_XMAX_INVALID)	/* xid invalid */
+ 				return HEAPTUPLE_INSERT_IN_PROGRESS;
+ 			if (snpf->infomask & HEAP_IS_LOCKED)
+ 				return HEAPTUPLE_INSERT_IN_PROGRESS;
+ 			/* inserted and then deleted by same xact */
+ 			return HEAPTUPLE_DELETE_IN_PROGRESS;
+ 		}
+ 		else if (TransactionIdDidCommit(SnapshotFieldsGetXmin(snpf)))
+ 			SetIndexHintBits(snpf, buffer, HEAP_XMIN_COMMITTED,
+ 						SnapshotFieldsGetXmin(snpf));
+ 		else
+ 		{
+ 			/*
+ 			 * Not in Progress, Not Committed, so either Aborted or crashed
+ 			 */
+ 			SetIndexHintBits(snpf, buffer, HEAP_XMIN_INVALID,
+ 						InvalidTransactionId);
+ 			return HEAPTUPLE_DEAD;
+ 		}
+ 		/*
+ 		 * At this point the xmin is known committed, but we might not have
+ 		 * been able to set the hint bit yet; so we can no longer Assert
+ 		 * that it's set.
+ 		 */
+ 	}
+ 
+ 	/*
+ 	 * Okay, the inserter committed, so it was good at some point.	Now what
+ 	 * about the deleting transaction?
+ 	 */
+ 	if (snpf->infomask & HEAP_XMAX_INVALID)
+ 		return HEAPTUPLE_LIVE;
+ 
+ 	if (!(snpf->infomask & HEAP_XMAX_COMMITTED))
+ 	{
+ 		if (TransactionIdIsInProgress(SnapshotFieldsGetXmax(snpf)))
+ 			return HEAPTUPLE_DELETE_IN_PROGRESS;
+ 		else if (TransactionIdDidCommit(SnapshotFieldsGetXmax(snpf)))
+ 			SetIndexHintBits(snpf, buffer, HEAP_XMAX_COMMITTED,
+ 						SnapshotFieldsGetXmax(snpf));
+ 		else
+ 		{
+ 			/*
+ 			 * Not in Progress, Not Committed, so either Aborted or crashed
+ 			 */
+ 			SetIndexHintBits(snpf, buffer, HEAP_XMAX_INVALID,
+ 						InvalidTransactionId);
+ 			return HEAPTUPLE_LIVE;
+ 		}
+ 		/*
+ 		 * At this point the xmax is known committed, but we might not have
+ 		 * been able to set the hint bit yet; so we can no longer Assert
+ 		 * that it's set.
+ 		 */
+ 	}
+ 
+ 	/*
+ 	 * Deleter committed, but check special cases.
+ 	 */
+ 
+ 	if (TransactionIdEquals(SnapshotFieldsGetXmin(snpf),
+ 							SnapshotFieldsGetXmax(snpf)))
+ 	{
+ 		/*
+ 		 * Inserter also deleted it, so it was never visible to anyone else.
+ 		 * However, we can only remove it early if it's not an updated tuple;
+ 		 * else its parent tuple is linking to it via t_ctid, and this tuple
+ 		 * mustn't go away before the parent does.
+ 		 */
+ 		if (!(snpf->infomask & HEAP_UPDATED))
+ 			return HEAPTUPLE_DEAD;
+ 	}
+ 
+ 	if (!TransactionIdPrecedes(SnapshotFieldsGetXmax(snpf), OldestXmin))
+ 	{
+ 		/* deleting xact is too recent, tuple could still be visible */
+ 		return HEAPTUPLE_RECENTLY_DEAD;
+ 	}
+ 
+ 	/* Otherwise, it's dead and removable */
+ 	return HEAPTUPLE_DEAD;
+ }
+ 
*** postgresql-8.3beta1/src/backend/utils/time/combocid.c	Thu Feb  8 22:35:34 2007
--- postgresql-8.3patch/src/backend/utils/time/combocid.c	Sun Oct 14 17:58:43 2007
***************
*** 42,47 ****
--- 42,48 ----
  #include "postgres.h"
  
  #include "access/htup.h"
+ #include "access/itup.h"
  #include "access/xact.h"
  #include "utils/combocid.h"
  #include "utils/hsearch.h"
***************
*** 128,133 ****
--- 129,164 ----
  		return cid;
  }
  
+ CommandId
+ SnapshotFieldsGetCmin(SnapshotFields snpf)
+ {
+ 	CommandId cid = SnapshotFieldsGetRawCommandId(snpf);
+ 
+ 	Assert(!(snpf->infomask & HEAP_MOVED));
+ 	Assert(TransactionIdIsCurrentTransactionId(SnapshotFieldsGetXmin(snpf)));
+ 
+ 	if (snpf->infomask & HEAP_COMBOCID)
+ 		return GetRealCmin(cid);
+ 	else
+ 		return cid;
+ }
+ 
+ CommandId
+ SnapshotFieldsGetCmax(SnapshotFields snpf)
+ {
+ 	CommandId cid = SnapshotFieldsGetRawCommandId(snpf);
+ 
+ 	/* We do not store cmax when locking a tuple */
+ 	Assert(!(snpf->infomask & (HEAP_MOVED | HEAP_IS_LOCKED)));
+ 	Assert(TransactionIdIsCurrentTransactionId(SnapshotFieldsGetXmax(snpf)));
+ 
+ 	if (snpf->infomask & HEAP_COMBOCID)
+ 		return GetRealCmax(cid);
+ 	else
+ 		return cid;
+ }
+ 
+ 
  /*
   * Given a tuple we are about to delete, determine the correct value to store
   * into its t_cid field.
*** postgresql-8.3beta1/src/backend/optimizer/path/costsize.c	Sat Sep 22 17:36:40 2007
--- postgresql-8.3patch/src/backend/optimizer/path/costsize.c	Fri Oct 19 23:25:05 2007
***************
*** 89,94 ****
--- 89,95 ----
  
  
  double		seq_page_cost = DEFAULT_SEQ_PAGE_COST;
+ double          index_only_scan_factor = DEFAULT_INDEX_ONLY_SCAN_FACTOR;
  double		random_page_cost = DEFAULT_RANDOM_PAGE_COST;
  double		cpu_tuple_cost = DEFAULT_CPU_TUPLE_COST;
  double		cpu_index_tuple_cost = DEFAULT_CPU_INDEX_TUPLE_COST;
***************
*** 124,129 ****
--- 125,131 ----
  static void set_rel_width(PlannerInfo *root, RelOptInfo *rel);
  static double relation_byte_size(double tuples, int width);
  static double page_size(double tuples, int width);
+ static bool IndexOnlyScan(IndexOptInfo* index, List *OrigQuals, List *targetList, List *indexQuals );
  
  
  /*
***************
*** 377,384 ****
--- 379,431 ----
  
  	path->path.startup_cost = startup_cost;
  	path->path.total_cost = startup_cost + run_cost;
+         if(IndexOnlyScan(index, baserel->baserestrictinfo, baserel->reltargetlist, indexQuals))
+         {
+             path->index_only_scan = true;
+             run_cost = run_cost/index_only_scan_factor;
+             path->path.total_cost = startup_cost + run_cost;
+         }
  }
  
+ static bool IndexOnlyScan(IndexOptInfo* index, List *OrigQuals, List *targetList, List *indexQuals )
+ {
+         int i,j;
+         Var *var;
+         bool found;
+         ListCell *tlist_item = list_head(targetList);
+ 
+         if(!index->has_snapshot)
+             return false;
+         
+         if(OrigQuals->length != indexQuals->length)
+             return false;
+ 
+          if(!targetList)
+              return true;
+         
+         for(i=0; i< targetList->length ; i++)
+         {
+             found = false;
+             if(((Node *)lfirst(tlist_item))->type != T_Var)
+                 return false;
+             var = (Var *) lfirst(tlist_item);
+             for(j=0; j<index->ncolumns; j++)
+             {
+                 if(var->varattno == index->indexkeys[j])
+                 {
+                     found = true;
+                     break;
+                 }
+             }
+             if(!found)
+                 return false;
+             if(i < (targetList->length -1))
+                 tlist_item = lnext(tlist_item);
+         }
+         
+         return true;
+ }
+ 
  /*
   * index_pages_fetched
   *	  Estimate the number of pages actually fetched after accounting for
*** postgresql-8.3beta1/src/backend/optimizer/util/plancat.c	Thu Sep 20 13:56:31 2007
--- postgresql-8.3patch/src/backend/optimizer/util/plancat.c	Thu Oct 18 14:28:31 2007
***************
*** 268,273 ****
--- 268,274 ----
  				ChangeVarNodes((Node *) info->indpred, 1, varno, 0);
  			info->predOK = false;		/* set later in indxpath.c */
  			info->unique = index->indisunique;
+ 			info->has_snapshot = index->indhassnapshot;
  
  			/*
  			 * Estimate the index size.  If it's not a partial index, we lock
*** postgresql-8.3beta1/src/backend/optimizer/util/pathnode.c	Thu May  3 21:13:44 2007
--- postgresql-8.3patch/src/backend/optimizer/util/pathnode.c	Thu Oct 18 16:01:51 2007
***************
*** 465,470 ****
--- 465,471 ----
  	pathnode->indexquals = indexquals;
  
  	pathnode->isjoininner = (outer_rel != NULL);
+ 	pathnode->index_only_scan = FALSE;
  	pathnode->indexscandir = indexscandir;
  
  	if (outer_rel != NULL)
*** postgresql-8.3beta1/src/backend/optimizer/plan/createplan.c	Mon May 21 13:57:34 2007
--- postgresql-8.3patch/src/backend/optimizer/plan/createplan.c	Thu Oct 18 17:59:43 2007
***************
*** 83,89 ****
  static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
  			   Oid indexid, List *indexqual, List *indexqualorig,
  			   List *indexstrategy, List *indexsubtype,
! 			   ScanDirection indexscandir);
  static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid,
  					  List *indexqual,
  					  List *indexqualorig,
--- 83,89 ----
  static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
  			   Oid indexid, List *indexqual, List *indexqualorig,
  			   List *indexstrategy, List *indexsubtype,
! 			   ScanDirection indexscandir, bool index_only_scan);
  static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid,
  					  List *indexqual,
  					  List *indexqualorig,
***************
*** 967,973 ****
  							   stripped_indexquals,
  							   indexstrategy,
  							   indexsubtype,
! 							   best_path->indexscandir);
  
  	copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
  	/* use the indexscan-specific rows estimate, not the parent rel's */
--- 967,974 ----
  							   stripped_indexquals,
  							   indexstrategy,
  							   indexsubtype,
! 							   best_path->indexscandir,
!                                                            best_path->index_only_scan);
  
  	copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
  	/* use the indexscan-specific rows estimate, not the parent rel's */
***************
*** 2282,2288 ****
  			   List *indexqualorig,
  			   List *indexstrategy,
  			   List *indexsubtype,
! 			   ScanDirection indexscandir)
  {
  	IndexScan  *node = makeNode(IndexScan);
  	Plan	   *plan = &node->scan.plan;
--- 2283,2290 ----
  			   List *indexqualorig,
  			   List *indexstrategy,
  			   List *indexsubtype,
! 			   ScanDirection indexscandir,
!                            bool  index_only_scan)
  {
  	IndexScan  *node = makeNode(IndexScan);
  	Plan	   *plan = &node->scan.plan;
***************
*** 2299,2304 ****
--- 2301,2307 ----
  	node->indexstrategy = indexstrategy;
  	node->indexsubtype = indexsubtype;
  	node->indexorderdir = indexscandir;
+         node->indexOnlyScan = index_only_scan;
  
  	return node;
  }
*** postgresql-8.3beta1/src/backend/parser/keywords.c	Sun Sep 23 21:29:29 2007
--- postgresql-8.3patch/src/backend/parser/keywords.c	Fri Oct 19 02:35:46 2007
***************
*** 351,356 ****
--- 351,357 ----
  	{"temporary", TEMPORARY, UNRESERVED_KEYWORD},
  	{"text", TEXT_P, UNRESERVED_KEYWORD},
  	{"then", THEN, RESERVED_KEYWORD},
+ 	{"thick", THICK, UNRESERVED_KEYWORD},
  	{"time", TIME, COL_NAME_KEYWORD},
  	{"timestamp", TIMESTAMP, COL_NAME_KEYWORD},
  	{"to", TO, RESERVED_KEYWORD},
*** postgresql-8.3beta1/src/backend/parser/parse_oper.c	Sun Apr  1 23:49:39 2007
--- postgresql-8.3patch/src/backend/parser/parse_oper.c	Tue Oct 16 23:49:01 2007
***************
*** 29,39 ****
  #include "utils/typcache.h"
  
  
- static Oid	binary_oper_exact(List *opname, Oid arg1, Oid arg2);
- static FuncDetailCode oper_select_candidate(int nargs,
- 					  Oid *input_typeids,
- 					  FuncCandidateList candidates,
- 					  Oid *operOid);
  static const char *op_signature_string(List *op, char oprkind,
  					Oid arg1, Oid arg2);
  static void op_error(ParseState *pstate, List *op, char oprkind,
--- 29,34 ----
***************
*** 383,389 ****
   * the possibility that the other operand is a domain type that needs to
   * be reduced to its base type to find an "exact" match.
   */
! static Oid
  binary_oper_exact(List *opname, Oid arg1, Oid arg2)
  {
  	Oid			result;
--- 378,384 ----
   * the possibility that the other operand is a domain type that needs to
   * be reduced to its base type to find an "exact" match.
   */
! Oid
  binary_oper_exact(List *opname, Oid arg1, Oid arg2)
  {
  	Oid			result;
***************
*** 433,439 ****
   * exactly matching the input argtype(s).  Incompatible candidates are not yet
   * pruned away, however.
   */
! static FuncDetailCode
  oper_select_candidate(int nargs,
  					  Oid *input_typeids,
  					  FuncCandidateList candidates,
--- 428,434 ----
   * exactly matching the input argtype(s).  Incompatible candidates are not yet
   * pruned away, however.
   */
! FuncDetailCode
  oper_select_candidate(int nargs,
  					  Oid *input_typeids,
  					  FuncCandidateList candidates,
*** postgresql-8.3beta1/src/backend/tcop/utility.c	Mon Sep  3 14:46:30 2007
--- postgresql-8.3patch/src/backend/tcop/utility.c	Sat Oct 13 00:40:33 2007
***************
*** 932,938 ****
  							true,		/* check_rights */
  							false,		/* skip_build */
  							false,		/* quiet */
! 							stmt->concurrent);	/* concurrent */
  			}
  			break;
  
--- 932,939 ----
  							true,		/* check_rights */
  							false,		/* skip_build */
  							false,		/* quiet */
! 							stmt->concurrent, /* concurrent */
! 							stmt->withSnapshot ); /* Whether to store snapshot with index */	  
  			}
  			break;
  
*** postgresql-8.3beta1/src/backend/nodes/copyfuncs.c	Mon Sep  3 14:46:30 2007
--- postgresql-8.3patch/src/backend/nodes/copyfuncs.c	Sat Oct 13 11:54:34 2007
***************
*** 2200,2205 ****
--- 2200,2206 ----
  	COPY_SCALAR_FIELD(primary);
  	COPY_SCALAR_FIELD(isconstraint);
  	COPY_SCALAR_FIELD(concurrent);
+ 	COPY_SCALAR_FIELD(withSnapshot);
  
  	return newnode;
  }
*** postgresql-8.3beta1/src/backend/bootstrap/bootparse.c	Fri Oct  5 00:36:51 2007
--- postgresql-8.3patch/src/backend/bootstrap/bootparse.c	Sat Oct 13 00:38:03 2007
***************
*** 1320,1326 ****
  								yyvsp[-1].list,
  								NULL, NIL, NULL,
  								false, false, false,
! 								false, false, true, false, false);
  					do_end();
  				}
      break;
--- 1320,1326 ----
  								yyvsp[-1].list,
  								NULL, NIL, NULL,
  								false, false, false,
! 								false, false, true, false, false, false);
  					do_end();
  				}
      break;
***************
*** 1338,1344 ****
  								yyvsp[-1].list,
  								NULL, NIL, NULL,
  								true, false, false,
! 								false, false, true, false, false);
  					do_end();
  				}
      break;
--- 1338,1344 ----
  								yyvsp[-1].list,
  								NULL, NIL, NULL,
  								true, false, false,
! 								false, false, true, false, false, false);
  					do_end();
  				}
      break;
*** postgresql-8.3beta1/src/backend/executor/nodeAppend.c	Fri Jan  5 17:19:28 2007
--- postgresql-8.3patch/src/backend/executor/nodeAppend.c	Tue Oct 23 13:46:45 2007
***************
*** 268,273 ****
--- 268,285 ----
  		 */
  		result = ExecProcNode(subnode);
  
+                 /*
+                  * Old Tuple is needed for Indexes with Snapshots. Hence this assignment
+                  */
+                  if(!node->ps.ps_ExprContext)
+                     node->ps.ps_ExprContext = subnode->ps_ExprContext;
+                  else
+                     {
+                         /*
+                          *  We are in trouble. Has to find out some way to get the old tuple
+                          */
+                     }
+ 
  		if (!TupIsNull(result))
  		{
  			/*
*** postgresql-8.3beta1/src/backend/executor/nodeIndexscan.c	Thu May 31 16:45:26 2007
--- postgresql-8.3patch/src/backend/executor/nodeIndexscan.c	Fri Oct 19 00:41:29 2007
***************
*** 55,60 ****
--- 55,61 ----
  	Index		scanrelid;
  	HeapTuple	tuple;
  	TupleTableSlot *slot;
+         bool    isIndexOnlyScan;
  
  	/*
  	 * extract necessary information from index scan node
***************
*** 70,75 ****
--- 71,78 ----
  			direction = ForwardScanDirection;
  	}
  	scandesc = node->iss_ScanDesc;
+         if(scandesc->sindex_params)
+             scandesc->sindex_params->isIndexOnlyScan = ((IndexScan *) node->ss.ps.plan)->indexOnlyScan;
  	econtext = node->ss.ps.ps_ExprContext;
  	slot = node->ss.ss_ScanTupleSlot;
  	scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
***************
*** 102,107 ****
--- 105,115 ----
  
  		return slot;
  	}
+         
+         isIndexOnlyScan = scandesc->sindex_params && scandesc->sindex_params->isIndexOnlyScan;
+         
+         if(isIndexOnlyScan)
+               scandesc->sindex_params->slot = slot;
  
  	/*
  	 * ok, now that we have what we need, fetch the next tuple.
***************
*** 113,119 ****
  		 * Note: we pass 'false' because tuples returned by amgetnext are
  		 * pointers onto disk pages and must not be pfree()'d.
  		 */
! 		ExecStoreTuple(tuple,	/* tuple to store */
  					   slot,	/* slot to store in */
  					   scandesc->xs_cbuf,		/* buffer containing tuple */
  					   false);	/* don't pfree */
--- 121,128 ----
  		 * Note: we pass 'false' because tuples returned by amgetnext are
  		 * pointers onto disk pages and must not be pfree()'d.
  		 */
!                   if(!isIndexOnlyScan)
!                             ExecStoreTuple(tuple,	/* tuple to store */
  					   slot,	/* slot to store in */
  					   scandesc->xs_cbuf,		/* buffer containing tuple */
  					   false);	/* don't pfree */
*** postgresql-8.3beta1/src/backend/executor/execUtils.c	Thu Sep 20 13:56:31 2007
--- postgresql-8.3patch/src/backend/executor/execUtils.c	Thu Oct 18 23:23:54 2007
***************
*** 44,52 ****
--- 44,56 ----
  
  #include "access/genam.h"
  #include "access/heapam.h"
+ #include "access/nbtree.h"
  #include "catalog/index.h"
+ #include "catalog/namespace.h"
  #include "executor/execdebug.h"
  #include "parser/parsetree.h"
+ #include "parser/parse_func.h"
+ #include "utils/lsyscache.h"
  #include "utils/memutils.h"
  #include "utils/relcache.h"
  
***************
*** 66,73 ****
--- 70,87 ----
  
  
  static void ShutdownExprContext(ExprContext *econtext);
+ static IndexScanDesc index_form_iscan(Relation heapRelation, 
+ 				Relation indexRelation, 
+ 				Datum *values,
+ 				bool  *isnull,
+ 				CmdType operation);
+ static void index_free_iscan(IndexScanDesc iscan);
+ static ScanKey index_skey(Relation rel, Datum *values, bool *isnull, char skey_type );
+ static bool FindIndexUpdation(int natts, Datum *values1, bool *isnull1, Datum *values2, bool *isnull2);
  
  
+ 
+ 
  /* ----------------------------------------------------------------
   *						statistic functions
   * ----------------------------------------------------------------
***************
*** 1000,1007 ****
  	Relation	heapRelation;
  	IndexInfo **indexInfoArray;
  	ExprContext *econtext;
! 	Datum		values[INDEX_MAX_KEYS];
! 	bool		isnull[INDEX_MAX_KEYS];
  
  	/*
  	 * Get information from the result relation info structure.
--- 1014,1021 ----
  	Relation	heapRelation;
  	IndexInfo **indexInfoArray;
  	ExprContext *econtext;
! 	Datum		values[INDEX_MAX_KEYS + SNAPSHOT_KEYS];
! 	bool		isnull[INDEX_MAX_KEYS + SNAPSHOT_KEYS];
  
  	/*
  	 * Get information from the result relation info structure.
***************
*** 1080,1086 ****
  					 isnull,	/* null flags */
  					 tupleid,	/* tid of heap tuple */
  					 heapRelation,
! 					 relationDescs[i]->rd_index->indisunique && !is_vacuum);
  
  		/*
  		 * keep track of index inserts for debugging
--- 1094,1101 ----
  					 isnull,	/* null flags */
  					 tupleid,	/* tid of heap tuple */
  					 heapRelation,
! 					 relationDescs[i]->rd_index->indisunique && !is_vacuum,
! 					 NULL);
  
  		/*
  		 * keep track of index inserts for debugging
***************
*** 1089,1094 ****
--- 1104,1514 ----
  	}
  }
  
+ void
+ ExecDeleteIndexTuples(TupleTableSlot *slot,
+ 					  ItemPointer tupleid,
+ 					  EState *estate,
+ 					  bool is_vacuum)
+ {
+ 	ResultRelInfo *resultRelInfo;
+ 	int			i;
+ 	int			numIndices;
+ 	RelationPtr relationDescs;
+ 	Relation	heapRelation;
+ 	IndexInfo **indexInfoArray;
+ 	ExprContext *econtext;
+ 	TupleDesc	tupdesc;
+ 	Datum		values[INDEX_MAX_KEYS];
+ 	bool		isnull[INDEX_MAX_KEYS];
+ 	int 		natts;
+ 	IndexScanDesc   iscan;
+ 	ScanKey         iskey;
+ 
+ 	/*
+ 	 * Get information from the result relation info structure.
+ 	 */
+ 	resultRelInfo = estate->es_result_relation_info;
+ 	numIndices = resultRelInfo->ri_NumIndices;
+ 	relationDescs = resultRelInfo->ri_IndexRelationDescs;
+ 	indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
+ 	heapRelation = resultRelInfo->ri_RelationDesc;
+ 	tupdesc = RelationGetDescr(heapRelation);
+ 	natts   = tupdesc->natts;
+ 
+ 	/*
+ 	 * We will use the EState's per-tuple context for evaluating predicates
+ 	 * and index expressions (creating it if it's not already there).
+ 	 */
+ 	econtext = GetPerTupleExprContext(estate);
+ 
+ 	/* Arrange for econtext's scan tuple to be the tuple under test */
+ 	econtext->ecxt_scantuple = slot;
+ 
+ 	/*
+ 	 * for each index, form and insert the index tuple
+ 	 */
+ 	for (i = 0; i < numIndices; i++)
+ 	{
+ 		IndexInfo  *indexInfo;
+ 
+ 		if ((relationDescs[i] == NULL)  ||  (!(relationDescs[i]->rd_index->indhassnapshot)) )
+ 			continue;
+ 
+ 		indexInfo = indexInfoArray[i];
+ 
+ 		/* If the index is marked as read-only, ignore it */
+ 		if (!indexInfo->ii_ReadyForInserts)
+ 			continue;
+ 
+ 		/* Check for partial index */
+ 		if (indexInfo->ii_Predicate != NIL)
+ 		{
+ 			List	   *predicate;
+ 
+ 			/*
+ 			 * If predicate state not set up yet, create it (in the estate's
+ 			 * per-query context)
+ 			 */
+ 			predicate = indexInfo->ii_PredicateState;
+ 			if (predicate == NIL)
+ 			{
+ 				predicate = (List *)
+ 					ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
+ 									estate);
+ 				indexInfo->ii_PredicateState = predicate;
+ 			}
+ 
+ 			/* Skip this index-update if the predicate isn't satisfied */
+ 			if (!ExecQual(predicate, econtext, false))
+ 				continue;
+ 		}
+ 		
+ 	
+ 		FormIndexDatum(indexInfo,
+ 					   slot,
+ 					   estate,
+ 					   values,
+ 					   isnull);
+ 
+ 		iscan = index_form_iscan(heapRelation, relationDescs[i], values, isnull, CMD_DELETE);
+ 		iskey = index_skey(relationDescs[i], values, isnull, SK_INSERTION);
+ 		iscan->sindex_params->insertion_skey = iskey;
+ 		iscan->sindex_params->htup = slot->tts_tuple;
+ 
+ 		/*
+ 		 * The index AM does the rest.	
+ 		 */
+ 		index_getnext(iscan, ForwardScanDirection);
+ 
+ 		index_free_iscan(iscan);
+ 
+ 	}
+ }
+ 
+ void
+ ExecUpdateIndexTuples(TupleTableSlot *oldslot, TupleTableSlot *newslot,
+ 					  ItemPointer tupleid,
+ 					  EState *estate,
+ 					  bool is_vacuum,
+ 					  bool is_HOT_Tuple)
+ {
+ 	ResultRelInfo *resultRelInfo;
+ 	int			i;
+ 	int			numIndices;
+ 	RelationPtr relationDescs;
+ 	Relation	heapRelation;
+ 	IndexInfo **indexInfoArray;
+ 	ExprContext *econtext;
+ 	TupleDesc	tupdesc;
+ 	Datum		values_old[INDEX_MAX_KEYS];
+ 	bool		isnull_old[INDEX_MAX_KEYS];
+ 	Datum		values_new[INDEX_MAX_KEYS];
+ 	bool		isnull_new[INDEX_MAX_KEYS];
+ 	int 		natts;
+ 	IndexScanDesc   iscan;
+ 	ScanKey         iskey;
+ 	bool            ind_has_snapshot;
+ 
+ 	/*
+ 	 * Get information from the result relation info structure.
+ 	 */
+ 	resultRelInfo = estate->es_result_relation_info;
+ 	numIndices = resultRelInfo->ri_NumIndices;
+ 	relationDescs = resultRelInfo->ri_IndexRelationDescs;
+ 	indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
+ 	heapRelation = resultRelInfo->ri_RelationDesc;
+ 	tupdesc = RelationGetDescr(heapRelation);
+ 	natts   = tupdesc->natts;
+ 
+ 	/*
+ 	 * We will use the EState's per-tuple context for evaluating predicates
+ 	 * and index expressions (creating it if it's not already there).
+ 	 */
+ 	econtext = GetPerTupleExprContext(estate);
+ 
+ 	/* Arrange for econtext's scan tuple to be the tuple under test */
+ 	econtext->ecxt_scantuple = oldslot;
+ 
+ 	/*
+ 	 * for each index, form and insert the index tuple
+ 	 */
+ 	for (i = 0; i < numIndices; i++)
+ 	{
+ 		IndexInfo  *indexInfo;
+ 		bool        is_index_updated = false;
+ 		ind_has_snapshot = relationDescs[i]->rd_index->indhassnapshot;
+ 
+ 		if (relationDescs[i] == NULL)  
+ 			continue;
+ 
+ 		if(!(ind_has_snapshot) && (is_HOT_Tuple))
+ 			continue;
+ 
+ 		indexInfo = indexInfoArray[i];
+ 
+ 		/* If the index is marked as read-only, ignore it */
+ 		if (!indexInfo->ii_ReadyForInserts)
+ 			continue;
+ 
+ 		/* Check for partial index */
+ 		if (indexInfo->ii_Predicate != NIL)
+ 		{
+ 			List	   *predicate;
+ 
+ 			/*
+ 			 * If predicate state not set up yet, create it (in the estate's
+ 			 * per-query context)
+ 			 */
+ 			predicate = indexInfo->ii_PredicateState;
+ 			if (predicate == NIL)
+ 			{
+ 				predicate = (List *)
+ 					ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
+ 									estate);
+ 				indexInfo->ii_PredicateState = predicate;
+ 			}
+ 
+ 			/* Skip this index-update if the predicate isn't satisfied */
+ 			if (!ExecQual(predicate, econtext, false))
+ 				continue;
+ 		}
+ 
+ 		FormIndexDatum(indexInfo,
+ 					   newslot,
+ 					   estate,
+ 					   values_new,
+ 					   isnull_new);
+ 
+ 		
+ 		
+ 		if(ind_has_snapshot)
+ 		{
+ 
+ 			FormIndexDatum(indexInfo,
+ 					   oldslot,
+ 					   estate,
+ 					   values_old,
+ 					   isnull_old);
+ 
+ 		
+ 		        is_index_updated = FindIndexUpdation(relationDescs[i]->rd_index->indnatts, 
+ 								values_old, isnull_old,	values_new, isnull_new);
+ 			
+ 			iscan = index_form_iscan(heapRelation, relationDescs[i], values_old, isnull_old, CMD_UPDATE);
+ 			iskey = index_skey(relationDescs[i], values_old, isnull_old, SK_INSERTION);
+ 			iscan->sindex_params->insertion_skey = iskey;
+ 			iscan->sindex_params->htup = oldslot->tts_tuple;
+ 			iscan->sindex_params->cache_stack = !(is_index_updated);
+ 
+ 			/*
+ 			 * The index AM does the rest.	
+ 			 */
+ 			index_getnext(iscan, ForwardScanDirection);
+ 
+ 			index_free_iscan(iscan);
+ 			if(!is_index_updated)
+ 				index_insert(relationDescs[i],	/* index relation */
+ 					 values_new,	/* array of index Datums */
+ 					 isnull_new,	/* null flags */
+ 					 tupleid,	/* tid of heap tuple */
+ 					 heapRelation,
+ 					 relationDescs[i]->rd_index->indisunique && !is_vacuum,
+ 					 iscan->sindex_params->stack);
+ 		}
+ 		if(!ind_has_snapshot || is_index_updated)
+ 		{
+ 			/*
+ 			 * The index AM does the rest.	Note we suppress unique-index checks
+ 		 	 * if we are being called from VACUUM, since VACUUM may need to move
+ 		 	 * dead tuples that have the same keys as live ones.
+ 		 	 */
+ 			index_insert(relationDescs[i],	/* index relation */
+ 					 values_new,	/* array of index Datums */
+ 					 isnull_new,	/* null flags */
+ 					 tupleid,	/* tid of heap tuple */
+ 					 heapRelation,
+ 					 relationDescs[i]->rd_index->indisunique && !is_vacuum,
+ 					 NULL);
+ 		}
+ 		/*
+ 	 	 * keep track of index inserts for debugging
+ 	 	 */
+ 		IncrIndexInserted();
+ 
+ 	}
+ }
+ 
+ static bool FindIndexUpdation(int natts, Datum *values1, bool *isnull1, Datum *values2, bool *isnull2)
+ {
+ 	int i;
+ 	for(i=0; i<natts; i++)
+ 	{
+ 		if (isnull1[i] && isnull2[i])
+ 			continue;
+ 		if(values1[i] != values2[i])
+ 			return true;
+ 	}
+ 	return false;
+ }
+ 
+ 
+ static IndexScanDesc index_form_iscan(Relation heapRelation, 
+ 				Relation indexRelation, 
+ 				Datum *values,
+ 				bool  *isnull,
+ 				CmdType operation)
+ {
+     IndexScanDesc iscan;
+     ScanKey skey;
+     BTScanOpaque so;
+     
+     iscan = palloc0(sizeof(IndexScanDescData));
+     iscan->heapRelation = heapRelation;
+     iscan->indexRelation = indexRelation;
+     iscan->xs_snapshot = ActiveSnapshot;
+     iscan->numberOfKeys = indexRelation->rd_index->indnatts ;
+     iscan->is_multiscan = FALSE;
+     iscan->kill_prior_tuple = FALSE;
+     iscan->ignore_killed_tuples = TRUE;
+ 
+     iscan->opaque = palloc0(sizeof(BTScanOpaqueData));
+     so = (BTScanOpaque) iscan->opaque;
+     so->numberOfKeys = iscan->numberOfKeys;
+     skey = index_skey(indexRelation , values, isnull, SK_SEARCH);
+     so->keyData = skey;
+     iscan->keyData = skey;
+ 
+     iscan->sindex_params = palloc0(sizeof(SnapshotIndexParamsData));
+     iscan->sindex_params->operation = operation;
+ 
+     return iscan;
+ }
+ 
+ static void index_free_iscan(IndexScanDesc iscan)
+ {
+ 	BTScanOpaque so = (BTScanOpaque) iscan->opaque;
+ 	pfree(iscan->sindex_params);
+ 	if (BufferIsValid(so->currPos.buf))
+ 		ReleaseBuffer(so->currPos.buf);
+ 	pfree(iscan->keyData);
+ 	pfree(iscan);
+ }
+ 	
+ 
+ static ScanKey index_skey(Relation rel, Datum *values, bool *isnull, char skey_type )
+ {
+ 	ScanKey skey;
+ 	int i;
+         int natts = rel->rd_index->indnatts;
+ 	int flags=0;
+ 	
+ 	        
+ 	skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
+ 	if(skey_type == SK_INSERTION)
+ 	{
+ 		int16* indoption = rel->rd_indoption;        	
+ 		for (i = 0; i < natts; i++)
+         	{
+                 	FmgrInfo   *procinfo;
+ 			
+ 
+                 	/*
+                  	* We can use the cached (default) support procs since no cross-type
+                  	* comparison can be needed.
+                  	*/
+                 	procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
+ 			flags = (isnull[i] ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
+                 	ScanKeyEntryInitializeWithInfo(&skey[i],
+                                                                            flags,
+                                                                            (AttrNumber) (i + 1),
+                                                                            InvalidStrategy,
+                                                                            InvalidOid,
+                                                                            procinfo,
+                                                                            values[i]);
+         	}
+ 
+ 	}
+ 	/* This involves a very costly operation of calculating the opfuncid.         *
+ 	 * Some Optimization should be put in this place for the sake of bulk-deletes. *
+          * One option may be to cache this in pg_index. It would even help index scan  */
+ 	else if(skey_type == SK_SEARCH)
+ 	{
+     		List *opname = NULL;
+ 	
+ 		opname = list_make1(makeString("="));
+ 
+     		for (i = 0; i < natts; i++)
+ 		{
+         		Oid typeId = rel->rd_att->attrs[i]->atttypid;
+         		Oid operOid, opfuncid;
+         		FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
+         		FuncCandidateList clist;
+ 
+ 			operOid = binary_oper_exact(opname, typeId, typeId);
+ 
+        	 		if(!OidIsValid(operOid))
+ 			{
+             			clist = OpernameGetCandidates(opname, 'b');
+             			if (clist != NULL) 
+ 				{
+                 		/*
+                   		 * Unspecified type for one of the arguments? then use the other
+                  		 * (XXX this is probably dead code?)
+                  		 */
+                 			Oid   inputOids[2];
+ 
+                 			inputOids[0] = typeId;
+                 			inputOids[1] = typeId;
+ 
+                 			//#warning TODO: might need fdresult later
+                 			fdresult = oper_select_candidate(2, inputOids, clist, &operOid);
+             			}
+         		}
+ 
+        			opfuncid = get_opcode(operOid);
+ 			if(isnull[i])
+ 				flags |= SK_ISNULL;
+ 			else
+ 				flags = 0;
+ 
+ 			ScanKeyEntryInitialize(&skey[i],
+         				flags,
+         				(AttrNumber) (i + 1),
+         				BTEqualStrategyNumber,
+ 	 				InvalidOid,
+         				opfuncid,
+         				values[i]);
+ 	
+ 		}
+     	
+     		if(opname)
+         		list_free_deep(opname);
+ 	}
+ 		
+ 	return skey;
+ 
+ }
+ 
  /*
   * UpdateChangedParamSet
   *		Add changed parameters to a plan node's chgParam set
***************
*** 1206,1208 ****
--- 1626,1629 ----
  
  	MemoryContextSwitchTo(oldcontext);
  }
+ 
*** postgresql-8.3beta1/src/backend/executor/execMain.c	Thu Sep 20 13:56:31 2007
--- postgresql-8.3patch/src/backend/executor/execMain.c	Thu Oct 18 03:19:11 2007
***************
*** 83,92 ****
  		   DestReceiver *dest, EState *estate);
  static void ExecDelete(ItemPointer tupleid,
  		   TupleTableSlot *planSlot,
! 		   DestReceiver *dest, EState *estate);
  static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,
  		   TupleTableSlot *planSlot,
! 		   DestReceiver *dest, EState *estate);
  static void ExecProcessReturning(ProjectionInfo *projectReturning,
  					 TupleTableSlot *tupleSlot,
  					 TupleTableSlot *planSlot,
--- 83,92 ----
  		   DestReceiver *dest, EState *estate);
  static void ExecDelete(ItemPointer tupleid,
  		   TupleTableSlot *planSlot,
! 		   DestReceiver *dest, EState *estate, TupleTableSlot *slot);
  static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,
  		   TupleTableSlot *planSlot,
! 		   DestReceiver *dest, EState *estate, TupleTableSlot *oldslot);
  static void ExecProcessReturning(ProjectionInfo *projectReturning,
  					 TupleTableSlot *tupleSlot,
  					 TupleTableSlot *planSlot,
***************
*** 913,920 ****
  	 * entries for the tuples we add/update.  We need not do this for a
  	 * DELETE, however, since deletion doesn't affect indexes.
  	 */
! 	if (resultRelationDesc->rd_rel->relhasindex &&
! 		operation != CMD_DELETE)
  		ExecOpenIndices(resultRelInfo);
  }
  
--- 913,919 ----
  	 * entries for the tuples we add/update.  We need not do this for a
  	 * DELETE, however, since deletion doesn't affect indexes.
  	 */
! 	if (resultRelationDesc->rd_rel->relhasindex)
  		ExecOpenIndices(resultRelInfo);
  }
  
***************
*** 1360,1371 ****
  				break;
  
  			case CMD_DELETE:
! 				ExecDelete(tupleid, planSlot, dest, estate);
  				result = NULL;
  				break;
  
  			case CMD_UPDATE:
! 				ExecUpdate(slot, tupleid, planSlot, dest, estate);
  				result = NULL;
  				break;
  
--- 1359,1370 ----
  				break;
  
  			case CMD_DELETE:
! 				ExecDelete(tupleid, planSlot, dest, estate, planstate->ps_ExprContext->ecxt_scantuple);
  				result = NULL;
  				break;
  
  			case CMD_UPDATE:
! 				ExecUpdate(slot, tupleid, planSlot, dest, estate, planstate->ps_ExprContext->ecxt_scantuple);
  				result = NULL;
  				break;
  
***************
*** 1537,1543 ****
  ExecDelete(ItemPointer tupleid,
  		   TupleTableSlot *planSlot,
  		   DestReceiver *dest,
! 		   EState *estate)
  {
  	ResultRelInfo *resultRelInfo;
  	Relation	resultRelationDesc;
--- 1536,1543 ----
  ExecDelete(ItemPointer tupleid,
  		   TupleTableSlot *planSlot,
  		   DestReceiver *dest,
! 		   EState *estate,
! 		   TupleTableSlot *slot)
  {
  	ResultRelInfo *resultRelInfo;
  	Relation	resultRelationDesc;
***************
*** 1544,1549 ****
--- 1544,1550 ----
  	HTSU_Result result;
  	ItemPointerData update_ctid;
  	TransactionId update_xmax;
+ 	ItemPointerData original_tupleid = *tupleid;
  
  	/*
  	 * get information on the (current) result relation
***************
*** 1618,1623 ****
--- 1619,1628 ----
  	IncrDeleted();
  	(estate->es_processed)++;
  
+ 	if (resultRelInfo->ri_NumIndices > 0)
+ 		ExecDeleteIndexTuples(slot, &original_tupleid, estate, false);
+ 
+ 
  	/*
  	 * Note: Normally one would think that we have to delete index tuples
  	 * associated with the heap tuple now...
***************
*** 1674,1680 ****
  		   ItemPointer tupleid,
  		   TupleTableSlot *planSlot,
  		   DestReceiver *dest,
! 		   EState *estate)
  {
  	HeapTuple	tuple;
  	ResultRelInfo *resultRelInfo;
--- 1679,1686 ----
  		   ItemPointer tupleid,
  		   TupleTableSlot *planSlot,
  		   DestReceiver *dest,
! 		   EState *estate,
! 		   TupleTableSlot *oldslot)
  {
  	HeapTuple	tuple;
  	ResultRelInfo *resultRelInfo;
***************
*** 1816,1823 ****
  	 *
  	 * If it's a HOT update, we mustn't insert new index entries.
  	 */
! 	if (resultRelInfo->ri_NumIndices > 0 && !HeapTupleIsHeapOnly(tuple))
! 		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
  
  	/* AFTER ROW UPDATE Triggers */
  	ExecARUpdateTriggers(estate, resultRelInfo, tupleid, tuple);
--- 1822,1829 ----
  	 *
  	 * If it's a HOT update, we mustn't insert new index entries.
  	 */
! 	if (resultRelInfo->ri_NumIndices > 0 )
! 		ExecUpdateIndexTuples(oldslot, slot, &(tuple->t_self), estate, false, HeapTupleIsHeapOnly(tuple));
  
  	/* AFTER ROW UPDATE Triggers */
  	ExecARUpdateTriggers(estate, resultRelInfo, tupleid, tuple);
