diff -cpr pgsql-orig/src/backend/access/common/indextuple.c pgsql/src/backend/access/common/indextuple.c
*** pgsql-orig/src/backend/access/common/indextuple.c	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/backend/access/common/indextuple.c	2005-12-27 18:40:29.000000000 +0900
*************** index_form_tuple(TupleDesc tupleDescript
*** 46,51 ****
--- 46,53 ----
  	uint16		tupmask = 0;
  	int			numberOfAttributes = tupleDescriptor->natts;
  
+ 	Size		maxalign;
+ 
  #ifdef TOAST_INDEX_HACK
  	Datum		untoasted_values[INDEX_MAX_KEYS];
  	bool		untoasted_free[INDEX_MAX_KEYS];
*************** index_form_tuple(TupleDesc tupleDescript
*** 123,129 ****
  	size = hoff + heap_compute_data_size(tupleDescriptor,
  										 values, isnull);
  #endif
! 	size = MAXALIGN(size);		/* be conservative */
  
  	tp = (char *) palloc0(size);
  	tuple = (IndexTuple) tp;
--- 125,140 ----
  	size = hoff + heap_compute_data_size(tupleDescriptor,
  										 values, isnull);
  #endif
! 	maxalign = 1;
! 	for (i = 0; i < numberOfAttributes; i++)
! 	{
! 		if (!isnull[i])
! 		{
! 			long align = att_align(1, tupleDescriptor->attrs[i]->attalign);
! 			maxalign = Max(maxalign, align);
! 		}
! 	}
! 	size = TYPEALIGN(maxalign, size);
  
  	tp = (char *) palloc0(size);
  	tuple = (IndexTuple) tp;
diff -cpr pgsql-orig/src/backend/access/nbtree/nbtinsert.c pgsql/src/backend/access/nbtree/nbtinsert.c
*** pgsql-orig/src/backend/access/nbtree/nbtinsert.c	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/backend/access/nbtree/nbtinsert.c	2005-12-27 18:40:29.000000000 +0900
*************** _bt_insertonpg(Relation rel,
*** 376,383 ****
  	itemsz = IndexTupleDSize(btitem->bti_itup)
  		+ (sizeof(BTItemData) - sizeof(IndexTupleData));
  
! 	itemsz = MAXALIGN(itemsz);	/* be safe, PageAddItem will do this but we
! 								 * need to be consistent */
  
  	/*
  	 * Check whether the item can fit on a btree page at all. (Eventually, we
--- 376,383 ----
  	itemsz = IndexTupleDSize(btitem->bti_itup)
  		+ (sizeof(BTItemData) - sizeof(IndexTupleData));
  
! 	/* be safe, PageAddItem will do this but we need to be consistent */
! 	itemsz = TYPEALIGN(lpageop->btpo_align, itemsz);
  
  	/*
  	 * Check whether the item can fit on a btree page at all. (Eventually, we
*************** _bt_split(Relation rel, Buffer buf, Offs
*** 680,688 ****
  	ropaque = (BTPageOpaque) PageGetSpecialPointer(rightpage);
  
  	/* if we're splitting this page, it won't be the root when we're done */
! 	lopaque->btpo_flags = oopaque->btpo_flags;
! 	lopaque->btpo_flags &= ~BTP_ROOT;
! 	ropaque->btpo_flags = lopaque->btpo_flags;
  	lopaque->btpo_prev = oopaque->btpo_prev;
  	lopaque->btpo_next = BufferGetBlockNumber(rbuf);
  	ropaque->btpo_prev = BufferGetBlockNumber(buf);
--- 680,687 ----
  	ropaque = (BTPageOpaque) PageGetSpecialPointer(rightpage);
  
  	/* if we're splitting this page, it won't be the root when we're done */
! 	lopaque->btpo_flags = ropaque->btpo_flags = (oopaque->btpo_flags & ~BTP_ROOT);
! 	lopaque->btpo_align = ropaque->btpo_align = oopaque->btpo_align;
  	lopaque->btpo_prev = oopaque->btpo_prev;
  	lopaque->btpo_next = BufferGetBlockNumber(rbuf);
  	ropaque->btpo_prev = BufferGetBlockNumber(buf);
*************** _bt_split(Relation rel, Buffer buf, Offs
*** 703,710 ****
  		itemid = PageGetItemId(origpage, P_HIKEY);
  		itemsz = ItemIdGetLength(itemid);
  		item = (BTItem) PageGetItem(origpage, itemid);
! 		if (PageAddItem(rightpage, (Item) item, itemsz, rightoff,
! 						LP_USED) == InvalidOffsetNumber)
  			elog(PANIC, "failed to add hikey to the right sibling");
  		rightoff = OffsetNumberNext(rightoff);
  	}
--- 702,709 ----
  		itemid = PageGetItemId(origpage, P_HIKEY);
  		itemsz = ItemIdGetLength(itemid);
  		item = (BTItem) PageGetItem(origpage, itemid);
! 		if (PageAddItemAligned(rightpage, (Item) item, itemsz, rightoff,
! 						LP_USED, ropaque->btpo_align) == InvalidOffsetNumber)
  			elog(PANIC, "failed to add hikey to the right sibling");
  		rightoff = OffsetNumberNext(rightoff);
  	}
*************** _bt_split(Relation rel, Buffer buf, Offs
*** 728,735 ****
  		itemsz = ItemIdGetLength(itemid);
  		item = (BTItem) PageGetItem(origpage, itemid);
  	}
! 	if (PageAddItem(leftpage, (Item) item, itemsz, leftoff,
! 					LP_USED) == InvalidOffsetNumber)
  		elog(PANIC, "failed to add hikey to the left sibling");
  	leftoff = OffsetNumberNext(leftoff);
  
--- 727,734 ----
  		itemsz = ItemIdGetLength(itemid);
  		item = (BTItem) PageGetItem(origpage, itemid);
  	}
! 	if (PageAddItemAligned(leftpage, (Item) item, itemsz, leftoff,
! 					LP_USED, lopaque->btpo_align) == InvalidOffsetNumber)
  		elog(PANIC, "failed to add hikey to the left sibling");
  	leftoff = OffsetNumberNext(leftoff);
  
*************** _bt_findsplitloc(Relation rel,
*** 996,1002 ****
  	if (!P_RIGHTMOST(opaque))
  	{
  		itemid = PageGetItemId(page, P_HIKEY);
! 		rightspace -= (int) (MAXALIGN(ItemIdGetLength(itemid)) +
  							 sizeof(ItemIdData));
  	}
  
--- 995,1001 ----
  	if (!P_RIGHTMOST(opaque))
  	{
  		itemid = PageGetItemId(page, P_HIKEY);
! 		rightspace -= (int) (TYPEALIGN(opaque->btpo_align, ItemIdGetLength(itemid)) +
  							 sizeof(ItemIdData));
  	}
  
*************** _bt_findsplitloc(Relation rel,
*** 1019,1025 ****
  					rightfree;
  
  		itemid = PageGetItemId(page, offnum);
! 		itemsz = MAXALIGN(ItemIdGetLength(itemid)) + sizeof(ItemIdData);
  
  		/*
  		 * We have to allow for the current item becoming the high key of the
--- 1018,1024 ----
  					rightfree;
  
  		itemid = PageGetItemId(page, offnum);
! 		itemsz = TYPEALIGN(opaque->btpo_align, ItemIdGetLength(itemid)) + sizeof(ItemIdData);
  
  		/*
  		 * We have to allow for the current item becoming the high key of the
*************** _bt_newroot(Relation rel, Buffer lbuf, B
*** 1410,1415 ****
--- 1409,1415 ----
  	rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
  	rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;
  	rootopaque->btpo_flags = BTP_ROOT;
+ 	rootopaque->btpo_align = RelationGetAlignment(rel);
  	rootopaque->btpo.level =
  		((BTPageOpaque) PageGetSpecialPointer(lpage))->btpo.level + 1;
  
*************** _bt_newroot(Relation rel, Buffer lbuf, B
*** 1434,1440 ****
  	 * the rightmost page on its level so there is no "high key" in it; the
  	 * two items will go into positions P_HIKEY and P_FIRSTKEY.
  	 */
! 	if (PageAddItem(rootpage, (Item) new_item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber)
  		elog(PANIC, "failed to add leftkey to new root page");
  	pfree(new_item);
  
--- 1434,1441 ----
  	 * the rightmost page on its level so there is no "high key" in it; the
  	 * two items will go into positions P_HIKEY and P_FIRSTKEY.
  	 */
! 	if (PageAddItemAligned(rootpage, (Item) new_item, itemsz, P_HIKEY,
! 			LP_USED, rootopaque->btpo_align) == InvalidOffsetNumber)
  		elog(PANIC, "failed to add leftkey to new root page");
  	pfree(new_item);
  
*************** _bt_newroot(Relation rel, Buffer lbuf, B
*** 1451,1457 ****
  	/*
  	 * insert the right page pointer into the new root page.
  	 */
! 	if (PageAddItem(rootpage, (Item) new_item, itemsz, P_FIRSTKEY, LP_USED) == InvalidOffsetNumber)
  		elog(PANIC, "failed to add rightkey to new root page");
  	pfree(new_item);
  
--- 1452,1459 ----
  	/*
  	 * insert the right page pointer into the new root page.
  	 */
! 	if (PageAddItemAligned(rootpage, (Item) new_item, itemsz, P_FIRSTKEY,
! 			LP_USED, rootopaque->btpo_align) == InvalidOffsetNumber)
  		elog(PANIC, "failed to add rightkey to new root page");
  	pfree(new_item);
  
*************** _bt_pgaddtup(Relation rel,
*** 1535,1542 ****
  		itemsize = sizeof(BTItemData);
  	}
  
! 	if (PageAddItem(page, (Item) btitem, itemsize, itup_off,
! 					LP_USED) == InvalidOffsetNumber)
  		elog(PANIC, "failed to add item to the %s for \"%s\"",
  			 where, RelationGetRelationName(rel));
  }
--- 1537,1544 ----
  		itemsize = sizeof(BTItemData);
  	}
  
! 	if (PageAddItemAligned(page, (Item) btitem, itemsize, itup_off,
! 					LP_USED, opaque->btpo_align) == InvalidOffsetNumber)
  		elog(PANIC, "failed to add item to the %s for \"%s\"",
  			 where, RelationGetRelationName(rel));
  }
diff -cpr pgsql-orig/src/backend/access/nbtree/nbtpage.c pgsql/src/backend/access/nbtree/nbtpage.c
*** pgsql-orig/src/backend/access/nbtree/nbtpage.c	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/backend/access/nbtree/nbtpage.c	2005-12-27 18:40:29.000000000 +0900
*************** _bt_initmetapage(Page page, BlockNumber 
*** 113,118 ****
--- 113,119 ----
  
  	metaopaque = (BTPageOpaque) PageGetSpecialPointer(page);
  	metaopaque->btpo_flags = BTP_META;
+ 	metaopaque->btpo_align = MAXIMUM_ALIGNOF;
  
  	/*
  	 * Set pd_lower just past the end of the metadata.	This is not essential
*************** _bt_getroot(Relation rel, int access)
*** 225,230 ****
--- 226,232 ----
  		rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
  		rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;
  		rootopaque->btpo_flags = (BTP_LEAF | BTP_ROOT);
+ 		rootopaque->btpo_align = RelationGetAlignment(rel);
  		rootopaque->btpo.level = 0;
  
  		/* NO ELOG(ERROR) till meta is updated */
*************** _bt_delitems(Relation rel, Buffer buf,
*** 685,696 ****
  			 OffsetNumber *itemnos, int nitems)
  {
  	Page		page = BufferGetPage(buf);
  
  	/* No ereport(ERROR) until changes are logged */
  	START_CRIT_SECTION();
  
  	/* Fix the page */
! 	PageIndexMultiDelete(page, itemnos, nitems);
  
  	/* XLOG stuff */
  	if (!rel->rd_istemp)
--- 687,699 ----
  			 OffsetNumber *itemnos, int nitems)
  {
  	Page		page = BufferGetPage(buf);
+ 	BTPageOpaque	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  
  	/* No ereport(ERROR) until changes are logged */
  	START_CRIT_SECTION();
  
  	/* Fix the page */
! 	PageIndexMultiDelete(page, itemnos, nitems, opaque->btpo_align);
  
  	/* XLOG stuff */
  	if (!rel->rd_istemp)
*************** _bt_pagedel(Relation rel, Buffer buf, bo
*** 1000,1006 ****
  	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  	if (parent_half_dead)
  	{
! 		PageIndexTupleDelete(page, poffset);
  		opaque->btpo_flags |= BTP_HALF_DEAD;
  	}
  	else
--- 1003,1009 ----
  	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  	if (parent_half_dead)
  	{
! 		PageIndexTupleDeleteAligned(page, poffset, opaque->btpo_align);
  		opaque->btpo_flags |= BTP_HALF_DEAD;
  	}
  	else
*************** _bt_pagedel(Relation rel, Buffer buf, bo
*** 1019,1025 ****
  		if (ItemPointerGetBlockNumber(&(btitem->bti_itup.t_tid)) != rightsib)
  			elog(PANIC, "right sibling is not next child in \"%s\"",
  				 RelationGetRelationName(rel));
! 		PageIndexTupleDelete(page, nextoffset);
  	}
  
  	/*
--- 1022,1028 ----
  		if (ItemPointerGetBlockNumber(&(btitem->bti_itup.t_tid)) != rightsib)
  			elog(PANIC, "right sibling is not next child in \"%s\"",
  				 RelationGetRelationName(rel));
! 		PageIndexTupleDeleteAligned(page, nextoffset, opaque->btpo_align);
  	}
  
  	/*
diff -cpr pgsql-orig/src/backend/access/nbtree/nbtsort.c pgsql/src/backend/access/nbtree/nbtsort.c
*** pgsql-orig/src/backend/access/nbtree/nbtsort.c	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/backend/access/nbtree/nbtsort.c	2005-12-27 18:40:29.000000000 +0900
*************** typedef struct BTWriteState
*** 126,132 ****
  	 0)
  
  
! static Page _bt_blnewpage(uint32 level);
  static BTPageState *_bt_pagestate(BTWriteState *wstate, uint32 level);
  static void _bt_slideleft(Page page);
  static void _bt_sortaddtup(Page page, Size itemsize,
--- 126,132 ----
  	 0)
  
  
! static Page _bt_blnewpage(uint32 level, Size align);
  static BTPageState *_bt_pagestate(BTWriteState *wstate, uint32 level);
  static void _bt_slideleft(Page page);
  static void _bt_sortaddtup(Page page, Size itemsize,
*************** _bt_leafbuild(BTSpool *btspool, BTSpool 
*** 243,249 ****
   * allocate workspace for a new, clean btree page, not linked to any siblings.
   */
  static Page
! _bt_blnewpage(uint32 level)
  {
  	Page		page;
  	BTPageOpaque opaque;
--- 243,249 ----
   * allocate workspace for a new, clean btree page, not linked to any siblings.
   */
  static Page
! _bt_blnewpage(uint32 level, Size align)
  {
  	Page		page;
  	BTPageOpaque opaque;
*************** _bt_blnewpage(uint32 level)
*** 258,263 ****
--- 258,264 ----
  	opaque->btpo_prev = opaque->btpo_next = P_NONE;
  	opaque->btpo.level = level;
  	opaque->btpo_flags = (level > 0) ? 0 : BTP_LEAF;
+ 	opaque->btpo_align = align;
  
  	/* Make the P_HIKEY line pointer appear allocated */
  	((PageHeader) page)->pd_lower += sizeof(ItemIdData);
*************** _bt_pagestate(BTWriteState *wstate, uint
*** 347,353 ****
  	BTPageState *state = (BTPageState *) palloc0(sizeof(BTPageState));
  
  	/* create initial page for level */
! 	state->btps_page = _bt_blnewpage(level);
  
  	/* and assign it a page position */
  	state->btps_blkno = wstate->btws_pages_alloced++;
--- 348,354 ----
  	BTPageState *state = (BTPageState *) palloc0(sizeof(BTPageState));
  
  	/* create initial page for level */
! 	state->btps_page = _bt_blnewpage(level, RelationGetAlignment(wstate->index));
  
  	/* and assign it a page position */
  	state->btps_blkno = wstate->btws_pages_alloced++;
*************** _bt_sortaddtup(Page page,
*** 425,432 ****
  		itemsize = sizeof(BTItemData);
  	}
  
! 	if (PageAddItem(page, (Item) btitem, itemsize, itup_off,
! 					LP_USED) == InvalidOffsetNumber)
  		elog(ERROR, "failed to add item to the index page");
  }
  
--- 426,433 ----
  		itemsize = sizeof(BTItemData);
  	}
  
! 	if (PageAddItemAligned(page, (Item) btitem, itemsize, itup_off,
! 					LP_USED, opaque->btpo_align) == InvalidOffsetNumber)
  		elog(ERROR, "failed to add item to the index page");
  }
  
*************** _bt_buildadd(BTWriteState *wstate, BTPag
*** 471,484 ****
  	OffsetNumber last_off;
  	Size		pgspc;
  	Size		btisz;
  
  	npage = state->btps_page;
  	nblkno = state->btps_blkno;
  	last_off = state->btps_lastoff;
  
  	pgspc = PageGetFreeSpace(npage);
  	btisz = BTITEMSZ(bti);
! 	btisz = MAXALIGN(btisz);
  
  	/*
  	 * Check whether the item can fit on a btree page at all. (Eventually, we
--- 472,487 ----
  	OffsetNumber last_off;
  	Size		pgspc;
  	Size		btisz;
+ 	BTPageOpaque opaque;
  
  	npage = state->btps_page;
  	nblkno = state->btps_blkno;
  	last_off = state->btps_lastoff;
+ 	opaque = (BTPageOpaque) PageGetSpecialPointer(npage);
  
  	pgspc = PageGetFreeSpace(npage);
  	btisz = BTITEMSZ(bti);
! 	btisz = TYPEALIGN(opaque->btpo_align, btisz);
  
  	/*
  	 * Check whether the item can fit on a btree page at all. (Eventually, we
*************** _bt_buildadd(BTWriteState *wstate, BTPag
*** 514,520 ****
  		BTItem		obti;
  
  		/* Create new page of same level */
! 		npage = _bt_blnewpage(state->btps_level);
  
  		/* and assign it a page position */
  		nblkno = wstate->btws_pages_alloced++;
--- 517,523 ----
  		BTItem		obti;
  
  		/* Create new page of same level */
! 		npage = _bt_blnewpage(state->btps_level, opaque->btpo_align);
  
  		/* and assign it a page position */
  		nblkno = wstate->btws_pages_alloced++;
diff -cpr pgsql-orig/src/backend/access/nbtree/nbtxlog.c pgsql/src/backend/access/nbtree/nbtxlog.c
*** pgsql-orig/src/backend/access/nbtree/nbtxlog.c	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/backend/access/nbtree/nbtxlog.c	2005-12-27 18:40:29.000000000 +0900
*************** _bt_restore_page(Page page, char *from, 
*** 93,107 ****
  	BTItemData	btdata;
  	Size		itemsz;
  	char	   *end = from + len;
  
  	for (; from < end;)
  	{
  		memcpy(&btdata, from, sizeof(BTItemData));
  		itemsz = IndexTupleDSize(btdata.bti_itup) +
  			(sizeof(BTItemData) - sizeof(IndexTupleData));
! 		itemsz = MAXALIGN(itemsz);
! 		if (PageAddItem(page, (Item) from, itemsz,
! 						FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
  			elog(PANIC, "_bt_restore_page: can't add item to page");
  		from += itemsz;
  	}
--- 93,108 ----
  	BTItemData	btdata;
  	Size		itemsz;
  	char	   *end = from + len;
+ 	BTPageOpaque	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  
  	for (; from < end;)
  	{
  		memcpy(&btdata, from, sizeof(BTItemData));
  		itemsz = IndexTupleDSize(btdata.bti_itup) +
  			(sizeof(BTItemData) - sizeof(IndexTupleData));
! 		itemsz = TYPEALIGN(opaque->btpo_align, itemsz);
! 		if (PageAddItemAligned(page, (Item) from, itemsz, FirstOffsetNumber,
! 				LP_USED, opaque->btpo_align) == InvalidOffsetNumber)
  			elog(PANIC, "_bt_restore_page: can't add item to page");
  		from += itemsz;
  	}
*************** btree_xlog_insert(bool isleaf, bool isme
*** 194,202 ****
  		}
  		else
  		{
! 			if (PageAddItem(page, (Item) datapos, datalen,
  							ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
! 							LP_USED) == InvalidOffsetNumber)
  				elog(PANIC, "btree_insert_redo: failed to add item");
  
  			PageSetLSN(page, lsn);
--- 195,204 ----
  		}
  		else
  		{
! 			BTPageOpaque	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
! 			if (PageAddItemAligned(page, (Item) datapos, datalen,
  							ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
! 							LP_USED, opaque->btpo_align) == InvalidOffsetNumber)
  				elog(PANIC, "btree_insert_redo: failed to add item");
  
  			PageSetLSN(page, lsn);
*************** btree_xlog_delete(XLogRecPtr lsn, XLogRe
*** 366,376 ****
  	{
  		OffsetNumber *unused;
  		OffsetNumber *unend;
  
  		unused = (OffsetNumber *) ((char *) xlrec + SizeOfBtreeDelete);
  		unend = (OffsetNumber *) ((char *) xlrec + record->xl_len);
  
! 		PageIndexMultiDelete(page, unused, unend - unused);
  	}
  
  	PageSetLSN(page, lsn);
--- 368,379 ----
  	{
  		OffsetNumber *unused;
  		OffsetNumber *unend;
+ 		BTPageOpaque  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  
  		unused = (OffsetNumber *) ((char *) xlrec + SizeOfBtreeDelete);
  		unend = (OffsetNumber *) ((char *) xlrec + record->xl_len);
  
! 		PageIndexMultiDelete(page, unused, unend - unused, opaque->btpo_align);
  	}
  
  	PageSetLSN(page, lsn);
*************** btree_xlog_delete_page(bool ismeta,
*** 425,431 ****
  			if (poffset >= PageGetMaxOffsetNumber(page))
  			{
  				Assert(poffset == P_FIRSTDATAKEY(pageop));
! 				PageIndexTupleDelete(page, poffset);
  				pageop->btpo_flags |= BTP_HALF_DEAD;
  			}
  			else
--- 428,434 ----
  			if (poffset >= PageGetMaxOffsetNumber(page))
  			{
  				Assert(poffset == P_FIRSTDATAKEY(pageop));
! 				PageIndexTupleDeleteAligned(page, poffset, pageop->btpo_align);
  				pageop->btpo_flags |= BTP_HALF_DEAD;
  			}
  			else
*************** btree_xlog_delete_page(bool ismeta,
*** 438,444 ****
  				btitem = (BTItem) PageGetItem(page, itemid);
  				ItemPointerSet(&(btitem->bti_itup.t_tid), rightsib, P_HIKEY);
  				nextoffset = OffsetNumberNext(poffset);
! 				PageIndexTupleDelete(page, nextoffset);
  			}
  
  			PageSetLSN(page, lsn);
--- 441,447 ----
  				btitem = (BTItem) PageGetItem(page, itemid);
  				ItemPointerSet(&(btitem->bti_itup.t_tid), rightsib, P_HIKEY);
  				nextoffset = OffsetNumberNext(poffset);
! 				PageIndexTupleDeleteAligned(page, nextoffset, pageop->btpo_align);
  			}
  
  			PageSetLSN(page, lsn);
diff -cpr pgsql-orig/src/backend/storage/page/bufpage.c pgsql/src/backend/storage/page/bufpage.c
*** pgsql-orig/src/backend/storage/page/bufpage.c	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/backend/storage/page/bufpage.c	2005-12-27 18:40:29.000000000 +0900
*************** PageHeaderIsValid(PageHeader page)
*** 92,98 ****
  
  
  /*
!  *	PageAddItem
   *
   *	Add an item to a page.	Return value is offset at which it was
   *	inserted, or InvalidOffsetNumber if there's not room to insert.
--- 92,98 ----
  
  
  /*
!  *	PageAddItemAligned
   *
   *	Add an item to a page.	Return value is offset at which it was
   *	inserted, or InvalidOffsetNumber if there's not room to insert.
*************** PageHeaderIsValid(PageHeader page)
*** 106,116 ****
   *	!!! EREPORT(ERROR) IS DISALLOWED HERE !!!
   */
  OffsetNumber
! PageAddItem(Page page,
  			Item item,
  			Size size,
  			OffsetNumber offsetNumber,
! 			ItemIdFlags flags)
  {
  	PageHeader	phdr = (PageHeader) page;
  	Size		alignedSize;
--- 106,117 ----
   *	!!! EREPORT(ERROR) IS DISALLOWED HERE !!!
   */
  OffsetNumber
! PageAddItemAligned(Page page,
  			Item item,
  			Size size,
  			OffsetNumber offsetNumber,
! 			ItemIdFlags flags,
! 			Size align)
  {
  	PageHeader	phdr = (PageHeader) page;
  	Size		alignedSize;
*************** PageAddItem(Page page,
*** 121,126 ****
--- 122,130 ----
  	bool		needshuffle = false;
  	bool		overwritemode = (flags & OverwritePageMode) != 0;
  
+ 	Assert(align == 1 || align == ALIGNOF_SHORT ||
+ 		align == ALIGNOF_INT || align == ALIGNOF_DOUBLE);
+ 
  	flags &= ~OverwritePageMode;
  
  	/*
*************** PageAddItem(Page page,
*** 192,198 ****
  	else
  		lower = phdr->pd_lower;
  
! 	alignedSize = MAXALIGN(size);
  
  	upper = (int) phdr->pd_upper - (int) alignedSize;
  
--- 196,202 ----
  	else
  		lower = phdr->pd_lower;
  
! 	alignedSize = TYPEALIGN(align, size);
  
  	upper = (int) phdr->pd_upper - (int) alignedSize;
  
*************** PageGetFreeSpace(Page page)
*** 441,454 ****
  
  
  /*
!  * PageIndexTupleDelete
   *
   * This routine does the work of removing a tuple from an index page.
   *
   * Unlike heap pages, we compact out the line pointer for the removed tuple.
   */
  void
! PageIndexTupleDelete(Page page, OffsetNumber offnum)
  {
  	PageHeader	phdr = (PageHeader) page;
  	char	   *addr;
--- 445,458 ----
  
  
  /*
!  * PageIndexTupleDeleteAligned
   *
   * This routine does the work of removing a tuple from an index page.
   *
   * Unlike heap pages, we compact out the line pointer for the removed tuple.
   */
  void
! PageIndexTupleDeleteAligned(Page page, OffsetNumber offnum, Size align)
  {
  	PageHeader	phdr = (PageHeader) page;
  	char	   *addr;
*************** PageIndexTupleDelete(Page page, OffsetNu
*** 483,489 ****
  	offset = ItemIdGetOffset(tup);
  
  	if (offset < phdr->pd_upper || (offset + size) > phdr->pd_special ||
! 		offset != MAXALIGN(offset) || size != MAXALIGN(size))
  		ereport(ERROR,
  				(errcode(ERRCODE_DATA_CORRUPTED),
  				 errmsg("corrupted item pointer: offset = %u, size = %u",
--- 487,493 ----
  	offset = ItemIdGetOffset(tup);
  
  	if (offset < phdr->pd_upper || (offset + size) > phdr->pd_special ||
! 		offset != TYPEALIGN(align, offset) || size != TYPEALIGN(align, size))
  		ereport(ERROR,
  				(errcode(ERRCODE_DATA_CORRUPTED),
  				 errmsg("corrupted item pointer: offset = %u, size = %u",
*************** PageIndexTupleDelete(Page page, OffsetNu
*** 548,558 ****
   *
   * This routine handles the case of deleting multiple tuples from an
   * index page at once.	It is considerably faster than a loop around
!  * PageIndexTupleDelete ... however, the caller *must* supply the array
   * of item numbers to be deleted in item number order!
   */
  void
! PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
  {
  	PageHeader	phdr = (PageHeader) page;
  	Offset		pd_lower = phdr->pd_lower;
--- 552,562 ----
   *
   * This routine handles the case of deleting multiple tuples from an
   * index page at once.	It is considerably faster than a loop around
!  * PageIndexTupleDeleteAligned ... however, the caller *must* supply the array
   * of item numbers to be deleted in item number order!
   */
  void
! PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems, Size align)
  {
  	PageHeader	phdr = (PageHeader) page;
  	Offset		pd_lower = phdr->pd_lower;
*************** PageIndexMultiDelete(Page page, OffsetNu
*** 573,579 ****
  
  	/*
  	 * If there aren't very many items to delete, then retail
! 	 * PageIndexTupleDelete is the best way.  Delete the items in reverse
  	 * order so we don't have to think about adjusting item numbers for
  	 * previous deletions.
  	 *
--- 577,583 ----
  
  	/*
  	 * If there aren't very many items to delete, then retail
! 	 * PageIndexTupleDeleteAligned is the best way.  Delete the items in reverse
  	 * order so we don't have to think about adjusting item numbers for
  	 * previous deletions.
  	 *
*************** PageIndexMultiDelete(Page page, OffsetNu
*** 582,588 ****
  	if (nitems <= 2)
  	{
  		while (--nitems >= 0)
! 			PageIndexTupleDelete(page, itemnos[nitems]);
  		return;
  	}
  
--- 586,592 ----
  	if (nitems <= 2)
  	{
  		while (--nitems >= 0)
! 			PageIndexTupleDeleteAligned(page, itemnos[nitems], align);
  		return;
  	}
  
*************** PageIndexMultiDelete(Page page, OffsetNu
*** 617,623 ****
  		offset = ItemIdGetOffset(lp);
  		if (offset < pd_upper ||
  			(offset + size) > pd_special ||
! 			offset != MAXALIGN(offset))
  			ereport(ERROR,
  					(errcode(ERRCODE_DATA_CORRUPTED),
  					 errmsg("corrupted item pointer: offset = %u, size = %u",
--- 621,627 ----
  		offset = ItemIdGetOffset(lp);
  		if (offset < pd_upper ||
  			(offset + size) > pd_special ||
! 			offset != TYPEALIGN(align, offset))
  			ereport(ERROR,
  					(errcode(ERRCODE_DATA_CORRUPTED),
  					 errmsg("corrupted item pointer: offset = %u, size = %u",
*************** PageIndexMultiDelete(Page page, OffsetNu
*** 633,639 ****
  			itemidptr->offsetindex = nused;		/* where it will go */
  			itemidptr->itemoff = offset;
  			itemidptr->olditemid = *lp;
! 			itemidptr->alignedlen = MAXALIGN(size);
  			totallen += itemidptr->alignedlen;
  			itemidptr++;
  			nused++;
--- 637,643 ----
  			itemidptr->offsetindex = nused;		/* where it will go */
  			itemidptr->itemoff = offset;
  			itemidptr->olditemid = *lp;
! 			itemidptr->alignedlen = TYPEALIGN(align, size);
  			totallen += itemidptr->alignedlen;
  			itemidptr++;
  			nused++;
diff -cpr pgsql-orig/src/backend/utils/cache/relcache.c pgsql/src/backend/utils/cache/relcache.c
*** pgsql-orig/src/backend/utils/cache/relcache.c	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/backend/utils/cache/relcache.c	2005-12-27 18:40:29.000000000 +0900
*************** static OpClassCacheEnt *LookupOpclassInf
*** 213,219 ****
  				  StrategyNumber numStrats,
  				  StrategyNumber numSupport);
  
- 
  /*
   *		ScanPgRelation
   *
--- 213,218 ----
*************** AllocateRelationDesc(Relation relation, 
*** 319,324 ****
--- 318,324 ----
  	/* and allocate attribute tuple form storage */
  	relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts,
  											   relationForm->relhasoids);
+ 	relation->rd_align = 0;
  
  	MemoryContextSwitchTo(oldcxt);
  
*************** formrdesc(const char *relationName, Oid 
*** 1232,1237 ****
--- 1232,1238 ----
  	relation->rd_att = CreateTemplateTupleDesc(natts, hasoids);
  	relation->rd_att->tdtypeid = relationReltype;
  	relation->rd_att->tdtypmod = -1;	/* unnecessary, but... */
+ 	relation->rd_align = 0;
  
  	/*
  	 * initialize tuple desc info
*************** RelationClearRelation(Relation relation,
*** 1602,1607 ****
--- 1603,1609 ----
  			/* needn't flush typcache here */
  			FreeTupleDesc(relation->rd_att);
  			relation->rd_att = old_att;
+ 			relation->rd_align = 0;
  		}
  		else
  		{
*************** RelationBuildLocalRelation(const char *r
*** 2042,2047 ****
--- 2044,2050 ----
  	 * catalogs.  We can copy attnotnull constraints here, however.
  	 */
  	rel->rd_att = CreateTupleDescCopy(tupDesc);
+ 	rel->rd_align = 0;
  	has_not_null = false;
  	for (i = 0; i < natts; i++)
  	{
*************** load_relcache_init_file(void)
*** 2952,2957 ****
--- 2955,2961 ----
  											  relform->relhasoids);
  		rel->rd_att->tdtypeid = relform->reltype;
  		rel->rd_att->tdtypmod = -1;		/* unnecessary, but... */
+ 		rel->rd_align = 0;
  
  		/* next read all the attribute tuple form data entries */
  		has_not_null = false;
*************** RelationCacheInitFileInvalidate(bool bef
*** 3399,3401 ****
--- 3403,3440 ----
  		LWLockRelease(RelCacheInitLock);
  	}
  }
+ 
+ Size
+ RelationComputeAlignment(Relation relation)
+ {
+ 	TupleDesc	tupleDesc;
+ 	int			numberOfAttributes;
+ 	int			maxalign;
+ 	int			i;
+ 
+ 	Assert(relation != NULL);
+ 	Assert(RelationGetForm(relation) != NULL);
+ 
+ 	switch (RelationGetForm(relation)->relkind)
+ 	{
+ 		case RELKIND_INDEX:
+ 			maxalign = ALIGNOF_INDEXTUPLE;
+ 			tupleDesc = RelationGetDescr(relation);
+ 			Assert(tupleDesc != NULL);
+ 			numberOfAttributes = tupleDesc->natts;
+ 			for (i = 0; i < numberOfAttributes; i++)
+ 			{
+ 				Form_pg_attribute attr = tupleDesc->attrs[i];
+ 				int align = (int) att_align(1, attr->attalign);
+ 				maxalign = Max(maxalign, align);
+ 			}
+ 			break;
+ 		case RELKIND_RELATION:
+ 		default:
+ 			maxalign = MAXIMUM_ALIGNOF;
+ 			break;
+ 	}
+ 
+ 	relation->rd_align = maxalign;
+ 	return maxalign;
+ }
diff -cpr pgsql-orig/src/include/access/itup.h pgsql/src/include/access/itup.h
*** pgsql-orig/src/include/access/itup.h	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/include/access/itup.h	2005-12-27 18:40:29.000000000 +0900
*************** typedef struct IndexTupleData
*** 52,57 ****
--- 52,59 ----
  
  typedef IndexTupleData *IndexTuple;
  
+ #define ALIGNOF_INDEXTUPLE		ALIGNOF_SHORT
+ 
  typedef struct IndexAttributeBitMapData
  {
  	bits8		bits[(INDEX_MAX_KEYS + 8 - 1) / 8];
diff -cpr pgsql-orig/src/include/access/nbtree.h pgsql/src/include/access/nbtree.h
*** pgsql-orig/src/include/access/nbtree.h	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/include/access/nbtree.h	2005-12-27 18:40:29.000000000 +0900
*************** typedef struct BTPageOpaqueData
*** 45,50 ****
--- 45,52 ----
  		TransactionId xact;		/* next transaction ID, if deleted */
  	}			btpo;
  	uint16		btpo_flags;		/* flag bits, see below */
+ 	uint16		btpo_align;		/* item alignment of this page
+ 								 * (This field can shrink to 2bit) */
  } BTPageOpaqueData;
  
  typedef BTPageOpaqueData *BTPageOpaque;
diff -cpr pgsql-orig/src/include/storage/bufpage.h pgsql/src/include/storage/bufpage.h
*** pgsql-orig/src/include/storage/bufpage.h	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/include/storage/bufpage.h	2005-12-27 18:40:29.000000000 +0900
*************** typedef PageHeaderData *PageHeader;
*** 317,329 ****
  
  extern void PageInit(Page page, Size pageSize, Size specialSize);
  extern bool PageHeaderIsValid(PageHeader page);
! extern OffsetNumber PageAddItem(Page page, Item item, Size size,
! 			OffsetNumber offsetNumber, ItemIdFlags flags);
  extern Page PageGetTempPage(Page page, Size specialSize);
  extern void PageRestoreTempPage(Page tempPage, Page oldPage);
  extern int	PageRepairFragmentation(Page page, OffsetNumber *unused);
  extern Size PageGetFreeSpace(Page page);
! extern void PageIndexTupleDelete(Page page, OffsetNumber offset);
! extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems);
  
  #endif   /* BUFPAGE_H */
--- 317,333 ----
  
  extern void PageInit(Page page, Size pageSize, Size specialSize);
  extern bool PageHeaderIsValid(PageHeader page);
! extern OffsetNumber PageAddItemAligned(Page page, Item item, Size size,
! 			OffsetNumber offsetNumber, ItemIdFlags flags, Size align);
! #define PageAddItem(page, item, size, offsetNumber, flags)	\
! 	PageAddItemAligned((page), (item), (size), (offsetNumber), (flags), MAXIMUM_ALIGNOF)
  extern Page PageGetTempPage(Page page, Size specialSize);
  extern void PageRestoreTempPage(Page tempPage, Page oldPage);
  extern int	PageRepairFragmentation(Page page, OffsetNumber *unused);
  extern Size PageGetFreeSpace(Page page);
! extern void PageIndexTupleDeleteAligned(Page page, OffsetNumber offset, Size align);
! #define PageIndexTupleDelete(page, offset) \
! 	PageIndexTupleDeleteAligned((page), (offset), MAXIMUM_ALIGNOF)
! extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems, Size align);
  
  #endif   /* BUFPAGE_H */
diff -cpr pgsql-orig/src/include/utils/rel.h pgsql/src/include/utils/rel.h
*** pgsql-orig/src/include/utils/rel.h	2005-12-27 18:40:16.000000000 +0900
--- pgsql/src/include/utils/rel.h	2005-12-27 18:40:29.000000000 +0900
*************** typedef struct RelationData
*** 176,181 ****
--- 176,183 ----
  	List	   *rd_indexprs;	/* index expression trees, if any */
  	List	   *rd_indpred;		/* index predicate tree, if any */
  
+ 	int			rd_align;	/* max alignment, typically 1, 2, 4, or 8 */
+ 
  	/* statistics collection area */
  	PgStat_Info pgstat_info;
  } RelationData;
*************** typedef Relation *RelationPtr;
*** 254,259 ****
--- 256,270 ----
  	((relation)->rd_rel->relnamespace)
  
  /*
+  * RelationGetAlignment
+  *		Returns the rel's max alignment.
+  */
+ #define RelationGetAlignment(relation) \
+ 	((relation)->rd_align != 0 \
+ 		? (relation)->rd_align \
+ 		: RelationComputeAlignment((relation)))
+ 
+ /*
   * RelationOpenSmgr
   *		Open the relation at the smgr level, if not already done.
   */
*************** typedef Relation *RelationPtr;
*** 292,296 ****
--- 303,308 ----
  /* routines in utils/cache/relcache.c */
  extern void RelationIncrementReferenceCount(Relation rel);
  extern void RelationDecrementReferenceCount(Relation rel);
+ extern Size RelationComputeAlignment(Relation relation);
  
  #endif   /* REL_H */
