Solve the problem of OID collisions by probing for duplicate OIDs

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.
This commit is contained in:
Tom Lane 2005-08-12 01:36:05 +00:00
parent 9e4a2de844
commit 721e53785d
20 changed files with 416 additions and 268 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.42 2005/07/14 06:17:35 neilc Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.43 2005/08/12 01:35:53 tgl Exp $ -->
<chapter id="ddl">
<title>Data Definition</title>
@ -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>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.196 2005/08/01 20:31:05 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.197 2005/08/12 01:35:54 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -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
{

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.51 2005/08/02 16:11:57 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.52 2005/08/12 01:35:54 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -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);
/*

View File

@ -6,7 +6,7 @@
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.64 2005/05/19 21:35:45 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.65 2005/08/12 01:35:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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);
}

View File

@ -9,18 +9,25 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.62 2005/07/04 04:51:45 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.63 2005/08/12 01:35:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#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.
*
* Object Id allocation is now done by GetNewObjectID in
* access/transam/varsup.
* Caller must have a suitable lock on the relation.
*
* This code probably needs to change to generate OIDs separately
* for each table.
* 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
newoid(void)
GetNewOid(Relation relation)
{
return GetNewObjectId();
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.
*
* As with GetNewOid, there is some theoretical risk of a race condition,
* but it doesn't seem worth worrying about.
*
* Note: we don't support using this in bootstrap mode. All relations
* created by bootstrap have preassigned OIDs, so there's no need.
*/
Oid
GetNewRelFileNode(Oid reltablespace, bool relisshared, Relation pg_class)
{
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;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.288 2005/07/28 07:38:33 neilc Exp $
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.289 2005/08/12 01:35:56 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -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,26 +715,7 @@ 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);
/* Assign an OID for the relation's tuple type */
new_type_oid = newoid();
/*
* now create an entry in pg_class for the relation.
*
* NOTE: we could get a unique-index failure here, in case someone else
* 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,
new_type_oid,
relkind);
Assert(relid == RelationGetRelid(new_rel_desc));
/*
* since defining a relation also defines a complex type, we add a new
@ -738,17 +724,29 @@ heap_create_with_catalog(const char *relname,
* 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);
new_type_oid = AddNewRelationType(relname,
relnamespace,
relid,
relkind);
/*
* now create an entry in pg_class for the relation.
*
* NOTE: we could get a unique-index failure here, in case someone else
* is creating the same relation name in parallel but hadn't committed
* yet when we checked for a duplicate name above.
*/
AddNewRelationTuple(pg_class_desc,
new_rel_desc,
relid,
new_type_oid,
relkind);
/*
* 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;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.258 2005/06/25 16:53:49 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.259 2005/08/12 01:35:56 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -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.

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.102 2005/07/07 20:39:57 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.103 2005/08/12 01:35:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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);
}

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.169 2005/08/02 19:02:31 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.170 2005/08/12 01:35:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.190 2005/08/01 20:31:07 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.191 2005/08/12 01:35:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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,

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.78 2005/08/04 01:09:28 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.79 2005/08/12 01:35:58 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@ -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 */

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.111 2005/06/13 02:26:49 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.112 2005/08/12 01:35:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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);
}
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.226 2005/08/08 19:17:22 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.227 2005/08/12 01:35:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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));

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.111 2005/06/21 20:45:44 tgl Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.112 2005/08/12 01:35:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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)

View File

@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.415 2005/07/10 15:08:52 momjian Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.416 2005/08/12 01:36:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/access/transam.h,v 1.54 2005/04/13 18:54:57 tgl Exp $
* $PostgreSQL: pgsql/src/include/access/transam.h,v 1.55 2005/08/12 01:36:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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 */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.32 2005/05/10 22:27:30 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.33 2005/08/12 01:36:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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 */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.164 2005/07/20 16:42:32 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.165 2005/08/12 01:36:04 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -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,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.84 2005/05/27 23:31:21 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.85 2005/08/12 01:36:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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,
* 1 = 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 */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/relcache.h,v 1.50 2005/04/14 20:03:27 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/relcache.h,v 1.51 2005/08/12 01:36:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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);