[WIP] In-place upgrade - Mailing list pgsql-hackers
From | Zdenek Kotala |
---|---|
Subject | [WIP] In-place upgrade |
Date | |
Msg-id | 490B7C1B.8050408@sun.com Whole thread Raw |
Responses |
Re: [WIP] In-place upgrade
|
List | pgsql-hackers |
This is really first patch which is not clean up, but it add in-place upgrade functionality. The patch requires other clean up patches which I already send. You can find aslo GIT repository with "workable" version. Main point is that tuples are converted to latest version in SeqScan and IndexScan node. All storage/access module is able process database 8.1-8.4. (Page Layout 3 and 4). What works: - select - heap scan is ok, but index scan does not work on varlena datatypes. I need to convert index key somewhere in index access. What does not work: - tuple conversion which contains arrays, composite datatypes and toast - vacuum - it tries to cleanup old pages - probably better could be converted them to the new format during processing... - insert/delete/update The Patch contains lot of extra comments and rubbish, but it is in process of cleanup. What I need to know/solve: 1) yes/no for this kind of online upgrade method 2) I'm not sure if the calling ExecStoreTuple correct. 3) I'm still looking best place to store old data structures and conversion functions. My idea is to create new directories: src/include/odf/v03/... src/backend/storage/upgrade/ src/backend/access/upgrade (odf = On Disk Format) Links: http://git.postgresql.org/?p=~davidfetter/upgrade_in_place/.git;a=summary http://src.opensolaris.org/source/xref/sfw/usr/src/cmd/postgres/postgresql-upgrade/ Thanks for your comments Zdenek -- Zdenek Kotala Sun Microsystems Prague, Czech Republic http://sun.com/postgresql diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/backend/access/heap/htup_03.c pgsql_master_upgrade.13a47c410da7/src/backend/access/heap/htup_03.c *** pgsql_master_upgrade.751eb7c6969f/src/backend/access/heap/htup_03.c 1970-01-01 01:00:00.000000000 +0100 --- pgsql_master_upgrade.13a47c410da7/src/backend/access/heap/htup_03.c 2008-10-31 21:45:33.281134312 +0100 *************** *** 0 **** --- 1,223 ---- + #include "postgres.h" + #include "access/htup_03.h" + #include "access/heapam.h" + #include "utils/rel.h" + + #define VARATT_FLAG_EXTERNAL 0x80000000 + #define VARATT_FLAG_COMPRESSED 0x40000000 + #define VARATT_MASK_FLAGS 0xc0000000 + #define VARATT_MASK_SIZE 0x3fffffff + #define VARATT_SIZEP(_PTR) (((varattrib_03 *)(_PTR))->va_header) + #define VARATT_SIZE(PTR) (VARATT_SIZEP(PTR) & VARATT_MASK_SIZE) + + typedef struct varattrib_03 + { + int32 va_header; /* External/compressed storage */ + /* flags and item size */ + union + { + struct + { + int32 va_rawsize; /* Plain data size */ + char va_data[1]; /* Compressed data */ + } va_compressed; /* Compressed stored attribute */ + + struct + { + int32 va_rawsize; /* Plain data size */ + int32 va_extsize; /* External saved size */ + Oid va_valueid; /* Unique identifier of value */ + Oid va_toastrelid; /* RelID where to find chunks */ + } va_external; /* External stored attribute */ + + char va_data[1]; /* Plain stored attribute */ + } va_content; + } varattrib_03; + + /* + * att_align aligns the given offset as needed for a datum of alignment + * requirement attalign. The cases are tested in what is hopefully something + * like their frequency of occurrence. + */ + static + long att_align_03(long cur_offset, char attalign) + { + switch(attalign) + { + case 'i' : return INTALIGN(cur_offset); + case 'c' : return cur_offset; + case 'd' : return DOUBLEALIGN(cur_offset); + case 's' : return SHORTALIGN(cur_offset); + default: elog(ERROR, "unsupported alligment (%c).", attalign); + } + } + + /* + * att_addlength increments the given offset by the length of the attribute. + * attval is only accessed if we are dealing with a variable-length attribute. + */ + static + long att_addlength_03(long cur_offset, int attlen, Datum attval) + { + if(attlen > 0) + return cur_offset + attlen; + + if(attlen == -1) + return cur_offset + (*((uint32*) DatumGetPointer(attval)) & 0x3fffffff); + + if(attlen != -2) + elog(ERROR, "not supported attlen (%i).", attlen); + + return cur_offset + strlen(DatumGetCString(attval)) + 1; + } + + + /* deform tuple from version 03 including varlena and + * composite type handling */ + void + heap_deform_tuple_03(HeapTuple tuple, TupleDesc tupleDesc, + Datum *values, bool *isnull) + { + HeapTupleHeader_03 tup = (HeapTupleHeader_03) tuple->t_data; + bool hasnulls = (tup->t_infomask & 0x01); + Form_pg_attribute *att = tupleDesc->attrs; + int tdesc_natts = tupleDesc->natts; + int natts; /* number of atts to extract */ + int attnum; + Pointer tp_data; + long off; /* offset in tuple data */ + bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */ + + natts = tup->t_natts; + + /* + * In inheritance situations, it is possible that the given tuple actually + * has more fields than the caller is expecting. Don't run off the end of + * the caller's arrays. + */ + natts = Min(natts, tdesc_natts); + + tp_data = ((Pointer)tup) + tup->t_hoff; + + off = 0; + + for (attnum = 0; attnum < natts; attnum++) + { + Form_pg_attribute thisatt = att[attnum]; + + if (hasnulls && att_isnull(attnum, bp)) + { + values[attnum] = (Datum) 0; + isnull[attnum] = true; + continue; + } + + isnull[attnum] = false; + + off = att_align_03(off, thisatt->attalign); + + values[attnum] = fetchatt(thisatt, tp_data + off); /* fetchatt looks compatible */ + + off = att_addlength_03(off, thisatt->attlen, (Datum)(tp_data + off)); + } + + /* + * If tuple doesn't have all the atts indicated by tupleDesc, read the + * rest as null + */ + for (; attnum < tdesc_natts; attnum++) + { + values[attnum] = (Datum) 0; + isnull[attnum] = true; + } + } + + HeapTuple heap_tuple_upgrade_03(Relation rel, HeapTuple tuple) + { + TupleDesc tupleDesc = RelationGetDescr(rel); + int natts; + Datum *values; + bool *isnull; + bool *isalloc; + HeapTuple newTuple; + int n; + + /* Preallocate values/isnull arrays */ + natts = tupleDesc->natts; + values = (Datum *) palloc0(natts * sizeof(Datum)); + isnull = (bool *) palloc0(natts * sizeof(bool)); + isalloc = (bool *) palloc0(natts * sizeof(bool)); + + heap_deform_tuple_03(tuple, tupleDesc, values, isnull); + + /* now we need to go through values and convert varlen and composite types */ + for( n = 0; n < natts; n++) + { + if(isnull[n]) + continue; + + if(tupleDesc->attrs[n]->attlen == -1) + { + varattrib_03* varhdr_03; + varattrib_4b* varhdr_04; + char *data; + + // elog(NOTICE,"attname %s", tupleDesc->attrs[n]->attname); + + /* varlena conversion */ + varhdr_03 = (varattrib_03*) DatumGetPointer(values[n]); + data = palloc(VARATT_SIZE(varhdr_03)); + varhdr_04 = (varattrib_4b*) data; + + if( (varhdr_03->va_header & VARATT_MASK_FLAGS) == 0 ) + { /* TODO short varlena - but form_tuple should convert it anyway */ + + SET_VARSIZE(varhdr_04, VARATT_SIZE(varhdr_03)); + memcpy( VARDATA(varhdr_04), varhdr_03->va_content.va_data, + VARATT_SIZE(varhdr_03)- offsetof(varattrib_03, va_content.va_data) ); + } else + if( (varhdr_03->va_header & VARATT_FLAG_EXTERNAL) != 0) + { + SET_VARSIZE_EXTERNAL(varhdr_04, + VARHDRSZ_EXTERNAL + sizeof(struct varatt_external)); + memcpy( VARDATA_EXTERNAL(varhdr_04), + &(varhdr_03->va_content.va_external.va_rawsize), sizeof(struct varatt_external)); + } else + if( (varhdr_03->va_header & VARATT_FLAG_COMPRESSED ) != 0) + { + + SET_VARSIZE_COMPRESSED(varhdr_04, VARATT_SIZE(varhdr_03)); + varhdr_04->va_compressed.va_rawsize = varhdr_03->va_content.va_compressed.va_rawsize; + + memcpy( VARDATA_4B_C(varhdr_04), varhdr_03->va_content.va_compressed.va_data, + VARATT_SIZE(varhdr_03)- offsetof(varattrib_03, va_content.va_compressed.va_data) ); + } + + values[n] = PointerGetDatum(data); + isalloc[n] = true; + } + } + + newTuple = heap_form_tuple(tupleDesc, values, isnull); + + /* free allocated memory */ + for( n = 0; n < natts; n++) + { + if(isalloc[n]) + pfree(DatumGetPointer(values[n])); + } + + /* Preserve OID, if any */ + if(rel->rd_rel->relhasoids) + { + Oid oid; + oid = *((Oid *) ((char *)(tuple->t_data) + ((HeapTupleHeader_03)(tuple->t_data))->t_hoff - sizeof(Oid))); + HeapTupleSetOid(newTuple, oid); + } + return newTuple; + } + + + + + diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/backend/access/heap/htup.c pgsql_master_upgrade.13a47c410da7/src/backend/access/heap/htup.c *** pgsql_master_upgrade.751eb7c6969f/src/backend/access/heap/htup.c 2008-10-31 21:45:33.114200837 +0100 --- pgsql_master_upgrade.13a47c410da7/src/backend/access/heap/htup.c 2008-10-31 21:45:33.218887161 +0100 *************** *** 2,10 **** --- 2,15 ---- #include "fmgr.h" #include "access/htup.h" + #include "access/htup_03.h" #include "access/transam.h" #include "storage/bufpage.h" + + #define TPH03(tup) \ + ((HeapTupleHeader_03)tuple->t_data) + /* * HeapTupleHeader accessor macros * *************** *** 135,251 **** */ bool HeapTupleIsHotUpdated(HeapTuple tuple) { ! return ((tuple->t_data->t_infomask2 & HEAP_HOT_UPDATED) != 0 && ! (tuple->t_data->t_infomask & (HEAP_XMIN_INVALID | HEAP_XMAX_INVALID)) == 0); } void HeapTupleSetHotUpdated(HeapTuple tuple) { ! tuple->t_data->t_infomask2 |= HEAP_HOT_UPDATED; } void HeapTupleClearHotUpdated(HeapTuple tuple) { ! tuple->t_data->t_infomask2 &= ~HEAP_HOT_UPDATED; } bool HeapTupleIsHeapOnly(HeapTuple tuple) { ! return (tuple->t_data->t_infomask2 & HEAP_ONLY_TUPLE) != 0; } void HeapTupleSetHeapOnly(HeapTuple tuple) { ! tuple->t_data->t_infomask2 |= HEAP_ONLY_TUPLE; } void HeapTupleClearHeapOnly(HeapTuple tuple) { ! tuple->t_data->t_infomask2 &= ~HEAP_ONLY_TUPLE; } Oid HeapTupleGetOid(HeapTuple tuple) { if(!HeapTupleIs(tuple, HEAP_HASOID)) return InvalidOid; ! return *((Oid *) ((char *)tuple->t_data + HeapTupleGetHoff(tuple) - sizeof(Oid))); } void HeapTupleSetOid(HeapTuple tuple, Oid oid) { Assert(HeapTupleIs(tuple, HEAP_HASOID)); ! *((Oid *) ((char *)(tuple->t_data) + HeapTupleGetHoff(tuple) - sizeof(Oid))) = oid; ! } ! ! bool HeapTupleHasOid(HeapTuple tuple) ! { ! return HeapTupleIs(tuple, HEAP_HASOID); } TransactionId HeapTupleGetXmax(HeapTuple tuple) { ! return tuple->t_data->t_choice.t_heap.t_xmax; } void HeapTupleSetXmax(HeapTuple tuple, TransactionId xmax) { ! tuple->t_data->t_choice.t_heap.t_xmax = xmax; } TransactionId HeapTupleGetXmin(HeapTuple tuple) { ! return tuple->t_data->t_choice.t_heap.t_xmin; } void HeapTupleSetXmin(HeapTuple tuple, TransactionId xmin) { ! tuple->t_data->t_choice.t_heap.t_xmin = xmin; } TransactionId HeapTupleGetXvac(HeapTuple tuple) { ! return (HeapTupleIs(tuple, HEAP_MOVED)) ? ! tuple->t_data->t_choice.t_heap.t_field3.t_xvac : ! InvalidTransactionId; } void HeapTupleSetXvac(HeapTuple tuple, TransactionId Xvac) { ! Assert(HeapTupleIs(tuple, HEAP_MOVED)); ! tuple->t_data->t_choice.t_heap.t_field3.t_xvac = Xvac; } void HeapTupleSetCmax(HeapTuple tuple, CommandId cid, bool iscombo) { ! Assert(!(HeapTupleIs(tuple, HEAP_MOVED))); ! tuple->t_data->t_choice.t_heap.t_field3.t_cid = cid; ! if(iscombo) ! HeapTupleSet(tuple, HEAP_COMBOCID); ! else ! HeapTupleClear(tuple, HEAP_COMBOCID); } void HeapTupleSetCmin(HeapTuple tuple, CommandId cid) { ! Assert(!(HeapTupleIs(tuple, HEAP_MOVED))); ! tuple->t_data->t_choice.t_heap.t_field3.t_cid = cid; ! HeapTupleClear(tuple, HEAP_COMBOCID); } uint16 HeapTupleGetInfoMask(HeapTuple tuple) { ! return ((tuple)->t_data->t_infomask); } void HeapTupleSetInfoMask(HeapTuple tuple, uint16 infomask) { ! ((tuple)->t_data->t_infomask = (infomask)); } uint16 HeapTupleGetInfoMask2(HeapTuple tuple) { ! return ((tuple)->t_data->t_infomask2); } bool HeapTupleIs(HeapTuple tuple, uint16 mask) --- 140,361 ---- */ bool HeapTupleIsHotUpdated(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4 : return ((tuple->t_data->t_infomask2 & HEAP_HOT_UPDATED) != 0 && ! (tuple->t_data->t_infomask & (HEAP_XMIN_INVALID | HEAP_XMAX_INVALID)) == 0); ! case 3 : return false; ! } ! Assert(false); ! return false; } void HeapTupleSetHotUpdated(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4 : tuple->t_data->t_infomask2 |= HEAP_HOT_UPDATED; ! return; ! } ! elog(PANIC,"Tuple cannot be HOT updated"); } void HeapTupleClearHotUpdated(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4 : tuple->t_data->t_infomask2 &= ~HEAP_HOT_UPDATED; ! return; ! } ! elog(PANIC,"Tuple cannot be HOT updated"); } bool HeapTupleIsHeapOnly(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4 : return (tuple->t_data->t_infomask2 & HEAP_ONLY_TUPLE) != 0; ! case 3 : return false; ! } ! Assert(false); ! return false; } void HeapTupleSetHeapOnly(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4 : tuple->t_data->t_infomask2 |= HEAP_ONLY_TUPLE; ! return; ! } ! elog(PANIC, "HeapOnly flag is not supported."); } void HeapTupleClearHeapOnly(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4 : tuple->t_data->t_infomask2 &= ~HEAP_ONLY_TUPLE; ! return; ! } ! elog(PANIC, "HeapOnly flag is not supported."); } + bool HeapTupleHasOid(HeapTuple tuple) + { + return HeapTupleIs(tuple, HEAP_HASOID); + } Oid HeapTupleGetOid(HeapTuple tuple) { if(!HeapTupleIs(tuple, HEAP_HASOID)) return InvalidOid; ! switch(tuple->t_ver) ! { ! case 4 : return *((Oid *) ((char *)tuple->t_data + HeapTupleGetHoff(tuple) - sizeof(Oid))); ! case 3 : return *((Oid *) ((char *)TPH03(tuple) + HeapTupleGetHoff(tuple) - sizeof(Oid))); ! } ! elog(PANIC, "HeapTupleGetOid is not supported."); } void HeapTupleSetOid(HeapTuple tuple, Oid oid) { Assert(HeapTupleIs(tuple, HEAP_HASOID)); ! switch(tuple->t_ver) ! { ! case 4 : *((Oid *) ((char *)(tuple->t_data) + HeapTupleGetHoff(tuple) - sizeof(Oid))) = oid; ! break; ! case 3 : *((Oid *) ((char *)TPH03(tuple) + HeapTupleGetHoff(tuple) - sizeof(Oid))) = oid; ! break; ! default: elog(PANIC, "HeapTupleSetOid is not supported."); ! } } TransactionId HeapTupleGetXmax(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4 : return tuple->t_data->t_choice.t_heap.t_xmax; ! case 3 : return TPH03(tuple)->t_choice.t_heap.t_xmax; ! } ! elog(PANIC, "HeapTupleGetXmax is not supported."); ! return 0; } void HeapTupleSetXmax(HeapTuple tuple, TransactionId xmax) { ! switch(tuple->t_ver) ! { ! case 4 : tuple->t_data->t_choice.t_heap.t_xmax = xmax; ! break; ! case 3 : TPH03(tuple)->t_choice.t_heap.t_xmax = xmax; ! break; ! default: elog(PANIC, "HeapTupleSetXmax is not supported."); ! } } TransactionId HeapTupleGetXmin(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4 : return tuple->t_data->t_choice.t_heap.t_xmin; ! case 3 : return TPH03(tuple)->t_choice.t_heap.t_xmin; ! } ! elog(PANIC, "HeapTupleSetXmin is not supported."); ! return 0; } void HeapTupleSetXmin(HeapTuple tuple, TransactionId xmin) { ! switch(tuple->t_ver) ! { ! case 4 : tuple->t_data->t_choice.t_heap.t_xmin = xmin; ! break; ! case 3 : TPH03(tuple)->t_choice.t_heap.t_xmin = xmin; ! default: elog(PANIC, "HeapTupleSetXmin is not supported."); ! } } TransactionId HeapTupleGetXvac(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4 : return (HeapTupleIs(tuple, HEAP_MOVED)) ? ! tuple->t_data->t_choice.t_heap.t_field3.t_xvac : ! InvalidTransactionId; ! } ! Assert(false); ! return InvalidTransactionId; } void HeapTupleSetXvac(HeapTuple tuple, TransactionId Xvac) { ! switch(tuple->t_ver) ! { ! case 4 : Assert(HeapTupleIs(tuple, HEAP_MOVED)); ! tuple->t_data->t_choice.t_heap.t_field3.t_xvac = Xvac; ! break; ! default: Assert(false); ! } } void HeapTupleSetCmax(HeapTuple tuple, CommandId cid, bool iscombo) { ! switch(tuple->t_ver) ! { ! case 4 : Assert(!(HeapTupleIs(tuple, HEAP_MOVED))); ! tuple->t_data->t_choice.t_heap.t_field3.t_cid = cid; ! if(iscombo) ! HeapTupleSet(tuple, HEAP_COMBOCID); ! else ! HeapTupleClear(tuple, HEAP_COMBOCID); ! break; ! default: Assert(false); ! } } void HeapTupleSetCmin(HeapTuple tuple, CommandId cid) { ! switch(tuple->t_ver) ! { ! case 4 : Assert(!(HeapTupleIs(tuple, HEAP_MOVED))); ! tuple->t_data->t_choice.t_heap.t_field3.t_cid = cid; ! HeapTupleClear(tuple, HEAP_COMBOCID); ! break; ! default: Assert(false); ! } } uint16 HeapTupleGetInfoMask(HeapTuple tuple) { ! uint16 infomask; ! switch(tuple->t_ver) ! { ! case 4: return ((tuple)->t_data->t_infomask); ! case 3: infomask = TPH03(tuple)->t_infomask & 0xFFB7; /* reset 3 (HASOID), 4 (UNUSED), 5 (COMBOCID) bit */ ! infomask |= ((TPH03(tuple)->t_infomask& 0x0010) << 1 ); /* copy HASOID */ ! return infomask; ! } ! elog(PANIC, "HeapTupleGetInfoMask is not supported."); } void HeapTupleSetInfoMask(HeapTuple tuple, uint16 infomask) { ! switch(tuple->t_ver) ! { ! case 4: ((tuple)->t_data->t_infomask = (infomask)); ! break; ! default: Assert(false); ! } } uint16 HeapTupleGetInfoMask2(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4 :return ((tuple)->t_data->t_infomask2); ! default: return 0; ! } } bool HeapTupleIs(HeapTuple tuple, uint16 mask) *************** *** 265,271 **** void HeapTupleClear2(HeapTuple tuple, uint16 mask) { ! ((tuple)->t_data->t_infomask2 &= ~(mask)); } CommandId HeapTupleGetRawCommandId(HeapTuple tuple) --- 375,386 ---- void HeapTupleClear2(HeapTuple tuple, uint16 mask) { ! switch(tuple->t_ver) ! { ! case 4: ((tuple)->t_data->t_infomask2 &= ~(mask)); ! break; ! } ! /* silently ignore on older versions */ } CommandId HeapTupleGetRawCommandId(HeapTuple tuple) *************** *** 275,281 **** int HeapTupleGetNatts(HeapTuple tuple) { ! return (tuple->t_data->t_infomask2 & HEAP_NATTS_MASK); } ItemPointer HeapTupleGetCtid(HeapTuple tuple) --- 390,401 ---- int HeapTupleGetNatts(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4: return (tuple->t_data->t_infomask2 & HEAP_NATTS_MASK); ! case 3: return TPH03(tuple)->t_natts; ! } ! elog(PANIC, "HeapTupleGetNatts is not supported."); } ItemPointer HeapTupleGetCtid(HeapTuple tuple) *************** *** 290,306 **** uint8 HeapTupleGetHoff(HeapTuple tuple) { ! return (tuple->t_data->t_hoff); } Pointer HeapTupleGetBits(HeapTuple tuple) { ! return (Pointer)(tuple->t_data->t_bits); } Pointer HeapTupleGetData(HeapTuple tuple) { ! return (((Pointer)tuple->t_data) + tuple->t_data->t_hoff); } void HeapTupleInit(HeapTuple tuple, int32 len, Oid typid, int32 typmod, --- 410,438 ---- uint8 HeapTupleGetHoff(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4: return (tuple->t_data->t_hoff); ! } ! elog(PANIC, "HeapTupleGetHoff is not supported."); } Pointer HeapTupleGetBits(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4: return (Pointer)(tuple->t_data->t_bits); ! } ! elog(PANIC, "HeapTupleGetBits is not supported."); } Pointer HeapTupleGetData(HeapTuple tuple) { ! switch(tuple->t_ver) ! { ! case 4: return (((Pointer)tuple->t_data) + tuple->t_data->t_hoff); ! } ! elog(PANIC, "HeapTupleGetData is not supported."); } void HeapTupleInit(HeapTuple tuple, int32 len, Oid typid, int32 typmod, diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/backend/access/heap/Makefile pgsql_master_upgrade.13a47c410da7/src/backend/access/heap/Makefile *** pgsql_master_upgrade.751eb7c6969f/src/backend/access/heap/Makefile 2008-10-31 21:45:33.112796571 +0100 --- pgsql_master_upgrade.13a47c410da7/src/backend/access/heap/Makefile 2008-10-31 21:45:33.217276252 +0100 *************** *** 12,17 **** top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global ! OBJS = heapam.o hio.o pruneheap.o rewriteheap.o syncscan.o tuptoaster.o htup.o include $(top_srcdir)/src/backend/common.mk --- 12,17 ---- top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global ! OBJS = heapam.o hio.o pruneheap.o rewriteheap.o syncscan.o tuptoaster.o htup.o htup_03.o include $(top_srcdir)/src/backend/common.mk diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/backend/access/nbtree/nbtinsert.c pgsql_master_upgrade.13a47c410da7/src/backend/access/nbtree/nbtinsert.c *** pgsql_master_upgrade.751eb7c6969f/src/backend/access/nbtree/nbtinsert.c 2008-10-31 21:45:33.136480748 +0100 --- pgsql_master_upgrade.13a47c410da7/src/backend/access/nbtree/nbtinsert.c 2008-10-31 21:45:33.231075233 +0100 *************** *** 1203,1209 **** /* Total free space available on a btree page, after fixed overhead */ leftspace = rightspace = ! PageGetPageSize(page) - SizeOfPageHeaderData - MAXALIGN(sizeof(BTPageOpaqueData)); /* The right page will have the same high key as the old page */ --- 1203,1209 ---- /* Total free space available on a btree page, after fixed overhead */ leftspace = rightspace = ! PageGetPageSize(page) - SizeOfPageHeaderData04 - MAXALIGN(sizeof(BTPageOpaqueData)); /* The right page will have the same high key as the old page */ diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/backend/executor/nodeIndexscan.c pgsql_master_upgrade.13a47c410da7/src/backend/executor/nodeIndexscan.c *** pgsql_master_upgrade.751eb7c6969f/src/backend/executor/nodeIndexscan.c 2008-10-31 21:45:33.144606136 +0100 --- pgsql_master_upgrade.13a47c410da7/src/backend/executor/nodeIndexscan.c 2008-10-31 21:45:33.238969129 +0100 *************** *** 27,32 **** --- 27,33 ---- #include "access/genam.h" #include "access/nbtree.h" #include "access/relscan.h" + #include "access/htup_03.h" #include "executor/execdebug.h" #include "executor/nodeIndexscan.h" #include "optimizer/clauses.h" *************** *** 113,122 **** * Note: we pass 'false' because tuples returned by amgetnext are * pointers onto disk pages and must not be pfree()'d. */ ! ExecStoreTuple(tuple, /* tuple to store */ ! slot, /* slot to store in */ ! scandesc->xs_cbuf, /* buffer containing tuple */ ! false); /* don't pfree */ /* * If the index was lossy, we have to recheck the index quals using --- 114,138 ---- * Note: we pass 'false' because tuples returned by amgetnext are * pointers onto disk pages and must not be pfree()'d. */ ! if(tuple->t_ver == 4) ! { ! ExecStoreTuple(tuple, /* tuple to store */ ! slot, /* slot to store in */ ! scandesc->xs_cbuf, /* buffer containing tuple */ ! false); /* don't pfree */ ! } else ! if(tuple->t_ver == 3) ! { ! HeapTuple newtup; ! newtup = heap_tuple_upgrade_03(scandesc->heapRelation, tuple); ! ExecStoreTuple(newtup, /* tuple to store */ ! slot, /* slot to store in */ ! InvalidBuffer, /* buffer associated with this ! * tuple */ ! true); /* pfree this pointer */ ! } ! else ! elog(ERROR,"Unsupported tuple version (%i).",tuple->t_ver); /* * If the index was lossy, we have to recheck the index quals using diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/backend/executor/nodeSeqscan.c pgsql_master_upgrade.13a47c410da7/src/backend/executor/nodeSeqscan.c *** pgsql_master_upgrade.751eb7c6969f/src/backend/executor/nodeSeqscan.c 2008-10-31 21:45:33.148191833 +0100 --- pgsql_master_upgrade.13a47c410da7/src/backend/executor/nodeSeqscan.c 2008-10-31 21:45:33.242644971 +0100 *************** *** 25,30 **** --- 25,31 ---- #include "postgres.h" #include "access/heapam.h" + #include "access/htup_03.h" #include "access/relscan.h" #include "executor/execdebug.h" #include "executor/nodeSeqscan.h" *************** *** 101,111 **** * refcount will not be dropped until the tuple table slot is cleared. */ if (tuple) ! ExecStoreTuple(tuple, /* tuple to store */ ! slot, /* slot to store in */ ! scandesc->rs_cbuf, /* buffer associated with this ! * tuple */ ! false); /* don't pfree this pointer */ else ExecClearTuple(slot); --- 102,129 ---- * refcount will not be dropped until the tuple table slot is cleared. */ if (tuple) ! { ! if(tuple->t_ver == 4) ! { ! ExecStoreTuple(tuple, /* tuple to store */ ! slot, /* slot to store in */ ! scandesc->rs_cbuf, /* buffer associated with this ! * tuple */ ! false); /* don't pfree this pointer */ ! } else ! if(tuple->t_ver == 3) ! { ! HeapTuple newtup; ! newtup = heap_tuple_upgrade_03(scandesc->rs_rd, tuple); ! ExecStoreTuple(newtup, /* tuple to store */ ! slot, /* slot to store in */ ! InvalidBuffer, /* buffer associated with this ! * tuple */ ! true); /* pfree this pointer */ ! } ! else ! elog(ERROR,"Unsupported tuple version (%i).",tuple->t_ver); ! } else ExecClearTuple(slot); diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/backend/optimizer/util/plancat.c pgsql_master_upgrade.13a47c410da7/src/backend/optimizer/util/plancat.c *** pgsql_master_upgrade.751eb7c6969f/src/backend/optimizer/util/plancat.c 2008-10-31 21:45:33.157104094 +0100 --- pgsql_master_upgrade.13a47c410da7/src/backend/optimizer/util/plancat.c 2008-10-31 21:45:33.251184277 +0100 *************** *** 429,435 **** tuple_width += sizeof(HeapTupleHeaderData); tuple_width += sizeof(ItemPointerData); /* note: integer division is intentional here */ ! density = (BLCKSZ - SizeOfPageHeaderData) / tuple_width; } *tuples = rint(density * (double) curpages); break; --- 429,435 ---- tuple_width += sizeof(HeapTupleHeaderData); tuple_width += sizeof(ItemPointerData); /* note: integer division is intentional here */ ! density = (BLCKSZ - SizeOfPageHeaderData04) / tuple_width; } *tuples = rint(density * (double) curpages); break; diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/backend/storage/page/bufpage.c pgsql_master_upgrade.13a47c410da7/src/backend/storage/page/bufpage.c *** pgsql_master_upgrade.751eb7c6969f/src/backend/storage/page/bufpage.c 2008-10-31 21:45:33.168097249 +0100 --- pgsql_master_upgrade.13a47c410da7/src/backend/storage/page/bufpage.c 2008-10-31 21:45:33.262190876 +0100 *************** *** 19,24 **** --- 19,28 ---- #include "access/transam.h" #include "storage/bufpage.h" + + static bool PageLayoutIsValid_04(Page page); + static bool PageLayoutIsValid_03(Page page); + static bool PageIsZeroed(Page page); static Item PageGetItem(Page page, OffsetNumber offsetNumber); /* ---------------------------------------------------------------- *************** *** 28,50 **** /* * PageInit ! * Initializes the contents of a page. */ void PageInit(Page page, Size pageSize, Size specialSize) { ! PageHeader p = (PageHeader) page; specialSize = MAXALIGN(specialSize); Assert(pageSize == BLCKSZ); ! Assert(pageSize > specialSize + SizeOfPageHeaderData); /* Make sure all fields of page are zero, as well as unused space */ MemSet(p, 0, pageSize); /* p->pd_flags = 0; done by above MemSet */ ! p->pd_lower = SizeOfPageHeaderData; p->pd_upper = pageSize - specialSize; p->pd_special = pageSize - specialSize; PageSetPageSizeAndVersion(page, pageSize, PG_PAGE_LAYOUT_VERSION); --- 32,55 ---- /* * PageInit ! * Initializes the contents of a page. We allow to initialize page only ! * in latest Page Layout Version. */ void PageInit(Page page, Size pageSize, Size specialSize) { ! PageHeader_04 p = (PageHeader_04) page; specialSize = MAXALIGN(specialSize); Assert(pageSize == BLCKSZ); ! Assert(pageSize > specialSize + SizeOfPageHeaderData04); /* Make sure all fields of page are zero, as well as unused space */ MemSet(p, 0, pageSize); /* p->pd_flags = 0; done by above MemSet */ ! p->pd_lower = SizeOfPageHeaderData04; p->pd_upper = pageSize - specialSize; p->pd_special = pageSize - specialSize; PageSetPageSizeAndVersion(page, pageSize, PG_PAGE_LAYOUT_VERSION); *************** *** 53,59 **** /* ! * PageHeaderIsValid * Check that the header fields of a page appear valid. * * This is called when a page has just been read in from disk. The idea is --- 58,64 ---- /* ! * PageLayoutIsValid * Check that the header fields of a page appear valid. * * This is called when a page has just been read in from disk. The idea is *************** *** 73,94 **** bool PageLayoutIsValid(Page page) { char *pagebytes; int i; - PageHeader ph = (PageHeader)page; - - /* Check normal case */ - if (PageGetPageSize(page) == BLCKSZ && - PageGetPageLayoutVersion(page) == PG_PAGE_LAYOUT_VERSION && - (ph->pd_flags & ~PD_VALID_FLAG_BITS) == 0 && - ph->pd_lower >= SizeOfPageHeaderData && - ph->pd_lower <= ph->pd_upper && - ph->pd_upper <= ph->pd_special && - ph->pd_special <= BLCKSZ && - ph->pd_special == MAXALIGN(ph->pd_special)) - return true; - /* Check all-zeroes case */ pagebytes = (char *) page; for (i = 0; i < BLCKSZ; i++) { --- 78,102 ---- bool PageLayoutIsValid(Page page) { + /* Check normal case */ + switch(PageGetPageLayoutVersion(page)) + { + case 4 : return(PageLayoutIsValid_04(page)); + case 3 : return(PageLayoutIsValid_03(page)); + case 0 : return(PageIsZeroed(page)); + } + return false; + } + + /* + * Check all-zeroes case + */ + bool + PageIsZeroed(Page page) + { char *pagebytes; int i; pagebytes = (char *) page; for (i = 0; i < BLCKSZ; i++) { *************** *** 98,103 **** --- 106,141 ---- return true; } + bool PageLayoutIsValid_04(Page page) + { + PageHeader_04 phdr = (PageHeader_04)page; + if( + PageGetPageSize(page) == BLCKSZ && + (phdr->pd_flags & ~PD_VALID_FLAG_BITS) == 0 && + phdr->pd_lower >= SizeOfPageHeaderData04 && + phdr->pd_lower <= phdr->pd_upper && + phdr->pd_upper <= phdr->pd_special && + phdr->pd_special <= BLCKSZ && + phdr->pd_special == MAXALIGN(phdr->pd_special)) + return true; + return false; + } + + bool PageLayoutIsValid_03(Page page) + { + PageHeader_03 phdr = (PageHeader_03)page; + if( + PageGetPageSize(page) == BLCKSZ && + phdr->pd_lower >= SizeOfPageHeaderData03 && + phdr->pd_lower <= phdr->pd_upper && + phdr->pd_upper <= phdr->pd_special && + phdr->pd_special <= BLCKSZ && + phdr->pd_special == MAXALIGN(phdr->pd_special)) + return true; + return false; + } + + /* * PageAddItem *************** *** 127,133 **** bool overwrite, bool is_heap) { ! PageHeader phdr = (PageHeader) page; Size alignedSize; int lower; int upper; --- 165,171 ---- bool overwrite, bool is_heap) { ! PageHeader_04 phdr = (PageHeader_04) page; Size alignedSize; int lower; int upper; *************** *** 135,144 **** OffsetNumber limit; bool needshuffle = false; /* * Be wary about corrupted page pointers */ ! if (phdr->pd_lower < SizeOfPageHeaderData || phdr->pd_lower > phdr->pd_upper || phdr->pd_upper > phdr->pd_special || phdr->pd_special > BLCKSZ) --- 173,185 ---- OffsetNumber limit; bool needshuffle = false; + /* We allow add new items only on the new page layout - TODO indexes? */ + if( PageGetPageLayoutVersion(page) != PG_PAGE_LAYOUT_VERSION ) + elog(PANIC, "Add item on old page layout version is forbidden."); /* * Be wary about corrupted page pointers */ ! if (phdr->pd_lower < SizeOfPageHeaderData04 || phdr->pd_lower > phdr->pd_upper || phdr->pd_upper > phdr->pd_special || phdr->pd_special > BLCKSZ) *************** *** 265,281 **** { Size pageSize; Page temp; ! PageHeader thdr; pageSize = PageGetPageSize(page); temp = (Page) palloc(pageSize); ! thdr = (PageHeader) temp; /* copy old page in */ memcpy(temp, page, pageSize); /* set high, low water marks */ ! thdr->pd_lower = SizeOfPageHeaderData; thdr->pd_upper = pageSize - MAXALIGN(specialSize); /* clear out the middle */ --- 306,322 ---- { Size pageSize; Page temp; ! PageHeader_04 thdr; pageSize = PageGetPageSize(page); temp = (Page) palloc(pageSize); ! thdr = (PageHeader_04) temp; /* copy old page in */ memcpy(temp, page, pageSize); /* set high, low water marks */ ! thdr->pd_lower = SizeOfPageHeaderData04; thdr->pd_upper = pageSize - MAXALIGN(specialSize); /* clear out the middle */ *************** *** 333,341 **** void PageRepairFragmentation(Page page) { ! Offset pd_lower = ((PageHeader) page)->pd_lower; ! Offset pd_upper = ((PageHeader) page)->pd_upper; ! Offset pd_special = ((PageHeader) page)->pd_special; itemIdSort itemidbase, itemidptr; ItemId lp; --- 374,382 ---- void PageRepairFragmentation(Page page) { ! Offset pd_lower = PageGetLower(page); ! Offset pd_upper = PageGetUpper(page); ! Offset pd_special = PageGetSpecial(page); itemIdSort itemidbase, itemidptr; ItemId lp; *************** *** 353,359 **** * etc could cause us to clobber adjacent disk buffers, spreading the data * loss further. So, check everything. */ ! if (pd_lower < SizeOfPageHeaderData || pd_lower > pd_upper || pd_upper > pd_special || pd_special > BLCKSZ || --- 394,400 ---- * etc could cause us to clobber adjacent disk buffers, spreading the data * loss further. So, check everything. */ ! if (pd_lower < SizeOfPageHeaderData04 || pd_lower > pd_upper || pd_upper > pd_special || pd_special > BLCKSZ || *************** *** 384,390 **** if (nstorage == 0) { /* Page is completely empty, so just reset it quickly */ ! ((PageHeader) page)->pd_upper = pd_special; } else { /* nstorage != 0 */ --- 425,431 ---- if (nstorage == 0) { /* Page is completely empty, so just reset it quickly */ ! PageSetUpper(page, pd_special); } else { /* nstorage != 0 */ *************** *** 434,440 **** lp->lp_off = upper; } ! ((PageHeader) page)->pd_upper = upper; pfree(itemidbase); } --- 475,481 ---- lp->lp_off = upper; } ! PageSetUpper(page, upper); pfree(itemidbase); } *************** *** 463,470 **** * 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; --- 504,510 ---- * Use signed arithmetic here so that we behave sensibly if pd_lower > * pd_upper. */ ! space = PageGetExactFreeSpace(page); if (space < (int) sizeof(ItemIdData)) return 0; *************** *** 487,494 **** * 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 < 0) return 0; --- 527,533 ---- * Use signed arithmetic here so that we behave sensibly if pd_lower > * pd_upper. */ ! space = (int)PageGetUpper(page) - (int)PageGetLower(page); if (space < 0) return 0; *************** *** 575,581 **** void PageIndexTupleDelete(Page page, OffsetNumber offnum) { ! PageHeader phdr = (PageHeader) page; char *addr; ItemId tup; Size size; --- 614,620 ---- void PageIndexTupleDelete(Page page, OffsetNumber offnum) { ! PageHeader_04 phdr = (PageHeader_04) page; /* TODO PGU */ char *addr; ItemId tup; Size size; *************** *** 587,593 **** /* * As with PageRepairFragmentation, paranoia seems justified. */ ! if (phdr->pd_lower < SizeOfPageHeaderData || phdr->pd_lower > phdr->pd_upper || phdr->pd_upper > phdr->pd_special || phdr->pd_special > BLCKSZ) --- 626,632 ---- /* * As with PageRepairFragmentation, paranoia seems justified. */ ! if (phdr->pd_lower < SizeOfPageHeaderData04 || phdr->pd_lower > phdr->pd_upper || phdr->pd_upper > phdr->pd_special || phdr->pd_special > BLCKSZ) *************** *** 681,687 **** void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems) { ! PageHeader phdr = (PageHeader) page; Offset pd_lower = phdr->pd_lower; Offset pd_upper = phdr->pd_upper; Offset pd_special = phdr->pd_special; --- 720,726 ---- void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems) { ! PageHeader_04 phdr = (PageHeader_04) page; /* TODO PGU */ Offset pd_lower = phdr->pd_lower; Offset pd_upper = phdr->pd_upper; Offset pd_special = phdr->pd_special; *************** *** 716,722 **** /* * As with PageRepairFragmentation, paranoia seems justified. */ ! if (pd_lower < SizeOfPageHeaderData || pd_lower > pd_upper || pd_upper > pd_special || pd_special > BLCKSZ || --- 755,761 ---- /* * As with PageRepairFragmentation, paranoia seems justified. */ ! if (pd_lower < SizeOfPageHeaderData04 || pd_lower > pd_upper || pd_upper > pd_special || pd_special > BLCKSZ || *************** *** 796,815 **** lp->lp_off = upper; } ! phdr->pd_lower = SizeOfPageHeaderData + nused * sizeof(ItemIdData); phdr->pd_upper = upper; pfree(itemidbase); } /* * PageGetItemId * Returns an item identifier of a page. */ ! static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber) { AssertMacro(offsetNumber > 0); ! return (ItemId) (& ((PageHeader) page)->pd_linp[(offsetNumber) - 1]) ; } /* --- 835,861 ---- lp->lp_off = upper; } ! phdr->pd_lower = SizeOfPageHeaderData04 + nused * sizeof(ItemIdData); phdr->pd_upper = upper; pfree(itemidbase); } + + /* * PageGetItemId * Returns an item identifier of a page. */ ! ItemId PageGetItemId(Page page, OffsetNumber offsetNumber) { AssertMacro(offsetNumber > 0); ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return (ItemId) (& ((PageHeader_04) page)->pd_linp[(offsetNumber) - 1]) ; ! case 3 : return (ItemId) (& ((PageHeader_03) page)->pd_linp[(offsetNumber) - 1]) ; ! } ! elog(PANIC, "Unsupported page layout in function PageGetItemId."); } /* *************** *** 824,836 **** Item PageGetItem(Page page, OffsetNumber offsetNumber) { AssertMacro(PageIsValid(page)); ! return (Item) (page + ((PageHeader) page)->pd_linp[(offsetNumber) - 1].lp_off); } ItemLength PageItemGetSize(Page page, OffsetNumber offsetNumber) { ! return (ItemLength) ! ((PageHeader) page)->pd_linp[(offsetNumber) - 1].lp_len; } IndexTuple PageGetIndexTuple(Page page, OffsetNumber offsetNumber) --- 870,896 ---- Item PageGetItem(Page page, OffsetNumber offsetNumber) { AssertMacro(PageIsValid(page)); ! // AssertMacro(ItemIdHasStorage(itemId)); ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return (Item) (page + ! ((PageHeader_04) page)->pd_linp[(offsetNumber) - 1].lp_off); ! case 3 : return (Item) (page + ! ((PageHeader_03) page)->pd_linp[(offsetNumber) - 1].lp_off); ! } ! elog(PANIC, "Unsupported page layout in function PageGetItem."); } ItemLength PageItemGetSize(Page page, OffsetNumber offsetNumber) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return (ItemLength) ! ((PageHeader_04) page)->pd_linp[(offsetNumber) - 1].lp_len; ! case 3 : return (ItemLength) ! ((PageHeader_03) page)->pd_linp[(offsetNumber) - 1].lp_len; ! } ! elog(PANIC, "Unsupported page layout in function PageItemGetSize."); } IndexTuple PageGetIndexTuple(Page page, OffsetNumber offsetNumber) *************** *** 848,889 **** bool PageItemIsDead(Page page, OffsetNumber offsetNumber) { ! return ItemIdIsDead(PageGetItemId(page, offsetNumber)); } void PageItemMarkDead(Page page, OffsetNumber offsetNumber) { ! ItemIdMarkDead(PageGetItemId(page, offsetNumber)); } bool PageItemIsNormal(Page page, OffsetNumber offsetNumber) { ! return ItemIdIsNormal(PageGetItemId(page, offsetNumber)); } bool PageItemIsUsed(Page page, OffsetNumber offsetNumber) { ! return ItemIdIsUsed(PageGetItemId(page, offsetNumber)); } void PageItemSetUnused(Page page, OffsetNumber offsetNumber) { ! ItemIdSetUnused(PageGetItemId(page, offsetNumber)); } bool PageItemIsRedirected(Page page, OffsetNumber offsetNumber) { ! return ItemIdIsRedirected(PageGetItemId(page, offsetNumber)); } OffsetNumber PageItemGetRedirect(Page page, OffsetNumber offsetNumber) { ! return ItemIdGetRedirect(PageGetItemId(page, offsetNumber)); } void PageItemSetRedirect(Page page, OffsetNumber fromoff, OffsetNumber tooff) { ! ItemIdSetRedirect( PageGetItemId(page, fromoff), tooff); } void PageItemMove(Page page, OffsetNumber dstoff, OffsetNumber srcoff) --- 908,949 ---- bool PageItemIsDead(Page page, OffsetNumber offsetNumber) { ! return ItemIdIsDead(PageGetItemId(page, offsetNumber)); // TODO multi version } void PageItemMarkDead(Page page, OffsetNumber offsetNumber) { ! ItemIdMarkDead(PageGetItemId(page, offsetNumber)); // TODO multi version } bool PageItemIsNormal(Page page, OffsetNumber offsetNumber) { ! return ItemIdIsNormal(PageGetItemId(page, offsetNumber)); // TODO multi version } bool PageItemIsUsed(Page page, OffsetNumber offsetNumber) { ! return ItemIdIsUsed(PageGetItemId(page, offsetNumber)); // TODO multi version } void PageItemSetUnused(Page page, OffsetNumber offsetNumber) { ! ItemIdSetUnused(PageGetItemId(page, offsetNumber)); // TODO multi version } bool PageItemIsRedirected(Page page, OffsetNumber offsetNumber) { ! return ItemIdIsRedirected(PageGetItemId(page, offsetNumber)); // TODO multi version } OffsetNumber PageItemGetRedirect(Page page, OffsetNumber offsetNumber) { ! return ItemIdGetRedirect(PageGetItemId(page, offsetNumber)); // TODO multi version } void PageItemSetRedirect(Page page, OffsetNumber fromoff, OffsetNumber tooff) { ! ItemIdSetRedirect(PageGetItemId(page, fromoff), tooff); // TODO multi version } void PageItemMove(Page page, OffsetNumber dstoff, OffsetNumber srcoff) *************** *** 900,906 **** */ Pointer PageGetContents(Page page) { ! return (Pointer) (&((PageHeader) (page))->pd_linp[0]); } /* ---------------- --- 960,971 ---- */ Pointer PageGetContents(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return (Pointer) (&((PageHeader_04) (page))->pd_linp[0]); ! case 3 : return (Pointer) (&((PageHeader_03) (page))->pd_linp[0]); ! } ! elog(PANIC, "Unsupported page layout in function PageGetContents."); } /* ---------------- *************** *** 913,924 **** */ Size PageGetSpecialSize(Page page) { ! return (Size) PageGetPageSize(page) - ((PageHeader)(page))->pd_special; } Size PageGetDataSize(Page page) { ! return (Size) ((PageHeader)(page))->pd_special - ((PageHeader)(page))->pd_upper; } /* --- 978,1000 ---- */ Size PageGetSpecialSize(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return (Size) PageGetPageSize(page) - ((PageHeader_04)(page))->pd_special; ! case 3 : return (Size) PageGetPageSize(page) - ((PageHeader_03)(page))->pd_special; ! ! } ! elog(PANIC, "Unsupported page layout in function PageGetSpecialSize."); } Size PageGetDataSize(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return (Size) ((PageHeader_04)(page))->pd_special - ((PageHeader_04)(page))->pd_upper; ! case 3 : return (Size) ((PageHeader_03)(page))->pd_special - ((PageHeader_03)(page))->pd_upper; ! } ! elog(PANIC, "Unsupported page layout in function PageGetDataSize."); } /* *************** *** 928,934 **** Pointer PageGetSpecialPointer(Page page) { AssertMacro(PageIsValid(page)); ! return page + ((PageHeader)(page))->pd_special; } /* --- 1004,1015 ---- Pointer PageGetSpecialPointer(Page page) { AssertMacro(PageIsValid(page)); ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return page + ((PageHeader_04)(page))->pd_special; ! case 3 : return page + ((PageHeader_03)(page))->pd_special; ! } ! elog(PANIC, "Unsupported page layout in function PageGetSpecialPointer."); } /* *************** *** 938,970 **** Pointer PageGetUpperPointer(Page page) { AssertMacro(PageIsValid(page)); ! return page + ((PageHeader)(page))->pd_upper; } void PageSetLower(Page page, LocationIndex lower) { ! ((PageHeader) page)->pd_lower = lower; } void PageSetUpper(Page page, LocationIndex upper) { ! ((PageHeader) page)->pd_upper = upper; } void PageReserveLinp(Page page) { AssertMacro(PageIsValid(page)); ! ((PageHeader) page)->pd_lower += sizeof(ItemIdData); ! AssertMacro(((PageHeader) page)->pd_lower <= ((PageHeader) page)->pd_upper ); } void PageReleaseLinp(Page page) { AssertMacro(PageIsValid(page)); ! ((PageHeader) page)->pd_lower -= sizeof(ItemIdData); ! AssertMacro(((PageHeader) page)->pd_lower >= SizeOfPageHeaderData); } /* * PageGetMaxOffsetNumber * Returns the maximum offset number used by the given page. --- 1019,1087 ---- Pointer PageGetUpperPointer(Page page) { AssertMacro(PageIsValid(page)); ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return page + ((PageHeader_04)(page))->pd_upper; ! case 3 : return page + ((PageHeader_03)(page))->pd_upper; ! } ! elog(PANIC, "Unsupported page layout in function PageGetUpperPointer."); } void PageSetLower(Page page, LocationIndex lower) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) page)->pd_lower = lower; ! break; ! case 3 : ((PageHeader_03) page)->pd_lower = lower; ! break; ! default: elog(PANIC, "Unsupported page layout in function PageSetLower."); ! } } void PageSetUpper(Page page, LocationIndex upper) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) page)->pd_upper = upper; ! break; ! case 3 : ((PageHeader_03) page)->pd_upper = upper; ! break; ! default: elog(PANIC, "Unsupported page layout in function PageSetLower."); ! } } void PageReserveLinp(Page page) { AssertMacro(PageIsValid(page)); ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) page)->pd_lower += sizeof(ItemIdData); ! AssertMacro(((PageHeader_04) page)->pd_lower <= ((PageHeader_04) page)->pd_upper ); ! break; ! case 3 : ((PageHeader_03) page)->pd_lower += sizeof(ItemIdData); ! AssertMacro(((PageHeader_03) page)->pd_lower <= ((PageHeader_03) page)->pd_upper ); ! break; ! default: elog(PANIC, "Unsupported page layout in function PageReserveLinp."); ! } } void PageReleaseLinp(Page page) { AssertMacro(PageIsValid(page)); ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) page)->pd_lower -= sizeof(ItemIdData); ! AssertMacro(((PageHeader_04) page)->pd_lower >= SizeOfPageHeaderData04); ! break; ! case 3 : ((PageHeader_03) page)->pd_lower -= sizeof(ItemIdData); ! AssertMacro(((PageHeader_03) page)->pd_lower >= SizeOfPageHeaderData03); ! break; ! default: elog(PANIC, "Unsupported page layout in function PageReleaseLinp."); ! } } + /* * PageGetMaxOffsetNumber * Returns the maximum offset number used by the given page. *************** *** 977,985 **** */ int PageGetMaxOffsetNumber(Page page) { ! PageHeader header = (PageHeader) (page); ! return header->pd_lower <= SizeOfPageHeaderData ? 0 : ! (header->pd_lower - SizeOfPageHeaderData) / sizeof(ItemIdData); } /* --- 1094,1115 ---- */ int PageGetMaxOffsetNumber(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : { ! PageHeader_04 header = (PageHeader_04) (page); ! return header->pd_lower <= SizeOfPageHeaderData04 ? 0 : ! (header->pd_lower - SizeOfPageHeaderData04) / sizeof(ItemIdData); ! } ! case 3 : { ! PageHeader_03 header = (PageHeader_03) (page); ! return header->pd_lower <= SizeOfPageHeaderData03 ? 0 : ! (header->pd_lower - SizeOfPageHeaderData03) / sizeof(ItemIdData); ! } ! ! } ! elog(PANIC, "Unsupported page layout in function PageGetMaxOffsetNumber. (%i)", PageGetPageLayoutVersion(page) ); ! return 0; } /* *************** *** 987,1089 **** */ XLogRecPtr PageGetLSN(Page page) { ! return ((PageHeader) page)->pd_lsn; } LocationIndex PageGetLower(Page page) { ! return ((PageHeader) page)->pd_lower; } LocationIndex PageGetUpper(Page page) { ! return ((PageHeader) page)->pd_upper; } LocationIndex PageGetSpecial(Page page) { ! return ((PageHeader) page)->pd_special; } void PageSetLSN(Page page, XLogRecPtr lsn) { ! ((PageHeader) page)->pd_lsn = lsn; } /* NOTE: only the 16 least significant bits are stored */ TimeLineID PageGetTLI(Page page) { ! return ((PageHeader) (page))->pd_tli; } void PageSetTLI(Page page, TimeLineID tli) { ! ((PageHeader) (page))->pd_tli = (uint16) (tli); } bool PageHasFreeLinePointers(Page page) { ! return ((PageHeader) (page))->pd_flags & PD_HAS_FREE_LINES; } void PageSetHasFreeLinePointers(Page page) { ! ((PageHeader) (page))->pd_flags |= PD_HAS_FREE_LINES; } void PageClearHasFreeLinePointers(Page page) { ! ((PageHeader) (page))->pd_flags &= ~PD_HAS_FREE_LINES; } bool PageIsFull(Page page) { ! return ((PageHeader) (page))->pd_flags & PD_PAGE_FULL; } void PageSetFull(Page page) { ! ((PageHeader) (page))->pd_flags |= PD_PAGE_FULL; } void PageClearFull(Page page) { ! ((PageHeader) (page))->pd_flags &= ~PD_PAGE_FULL; } bool PageIsPrunable(Page page, TransactionId oldestxmin) { AssertMacro(TransactionIdIsNormal(oldestxmin)); ! return ( ! TransactionIdIsValid(((PageHeader) page)->pd_prune_xid) && ! TransactionIdPrecedes(((PageHeader) page)->pd_prune_xid, oldestxmin) ); } TransactionId PageGetPrunable(Page page) { ! return ((PageHeader) page)->pd_prune_xid; } void PageSetPrunable(Page page, TransactionId xid) { Assert(TransactionIdIsNormal(xid)); ! if (!TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) || ! TransactionIdPrecedes(xid, ((PageHeader) (page))->pd_prune_xid)) ! ((PageHeader) (page))->pd_prune_xid = (xid); } void PageClearPrunable(Page page) { ! ((PageHeader) page)->pd_prune_xid = InvalidTransactionId; } bool PageIsComprimable(Page page) { ! PageHeader ph = (PageHeader) page; ! return(ph->pd_lower >= SizeOfPageHeaderData && ! ph->pd_upper > ph->pd_lower && ! ph->pd_upper <= BLCKSZ); } /* --- 1117,1335 ---- */ XLogRecPtr PageGetLSN(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return ((PageHeader_04) page)->pd_lsn; ! case 3 : return ((PageHeader_03) page)->pd_lsn; ! } ! elog(PANIC, "Unsupported page layout in function PageGetLSN."); } LocationIndex PageGetLower(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return ((PageHeader_04) page)->pd_lower; ! case 3 : return ((PageHeader_03) page)->pd_lower; ! case 0 : return 0; ! } ! elog(PANIC, "Unsupported page layout in function PageGetLower."); ! return 0; } LocationIndex PageGetUpper(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return ((PageHeader_04) page)->pd_upper; ! case 3 : return ((PageHeader_03) page)->pd_upper; ! case 0 : return 0; ! } ! elog(PANIC, "Unsupported page layout in function PageGetUpper."); ! return 0; } LocationIndex PageGetSpecial(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return ((PageHeader_04) page)->pd_special; ! case 3 : return ((PageHeader_03) page)->pd_special; ! } ! elog(PANIC, "Unsupported page layout in function PageGetUpper."); ! return 0; } + void PageSetLSN(Page page, XLogRecPtr lsn) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) page)->pd_lsn = lsn; ! break; ! case 3 : ((PageHeader_03) page)->pd_lsn = lsn; ! break; ! default: elog(PANIC, "Unsupported page layout in function PageSetLSN."); ! } } /* NOTE: only the 16 least significant bits are stored */ TimeLineID PageGetTLI(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return ((PageHeader_04) (page))->pd_tli; ! case 3 : return ((PageHeader_03) (page))->pd_tli; ! } ! elog(PANIC, "Unsupported page layout in function PageGetTLI."); } void PageSetTLI(Page page, TimeLineID tli) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) (page))->pd_tli = (uint16) (tli); ! break; ! case 3 : ((PageHeader_03) (page))->pd_tli = tli; ! break; ! default: elog(PANIC, "Unsupported page layout in function PageSetTLI."); ! } } bool PageHasFreeLinePointers(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return ((PageHeader_04) (page))->pd_flags & PD_HAS_FREE_LINES; ! default: return false; ! } } void PageSetHasFreeLinePointers(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) (page))->pd_flags |= PD_HAS_FREE_LINES; ! break; ! default: elog(PANIC, "HasFreeLinePointers is not supported on page layout version %i", ! PageGetPageLayoutVersion(page)); ! } } void PageClearHasFreeLinePointers(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) (page))->pd_flags &= ~PD_HAS_FREE_LINES; ! break; ! default: elog(PANIC, "HasFreeLinePointers is not supported on page layout version %i", ! PageGetPageLayoutVersion(page)); ! } } bool PageIsFull(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return ((PageHeader_04) (page))->pd_flags & PD_PAGE_FULL; ! default : return true; ! } ! return true; /* no space on old data page */ } void PageSetFull(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) (page))->pd_flags |= PD_PAGE_FULL; ! break; ! default: elog(PANIC, "PageSetFull is not supported on page layout version %i", ! PageGetPageLayoutVersion(page)); ! } } void PageClearFull(Page page) { ! switch( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) (page))->pd_flags &= ~PD_PAGE_FULL; ! break; ! default: elog(PANIC, "PageClearFull is not supported on page layout version %i", ! PageGetPageLayoutVersion(page)); ! } } bool PageIsPrunable(Page page, TransactionId oldestxmin) { AssertMacro(TransactionIdIsNormal(oldestxmin)); ! switch( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return ( ! TransactionIdIsValid(((PageHeader_04) page)->pd_prune_xid) && ! TransactionIdPrecedes(((PageHeader_04) page)->pd_prune_xid, oldestxmin) ); ! case 3 : return false; ! } ! elog(PANIC, "PageIsPrunable is not supported on page layout version %i", ! PageGetPageLayoutVersion(page)); } TransactionId PageGetPrunable(Page page) { ! switch( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return ((PageHeader_04) page)->pd_prune_xid; ! case 3 : return 0; ! } ! elog(PANIC, "PageGetPrunable is not supported on page layout version %i", ! PageGetPageLayoutVersion(page)); } void PageSetPrunable(Page page, TransactionId xid) { Assert(TransactionIdIsNormal(xid)); ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : if (!TransactionIdIsValid(((PageHeader_04) (page))->pd_prune_xid) || ! TransactionIdPrecedes(xid, ((PageHeader_04) (page))->pd_prune_xid)) ! ((PageHeader_04) (page))->pd_prune_xid = (xid); ! break; ! default: elog(PANIC, "PageSetPrunable is not supported on page layout version %i", ! PageGetPageLayoutVersion(page)); ! } } void PageClearPrunable(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : ((PageHeader_04) page)->pd_prune_xid = InvalidTransactionId; ! break; ! // default: elog(PANIC, "PageClearPrunable is not supported on page layout version %i", ! // PageGetPageLayoutVersion(page)); ! // Silently ignore this request ! } } bool PageIsComprimable(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : { ! PageHeader_04 ph = (PageHeader_04) page; ! return(ph->pd_lower >= SizeOfPageHeaderData04 && ! ph->pd_upper > ph->pd_lower && ! ph->pd_upper <= BLCKSZ); ! } ! case 3 : { ! PageHeader_03 ph = (PageHeader_03) page; ! return(ph->pd_lower >= SizeOfPageHeaderData03 && ! ph->pd_upper > ph->pd_lower && ! ph->pd_upper <= BLCKSZ); ! } ! default: elog(PANIC, "PageIsComprimable is not supported on page layout version %i", ! PageGetPageLayoutVersion(page)); ! } } /* *************** *** 1092,1097 **** */ bool PageIsEmpty(Page page) { ! return (((PageHeader) (page))->pd_lower <= SizeOfPageHeaderData); } --- 1338,1349 ---- */ bool PageIsEmpty(Page page) { ! switch ( PageGetPageLayoutVersion(page) ) ! { ! case 4 : return (((PageHeader_04) (page))->pd_lower <= SizeOfPageHeaderData04); ! case 3 : return (((PageHeader_04) (page))->pd_lower <= SizeOfPageHeaderData03); ! default: elog(PANIC, "PageIsEmpty is not supported on page layout version %i", ! PageGetPageLayoutVersion(page)); ! } } diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/include/access/gin.h pgsql_master_upgrade.13a47c410da7/src/include/access/gin.h *** pgsql_master_upgrade.751eb7c6969f/src/include/access/gin.h 2008-10-31 21:45:33.172329319 +0100 --- pgsql_master_upgrade.13a47c410da7/src/include/access/gin.h 2008-10-31 21:45:33.265898951 +0100 *************** *** 115,121 **** #define GinGetPosting(itup) ( (ItemPointer)(( ((char*)(itup)) + SHORTALIGN(GinGetOrigSizePosting(itup)) )) ) #define GinMaxItemSize \ ! ((BLCKSZ - SizeOfPageHeaderData - \ MAXALIGN(sizeof(GinPageOpaqueData))) / 3 - sizeof(ItemIdData)) --- 115,121 ---- #define GinGetPosting(itup) ( (ItemPointer)(( ((char*)(itup)) + SHORTALIGN(GinGetOrigSizePosting(itup)) )) ) #define GinMaxItemSize \ ! ((BLCKSZ - SizeOfPageHeaderData04 - \ MAXALIGN(sizeof(GinPageOpaqueData))) / 3 - sizeof(ItemIdData)) *************** *** 131,137 **** (GinDataPageGetData(page) + ((i)-1) * GinSizeOfItem(page)) #define GinDataPageGetFreeSpace(page) \ ! (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) \ - MAXALIGN(sizeof(ItemPointerData)) \ - GinPageGetOpaque(page)->maxoff * GinSizeOfItem(page) \ - MAXALIGN(sizeof(GinPageOpaqueData))) --- 131,137 ---- (GinDataPageGetData(page) + ((i)-1) * GinSizeOfItem(page)) #define GinDataPageGetFreeSpace(page) \ ! (BLCKSZ - MAXALIGN(SizeOfPageHeaderData04) \ - MAXALIGN(sizeof(ItemPointerData)) \ - GinPageGetOpaque(page)->maxoff * GinSizeOfItem(page) \ - MAXALIGN(sizeof(GinPageOpaqueData))) diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/include/access/gist_private.h pgsql_master_upgrade.13a47c410da7/src/include/access/gist_private.h *** pgsql_master_upgrade.751eb7c6969f/src/include/access/gist_private.h 2008-10-31 21:45:33.176541012 +0100 --- pgsql_master_upgrade.13a47c410da7/src/include/access/gist_private.h 2008-10-31 21:45:33.270105878 +0100 *************** *** 272,278 **** /* gistutil.c */ #define GiSTPageSize \ ! ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GISTPageOpaqueData)) ) #define GIST_MIN_FILLFACTOR 10 #define GIST_DEFAULT_FILLFACTOR 90 --- 272,278 ---- /* gistutil.c */ #define GiSTPageSize \ ! ( BLCKSZ - SizeOfPageHeaderData04 - MAXALIGN(sizeof(GISTPageOpaqueData)) ) #define GIST_MIN_FILLFACTOR 10 #define GIST_DEFAULT_FILLFACTOR 90 diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/include/access/hash.h pgsql_master_upgrade.13a47c410da7/src/include/access/hash.h *** pgsql_master_upgrade.751eb7c6969f/src/include/access/hash.h 2008-10-31 21:45:33.180773015 +0100 --- pgsql_master_upgrade.13a47c410da7/src/include/access/hash.h 2008-10-31 21:45:33.274260668 +0100 *************** *** 168,174 **** */ #define HashMaxItemSize(page) \ MAXALIGN_DOWN(PageGetPageSize(page) - \ ! SizeOfPageHeaderData - \ sizeof(ItemIdData) - \ MAXALIGN(sizeof(HashPageOpaqueData))) --- 168,174 ---- */ #define HashMaxItemSize(page) \ MAXALIGN_DOWN(PageGetPageSize(page) - \ ! SizeOfPageHeaderData04 - \ sizeof(ItemIdData) - \ MAXALIGN(sizeof(HashPageOpaqueData))) *************** *** 198,204 **** #define HashGetMaxBitmapSize(page) \ (PageGetPageSize((Page) page) - \ ! (MAXALIGN(SizeOfPageHeaderData) + MAXALIGN(sizeof(HashPageOpaqueData)))) #define HashPageGetMeta(page) \ ((HashMetaPage) PageGetContents(page)) --- 198,204 ---- #define HashGetMaxBitmapSize(page) \ (PageGetPageSize((Page) page) - \ ! (MAXALIGN(SizeOfPageHeaderData04) + MAXALIGN(sizeof(HashPageOpaqueData)))) #define HashPageGetMeta(page) \ ((HashMetaPage) PageGetContents(page)) diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/include/access/htup_03.h pgsql_master_upgrade.13a47c410da7/src/include/access/htup_03.h *** pgsql_master_upgrade.751eb7c6969f/src/include/access/htup_03.h 1970-01-01 01:00:00.000000000 +0100 --- pgsql_master_upgrade.13a47c410da7/src/include/access/htup_03.h 2008-10-31 21:45:33.282414095 +0100 *************** *** 0 **** --- 1,311 ---- + /*------------------------------------------------------------------------- + * + * htup.h + * POSTGRES heap tuple definitions. + * + * + * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * $PostgreSQL: pgsql/src/include/access/htup.h,v 1.87 2006/11/05 22:42:10 tgl Exp $ + * + *------------------------------------------------------------------------- + */ + #ifndef HTUP_03_H + #define HTUP_03_H + + #include "access/htup.h" + #include "storage/itemptr.h" + #include "storage/relfilenode.h" + #include "utils/rel.h" + + /* + * Heap tuple header. To avoid wasting space, the fields should be + * layed out in such a way to avoid structure padding. + * + * Datums of composite types (row types) share the same general structure + * as on-disk tuples, so that the same routines can be used to build and + * examine them. However the requirements are slightly different: a Datum + * does not need any transaction visibility information, and it does need + * a length word and some embedded type information. We can achieve this + * by overlaying the xmin/cmin/xmax/cmax/xvac fields of a heap tuple + * with the fields needed in the Datum case. Typically, all tuples built + * in-memory will be initialized with the Datum fields; but when a tuple is + * about to be inserted in a table, the transaction fields will be filled, + * overwriting the datum fields. + * + * The overall structure of a heap tuple looks like: + * fixed fields (HeapTupleHeaderData struct) + * nulls bitmap (if HEAP_HASNULL is set in t_infomask) + * alignment padding (as needed to make user data MAXALIGN'd) + * object ID (if HEAP_HASOID is set in t_infomask) + * user data fields + * + * We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac in four + * physical fields. Xmin, Cmin and Xmax are always really stored, but + * Cmax and Xvac share a field. This works because we know that there are + * only a limited number of states that a tuple can be in, and that Cmax + * is only interesting for the lifetime of the deleting transaction. + * This assumes that VACUUM FULL never tries to move a tuple whose Cmax + * is still interesting (ie, delete-in-progress). + * + * Note that in 7.3 and 7.4 a similar idea was applied to Xmax and Cmin. + * However, with the advent of subtransactions, a tuple may need both Xmax + * and Cmin simultaneously, so this is no longer possible. + * + * A word about t_ctid: whenever a new tuple is stored on disk, its t_ctid + * is initialized with its own TID (location). If the tuple is ever updated, + * its t_ctid is changed to point to the replacement version of the tuple. + * Thus, a tuple is the latest version of its row iff XMAX is invalid or + * t_ctid points to itself (in which case, if XMAX is valid, the tuple is + * either locked or deleted). One can follow the chain of t_ctid links + * to find the newest version of the row. Beware however that VACUUM might + * erase the pointed-to (newer) tuple before erasing the pointing (older) + * tuple. Hence, when following a t_ctid link, it is necessary to check + * to see if the referenced slot is empty or contains an unrelated tuple. + * Check that the referenced tuple has XMIN equal to the referencing tuple's + * XMAX to verify that it is actually the descendant version and not an + * unrelated tuple stored into a slot recently freed by VACUUM. If either + * check fails, one may assume that there is no live descendant version. + * + * Following the fixed header fields, the nulls bitmap is stored (beginning + * at t_bits). The bitmap is *not* stored if t_infomask shows that there + * are no nulls in the tuple. If an OID field is present (as indicated by + * t_infomask), then it is stored just before the user data, which begins at + * the offset shown by t_hoff. Note that t_hoff must be a multiple of + * MAXALIGN. + */ + + typedef struct HeapTupleFields_03 + { + TransactionId t_xmin; /* inserting xact ID */ + CommandId t_cmin; /* inserting command ID */ + TransactionId t_xmax; /* deleting or locking xact ID */ + + union + { + CommandId t_cmax; /* deleting or locking command ID */ + TransactionId t_xvac; /* VACUUM FULL xact ID */ + } t_field4; + } HeapTupleFields_03; + + typedef struct DatumTupleFields_03 + { + int32 datum_len; /* required to be a varlena type */ + + int32 datum_typmod; /* -1, or identifier of a record type */ + + Oid datum_typeid; /* composite type OID, or RECORDOID */ + + /* + * Note: field ordering is chosen with thought that Oid might someday + * widen to 64 bits. + */ + } DatumTupleFields_03; + + typedef struct HeapTupleHeaderData_03 + { + union + { + HeapTupleFields_03 t_heap; + DatumTupleFields_03 t_datum; + } t_choice; + + ItemPointerData t_ctid; /* current TID of this or newer tuple */ + + /* Fields below here must match MinimalTupleData! */ + + int16 t_natts; /* number of attributes */ + + uint16 t_infomask; /* various flag bits, see below */ + + uint8 t_hoff; /* sizeof header incl. bitmap, padding */ + + /* ^ - 27 bytes - ^ */ + + bits8 t_bits[1]; /* bitmap of NULLs -- VARIABLE LENGTH */ + + /* MORE DATA FOLLOWS AT END OF STRUCT */ + } HeapTupleHeaderData_03; + + typedef HeapTupleHeaderData_03 *HeapTupleHeader_03; + + /* + * information stored in t_infomask: + */ + #define HEAP03_HASNULL 0x0001 /* has null attribute(s) */ + #define HEAP03_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */ + #define HEAP03_HASEXTERNAL 0x0004 /* has external stored attribute(s) */ + #define HEAP03_HASCOMPRESSED 0x0008 /* has compressed stored attribute(s) */ + #define HEAP03_HASEXTENDED 0x000C /* the two above combined */ + #define HEAP03_HASOID 0x0010 /* has an object-id field */ + /* 0x0020 is presently unused */ + #define HEAP03_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */ + #define HEAP03_XMAX_SHARED_LOCK 0x0080 /* xmax is shared locker */ + /* if either LOCK bit is set, xmax hasn't deleted the tuple, only locked it */ + #define HEAP03_IS_LOCKED (HEAP03_XMAX_EXCL_LOCK | HEAP03_XMAX_SHARED_LOCK) + #define HEAP03_XMIN_COMMITTED 0x0100 /* t_xmin committed */ + #define HEAP03_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */ + #define HEAP03_XMAX_COMMITTED 0x0400 /* t_xmax committed */ + #define HEAP03_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */ + #define HEAP03_XMAX_IS_MULTI 0x1000 /* t_xmax is a MultiXactId */ + #define HEAP03_UPDATED 0x2000 /* this is UPDATEd version of row */ + #define HEAP03_MOVED_OFF 0x4000 /* moved to another place by VACUUM + * FULL */ + #define HEAP03_MOVED_IN 0x8000 /* moved from another place by VACUUM + * FULL */ + #define HEAP03_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN) + + #define HEAP03_XACT_MASK 0xFFC0 /* visibility-related bits */ + + + /* + * HeapTupleHeader accessor macros + * + * Note: beware of multiple evaluations of "tup" argument. But the Set + * macros evaluate their other argument only once. + */ + /* + #define HeapTupleHeaderGetXmin(tup) \ + ( \ + (tup)->t_choice.t_heap.t_xmin \ + ) + + #define HeapTupleHeaderSetXmin(tup, xid) \ + ( \ + TransactionIdStore((xid), &(tup)->t_choice.t_heap.t_xmin) \ + ) + + #define HeapTupleHeaderGetXmax(tup) \ + ( \ + (tup)->t_choice.t_heap.t_xmax \ + ) + + #define HeapTupleHeaderSetXmax(tup, xid) \ + ( \ + TransactionIdStore((xid), &(tup)->t_choice.t_heap.t_xmax) \ + ) + + #define HeapTupleHeaderGetCmin(tup) \ + ( \ + (tup)->t_choice.t_heap.t_cmin \ + ) + + #define HeapTupleHeaderSetCmin(tup, cid) \ + ( \ + (tup)->t_choice.t_heap.t_cmin = (cid) \ + ) + */ + /* + * Note: GetCmax will produce wrong answers after SetXvac has been executed + * by a transaction other than the inserting one. We could check + * HEAP_XMAX_INVALID and return FirstCommandId if it's clear, but since that + * bit will be set again if the deleting transaction aborts, there'd be no + * real gain in safety from the extra test. So, just rely on the caller not + * to trust the value unless it's meaningful. + */ + /* + #define HeapTupleHeaderGetCmax(tup) \ + ( \ + (tup)->t_choice.t_heap.t_field4.t_cmax \ + ) + + #define HeapTupleHeaderSetCmax(tup, cid) \ + do { \ + Assert(!((tup)->t_infomask & HEAP_MOVED)); \ + (tup)->t_choice.t_heap.t_field4.t_cmax = (cid); \ + } while (0) + + #define HeapTupleHeaderGetXvac(tup) \ + ( \ + ((tup)->t_infomask & HEAP_MOVED) ? \ + (tup)->t_choice.t_heap.t_field4.t_xvac \ + : \ + InvalidTransactionId \ + ) + + #define HeapTupleHeaderSetXvac(tup, xid) \ + do { \ + Assert((tup)->t_infomask & HEAP_MOVED); \ + TransactionIdStore((xid), &(tup)->t_choice.t_heap.t_field4.t_xvac); \ + } while (0) + + #define HeapTupleHeaderGetDatumLength(tup) \ + ( \ + (tup)->t_choice.t_datum.datum_len \ + ) + + #define HeapTupleHeaderSetDatumLength(tup, len) \ + ( \ + (tup)->t_choice.t_datum.datum_len = (len) \ + ) + + #define HeapTupleHeaderGetTypeId(tup) \ + ( \ + (tup)->t_choice.t_datum.datum_typeid \ + ) + + #define HeapTupleHeaderSetTypeId(tup, typeid) \ + ( \ + (tup)->t_choice.t_datum.datum_typeid = (typeid) \ + ) + + #define HeapTupleHeaderGetTypMod(tup) \ + ( \ + (tup)->t_choice.t_datum.datum_typmod \ + ) + + #define HeapTupleHeaderSetTypMod(tup, typmod) \ + ( \ + (tup)->t_choice.t_datum.datum_typmod = (typmod) \ + ) + + #define HeapTupleHeaderGetOid(tup) \ + ( \ + ((tup)->t_infomask & HEAP_HASOID) ? \ + *((Oid *) ((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) \ + : \ + InvalidOid \ + ) + + #define HeapTupleHeaderSetOid(tup, oid) \ + do { \ + Assert((tup)->t_infomask & HEAP_HASOID); \ + *((Oid *) ((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) = (oid); \ + } while (0) + + */ + /* + * BITMAPLEN(NATTS) - + * Computes size of null bitmap given number of data columns. + */ + //#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8) + + /* + * MaxTupleSize is the maximum allowed size of a tuple, including header and + * MAXALIGN alignment padding. Basically it's BLCKSZ minus the other stuff + * that has to be on a disk page. The "other stuff" includes access-method- + * dependent "special space", which we assume will be no more than + * MaxSpecialSpace bytes (currently, on heap pages it's actually zero). + * + * NOTE: we do not need to count an ItemId for the tuple because + * sizeof(PageHeaderData) includes the first ItemId on the page. + */ + //#define MaxSpecialSpace 32 + + //#define MaxTupleSize \ + // (BLCKSZ - MAXALIGN(sizeof(PageHeaderData) + MaxSpecialSpace)) + + /* + * MaxHeapTuplesPerPage is an upper bound on the number of tuples that can + * fit on one heap page. (Note that indexes could have more, because they + * use a smaller tuple header.) We arrive at the divisor because each tuple + * must be maxaligned, and it must have an associated item pointer. + */ + //#define MaxHeapTuplesPerPage \ + // ((int) ((BLCKSZ - offsetof(PageHeaderData, pd_linp)) / \ + // (MAXALIGN(offsetof(HeapTupleHeaderData, t_bits)) + sizeof(ItemIdData)))) + + extern HeapTuple heap_tuple_upgrade_03(Relation rel, HeapTuple tuple); + + #endif /* HTUP_H */ diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/include/access/tuplimits.h pgsql_master_upgrade.13a47c410da7/src/include/access/tuplimits.h *** pgsql_master_upgrade.751eb7c6969f/src/include/access/tuplimits.h 2008-10-31 21:45:33.181679309 +0100 --- pgsql_master_upgrade.13a47c410da7/src/include/access/tuplimits.h 2008-10-31 21:45:33.275179286 +0100 *************** *** 29,35 **** * ItemIds and tuples have different alignment requirements, don't assume that * you can, say, fit 2 tuples of size MaxHeapTupleSize/2 on the same page. */ ! #define MaxHeapTupleSize (BLCKSZ - MAXALIGN(SizeOfPageHeaderData + sizeof(ItemIdData))) /* * MaxHeapTuplesPerPage is an upper bound on the number of tuples that can --- 29,35 ---- * ItemIds and tuples have different alignment requirements, don't assume that * you can, say, fit 2 tuples of size MaxHeapTupleSize/2 on the same page. */ ! #define MaxHeapTupleSize (BLCKSZ - MAXALIGN(SizeOfPageHeaderData04 + sizeof(ItemIdData))) /* * MaxHeapTuplesPerPage is an upper bound on the number of tuples that can *************** *** 43,49 **** * require increases in the size of work arrays. */ #define MaxHeapTuplesPerPage \ ! ((int) ((BLCKSZ - SizeOfPageHeaderData) / \ (MAXALIGN(offsetof(HeapTupleHeaderData, t_bits)) + sizeof(ItemIdData)))) --- 43,49 ---- * require increases in the size of work arrays. */ #define MaxHeapTuplesPerPage \ ! ((int) ((BLCKSZ - SizeOfPageHeaderData04) / \ (MAXALIGN(offsetof(HeapTupleHeaderData, t_bits)) + sizeof(ItemIdData)))) *************** *** 55,61 **** * must be maxaligned, and it must have an associated item pointer. */ #define MaxIndexTuplesPerPage \ ! ((int) ((BLCKSZ - SizeOfPageHeaderData) / \ (MAXALIGN(sizeof(IndexTupleData) + 1) + sizeof(ItemIdData)))) /* --- 55,61 ---- * must be maxaligned, and it must have an associated item pointer. */ #define MaxIndexTuplesPerPage \ ! ((int) ((BLCKSZ - SizeOfPageHeaderData04) / \ (MAXALIGN(sizeof(IndexTupleData) + 1) + sizeof(ItemIdData)))) /* *************** *** 66,72 **** */ #define BTMaxItemSize(page) \ MAXALIGN_DOWN((PageGetPageSize(page) - \ ! MAXALIGN(SizeOfPageHeaderData + 3*sizeof(ItemIdData)) - \ MAXALIGN(sizeof(BTPageOpaqueData))) / 3) --- 66,72 ---- */ #define BTMaxItemSize(page) \ MAXALIGN_DOWN((PageGetPageSize(page) - \ ! MAXALIGN(SizeOfPageHeaderData04 + 3*sizeof(ItemIdData)) - \ MAXALIGN(sizeof(BTPageOpaqueData))) / 3) diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/include/access/tuptoaster.h pgsql_master_upgrade.13a47c410da7/src/include/access/tuptoaster.h *** pgsql_master_upgrade.751eb7c6969f/src/include/access/tuptoaster.h 2008-10-31 21:45:33.183208112 +0100 --- pgsql_master_upgrade.13a47c410da7/src/include/access/tuptoaster.h 2008-10-31 21:45:33.276709073 +0100 *************** *** 49,55 **** #define TOAST_TUPLE_THRESHOLD \ MAXALIGN_DOWN((BLCKSZ - \ ! MAXALIGN(SizeOfPageHeaderData + TOAST_TUPLES_PER_PAGE * sizeof(ItemIdData))) \ / TOAST_TUPLES_PER_PAGE) #define TOAST_TUPLE_TARGET TOAST_TUPLE_THRESHOLD --- 49,55 ---- #define TOAST_TUPLE_THRESHOLD \ MAXALIGN_DOWN((BLCKSZ - \ ! MAXALIGN(SizeOfPageHeaderData04 + TOAST_TUPLES_PER_PAGE * sizeof(ItemIdData))) \ / TOAST_TUPLES_PER_PAGE) #define TOAST_TUPLE_TARGET TOAST_TUPLE_THRESHOLD *************** *** 75,81 **** #define EXTERN_TUPLE_MAX_SIZE \ MAXALIGN_DOWN((BLCKSZ - \ ! MAXALIGN(SizeOfPageHeaderData + EXTERN_TUPLES_PER_PAGE * sizeof(ItemIdData))) \ / EXTERN_TUPLES_PER_PAGE) #define TOAST_MAX_CHUNK_SIZE \ --- 75,81 ---- #define EXTERN_TUPLE_MAX_SIZE \ MAXALIGN_DOWN((BLCKSZ - \ ! MAXALIGN(SizeOfPageHeaderData04 + EXTERN_TUPLES_PER_PAGE * sizeof(ItemIdData))) \ / EXTERN_TUPLES_PER_PAGE) #define TOAST_MAX_CHUNK_SIZE \ diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/include/storage/bufpage.h pgsql_master_upgrade.13a47c410da7/src/include/storage/bufpage.h *** pgsql_master_upgrade.751eb7c6969f/src/include/storage/bufpage.h 2008-10-31 21:45:33.185832325 +0100 --- pgsql_master_upgrade.13a47c410da7/src/include/storage/bufpage.h 2008-10-31 21:45:33.279178878 +0100 *************** *** 121,127 **** * On the high end, we can only support pages up to 32KB because lp_off/lp_len * are 15 bits. */ ! typedef struct PageHeaderData { /* XXX LSN is member of *any* block, not only page-organized ones */ XLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog --- 121,127 ---- * On the high end, we can only support pages up to 32KB because lp_off/lp_len * are 15 bits. */ ! typedef struct PageHeaderData_04 { /* XXX LSN is member of *any* block, not only page-organized ones */ XLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog *************** *** 135,143 **** uint16 pd_pagesize_version; TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */ ItemIdData pd_linp[1]; /* beginning of line pointer array */ ! } PageHeaderData; - typedef PageHeaderData *PageHeader; /* * pd_flags contains the following flag bits. Undefined bits are initialized --- 135,160 ---- uint16 pd_pagesize_version; TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */ ItemIdData pd_linp[1]; /* beginning of line pointer array */ ! } PageHeaderData_04; ! ! typedef PageHeaderData_04 *PageHeader_04; ! ! typedef struct PageHeaderData_03 ! { ! /* XXX LSN is member of *any* block, not only page-organized ones */ ! XLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog ! * record for last change to this page */ ! TimeLineID pd_tli; /* TLI of last change */ ! LocationIndex pd_lower; /* offset to start of free space */ ! LocationIndex pd_upper; /* offset to end of free space */ ! LocationIndex pd_special; /* offset to start of special space */ ! uint16 pd_pagesize_version; ! ItemIdData pd_linp[1]; /* beginning of line pointer array */ ! } PageHeaderData_03; ! ! typedef PageHeaderData_03 *PageHeader_03; ! /* * pd_flags contains the following flag bits. Undefined bits are initialized *************** *** 181,195 **** #define PageIsValid(page) PointerIsValid(page) /* ! * line pointer(s) do not count as part of header */ ! #define SizeOfPageHeaderData (offsetof(PageHeaderData, pd_linp)) /* * PageIsNew * returns true iff page has not been initialized (by PageInit) */ ! #define PageIsNew(page) (((PageHeader) (page))->pd_upper == 0) /* ---------------- * macros to access page size info --- 198,213 ---- #define PageIsValid(page) PointerIsValid(page) /* ! * line pointer does not count as part of header */ ! #define SizeOfPageHeaderData04 offsetof(PageHeaderData_04, pd_linp[0]) ! #define SizeOfPageHeaderData03 offsetof(PageHeaderData_03, pd_linp[0]) /* * PageIsNew * returns true iff page has not been initialized (by PageInit) */ ! #define PageIsNew(page) (((PageHeader_04) (page))->pd_upper == 0) /* ---------------- * macros to access page size info *************** *** 211,224 **** * however, it can be called on a page that is not stored in a buffer. */ #define PageGetPageSize(page) \ ! ((Size) (((PageHeader) (page))->pd_pagesize_version & (uint16) 0xFF00)) /* * PageGetPageLayoutVersion * Returns the page layout version of a page. */ #define PageGetPageLayoutVersion(page) \ ! (((PageHeader) (page))->pd_pagesize_version & 0x00FF) /* * PageSetPageSizeAndVersion --- 229,242 ---- * however, it can be called on a page that is not stored in a buffer. */ #define PageGetPageSize(page) \ ! ((Size) (((PageHeader_04) (page))->pd_pagesize_version & (uint16) 0xFF00)) /* * PageGetPageLayoutVersion * Returns the page layout version of a page. */ #define PageGetPageLayoutVersion(page) \ ! (((PageHeader_04) (page))->pd_pagesize_version & 0x00FF) /* * PageSetPageSizeAndVersion *************** *** 231,239 **** ( \ AssertMacro(((size) & 0xFF00) == (size)), \ AssertMacro(((version) & 0x00FF) == (version)), \ ! ((PageHeader) (page))->pd_pagesize_version = (size) | (version) \ ) /* ---------------------------------------------------------------- * extern declarations * ---------------------------------------------------------------- --- 249,259 ---- ( \ AssertMacro(((size) & 0xFF00) == (size)), \ AssertMacro(((version) & 0x00FF) == (version)), \ ! ((PageHeader_04) (page))->pd_pagesize_version = (size) | (version) \ ) + + /* ---------------------------------------------------------------- * extern declarations * ---------------------------------------------------------------- *************** *** 303,307 **** --- 323,328 ---- extern OffsetNumber PageItemGetRedirect(Page, OffsetNumber offsetNumber); extern ItemId PageGetItemId(Page page, OffsetNumber offsetNumber);/* do not use it - only for pg_inspect contrib modul*/ + #endif /* BUFPAGE_H */ diff -Nrc pgsql_master_upgrade.751eb7c6969f/src/include/storage/fsm_internals.h pgsql_master_upgrade.13a47c410da7/src/include/storage/fsm_internals.h *** pgsql_master_upgrade.751eb7c6969f/src/include/storage/fsm_internals.h 2008-10-31 21:45:33.186717311 +0100 --- pgsql_master_upgrade.13a47c410da7/src/include/storage/fsm_internals.h 2008-10-31 21:45:33.280068969 +0100 *************** *** 49,55 **** * Number of non-leaf and leaf nodes, and nodes in total, on an FSM page. * These definitions are internal to fsmpage.c. */ ! #define NodesPerPage (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - \ offsetof(FSMPageData, fp_nodes)) #define NonLeafNodesPerPage (BLCKSZ / 2 - 1) --- 49,55 ---- * Number of non-leaf and leaf nodes, and nodes in total, on an FSM page. * These definitions are internal to fsmpage.c. */ ! #define NodesPerPage (BLCKSZ - MAXALIGN(SizeOfPageHeaderData04) - \ offsetof(FSMPageData, fp_nodes)) #define NonLeafNodesPerPage (BLCKSZ / 2 - 1)
pgsql-hackers by date: