Remove VARLENA_FIXED_SIZE hack, which is irreversibly broken now that
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 30 Nov 2000 18:38:47 +0000 (18:38 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 30 Nov 2000 18:38:47 +0000 (18:38 +0000)
both MULTIBYTE and TOAST prevent char(n) from being truly fixed-size.
Simplify and speed up fastgetattr() and index_getattr() macros by
eliminating special cases for attnum=1.  It's just as fast to handle
the first attribute by presetting its attcacheoff to zero; so do that
instead when loading the tupledesc in relcache.c.

src/backend/access/common/heaptuple.c
src/backend/access/common/indextuple.c
src/backend/access/heap/heapam.c
src/backend/utils/cache/relcache.c
src/include/access/heapam.h
src/include/access/itup.h
src/include/catalog/pg_type.h

index 4640b2022438a19a69499319a919cc6023bc1789..e76fa5a5652873125de876b9a4cc03da080ed6a3 100644 (file)
@@ -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;
        }
 
index 15ed18245607afd8380c783e817e2eba562d69d3..9f2bfb02c530a9545a4ff33641c25895801d85f8 100644 (file)
@@ -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;
            }
        }
 
index 7b60a897aa468e5de8cd5dcb40e228acf0b43fb0..f345df7cc110e34d03c78fdac450c7cf2e927f58 100644 (file)
@@ -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))
index 2f4697a39b84f5083d315b2693840d4b2037ec8f..e4551d4c604b2dd48d4b6a1f06ece095752d44c7 100644 (file)
@@ -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);
 }
 
index de4f29348535d14d481bf15d720bbd936aa2037c..db40344dc4668cce1817f25c5c03d3b55a4a9c93 100644 (file)
@@ -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))  \
index a5047729616ce140246533c24cda382f0338dafe..18639eb7f209ff31ddac9562317f67e40797e2c5 100644 (file)
@@ -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)) \
index 48cf26d172a27ad2b9114a586736218811ec2898..f9f7372fd7800aabfd09ce1372d0917af244d1f5 100644 (file)
@@ -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