Optional Oid - Mailing list pgsql-patches

From Manfred Koizar
Subject Optional Oid
Date
Msg-id t37aju841ba4qc6jaem23vhfhb8k5cmttg@4ax.com
Whole thread Raw
Responses Re: Optional Oid
Re: Optional Oid
List pgsql-patches
Here is a preview of a patch which shall eventually further reduce
heap tuple header size by four bytes for tables created WITHOUT OIDS.

t_oid is eliminated from the start of struct HeapTupleHeader.  If an
oid is needed, it is added at the end of the struct (after the null
bitmap, if present).

Per Tom Lane's suggestion the information whether a tuple has an oid
or not is carried in the tuple descriptor.  For debugging reasons
tdhasoid is of type char, not bool.  There are predefined values for
WITHOID, WITHOUTOID and UNDEFOID.

This patch has been generated against a cvs snapshot from last week
and I don't expect it to apply cleanly to current sources.  While I
post it here for public review, I'm working on a new version against a
current snapshot.  (There's been heavy activity recently; hope to
catch up some day ...)

This is a long patch;  if it is too hard to swallow, I can provide it
in smaller pieces:

Part 1:  Accessor macros
Part 2:  tdhasoid in TupDesc
Part 3:  Regression test
Part 4:  Parameter withoid to heap_addheader
Part 5:  Eliminate t_oid from HeapTupleHeader

Part 2 is the most hairy part because of changes in the executor and
even in the parser;  the other parts are straightforward.

Up to part 4 the patched postmaster stays binary compatible to
databases created with an unpatched version.  Part 5 is small (100
lines) and finally breaks compatibility.

[Follow-up to -hackers?]

Servus
 Manfred
diff -ruN ../base/src/backend/access/common/heaptuple.c src/backend/access/common/heaptuple.c
--- ../base/src/backend/access/common/heaptuple.c    2002-06-21 02:12:13.000000000 +0200
+++ src/backend/access/common/heaptuple.c    2002-07-16 19:58:01.000000000 +0200
@@ -436,7 +436,7 @@
             result = PointerGetDatum(&(tup->t_self));
             break;
         case ObjectIdAttributeNumber:
-            result = ObjectIdGetDatum(tup->t_data->t_oid);
+            result = ObjectIdGetDatum(HeapTupleGetOid(tup));
             break;
         case MinTransactionIdAttributeNumber:
             result = TransactionIdGetDatum(HeapTupleHeaderGetXmin(tup->t_data));
@@ -581,6 +581,8 @@
         elog(ERROR, "heap_formtuple: numberOfAttributes %d exceeds limit %d",
              numberOfAttributes, MaxTupleAttributeNumber);

+    AssertTupleDescHasOidIsValid(tupleDescriptor);
+
     for (i = 0; i < numberOfAttributes; i++)
     {
         if (nulls[i] != ' ')
@@ -595,6 +597,9 @@
     if (hasnull)
         len += BITMAPLEN(numberOfAttributes);

+    if (tupleDescriptor->tdhasoid == WITHOID)
+        len += sizeof(Oid);
+
     hoff = len = MAXALIGN(len); /* align user data safely */

     len += ComputeDataSize(tupleDescriptor, value, nulls);
@@ -698,14 +703,18 @@
      * t_infomask
      */
     infomask = newTuple->t_data->t_infomask;
-    memmove((char *) &newTuple->t_data->t_oid,    /* XXX */
-            (char *) &tuple->t_data->t_oid,
-            ((char *) &tuple->t_data->t_hoff -
-             (char *) &tuple->t_data->t_oid));    /* XXX */
+    /*
+     * copy t_xmin, t_cid, t_xmax, t_ctid, t_natts, t_infomask
+     */
+    memmove((char *) newTuple->t_data,    /* XXX */
+            (char *) tuple->t_data,
+            offsetof(HeapTupleHeaderData, t_hoff));    /* XXX */
     newTuple->t_data->t_infomask = infomask;
     newTuple->t_data->t_natts = numberOfAttributes;
     newTuple->t_self = tuple->t_self;
     newTuple->t_tableOid = tuple->t_tableOid;
+    if (relation->rd_rel->relhasoids)
+        HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));

     return newTuple;
 }
@@ -738,6 +747,7 @@
  */
 HeapTuple
 heap_addheader(int natts,        /* max domain index */
+               bool withoid,    /* reserve space for oid */
                Size structlen,    /* its length */
                void *structure) /* pointer to the struct */
 {
@@ -749,7 +759,10 @@
     AssertArg(natts > 0);

     /* header needs no null bitmap */
-    hoff = MAXALIGN(offsetof(HeapTupleHeaderData, t_bits));
+    hoff = offsetof(HeapTupleHeaderData, t_bits);
+    if (withoid)
+        hoff += sizeof(Oid);
+    hoff = MAXALIGN(hoff);
     len = hoff + structlen;

     tuple = (HeapTuple) palloc(HEAPTUPLESIZE + len);
diff -ruN ../base/src/backend/access/common/tupdesc.c src/backend/access/common/tupdesc.c
--- ../base/src/backend/access/common/tupdesc.c    2002-06-21 02:12:13.000000000 +0200
+++ src/backend/access/common/tupdesc.c    2002-07-15 21:29:30.000000000 +0200
@@ -36,7 +36,7 @@
  * ----------------------------------------------------------------
  */
 TupleDesc
-CreateTemplateTupleDesc(int natts)
+CreateTemplateTupleDesc(int natts, hasoid_t withoid)
 {
     uint32        size;
     TupleDesc    desc;
@@ -58,6 +58,7 @@
     MemSet(desc->attrs, 0, size);

     desc->natts = natts;
+    desc->tdhasoid = withoid;

     return desc;
 }
@@ -82,6 +83,7 @@
     desc->attrs = attrs;
     desc->natts = natts;
     desc->constr = NULL;
+    desc->tdhasoid = UNDEFOID;

     return desc;
 }
@@ -116,6 +118,7 @@
         desc->attrs[i]->atthasdef = false;
     }
     desc->constr = NULL;
+    desc->tdhasoid = tupdesc->tdhasoid;

     return desc;
 }
@@ -182,6 +185,7 @@
     else
         desc->constr = NULL;

+    desc->tdhasoid = tupdesc->tdhasoid;
     return desc;
 }

@@ -235,6 +239,8 @@

     if (tupdesc1->natts != tupdesc2->natts)
         return false;
+    if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
+        return false;
     for (i = 0; i < tupdesc1->natts; i++)
     {
         Form_pg_attribute attr1 = tupdesc1->attrs[i];
@@ -392,7 +398,7 @@
      */
     typeForm = (Form_pg_type) GETSTRUCT(tuple);

-    att->atttypid = tuple->t_data->t_oid;
+    att->atttypid = HeapTupleGetOid(tuple);

     /*
      * There are a couple of cases where we must override the information
@@ -479,7 +485,7 @@
      * allocate a new tuple descriptor
      */
     natts = length(schema);
-    desc = CreateTemplateTupleDesc(natts);
+    desc = CreateTemplateTupleDesc(natts, UNDEFOID);
     constr->has_not_null = false;

     attnum = 0;
@@ -646,7 +652,7 @@
         /* OK, get the column alias */
         attname = strVal(lfirst(colaliases));

-        tupdesc = CreateTemplateTupleDesc(1);
+        tupdesc = CreateTemplateTupleDesc(1, WITHOUTOID);
         TupleDescInitEntry(tupdesc,
                            (AttrNumber) 1,
                            attname,
diff -ruN ../base/src/backend/access/heap/heapam.c src/backend/access/heap/heapam.c
--- ../base/src/backend/access/heap/heapam.c    2002-07-03 12:27:39.000000000 +0200
+++ src/backend/access/heap/heapam.c    2002-07-15 22:22:28.000000000 +0200
@@ -1116,10 +1116,11 @@
          * to support a persistent object store (objects need to contain
          * pointers to one another).
          */
-        if (!OidIsValid(tup->t_data->t_oid))
-            tup->t_data->t_oid = newoid();
+        AssertTupleDescHasOid(relation->rd_att);
+        if (!OidIsValid(HeapTupleGetOid(tup)))
+            HeapTupleSetOid(tup, newoid());
         else
-            CheckMaxObjectId(tup->t_data->t_oid);
+            CheckMaxObjectId(HeapTupleGetOid(tup));
     }

     HeapTupleHeaderSetXmin(tup->t_data, GetCurrentTransactionId());
@@ -1166,7 +1167,13 @@
         rdata[0].len = SizeOfHeapInsert;
         rdata[0].next = &(rdata[1]);

-        xlhdr.t_oid = tup->t_data->t_oid;
+        if (relation->rd_rel->relhasoids)
+        {
+            AssertTupleDescHasOid(relation->rd_att);
+            xlhdr.t_oid = HeapTupleGetOid(tup);
+        }
+        else
+            xlhdr.t_oid = InvalidOid;
         xlhdr.t_natts = tup->t_data->t_natts;
         xlhdr.t_hoff = tup->t_data->t_hoff;
         xlhdr.mask = tup->t_data->t_infomask;
@@ -1176,6 +1183,7 @@
         rdata[1].next = &(rdata[2]);

         rdata[2].buffer = buffer;
+        /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
         rdata[2].data = (char *) tup->t_data + offsetof(HeapTupleHeaderData, t_bits);
         rdata[2].len = tup->t_len - offsetof(HeapTupleHeaderData, t_bits);
         rdata[2].next = NULL;
@@ -1206,7 +1214,11 @@
      */
     CacheInvalidateHeapTuple(relation, tup);

-    return tup->t_data->t_oid;
+    if (!relation->rd_rel->relhasoids)
+        return InvalidOid;
+
+    AssertTupleDescHasOid(relation->rd_att);
+    return HeapTupleGetOid(tup);
 }

 /*
@@ -1499,7 +1511,11 @@
     }

     /* Fill in OID and transaction status data for newtup */
-    newtup->t_data->t_oid = oldtup.t_data->t_oid;
+    if (relation->rd_rel->relhasoids)
+    {
+        AssertTupleDescHasOid(relation->rd_att);
+        HeapTupleSetOid(newtup, HeapTupleGetOid(&oldtup));
+    }
     newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
     newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED);
     HeapTupleHeaderSetXmin(newtup->t_data, GetCurrentTransactionId());
@@ -1972,24 +1988,28 @@
     rdata[1].len = 0;
     rdata[1].next = &(rdata[2]);

-    xlhdr.hdr.t_oid = newtup->t_data->t_oid;
+    if (reln->rd_rel->relhasoids)
+    {
+        AssertTupleDescHasOid(reln->rd_att);
+        xlhdr.hdr.t_oid = HeapTupleGetOid(newtup);
+    }
+    else
+        xlhdr.hdr.t_oid = InvalidOid;
     xlhdr.hdr.t_natts = newtup->t_data->t_natts;
     xlhdr.hdr.t_hoff = newtup->t_data->t_hoff;
     xlhdr.hdr.mask = newtup->t_data->t_infomask;
     if (move)                    /* remember xmin & xmax */
     {
-        TransactionId xmax;
-        TransactionId xmin;
+        TransactionId xid[2];   /* xmax, xmin */

-        if (newtup->t_data->t_infomask & HEAP_XMAX_INVALID ||
-            newtup->t_data->t_infomask & HEAP_MARKED_FOR_UPDATE)
-            xmax = InvalidTransactionId;
+        if (newtup->t_data->t_infomask & (HEAP_XMAX_INVALID |
+                                          HEAP_MARKED_FOR_UPDATE))
+            xid[0] = InvalidTransactionId;
         else
-            xmax = HeapTupleHeaderGetXmax(newtup->t_data);
-        xmin = HeapTupleHeaderGetXmin(newtup->t_data);
-        memcpy((char *) &xlhdr + hsize, &xmax, sizeof(TransactionId));
-        memcpy((char *) &xlhdr + hsize + sizeof(TransactionId),
-               &xmin, sizeof(TransactionId));
+            xid[0] = HeapTupleHeaderGetXmax(newtup->t_data);
+        xid[1] = HeapTupleHeaderGetXmin(newtup->t_data);
+        memcpy((char *) &xlhdr + hsize,
+               (char *) xid,            2 * sizeof(TransactionId));
         hsize += 2 * sizeof(TransactionId);
     }
     rdata[2].buffer = newbuf;
@@ -1998,6 +2018,7 @@
     rdata[2].next = &(rdata[3]);

     rdata[3].buffer = newbuf;
+    /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
     rdata[3].data = (char *) newtup->t_data + offsetof(HeapTupleHeaderData, t_bits);
     rdata[3].len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits);
     rdata[3].next = NULL;
@@ -2193,12 +2214,13 @@
         memcpy((char *) &xlhdr,
                (char *) xlrec + SizeOfHeapInsert,
                SizeOfHeapHeader);
+        htup = &tbuf.hdr;
+        MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData));
+        /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */
         memcpy((char *) &tbuf + offsetof(HeapTupleHeaderData, t_bits),
                (char *) xlrec + SizeOfHeapInsert + SizeOfHeapHeader,
                newlen);
         newlen += offsetof(HeapTupleHeaderData, t_bits);
-        htup = &tbuf.hdr;
-        htup->t_oid = xlhdr.t_oid;
         htup->t_natts = xlhdr.t_natts;
         htup->t_hoff = xlhdr.t_hoff;
         htup->t_infomask = HEAP_XMAX_INVALID | xlhdr.mask;
@@ -2206,6 +2228,11 @@
         HeapTupleHeaderSetCmin(htup, FirstCommandId);
         HeapTupleHeaderSetXmaxInvalid(htup);
         HeapTupleHeaderSetCmax(htup, FirstCommandId);
+        if (reln->rd_rel->relhasoids)
+        {
+            AssertTupleDescHasOid(reln->rd_att);
+            HeapTupleHeaderSetOid(htup, xlhdr.t_oid);
+        }

         offnum = PageAddItem(page, (Item) htup, newlen, offnum,
                              LP_USED | OverwritePageMode);
@@ -2362,28 +2389,33 @@
         memcpy((char *) &xlhdr,
                (char *) xlrec + SizeOfHeapUpdate,
                SizeOfHeapHeader);
+        htup = &tbuf.hdr;
+        MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData));
+        /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */
         memcpy((char *) &tbuf + offsetof(HeapTupleHeaderData, t_bits),
                (char *) xlrec + hsize,
                newlen);
         newlen += offsetof(HeapTupleHeaderData, t_bits);
-        htup = &tbuf.hdr;
-        htup->t_oid = xlhdr.t_oid;
         htup->t_natts = xlhdr.t_natts;
         htup->t_hoff = xlhdr.t_hoff;
+        if (reln->rd_rel->relhasoids)
+        {
+            AssertTupleDescHasOid(reln->rd_att);
+            HeapTupleHeaderSetOid(htup, xlhdr.t_oid);
+        }
         if (move)
         {
-            TransactionId xmax;
-            TransactionId xmin;
+            TransactionId xid[2];   /* xmax, xmin */

             hsize = SizeOfHeapUpdate + SizeOfHeapHeader;
-            memcpy(&xmax, (char *) xlrec + hsize, sizeof(TransactionId));
-            memcpy(&xmin, (char *) xlrec + hsize + sizeof(TransactionId), sizeof(TransactionId));
+            memcpy((char *) xid,
+                   (char *) xlrec + hsize, 2 * sizeof(TransactionId));
             htup->t_infomask = xlhdr.mask;
             htup->t_infomask &= ~(HEAP_XMIN_COMMITTED |
                                   HEAP_XMIN_INVALID | HEAP_MOVED_OFF);
             htup->t_infomask |= HEAP_MOVED_IN;
-            HeapTupleHeaderSetXmin(htup, xmin);
-            HeapTupleHeaderSetXmax(htup, xmax);
+            HeapTupleHeaderSetXmin(htup, xid[1]);
+            HeapTupleHeaderSetXmax(htup, xid[0]);
             HeapTupleHeaderSetXvac(htup, record->xl_xid);
         }
         else
diff -ruN ../base/src/backend/access/heap/tuptoaster.c src/backend/access/heap/tuptoaster.c
--- ../base/src/backend/access/heap/tuptoaster.c    2002-05-27 23:52:41.000000000 +0200
+++ src/backend/access/heap/tuptoaster.c    2002-07-16 19:58:01.000000000 +0200
@@ -726,6 +726,8 @@
         new_len = offsetof(HeapTupleHeaderData, t_bits);
         if (has_nulls)
             new_len += BITMAPLEN(numAttrs);
+        if (rel->rd_rel->relhasoids)
+            new_len += sizeof(Oid);
         new_len = MAXALIGN(new_len);
         Assert(new_len == olddata->t_hoff);
         new_len += ComputeDataSize(tupleDesc, toast_values, toast_nulls);
diff -ruN ../base/src/backend/bootstrap/bootparse.y src/backend/bootstrap/bootparse.y
--- ../base/src/backend/bootstrap/bootparse.y    2002-06-21 02:12:14.000000000 +0200
+++ src/backend/bootstrap/bootparse.y    2002-07-15 22:11:00.000000000 +0200
@@ -179,13 +179,13 @@
                         }

                         tupdesc = CreateTupleDesc(numattr, attrtypes);
+                        tupdesc->tdhasoid = BoolToHasOid(! ($4));
                         boot_reldesc = heap_create(LexIDStr($5),
                                                    PG_CATALOG_NAMESPACE,
                                                    tupdesc,
                                                    $3,
                                                    true,
                                                    true);
-                        boot_reldesc->rd_rel->relhasoids = ! ($4);
                         elog(DEBUG3, "bootstrap relation created");
                     }
                     else
diff -ruN ../base/src/backend/bootstrap/bootstrap.c src/backend/bootstrap/bootstrap.c
--- ../base/src/backend/bootstrap/bootstrap.c    2002-06-21 02:12:14.000000000 +0200
+++ src/backend/bootstrap/bootstrap.c    2002-07-15 21:31:23.000000000 +0200
@@ -495,7 +495,8 @@
         app = Typ;
         while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
         {
-            (*app)->am_oid = tup->t_data->t_oid;
+            AssertTupleDescHasOid(rel->rd_att);
+            (*app)->am_oid = HeapTupleGetOid(tup);
             memcpy((char *) &(*app)->am_typ,
                    (char *) GETSTRUCT(tup),
                    sizeof((*app)->am_typ));
@@ -675,11 +676,15 @@
     elog(DEBUG3, "inserting row oid %u, %d columns", objectid, numattr);

     tupDesc = CreateTupleDesc(numattr, attrtypes);
+    tupDesc->tdhasoid = BoolToHasOid(RelationGetForm(boot_reldesc)->relhasoids);
     tuple = heap_formtuple(tupDesc, values, Blanks);
-    pfree(tupDesc);                /* just free's tupDesc, not the attrtypes */

     if (objectid != (Oid) 0)
-        tuple->t_data->t_oid = objectid;
+    {
+        AssertTupleDescHasOid(tupDesc);
+        HeapTupleSetOid(tuple, objectid);
+    }
+    pfree(tupDesc);                /* just free's tupDesc, not the attrtypes */
     simple_heap_insert(boot_reldesc, tuple);
     heap_freetuple(tuple);
     elog(DEBUG3, "row inserted");
@@ -871,7 +876,8 @@
         app = Typ;
         while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
         {
-            (*app)->am_oid = tup->t_data->t_oid;
+            AssertTupleDescHasOid(rel->rd_att);
+            (*app)->am_oid = HeapTupleGetOid(tup);
             memmove((char *) &(*app++)->am_typ,
                     (char *) GETSTRUCT(tup),
                     sizeof((*app)->am_typ));
diff -ruN ../base/src/backend/catalog/aclchk.c src/backend/catalog/aclchk.c
--- ../base/src/backend/catalog/aclchk.c    2002-06-21 02:12:14.000000000 +0200
+++ src/backend/catalog/aclchk.c    2002-07-15 20:26:36.000000000 +0200
@@ -591,7 +591,8 @@
             elog(ERROR, "namespace \"%s\" not found", nspname);
         pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);

-        if (!pg_namespace_ownercheck(tuple->t_data->t_oid, GetUserId()))
+        AssertTupleDescHasOid(relation->rd_att);
+        if (!pg_namespace_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
             aclcheck_error(ACLCHECK_NOT_OWNER, nspname);

         /*
diff -ruN ../base/src/backend/catalog/heap.c src/backend/catalog/heap.c
--- ../base/src/backend/catalog/heap.c    2002-06-21 02:12:14.000000000 +0200
+++ src/backend/catalog/heap.c    2002-07-16 19:35:34.000000000 +0200
@@ -66,7 +66,7 @@
 static void AddNewRelationTuple(Relation pg_class_desc,
                     Relation new_rel_desc,
                     Oid new_rel_oid, Oid new_type_oid,
-                    char relkind, bool relhasoids);
+                    char relkind);
 static void DeleteAttributeTuples(Relation rel);
 static void DeleteRelationTuple(Relation rel);
 static void DeleteTypeTuple(Relation rel);
@@ -448,6 +448,7 @@
         (*dpp)->attcacheoff = -1;

         tup = heap_addheader(Natts_pg_attribute,
+                             false,
                              ATTRIBUTE_TUPLE_SIZE,
                              (void *) *dpp);

@@ -473,6 +474,7 @@
                 Form_pg_attribute attStruct;

                 tup = heap_addheader(Natts_pg_attribute,
+                                     false,
                                      ATTRIBUTE_TUPLE_SIZE,
                                      (void *) *dpp);

@@ -519,8 +521,7 @@
                     Relation new_rel_desc,
                     Oid new_rel_oid,
                     Oid new_type_oid,
-                    char relkind,
-                    bool relhasoids)
+                    char relkind)
 {
     Form_pg_class new_rel_reltup;
     HeapTuple    tup;
@@ -571,7 +572,6 @@
     new_rel_reltup->relowner = GetUserId();
     new_rel_reltup->reltype = new_type_oid;
     new_rel_reltup->relkind = relkind;
-    new_rel_reltup->relhasoids = relhasoids;

     /* ----------------
      *    now form a tuple to add to pg_class
@@ -579,11 +579,13 @@
      * ----------------
      */
     tup = heap_addheader(Natts_pg_class_fixed,
+                         true,
                          CLASS_TUPLE_SIZE,
                          (void *) new_rel_reltup);

     /* force tuple to have the desired OID */
-    tup->t_data->t_oid = new_rel_oid;
+    AssertTupleDescHasOid(pg_class_desc->rd_att);
+    HeapTupleSetOid(tup, new_rel_oid);

     /*
      * finally insert the new tuple and free it.
@@ -683,6 +685,8 @@
     if (get_relname_relid(relname, relnamespace))
         elog(ERROR, "Relation '%s' already exists", relname);

+    tupdesc->tdhasoid = BoolToHasOid(relhasoids);
+
     /*
      * Tell heap_create not to create a physical file; we'll do that below
      * after all our catalog updates are done.    (This isn't really
@@ -715,8 +719,7 @@
                         new_rel_desc,
                         new_rel_oid,
                         new_type_oid,
-                        relkind,
-                        relhasoids);
+                        relkind);

     /*
      * since defining a relation also defines a complex type, we add a new
@@ -1109,7 +1112,8 @@
      * the type of the relation we are deleteing then we have to disallow
      * the deletion.  should talk to stonebraker about this.  -cim 6/19/90
      */
-    typoid = tup->t_data->t_oid;
+    AssertTupleDescHasOid(pg_type_desc->rd_att);
+    typoid = HeapTupleGetOid(tup);

     pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);

diff -ruN ../base/src/backend/catalog/index.c src/backend/catalog/index.c
--- ../base/src/backend/catalog/index.c    2002-06-21 02:12:14.000000000 +0200
+++ src/backend/catalog/index.c    2002-07-16 19:35:34.000000000 +0200
@@ -110,7 +110,7 @@
     /*
      * Allocate and zero a tuple descriptor for a one-column tuple.
      */
-    funcTupDesc = CreateTemplateTupleDesc(1);
+    funcTupDesc = CreateTemplateTupleDesc(1, UNDEFOID);
     funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
     MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);

@@ -198,7 +198,7 @@
      * allocate the new tuple descriptor
      */

-    indexTupDesc = CreateTemplateTupleDesc(numatts);
+    indexTupDesc = CreateTemplateTupleDesc(numatts, WITHOUTOID);

     /* ----------------
      *      for each attribute we are indexing, obtain its attribute
@@ -319,6 +319,7 @@

     /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
     tuple = heap_addheader(Natts_pg_class_fixed,
+                           true,
                            CLASS_TUPLE_SIZE,
                            (void *) indexRelation->rd_rel);

@@ -326,7 +327,8 @@
      * the new tuple must have the oid already chosen for the index.
      * sure would be embarrassing to do this sort of thing in polite company.
      */
-    tuple->t_data->t_oid = RelationGetRelid(indexRelation);
+    AssertTupleDescHasOid(pg_class->rd_att);
+    HeapTupleSetOid(tuple, RelationGetRelid(indexRelation));
     simple_heap_insert(pg_class, tuple);

     /*
@@ -405,6 +407,7 @@
         Assert(indexTupDesc->attrs[i]->attcacheoff == -1);

         new_tuple = heap_addheader(Natts_pg_attribute,
+                                   false,
                                    ATTRIBUTE_TUPLE_SIZE,
                                    (void *) indexTupDesc->attrs[i]);

@@ -494,6 +497,7 @@
      * form a tuple to insert into pg_index
      */
     tuple = heap_addheader(Natts_pg_index,
+                           false,
                            itupLen,
                            (void *) indexForm);

@@ -596,6 +600,7 @@
                                             indexInfo->ii_KeyAttrNumbers,
                                                 classObjectId);

+    indexTupDesc->tdhasoid = WITHOUTOID;
     /*
      * create the index relation (but don't create storage yet)
      */
@@ -623,7 +628,7 @@
     indexRelation->rd_rel->relowner = GetUserId();
     indexRelation->rd_rel->relam = accessMethodObjectId;
     indexRelation->rd_rel->relkind = RELKIND_INDEX;
-    indexRelation->rd_rel->relhasoids = false;
+    indexRelation->rd_rel->relhasoids = false;  /* WITHOUTOID! */

     /*
      * store index's pg_class entry
diff -ruN ../base/src/backend/catalog/namespace.c src/backend/catalog/namespace.c
--- ../base/src/backend/catalog/namespace.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/catalog/namespace.c    2002-07-15 20:19:46.000000000 +0200
@@ -584,7 +584,7 @@
                         continue; /* keep previous result */
                     /* replace previous result */
                     prevResult->pathpos = pathpos;
-                    prevResult->oid = proctup->t_data->t_oid;
+                    prevResult->oid = HeapTupleGetOid(proctup);
                     continue;    /* args are same, of course */
                 }
             }
@@ -597,7 +597,7 @@
             palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
                    + nargs * sizeof(Oid));
         newResult->pathpos = pathpos;
-        newResult->oid = proctup->t_data->t_oid;
+        newResult->oid = HeapTupleGetOid(proctup);
         newResult->nargs = nargs;
         memcpy(newResult->args, procform->proargtypes, nargs * sizeof(Oid));

@@ -831,7 +831,7 @@
                         continue; /* keep previous result */
                     /* replace previous result */
                     prevResult->pathpos = pathpos;
-                    prevResult->oid = opertup->t_data->t_oid;
+                    prevResult->oid = HeapTupleGetOid(opertup);
                     continue;    /* args are same, of course */
                 }
             }
@@ -843,7 +843,7 @@
         newResult = (FuncCandidateList)
             palloc(sizeof(struct _FuncCandidateList) + sizeof(Oid));
         newResult->pathpos = pathpos;
-        newResult->oid = opertup->t_data->t_oid;
+        newResult->oid = HeapTupleGetOid(opertup);
         newResult->nargs = 2;
         newResult->args[0] = operform->oprleft;
         newResult->args[1] = operform->oprright;
@@ -1007,7 +1007,7 @@
                 /* replace previous result */
                 prevResult->opcname_tmp = NameStr(opcform->opcname);
                 prevResult->pathpos = pathpos;
-                prevResult->oid = opctup->t_data->t_oid;
+                prevResult->oid = HeapTupleGetOid(opctup);
                 prevResult->opcintype = opcform->opcintype;
                 prevResult->opcdefault = opcform->opcdefault;
                 prevResult->opckeytype = opcform->opckeytype;
@@ -1022,7 +1022,7 @@
             palloc(sizeof(struct _OpclassCandidateList));
         newResult->opcname_tmp = NameStr(opcform->opcname);
         newResult->pathpos = pathpos;
-        newResult->oid = opctup->t_data->t_oid;
+        newResult->oid = HeapTupleGetOid(opctup);
         newResult->opcintype = opcform->opcintype;
         newResult->opcdefault = opcform->opcdefault;
         newResult->opckeytype = opcform->opckeytype;
@@ -1597,7 +1597,8 @@
             case RELKIND_RELATION:
             case RELKIND_SEQUENCE:
             case RELKIND_VIEW:
-                tempRelList = lconsi(tuple->t_data->t_oid, tempRelList);
+                AssertTupleDescHasOid(pgclass->rd_att);
+                tempRelList = lconsi(HeapTupleGetOid(tuple), tempRelList);
                 break;
             default:
                 break;
diff -ruN ../base/src/backend/catalog/pg_operator.c src/backend/catalog/pg_operator.c
--- ../base/src/backend/catalog/pg_operator.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/catalog/pg_operator.c    2002-07-15 16:52:05.000000000 +0200
@@ -141,7 +141,7 @@
     {
         RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;

-        operatorObjectId = tup->t_data->t_oid;
+        operatorObjectId = HeapTupleGetOid(tup);
         *defined = RegProcedureIsValid(oprcode);
         ReleaseSysCache(tup);
     }
diff -ruN ../base/src/backend/catalog/pg_proc.c src/backend/catalog/pg_proc.c
--- ../base/src/backend/catalog/pg_proc.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/catalog/pg_proc.c    2002-07-15 20:28:36.000000000 +0200
@@ -235,6 +235,7 @@
         /* start out with empty permissions */
         nulls[Anum_pg_proc_proacl-1] = 'n';

+        AssertTupleDescHasOid(tupDesc);
         tup = heap_formtuple(tupDesc, values, nulls);
         simple_heap_insert(rel, tup);
     }
@@ -249,7 +250,8 @@
         CatalogCloseIndices(Num_pg_proc_indices, idescs);
     }

-    retval = tup->t_data->t_oid;
+    AssertTupleDescHasOid(tupDesc);
+    retval = HeapTupleGetOid(tup);
     heap_freetuple(tup);

     heap_close(rel, RowExclusiveLock);
diff -ruN ../base/src/backend/catalog/pg_type.c src/backend/catalog/pg_type.c
--- ../base/src/backend/catalog/pg_type.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/catalog/pg_type.c    2002-07-15 20:30:03.000000000 +0200
@@ -272,7 +272,8 @@

         simple_heap_update(pg_type_desc, &tup->t_self, tup);

-        typeObjectId = tup->t_data->t_oid;
+        AssertTupleDescHasOid(pg_type_desc->rd_att);
+        typeObjectId = HeapTupleGetOid(tup);
     }
     else
     {
@@ -283,7 +284,8 @@
                              nulls);

         /* preassign tuple Oid, if one was given */
-        tup->t_data->t_oid = assignedTypeOid;
+        AssertTupleDescHasOid(tupDesc);
+        HeapTupleSetOid(tup, assignedTypeOid);

         typeObjectId = simple_heap_insert(pg_type_desc, tup);
     }
diff -ruN ../base/src/backend/commands/comment.c src/backend/commands/comment.c
--- ../base/src/backend/commands/comment.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/commands/comment.c    2002-07-15 20:33:21.000000000 +0200
@@ -424,7 +424,8 @@

     if (!HeapTupleIsValid(dbtuple))
         elog(ERROR, "database \"%s\" does not exist", database);
-    oid = dbtuple->t_data->t_oid;
+    AssertTupleDescHasOid(pg_database->rd_att);
+    oid = HeapTupleGetOid(dbtuple);

     /* Allow if the user matches the database dba or is a superuser */

@@ -470,7 +471,8 @@
         elog(ERROR, "CommentSchema: Schema \"%s\" could not be found",
              namespace);

-    oid = tp->t_data->t_oid;
+    /* no TupleDesc here to Assert(...->tdhasoid); */
+    oid = HeapTupleGetOid(tp);

     /* Check object security */
     if (!pg_namespace_ownercheck(oid, GetUserId()))
@@ -541,7 +543,8 @@
         if (HeapTupleIsValid(tuple))
         {
             reloid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class;
-            ruleoid = tuple->t_data->t_oid;
+            AssertTupleDescHasOid(RewriteRelation->rd_att);
+            ruleoid = HeapTupleGetOid(tuple);
         }
         else
         {
@@ -581,7 +584,8 @@
         if (!HeapTupleIsValid(tuple))
             elog(ERROR, "rule \"%s\" does not exist", rulename);
         Assert(reloid == ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class);
-        ruleoid = tuple->t_data->t_oid;
+        AssertTupleDescHasOid(relation->rd_att);
+        ruleoid = HeapTupleGetOid(tuple);
         ReleaseSysCache(tuple);
     }

@@ -794,7 +798,8 @@
         elog(ERROR, "trigger \"%s\" for relation \"%s\" does not exist",
              trigname, RelationGetRelationName(relation));

-    oid = triggertuple->t_data->t_oid;
+    AssertTupleDescHasOid(pg_trigger->rd_att);
+    oid = HeapTupleGetOid(triggertuple);

     systable_endscan(scan);

diff -ruN ../base/src/backend/commands/copy.c src/backend/commands/copy.c
--- ../base/src/backend/commands/copy.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/commands/copy.c    2002-07-15 20:34:46.000000000 +0200
@@ -575,9 +575,13 @@
             /* Send OID if wanted --- note fld_count doesn't include it */
             if (oids)
             {
+                Oid oid;
+
+                AssertTupleDescHasOid(tupDesc);
+                oid = HeapTupleGetOid(tuple);
                 fld_size = sizeof(Oid);
                 CopySendData(&fld_size, sizeof(int16), fp);
-                CopySendData(&tuple->t_data->t_oid, sizeof(Oid), fp);
+                CopySendData(&oid, sizeof(Oid), fp);
             }
         }
         else
@@ -585,8 +589,9 @@
             /* Text format has no per-tuple header, but send OID if wanted */
             if (oids)
             {
+                AssertTupleDescHasOid(tupDesc);
                 string = DatumGetCString(DirectFunctionCall1(oidout,
-                                ObjectIdGetDatum(tuple->t_data->t_oid)));
+                                ObjectIdGetDatum(HeapTupleGetOid(tuple))));
                 CopySendString(string, fp);
                 pfree(string);
                 need_delim = true;
@@ -977,7 +982,7 @@
         tuple = heap_formtuple(tupDesc, values, nulls);

         if (oids && file_has_oids)
-            tuple->t_data->t_oid = loaded_oid;
+            HeapTupleSetOid(tuple, loaded_oid);

         skip_tuple = false;

diff -ruN ../base/src/backend/commands/dbcommands.c src/backend/commands/dbcommands.c
--- ../base/src/backend/commands/dbcommands.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/commands/dbcommands.c    2002-07-15 20:36:01.000000000 +0200
@@ -341,7 +341,8 @@

     tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);

-    tuple->t_data->t_oid = dboid;        /* override heap_insert's OID
+    AssertTupleDescHasOid(pg_database_dsc);
+    HeapTupleSetOid(tuple, dboid);        /* override heap_insert's OID
                                          * selection */

     simple_heap_insert(pg_database_rel, tuple);
@@ -611,7 +612,10 @@

         /* oid of the database */
         if (dbIdP)
-            *dbIdP = tuple->t_data->t_oid;
+        {
+            AssertTupleDescHasOid(relation->rd_att);
+            *dbIdP = HeapTupleGetOid(tuple);
+        }
         /* sysid of the owner */
         if (ownerIdP)
             *ownerIdP = dbform->datdba;
diff -ruN ../base/src/backend/commands/explain.c src/backend/commands/explain.c
--- ../base/src/backend/commands/explain.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/commands/explain.c    2002-07-15 20:19:46.000000000 +0200
@@ -855,7 +855,7 @@
     tstate = (TextOutputState *) palloc(sizeof(TextOutputState));

     /* need a tuple descriptor representing a single TEXT column */
-    tupdesc = CreateTemplateTupleDesc(1);
+    tupdesc = CreateTemplateTupleDesc(1, WITHOUTOID);
     TupleDescInitEntry(tupdesc, (AttrNumber) 1, title,
                        TEXTOID, -1, 0, false);

diff -ruN ../base/src/backend/commands/functioncmds.c src/backend/commands/functioncmds.c
--- ../base/src/backend/commands/functioncmds.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/commands/functioncmds.c    2002-07-15 18:41:59.000000000 +0200
@@ -439,7 +439,7 @@
     if (!HeapTupleIsValid(languageTuple))
         elog(ERROR, "language \"%s\" does not exist", languageName);

-    languageOid = languageTuple->t_data->t_oid;
+    languageOid = HeapTupleGetOid(languageTuple);
     languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);

     if (languageStruct->lanpltrusted)
diff -ruN ../base/src/backend/commands/indexcmds.c src/backend/commands/indexcmds.c
--- ../base/src/backend/commands/indexcmds.c    2002-07-01 19:50:36.000000000 +0200
+++ src/backend/commands/indexcmds.c    2002-07-15 17:46:58.000000000 +0200
@@ -139,7 +139,7 @@
     if (!HeapTupleIsValid(tuple))
         elog(ERROR, "DefineIndex: access method \"%s\" not found",
              accessMethodName);
-    accessMethodId = tuple->t_data->t_oid;
+    accessMethodId = HeapTupleGetOid(tuple);
     accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);

     if (unique && !accessMethodForm->amcanunique)
@@ -494,7 +494,7 @@
      * Verify that the index operator class accepts this
      * datatype.  Note we will accept binary compatibility.
      */
-    opClassId = tuple->t_data->t_oid;
+    opClassId = HeapTupleGetOid(tuple);
     opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;

     if (!IsBinaryCompatible(attrType, opInputType))
@@ -754,7 +754,7 @@
                 relids = repalloc(relids, sizeof(Oid) * relalc);
             }
             MemoryContextSwitchTo(old);
-            relids[relcnt] = tuple->t_data->t_oid;
+            relids[relcnt] = HeapTupleGetOid(tuple);
             relcnt++;
         }
     }
diff -ruN ../base/src/backend/commands/tablecmds.c src/backend/commands/tablecmds.c
--- ../base/src/backend/commands/tablecmds.c    2002-07-09 14:00:55.000000000 +0200
+++ src/backend/commands/tablecmds.c    2002-07-16 19:35:34.000000000 +0200
@@ -141,6 +141,7 @@
      * have to copy inherited constraints here.)
      */
     descriptor = BuildDescForRelation(schema);
+    descriptor->tdhasoid = BoolToHasOid(stmt->hasoids || parentHasOids);

     if (old_constraints != NIL)
     {
@@ -1597,6 +1598,7 @@
     tform = (Form_pg_type) GETSTRUCT(typeTuple);

     attributeTuple = heap_addheader(Natts_pg_attribute,
+                                    false,
                                     ATTRIBUTE_TUPLE_SIZE,
                                     (void *) &attributeD);

@@ -1604,7 +1606,7 @@

     attribute->attrelid = myrelid;
     namestrcpy(&(attribute->attname), colDef->colname);
-    attribute->atttypid = typeTuple->t_data->t_oid;
+    attribute->atttypid = HeapTupleGetOid(typeTuple);
     attribute->attstattarget = DEFAULT_ATTSTATTARGET;
     attribute->attlen = tform->typlen;
     attribute->attcacheoff = -1;
@@ -1621,6 +1623,7 @@

     ReleaseSysCache(typeTuple);

+    AssertTupleDescHasNoOid(attrdesc->rd_att);
     simple_heap_insert(attrdesc, attributeTuple);

     /* Update indexes on pg_attribute */
@@ -1641,6 +1644,7 @@
     newreltup = heap_copytuple(reltup);

     ((Form_pg_class) GETSTRUCT(newreltup))->relnatts = maxatts;
+    AssertTupleDescHasOid(pgclass->rd_att);
     simple_heap_update(pgclass, &newreltup->t_self, newreltup);

     /* keep catalog indices current */
@@ -2892,7 +2896,7 @@
     sprintf(toast_idxname, "pg_toast_%u_index", relOid);

     /* this is pretty painful...  need a tuple descriptor */
-    tupdesc = CreateTemplateTupleDesc(3);
+    tupdesc = CreateTemplateTupleDesc(3, WITHOUTOID);
     TupleDescInitEntry(tupdesc, (AttrNumber) 1,
                        "chunk_id",
                        OIDOID,
diff -ruN ../base/src/backend/commands/trigger.c src/backend/commands/trigger.c
--- ../base/src/backend/commands/trigger.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/commands/trigger.c    2002-07-15 22:22:28.000000000 +0200
@@ -364,7 +364,8 @@
         if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
         {
             /* Delete any comments associated with this trigger */
-            DeleteComments(tuple->t_data->t_oid, RelationGetRelid(tgrel));
+            AssertTupleDescHasOid(tgrel->rd_att);
+            DeleteComments(HeapTupleGetOid(tuple), RelationGetRelid(tgrel));

             simple_heap_delete(tgrel, &tuple->t_self);
             found++;
@@ -430,7 +431,8 @@
     while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
     {
         /* Delete any comments associated with this trigger */
-        DeleteComments(tup->t_data->t_oid, RelationGetRelid(tgrel));
+        AssertTupleDescHasOid(tgrel->rd_att);
+        DeleteComments(HeapTupleGetOid(tup), RelationGetRelid(tgrel));

         simple_heap_delete(tgrel, &tup->t_self);

@@ -667,7 +669,8 @@
                  RelationGetRelationName(relation));
         build = &(triggers[found]);

-        build->tgoid = htup->t_data->t_oid;
+        AssertTupleDescHasOid(tgrel->rd_att);
+        build->tgoid = HeapTupleGetOid(htup);
         build->tgname = MemoryContextStrdup(CacheMemoryContext,
                              DatumGetCString(DirectFunctionCall1(nameout,
                                     NameGetDatum(&pg_trigger->tgname))));
@@ -1928,7 +1931,8 @@
                 elog(ERROR, "Constraint '%s' is not deferrable",
                      cname);

-            constr_oid = htup->t_data->t_oid;
+            AssertTupleDescHasOid(tgrel->rd_att);
+            constr_oid = HeapTupleGetOid(htup);
             loid = lappendi(loid, constr_oid);
             found = true;
         }
diff -ruN ../base/src/backend/commands/typecmds.c src/backend/commands/typecmds.c
--- ../base/src/backend/commands/typecmds.c    2002-07-01 19:50:36.000000000 +0200
+++ src/backend/commands/typecmds.c    2002-07-15 16:52:05.000000000 +0200
@@ -474,7 +474,7 @@
                  * Note: Name is strictly for error message
                  */
                 expr = cookDefault(pstate, colDef->raw_expr,
-                                   typeTup->t_data->t_oid,
+                                   HeapTupleGetOid(typeTup),
                                    stmt->typename->typmod,
                                    domainName);
                 /*
@@ -551,7 +551,7 @@
                receiveProcedure,    /* receive procedure */
                sendProcedure,        /* send procedure */
                basetypelem,            /* element type ID */
-               typeTup->t_data->t_oid,    /* base type ID */
+               HeapTupleGetOid(typeTup),    /* base type ID */
                defaultValue,        /* default type value (text) */
                defaultValueBin,        /* default type value (binary) */
                byValue,                /* passed by value */
diff -ruN ../base/src/backend/commands/vacuum.c src/backend/commands/vacuum.c
--- ../base/src/backend/commands/vacuum.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/commands/vacuum.c    2002-07-15 20:39:19.000000000 +0200
@@ -392,7 +392,8 @@
         {
             /* Make a relation list entry for this guy */
             oldcontext = MemoryContextSwitchTo(vac_context);
-            vrl = lappendi(vrl, tuple->t_data->t_oid);
+            AssertTupleDescHasOid(pgclass->rd_att);
+            vrl = lappendi(vrl, HeapTupleGetOid(tuple));
             MemoryContextSwitchTo(oldcontext);
         }

@@ -1172,8 +1173,8 @@
             /*
              * Other checks...
              */
-            if (!OidIsValid(tuple.t_data->t_oid) &&
-                onerel->rd_rel->relhasoids)
+            if (onerel->rd_rel->relhasoids &&
+                !OidIsValid(HeapTupleGetOid(&tuple)))
                 elog(WARNING, "Rel %s: TID %u/%u: OID IS INVALID. TUPGONE %d.",
                      relname, blkno, offnum, (int) tupgone);

diff -ruN ../base/src/backend/commands/vacuumlazy.c src/backend/commands/vacuumlazy.c
--- ../base/src/backend/commands/vacuumlazy.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/commands/vacuumlazy.c    2002-07-15 16:52:05.000000000 +0200
@@ -368,8 +368,8 @@
             /*
              * Other checks...
              */
-            if (!OidIsValid(tuple.t_data->t_oid) &&
-                onerel->rd_rel->relhasoids)
+            if (onerel->rd_rel->relhasoids &&
+                !OidIsValid(HeapTupleGetOid(&tuple)))
                 elog(WARNING, "Rel %s: TID %u/%u: OID IS INVALID. TUPGONE %d.",
                      relname, blkno, offnum, (int) tupgone);

diff -ruN ../base/src/backend/executor/execJunk.c src/backend/executor/execJunk.c
--- ../base/src/backend/executor/execJunk.c    2002-06-21 02:12:15.000000000 +0200
+++ src/backend/executor/execJunk.c    2002-07-15 21:41:28.000000000 +0200
@@ -170,7 +170,7 @@
      * Now calculate the tuple type for the cleaned tuple (we were already
      * given the type for the original targetlist).
      */
-    cleanTupType = ExecTypeFromTL(cleanTargetList);
+    cleanTupType = ExecTypeFromTL(cleanTargetList, tupType->tdhasoid);

     len = ExecTargetListLength(targetList);
     cleanLength = ExecTargetListLength(cleanTargetList);
@@ -383,8 +383,8 @@
      * information for the new "clean" tuple.
      *
      * Note: we use memory on the stack to optimize things when we are
-     * dealing with a small number of tuples. for large tuples we just use
-     * palloc.
+     * dealing with a small number of attributes. for large tuples we
+     * just use palloc.
      */
     if (cleanLength > 64)
     {
diff -ruN ../base/src/backend/executor/execMain.c src/backend/executor/execMain.c
--- ../base/src/backend/executor/execMain.c    2002-06-27 13:58:04.000000000 +0200
+++ src/backend/executor/execMain.c    2002-07-15 21:46:35.000000000 +0200
@@ -717,6 +717,10 @@
                 }

                 /*
+                 * new "INTO" table is created WITH OIDS
+                 */
+                tupType->tdhasoid = WITHOID;
+                /*
                  * have to copy tupType to get rid of constraints
                  */
                 tupdesc = CreateTupleDescCopy(tupType);
diff -ruN ../base/src/backend/executor/execQual.c src/backend/executor/execQual.c
--- ../base/src/backend/executor/execQual.c    2002-07-09 14:00:55.000000000 +0200
+++ src/backend/executor/execQual.c    2002-07-15 20:19:46.000000000 +0200
@@ -1770,7 +1770,10 @@
      * natts = 0 to deal with it.
      */
     if (targettype == NULL)
+    {
         targettype = &NullTupleDesc;
+        targettype->tdhasoid = WITHOUTOID;
+    }

     /*
      * allocate an array of char's to hold the "null" information only if
diff -ruN ../base/src/backend/executor/execTuples.c src/backend/executor/execTuples.c
--- ../base/src/backend/executor/execTuples.c    2002-06-21 02:12:16.000000000 +0200
+++ src/backend/executor/execTuples.c    2002-07-15 21:13:09.000000000 +0200
@@ -540,6 +540,7 @@

     ExecSetSlotDescriptor(slot, tupType, false);

+    NullTupleDesc.tdhasoid = WITHOUTOID;
     nullTuple = heap_formtuple(&NullTupleDesc, values, nulls);

     return ExecStoreTuple(nullTuple, slot, InvalidBuffer, true);
@@ -557,7 +558,7 @@
  * ----------------------------------------------------------------
  */
 TupleDesc
-ExecTypeFromTL(List *targetList)
+ExecTypeFromTL(List *targetList, hasoid_t withoid)
 {
     List       *tlitem;
     TupleDesc    typeInfo;
@@ -576,7 +577,7 @@
     /*
      * allocate a new typeInfo
      */
-    typeInfo = CreateTemplateTupleDesc(len);
+    typeInfo = CreateTemplateTupleDesc(len, withoid);

     /*
      * scan list, generate type info for each entry
diff -ruN ../base/src/backend/executor/execUtils.c src/backend/executor/execUtils.c
--- ../base/src/backend/executor/execUtils.c    2002-06-27 13:58:04.000000000 +0200
+++ src/backend/executor/execUtils.c    2002-07-15 21:21:39.000000000 +0200
@@ -290,9 +290,23 @@
 void
 ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
 {
+    ResultRelInfo *ri;
+    Relation    rel;
+    hasoid_t    withoid;
     TupleDesc    tupDesc;

-    tupDesc = ExecTypeFromTL(node->targetlist);
+    ri = node->state->es_result_relation_info;
+    if (ri != NULL)
+        rel = ri->ri_RelationDesc;
+    else
+        rel = node->state->es_into_relation_descriptor;
+
+    if (rel != NULL)
+        withoid = BoolToHasOid(rel->rd_rel->relhasoids);
+    else
+        withoid = WITHOUTOID;
+
+    tupDesc = ExecTypeFromTL(node->targetlist, withoid);
     ExecAssignResultType(commonstate, tupDesc, true);
 }

diff -ruN ../base/src/backend/executor/nodeFunctionscan.c src/backend/executor/nodeFunctionscan.c
--- ../base/src/backend/executor/nodeFunctionscan.c    2002-06-21 02:12:16.000000000 +0200
+++ src/backend/executor/nodeFunctionscan.c    2002-07-15 20:19:46.000000000 +0200
@@ -234,7 +234,7 @@
          */
         char       *attname = strVal(lfirst(rte->eref->colnames));

-        tupdesc = CreateTemplateTupleDesc(1);
+        tupdesc = CreateTemplateTupleDesc(1, WITHOUTOID);
         TupleDescInitEntry(tupdesc,
                            (AttrNumber) 1,
                            attname,
diff -ruN ../base/src/backend/executor/spi.c src/backend/executor/spi.c
--- ../base/src/backend/executor/spi.c    2002-06-21 02:12:16.000000000 +0200
+++ src/backend/executor/spi.c    2002-07-15 16:52:05.000000000 +0200
@@ -435,11 +435,15 @@
     {
         mtuple = heap_formtuple(rel->rd_att, v, n);
         infomask = mtuple->t_data->t_infomask;
-        memmove(&(mtuple->t_data->t_oid), &(tuple->t_data->t_oid),
-                ((char *) &(tuple->t_data->t_hoff) -
-                 (char *) &(tuple->t_data->t_oid)));
+        /*
+         * copy t_xmin, t_cid, t_xmax, t_ctid, t_natts, t_infomask
+         */
+        memmove((char *)mtuple->t_data, (char *)tuple->t_data,
+                offsetof(HeapTupleHeaderData, t_hoff));
         mtuple->t_data->t_infomask = infomask;
         mtuple->t_data->t_natts = numberOfAttributes;
+        if (rel->rd_rel->relhasoids)
+            HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
     }
     else
     {
diff -ruN ../base/src/backend/optimizer/util/clauses.c src/backend/optimizer/util/clauses.c
--- ../base/src/backend/optimizer/util/clauses.c    2002-07-09 14:00:55.000000000 +0200
+++ src/backend/optimizer/util/clauses.c    2002-07-15 16:52:05.000000000 +0200
@@ -1071,7 +1071,7 @@

     commuTup = (Form_pg_operator) GETSTRUCT(optup);

-    commu = makeOper(optup->t_data->t_oid,
+    commu = makeOper(HeapTupleGetOid(optup),
                      commuTup->oprcode,
                      commuTup->oprresult,
                      ((Oper *) clause->oper)->opretset);
diff -ruN ../base/src/backend/parser/parse_coerce.c src/backend/parser/parse_coerce.c
--- ../base/src/backend/parser/parse_coerce.c    2002-07-09 14:00:55.000000000 +0200
+++ src/backend/parser/parse_coerce.c    2002-07-15 19:03:43.000000000 +0200
@@ -792,7 +792,7 @@
             if (isExplicit || pform->proimplicit)
             {
                 /* Okay to use it */
-                funcid = ftup->t_data->t_oid;
+                funcid = HeapTupleGetOid(ftup);
             }
         }
         ReleaseSysCache(ftup);
diff -ruN ../base/src/backend/parser/parse_oper.c src/backend/parser/parse_oper.c
--- ../base/src/backend/parser/parse_oper.c    2002-06-21 02:12:19.000000000 +0200
+++ src/backend/parser/parse_oper.c    2002-07-15 18:44:09.000000000 +0200
@@ -150,7 +150,7 @@
 Oid
 oprid(Operator op)
 {
-    return op->t_data->t_oid;
+    return HeapTupleGetOid(op);
 }

 /* given operator tuple, return the underlying function's OID */
diff -ruN ../base/src/backend/parser/parse_type.c src/backend/parser/parse_type.c
--- ../base/src/backend/parser/parse_type.c    2002-07-09 14:00:55.000000000 +0200
+++ src/backend/parser/parse_type.c    2002-07-15 18:44:32.000000000 +0200
@@ -283,7 +283,7 @@
 {
     if (tp == NULL)
         elog(ERROR, "typeTypeId() called with NULL type struct");
-    return tp->t_data->t_oid;
+    return HeapTupleGetOid(tp);
 }

 /* given type (as type struct), return the length of type */
diff -ruN ../base/src/backend/postmaster/pgstat.c src/backend/postmaster/pgstat.c
--- ../base/src/backend/postmaster/pgstat.c    2002-05-21 11:54:17.000000000 +0200
+++ src/backend/postmaster/pgstat.c    2002-07-15 20:40:20.000000000 +0200
@@ -628,7 +628,8 @@
             dbidlist = (Oid *) repalloc((char *) dbidlist,
                                         sizeof(Oid) * dbidalloc);
         }
-        dbidlist[dbidused++] = dbtup->t_data->t_oid;
+        AssertTupleDescHasOid(dbrel->rd_att);
+        dbidlist[dbidused++] = HeapTupleGetOid(dbtup);
     }
     heap_endscan(dbscan);
     heap_close(dbrel, AccessShareLock);
diff -ruN ../base/src/backend/rewrite/rewriteRemove.c src/backend/rewrite/rewriteRemove.c
--- ../base/src/backend/rewrite/rewriteRemove.c    2002-06-21 02:12:20.000000000 +0200
+++ src/backend/rewrite/rewriteRemove.c    2002-07-15 20:41:32.000000000 +0200
@@ -67,7 +67,8 @@
      * Save the OID of the rule (i.e. the tuple's OID) and the event
      * relation's OID
      */
-    ruleId = tuple->t_data->t_oid;
+    AssertTupleDescHasOid(RewriteRelation->rd_att);
+    ruleId = HeapTupleGetOid(tuple);
     eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class;
     Assert(eventRelationOid == owningRel);

@@ -157,7 +158,8 @@
     while (HeapTupleIsValid(tuple = systable_getnext(scanDesc)))
     {
         /* Delete any comments associated with this rule */
-        DeleteComments(tuple->t_data->t_oid, RelationGetRelid(RewriteRelation));
+        AssertTupleDescHasOid(RewriteRelation->rd_att);
+        DeleteComments(HeapTupleGetOid(tuple), RelationGetRelid(RewriteRelation));

         simple_heap_delete(RewriteRelation, &tuple->t_self);
     }
diff -ruN ../base/src/backend/utils/adt/regproc.c src/backend/utils/adt/regproc.c
--- ../base/src/backend/utils/adt/regproc.c    2002-06-21 02:12:22.000000000 +0200
+++ src/backend/utils/adt/regproc.c    2002-07-15 20:43:19.000000000 +0200
@@ -110,7 +110,8 @@

         while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
         {
-            result = (RegProcedure) tuple->t_data->t_oid;
+            AssertTupleDescHasOid(hdesc->rd_att);
+            result = (RegProcedure) HeapTupleGetOid(tuple);
             if (++matches > 1)
                 break;
         }
@@ -414,7 +415,8 @@

         while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
         {
-            result = tuple->t_data->t_oid;
+            AssertTupleDescHasOid(hdesc->rd_att);
+            result = HeapTupleGetOid(tuple);
             if (++matches > 1)
                 break;
         }
@@ -731,7 +733,10 @@
                                      SnapshotNow, 1, skey);

         if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
-            result = tuple->t_data->t_oid;
+        {
+            AssertTupleDescHasOid(hdesc->rd_att);
+            result = HeapTupleGetOid(tuple);
+        }
         else
             elog(ERROR, "No class with name %s", class_name_or_oid);

@@ -884,7 +889,10 @@
                                      SnapshotNow, 1, skey);

         if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
-            result = tuple->t_data->t_oid;
+        {
+            AssertTupleDescHasOid(hdesc->rd_att);
+            result = HeapTupleGetOid(tuple);
+        }
         else
             elog(ERROR, "No type with name %s", typ_name_or_oid);

diff -ruN ../base/src/backend/utils/adt/sets.c src/backend/utils/adt/sets.c
--- ../base/src/backend/utils/adt/sets.c    2002-06-21 02:12:22.000000000 +0200
+++ src/backend/utils/adt/sets.c    2002-07-15 20:43:55.000000000 +0200
@@ -120,7 +120,8 @@

         simple_heap_update(procrel, &newtup->t_self, newtup);

-        setoid = newtup->t_data->t_oid;
+        AssertTupleDescHasOid(procrel->rd_att);
+        setoid = HeapTupleGetOid(newtup);

         if (RelationGetForm(procrel)->relhasindex)
         {
diff -ruN ../base/src/backend/utils/cache/catcache.c src/backend/utils/cache/catcache.c
--- ../base/src/backend/utils/cache/catcache.c    2002-06-21 02:12:22.000000000 +0200
+++ src/backend/utils/cache/catcache.c    2002-07-15 20:19:47.000000000 +0200
@@ -218,7 +218,7 @@
         case 4:
             cur_skey[3].sk_argument =
                 (cache->cc_key[3] == ObjectIdAttributeNumber)
-                ? ObjectIdGetDatum(tuple->t_data->t_oid)
+                ? ObjectIdGetDatum(HeapTupleGetOid(tuple))
                 : fastgetattr(tuple,
                               cache->cc_key[3],
                               cache->cc_tupdesc,
@@ -228,7 +228,7 @@
         case 3:
             cur_skey[2].sk_argument =
                 (cache->cc_key[2] == ObjectIdAttributeNumber)
-                ? ObjectIdGetDatum(tuple->t_data->t_oid)
+                ? ObjectIdGetDatum(HeapTupleGetOid(tuple))
                 : fastgetattr(tuple,
                               cache->cc_key[2],
                               cache->cc_tupdesc,
@@ -238,7 +238,7 @@
         case 2:
             cur_skey[1].sk_argument =
                 (cache->cc_key[1] == ObjectIdAttributeNumber)
-                ? ObjectIdGetDatum(tuple->t_data->t_oid)
+                ? ObjectIdGetDatum(HeapTupleGetOid(tuple))
                 : fastgetattr(tuple,
                               cache->cc_key[1],
                               cache->cc_tupdesc,
@@ -248,7 +248,7 @@
         case 1:
             cur_skey[0].sk_argument =
                 (cache->cc_key[0] == ObjectIdAttributeNumber)
-                ? ObjectIdGetDatum(tuple->t_data->t_oid)
+                ? ObjectIdGetDatum(HeapTupleGetOid(tuple))
                 : fastgetattr(tuple,
                               cache->cc_key[0],
                               cache->cc_tupdesc,
@@ -572,7 +572,7 @@
             if (isCommit)
                 elog(WARNING, "Cache reference leak: cache %s (%d), tuple %u has count %d",
                      ct->my_cache->cc_relname, ct->my_cache->id,
-                     ct->tuple.t_data->t_oid,
+                     HeapTupleGetOid(&ct->tuple),
                      ct->refcount);
             ct->refcount = 0;
         }
@@ -717,7 +717,7 @@
                     continue;

                 if (cache->cc_reloidattr == ObjectIdAttributeNumber)
-                    tupRelid = ct->tuple.t_data->t_oid;
+                    tupRelid = HeapTupleGetOid(&ct->tuple);
                 else
                 {
                     bool        isNull;
@@ -907,6 +907,7 @@
      * copy the relcache's tuple descriptor to permanent cache storage
      */
     tupdesc = CreateTupleDescCopyConstr(RelationGetDescr(relation));
+    AssertTupleDescHasOidIsValid(tupdesc);

     /*
      * get the relation's OID and relisshared flag, too
@@ -1685,7 +1686,11 @@
     }

     ntp = heap_formtuple(tupDesc, values, nulls);
-    ntp->t_data->t_oid = tupOid;
+    if (tupOid != InvalidOid)
+    {
+        AssertTupleDescHasOid(tupDesc);
+        HeapTupleSetOid(ntp, tupOid);
+    }

     pfree(values);
     pfree(nulls);
diff -ruN ../base/src/backend/utils/cache/inval.c src/backend/utils/cache/inval.c
--- ../base/src/backend/utils/cache/inval.c    2002-06-21 02:12:22.000000000 +0200
+++ src/backend/utils/cache/inval.c    2002-07-15 20:44:46.000000000 +0200
@@ -525,7 +525,10 @@
     tupleRelId = RelationGetRelid(relation);

     if (tupleRelId == RelOid_pg_class)
-        relationId = tuple->t_data->t_oid;
+    {
+        AssertTupleDescHasOid(relation->rd_att);
+        relationId = HeapTupleGetOid(tuple);
+    }
     else if (tupleRelId == RelOid_pg_attribute)
         relationId = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid;
     else
diff -ruN ../base/src/backend/utils/cache/relcache.c src/backend/utils/cache/relcache.c
--- ../base/src/backend/utils/cache/relcache.c    2002-06-21 02:12:23.000000000 +0200
+++ src/backend/utils/cache/relcache.c    2002-07-15 22:22:28.000000000 +0200
@@ -440,7 +440,7 @@
     relation->rd_rel = relationForm;

     /* and allocate attribute tuple form storage */
-    relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts);
+    relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts, BoolToHasOid(relationForm->relhasoids));

     MemoryContextSwitchTo(oldcxt);

@@ -701,7 +701,8 @@
         rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
                                                   sizeof(RewriteRule));

-        rule->ruleId = rewrite_tuple->t_data->t_oid;
+        AssertTupleDescHasOid(rewrite_tupdesc);
+        rule->ruleId = HeapTupleGetOid(rewrite_tuple);

         rule->event = rewrite_form->ev_type - '0';
         rule->attrno = rewrite_form->ev_attr;
@@ -839,7 +840,7 @@
     /*
      * get information from the pg_class_tuple
      */
-    relid = pg_class_tuple->t_data->t_oid;
+    relid = HeapTupleGetOid(pg_class_tuple);
     relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);

     /*
@@ -872,6 +873,7 @@
      * initialize the tuple descriptor (relation->rd_att).
      */
     RelationBuildTupleDesc(buildinfo, relation);
+    RelationGetDescr(relation)->tdhasoid = BoolToHasOid(RelationGetForm(relation)->relhasoids);

     /*
      * Fetch rules and triggers that affect this relation
@@ -1395,7 +1397,7 @@
      * right because it will never be replaced.  The input values must be
      * correctly defined by macros in src/include/catalog/ headers.
      */
-    relation->rd_att = CreateTemplateTupleDesc(natts);
+    relation->rd_att = CreateTemplateTupleDesc(natts, BoolToHasOid(relation->rd_rel->relhasoids));

     /*
      * initialize tuple desc info
@@ -2067,7 +2069,7 @@
     rel->rd_rel->relnamespace = relnamespace;

     rel->rd_rel->relkind = RELKIND_UNCATALOGED;
-    rel->rd_rel->relhasoids = true;
+    rel->rd_rel->relhasoids = (rel->rd_att->tdhasoid == WITHOID);
     rel->rd_rel->relnatts = natts;
     rel->rd_rel->reltype = InvalidOid;

@@ -2313,6 +2315,7 @@
              */
             Assert(relation->rd_rel != NULL);
             memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
+            relation->rd_att->tdhasoid = BoolToHasOid(relp->relhasoids);

             ReleaseSysCache(htup);
         }
@@ -2776,7 +2779,7 @@
         rel->rd_rel = relform;

         /* initialize attribute tuple forms */
-        rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
+        rel->rd_att = CreateTemplateTupleDesc(relform->relnatts, BoolToHasOid(relform->relhasoids));

         /* next read all the attribute tuple form data entries */
         for (i = 0; i < relform->relnatts; i++)
diff -ruN ../base/src/backend/utils/cache/syscache.c src/backend/utils/cache/syscache.c
--- ../base/src/backend/utils/cache/syscache.c    2002-06-21 02:12:23.000000000 +0200
+++ src/backend/utils/cache/syscache.c    2002-07-15 18:47:21.000000000 +0200
@@ -574,7 +574,7 @@
     tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
     if (!HeapTupleIsValid(tuple))
         return InvalidOid;
-    result = tuple->t_data->t_oid;
+    result = HeapTupleGetOid(tuple);
     ReleaseSysCache(tuple);
     return result;
 }
diff -ruN ../base/src/backend/utils/init/postinit.c src/backend/utils/init/postinit.c
--- ../base/src/backend/utils/init/postinit.c    2002-06-21 02:12:23.000000000 +0200
+++ src/backend/utils/init/postinit.c    2002-07-15 20:46:54.000000000 +0200
@@ -98,8 +98,9 @@
     pgdbscan = heap_beginscan(pgdbrel, SnapshotNow, 1, &key);

     tup = heap_getnext(pgdbscan, ForwardScanDirection);
+    AssertTupleDescHasOid(pgdbrel->rd_att);
     if (!HeapTupleIsValid(tup) ||
-        tup->t_data->t_oid != MyDatabaseId)
+        HeapTupleGetOid(tup) != MyDatabaseId)
     {
         /* OOPS */
         heap_close(pgdbrel, AccessShareLock);
diff -ruN ../base/src/backend/utils/misc/database.c src/backend/utils/misc/database.c
--- ../base/src/backend/utils/misc/database.c    2002-06-21 02:12:23.000000000 +0200
+++ src/backend/utils/misc/database.c    2002-07-15 18:48:11.000000000 +0200
@@ -220,7 +220,7 @@
             if (strcmp(name, NameStr(tup_db->datname)) == 0)
             {
                 /* Found it; extract the OID and the database path. */
-                *db_id = tup.t_data->t_oid;
+                *db_id = HeapTupleGetOid(&tup);
                 pathlen = VARSIZE(&(tup_db->datpath)) - VARHDRSZ;
                 if (pathlen < 0)
                     pathlen = 0;                /* pure paranoia */
diff -ruN ../base/src/include/access/heapam.h src/include/access/heapam.h
--- ../base/src/include/access/heapam.h    2002-06-21 02:12:26.000000000 +0200
+++ src/include/access/heapam.h    2002-07-16 19:35:34.000000000 +0200
@@ -200,6 +200,6 @@
 extern HeapTuple heap_modifytuple(HeapTuple tuple,
         Relation relation, Datum *replValue, char *replNull, char *repl);
 extern void heap_freetuple(HeapTuple tuple);
-extern HeapTuple heap_addheader(int natts, Size structlen, void *structure);
+extern HeapTuple heap_addheader(int natts, bool withoid, Size structlen, void *structure);

 #endif   /* HEAPAM_H */
diff -ruN ../base/src/include/access/htup.h src/include/access/htup.h
--- ../base/src/include/access/htup.h    2002-07-09 14:00:56.000000000 +0200
+++ src/include/access/htup.h    2002-07-16 19:58:01.000000000 +0200
@@ -70,8 +70,6 @@
 */
 typedef struct HeapTupleHeaderData
 {
-    Oid            t_oid;            /* OID of this tuple -- 4 bytes */
-
     TransactionId t_xmin;        /* Xmin -- 4 bytes each */
     TransactionId t_cid;        /* Cmin, Cmax, Xvac */
     TransactionId t_xmax;        /* Xmax, Cmax */
@@ -84,7 +82,7 @@

     uint8        t_hoff;            /* sizeof header incl. bitmap, padding */

-    /* ^ - 27 bytes - ^ */
+    /* ^ - 23 bytes - ^ */

     bits8        t_bits[1];        /* bitmap of NULLs -- VARIABLE LENGTH */

@@ -123,10 +121,42 @@

 #define HEAP_XACT_MASK            0xFFF0    /* visibility-related bits */

+/* paranoid checking */
+
+#ifdef DEBUG_TUPLE_ACCESS
+
+#define HeapTupleHeaderExpectedLen(tup, withoid) \
+    MAXALIGN(offsetof(HeapTupleHeaderData, t_bits) + \
+             (((tup)->t_infomask & HEAP_HASNULL) \
+              ? BITMAPLEN((tup)->t_natts) : 0) + \
+             ((withoid) ? sizeof(Oid) : 0) \
+            )
+
+#define AssertHeapTupleHeaderHoffIsValid(tup, withoid) \
+    AssertMacro((tup)->t_hoff == HeapTupleHeaderExpectedLen(tup, withoid))
+
+#else
+
+#define AssertHeapTupleHeaderHoffIsValid(tup, withoid) ((void)true)
+
+#endif  /* DEBUG_TUPLE_ACCESS */


 /* HeapTupleHeader accessor macros */

+#define HeapTupleHeaderGetOid(tup) \
+( \
+    AssertHeapTupleHeaderHoffIsValid(tup, true), \
+    *((Oid *)((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) \
+)
+
+#define HeapTupleHeaderSetOid(tup, oid) \
+( \
+    AssertHeapTupleHeaderHoffIsValid(tup, true), \
+    *((Oid *)((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) = (oid) \
+)
+
+
 #define HeapTupleHeaderGetXmin(tup) \
 ( \
     (tup)->t_xmin \
@@ -406,4 +436,10 @@
 #define HeapTupleHasExtended(tuple) \
         ((((HeapTuple)(tuple))->t_data->t_infomask & HEAP_HASEXTENDED) != 0)

+#define HeapTupleGetOid(tuple) \
+        HeapTupleHeaderGetOid(((HeapTuple)(tuple))->t_data)
+
+#define HeapTupleSetOid(tuple, oid) \
+        HeapTupleHeaderSetOid(((HeapTuple)(tuple))->t_data, (oid))
+
 #endif   /* HTUP_H */
diff -ruN ../base/src/include/access/tupdesc.h src/include/access/tupdesc.h
--- ../base/src/include/access/tupdesc.h    2002-06-21 02:12:26.000000000 +0200
+++ src/include/access/tupdesc.h    2002-07-15 20:56:56.000000000 +0200
@@ -41,6 +41,11 @@
     bool        has_not_null;
 } TupleConstr;

+typedef char hasoid_t;
+#define WITHOID 'C'
+#define WITHOUTOID 'S'
+#define UNDEFOID '?'
+#define BoolToHasOid(b) ((b) ? WITHOID : WITHOUTOID)
 /*
  * This structure contains all information (i.e. from Classes
  * pg_attribute, pg_attrdef, pg_relcheck) for a tuple.
@@ -51,9 +56,27 @@
     Form_pg_attribute *attrs;
     /* attrs[N] is a pointer to the description of Attribute Number N+1.  */
     TupleConstr *constr;
+    hasoid_t    tdhasoid;        /* Tuple has an oid attribute in its header */
 }    *TupleDesc;

-extern TupleDesc CreateTemplateTupleDesc(int natts);
+#ifdef DEBUG_TUPLE_ACCESS
+
+#define AssertTupleDescHasOidIsValid(td) \
+    Assert(((td)->tdhasoid == WITHOID) || ((td)->tdhasoid == WITHOUTOID))
+#define AssertTupleDescHasOid(td) \
+    Assert((td)->tdhasoid == WITHOID)
+#define AssertTupleDescHasNoOid(td) \
+    Assert((td)->tdhasoid == WITHOUTOID)
+
+#else
+
+#define AssertTupleDescHasOidIsValid(td)
+#define AssertTupleDescHasOid(td)
+#define AssertTupleDescHasNoOid(td)
+
+#endif
+
+extern TupleDesc CreateTemplateTupleDesc(int natts, hasoid_t withoid);

 extern TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs);

diff -ruN ../base/src/include/executor/executor.h src/include/executor/executor.h
--- ../base/src/include/executor/executor.h    2002-06-27 13:58:05.000000000 +0200
+++ src/include/executor/executor.h    2002-07-15 22:53:02.000000000 +0200
@@ -118,7 +118,7 @@
 extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
 extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
                       TupleDesc tupType);
-extern TupleDesc ExecTypeFromTL(List *targetList);
+extern TupleDesc ExecTypeFromTL(List *targetList, hasoid_t withoid);
 extern void SetChangedParamList(Plan *node, List *newchg);

 /*
diff -ruN ../base/src/include/pg_config.h.in src/include/pg_config.h.in
--- ../base/src/include/pg_config.h.in    2002-05-05 02:03:29.000000000 +0200
+++ src/include/pg_config.h.in    2002-07-15 16:52:05.000000000 +0200
@@ -311,6 +311,12 @@
 /* #define ACLDEBUG */
 /* #define RTDEBUG */
 /* #define GISTDEBUG */
+/*
+ * DEBUG_TUPLE_ACCESS enables paranoid assertions during
+ * elimination of oids from the fixed sized part of HeapTupleHeader.
+ * This is expected to be undef'd after v7.3 release at the latest.
+ */
+#define DEBUG_TUPLE_ACCESS

 /*
  * defining unsafe floats will make float4 and float8 ops faster
diff -ruN ../base/src/pl/plpython/plpython.c src/pl/plpython/plpython.c
--- ../base/src/pl/plpython/plpython.c    2002-06-17 10:11:34.000000000 +0200
+++ src/pl/plpython/plpython.c    2002-07-15 16:52:05.000000000 +0200
@@ -2091,7 +2091,7 @@
                 Py_DECREF(optr);
                 optr = NULL;    /* this is important */

-                plan->types[i] = typeTup->t_data->t_oid;
+                plan->types[i] = HeapTupleGetOid(typeTup);
                 typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
                 if (typeStruct->typrelid == InvalidOid)
                     PLy_output_datum_func(&plan->args[i], typeStruct);
diff -ruN ../base/src/pl/tcl/pltcl.c src/pl/tcl/pltcl.c
--- ../base/src/pl/tcl/pltcl.c    2002-06-17 10:11:34.000000000 +0200
+++ src/pl/tcl/pltcl.c    2002-07-15 16:52:05.000000000 +0200
@@ -1755,7 +1755,7 @@
     {
         /* XXX should extend this to allow qualified type names */
         typeTup = typenameType(makeTypeName(args[i]));
-        qdesc->argtypes[i] = typeTup->t_data->t_oid;
+        qdesc->argtypes[i] = HeapTupleGetOid(typeTup);
         perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
                        &(qdesc->arginfuncs[i]));
         qdesc->argtypelems[i] = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
diff -ruN ../base/src/test/regress/expected/without_oid.out src/test/regress/expected/without_oid.out
--- ../base/src/test/regress/expected/without_oid.out    1970-01-01 01:00:00.000000000 +0100
+++ src/test/regress/expected/without_oid.out    2002-07-10 23:53:44.000000000 +0200
@@ -0,0 +1,38 @@
+--
+-- WITHOUT OID
+--
+CREATE TABLE wi (i INT);
+CREATE TABLE wo (i INT) WITHOUT OIDS;
+INSERT INTO wi VALUES (1);  -- 1
+INSERT INTO wo SELECT i FROM wi;  -- 1
+INSERT INTO wo SELECT i+1 FROM wi;  -- 1+1=2
+INSERT INTO wi SELECT i+1 FROM wo;  -- 1+2=3
+INSERT INTO wi SELECT i+3 FROM wi;  -- 3+3=6
+INSERT INTO wo SELECT i+2 FROM wi;  -- 2+6=8
+INSERT INTO wo SELECT i+8 FROM wo;  -- 8+8=16
+INSERT INTO wi SELECT i+6 FROM wo;  -- 6+16=22
+INSERT INTO wi SELECT i+22 FROM wi;  -- 22+22=44
+INSERT INTO wo SELECT i+16 FROM wi;  -- 16+44=60
+INSERT INTO wo SELECT i+60 FROM wo;  -- 60+60=120
+INSERT INTO wi SELECT i+44 FROM wo;  -- 44+120=164
+INSERT INTO wi SELECT i+164 FROM wi;  -- 164+164=328
+INSERT INTO wo SELECT i+120 FROM wi;  -- 120+328=448
+INSERT INTO wo SELECT i+448 FROM wo;  -- 448+448=896
+INSERT INTO wi SELECT i+328 FROM wo;  -- 328+896=1224
+INSERT INTO wi SELECT i+1224 FROM wi;  -- 1224+1224=2448
+INSERT INTO wo SELECT i+896 FROM wi;  -- 896+2448=3344
+INSERT INTO wo SELECT i+3344 FROM wo;  -- 3344+3344=6688
+INSERT INTO wi SELECT i+2448 FROM wo;  -- 2448+6688=9136
+INSERT INTO wo SELECT i+6688 FROM wi WHERE i<=2448;  -- 6688+2448=9136
+VACUUM ANALYZE wi;
+VACUUM ANALYZE wo;
+SELECT min(relpages) < max(relpages), min(reltuples) - max(reltuples)
+  FROM pg_class
+ WHERE relname IN ('wi', 'wo');
+ ?column? | ?column?
+----------+----------
+ t        |        0
+(1 row)
+
+DROP TABLE wi;
+DROP TABLE wo;
diff -ruN ../base/src/test/regress/parallel_schedule src/test/regress/parallel_schedule
--- ../base/src/test/regress/parallel_schedule    2002-06-21 02:12:33.000000000 +0200
+++ src/test/regress/parallel_schedule    2002-07-10 23:29:32.000000000 +0200
@@ -75,3 +75,5 @@
 # ----------
 # "plpgsql" cannot run concurrently with "rules"
 test: limit plpgsql temp domain rangefuncs
+
+test: without_oid
diff -ruN ../base/src/test/regress/serial_schedule src/test/regress/serial_schedule
--- ../base/src/test/regress/serial_schedule    2002-06-21 02:12:33.000000000 +0200
+++ src/test/regress/serial_schedule    2002-07-10 23:31:16.000000000 +0200
@@ -83,3 +83,4 @@
 test: temp
 test: domain
 test: rangefuncs
+test: without_oid
diff -ruN ../base/src/test/regress/sql/without_oid.sql src/test/regress/sql/without_oid.sql
--- ../base/src/test/regress/sql/without_oid.sql    1970-01-01 01:00:00.000000000 +0100
+++ src/test/regress/sql/without_oid.sql    2002-07-10 23:54:13.000000000 +0200
@@ -0,0 +1,35 @@
+--
+-- WITHOUT OID
+--
+
+CREATE TABLE wi (i INT);
+CREATE TABLE wo (i INT) WITHOUT OIDS;
+INSERT INTO wi VALUES (1);  -- 1
+INSERT INTO wo SELECT i FROM wi;  -- 1
+INSERT INTO wo SELECT i+1 FROM wi;  -- 1+1=2
+INSERT INTO wi SELECT i+1 FROM wo;  -- 1+2=3
+INSERT INTO wi SELECT i+3 FROM wi;  -- 3+3=6
+INSERT INTO wo SELECT i+2 FROM wi;  -- 2+6=8
+INSERT INTO wo SELECT i+8 FROM wo;  -- 8+8=16
+INSERT INTO wi SELECT i+6 FROM wo;  -- 6+16=22
+INSERT INTO wi SELECT i+22 FROM wi;  -- 22+22=44
+INSERT INTO wo SELECT i+16 FROM wi;  -- 16+44=60
+INSERT INTO wo SELECT i+60 FROM wo;  -- 60+60=120
+INSERT INTO wi SELECT i+44 FROM wo;  -- 44+120=164
+INSERT INTO wi SELECT i+164 FROM wi;  -- 164+164=328
+INSERT INTO wo SELECT i+120 FROM wi;  -- 120+328=448
+INSERT INTO wo SELECT i+448 FROM wo;  -- 448+448=896
+INSERT INTO wi SELECT i+328 FROM wo;  -- 328+896=1224
+INSERT INTO wi SELECT i+1224 FROM wi;  -- 1224+1224=2448
+INSERT INTO wo SELECT i+896 FROM wi;  -- 896+2448=3344
+INSERT INTO wo SELECT i+3344 FROM wo;  -- 3344+3344=6688
+INSERT INTO wi SELECT i+2448 FROM wo;  -- 2448+6688=9136
+INSERT INTO wo SELECT i+6688 FROM wi WHERE i<=2448;  -- 6688+2448=9136
+VACUUM ANALYZE wi;
+VACUUM ANALYZE wo;
+SELECT min(relpages) < max(relpages), min(reltuples) - max(reltuples)
+  FROM pg_class
+ WHERE relname IN ('wi', 'wo');
+
+DROP TABLE wi;
+DROP TABLE wo;
diff -ruN ../base/contrib/dbsize/dbsize.c contrib/dbsize/dbsize.c
--- ../base/contrib/dbsize/dbsize.c    2002-05-21 11:54:08.000000000 +0200
+++ contrib/dbsize/dbsize.c    2002-07-15 18:01:46.000000000 +0200
@@ -65,7 +65,7 @@
     if (!HeapTupleIsValid(tuple))
         elog(ERROR, "database %s does not exist", NameStr(*dbname));

-    dbid = tuple->t_data->t_oid;
+    dbid = HeapTupleGetOid(tuple);
     if (dbid == InvalidOid)
         elog(ERROR, "invalid database id");

diff -ruN ../base/contrib/fulltextindex/fti.c contrib/fulltextindex/fti.c
--- ../base/contrib/fulltextindex/fti.c    2001-11-05 19:46:23.000000000 +0100
+++ contrib/fulltextindex/fti.c    2002-07-15 16:52:05.000000000 +0200
@@ -190,7 +190,7 @@
     tupdesc = rel->rd_att;        /* what the tuple looks like (?) */

     /* get oid of current tuple, needed by all, so place here */
-    oid = rettuple->t_data->t_oid;
+    oid = rel->rd_rel->relhasoids ? HeapTupleGetOid(rettuple) : InvalidOid;
     if (!OidIsValid(oid))
         elog(ERROR, "Full Text Indexing: Oid of current tuple is invalid");

diff -ruN ../base/contrib/rserv/rserv.c contrib/rserv/rserv.c
--- ../base/contrib/rserv/rserv.c    2002-03-06 08:09:11.000000000 +0100
+++ contrib/rserv/rserv.c    2002-07-15 16:52:05.000000000 +0200
@@ -102,7 +102,9 @@

     if (keynum == ObjectIdAttributeNumber)
     {
-        sprintf(oidbuf, "%u", tuple->t_data->t_oid);
+        sprintf(oidbuf, "%u", rel->rd_rel->relhasoids
+                              ? HeapTupleGetOid(tuple)
+                              : InvalidOid);
         key = oidbuf;
     }
     else

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: utils C files
Next
From: Peter Eisentraut
Date:
Subject: Re: several minor cleanups