diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 4640b2022438a19a69499319a919cc6023bc1789..e76fa5a5652873125de876b9a4cc03da080ed6a3 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.66 2000/11/14 21:04:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.67 2000/11/30 18:38:45 tgl Exp $
  *
  * NOTES
  *	  The old interface functions have been converted to macros
@@ -300,11 +300,11 @@ nocachegetattr(HeapTuple tuple,
 			   TupleDesc tupleDesc,
 			   bool *isnull)
 {
-	char	   *tp;				/* ptr to att in tuple */
 	HeapTupleHeader tup = tuple->t_data;
-	bits8	   *bp = tup->t_bits;		/* ptr to att in tuple */
 	Form_pg_attribute *att = tupleDesc->attrs;
-	int			slow = 0;		/* do we have to walk nulls? */
+	char	   *tp;				/* ptr to att in tuple */
+	bits8	   *bp = tup->t_bits;		/* ptr to null bitmask in tuple */
+	bool		slow = false;	/* do we have to walk nulls? */
 
 	(void) isnull;				/* not used */
 #ifdef IN_MACRO
@@ -336,14 +336,6 @@ nocachegetattr(HeapTuple tuple,
 				fetchatt(&(att[attnum]),
 				  (char *) tup + tup->t_hoff + att[attnum]->attcacheoff);
 		}
-		else if (attnum == 0)
-		{
-
-			/*
-			 * first attribute is always at position zero
-			 */
-			return (Datum) fetchatt(&(att[0]), (char *) tup + tup->t_hoff);
-		}
 #endif
 	}
 	else
@@ -378,7 +370,7 @@ nocachegetattr(HeapTuple tuple,
 
 			/* check for nulls "before" final bit of last byte */
 			if ((~bp[byte]) & ((1 << finalbit) - 1))
-				slow = 1;
+				slow = true;
 			else
 			{
 				/* check for nulls in any "earlier" bytes */
@@ -388,7 +380,7 @@ nocachegetattr(HeapTuple tuple,
 				{
 					if (bp[i] != 0xFF)
 					{
-						slow = 1;
+						slow = true;
 						break;
 					}
 				}
@@ -408,21 +400,19 @@ nocachegetattr(HeapTuple tuple,
 			return (Datum) fetchatt(&(att[attnum]),
 									tp + att[attnum]->attcacheoff);
 		}
-		else if (attnum == 0)
-			return (Datum) fetchatt(&(att[0]), tp);
 		else if (!HeapTupleAllFixed(tuple))
 		{
 			int			j;
 
 			/*
-			 * In for(), we make this <= and not < because we want to test
+			 * In for(), we test <= and not < because we want to see
 			 * if we can go past it in initializing offsets.
 			 */
 			for (j = 0; j <= attnum; j++)
 			{
-				if (att[j]->attlen < 1 && !VARLENA_FIXED_SIZE(att[j]))
+				if (att[j]->attlen <= 0)
 				{
-					slow = 1;
+					slow = true;
 					break;
 				}
 			}
@@ -430,7 +420,7 @@ nocachegetattr(HeapTuple tuple,
 	}
 
 	/*
-	 * If slow is zero, and we got here, we know that we have a tuple with
+	 * If slow is false, and we got here, we know that we have a tuple with
 	 * no nulls or varlenas before the target attribute. If possible, we
 	 * also want to initialize the remainder of the attribute cached
 	 * offset values.
@@ -446,21 +436,17 @@ nocachegetattr(HeapTuple tuple,
 
 		att[0]->attcacheoff = 0;
 
-		while (att[j]->attcacheoff > 0)
+		while (j < attnum && att[j]->attcacheoff > 0)
 			j++;
 
-		if (!VARLENA_FIXED_SIZE(att[j - 1]))
-			off = att[j - 1]->attcacheoff + att[j - 1]->attlen;
-		else
-			off = att[j - 1]->attcacheoff + att[j - 1]->atttypmod;
+		off = att[j - 1]->attcacheoff + att[j - 1]->attlen;
 
 		for (; j <= attnum ||
 		/* Can we compute more?  We will probably need them */
 			 (j < tup->t_natts &&
 			  att[j]->attcacheoff == -1 &&
 			  (HeapTupleNoNulls(tuple) || !att_isnull(j, bp)) &&
-			  (HeapTupleAllFixed(tuple) ||
-			   att[j]->attlen > 0 || VARLENA_FIXED_SIZE(att[j]))); j++)
+			  (HeapTupleAllFixed(tuple) || att[j]->attlen > 0)); j++)
 		{
 
 			/*
@@ -516,8 +502,7 @@ nocachegetattr(HeapTuple tuple,
 
 			off = att_addlength(off, att[i]->attlen, tp + off);
 
-			if (usecache &&
-				att[i]->attlen == -1 && !VARLENA_FIXED_SIZE(att[i]))
+			if (usecache && att[i]->attlen == -1)
 				usecache = false;
 		}
 
diff --git a/src/backend/access/common/indextuple.c b/src/backend/access/common/indextuple.c
index 15ed18245607afd8380c783e817e2eba562d69d3..9f2bfb02c530a9545a4ff33641c25895801d85f8 100644
--- a/src/backend/access/common/indextuple.c
+++ b/src/backend/access/common/indextuple.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.46 2000/11/16 05:50:57 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.47 2000/11/30 18:38:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -160,13 +160,13 @@ index_formtuple(TupleDesc tupleDescriptor,
  *
  *		This caches attribute offsets in the attribute descriptor.
  *
- *		an alternate way to speed things up would be to cache offsets
+ *		An alternate way to speed things up would be to cache offsets
  *		with the tuple, but that seems more difficult unless you take
  *		the storage hit of actually putting those offsets into the
  *		tuple you send to disk.  Yuck.
  *
  *		This scheme will be slightly slower than that, but should
- *		preform well for queries which hit large #'s of tuples.  After
+ *		perform well for queries which hit large #'s of tuples.  After
  *		you cache the offsets once, examining all the other tuples using
  *		the same attribute descriptor will go much quicker. -cim 5/4/91
  * ----------------
@@ -177,13 +177,13 @@ nocache_index_getattr(IndexTuple tup,
 					  TupleDesc tupleDesc,
 					  bool *isnull)
 {
+	Form_pg_attribute *att = tupleDesc->attrs;
 	char	   *tp;				/* ptr to att in tuple */
-	char	   *bp = NULL;		/* ptr to att in tuple */
-	int			slow;			/* do we have to walk nulls? */
+	bits8	   *bp = NULL;		/* ptr to null bitmask in tuple */
+	bool		slow = false;	/* do we have to walk nulls? */
 	int			data_off;		/* tuple data offset */
-	Form_pg_attribute *att = tupleDesc->attrs;
 
-	(void) isnull;
+	(void) isnull;				/* not used */
 	/* ----------------
 	 *	sanity checks
 	 * ----------------
@@ -209,17 +209,12 @@ nocache_index_getattr(IndexTuple tup,
 	data_off = IndexTupleHasMinHeader(tup) ? sizeof *tup :
 		IndexInfoFindDataOffset(tup->t_info);
 
+	attnum--;
+
 	if (IndexTupleNoNulls(tup))
 	{
-		attnum--;
-
 #ifdef IN_MACRO
 /* This is handled in the macro */
-
-		/* first attribute is always at position zero */
-
-		if (attnum == 1)
-			return (Datum) fetchatt(&(att[0]), (char *) tup + data_off);
 		if (att[attnum]->attcacheoff != -1)
 		{
 			return (Datum) fetchatt(&(att[attnum]),
@@ -227,20 +222,13 @@ nocache_index_getattr(IndexTuple tup,
 									att[attnum]->attcacheoff);
 		}
 #endif
-
-		slow = 0;
 	}
 	else
 	{							/* there's a null somewhere in the tuple */
-
-		slow = 0;
 		/* ----------------
 		 *		check to see if desired att is null
 		 * ----------------
 		 */
-
-		attnum--;
-
 		bp = (char *) tup + sizeof(*tup);		/* "knows" t_bits are
 												 * here! */
 #ifdef IN_MACRO
@@ -254,34 +242,28 @@ nocache_index_getattr(IndexTuple tup,
 #endif
 
 		/* ----------------
-		 *		Now check to see if any preceeding bits are null...
+		 *		Now check to see if any preceding bits are null...
 		 * ----------------
 		 */
 		{
-			int			i = 0;	/* current offset in bp */
-			int			mask;	/* bit in byte we're looking at */
-			char		n;		/* current byte in bp */
-			int			byte,
-						finalbit;
+			int			byte = attnum >> 3;
+			int			finalbit = attnum & 0x07;
 
-			byte = attnum >> 3;
-			finalbit = attnum & 0x07;
-
-			for (; i <= byte && !slow; i++)
+			/* check for nulls "before" final bit of last byte */
+			if ((~bp[byte]) & ((1 << finalbit) - 1))
+				slow = true;
+			else
 			{
-				n = bp[i];
-				if (i < byte)
-				{
-					/* check for nulls in any "earlier" bytes */
-					if ((~n) != 0)
-						slow = 1;
-				}
-				else
+				/* check for nulls in any "earlier" bytes */
+				int			i;
+
+				for (i = 0; i < byte; i++)
 				{
-					/* check for nulls "before" final bit of last byte */
-					mask = (1 << finalbit) - 1;
-					if ((~n) & mask)
-						slow = 1;
+					if (bp[i] != 0xFF)
+					{
+						slow = true;
+						break;
+					}
 				}
 			}
 		}
@@ -298,24 +280,25 @@ nocache_index_getattr(IndexTuple tup,
 			return (Datum) fetchatt(&(att[attnum]),
 									tp + att[attnum]->attcacheoff);
 		}
-		else if (attnum == 0)
-			return (Datum) fetchatt(&(att[0]), (char *) tp);
 		else if (!IndexTupleAllFixed(tup))
 		{
-			int			j = 0;
+			int			j;
 
-			for (j = 0; j < attnum && !slow; j++)
-				if (att[j]->attlen < 1 && !VARLENA_FIXED_SIZE(att[j]))
-					slow = 1;
+			for (j = 0; j < attnum; j++)
+				if (att[j]->attlen <= 0)
+				{
+					slow = true;
+					break;
+				}
 		}
 	}
 
 	/*
-	 * if slow is zero, and we got here, we know that we have a tuple with
-	 * no nulls.  We also know that we have to initialize the remainder of
-	 * the attribute cached offset values.
+	 * If slow is false, and we got here, we know that we have a tuple with
+	 * no nulls or varlenas before the target attribute. If possible, we
+	 * also want to initialize the remainder of the attribute cached
+	 * offset values.
 	 */
-
 	if (!slow)
 	{
 		int			j = 1;
@@ -327,15 +310,12 @@ nocache_index_getattr(IndexTuple tup,
 
 		att[0]->attcacheoff = 0;
 
-		while (att[j]->attcacheoff != -1)
+		while (j < attnum && att[j]->attcacheoff > 0)
 			j++;
 
-		if (!VARLENA_FIXED_SIZE(att[j - 1]))
-			off = att[j - 1]->attcacheoff + att[j - 1]->attlen;
-		else
-			off = att[j - 1]->attcacheoff + att[j - 1]->atttypmod;
+		off = att[j - 1]->attcacheoff + att[j - 1]->attlen;
 
-		for (; j < attnum + 1; j++)
+		for (; j <= attnum; j++)
 		{
 
 			/*
@@ -347,14 +327,7 @@ nocache_index_getattr(IndexTuple tup,
 
 			att[j]->attcacheoff = off;
 
-			/* The only varlena/-1 length value to get here is this */
-			if (!VARLENA_FIXED_SIZE(att[j]))
-				off += att[j]->attlen;
-			else
-			{
-				Assert(att[j]->atttypmod == VARSIZE(tp + off));
-				off += att[j]->atttypmod;
-			}
+			off += att[j]->attlen;
 		}
 
 		return (Datum) fetchatt(&(att[attnum]), tp + att[attnum]->attcacheoff);
@@ -391,27 +364,14 @@ nocache_index_getattr(IndexTuple tup,
 					att[i]->attcacheoff = off;
 			}
 
-			switch (att[i]->attlen)
+			if (att[i]->attlen == -1)
 			{
-				case sizeof(char):
-					off++;
-					break;
-				case sizeof(short):
-					off += sizeof(short);
-					break;
-				case sizeof(int32):
-					off += sizeof(int32);
-					break;
-				case -1:
-					Assert(!VARLENA_FIXED_SIZE(att[i]) ||
-						   att[i]->atttypmod == VARSIZE(tp + off));
-					off += VARSIZE(tp + off);
-					if (!VARLENA_FIXED_SIZE(att[i]))
-						usecache = false;
-					break;
-				default:
-					off += att[i]->attlen;
-					break;
+				off += VARSIZE(tp + off);
+				usecache = false;
+			}
+			else
+			{
+				off += att[i]->attlen;
 			}
 		}
 
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 7b60a897aa468e5de8cd5dcb40e228acf0b43fb0..f345df7cc110e34d03c78fdac450c7cf2e927f58 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.97 2000/11/30 08:46:20 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.98 2000/11/30 18:38:45 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -535,18 +535,11 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
 			 ((isnull) ? (*(isnull) = false) : (dummyret) NULL),
 			 HeapTupleNoNulls(tup) ?
 			 (
-			  ((tupleDesc)->attrs[(attnum) - 1]->attcacheoff != -1 ||
-			   (attnum) == 1) ?
+			  (tupleDesc)->attrs[(attnum) - 1]->attcacheoff >= 0 ?
 			  (
 			   (Datum) fetchatt(&((tupleDesc)->attrs[(attnum) - 1]),
 						 (char *) (tup)->t_data + (tup)->t_data->t_hoff +
-								(
-								 ((attnum) != 1) ?
-							(tupleDesc)->attrs[(attnum) - 1]->attcacheoff
-								 :
-								 0
-								 )
-								)
+							(tupleDesc)->attrs[(attnum) - 1]->attcacheoff)
 			   )
 			  :
 			  nocachegetattr((tup), (attnum), (tupleDesc), (isnull))
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 2f4697a39b84f5083d315b2693840d4b2037ec8f..e4551d4c604b2dd48d4b6a1f06ece095752d44c7 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.117 2000/11/30 08:46:24 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.118 2000/11/30 18:38:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -630,6 +630,32 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
 	heap_endscan(pg_attribute_scan);
 	heap_close(pg_attribute_desc, AccessShareLock);
 
+	/* ----------------
+	 *	The attcacheoff values we read from pg_attribute should all be -1
+	 *	("unknown").  Verify this if assert checking is on.  They will be
+	 *	computed when and if needed during tuple access.
+	 * ----------------
+	 */
+#ifdef USE_ASSERT_CHECKING
+	{
+		int		i;
+
+		for (i = 0; i < relation->rd_rel->relnatts; i++)
+		{
+			Assert(relation->rd_att->attrs[i]->attcacheoff == -1);
+		}
+	}
+#endif
+
+	/* ----------------
+	 *	However, we can easily set the attcacheoff value for the first
+	 *	attribute: it must be zero.  This eliminates the need for special
+	 *	cases for attnum=1 that used to exist in fastgetattr() and
+	 *	index_getattr().
+	 * ----------------
+	 */
+	relation->rd_att->attrs[0]->attcacheoff = 0;
+
 	SetConstrOfRelation(relation, constr, ndef, attrdef);
 }
 
@@ -715,6 +741,28 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
 
 	heap_close(attrel, AccessShareLock);
 
+	/* ----------------
+	 *	The attcacheoff values we read from pg_attribute should all be -1
+	 *	("unknown").  Verify this if assert checking is on.  They will be
+	 *	computed when and if needed during tuple access.
+	 * ----------------
+	 */
+#ifdef USE_ASSERT_CHECKING
+	for (i = 0; i < relation->rd_rel->relnatts; i++)
+	{
+		Assert(relation->rd_att->attrs[i]->attcacheoff == -1);
+	}
+#endif
+
+	/* ----------------
+	 *	However, we can easily set the attcacheoff value for the first
+	 *	attribute: it must be zero.  This eliminates the need for special
+	 *	cases for attnum=1 that used to exist in fastgetattr() and
+	 *	index_getattr().
+	 * ----------------
+	 */
+	relation->rd_att->attrs[0]->attcacheoff = 0;
+
 	SetConstrOfRelation(relation, constr, ndef, attrdef);
 }
 
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index de4f29348535d14d481bf15d720bbd936aa2037c..db40344dc4668cce1817f25c5c03d3b55a4a9c93 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: heapam.h,v 1.58 2000/11/21 21:16:05 petere Exp $
+ * $Id: heapam.h,v 1.59 2000/11/30 18:38:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -107,18 +107,11 @@ extern Datum nocachegetattr(HeapTuple tup, int attnum,
 	((isnull) ? (*(isnull) = false) : (dummyret)NULL),				\
 	HeapTupleNoNulls(tup) ?											\
 	(																\
-		((tupleDesc)->attrs[(attnum)-1]->attcacheoff != -1 ||		\
-		 (attnum) == 1) ?											\
+		(tupleDesc)->attrs[(attnum)-1]->attcacheoff >= 0 ?			\
 		(															\
-			(Datum)fetchatt(&((tupleDesc)->attrs[(attnum)-1]),		\
+			(Datum) fetchatt(&((tupleDesc)->attrs[(attnum)-1]),		\
 				(char *) (tup)->t_data + (tup)->t_data->t_hoff +	\
-				(													\
-					((attnum) != 1) ?								\
-						(tupleDesc)->attrs[(attnum)-1]->attcacheoff	\
-					:												\
-						0											\
-				)													\
-			)														\
+					(tupleDesc)->attrs[(attnum)-1]->attcacheoff)	\
 		)															\
 		:															\
 			nocachegetattr((tup), (attnum), (tupleDesc), (isnull))	\
diff --git a/src/include/access/itup.h b/src/include/access/itup.h
index a5047729616ce140246533c24cda382f0338dafe..18639eb7f209ff31ddac9562317f67e40797e2c5 100644
--- a/src/include/access/itup.h
+++ b/src/include/access/itup.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: itup.h,v 1.25 2000/07/14 22:17:53 tgl Exp $
+ * $Id: itup.h,v 1.26 2000/11/30 18:38:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -109,24 +109,17 @@ typedef RetrieveIndexResultData *RetrieveIndexResult;
 	*(isnull) = false, \
 	IndexTupleNoNulls(tup) ? \
 	( \
-		((tupleDesc)->attrs[(attnum)-1]->attcacheoff != -1 || \
-		 (attnum) == 1) ? \
+		(tupleDesc)->attrs[(attnum)-1]->attcacheoff >= 0 ? \
 		( \
-			(Datum)fetchatt(&((tupleDesc)->attrs[(attnum)-1]), \
+			(Datum) fetchatt(&((tupleDesc)->attrs[(attnum)-1]), \
 			(char *) (tup) + \
 			( \
 				IndexTupleHasMinHeader(tup) ? \
 						sizeof (*(tup)) \
 					: \
 						IndexInfoFindDataOffset((tup)->t_info) \
-				) + \
-				( \
-					((attnum) != 1) ? \
-						(tupleDesc)->attrs[(attnum)-1]->attcacheoff \
-					: \
-						0 \
-				) \
 			) \
+			+ (tupleDesc)->attrs[(attnum)-1]->attcacheoff) \
 		) \
 		: \
 			nocache_index_getattr((tup), (attnum), (tupleDesc), (isnull)) \
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 48cf26d172a27ad2b9114a586736218811ec2898..f9f7372fd7800aabfd09ce1372d0917af244d1f5 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_type.h,v 1.97 2000/08/21 04:48:52 tgl Exp $
+ * $Id: pg_type.h,v 1.98 2000/11/30 18:38:47 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -415,7 +415,6 @@ DATA(insert OID = 1700 ( numeric	   PGUID -1  -1 f b t \054 0  0 numeric_in nume
 DESCR("numeric(precision, decimal), arbitrary precision number");
 #define NUMERICOID		1700
 
-#define VARLENA_FIXED_SIZE(attr)	((attr)->atttypid == BPCHAROID && (attr)->atttypmod > 0)
 
 /*
  * prototypes for functions in pg_type.c