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 */