diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 042a33a5d2bc6fd7a7109763057037b32dceeb65..71ba6d2e52ef25d94b00820e2803fa24b9d21751 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.226 2007/02/04 20:00:37 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.227 2007/02/05 04:22:18 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -3463,7 +3463,7 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
 	struct
 	{
 		HeapTupleHeaderData hdr;
-		char		data[MaxTupleSize];
+		char		data[MaxHeapTupleSize];
 	}			tbuf;
 	HeapTupleHeader htup;
 	xl_heap_header xlhdr;
@@ -3505,7 +3505,7 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
 		elog(PANIC, "heap_insert_redo: invalid max offset number");
 
 	newlen = record->xl_len - SizeOfHeapInsert - SizeOfHeapHeader;
-	Assert(newlen <= MaxTupleSize);
+	Assert(newlen <= MaxHeapTupleSize);
 	memcpy((char *) &xlhdr,
 		   (char *) xlrec + SizeOfHeapInsert,
 		   SizeOfHeapHeader);
@@ -3551,7 +3551,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move)
 	struct
 	{
 		HeapTupleHeaderData hdr;
-		char		data[MaxTupleSize];
+		char		data[MaxHeapTupleSize];
 	}			tbuf;
 	xl_heap_header xlhdr;
 	int			hsize;
@@ -3668,7 +3668,7 @@ newsame:;
 		hsize += (2 * sizeof(TransactionId));
 
 	newlen = record->xl_len - hsize;
-	Assert(newlen <= MaxTupleSize);
+	Assert(newlen <= MaxHeapTupleSize);
 	memcpy((char *) &xlhdr,
 		   (char *) xlrec + SizeOfHeapUpdate,
 		   SizeOfHeapHeader);
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index 4e033be4e0d31442bf3e81205bfcfb7622d2f044..0bb617a8cdcd2b4f3863e78112f914312a581c4b 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.64 2007/01/05 22:19:22 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.65 2007/02/05 04:22:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -118,12 +118,12 @@ RelationGetBufferForTuple(Relation relation, Size len,
 	/*
 	 * If we're gonna fail for oversize tuple, do it right away
 	 */
-	if (len > MaxTupleSize)
+	if (len > MaxHeapTupleSize)
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("row is too big: size %lu, maximum size %lu",
 						(unsigned long) len,
-						(unsigned long) MaxTupleSize)));
+						(unsigned long) MaxHeapTupleSize)));
 
 	/* Compute desired extra freespace due to fillfactor option */
 	saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
@@ -147,7 +147,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
 	 * When use_fsm is false, we either put the tuple onto the existing target
 	 * page or extend the relation.
 	 */
-	if (len + saveFreeSpace <= MaxTupleSize)
+	if (len + saveFreeSpace <= MaxHeapTupleSize)
 		targetBlock = relation->rd_targblock;
 	else
 	{
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 43647d7989fc12da5365981984779e26b454df0d..5f9f787eeea4be7c7be98a0c2f349668ab0f165a 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.344 2007/02/01 19:10:26 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.345 2007/02/05 04:22:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1236,7 +1236,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
 				nunused;
 	double		free_space,
 				usable_free_space;
-	Size		min_tlen = MaxTupleSize;
+	Size		min_tlen = MaxHeapTupleSize;
 	Size		max_tlen = 0;
 	bool		do_shrinking = true;
 	VTupleLink	vtlinks = (VTupleLink) palloc(100 * sizeof(VTupleLinkData));
diff --git a/src/include/access/htup.h b/src/include/access/htup.h
index ddde6a466d1a30f8880368c39b2b8ec2dc559ccf..eecc6959e89a424187216d4e94eb5e10301450af 100644
--- a/src/include/access/htup.h
+++ b/src/include/access/htup.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/htup.h,v 1.89 2007/01/09 22:01:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/htup.h,v 1.90 2007/02/05 04:22:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -314,19 +314,17 @@ do { \
 #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).
+ * MaxHeapTupleSize is the maximum allowed size of a heap tuple, including
+ * header and MAXALIGN alignment padding.  Basically it's BLCKSZ minus the
+ * other stuff that has to be on a disk page.  Since heap pages use no
+ * "special space", there's no deduction for that.
  *
  * NOTE: we do not need to count an ItemId for the tuple because
- * sizeof(PageHeaderData) includes the first ItemId on the page.
+ * sizeof(PageHeaderData) includes the first ItemId on the page.  But beware
+ * of assuming that, say, you can fit 2 tuples of size MaxHeapTupleSize/2
+ * on the same page.
  */
-#define MaxSpecialSpace  32
-
-#define MaxTupleSize	\
-	(BLCKSZ - MAXALIGN(sizeof(PageHeaderData) + MaxSpecialSpace))
+#define MaxHeapTupleSize  (BLCKSZ - MAXALIGN(sizeof(PageHeaderData)))
 
 /*
  * MaxHeapTuplesPerPage is an upper bound on the number of tuples that can
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 574aec496f8c0d56f1bea005d4b1ff86408407f6..91d91a77053dfb73c6a1669c3772dd4284d16670 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.109 2007/01/20 18:43:35 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.110 2007/02/05 04:22:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -99,13 +99,18 @@ typedef struct BTMetaPageData
 #define BTREE_VERSION	2		/* current version number */
 
 /*
+ * Maximum size of a btree index entry, including its tuple header.
+ *
  * We actually need to be able to fit three items on every page,
  * so restrict any one item to 1/3 the per-page available space.
+ *
+ * Note: sizeof(PageHeaderData) includes the first ItemId, but we have
+ * to allow for 2 more, as well as the end-of-page special space.
  */
 #define BTMaxItemSize(page) \
-	((PageGetPageSize(page) - \
-	  sizeof(PageHeaderData) - \
-	  MAXALIGN(sizeof(BTPageOpaqueData))) / 3 - sizeof(ItemIdData))
+	MAXALIGN_DOWN((PageGetPageSize(page) - \
+				   MAXALIGN(sizeof(PageHeaderData) + 2*sizeof(ItemIdData)) - \
+				   MAXALIGN(sizeof(BTPageOpaqueData))) / 3)
 
 /*
  * The leaf-page fillfactor defaults to 90% but is user-adjustable.
diff --git a/src/include/access/tuptoaster.h b/src/include/access/tuptoaster.h
index 49d69836dcd79e95e9606e31b5a20324a0e1d8e4..3693379dba72edb0312539daa41b1dd123aee3c1 100644
--- a/src/include/access/tuptoaster.h
+++ b/src/include/access/tuptoaster.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 2000-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/access/tuptoaster.h,v 1.31 2007/02/04 20:00:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/tuptoaster.h,v 1.32 2007/02/05 04:22:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,40 +29,47 @@
  * TOAST_TUPLE_TARGET bytes.  Both numbers include all tuple header overhead
  * and between-fields alignment padding, but we do *not* consider any
  * end-of-tuple alignment padding; hence the values can be compared directly
- * to a tuple's t_len field.  (Note that the symbol values are not
- * necessarily MAXALIGN multiples.)
+ * to a tuple's t_len field.  We choose TOAST_TUPLE_THRESHOLD with the
+ * knowledge that toast-table tuples will be exactly that size, and we'd
+ * like to fit four of them per page with minimal space wastage.
  *
  * The numbers need not be the same, though they currently are.
+ *
+ * Note: sizeof(PageHeaderData) includes the first ItemId, but we have
+ * to allow for 3 more, if we want to fit 4 tuples on a page.
  */
-#define TOAST_TUPLE_THRESHOLD	(MaxTupleSize / 4)
+#define TOAST_TUPLE_THRESHOLD	\
+	MAXALIGN_DOWN((BLCKSZ - \
+				   MAXALIGN(sizeof(PageHeaderData) + 3 * sizeof(ItemIdData))) \
+				  / 4)
 
-#define TOAST_TUPLE_TARGET		(MaxTupleSize / 4)
+#define TOAST_TUPLE_TARGET		TOAST_TUPLE_THRESHOLD
 
 /*
  * If an index value is larger than TOAST_INDEX_TARGET, we will try to
  * compress it (we can't move it out-of-line, however).  Note that this
  * number is per-datum, not per-tuple, for simplicity in index_form_tuple().
  */
-#define TOAST_INDEX_TARGET		(MaxTupleSize / 16)
+#define TOAST_INDEX_TARGET		(MaxHeapTupleSize / 16)
 
 /*
  * When we store an oversize datum externally, we divide it into chunks
  * containing at most TOAST_MAX_CHUNK_SIZE data bytes.	This number *must*
  * be small enough that the completed toast-table tuple (including the
- * ID and sequence fields and all overhead) is no more than MaxTupleSize
+ * ID and sequence fields and all overhead) is no more than MaxHeapTupleSize
  * bytes.  It *should* be small enough to make toast-table tuples no more
  * than TOAST_TUPLE_THRESHOLD bytes, else heapam.c will uselessly invoke
- * the toaster on toast-table tuples.
+ * the toaster on toast-table tuples.  The current coding ensures that the
+ * maximum tuple length is exactly TOAST_TUPLE_THRESHOLD bytes.
  *
  * NB: you cannot change this value without forcing initdb, at least not
  * if your DB contains any multi-chunk toasted values.
  */
 #define TOAST_MAX_CHUNK_SIZE	(TOAST_TUPLE_THRESHOLD -			\
-			MAXALIGN(												\
-				MAXALIGN(offsetof(HeapTupleHeaderData, t_bits)) +	\
-				sizeof(Oid) +										\
-				sizeof(int32) +										\
-				VARHDRSZ))
+				MAXALIGN(offsetof(HeapTupleHeaderData, t_bits)) -	\
+				sizeof(Oid) -										\
+				sizeof(int32) -										\
+				VARHDRSZ)
 
 
 /* ----------
diff --git a/src/include/c.h b/src/include/c.h
index 9daa9e4c0eb00a149f0c9aa29510c2a533b34827..0774ec7cc1e636ad7706d8763de802e905102c4f 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/c.h,v 1.217 2007/01/25 03:30:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/c.h,v 1.218 2007/02/05 04:22:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -537,12 +537,12 @@ typedef NameData *Name;
 
 /* ----------------
  * Alignment macros: align a length or address appropriately for a given type.
+ * The fooALIGN() macros round up to a multiple of the required alignment,
+ * while the fooALIGN_DOWN() macros round down.  The latter are more useful
+ * for problems like "how many X-sized structures will fit in a page?".
  *
- * There used to be some incredibly crufty platform-dependent hackery here,
- * but now we rely on the configure script to get the info for us. Much nicer.
- *
- * NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
- * That case seems extremely unlikely to occur in practice, however.
+ * NOTE: TYPEALIGN[_DOWN] will not work if ALIGNVAL is not a power of 2.
+ * That case seems extremely unlikely to be needed in practice, however.
  * ----------------
  */
 
@@ -557,6 +557,14 @@ typedef NameData *Name;
 /* MAXALIGN covers only built-in types, not buffers */
 #define BUFFERALIGN(LEN)		TYPEALIGN(ALIGNOF_BUFFER, (LEN))
 
+#define TYPEALIGN_DOWN(ALIGNVAL,LEN)  \
+	(((long) (LEN)) & ~((long) ((ALIGNVAL) - 1)))
+
+#define SHORTALIGN_DOWN(LEN)	TYPEALIGN_DOWN(ALIGNOF_SHORT, (LEN))
+#define INTALIGN_DOWN(LEN)		TYPEALIGN_DOWN(ALIGNOF_INT, (LEN))
+#define LONGALIGN_DOWN(LEN)		TYPEALIGN_DOWN(ALIGNOF_LONG, (LEN))
+#define DOUBLEALIGN_DOWN(LEN)	TYPEALIGN_DOWN(ALIGNOF_DOUBLE, (LEN))
+#define MAXALIGN_DOWN(LEN)		TYPEALIGN_DOWN(MAXIMUM_ALIGNOF, (LEN))
 
 /* ----------------------------------------------------------------
  *				Section 6:	widely useful macros
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 2f1bb8ae1a46e36f7e94b944dca9ba38894cdda5..6aebea61dd990317570d1294bcd9316245d76f37 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.379 2007/02/03 14:06:55 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.380 2007/02/05 04:22:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200702031
+#define CATALOG_VERSION_NO	200702041
 
 #endif