diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/common/reloptions.c pgsql_spacereserve/src/backend/access/common/reloptions.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/common/reloptions.c	2008-12-12 11:36:42.140563612 +0100
--- pgsql_spacereserve/src/backend/access/common/reloptions.c	2008-12-12 11:36:42.233907101 +0100
***************
*** 286,330 ****
  default_reloptions(Datum reloptions, bool validate,
  				   int minFillfactor, int defaultFillfactor)
  {
! 	static const char *const default_keywords[1] = {"fillfactor"};
! 	char	   *values[1];
! 	int			fillfactor;
  	StdRdOptions *result;
  
! 	parseRelOptions(reloptions, 1, default_keywords, values, validate);
  
  	/*
  	 * If no options, we can just return NULL rather than doing anything.
  	 * (defaultFillfactor is thus not used, but we require callers to pass it
  	 * anyway since we would need it if more options were added.)
  	 */
! 	if (values[0] == NULL)
  		return NULL;
  
! 	if (!parse_int(values[0], &fillfactor, 0, NULL))
  	{
! 		if (validate)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 					 errmsg("fillfactor must be an integer: \"%s\"",
! 							values[0])));
! 		return NULL;
  	}
  
! 	if (fillfactor < minFillfactor || fillfactor > 100)
  	{
! 		if (validate)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 					 errmsg("fillfactor=%d is out of range (should be between %d and 100)",
! 							fillfactor, minFillfactor)));
! 		return NULL;
  	}
  
  	result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
  	SET_VARSIZE(result, sizeof(StdRdOptions));
  
  	result->fillfactor = fillfactor;
  
  	return (bytea *) result;
  }
--- 286,386 ----
  default_reloptions(Datum reloptions, bool validate,
  				   int minFillfactor, int defaultFillfactor)
  {
! 	static const char *const default_keywords[3] = {"fillfactor","rs_perpage","rs_pertuple"};
! 	char	   *values[3];
! 	int			fillfactor=defaultFillfactor;
! 	int			rs_perpage=0;
! 	int			rs_pertuple=0;
  	StdRdOptions *result;
  
! 	parseRelOptions(reloptions, 3, default_keywords, values, validate);
  
  	/*
  	 * If no options, we can just return NULL rather than doing anything.
  	 * (defaultFillfactor is thus not used, but we require callers to pass it
  	 * anyway since we would need it if more options were added.)
  	 */
! 	if ((values[0] == NULL) && (values[1] == NULL) && (values[2] == NULL))
  		return NULL;
  
! 	/* fill factor */
! 	if (values[0] != NULL)
  	{
! 		if (!parse_int(values[0], &fillfactor, 0, NULL))
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("fillfactor must be an integer: \"%s\"",
! 								values[0])));
! 			return NULL;
! 		}
! 
! 		if (fillfactor < minFillfactor || fillfactor > 100)
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("fillfactor=%d is out of range (should be between %d and 100)",
! 								fillfactor, minFillfactor)));
! 			return NULL;
! 		}
  	}
  
! 	/* reserved space per page */
! 	if (values[1] != NULL)
  	{
! 		if (!parse_int(values[1], &rs_perpage, 0, NULL))
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("rs_perpage must be an integer: \"%s\"",
! 								values[1])));
! 			return NULL;
! 		}
! 
! 		if (rs_perpage < 0 || rs_perpage > BLCKSZ/4)
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("rs_perpage=%d is out of range (should be between 0 and %d)",
! 								rs_perpage, BLCKSZ/4)));
! 			return NULL;
! 		}
! 	}
! 
! 	/* reserved space per tuple */
! 	if (values[2] != NULL)
! 	{
! 		if (!parse_int(values[2], &rs_pertuple, 0, NULL))
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("rs_pertuple must be an integer: \"%s\"",
! 								values[2])));
! 			return NULL;
! 		}
! 
! 		if (rs_pertuple < 0 || rs_pertuple > BLCKSZ/16)
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("rs_pertuple=%d is out of range (should be between 0 and %d)",
! 								rs_perpage, BLCKSZ/16)));
! 			return NULL;
! 		}
  	}
  
  	result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
  	SET_VARSIZE(result, sizeof(StdRdOptions));
  
  	result->fillfactor = fillfactor;
+ 	result->rs_perpage = rs_perpage;
+ 	result->rs_pertuple = rs_pertuple;
  
  	return (bytea *) result;
  }
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gin/ginentrypage.c pgsql_spacereserve/src/backend/access/gin/ginentrypage.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gin/ginentrypage.c	2008-12-12 11:36:42.142428004 +0100
--- pgsql_spacereserve/src/backend/access/gin/ginentrypage.c	2008-12-12 11:36:42.234193186 +0100
***************
*** 314,320 ****
  		itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
  	}
  
! 	if (PageGetFreeSpace(page) + itupsz >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData))
  		return true;
  
  	return false;
--- 314,323 ----
  		itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
  	}
  
! 	if (PageGetFreeSpace(page,
! 						 RelationGetReservedSpacePerPage(btree->index),
! 						 RelationGetReservedSpacePerTuple(btree->index)) + itupsz
! 			 >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData))
  		return true;
  
  	return false;
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gist.c pgsql_spacereserve/src/backend/access/gist/gist.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gist.c	2008-12-12 11:36:42.145173957 +0100
--- pgsql_spacereserve/src/backend/access/gist/gist.c	2008-12-12 11:36:42.234512343 +0100
***************
*** 299,305 ****
  	 * XXX: If we want to change fillfactors between node and leaf, fillfactor
  	 * = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
  	 */
! 	if (gistnospace(state->stack->page, state->itup, state->ituplen,
  					is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
  					state->freespace))
  	{
--- 299,305 ----
  	 * XXX: If we want to change fillfactors between node and leaf, fillfactor
  	 * = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
  	 */
! 	if (gistnospace(state->r, state->stack->page, state->itup, state->ituplen,
  					is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
  					state->freespace))
  	{
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gistutil.c pgsql_spacereserve/src/backend/access/gist/gistutil.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gistutil.c	2008-12-12 11:36:42.146684458 +0100
--- pgsql_spacereserve/src/backend/access/gist/gistutil.c	2008-12-12 11:36:42.234672831 +0100
***************
*** 56,62 ****
   * Check space for itup vector on page
   */
  bool
! gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
  {
  	unsigned int size = freespace,
  				deleted = 0;
--- 56,62 ----
   * Check space for itup vector on page
   */
  bool
! gistnospace(Relation rel, Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
  {
  	unsigned int size = freespace,
  				deleted = 0;
***************
*** 72,78 ****
  		deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
  	}
  
! 	return (PageGetFreeSpace(page) + deleted < size);
  }
  
  bool
--- 72,79 ----
  		deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
  	}
  
! 	return (PageGetFreeSpace(page, RelationGetReservedSpacePerPage(rel), 
! 							 RelationGetReservedSpacePerTuple(rel)) + deleted < size);
  }
  
  bool
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gistvacuum.c pgsql_spacereserve/src/backend/access/gist/gistvacuum.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gistvacuum.c	2008-12-12 11:36:42.148527110 +0100
--- pgsql_spacereserve/src/backend/access/gist/gistvacuum.c	2008-12-12 11:36:42.234839579 +0100
***************
*** 385,391 ****
  		if (curlenaddon)
  		{
  			/* insert updated tuples */
! 			if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0))
  			{
  				/* there is no space on page to insert tuples */
  				res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
--- 385,391 ----
  		if (curlenaddon)
  		{
  			/* insert updated tuples */
! 			if (gistnospace(gv->index, tempPage, addon, curlenaddon, InvalidOffsetNumber, 0))
  			{
  				/* there is no space on page to insert tuples */
  				res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gistxlog.c pgsql_spacereserve/src/backend/access/gist/gistxlog.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gistxlog.c	2008-12-12 11:36:42.150448436 +0100
--- pgsql_spacereserve/src/backend/access/gist/gistxlog.c	2008-12-12 11:36:42.235025843 +0100
***************
*** 688,694 ****
  			 * hope, that wiil be enough space....
  			 */
  
! 			if (gistnospace(pages[0], itup, lenitup, *todelete, 0))
  			{
  
  				/* no space left on page, so we must split */
--- 688,694 ----
  			 * hope, that wiil be enough space....
  			 */
  
! 			if (gistnospace(index, pages[0], itup, lenitup, *todelete, 0))
  			{
  
  				/* no space left on page, so we must split */
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/hash/hashinsert.c pgsql_spacereserve/src/backend/access/hash/hashinsert.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/hash/hashinsert.c	2008-12-12 11:36:42.151473973 +0100
--- pgsql_spacereserve/src/backend/access/hash/hashinsert.c	2008-12-12 11:36:42.235298303 +0100
***************
*** 106,112 ****
  	Assert(pageopaque->hasho_bucket == bucket);
  
  	/* Do the insertion */
! 	while (PageGetFreeSpace(page) < itemsz)
  	{
  		/*
  		 * no space on this page; check for an overflow page
--- 106,113 ----
  	Assert(pageopaque->hasho_bucket == bucket);
  
  	/* Do the insertion */
! 	while (PageGetFreeSpace(page,RelationGetReservedSpacePerPage(rel),
! 			RelationGetReservedSpacePerTuple(rel)) < itemsz)
  	{
  		/*
  		 * no space on this page; check for an overflow page
***************
*** 138,144 ****
  			page = BufferGetPage(buf);
  
  			/* should fit now, given test above */
! 			Assert(PageGetFreeSpace(page) >= itemsz);
  		}
  		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
  		Assert(pageopaque->hasho_flag == LH_OVERFLOW_PAGE);
--- 139,146 ----
  			page = BufferGetPage(buf);
  
  			/* should fit now, given test above */
! 			Assert(PageGetFreeSpace(page, RelationGetReservedSpacePerPage(rel),
! 				RelationGetReservedSpacePerTuple(rel)) >= itemsz);
  		}
  		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
  		Assert(pageopaque->hasho_flag == LH_OVERFLOW_PAGE);
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/hash/hashovfl.c pgsql_spacereserve/src/backend/access/hash/hashovfl.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/hash/hashovfl.c	2008-12-12 11:36:42.154025625 +0100
--- pgsql_spacereserve/src/backend/access/hash/hashovfl.c	2008-12-12 11:36:42.235471115 +0100
***************
*** 656,662 ****
  			 * Walk up the bucket chain, looking for a page big enough for
  			 * this item.  Exit if we reach the read page.
  			 */
! 			while (PageGetFreeSpace(wpage) < itemsz)
  			{
  				Assert(!PageIsEmpty(wpage));
  
--- 656,663 ----
  			 * Walk up the bucket chain, looking for a page big enough for
  			 * this item.  Exit if we reach the read page.
  			 */
! 			while (PageGetFreeSpace(wpage, RelationGetReservedSpacePerPage(rel),
! 					RelationGetReservedSpacePerTuple(rel)) < itemsz)
  			{
  				Assert(!PageIsEmpty(wpage));
  
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/hash/hashpage.c pgsql_spacereserve/src/backend/access/hash/hashpage.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/hash/hashpage.c	2008-12-12 11:36:42.157263189 +0100
--- pgsql_spacereserve/src/backend/access/hash/hashpage.c	2008-12-12 11:36:42.235655078 +0100
***************
*** 856,862 ****
  			itemsz = IndexTupleDSize(*itup);
  			itemsz = MAXALIGN(itemsz);
  
! 			if (PageGetFreeSpace(npage) < itemsz)
  			{
  				/* write out nbuf and drop lock, but keep pin */
  				_hash_chgbufaccess(rel, nbuf, HASH_WRITE, HASH_NOLOCK);
--- 856,863 ----
  			itemsz = IndexTupleDSize(*itup);
  			itemsz = MAXALIGN(itemsz);
  
! 			if (PageGetFreeSpace(npage, RelationGetReservedSpacePerPage(rel),
! 				RelationGetReservedSpacePerTuple(rel)) < itemsz)
  			{
  				/* write out nbuf and drop lock, but keep pin */
  				_hash_chgbufaccess(rel, nbuf, HASH_WRITE, HASH_NOLOCK);
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/heapam.c pgsql_spacereserve/src/backend/access/heap/heapam.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/heapam.c	2008-12-12 11:36:42.169918324 +0100
--- pgsql_spacereserve/src/backend/access/heap/heapam.c	2008-12-12 11:36:42.236162107 +0100
***************
*** 2634,2640 ****
  					  HeapTupleHasExternal(newtup) ||
  					  newtup->t_len > TOAST_TUPLE_THRESHOLD);
  
! 	pagefree = PageGetHeapFreeSpace(page);
  
  	newtupsize = MAXALIGN(newtup->t_len);
  
--- 2634,2642 ----
  					  HeapTupleHasExternal(newtup) ||
  					  newtup->t_len > TOAST_TUPLE_THRESHOLD);
  
! 	pagefree = PageGetHeapFreeSpace(page,
! 									RelationGetReservedSpacePerPage(relation),
! 									RelationGetReservedSpacePerTuple(relation));
  
  	newtupsize = MAXALIGN(newtup->t_len);
  
***************
*** 2699,2705 ****
  			/* Re-acquire the lock on the old tuple's page. */
  			LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  			/* Re-check using the up-to-date free space */
! 			pagefree = PageGetHeapFreeSpace(page);
  			if (newtupsize > pagefree)
  			{
  				/*
--- 2701,2709 ----
  			/* Re-acquire the lock on the old tuple's page. */
  			LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  			/* Re-check using the up-to-date free space */
! 			pagefree = PageGetHeapFreeSpace(page,
! 											RelationGetReservedSpacePerPage(relation),
! 											RelationGetReservedSpacePerTuple(relation));
  			if (newtupsize > pagefree)
  			{
  				/*
***************
*** 4155,4161 ****
  							nowunused, nunused,
  							clean_move);
  
! 	freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
  
  	/*
  	 * Note: we don't worry about updating the page's prunability hints.
--- 4159,4167 ----
  							nowunused, nunused,
  							clean_move);
  
! 	/* needed to update FSM below, we ignore reservation here, because there is
! 		no relation information and FSM can be inaccurate */
! 	freespace = PageGetHeapFreeSpace(page, 0, 0); 
  
  	/*
  	 * Note: we don't worry about updating the page's prunability hints.
***************
*** 4397,4407 ****
  	HeapTupleHeaderSetCmin(htup, FirstCommandId);
  	htup->t_ctid = xlrec->target.tid;
  
  	offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true);
  	if (offnum == InvalidOffsetNumber)
  		elog(PANIC, "heap_insert_redo: failed to add tuple");
  
! 	freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
  
  	PageSetLSN(page, lsn);
  	PageSetTLI(page, ThisTimeLineID);
--- 4403,4417 ----
  	HeapTupleHeaderSetCmin(htup, FirstCommandId);
  	htup->t_ctid = xlrec->target.tid;
  
+ 	/* XXX: Should we check reserved space here? It is probably not problem,
+ 	  because item is added and WAL logged only if reserved space is OK */
  	offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true);
  	if (offnum == InvalidOffsetNumber)
  		elog(PANIC, "heap_insert_redo: failed to add tuple");
  
! 	/* needed to update FSM below, we ignore reservation here, because there is
! 		no relation information and FSM can be inaccurate */
! 	freespace = PageGetHeapFreeSpace(page, 0, 0); 
  
  	PageSetLSN(page, lsn);
  	PageSetTLI(page, ThisTimeLineID);
***************
*** 4635,4641 ****
  	if (xlrec->new_all_visible_cleared)
  		PageClearAllVisible(page);
  
! 	freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
  
  	PageSetLSN(page, lsn);
  	PageSetTLI(page, ThisTimeLineID);
--- 4645,4653 ----
  	if (xlrec->new_all_visible_cleared)
  		PageClearAllVisible(page);
  
! 	/* needed to update FSM below, we ignore reservation here, because there is
! 		no relation information and FSM can be inaccurate */
! 	freespace = PageGetHeapFreeSpace(page,0,0); 
  
  	PageSetLSN(page, lsn);
  	PageSetTLI(page, ThisTimeLineID);
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/hio.c pgsql_spacereserve/src/backend/access/heap/hio.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/hio.c	2008-12-12 11:36:42.172119886 +0100
--- pgsql_spacereserve/src/backend/access/heap/hio.c	2008-12-12 11:36:42.236322663 +0100
***************
*** 269,275 ****
  		 * we're done.
  		 */
  		page = BufferGetPage(buffer);
! 		pageFreeSpace = PageGetHeapFreeSpace(page);
  		if (len + saveFreeSpace <= pageFreeSpace)
  		{
  			/* use this page as future insert target, too */
--- 269,277 ----
  		 * we're done.
  		 */
  		page = BufferGetPage(buffer);
! 		pageFreeSpace = PageGetHeapFreeSpace(page,
! 											 RelationGetReservedSpacePerPage(relation),
! 											 RelationGetReservedSpacePerTuple(relation));
  		if (len + saveFreeSpace <= pageFreeSpace)
  		{
  			/* use this page as future insert target, too */
***************
*** 362,368 ****
  
  	PageInit(page, BufferGetPageSize(buffer), 0);
  
! 	if (len > PageGetHeapFreeSpace(page))
  	{
  		/* We should not get here given the test at the top */
  		elog(PANIC, "tuple is too big: size %lu", (unsigned long) len);
--- 364,372 ----
  
  	PageInit(page, BufferGetPageSize(buffer), 0);
  
! 	if (len > PageGetHeapFreeSpace(page,
! 								   RelationGetReservedSpacePerPage(relation),
! 								   RelationGetReservedSpacePerTuple(relation)))
  	{
  		/* We should not get here given the test at the top */
  		elog(PANIC, "tuple is too big: size %lu", (unsigned long) len);
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/pruneheap.c pgsql_spacereserve/src/backend/access/heap/pruneheap.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/pruneheap.c	2008-12-12 11:36:42.173608706 +0100
--- pgsql_spacereserve/src/backend/access/heap/pruneheap.c	2008-12-12 11:36:42.236500498 +0100
***************
*** 100,106 ****
  											 HEAP_DEFAULT_FILLFACTOR);
  	minfree = Max(minfree, BLCKSZ / 10);
  
! 	if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
  	{
  		/* OK, try to get exclusive buffer lock */
  		if (!ConditionalLockBufferForCleanup(buffer))
--- 100,109 ----
  											 HEAP_DEFAULT_FILLFACTOR);
  	minfree = Max(minfree, BLCKSZ / 10);
  
! 	if (PageIsFull(page) || 
! 		PageGetHeapFreeSpace(page,
! 							 RelationGetReservedSpacePerPage(relation),
! 							 RelationGetReservedSpacePerTuple(relation)) < minfree)
  	{
  		/* OK, try to get exclusive buffer lock */
  		if (!ConditionalLockBufferForCleanup(buffer))
***************
*** 112,118 ****
  		 * prune. (We needn't recheck PageIsPrunable, since no one else could
  		 * have pruned while we hold pin.)
  		 */
! 		if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
  		{
  			/* OK to prune (though not to remove redirects) */
  			(void) heap_page_prune(relation, buffer, OldestXmin, false, true);
--- 115,124 ----
  		 * prune. (We needn't recheck PageIsPrunable, since no one else could
  		 * have pruned while we hold pin.)
  		 */
! 		if (PageIsFull(page) || 
! 			PageGetHeapFreeSpace(page,
! 								 RelationGetReservedSpacePerPage(relation),
! 								 RelationGetReservedSpacePerTuple(relation)))
  		{
  			/* OK to prune (though not to remove redirects) */
  			(void) heap_page_prune(relation, buffer, OldestXmin, false, true);
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/rewriteheap.c pgsql_spacereserve/src/backend/access/heap/rewriteheap.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/rewriteheap.c	2008-12-12 11:36:42.174776964 +0100
--- pgsql_spacereserve/src/backend/access/heap/rewriteheap.c	2008-12-12 11:36:42.236670422 +0100
***************
*** 600,606 ****
  	/* Now we can check to see if there's enough free space already. */
  	if (state->rs_buffer_valid)
  	{
! 		pageFreeSpace = PageGetHeapFreeSpace(page);
  
  		if (len + saveFreeSpace > pageFreeSpace)
  		{
--- 600,608 ----
  	/* Now we can check to see if there's enough free space already. */
  	if (state->rs_buffer_valid)
  	{
! 		pageFreeSpace = PageGetHeapFreeSpace(page,
! 											 RelationGetReservedSpacePerPage(state->rs_new_rel),
! 											 RelationGetReservedSpacePerTuple(state->rs_new_rel));
  
  		if (len + saveFreeSpace > pageFreeSpace)
  		{
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/nbtree/nbtinsert.c pgsql_spacereserve/src/backend/access/nbtree/nbtinsert.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/nbtree/nbtinsert.c	2008-12-12 11:36:42.179054235 +0100
--- pgsql_spacereserve/src/backend/access/nbtree/nbtinsert.c	2008-12-12 11:36:42.237013648 +0100
***************
*** 79,85 ****
  			int keysz, ScanKey scankey);
  static void _bt_vacuum_one_page(Relation rel, Buffer buffer);
  
- 
  /*
   *	_bt_doinsert() -- Handle insertion of a single index tuple in the tree.
   *
--- 79,84 ----
***************
*** 445,451 ****
  	 */
  	movedright = false;
  	vacuumed = false;
! 	while (PageGetFreeSpace(page) < itemsz)
  	{
  		Buffer		rbuf;
  
--- 444,452 ----
  	 */
  	movedright = false;
  	vacuumed = false;
! 	while (PageGetFreeSpace(page,
! 						 	RelationGetReservedSpacePerPage(rel),
! 						 	RelationGetReservedSpacePerTuple(rel)) < itemsz)
  	{
  		Buffer		rbuf;
  
***************
*** 463,469 ****
  			 */
  			vacuumed = true;
  
! 			if (PageGetFreeSpace(page) >= itemsz)
  				break;			/* OK, now we have enough space */
  		}
  
--- 464,472 ----
  			 */
  			vacuumed = true;
  
! 			if (PageGetFreeSpace(page,
! 						 		 RelationGetReservedSpacePerPage(rel),
! 						 		 RelationGetReservedSpacePerTuple(rel)) >= itemsz)
  				break;			/* OK, now we have enough space */
  		}
  
***************
*** 579,585 ****
  	 * so this comparison is correct even though we appear to be accounting
  	 * only for the item and not for its line pointer.
  	 */
! 	if (PageGetFreeSpace(page) < itemsz)
  	{
  		bool		is_root = P_ISROOT(lpageop);
  		bool		is_only = P_LEFTMOST(lpageop) && P_RIGHTMOST(lpageop);
--- 582,590 ----
  	 * so this comparison is correct even though we appear to be accounting
  	 * only for the item and not for its line pointer.
  	 */
! 	if (PageGetFreeSpace(page,
! 						 RelationGetReservedSpacePerPage(rel),
! 						 RelationGetReservedSpacePerTuple(rel)) < itemsz)
  	{
  		bool		is_root = P_ISROOT(lpageop);
  		bool		is_only = P_LEFTMOST(lpageop) && P_RIGHTMOST(lpageop);
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/nbtree/nbtsort.c pgsql_spacereserve/src/backend/access/nbtree/nbtsort.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/nbtree/nbtsort.c	2008-12-12 11:36:42.182353003 +0100
--- pgsql_spacereserve/src/backend/access/nbtree/nbtsort.c	2008-12-12 11:36:42.237190941 +0100
***************
*** 462,468 ****
  	nblkno = state->btps_blkno;
  	last_off = state->btps_lastoff;
  
! 	pgspc = PageGetFreeSpace(npage);
  	itupsz = IndexTupleDSize(*itup);
  	itupsz = MAXALIGN(itupsz);
  
--- 462,470 ----
  	nblkno = state->btps_blkno;
  	last_off = state->btps_lastoff;
  
! 	pgspc = PageGetFreeSpace(npage,
! 						 	 RelationGetReservedSpacePerPage(wstate->index),
! 						 	 RelationGetReservedSpacePerTuple(wstate->index));
  	itupsz = IndexTupleDSize(*itup);
  	itupsz = MAXALIGN(itupsz);
  
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/commands/dbcommands.c pgsql_spacereserve/src/backend/commands/dbcommands.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/commands/dbcommands.c	2008-12-12 11:36:42.188926495 +0100
--- pgsql_spacereserve/src/backend/commands/dbcommands.c	2008-12-12 11:36:42.237524718 +0100
***************
*** 518,523 ****
--- 518,524 ----
  	new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
  	new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
  	new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
+ 	new_record[Anum_pg_database_datpreupgstatus - 1] = Int32GetDatum(0);
  
  	/*
  	 * We deliberately set datconfig and datacl to defaults (NULL), rather
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/commands/vacuum.c pgsql_spacereserve/src/backend/commands/vacuum.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/commands/vacuum.c	2008-12-12 11:36:42.200107235 +0100
--- pgsql_spacereserve/src/backend/commands/vacuum.c	2008-12-12 11:36:42.237837082 +0100
***************
*** 3796,3801 ****
--- 3796,3807 ----
  	Size		freespace = PageGetExactFreeSpace(page);
  	Size		targetfree;
  
+ 	/* we need to reserve space, it could reserved more space because we count
+ 	   all line pointers, not only normal */
+ 	freespace -= (RelationGetReservedSpacePerPage(relation)+
+ 				  PageGetMaxOffsetNumber(page)*RelationGetReservedSpacePerTuple(relation));
+ 
+ 	freespace = freespace < 0 ? 0 : freespace;
  	targetfree = RelationGetTargetPageFreeSpace(relation,
  												HEAP_DEFAULT_FILLFACTOR);
  	if (freespace > targetfree)
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/commands/vacuumlazy.c pgsql_spacereserve/src/backend/commands/vacuumlazy.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/commands/vacuumlazy.c	2008-12-12 11:36:42.204215141 +0100
--- pgsql_spacereserve/src/backend/commands/vacuumlazy.c	2008-12-12 11:36:42.238023285 +0100
***************
*** 370,376 ****
  				PageInit(page, BufferGetPageSize(buf), 0);
  				empty_pages++;
  			}
! 			freespace = PageGetHeapFreeSpace(page);
  			MarkBufferDirty(buf);
  			UnlockReleaseBuffer(buf);
  
--- 370,378 ----
  				PageInit(page, BufferGetPageSize(buf), 0);
  				empty_pages++;
  			}
! 			freespace = PageGetHeapFreeSpace(page,
! 						 	 				 RelationGetReservedSpacePerPage(onerel),
! 						 	 				 RelationGetReservedSpacePerTuple(onerel));
  			MarkBufferDirty(buf);
  			UnlockReleaseBuffer(buf);
  
***************
*** 381,387 ****
  		if (PageIsEmpty(page))
  		{
  			empty_pages++;
! 			freespace = PageGetHeapFreeSpace(page);
  
  			if (!PageIsAllVisible(page))
  			{
--- 383,391 ----
  		if (PageIsEmpty(page))
  		{
  			empty_pages++;
! 			freespace = PageGetHeapFreeSpace(page,
! 						 	 				 RelationGetReservedSpacePerPage(onerel),
! 						 	 				 RelationGetReservedSpacePerTuple(onerel));
  
  			if (!PageIsAllVisible(page))
  			{
***************
*** 606,612 ****
  			vacuumed_pages++;
  		}
  
! 		freespace = PageGetHeapFreeSpace(page);
  
  		/* Update the all-visible flag on the page */
  		if (!PageIsAllVisible(page) && all_visible)
--- 610,618 ----
  			vacuumed_pages++;
  		}
  
! 		freespace = PageGetHeapFreeSpace(page,
! 						 	 			 RelationGetReservedSpacePerPage(onerel),
! 						 	 			 RelationGetReservedSpacePerTuple(onerel));
  
  		/* Update the all-visible flag on the page */
  		if (!PageIsAllVisible(page) && all_visible)
***************
*** 747,753 ****
  
  		/* Now that we've compacted the page, record its available space */
  		page = BufferGetPage(buf);
! 		freespace = PageGetHeapFreeSpace(page);
  
  		UnlockReleaseBuffer(buf);
  		RecordPageWithFreeSpace(onerel, tblk, freespace);
--- 753,761 ----
  
  		/* Now that we've compacted the page, record its available space */
  		page = BufferGetPage(buf);
! 		freespace = PageGetHeapFreeSpace(page,
! 						 	 			 RelationGetReservedSpacePerPage(onerel),
! 						 	 			 RelationGetReservedSpacePerTuple(onerel));
  
  		UnlockReleaseBuffer(buf);
  		RecordPageWithFreeSpace(onerel, tblk, freespace);
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/storage/page/bufpage.c pgsql_spacereserve/src/backend/storage/page/bufpage.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/storage/page/bufpage.c	2008-12-12 11:36:42.207450074 +0100
--- pgsql_spacereserve/src/backend/storage/page/bufpage.c	2008-12-12 11:36:42.238404271 +0100
***************
*** 482,497 ****
   * PageGetHeapFreeSpace on heap pages.
   */
  Size
! PageGetFreeSpace(Page page)
  {
  	int			space;
  
  	/*
  	 * Use signed arithmetic here so that we behave sensibly if pd_lower >
  	 * pd_upper.
  	 */
  	space = (int) ((PageHeader) page)->pd_upper -
! 		(int) ((PageHeader) page)->pd_lower;
  
  	if (space < (int) sizeof(ItemIdData))
  		return 0;
--- 482,502 ----
   * PageGetHeapFreeSpace on heap pages.
   */
  Size
! PageGetFreeSpace(Page page, int rs_perpage, int rs_pertuple)
  {
  	int			space;
+ 	int			reserved_space;
+ 
+ 	/* Count reserved space. It is used for in-place upgrade. Because this functions
+ 	   is usually called before PageAddItem we need to count with new item */
+ 	reserved_space = rs_perpage+rs_pertuple*(PageGetMaxOffsetNumber(page)+1);
  
  	/*
  	 * Use signed arithmetic here so that we behave sensibly if pd_lower >
  	 * pd_upper.
  	 */
  	space = (int) ((PageHeader) page)->pd_upper -
! 		(int) ((PageHeader) page)->pd_lower - reserved_space;
  
  	if (space < (int) sizeof(ItemIdData))
  		return 0;
***************
*** 539,549 ****
   * on the number of line pointers, we make this extra check.)
   */
  Size
! PageGetHeapFreeSpace(Page page)
  {
  	Size		space;
  
! 	space = PageGetFreeSpace(page);
  	if (space > 0)
  	{
  		OffsetNumber offnum,
--- 544,554 ----
   * on the number of line pointers, we make this extra check.)
   */
  Size
! PageGetHeapFreeSpace(Page page, int rs_perpage, int rs_pertuple)
  {
  	Size		space;
  
! 	space = PageGetFreeSpace(page, rs_perpage, rs_pertuple);
  	if (space > 0)
  	{
  		OffsetNumber offnum,
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/utils/cache/relcache.c pgsql_spacereserve/src/backend/utils/cache/relcache.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/utils/cache/relcache.c	2008-12-12 11:36:42.220122442 +0100
--- pgsql_spacereserve/src/backend/utils/cache/relcache.c	2008-12-12 11:36:42.238944249 +0100
***************
*** 2409,2414 ****
--- 2409,2415 ----
  	rel->rd_rel->relhasoids = rel->rd_att->tdhasoid;
  	rel->rd_rel->relnatts = natts;
  	rel->rd_rel->reltype = InvalidOid;
+ 	rel->rd_rel->relpreupgstatus = 0;
  	/* needed when bootstrapping: */
  	rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
  
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/include/access/gist_private.h pgsql_spacereserve/src/include/access/gist_private.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/access/gist_private.h	2008-12-12 11:36:42.221738954 +0100
--- pgsql_spacereserve/src/include/access/gist_private.h	2008-12-12 11:36:42.239308369 +0100
***************
*** 279,285 ****
  
  extern Datum gistoptions(PG_FUNCTION_ARGS);
  extern bool gistfitpage(IndexTuple *itvec, int len);
! extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace);
  extern void gistcheckpage(Relation rel, Buffer buf);
  extern Buffer gistNewBuffer(Relation r);
  extern void gistfillbuffer(Page page, IndexTuple *itup, int len,
--- 279,285 ----
  
  extern Datum gistoptions(PG_FUNCTION_ARGS);
  extern bool gistfitpage(IndexTuple *itvec, int len);
! extern bool gistnospace(Relation rel, Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace);
  extern void gistcheckpage(Relation rel, Buffer buf);
  extern Buffer gistNewBuffer(Relation r);
  extern void gistfillbuffer(Page page, IndexTuple *itup, int len,
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_attribute.h pgsql_spacereserve/src/include/catalog/pg_attribute.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_attribute.h	2008-12-12 11:36:42.225592264 +0100
--- pgsql_spacereserve/src/include/catalog/pg_attribute.h	2008-12-12 11:36:42.239591992 +0100
***************
*** 419,426 ****
  { 1259, {"relhastriggers"},16, -1,	1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 1259, {"relhassubclass"},16, -1,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 1259, {"relfrozenxid"},  28, -1,	4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
! { 1259, {"relacl"},		 1034, -1, -1, 23, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
! { 1259, {"reloptions"},  1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
  
  DATA(insert ( 1259 relname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0));
  DATA(insert ( 1259 relnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0));
--- 419,427 ----
  { 1259, {"relhastriggers"},16, -1,	1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 1259, {"relhassubclass"},16, -1,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 1259, {"relfrozenxid"},  28, -1,	4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
! { 1259, {"relpreupgstatus"}, 21, -1,	2, 23, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
! { 1259, {"relacl"},		 1034, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
! { 1259, {"reloptions"},  1009, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
  
  DATA(insert ( 1259 relname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0));
  DATA(insert ( 1259 relnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0));
***************
*** 444,451 ****
  DATA(insert ( 1259 relhastriggers	16 -1 1  20 0 -1 -1 t p c t f f t 0));
  DATA(insert ( 1259 relhassubclass	16 -1 1  21 0 -1 -1 t p c t f f t 0));
  DATA(insert ( 1259 relfrozenxid		28 -1 4  22 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1259 relacl		  1034 -1 -1 23 1 -1 -1 f x i f f f t 0));
! DATA(insert ( 1259 reloptions	  1009 -1 -1 24 1 -1 -1 f x i f f f t 0));
  DATA(insert ( 1259 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0));
  DATA(insert ( 1259 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0));
  DATA(insert ( 1259 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0));
--- 445,453 ----
  DATA(insert ( 1259 relhastriggers	16 -1 1  20 0 -1 -1 t p c t f f t 0));
  DATA(insert ( 1259 relhassubclass	16 -1 1  21 0 -1 -1 t p c t f f t 0));
  DATA(insert ( 1259 relfrozenxid		28 -1 4  22 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1259 relpreupgstatus	21 -1 2  23 0 -1 -1 t p s t f f t 0));
! DATA(insert ( 1259 relacl		  1034 -1 -1 24 1 -1 -1 f x i f f f t 0));
! DATA(insert ( 1259 reloptions	  1009 -1 -1 25 1 -1 -1 f x i f f f t 0));
  DATA(insert ( 1259 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0));
  DATA(insert ( 1259 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0));
  DATA(insert ( 1259 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0));
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_class.h pgsql_spacereserve/src/include/catalog/pg_class.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_class.h	2008-12-12 11:36:42.227311049 +0100
--- pgsql_spacereserve/src/include/catalog/pg_class.h	2008-12-12 11:36:42.239737867 +0100
***************
*** 58,63 ****
--- 58,64 ----
  	bool		relhastriggers;	/* has (or has had) any TRIGGERs */
  	bool		relhassubclass; /* has (or has had) derived classes */
  	TransactionId relfrozenxid; /* all Xids < this are frozen in this rel */
+ 	int2		relpreupgstatus;  /* tatus of pre-upgrade process */
  
  	/*
  	 * VARIABLE LENGTH FIELDS start here.  These fields may be NULL, too.
***************
*** 71,77 ****
  
  /* Size of fixed part of pg_class tuples, not counting var-length fields */
  #define CLASS_TUPLE_SIZE \
! 	 (offsetof(FormData_pg_class,relfrozenxid) + sizeof(TransactionId))
  
  /* ----------------
   *		Form_pg_class corresponds to a pointer to a tuple with
--- 72,78 ----
  
  /* Size of fixed part of pg_class tuples, not counting var-length fields */
  #define CLASS_TUPLE_SIZE \
! 	 (offsetof(FormData_pg_class,relpreupgstatus) + sizeof(int2))
  
  /* ----------------
   *		Form_pg_class corresponds to a pointer to a tuple with
***************
*** 85,91 ****
   * ----------------
   */
  
! #define Natts_pg_class					24
  #define Anum_pg_class_relname			1
  #define Anum_pg_class_relnamespace		2
  #define Anum_pg_class_reltype			3
--- 86,92 ----
   * ----------------
   */
  
! #define Natts_pg_class					25
  #define Anum_pg_class_relname			1
  #define Anum_pg_class_relnamespace		2
  #define Anum_pg_class_reltype			3
***************
*** 108,115 ****
  #define Anum_pg_class_relhastriggers	20
  #define Anum_pg_class_relhassubclass	21
  #define Anum_pg_class_relfrozenxid		22
! #define Anum_pg_class_relacl			23
! #define Anum_pg_class_reloptions		24
  
  /* ----------------
   *		initial contents of pg_class
--- 109,117 ----
  #define Anum_pg_class_relhastriggers	20
  #define Anum_pg_class_relhassubclass	21
  #define Anum_pg_class_relfrozenxid		22
! #define Anum_pg_class_relisupgready		23
! #define Anum_pg_class_relacl			24
! #define Anum_pg_class_reloptions		25
  
  /* ----------------
   *		initial contents of pg_class
***************
*** 121,133 ****
   */
  
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
! DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 28 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 f f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 24 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1259 (  pg_class		PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 24 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
  
  #define		  RELKIND_INDEX			  'i'		/* secondary index */
--- 123,135 ----
   */
  
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
! DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 28 0 t f f f f 3 0 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 f f f f f 3 0 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 24 0 t f f f f 3 0 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1259 (  pg_class		PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 25 0 t f f f f 3 0 _null_ _null_ ));
  DESCR("");
  
  #define		  RELKIND_INDEX			  'i'		/* secondary index */
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_database.h pgsql_spacereserve/src/include/catalog/pg_database.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_database.h	2008-12-12 11:36:42.228306479 +0100
--- pgsql_spacereserve/src/include/catalog/pg_database.h	2008-12-12 11:36:42.239875956 +0100
***************
*** 41,46 ****
--- 41,47 ----
  	Oid			datlastsysoid;	/* highest OID to consider a system OID */
  	TransactionId datfrozenxid; /* all Xids < this are frozen in this DB */
  	Oid			dattablespace;	/* default table space for this DB */
+ 	int2		datpreupgstatus;/* status of pre-upgrade process */
  	text		datconfig[1];	/* database-specific GUC (VAR LENGTH) */
  	aclitem		datacl[1];		/* access permissions (VAR LENGTH) */
  } FormData_pg_database;
***************
*** 56,62 ****
   *		compiler constants for pg_database
   * ----------------
   */
! #define Natts_pg_database				13
  #define Anum_pg_database_datname		1
  #define Anum_pg_database_datdba			2
  #define Anum_pg_database_encoding		3
--- 57,63 ----
   *		compiler constants for pg_database
   * ----------------
   */
! #define Natts_pg_database				14
  #define Anum_pg_database_datname		1
  #define Anum_pg_database_datdba			2
  #define Anum_pg_database_encoding		3
***************
*** 68,77 ****
  #define Anum_pg_database_datlastsysoid	9
  #define Anum_pg_database_datfrozenxid	10
  #define Anum_pg_database_dattablespace	11
! #define Anum_pg_database_datconfig		12
! #define Anum_pg_database_datacl			13
  
! DATA(insert OID = 1 (  template1 PGUID ENCODING "LC_COLLATE" "LC_CTYPE" t t -1 0 0 1663 _null_ _null_));
  SHDESCR("default template database");
  #define TemplateDbOid			1
  
--- 69,79 ----
  #define Anum_pg_database_datlastsysoid	9
  #define Anum_pg_database_datfrozenxid	10
  #define Anum_pg_database_dattablespace	11
! #define Anum_pg_database_datpreupgstatus 12
! #define Anum_pg_database_datconfig		13
! #define Anum_pg_database_datacl			14
  
! DATA(insert OID = 1 (  template1 PGUID ENCODING "LC_COLLATE" "LC_CTYPE" t t -1 0 0 1663 0 _null_ _null_));
  SHDESCR("default template database");
  #define TemplateDbOid			1
  
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/include/storage/bufpage.h pgsql_spacereserve/src/include/storage/bufpage.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/storage/bufpage.h	2008-12-12 11:36:42.231179457 +0100
--- pgsql_spacereserve/src/include/storage/bufpage.h	2008-12-12 11:36:42.240214381 +0100
***************
*** 361,366 ****
--- 361,374 ----
  #define PageClearPrunable(page) \
  	(((PageHeader) (page))->pd_prune_xid = InvalidTransactionId)
  
+ /* PageGetMaxDataSpace
+  * It returns maximal possible amount of space for data on the page. If page has
+  * already item pointers we take them as a non-data space. The reason is that we
+  * cannot reclaim this space for data if it is marked as dead, beacause indexes
+  * can have a pointer on this item.
+  */
+ #define PageGetMaxDataSpace(page) \
+ 	( ((PageHeader) (page))->pd_special - MAXALIGN(((PageHeader) (page))->pd_lower) )
  
  /* ----------------------------------------------------------------
   *		extern declarations
***************
*** 376,384 ****
  extern Page PageGetTempPageCopySpecial(Page page);
  extern void PageRestoreTempPage(Page tempPage, Page oldPage);
  extern void PageRepairFragmentation(Page page);
! extern Size PageGetFreeSpace(Page page);
  extern Size PageGetExactFreeSpace(Page page);
! extern Size PageGetHeapFreeSpace(Page page);
  extern void PageIndexTupleDelete(Page page, OffsetNumber offset);
  extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems);
  
--- 384,392 ----
  extern Page PageGetTempPageCopySpecial(Page page);
  extern void PageRestoreTempPage(Page tempPage, Page oldPage);
  extern void PageRepairFragmentation(Page page);
! extern Size PageGetFreeSpace(Page page, int rs_perpage, int rs_pertuple);
  extern Size PageGetExactFreeSpace(Page page);
! extern Size PageGetHeapFreeSpace(Page page, int rs_perpage, int rs_pertuple);
  extern void PageIndexTupleDelete(Page page, OffsetNumber offset);
  extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems);
  
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/include/utils/rel.h pgsql_spacereserve/src/include/utils/rel.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/utils/rel.h	2008-12-12 11:36:42.233198428 +0100
--- pgsql_spacereserve/src/include/utils/rel.h	2008-12-12 11:36:42.240482307 +0100
***************
*** 218,223 ****
--- 218,225 ----
  {
  	int32		vl_len_;		/* varlena header (do not touch directly!) */
  	int			fillfactor;		/* page fill factor in percent (0..100) */
+ 	int			rs_perpage;  	/* page reserved space per page for in-place upgrade in bytes */
+ 	int			rs_pertuple;  	/* page reserved space per tuple for in-place upgrade in bytes */
  } StdRdOptions;
  
  #define HEAP_MIN_FILLFACTOR			10
***************
*** 232,237 ****
--- 234,255 ----
  	 ((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))
  
  /*
+  * RelationGetReservedSpacePerPage
+  *		Returns the relation's reserved space per page.
+  */
+ #define RelationGetReservedSpacePerPage(relation) \
+ 	((relation)->rd_options ? \
+ 	 ((StdRdOptions *) (relation)->rd_options)->rs_perpage : 0)
+ 
+ /*
+  * RelationGetReservedSpacePerTuple
+  *		Returns the relation's reserved space per tuple.
+  */
+ #define RelationGetReservedSpacePerTuple(relation) \
+ 	((relation)->rd_options ? \
+ 	 ((StdRdOptions *) (relation)->rd_options)->rs_pertuple : 0)
+ 
+ /*
   * RelationGetTargetPageUsage
   *		Returns the relation's desired space usage per page in bytes.
   */
