Solve the problem of OID collisions by probing for duplicate OIDs
authorTom Lane <[email protected]>
Fri, 12 Aug 2005 01:36:05 +0000 (01:36 +0000)
committerTom Lane <[email protected]>
Fri, 12 Aug 2005 01:36:05 +0000 (01:36 +0000)
whenever we generate a new OID.  This prevents occasional duplicate-OID
errors that can otherwise occur once the OID counter has wrapped around.
Duplicate relfilenode values are also checked for when creating new
physical files.  Per my recent proposal.

20 files changed:
doc/src/sgml/ddl.sgml
src/backend/access/heap/heapam.c
src/backend/access/heap/tuptoaster.c
src/backend/access/transam/varsup.c
src/backend/catalog/catalog.c
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/catalog/pg_type.c
src/backend/commands/dbcommands.c
src/backend/commands/trigger.c
src/backend/commands/typecmds.c
src/backend/storage/large_object/inv_api.c
src/backend/utils/cache/relcache.c
src/bin/pg_dump/pg_backup_archiver.c
src/bin/pg_dump/pg_dump.c
src/include/access/transam.h
src/include/catalog/catalog.h
src/include/catalog/pg_type.h
src/include/utils/rel.h
src/include/utils/relcache.h

index d676ce2a169094ce050ca2885ebc9743bb0312c9..1daee9ce785aa2b3e78f8cc8a899dcd6d9af777d 100644 (file)
@@ -871,7 +871,7 @@ CREATE TABLE order_items (
       The object identifier (object ID) of a row. This column is only
       present if the table was created using <literal>WITH
       OIDS</literal>, or if the <xref linkend="guc-default-with-oids">
-      configuration variable was enabled. This column is of type
+      configuration variable was set. This column is of type
       <type>oid</type> (same name as the column); see <xref
       linkend="datatype-oid"> for more information about the type.
      </para>
@@ -992,7 +992,13 @@ CREATE TABLE order_items (
      <listitem>
       <para>
        A unique constraint should be created on the OID column of each
-       table for which the OID will be used to identify rows.
+       table for which the OID will be used to identify rows.  When such
+       a unique constraint (or unique index) exists, the system takes
+       care not to generate an OID matching an already-existing row.
+       (Of course, this is only possible if the table contains fewer
+       than 2<superscript>32</> (4 billion) rows, and in practice the
+       table size had better be much less than that, or performance
+       may suffer.)
       </para>
      </listitem>
      <listitem>
@@ -1005,9 +1011,8 @@ CREATE TABLE order_items (
      <listitem>
       <para>
        The tables in question should be created using <literal>WITH
-       OIDS</literal> to ensure forward compatibility with future
-       releases of <productname>PostgreSQL</productname>.  It is
-       planned that <literal>WITHOUT OIDS</> will become the default.
+       OIDS</literal>.  As of <productname>PostgreSQL</productname> 8.1,
+       <literal>WITHOUT OIDS</> is the default.
       </para>
      </listitem>
     </itemizedlist>
index 71d3bc43756c17a249903278bda9b263e29bf26a..ad7de6eb2bc497ef75ca77ad35aa55f38a0b484f 100644 (file)
@@ -1069,9 +1069,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
                 * pointers to one another).
                 */
                if (!OidIsValid(HeapTupleGetOid(tup)))
-                       HeapTupleSetOid(tup, newoid());
-               else
-                       CheckMaxObjectId(HeapTupleGetOid(tup));
+                       HeapTupleSetOid(tup, GetNewOid(relation));
        }
        else
        {
index e218b65fecbfce8024b36a3472dbdef264a35787..7946df055c2656f0d35a4b28176f69b46df7e4a6 100644 (file)
@@ -1006,6 +1006,15 @@ toast_save_datum(Relation rel, Datum value)
        char       *data_p;
        int32           data_todo;
 
+       /*
+        * Open the toast relation and its index.  We can use the index to
+        * check uniqueness of the OID we assign to the toasted item, even
+        * though it has additional columns besides OID.
+        */
+       toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
+       toasttupDesc = toastrel->rd_att;
+       toastidx = index_open(toastrel->rd_rel->reltoastidxid);
+
        /*
         * Create the varattrib reference
         */
@@ -1023,7 +1032,8 @@ toast_save_datum(Relation rel, Datum value)
 
        result->va_content.va_external.va_extsize =
                VARATT_SIZE(value) - VARHDRSZ;
-       result->va_content.va_external.va_valueid = newoid();
+       result->va_content.va_external.va_valueid =
+               GetNewOidWithIndex(toastrel, toastidx);
        result->va_content.va_external.va_toastrelid =
                rel->rd_rel->reltoastrelid;
 
@@ -1043,12 +1053,9 @@ toast_save_datum(Relation rel, Datum value)
        data_todo = VARATT_SIZE(value) - VARHDRSZ;
 
        /*
-        * Open the toast relation.  We must explicitly lock the toast index
-        * because we aren't using an index scan here.
+        * We must explicitly lock the toast index because we aren't using an
+        * index scan here.
         */
-       toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
-       toasttupDesc = toastrel->rd_att;
-       toastidx = index_open(toastrel->rd_rel->reltoastidxid);
        LockRelation(toastidx, RowExclusiveLock);
 
        /*
index 52c6b0ef91caa11e1b5abdcd7b4f8b0cced19498..4e48239d193d11696ce5aa21184d3206d26e4a07 100644 (file)
@@ -247,13 +247,16 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
 }
 
 
-/* ----------------------------------------------------------------
- *                                     object id generation support
- * ----------------------------------------------------------------
+/*
+ * GetNewObjectId -- allocate a new OID
+ *
+ * OIDs are generated by a cluster-wide counter.  Since they are only 32 bits
+ * wide, counter wraparound will occur eventually, and therefore it is unwise
+ * to assume they are unique unless precautions are taken to make them so.
+ * Hence, this routine should generally not be used directly.  The only
+ * direct callers should be GetNewOid() and GetNewRelFileNode() in
+ * catalog/catalog.c.
  */
-
-static Oid     lastSeenOid = InvalidOid;
-
 Oid
 GetNewObjectId(void)
 {
@@ -265,8 +268,9 @@ GetNewObjectId(void)
         * Check for wraparound of the OID counter.  We *must* not return 0
         * (InvalidOid); and as long as we have to check that, it seems a good
         * idea to skip over everything below FirstNormalObjectId too. (This
-        * basically just reduces the odds of OID collision right after a wrap
-        * occurs.)  Note we are relying on unsigned comparison here.
+        * basically just avoids lots of collisions with bootstrap-assigned OIDs
+        * right after a wrap occurs, so as to avoid a possibly large number of
+        * iterations in GetNewOid.)  Note we are relying on unsigned comparison.
         *
         * During initdb, we start the OID generator at FirstBootstrapObjectId,
         * so we only enforce wrapping to that point when in bootstrap or
@@ -310,46 +314,5 @@ GetNewObjectId(void)
 
        LWLockRelease(OidGenLock);
 
-       lastSeenOid = result;
-
        return result;
 }
-
-void
-CheckMaxObjectId(Oid assigned_oid)
-{
-       if (lastSeenOid != InvalidOid && assigned_oid < lastSeenOid)
-               return;
-
-       LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
-
-       if (assigned_oid < ShmemVariableCache->nextOid)
-       {
-               lastSeenOid = ShmemVariableCache->nextOid - 1;
-               LWLockRelease(OidGenLock);
-               return;
-       }
-
-       /* If we are in the logged oid range, just bump nextOid up */
-       if (assigned_oid <= ShmemVariableCache->nextOid +
-               ShmemVariableCache->oidCount - 1)
-       {
-               ShmemVariableCache->oidCount -=
-                       assigned_oid - ShmemVariableCache->nextOid + 1;
-               ShmemVariableCache->nextOid = assigned_oid + 1;
-               LWLockRelease(OidGenLock);
-               return;
-       }
-
-       /*
-        * We have exceeded the logged oid range. We should lock the database
-        * and kill all other backends but we are loading oid's that we can
-        * not guarantee are unique anyway, so we must rely on the user.
-        */
-
-       XLogPutNextOid(assigned_oid + VAR_OID_PREFETCH);
-       ShmemVariableCache->nextOid = assigned_oid + 1;
-       ShmemVariableCache->oidCount = VAR_OID_PREFETCH - 1;
-
-       LWLockRelease(OidGenLock);
-}
index b570d7f3897bc77d81fee47eef74960894917b86..11c9d9b2ca8693b847c3339f3aa9081094443787 100644 (file)
 
 #include "postgres.h"
 
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "access/genam.h"
 #include "access/transam.h"
 #include "catalog/catalog.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_tablespace.h"
 #include "miscadmin.h"
+#include "storage/fd.h"
+#include "utils/fmgroids.h"
+#include "utils/relcache.h"
 
 
 #define OIDCHARS       10                      /* max chars printed by %u */
@@ -211,16 +218,171 @@ IsReservedName(const char *name)
 
 
 /*
- *             newoid                  - returns a unique identifier across all catalogs.
+ * GetNewOid
+ *             Generate a new OID that is unique within the given relation.
+ *
+ * Caller must have a suitable lock on the relation.
+ *
+ * Uniqueness is promised only if the relation has a unique index on OID.
+ * This is true for all system catalogs that have OIDs, but might not be
+ * true for user tables.  Note that we are effectively assuming that the
+ * table has a relatively small number of entries (much less than 2^32)
+ * and there aren't very long runs of consecutive existing OIDs.  Again,
+ * this is reasonable for system catalogs but less so for user tables.
+ *
+ * Since the OID is not immediately inserted into the table, there is a
+ * race condition here; but a problem could occur only if someone else
+ * managed to cycle through 2^32 OIDs and generate the same OID before we
+ * finish inserting our row.  This seems unlikely to be a problem.  Note
+ * that if we had to *commit* the row to end the race condition, the risk
+ * would be rather higher; therefore we use SnapshotDirty in the test,
+ * so that we will see uncommitted rows.
+ */
+Oid
+GetNewOid(Relation relation)
+{
+       Oid                     newOid;
+       Oid                     oidIndex;
+       Relation        indexrel;
+
+       /* If relation doesn't have OIDs at all, caller is confused */
+       Assert(relation->rd_rel->relhasoids);
+
+       /* In bootstrap mode, we don't have any indexes to use */
+       if (IsBootstrapProcessingMode())
+               return GetNewObjectId();
+
+       /* The relcache will cache the identity of the OID index for us */
+       oidIndex = RelationGetOidIndex(relation);
+
+       /* If no OID index, just hand back the next OID counter value */
+       if (!OidIsValid(oidIndex))
+       {
+               /*
+                * System catalogs that have OIDs should *always* have a unique
+                * OID index; we should only take this path for user tables.
+                * Give a warning if it looks like somebody forgot an index.
+                */
+               if (IsSystemRelation(relation))
+                       elog(WARNING, "generating possibly-non-unique OID for \"%s\"",
+                                RelationGetRelationName(relation));
+
+               return GetNewObjectId();
+       }
+
+       /* Otherwise, use the index to find a nonconflicting OID */
+       indexrel = index_open(oidIndex);
+       newOid = GetNewOidWithIndex(relation, indexrel);
+       index_close(indexrel);
+
+       return newOid;
+}
+
+/*
+ * GetNewOidWithIndex
+ *             Guts of GetNewOid: use the supplied index
+ *
+ * This is exported separately because there are cases where we want to use
+ * an index that will not be recognized by RelationGetOidIndex: TOAST tables
+ * and pg_largeobject have indexes that are usable, but have multiple columns
+ * and are on ordinary columns rather than a true OID column.  This code
+ * will work anyway, so long as the OID is the index's first column.
+ *
+ * Caller must have a suitable lock on the relation.
+ */
+Oid
+GetNewOidWithIndex(Relation relation, Relation indexrel)
+{
+       Oid                     newOid;
+       IndexScanDesc scan;
+       ScanKeyData key;
+       bool            collides;
+
+       /* Generate new OIDs until we find one not in the table */
+       do
+       {
+               newOid = GetNewObjectId();
+
+               ScanKeyInit(&key,
+                                       (AttrNumber) 1,
+                                       BTEqualStrategyNumber, F_OIDEQ,
+                                       ObjectIdGetDatum(newOid));
+
+               /* see notes above about using SnapshotDirty */
+               scan = index_beginscan(relation, indexrel, SnapshotDirty, 1, &key);
+
+               collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection));
+
+               index_endscan(scan);
+       } while (collides);
+
+       return newOid;
+}
+
+/*
+ * GetNewRelFileNode
+ *             Generate a new relfilenode number that is unique within the given
+ *             tablespace.
+ *
+ * If the relfilenode will also be used as the relation's OID, pass the
+ * opened pg_class catalog, and this routine will guarantee that the result
+ * is also an unused OID within pg_class.  If the result is to be used only
+ * as a relfilenode for an existing relation, pass NULL for pg_class.
  *
- *             Object Id allocation is now done by GetNewObjectID in
- *             access/transam/varsup.
+ * As with GetNewOid, there is some theoretical risk of a race condition,
+ * but it doesn't seem worth worrying about.
  *
- *             This code probably needs to change to generate OIDs separately
- *             for each table.
+ * Note: we don't support using this in bootstrap mode.  All relations
+ * created by bootstrap have preassigned OIDs, so there's no need.
  */
 Oid
-newoid(void)
+GetNewRelFileNode(Oid reltablespace, bool relisshared, Relation pg_class)
 {
-       return GetNewObjectId();
+       RelFileNode     rnode;
+       char       *rpath;
+       int                     fd;
+       bool            collides;
+
+       /* This should match RelationInitPhysicalAddr */
+       rnode.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace;
+       rnode.dbNode = relisshared ? InvalidOid : MyDatabaseId;
+
+       do
+       {
+               /* Generate the OID */
+               if (pg_class)
+                       rnode.relNode = GetNewOid(pg_class);
+               else
+                       rnode.relNode = GetNewObjectId();
+
+               /* Check for existing file of same name */
+               rpath = relpath(rnode);
+               fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0);
+
+               if (fd >= 0)
+               {
+                       /* definite collision */
+                       close(fd);
+                       collides = true;
+               }
+               else
+               {
+                       /*
+                        * Here we have a little bit of a dilemma: if errno is something
+                        * other than ENOENT, should we declare a collision and loop?
+                        * In particular one might think this advisable for, say, EPERM.
+                        * However there really shouldn't be any unreadable files in a
+                        * tablespace directory, and if the EPERM is actually complaining
+                        * that we can't read the directory itself, we'd be in an infinite
+                        * loop.  In practice it seems best to go ahead regardless of the
+                        * errno.  If there is a colliding file we will get an smgr failure
+                        * when we attempt to create the new relation file.
+                        */
+                       collides = false;
+               }
+
+               pfree(rpath);
+       } while (collides);
+
+       return rnode.relNode;
 }
index 6cc918f1fde79ab5b2b64a870d9e8f8be027cd7d..92a1f41070d88c4e907a1289ce603d1cf5b8454f 100644 (file)
@@ -66,11 +66,10 @@ static void AddNewRelationTuple(Relation pg_class_desc,
                                        Relation new_rel_desc,
                                        Oid new_rel_oid, Oid new_type_oid,
                                        char relkind);
-static void AddNewRelationType(const char *typeName,
+static Oid     AddNewRelationType(const char *typeName,
                                   Oid typeNamespace,
                                   Oid new_rel_oid,
-                                  char new_rel_kind,
-                                  Oid new_type_oid);
+                                  char new_rel_kind);
 static void RelationRemoveInheritance(Oid relid);
 static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
 static void StoreConstraints(Relation rel, TupleDesc tupdesc);
@@ -190,9 +189,8 @@ SystemAttributeByName(const char *attname, bool relhasoids)
 /* ----------------------------------------------------------------
  *             heap_create             - Create an uncataloged heap relation
  *
- *             relid is normally InvalidOid to specify that this routine should
- *             generate an OID for the relation.  During bootstrap, it can be
- *             nonzero to specify a preselected OID.
+ *             Note API change: the caller must now always provide the OID
+ *             to use for the relation.
  *
  *             rel->rd_rel is initialized by RelationBuildLocalRelation,
  *             and is mostly zeroes at return.
@@ -211,6 +209,9 @@ heap_create(const char *relname,
        bool            create_storage;
        Relation        rel;
 
+       /* The caller must have provided an OID for the relation. */
+       Assert(OidIsValid(relid));
+
        /*
         * sanity checks
         */
@@ -223,12 +224,6 @@ heap_create(const char *relname,
                                                get_namespace_name(relnamespace), relname),
                                 errdetail("System catalog modifications are currently disallowed.")));
 
-       /*
-        * Allocate an OID for the relation, unless we were told what to use.
-        */
-       if (!OidIsValid(relid))
-               relid = newoid();
-
        /*
         * Decide if we need storage or not, and handle a couple other
         * special cases for particular relkinds.
@@ -307,12 +302,12 @@ heap_create(const char *relname,
  *
  *             3) heap_create() is called to create the new relation on disk.
  *
- *             4) AddNewRelationTuple() is called to register the
- *                relation in pg_class.
- *
- *             5) TypeCreate() is called to define a new type corresponding
+ *             4) TypeCreate() is called to define a new type corresponding
  *                to the new relation.
  *
+ *             5) AddNewRelationTuple() is called to register the
+ *                relation in pg_class.
+ *
  *             6) AddNewAttributeTuples() is called to register the
  *                new relation's schema in pg_attribute.
  *
@@ -628,36 +623,35 @@ AddNewRelationTuple(Relation pg_class_desc,
  *             define a composite type corresponding to the new relation
  * --------------------------------
  */
-static void
+static Oid
 AddNewRelationType(const char *typeName,
                                   Oid typeNamespace,
                                   Oid new_rel_oid,
-                                  char new_rel_kind,
-                                  Oid new_type_oid)
+                                  char new_rel_kind)
 {
-       TypeCreate(typeName,            /* type name */
-                          typeNamespace,       /* type namespace */
-                          new_type_oid,        /* preassigned oid for type */
-                          new_rel_oid,         /* relation oid */
-                          new_rel_kind,        /* relation kind */
-                          -1,                          /* internal size (varlena) */
-                          'c',                         /* type-type (complex) */
-                          ',',                         /* default array delimiter */
-                          F_RECORD_IN,         /* input procedure */
-                          F_RECORD_OUT,        /* output procedure */
-                          F_RECORD_RECV,       /* receive procedure */
-                          F_RECORD_SEND,       /* send procedure */
-                          InvalidOid,          /* analyze procedure - default */
-                          InvalidOid,          /* array element type - irrelevant */
-                          InvalidOid,          /* domain base type - irrelevant */
-                          NULL,                        /* default type value - none */
-                          NULL,                        /* default type binary representation */
-                          false,                       /* passed by reference */
-                          'd',                         /* alignment - must be the largest! */
-                          'x',                         /* fully TOASTable */
-                          -1,                          /* typmod */
-                          0,                           /* array dimensions for typBaseType */
-                          false);                      /* Type NOT NULL */
+       return
+               TypeCreate(typeName,            /* type name */
+                                  typeNamespace,       /* type namespace */
+                                  new_rel_oid,         /* relation oid */
+                                  new_rel_kind,        /* relation kind */
+                                  -1,                          /* internal size (varlena) */
+                                  'c',                         /* type-type (complex) */
+                                  ',',                         /* default array delimiter */
+                                  F_RECORD_IN,         /* input procedure */
+                                  F_RECORD_OUT,        /* output procedure */
+                                  F_RECORD_RECV,       /* receive procedure */
+                                  F_RECORD_SEND,       /* send procedure */
+                                  InvalidOid,          /* analyze procedure - default */
+                                  InvalidOid,          /* array element type - irrelevant */
+                                  InvalidOid,          /* domain base type - irrelevant */
+                                  NULL,                        /* default value - none */
+                                  NULL,                        /* default binary representation */
+                                  false,                       /* passed by reference */
+                                  'd',                         /* alignment - must be the largest! */
+                                  'x',                         /* fully TOASTable */
+                                  -1,                          /* typmod */
+                                  0,                           /* array dimensions for typBaseType */
+                                  false);                      /* Type NOT NULL */
 }
 
 /* --------------------------------
@@ -681,9 +675,10 @@ heap_create_with_catalog(const char *relname,
 {
        Relation        pg_class_desc;
        Relation        new_rel_desc;
-       Oid                     new_rel_oid;
        Oid                     new_type_oid;
 
+       pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);
+
        /*
         * sanity checks
         */
@@ -696,6 +691,16 @@ heap_create_with_catalog(const char *relname,
                                (errcode(ERRCODE_DUPLICATE_TABLE),
                                 errmsg("relation \"%s\" already exists", relname)));
 
+       /*
+        * Allocate an OID for the relation, unless we were told what to use.
+        *
+        * The OID will be the relfilenode as well, so make sure it doesn't
+        * collide with either pg_class OIDs or existing physical files.
+        */
+       if (!OidIsValid(relid))
+               relid = GetNewRelFileNode(reltablespace, shared_relation,
+                                                                 pg_class_desc);
+
        /*
         * Create the relcache entry (mostly dummy at this point) and the
         * physical disk file.  (If we fail further down, it's the smgr's
@@ -710,11 +715,19 @@ heap_create_with_catalog(const char *relname,
                                                           shared_relation,
                                                           allow_system_table_mods);
 
-       /* Fetch the relation OID assigned by heap_create */
-       new_rel_oid = RelationGetRelid(new_rel_desc);
+       Assert(relid == RelationGetRelid(new_rel_desc));
 
-       /* Assign an OID for the relation's tuple type */
-       new_type_oid = newoid();
+       /*
+        * since defining a relation also defines a complex type, we add a new
+        * system type corresponding to the new relation.
+        *
+        * NOTE: we could get a unique-index failure here, in case the same name
+        * has already been used for a type.
+        */
+       new_type_oid = AddNewRelationType(relname,
+                                                                         relnamespace,
+                                                                         relid,
+                                                                         relkind);
 
        /*
         * now create an entry in pg_class for the relation.
@@ -723,32 +736,17 @@ heap_create_with_catalog(const char *relname,
         * is creating the same relation name in parallel but hadn't committed
         * yet when we checked for a duplicate name above.
         */
-       pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);
-
        AddNewRelationTuple(pg_class_desc,
                                                new_rel_desc,
-                                               new_rel_oid,
+                                               relid,
                                                new_type_oid,
                                                relkind);
 
-       /*
-        * since defining a relation also defines a complex type, we add a new
-        * system type corresponding to the new relation.
-        *
-        * NOTE: we could get a unique-index failure here, in case the same name
-        * has already been used for a type.
-        */
-       AddNewRelationType(relname,
-                                          relnamespace,
-                                          new_rel_oid,
-                                          relkind,
-                                          new_type_oid);
-
        /*
         * now add tuples to pg_attribute for the attributes in our new
         * relation.
         */
-       AddNewAttributeTuples(new_rel_oid, new_rel_desc->rd_att, relkind,
+       AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind,
                                                  oidislocal, oidinhcount);
 
        /*
@@ -764,14 +762,14 @@ heap_create_with_catalog(const char *relname,
                                        referenced;
 
                myself.classId = RelationRelationId;
-               myself.objectId = new_rel_oid;
+               myself.objectId = relid;
                myself.objectSubId = 0;
                referenced.classId = NamespaceRelationId;
                referenced.objectId = relnamespace;
                referenced.objectSubId = 0;
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
-               recordDependencyOnOwner(RelationRelationId, new_rel_oid, GetUserId());
+               recordDependencyOnOwner(RelationRelationId, relid, GetUserId());
        }
 
        /*
@@ -788,16 +786,16 @@ heap_create_with_catalog(const char *relname,
         * If there's a special on-commit action, remember it
         */
        if (oncommit != ONCOMMIT_NOOP)
-               register_on_commit_action(new_rel_oid, oncommit);
+               register_on_commit_action(relid, oncommit);
 
        /*
         * ok, the relation has been cataloged, so close our relations and
-        * return the oid of the newly created relation.
+        * return the OID of the newly created relation.
         */
        heap_close(new_rel_desc, NoLock);       /* do not unlock till end of xact */
        heap_close(pg_class_desc, RowExclusiveLock);
 
-       return new_rel_oid;
+       return relid;
 }
 
 
index 5b2fa3936ad8d51883e5344bd1bc96fb4a8bd8b8..85581d54b071b1981e1a1623340514540f11f636 100644 (file)
@@ -53,7 +53,7 @@
 static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
                                                 IndexInfo *indexInfo,
                                                 Oid *classObjectId);
-static void UpdateRelationRelation(Relation indexRelation);
+static void UpdateRelationRelation(Relation pg_class, Relation indexRelation);
 static void InitializeAttributeOids(Relation indexRelation,
                                                int numatts, Oid indexoid);
 static void AppendAttributeTuples(Relation indexRelation, int numatts);
@@ -241,13 +241,10 @@ ConstructTupleDescriptor(Relation heapRelation,
  * ----------------------------------------------------------------
  */
 static void
-UpdateRelationRelation(Relation indexRelation)
+UpdateRelationRelation(Relation pg_class, Relation indexRelation)
 {
-       Relation        pg_class;
        HeapTuple       tuple;
 
-       pg_class = heap_open(RelationRelationId, RowExclusiveLock);
-
        /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
        tuple = heap_addheader(Natts_pg_class_fixed,
                                                   true,
@@ -259,13 +256,13 @@ UpdateRelationRelation(Relation indexRelation)
         * would be embarrassing to do this sort of thing in polite company.
         */
        HeapTupleSetOid(tuple, RelationGetRelid(indexRelation));
+
        simple_heap_insert(pg_class, tuple);
 
        /* update the system catalog indexes */
        CatalogUpdateIndexes(pg_class, tuple);
 
        heap_freetuple(tuple);
-       heap_close(pg_class, RowExclusiveLock);
 }
 
 /* ----------------------------------------------------------------
@@ -464,14 +461,16 @@ index_create(Oid heapRelationId,
                         bool allow_system_table_mods,
                         bool skip_build)
 {
+       Relation        pg_class;
        Relation        heapRelation;
        Relation        indexRelation;
        TupleDesc       indexTupDesc;
        bool            shared_relation;
        Oid                     namespaceId;
-       Oid                     indexoid;
        int                     i;
 
+       pg_class = heap_open(RelationRelationId, RowExclusiveLock);
+
        /*
         * Only SELECT ... FOR UPDATE/SHARE are allowed while doing this
         */
@@ -524,6 +523,16 @@ index_create(Oid heapRelationId,
                                                                                        indexInfo,
                                                                                        classObjectId);
 
+       /*
+        * Allocate an OID for the index, unless we were told what to use.
+        *
+        * The OID will be the relfilenode as well, so make sure it doesn't
+        * collide with either pg_class OIDs or existing physical files.
+        */
+       if (!OidIsValid(indexRelationId))
+               indexRelationId = GetNewRelFileNode(tableSpaceId, shared_relation,
+                                                                                       pg_class);
+
        /*
         * create the index relation's relcache entry and physical disk file.
         * (If we fail further down, it's the smgr's responsibility to remove
@@ -538,8 +547,7 @@ index_create(Oid heapRelationId,
                                                                shared_relation,
                                                                allow_system_table_mods);
 
-       /* Fetch the relation OID assigned by heap_create */
-       indexoid = RelationGetRelid(indexRelation);
+       Assert(indexRelationId == RelationGetRelid(indexRelation));
 
        /*
         * Obtain exclusive lock on it.  Although no other backends can see it
@@ -562,7 +570,10 @@ index_create(Oid heapRelationId,
        /*
         * store index's pg_class entry
         */
-       UpdateRelationRelation(indexRelation);
+       UpdateRelationRelation(pg_class, indexRelation);
+
+       /* done with pg_class */
+       heap_close(pg_class, RowExclusiveLock);
 
        /*
         * now update the object id's of all the attribute tuple forms in the
@@ -570,7 +581,7 @@ index_create(Oid heapRelationId,
         */
        InitializeAttributeOids(indexRelation,
                                                        indexInfo->ii_NumIndexAttrs,
-                                                       indexoid);
+                                                       indexRelationId);
 
        /*
         * append ATTRIBUTE tuples for the index
@@ -585,7 +596,7 @@ index_create(Oid heapRelationId,
         *        (Or, could define a rule to maintain the predicate) --Nels, Feb '92
         * ----------------
         */
-       UpdateIndexRelation(indexoid, heapRelationId, indexInfo,
+       UpdateIndexRelation(indexRelationId, heapRelationId, indexInfo,
                                                classObjectId, primary);
 
        /*
@@ -608,7 +619,7 @@ index_create(Oid heapRelationId,
                                        referenced;
 
                myself.classId = RelationRelationId;
-               myself.objectId = indexoid;
+               myself.objectId = indexRelationId;
                myself.objectSubId = 0;
 
                if (isconstraint)
@@ -735,7 +746,7 @@ index_create(Oid heapRelationId,
         */
        if (IsBootstrapProcessingMode())
        {
-               index_register(heapRelationId, indexoid, indexInfo);
+               index_register(heapRelationId, indexRelationId, indexInfo);
                /* XXX shouldn't we close the heap and index rels here? */
        }
        else if (skip_build)
@@ -750,7 +761,7 @@ index_create(Oid heapRelationId,
                /* index_build closes the passed rels */
        }
 
-       return indexoid;
+       return indexRelationId;
 }
 
 /*
@@ -1113,7 +1124,9 @@ setNewRelfilenode(Relation relation)
        Assert(!relation->rd_rel->relisshared);
 
        /* Allocate a new relfilenode */
-       newrelfilenode = newoid();
+       newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace,
+                                                                          relation->rd_rel->relisshared,
+                                                                          NULL);
 
        /*
         * Find the pg_class tuple for the given relation.      This is not used
@@ -1738,6 +1751,11 @@ reindex_relation(Oid relid, bool toast_too)
         * whether they have index entries.  Also, a new pg_class index will
         * be created with an entry for its own pg_class row because we do
         * setNewRelfilenode() before we do index_build().
+        *
+        * Note that we also clear pg_class's rd_oidindex until the loop is done,
+        * so that that index can't be accessed either.  This means we cannot
+        * safely generate new relation OIDs while in the loop; shouldn't be a
+        * problem.
         */
        is_pg_class = (RelationGetRelid(rel) == RelationRelationId);
        doneIndexes = NIL;
@@ -1748,7 +1766,7 @@ reindex_relation(Oid relid, bool toast_too)
                Oid                     indexOid = lfirst_oid(indexId);
 
                if (is_pg_class)
-                       RelationSetIndexList(rel, doneIndexes);
+                       RelationSetIndexList(rel, doneIndexes, InvalidOid);
 
                reindex_index(indexOid);
 
@@ -1759,7 +1777,7 @@ reindex_relation(Oid relid, bool toast_too)
        }
 
        if (is_pg_class)
-               RelationSetIndexList(rel, indexIds);
+               RelationSetIndexList(rel, indexIds, ClassOidIndexId);
 
        /*
         * Close rel, but continue to hold the lock.
index 69a2c055ba4d02ec23e802e8dfd255a481658631..641deafe9ce064515447af55471b3b039c8dae8f 100644 (file)
@@ -142,16 +142,12 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
  *
  *             This does all the necessary work needed to define a new type.
  *
- * NOTE: if assignedTypeOid is not InvalidOid, then that OID is assigned to
- * the new type (which, therefore, cannot already exist as a shell type).
- * This hack is only intended for use in creating a relation's associated
- * type, where we need to have created the relation tuple already.
+ *             Returns the OID assigned to the new type.
  * ----------------------------------------------------------------
  */
 Oid
 TypeCreate(const char *typeName,
                   Oid typeNamespace,
-                  Oid assignedTypeOid,
                   Oid relationOid,             /* only for 'c'atalog types */
                   char relationKind,   /* ditto */
                   int16 internalSize,
@@ -285,10 +281,9 @@ TypeCreate(const char *typeName,
        {
                /*
                 * check that the type is not already defined.  It may exist as a
-                * shell type, however (but only if assignedTypeOid is not given).
+                * shell type, however.
                 */
-               if (((Form_pg_type) GETSTRUCT(tup))->typisdefined ||
-                       assignedTypeOid != InvalidOid)
+               if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
                        ereport(ERROR,
                                        (errcode(ERRCODE_DUPLICATE_OBJECT),
                                         errmsg("type \"%s\" already exists", typeName)));
@@ -314,9 +309,6 @@ TypeCreate(const char *typeName,
                                                         values,
                                                         nulls);
 
-               /* preassign tuple Oid, if one was given */
-               HeapTupleSetOid(tup, assignedTypeOid);
-
                typeObjectId = simple_heap_insert(pg_type_desc, tup);
        }
 
index 0a3fd30d683db61e5d4388df659901525ddc50e9..b763ec3c607dacd7d0c38e6313667c99bbe46edf 100644 (file)
@@ -80,7 +80,7 @@ createdb(const CreatedbStmt *stmt)
        TransactionId src_frozenxid;
        Oid                     src_deftablespace;
        volatile Oid dst_deftablespace;
-       volatile Relation pg_database_rel = NULL;
+       volatile Relation pg_database_rel;
        HeapTuple       tuple;
        TupleDesc       pg_database_dsc;
        Datum           new_record[Natts_pg_database];
@@ -347,9 +347,13 @@ createdb(const CreatedbStmt *stmt)
 
        /*
         * Preassign OID for pg_database tuple, so that we can compute db
-        * path.
+        * path.  We have to open pg_database to do this, but we don't want
+        * to take ExclusiveLock yet, so just do it and close again.
         */
-       dboid = newoid();
+       pg_database_rel = heap_open(DatabaseRelationId, AccessShareLock);
+       dboid = GetNewOid(pg_database_rel);
+       heap_close(pg_database_rel, AccessShareLock);
+       pg_database_rel = NULL;
 
        /*
         * Force dirty buffers out to disk, to ensure source database is
index 2625048b6ff5305a872343cbc7731d7b52888bb5..79f55be9be9c5da1d8d5d06782fb15cdebcbc571 100644 (file)
@@ -184,7 +184,9 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint)
         * Generate the trigger's OID now, so that we can use it in the name
         * if needed.
         */
-       trigoid = newoid();
+       tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
+
+       trigoid = GetNewOid(tgrel);
 
        /*
         * If trigger is an RI constraint, use specified trigger name as
@@ -252,7 +254,6 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint)
         * NOTE that this is cool only because we have AccessExclusiveLock on the
         * relation, so the trigger set won't be changing underneath us.
         */
-       tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
        ScanKeyInit(&key,
                                Anum_pg_trigger_tgrelid,
                                BTEqualStrategyNumber, F_OIDEQ,
index ec48347784f3c2e1cdded86332c02f3983e5d6f8..1af67a4cc036d77d394c77dbed2315e589311095 100644 (file)
@@ -339,7 +339,6 @@ DefineType(List *names, List *parameters)
        typoid =
                TypeCreate(typeName,    /* type name */
                                   typeNamespace,               /* namespace */
-                                  InvalidOid,  /* preassigned type oid (not done here) */
                                   InvalidOid,  /* relation oid (n/a here) */
                                   0,                   /* relation kind (ditto) */
                                   internalLength,              /* internal size */
@@ -372,7 +371,6 @@ DefineType(List *names, List *parameters)
 
        TypeCreate(shadow_type,         /* type name */
                           typeNamespace,       /* namespace */
-                          InvalidOid,          /* preassigned type oid (not done here) */
                           InvalidOid,          /* relation oid (n/a here) */
                           0,                           /* relation kind (ditto) */
                           -1,                          /* internal size */
@@ -724,7 +722,6 @@ DefineDomain(CreateDomainStmt *stmt)
        domainoid =
                TypeCreate(domainName,  /* type name */
                                   domainNamespace,             /* namespace */
-                                  InvalidOid,  /* preassigned type oid (none here) */
                                   InvalidOid,  /* relation oid (n/a here) */
                                   0,                   /* relation kind (ditto) */
                                   internalLength,              /* internal size */
index ab0d074df15cbe6d3a7c9c19276ec463195bd287..aa4d8230ed26a6782d5c8b2782f79fba5e270067 100644 (file)
@@ -177,14 +177,14 @@ inv_create(Oid lobjId)
 {
        /*
         * Allocate an OID to be the LO's identifier, unless we were told
-        * what to use.  In event of collision with an existing ID, loop
-        * to find a free one.
+        * what to use.  We can use the index on pg_largeobject for checking
+        * OID uniqueness, even though it has additional columns besides OID.
         */
        if (!OidIsValid(lobjId))
        {
-               do {
-                       lobjId = newoid();
-               } while (LargeObjectExists(lobjId));
+               open_lo_relation();
+
+               lobjId = GetNewOidWithIndex(lo_heap_r, lo_index_r);
        }
 
        /*
index 216f5a5ee5fa07e5a562758831e459cc8fdb1107..28b56cb7c5d211a0d8322124f7f3caf252d235cf 100644 (file)
@@ -1899,6 +1899,7 @@ AtEOXact_RelationCache(bool isCommit)
                {
                        list_free(relation->rd_indexlist);
                        relation->rd_indexlist = NIL;
+                       relation->rd_oidindex = InvalidOid;
                        relation->rd_indexvalid = 0;
                }
        }
@@ -1959,6 +1960,7 @@ AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
                {
                        list_free(relation->rd_indexlist);
                        relation->rd_indexlist = NIL;
+                       relation->rd_oidindex = InvalidOid;
                        relation->rd_indexvalid = 0;
                }
        }
@@ -2512,6 +2514,11 @@ CheckConstraintFetch(Relation relation)
  * may freeList() the returned list after scanning it. This is necessary
  * since the caller will typically be doing syscache lookups on the relevant
  * indexes, and syscache lookup could cause SI messages to be processed!
+ *
+ * We also update rd_oidindex, which this module treats as effectively part
+ * of the index list.  rd_oidindex is valid when rd_indexvalid isn't zero;
+ * it is the pg_class OID of a unique index on OID when the relation has one,
+ * and InvalidOid if there is no such index.
  */
 List *
 RelationGetIndexList(Relation relation)
@@ -2521,6 +2528,7 @@ RelationGetIndexList(Relation relation)
        ScanKeyData skey;
        HeapTuple       htup;
        List       *result;
+       Oid                     oidIndex;
        MemoryContext oldcxt;
 
        /* Quick exit if we already computed the list. */
@@ -2534,6 +2542,7 @@ RelationGetIndexList(Relation relation)
         * memory leakage if we get some sort of error partway through.
         */
        result = NIL;
+       oidIndex = InvalidOid;
 
        /* Prepare to scan pg_index for entries having indrelid = this rel. */
        ScanKeyInit(&skey,
@@ -2549,7 +2558,16 @@ RelationGetIndexList(Relation relation)
        {
                Form_pg_index index = (Form_pg_index) GETSTRUCT(htup);
 
+               /* Add index's OID to result list in the proper order */
                result = insert_ordered_oid(result, index->indexrelid);
+
+               /* Check to see if it is a unique, non-partial btree index on OID */
+               if (index->indnatts == 1 &&
+                       index->indisunique &&
+                       index->indkey.values[0] == ObjectIdAttributeNumber &&
+                       index->indclass.values[0] == OID_BTREE_OPS_OID &&
+                       heap_attisnull(htup, Anum_pg_index_indpred))
+                       oidIndex = index->indexrelid;
        }
 
        systable_endscan(indscan);
@@ -2558,6 +2576,7 @@ RelationGetIndexList(Relation relation)
        /* Now save a copy of the completed list in the relcache entry. */
        oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
        relation->rd_indexlist = list_copy(result);
+       relation->rd_oidindex = oidIndex;
        relation->rd_indexvalid = 1;
        MemoryContextSwitchTo(oldcxt);
 
@@ -2601,8 +2620,8 @@ insert_ordered_oid(List *list, Oid datum)
  * RelationSetIndexList -- externally force the index list contents
  *
  * This is used to temporarily override what we think the set of valid
- * indexes is. The forcing will be valid only until transaction commit
- * or abort.
+ * indexes is (including the presence or absence of an OID index).
+ * The forcing will be valid only until transaction commit or abort.
  *
  * This should only be applied to nailed relations, because in a non-nailed
  * relation the hacked index list could be lost at any time due to SI
@@ -2611,7 +2630,7 @@ insert_ordered_oid(List *list, Oid datum)
  * It is up to the caller to make sure the given list is correctly ordered.
  */
 void
-RelationSetIndexList(Relation relation, List *indexIds)
+RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex)
 {
        MemoryContext oldcxt;
 
@@ -2623,11 +2642,40 @@ RelationSetIndexList(Relation relation, List *indexIds)
        /* Okay to replace old list */
        list_free(relation->rd_indexlist);
        relation->rd_indexlist = indexIds;
+       relation->rd_oidindex = oidIndex;
        relation->rd_indexvalid = 2;    /* mark list as forced */
        /* must flag that we have a forced index list */
        need_eoxact_work = true;
 }
 
+/*
+ * RelationGetOidIndex -- get the pg_class OID of the relation's OID index
+ *
+ * Returns InvalidOid if there is no such index.
+ */
+Oid
+RelationGetOidIndex(Relation relation)
+{
+       List       *ilist;
+
+       /*
+        * If relation doesn't have OIDs at all, caller is probably confused.
+        * (We could just silently return InvalidOid, but it seems better to
+        * throw an assertion.)
+        */
+       Assert(relation->rd_rel->relhasoids);
+
+       if (relation->rd_indexvalid == 0)
+       {
+               /* RelationGetIndexList does the heavy lifting. */
+               ilist = RelationGetIndexList(relation);
+               list_free(ilist);
+               Assert(relation->rd_indexvalid != 0);
+       }
+
+       return relation->rd_oidindex;
+}
+
 /*
  * RelationGetIndexExpressions -- get the index expressions for an index
  *
@@ -3057,6 +3105,7 @@ load_relcache_init_file(void)
                        rel->rd_refcnt = 0;
                rel->rd_indexvalid = 0;
                rel->rd_indexlist = NIL;
+               rel->rd_oidindex = InvalidOid;
                rel->rd_createSubid = InvalidSubTransactionId;
                MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
 
index 90cff1e4693fac0db2975d0043a4706363dedbd5..fcde31efc138bef3e46bbad8454310d564e68079 100644 (file)
@@ -1962,11 +1962,11 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
        }
 
        /*
-        * Special case: <Init> type with <Max OID> tag; this is part of a
-        * DATA restore even though it has SQL.
+        * Special case: <Init> type with <Max OID> tag; this is obsolete
+        * and we always ignore it.
         */
        if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
-               res = REQ_DATA;
+               return 0;
 
        /* Mask it if we only want schema */
        if (ropt->schemaOnly)
index 3baac73d0a7c2a01aa137983b55256ae35c1c5fd..906775d857314ed7b910b2088718b12499da7780 100644 (file)
@@ -158,7 +158,6 @@ static const char *convertRegProcReference(const char *proc);
 static const char *convertOperatorReference(const char *opr);
 static Oid     findLastBuiltinOid_V71(const char *);
 static Oid     findLastBuiltinOid_V70(void);
-static void setMaxOid(Archive *fout);
 static void selectSourceSchema(const char *schemaName);
 static char *getFormattedTypeName(Oid oid, OidOptions opts);
 static char *myFormatType(const char *typname, int32 typmod);
@@ -611,10 +610,6 @@ main(int argc, char **argv)
        if (!dataOnly)
                dumpDatabase(g_fout);
 
-       /* Max OID is next. */
-       if (oids == true)
-               setMaxOid(g_fout);
-
        /* Now the rearrangeable objects. */
        for (i = 0; i < numObjs; i++)
                dumpDumpableObject(g_fout, dobjs[i]);
@@ -7408,51 +7403,6 @@ dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
        destroyPQExpBuffer(q);
 }
 
-/*
- * setMaxOid -
- * find the maximum oid and generate a COPY statement to set it
- */
-static void
-setMaxOid(Archive *fout)
-{
-       PGresult   *res;
-       Oid                     max_oid;
-       char            sql[1024];
-
-       if (fout->remoteVersion >= 70200)
-               do_sql_command(g_conn,
-                                          "CREATE TEMPORARY TABLE pgdump_oid (dummy integer) WITH OIDS");
-       else
-               do_sql_command(g_conn,
-                                          "CREATE TEMPORARY TABLE pgdump_oid (dummy integer)");
-       res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
-       check_sql_result(res, g_conn, "INSERT INTO pgdump_oid VALUES (0)",
-                                        PGRES_COMMAND_OK);
-       max_oid = PQoidValue(res);
-       if (max_oid == 0)
-       {
-               write_msg(NULL, "inserted invalid OID\n");
-               exit_nicely();
-       }
-       PQclear(res);
-       do_sql_command(g_conn, "DROP TABLE pgdump_oid;");
-       if (g_verbose)
-               write_msg(NULL, "maximum system OID is %u\n", max_oid);
-       snprintf(sql, sizeof(sql),
-                        "CREATE TEMPORARY TABLE pgdump_oid (dummy integer) WITH OIDS;\n"
-                        "COPY pgdump_oid WITH OIDS FROM stdin;\n"
-                        "%u\t0\n"
-                        "\\.\n"
-                        "DROP TABLE pgdump_oid;\n",
-                        max_oid);
-
-       ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                "Max OID", NULL, NULL, "",
-                                false, "<Init>", sql, "", NULL,
-                                NULL, 0,
-                                NULL, NULL);
-}
-
 /*
  * findLastBuiltInOid -
  * find the last built in oid
index 41a7373c58df624797c6eddcc4052b0c75840041..44ea336d2740419d1a9b8c32d281d4538073871c 100644 (file)
@@ -126,6 +126,5 @@ extern TransactionId ReadNewTransactionId(void);
 extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
                                                                  Name oldest_datname);
 extern Oid     GetNewObjectId(void);
-extern void CheckMaxObjectId(Oid assigned_oid);
 
 #endif   /* TRAMSAM_H */
index 869cb4ad743d63664f7637e4b7e256251d5e1244..2e3c32aee49eaf0f1b9d7512ac198e68eb226563 100644 (file)
@@ -31,6 +31,9 @@ extern bool IsToastNamespace(Oid namespaceId);
 
 extern bool IsReservedName(const char *name);
 
-extern Oid     newoid(void);
+extern Oid     GetNewOid(Relation relation);
+extern Oid     GetNewOidWithIndex(Relation relation, Relation indexrel);
+extern Oid     GetNewRelFileNode(Oid reltablespace, bool relisshared,
+                                                         Relation pg_class);
 
 #endif   /* CATALOG_H */
index e820bfafc45d7ca7c6ab98de8c3fb002b80ab355..475ab0e1302a173883f1a4ebf5a7841f416eaba0 100644 (file)
@@ -556,7 +556,6 @@ extern Oid  TypeShellMake(const char *typeName, Oid typeNamespace);
 
 extern Oid TypeCreate(const char *typeName,
                   Oid typeNamespace,
-                  Oid assignedTypeOid,
                   Oid relationOid,
                   char relationKind,
                   int16 internalSize,
index 24eae48104bf22ad2aa934bbe37053c93f231a42..df9dfea68e5239f3d28a33fb422cae8bf1160d93 100644 (file)
@@ -136,8 +136,8 @@ typedef struct RelationData
        bool            rd_istemp;              /* rel uses the local buffer mgr */
        bool            rd_isnailed;    /* rel is nailed in cache */
        bool            rd_isvalid;             /* relcache entry is valid */
-       char            rd_indexvalid;  /* state of rd_indexlist: 0 = not valid, 1
-                                                                * = valid, 2 = temporarily forced */
+       char            rd_indexvalid;  /* state of rd_indexlist: 0 = not valid,
+                                                                * = valid, 2 = temporarily forced */
        SubTransactionId rd_createSubid;        /* rel was created in current xact */
 
        /*
@@ -151,6 +151,7 @@ typedef struct RelationData
        TupleDesc       rd_att;                 /* tuple descriptor */
        Oid                     rd_id;                  /* relation's object id */
        List       *rd_indexlist;       /* list of OIDs of indexes on relation */
+       Oid                     rd_oidindex;    /* OID of unique index on OID, if any */
        LockInfoData rd_lockInfo;       /* lock mgr's info for locking relation */
        RuleLock   *rd_rules;           /* rewrite rules */
        MemoryContext rd_rulescxt;      /* private memory cxt for rd_rules, if any */
index e4690998e241e39b97451b69c3f05c724cc4ca36..25775e46437f48117dcbfc69246cab83ebd11369 100644 (file)
@@ -30,10 +30,12 @@ extern void RelationClose(Relation relation);
  * Routines to compute/retrieve additional cached information
  */
 extern List *RelationGetIndexList(Relation relation);
+extern Oid     RelationGetOidIndex(Relation relation);
 extern List *RelationGetIndexExpressions(Relation relation);
 extern List *RelationGetIndexPredicate(Relation relation);
 
-extern void RelationSetIndexList(Relation relation, List *indexIds);
+extern void RelationSetIndexList(Relation relation,
+                                                                List *indexIds, Oid oidIndex);
 
 extern void RelationInitIndexAccessInfo(Relation relation);