diff --git a/doc/src/sgml/bki.sgml b/doc/src/sgml/bki.sgml
index db1b3d5e9a0..f32208b5504 100644
--- a/doc/src/sgml/bki.sgml
+++ b/doc/src/sgml/bki.sgml
@@ -418,19 +418,33 @@
If genbki.pl needs to assign an OID to a catalog
entry that does not have a manually-assigned OID, it will use a value in
- the range 10000—11999. The server's OID counter is set to 12000
- at the start of a bootstrap run. Thus objects created by regular SQL
- commands during the later phases of bootstrap, such as objects created
- while running the information_schema.sql script,
- receive OIDs of 12000 or above.
+ the range 10000—11999. The server's OID counter is set to 10000
+ at the start of a bootstrap run, so that any objects created on-the-fly
+ during bootstrap processing also receive OIDs in this range. (The
+ usual OID assignment mechanism takes care of preventing any conflicts.)
+
+
+
+ Objects with OIDs below FirstUnpinnedObjectId (12000)
+ are considered pinned, preventing them from being
+ deleted. (There are a small number of exceptions, which are
+ hard-wired into IsPinnedObject().)
+ initdb forces the OID counter up
+ to FirstUnpinnedObjectId as soon as it's ready to
+ create unpinned objects. Thus objects created during the later phases
+ of initdb, such as objects created while
+ running the information_schema.sql script, will
+ not be pinned, while all objects known
+ to genbki.pl will be.
OIDs assigned during normal database operation are constrained to be
16384 or higher. This ensures that the range 10000—16383 is free
for OIDs assigned automatically by genbki.pl or
- during bootstrap. These automatically-assigned OIDs are not considered
- stable, and may change from one installation to another.
+ during initdb. These
+ automatically-assigned OIDs are not considered stable, and may change
+ from one installation to another.
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 0f5d25b948a..5128f34d407 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -3264,8 +3264,7 @@ SCRAM-SHA-256$<iteration count>:&l
(references pg_class.oid)
- The OID of the system catalog the dependent object is in,
- or zero for a DEPENDENCY_PIN entry
+ The OID of the system catalog the dependent object is in
@@ -3275,8 +3274,7 @@ SCRAM-SHA-256$<iteration count>:&l
(references any OID column)
- The OID of the specific dependent object,
- or zero for a DEPENDENCY_PIN entry
+ The OID of the specific dependent object
@@ -3467,19 +3465,6 @@ SCRAM-SHA-256$<iteration count>:&l
-
-
- DEPENDENCY_PIN (p)
-
-
- There is no dependent object; this type of entry is a signal
- that the system itself depends on the referenced object, and so
- that object must never be deleted. Entries of this type are
- created only by initdb. The columns for the
- dependent object contain zeroes.
-
-
-
Other dependency flavors might be needed in future.
@@ -3498,6 +3483,19 @@ SCRAM-SHA-256$<iteration count>:&l
must be satisfied.
+
+ Most objects created during initdb are
+ considered pinned, which means that the system itself
+ depends on them. Therefore, they are never allowed to be dropped.
+ Also, knowing that pinned objects will not be dropped, the dependency
+ mechanism doesn't bother to make pg_depend
+ entries showing dependencies on them. Thus, for example, a table
+ column of type numeric notionally has
+ a NORMAL dependency on the numeric
+ data type, but no such entry actually appears
+ in pg_depend.
+
+
@@ -6779,7 +6777,6 @@ SCRAM-SHA-256$<iteration count>:&l
The OID of the database the dependent object is in,
or zero for a shared object
- or a SHARED_DEPENDENCY_PIN entry
@@ -6789,8 +6786,7 @@ SCRAM-SHA-256$<iteration count>:&l
(references pg_class.oid)
- The OID of the system catalog the dependent object is in,
- or zero for a SHARED_DEPENDENCY_PIN entry
+ The OID of the system catalog the dependent object is in
@@ -6800,8 +6796,7 @@ SCRAM-SHA-256$<iteration count>:&l
(references any OID column)
- The OID of the specific dependent object,
- or zero for a SHARED_DEPENDENCY_PIN entry
+ The OID of the specific dependent object
@@ -6889,19 +6884,6 @@ SCRAM-SHA-256$<iteration count>:&l
-
- SHARED_DEPENDENCY_PIN (p)
-
-
- There is no dependent object; this type of entry is a signal
- that the system itself depends on the referenced object, and so
- that object must never be deleted. Entries of this type are
- created only by initdb. The columns for the
- dependent object contain zeroes.
-
-
-
-
SHARED_DEPENDENCY_TABLESPACE (t)
@@ -6918,6 +6900,14 @@ SCRAM-SHA-256$<iteration count>:&l
objects.
+
+ As in the pg_depend catalog, most objects
+ created during initdb are
+ considered pinned. No entries are made
+ in pg_shdepend that would have a pinned
+ object as either referenced or dependent object.
+
+
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index a22bf375f85..5b4898bb786 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -541,11 +541,11 @@ GetNewObjectId(void)
* FirstNormalObjectId since that range is reserved for initdb (see
* IsCatalogRelationOid()). Note we are relying on unsigned comparison.
*
- * During initdb, we start the OID generator at FirstBootstrapObjectId, so
- * we only wrap if before that point when in bootstrap or standalone mode.
+ * During initdb, we start the OID generator at FirstGenbkiObjectId, so we
+ * only wrap if before that point when in bootstrap or standalone mode.
* The first time through this routine after normal postmaster start, the
* counter will be forced up to FirstNormalObjectId. This mechanism
- * leaves the OIDs between FirstBootstrapObjectId and FirstNormalObjectId
+ * leaves the OIDs between FirstGenbkiObjectId and FirstNormalObjectId
* available for automatic assignment during initdb, while ensuring they
* will never conflict with user-assigned OIDs.
*/
@@ -560,7 +560,7 @@ GetNewObjectId(void)
else
{
/* we may be bootstrapping, so don't enforce the full range */
- if (ShmemVariableCache->nextOid < ((Oid) FirstBootstrapObjectId))
+ if (ShmemVariableCache->nextOid < ((Oid) FirstGenbkiObjectId))
{
/* wraparound in standalone mode (unlikely but possible) */
ShmemVariableCache->nextOid = FirstNormalObjectId;
@@ -586,6 +586,47 @@ GetNewObjectId(void)
return result;
}
+/*
+ * SetNextObjectId
+ *
+ * This may only be called during initdb; it advances the OID counter
+ * to the specified value.
+ */
+static void
+SetNextObjectId(Oid nextOid)
+{
+ /* Safety check, this is only allowable during initdb */
+ if (IsPostmasterEnvironment)
+ elog(ERROR, "cannot advance OID counter anymore");
+
+ /* Taking the lock is, therefore, just pro forma; but do it anyway */
+ LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
+
+ if (ShmemVariableCache->nextOid > nextOid)
+ elog(ERROR, "too late to advance OID counter to %u, it is now %u",
+ nextOid, ShmemVariableCache->nextOid);
+
+ ShmemVariableCache->nextOid = nextOid;
+ ShmemVariableCache->oidCount = 0;
+
+ LWLockRelease(OidGenLock);
+}
+
+/*
+ * StopGeneratingPinnedObjectIds
+ *
+ * This is called once during initdb to force the OID counter up to
+ * FirstUnpinnedObjectId. This supports letting initdb's post-bootstrap
+ * processing create some pinned objects early on. Once it's done doing
+ * so, it calls this (via pg_stop_making_pinned_objects()) so that the
+ * remaining objects it makes will be considered un-pinned.
+ */
+void
+StopGeneratingPinnedObjectIds(void)
+{
+ SetNextObjectId(FirstUnpinnedObjectId);
+}
+
#ifdef USE_ASSERT_CHECKING
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c7c928f50bd..edb15fe58d2 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -5318,7 +5318,7 @@ BootStrapXLOG(void)
checkPoint.fullPageWrites = fullPageWrites;
checkPoint.nextXid =
FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId);
- checkPoint.nextOid = FirstBootstrapObjectId;
+ checkPoint.nextOid = FirstGenbkiObjectId;
checkPoint.nextMulti = FirstMultiXactId;
checkPoint.nextMultiOffset = 0;
checkPoint.oldestXid = FirstNormalTransactionId;
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index 7cabe741c66..aa7d4d5456b 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -31,6 +31,7 @@
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
#include "catalog/pg_db_role_setting.h"
+#include "catalog/pg_largeobject.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_replication_origin.h"
#include "catalog/pg_shdepend.h"
@@ -120,9 +121,9 @@ bool
IsCatalogRelationOid(Oid relid)
{
/*
- * We consider a relation to be a system catalog if it has an OID that was
- * manually assigned or assigned by genbki.pl. This includes all the
- * defined catalogs, their indexes, and their TOAST tables and indexes.
+ * We consider a relation to be a system catalog if it has a pinned OID.
+ * This includes all the defined catalogs, their indexes, and their TOAST
+ * tables and indexes.
*
* This rule excludes the relations in information_schema, which are not
* integral to the system and can be treated the same as user relations.
@@ -132,7 +133,7 @@ IsCatalogRelationOid(Oid relid)
* This test is reliable since an OID wraparound will skip this range of
* OIDs; see GetNewObjectId().
*/
- return (relid < (Oid) FirstBootstrapObjectId);
+ return (relid < (Oid) FirstUnpinnedObjectId);
}
/*
@@ -294,6 +295,64 @@ IsSharedRelation(Oid relationId)
return false;
}
+/*
+ * IsPinnedObject
+ * Given the class + OID identity of a database object, report whether
+ * it is "pinned", that is not droppable because the system requires it.
+ *
+ * We used to represent this explicitly in pg_depend, but that proved to be
+ * an undesirable amount of overhead, so now we rely on an OID range test.
+ */
+bool
+IsPinnedObject(Oid classId, Oid objectId)
+{
+ /*
+ * Objects with OIDs above FirstUnpinnedObjectId are never pinned. Since
+ * the OID generator skips this range when wrapping around, this check
+ * guarantees that user-defined objects are never considered pinned.
+ */
+ if (objectId >= FirstUnpinnedObjectId)
+ return false;
+
+ /*
+ * Large objects are never pinned. We need this special case because
+ * their OIDs can be user-assigned.
+ */
+ if (classId == LargeObjectRelationId)
+ return false;
+
+ /*
+ * There are a few objects defined in the catalog .dat files that, as a
+ * matter of policy, we prefer not to treat as pinned. We used to handle
+ * that by excluding them from pg_depend, but it's just as easy to
+ * hard-wire their OIDs here. (If the user does indeed drop and recreate
+ * them, they'll have new but certainly-unpinned OIDs, so no problem.)
+ *
+ * Checking both classId and objectId is overkill, since OIDs below
+ * FirstGenbkiObjectId should be globally unique, but do it anyway for
+ * robustness.
+ */
+
+ /* template1 is not pinned */
+ if (classId == DatabaseRelationId &&
+ objectId == TemplateDbOid)
+ return false;
+
+ /* the public namespace is not pinned */
+ if (classId == NamespaceRelationId &&
+ objectId == PG_PUBLIC_NAMESPACE)
+ return false;
+
+ /*
+ * All other initdb-created objects are pinned. This is overkill (the
+ * system doesn't really depend on having every last weird datatype, for
+ * instance) but generating only the minimum required set of dependencies
+ * seems hard, and enforcing an accurate list would be much more expensive
+ * than the simple range test used here.
+ */
+ return true;
+}
+
/*
* GetNewOidWithIndex
@@ -533,7 +592,8 @@ pg_nextoid(PG_FUNCTION_ARGS)
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to call pg_nextoid()")));
+ errmsg("must be superuser to call %s()",
+ "pg_nextoid")));
rel = table_open(reloid, RowExclusiveLock);
idx = index_open(idxoid, RowExclusiveLock);
@@ -580,5 +640,29 @@ pg_nextoid(PG_FUNCTION_ARGS)
table_close(rel, RowExclusiveLock);
index_close(idx, RowExclusiveLock);
- return newoid;
+ PG_RETURN_OID(newoid);
+}
+
+/*
+ * SQL callable interface for StopGeneratingPinnedObjectIds().
+ *
+ * This is only to be used by initdb, so it's intentionally not documented in
+ * the user facing docs.
+ */
+Datum
+pg_stop_making_pinned_objects(PG_FUNCTION_ARGS)
+{
+ /*
+ * Belt-and-suspenders check, since StopGeneratingPinnedObjectIds will
+ * fail anyway in non-single-user mode.
+ */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to call %s()",
+ "pg_stop_making_pinned_objects")));
+
+ StopGeneratingPinnedObjectIds();
+
+ PG_RETURN_VOID();
}
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 0c37fc1d53f..76b65e39c44 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -18,6 +18,7 @@
#include "access/htup_details.h"
#include "access/table.h"
#include "access/xact.h"
+#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
@@ -520,6 +521,16 @@ findDependentObjects(const ObjectAddress *object,
if (object_address_present_add_flags(object, objflags, targetObjects))
return;
+ /*
+ * If the target object is pinned, we can just error out immediately; it
+ * won't have any objects recorded as depending on it.
+ */
+ if (IsPinnedObject(object->classId, object->objectId))
+ ereport(ERROR,
+ (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
+ errmsg("cannot drop %s because it is required by the database system",
+ getObjectDescription(object, false))));
+
/*
* The target object might be internally dependent on some other object
* (its "owner"), and/or be a member of an extension (also considered its
@@ -783,15 +794,6 @@ findDependentObjects(const ObjectAddress *object,
objflags |= DEPFLAG_IS_PART;
break;
- case DEPENDENCY_PIN:
-
- /*
- * Should not happen; PIN dependencies should have zeroes in
- * the depender fields...
- */
- elog(ERROR, "incorrect use of PIN dependency with %s",
- getObjectDescription(object, false));
- break;
default:
elog(ERROR, "unrecognized dependency type '%c' for %s",
foundDep->deptype, getObjectDescription(object, false));
@@ -920,18 +922,6 @@ findDependentObjects(const ObjectAddress *object,
case DEPENDENCY_EXTENSION:
subflags = DEPFLAG_EXTENSION;
break;
- case DEPENDENCY_PIN:
-
- /*
- * For a PIN dependency we just ereport immediately; there
- * won't be any others to report.
- */
- ereport(ERROR,
- (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
- errmsg("cannot drop %s because it is required by the database system",
- getObjectDescription(object, false))));
- subflags = 0; /* keep compiler quiet */
- break;
default:
elog(ERROR, "unrecognized dependency type '%c' for %s",
foundDep->deptype, getObjectDescription(object, false));
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index b82df348b8d..70987b14876 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -170,14 +170,14 @@ die "found $found duplicate OID(s) in catalog data\n" if $found;
# OIDs not specified in the input files are automatically assigned,
-# starting at FirstGenbkiObjectId, extending up to FirstBootstrapObjectId.
+# starting at FirstGenbkiObjectId, extending up to FirstUnpinnedObjectId.
# We allow such OIDs to be assigned independently within each catalog.
my $FirstGenbkiObjectId =
Catalog::FindDefinedSymbol('access/transam.h', $include_path,
'FirstGenbkiObjectId');
-my $FirstBootstrapObjectId =
+my $FirstUnpinnedObjectId =
Catalog::FindDefinedSymbol('access/transam.h', $include_path,
- 'FirstBootstrapObjectId');
+ 'FirstUnpinnedObjectId');
# Hash of next available OID, indexed by catalog name.
my %GenbkiNextOids;
@@ -1101,8 +1101,8 @@ sub assign_next_oid
# Check that we didn't overrun available OIDs
die
- "genbki OID counter for $catname reached $result, overrunning FirstBootstrapObjectId\n"
- if $result >= $FirstBootstrapObjectId;
+ "genbki OID counter for $catname reached $result, overrunning FirstUnpinnedObjectId\n"
+ if $result >= $FirstUnpinnedObjectId;
return $result;
}
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index 54688094f58..10f31196700 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -17,6 +17,7 @@
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/table.h"
+#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_constraint.h"
@@ -29,7 +30,7 @@
#include "utils/rel.h"
-static bool isObjectPinned(const ObjectAddress *object, Relation rel);
+static bool isObjectPinned(const ObjectAddress *object);
/*
@@ -69,8 +70,11 @@ recordMultipleDependencies(const ObjectAddress *depender,
return; /* nothing to do */
/*
- * During bootstrap, do nothing since pg_depend may not exist yet. initdb
- * will fill in appropriate pg_depend entries after bootstrap.
+ * During bootstrap, do nothing since pg_depend may not exist yet.
+ *
+ * Objects created during bootstrap are most likely pinned, and the few
+ * that are not do not have dependencies on each other, so that there
+ * would be no need to make a pg_depend entry anyway.
*/
if (IsBootstrapProcessingMode())
return;
@@ -99,7 +103,7 @@ recordMultipleDependencies(const ObjectAddress *depender,
* need to record dependencies on it. This saves lots of space in
* pg_depend, so it's worth the time taken to check.
*/
- if (isObjectPinned(referenced, dependDesc))
+ if (isObjectPinned(referenced))
continue;
if (slot_init_count < max_slots)
@@ -399,8 +403,6 @@ changeDependencyFor(Oid classId, Oid objectId,
bool oldIsPinned;
bool newIsPinned;
- depRel = table_open(DependRelationId, RowExclusiveLock);
-
/*
* Check to see if either oldRefObjectId or newRefObjectId is pinned.
* Pinned objects should not have any dependency entries pointing to them,
@@ -411,16 +413,14 @@ changeDependencyFor(Oid classId, Oid objectId,
objAddr.objectId = oldRefObjectId;
objAddr.objectSubId = 0;
- oldIsPinned = isObjectPinned(&objAddr, depRel);
+ oldIsPinned = isObjectPinned(&objAddr);
objAddr.objectId = newRefObjectId;
- newIsPinned = isObjectPinned(&objAddr, depRel);
+ newIsPinned = isObjectPinned(&objAddr);
if (oldIsPinned)
{
- table_close(depRel, RowExclusiveLock);
-
/*
* If both are pinned, we need do nothing. However, return 1 not 0,
* else callers will think this is an error case.
@@ -440,6 +440,8 @@ changeDependencyFor(Oid classId, Oid objectId,
return 1;
}
+ depRel = table_open(DependRelationId, RowExclusiveLock);
+
/* There should be existing dependency record(s), so search. */
ScanKeyInit(&key[0],
Anum_pg_depend_classid,
@@ -574,7 +576,7 @@ changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
objAddr.objectId = oldRefObjectId;
objAddr.objectSubId = 0;
- if (isObjectPinned(&objAddr, depRel))
+ if (isObjectPinned(&objAddr))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot remove dependency on %s because it is a system object",
@@ -586,7 +588,7 @@ changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
*/
objAddr.objectId = newRefObjectId;
- newIsPinned = isObjectPinned(&objAddr, depRel);
+ newIsPinned = isObjectPinned(&objAddr);
/* Now search for dependency records */
ScanKeyInit(&key[0],
@@ -634,50 +636,14 @@ changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
* isObjectPinned()
*
* Test if an object is required for basic database functionality.
- * Caller must already have opened pg_depend.
*
* The passed subId, if any, is ignored; we assume that only whole objects
* are pinned (and that this implies pinning their components).
*/
static bool
-isObjectPinned(const ObjectAddress *object, Relation rel)
+isObjectPinned(const ObjectAddress *object)
{
- bool ret = false;
- SysScanDesc scan;
- HeapTuple tup;
- ScanKeyData key[2];
-
- ScanKeyInit(&key[0],
- Anum_pg_depend_refclassid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->classId));
-
- ScanKeyInit(&key[1],
- Anum_pg_depend_refobjid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
-
- scan = systable_beginscan(rel, DependReferenceIndexId, true,
- NULL, 2, key);
-
- /*
- * Since we won't generate additional pg_depend entries for pinned
- * objects, there can be at most one entry referencing a pinned object.
- * Hence, it's sufficient to look at the first returned tuple; we don't
- * need to loop.
- */
- tup = systable_getnext(scan);
- if (HeapTupleIsValid(tup))
- {
- Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
-
- if (foundDep->deptype == DEPENDENCY_PIN)
- ret = true;
- }
-
- systable_endscan(scan);
-
- return ret;
+ return IsPinnedObject(object->classId, object->objectId);
}
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 86e415af892..36bfff97069 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -85,7 +85,7 @@ check_publication_add_relation(Relation targetrel)
* XXX This also excludes all tables with relid < FirstNormalObjectId,
* ie all tables created during initdb. This mainly affects the preinstalled
* information_schema. IsCatalogRelationOid() only excludes tables with
- * relid < FirstBootstrapObjectId, making that test rather redundant,
+ * relid < FirstUnpinnedObjectId, making that test rather redundant,
* but really we should get rid of the FirstNormalObjectId test not
* IsCatalogRelationOid. We can't do so today because we don't want
* information_schema tables to be considered publishable; but this test
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 420ad965653..4b676f56078 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -101,7 +101,6 @@ static void storeObjectDescription(StringInfo descs,
ObjectAddress *object,
SharedDependencyType deptype,
int count);
-static bool isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel);
/*
@@ -140,8 +139,7 @@ recordSharedDependencyOn(ObjectAddress *depender,
sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
/* If the referenced object is pinned, do nothing. */
- if (!isSharedObjectPinned(referenced->classId, referenced->objectId,
- sdepRel))
+ if (!IsPinnedObject(referenced->classId, referenced->objectId))
{
shdepAddDependency(sdepRel, depender->classId, depender->objectId,
depender->objectSubId,
@@ -255,7 +253,7 @@ shdepChangeDep(Relation sdepRel,
systable_endscan(scan);
- if (isSharedObjectPinned(refclassid, refobjid, sdepRel))
+ if (IsPinnedObject(refclassid, refobjid))
{
/* No new entry needed, so just delete existing entry if any */
if (oldtup)
@@ -513,7 +511,7 @@ updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
continue;
/* Skip pinned roles; they don't need dependency entries */
- if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
+ if (IsPinnedObject(AuthIdRelationId, roleid))
continue;
shdepAddDependency(sdepRel, classId, objectId, objsubId,
@@ -531,7 +529,7 @@ updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
continue;
/* Skip pinned roles */
- if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
+ if (IsPinnedObject(AuthIdRelationId, roleid))
continue;
shdepDropDependency(sdepRel, classId, objectId, objsubId,
@@ -626,8 +624,6 @@ shared_dependency_comparator(const void *a, const void *b)
* on objects local to other databases. We can (and do) provide descriptions
* of the two former kinds of objects, but we can't do that for "remote"
* objects, so we just provide a count of them.
- *
- * If we find a SHARED_DEPENDENCY_PIN entry, we can error out early.
*/
bool
checkSharedDependencies(Oid classId, Oid objectId,
@@ -649,6 +645,18 @@ checkSharedDependencies(Oid classId, Oid objectId,
StringInfoData descs;
StringInfoData alldescs;
+ /* This case can be dispatched quickly */
+ if (IsPinnedObject(classId, objectId))
+ {
+ object.classId = classId;
+ object.objectId = objectId;
+ object.objectSubId = 0;
+ ereport(ERROR,
+ (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
+ errmsg("cannot drop %s because it is required by the database system",
+ getObjectDescription(&object, false))));
+ }
+
/*
* We limit the number of dependencies reported to the client to
* MAX_REPORTED_DEPS, since client software may not deal well with
@@ -685,18 +693,6 @@ checkSharedDependencies(Oid classId, Oid objectId,
{
Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
- /* This case can be dispatched quickly */
- if (sdepForm->deptype == SHARED_DEPENDENCY_PIN)
- {
- object.classId = classId;
- object.objectId = objectId;
- object.objectSubId = 0;
- ereport(ERROR,
- (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
- errmsg("cannot drop %s because it is required by the database system",
- getObjectDescription(&object, false))));
- }
-
object.classId = sdepForm->classid;
object.objectId = sdepForm->objid;
object.objectSubId = sdepForm->objsubid;
@@ -1272,53 +1268,6 @@ storeObjectDescription(StringInfo descs,
}
-/*
- * isSharedObjectPinned
- * Return whether a given shared object has a SHARED_DEPENDENCY_PIN entry.
- *
- * sdepRel must be the pg_shdepend relation, already opened and suitably
- * locked.
- */
-static bool
-isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel)
-{
- bool result = false;
- ScanKeyData key[2];
- SysScanDesc scan;
- HeapTuple tup;
-
- ScanKeyInit(&key[0],
- Anum_pg_shdepend_refclassid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(classId));
- ScanKeyInit(&key[1],
- Anum_pg_shdepend_refobjid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(objectId));
-
- scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
- NULL, 2, key);
-
- /*
- * Since we won't generate additional pg_shdepend entries for pinned
- * objects, there can be at most one entry referencing a pinned object.
- * Hence, it's sufficient to look at the first returned tuple; we don't
- * need to loop.
- */
- tup = systable_getnext(scan);
- if (HeapTupleIsValid(tup))
- {
- Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
-
- if (shdepForm->deptype == SHARED_DEPENDENCY_PIN)
- result = true;
- }
-
- systable_endscan(scan);
-
- return result;
-}
-
/*
* shdepDropOwned
*
@@ -1359,7 +1308,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
HeapTuple tuple;
/* Doesn't work for pinned objects */
- if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
+ if (IsPinnedObject(AuthIdRelationId, roleid))
{
ObjectAddress obj;
@@ -1402,7 +1351,6 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
switch (sdepForm->deptype)
{
/* Shouldn't happen */
- case SHARED_DEPENDENCY_PIN:
case SHARED_DEPENDENCY_INVALID:
elog(ERROR, "unexpected dependency type");
break;
@@ -1506,7 +1454,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
Oid roleid = lfirst_oid(cell);
/* Refuse to work on pinned roles */
- if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
+ if (IsPinnedObject(AuthIdRelationId, roleid))
{
ObjectAddress obj;
@@ -1549,10 +1497,6 @@ shdepReassignOwned(List *roleids, Oid newrole)
sdepForm->dbid != InvalidOid)
continue;
- /* Unexpected because we checked for pins above */
- if (sdepForm->deptype == SHARED_DEPENDENCY_PIN)
- elog(ERROR, "unexpected shared pin");
-
/* We leave non-owner dependencies alone */
if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER)
continue;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 96375814a8f..28b178f2089 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -5960,7 +5960,7 @@ alter_table_type_to_string(AlterTableType cmdtype)
case AT_DropExpression:
return "ALTER COLUMN ... DROP EXPRESSION";
case AT_CheckNotNull:
- return NULL; /* not real grammar */
+ return NULL; /* not real grammar */
case AT_SetStatistics:
return "ALTER COLUMN ... SET STATISTICS";
case AT_SetOptions:
@@ -5976,7 +5976,7 @@ alter_table_type_to_string(AlterTableType cmdtype)
return "DROP COLUMN";
case AT_AddIndex:
case AT_ReAddIndex:
- return NULL; /* not real grammar */
+ return NULL; /* not real grammar */
case AT_AddConstraint:
case AT_AddConstraintRecurse:
case AT_ReAddConstraint:
@@ -5992,7 +5992,7 @@ alter_table_type_to_string(AlterTableType cmdtype)
case AT_DropConstraintRecurse:
return "DROP CONSTRAINT";
case AT_ReAddComment:
- return NULL; /* not real grammar */
+ return NULL; /* not real grammar */
case AT_AlterColumnType:
return "ALTER COLUMN ... SET DATA TYPE";
case AT_AlterColumnGenericOptions:
@@ -6016,7 +6016,7 @@ alter_table_type_to_string(AlterTableType cmdtype)
case AT_ResetRelOptions:
return "RESET";
case AT_ReplaceRelOptions:
- return NULL; /* not real grammar */
+ return NULL; /* not real grammar */
case AT_EnableTrig:
return "ENABLE TRIGGER";
case AT_EnableAlwaysTrig:
@@ -6074,7 +6074,7 @@ alter_table_type_to_string(AlterTableType cmdtype)
case AT_DropIdentity:
return "ALTER COLUMN ... DROP IDENTITY";
case AT_ReAddStatistics:
- return NULL; /* not real grammar */
+ return NULL; /* not real grammar */
}
return NULL;
@@ -6129,7 +6129,7 @@ ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
if (action_str)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- /* translator: %s is a group of some SQL keywords */
+ /* translator: %s is a group of some SQL keywords */
errmsg("ALTER action %s cannot be performed on relation \"%s\"",
action_str, RelationGetRelationName(rel)),
errdetail_relkind_not_supported(rel->rd_rel->relkind)));
@@ -12080,10 +12080,6 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
ObjectAddress foundObject;
- /* We don't expect any PIN dependencies on columns */
- if (foundDep->deptype == DEPENDENCY_PIN)
- elog(ERROR, "cannot alter type of a pinned column");
-
foundObject.classId = foundDep->classid;
foundObject.objectId = foundDep->objid;
foundObject.objectSubId = foundDep->objsubid;
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 69ea155d502..0385fd61214 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -449,7 +449,6 @@ DropTableSpace(DropTableSpaceStmt *stmt)
ereport(NOTICE,
(errmsg("tablespace \"%s\" does not exist, skipping",
tablespacename)));
- /* XXX I assume I need one or both of these next two calls */
table_endscan(scandesc);
table_close(rel, NoLock);
}
@@ -465,8 +464,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
tablespacename);
/* Disallow drop of the standard tablespaces, even by superuser */
- if (tablespaceoid == GLOBALTABLESPACE_OID ||
- tablespaceoid == DEFAULTTABLESPACE_OID)
+ if (IsPinnedObject(TableSpaceRelationId, tablespaceoid))
aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_TABLESPACE,
tablespacename);
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 26f6872b4b0..b145c5f45fd 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -2955,11 +2955,11 @@ record_plan_function_dependency(PlannerInfo *root, Oid funcid)
* For performance reasons, we don't bother to track built-in functions;
* we just assume they'll never change (or at least not in ways that'd
* invalidate plans using them). For this purpose we can consider a
- * built-in function to be one with OID less than FirstBootstrapObjectId.
+ * built-in function to be one with OID less than FirstUnpinnedObjectId.
* Note that the OID generator guarantees never to generate such an OID
* after startup, even at OID wraparound.
*/
- if (funcid >= (Oid) FirstBootstrapObjectId)
+ if (funcid >= (Oid) FirstUnpinnedObjectId)
{
PlanInvalItem *inval_item = makeNode(PlanInvalItem);
@@ -2995,7 +2995,7 @@ record_plan_type_dependency(PlannerInfo *root, Oid typid)
* As in record_plan_function_dependency, ignore the possibility that
* someone would change a built-in domain.
*/
- if (typid >= (Oid) FirstBootstrapObjectId)
+ if (typid >= (Oid) FirstUnpinnedObjectId)
{
PlanInvalItem *inval_item = makeNode(PlanInvalItem);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index d493aeef0fc..56267bdc3ce 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -494,7 +494,7 @@ static void ReleasePredicateLocksLocal(void);
static inline bool
PredicateLockingNeededForRelation(Relation relation)
{
- return !(relation->rd_id < FirstBootstrapObjectId ||
+ return !(relation->rd_id < FirstUnpinnedObjectId ||
RelationUsesLocalBuffers(relation) ||
relation->rd_rel->relkind == RELKIND_MATVIEW);
}
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 77e621a7679..994bf07f3ba 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1525,83 +1525,10 @@ setup_depend(FILE *cmdfd)
const char *const *line;
static const char *const pg_depend_setup[] = {
/*
- * Make PIN entries in pg_depend for all objects made so far in the
- * tables that the dependency code handles. This is overkill (the
- * system doesn't really depend on having every last weird datatype,
- * for instance) but generating only the minimum required set of
- * dependencies seems hard.
- *
- * Catalogs that are intentionally not scanned here are:
- *
- * pg_database: it's a feature, not a bug, that template1 is not
+ * Advance the OID counter so that subsequently-created objects aren't
* pinned.
- *
- * pg_extension: a pinned extension isn't really an extension, hmm?
- *
- * pg_tablespace: tablespaces don't participate in the dependency
- * code, and DropTableSpace() explicitly protects the built-in
- * tablespaces.
- *
- * First delete any already-made entries; PINs override all else, and
- * must be the only entries for their objects.
*/
- "DELETE FROM pg_depend;\n\n",
- "VACUUM pg_depend;\n\n",
- "DELETE FROM pg_shdepend;\n\n",
- "VACUUM pg_shdepend;\n\n",
-
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_class;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_proc;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_type;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_cast;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_constraint;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_conversion;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_attrdef;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_language;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_operator;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_opclass;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_opfamily;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_am;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_amop;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_amproc;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_rewrite;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_trigger;\n\n",
-
- /*
- * restriction here to avoid pinning the public namespace
- */
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_namespace "
- " WHERE nspname LIKE 'pg%';\n\n",
-
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_ts_parser;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_ts_dict;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_ts_template;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_ts_config;\n\n",
- "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
- " FROM pg_collation;\n\n",
- "INSERT INTO pg_shdepend SELECT 0,0,0,0, tableoid,oid, 'p' "
- " FROM pg_authid;\n\n",
+ "SELECT pg_stop_making_pinned_objects();\n\n",
NULL
};
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index 805dafef072..2601f70a047 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -686,7 +686,7 @@ GuessControlValues(void)
ControlFile.checkPointCopy.fullPageWrites = false;
ControlFile.checkPointCopy.nextXid =
FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId);
- ControlFile.checkPointCopy.nextOid = FirstBootstrapObjectId;
+ ControlFile.checkPointCopy.nextOid = FirstGenbkiObjectId;
ControlFile.checkPointCopy.nextMulti = FirstMultiXactId;
ControlFile.checkPointCopy.nextMultiOffset = 0;
ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId;
diff --git a/src/include/access/transam.h b/src/include/access/transam.h
index 2fe8a591105..d22de19c94c 100644
--- a/src/include/access/transam.h
+++ b/src/include/access/transam.h
@@ -165,10 +165,14 @@ FullTransactionIdAdvance(FullTransactionId *dest)
* when the .dat files in src/include/catalog/ do not specify an OID
* for a catalog entry that requires one. Note that genbki.pl assigns
* these OIDs independently in each catalog, so they're not guaranteed
- * to be globally unique.
+ * to be globally unique. Furthermore, the bootstrap backend and
+ * initdb's post-bootstrap processing can also assign OIDs in this range.
+ * The normal OID-generation logic takes care of any OID conflicts that
+ * might arise from that.
*
- * OIDS 12000-16383 are reserved for assignment during initdb
- * using the OID generator. (We start the generator at 12000.)
+ * OIDs 12000-16383 are reserved for unpinned objects created by initdb's
+ * post-bootstrap processing. initdb forces the OID generator up to
+ * 12000 as soon as it's made the pinned objects it's responsible for.
*
* OIDs beginning at 16384 are assigned from the OID generator
* during normal multiuser operation. (We force the generator up to
@@ -184,11 +188,12 @@ FullTransactionIdAdvance(FullTransactionId *dest)
*
* NOTE: if the OID generator wraps around, we skip over OIDs 0-16383
* and resume with 16384. This minimizes the odds of OID conflict, by not
- * reassigning OIDs that might have been assigned during initdb.
+ * reassigning OIDs that might have been assigned during initdb. Critically,
+ * it also ensures that no user-created object will be considered pinned.
* ----------
*/
#define FirstGenbkiObjectId 10000
-#define FirstBootstrapObjectId 12000
+#define FirstUnpinnedObjectId 12000
#define FirstNormalObjectId 16384
/*
@@ -289,6 +294,7 @@ extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
extern void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid);
extern bool ForceTransactionIdLimitUpdate(void);
extern Oid GetNewObjectId(void);
+extern void StopGeneratingPinnedObjectIds(void);
#ifdef USE_ASSERT_CHECKING
extern void AssertTransactionIdInAllowableRange(TransactionId xid);
diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h
index f247be50b4d..ef2e88fe454 100644
--- a/src/include/catalog/catalog.h
+++ b/src/include/catalog/catalog.h
@@ -34,6 +34,8 @@ extern bool IsReservedName(const char *name);
extern bool IsSharedRelation(Oid relationId);
+extern bool IsPinnedObject(Oid classId, Oid objectId);
+
extern Oid GetNewOidWithIndex(Relation relation, Oid indexId,
AttrNumber oidcolumn);
extern Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class,
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index f2ecafa1daa..358dfdbbd30 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202107141
+#define CATALOG_VERSION_NO 202107151
#endif
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index fd44081e741..2885f35ccd2 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -36,8 +36,7 @@ typedef enum DependencyType
DEPENDENCY_PARTITION_PRI = 'P',
DEPENDENCY_PARTITION_SEC = 'S',
DEPENDENCY_EXTENSION = 'e',
- DEPENDENCY_AUTO_EXTENSION = 'x',
- DEPENDENCY_PIN = 'p'
+ DEPENDENCY_AUTO_EXTENSION = 'x'
} DependencyType;
/*
@@ -47,27 +46,21 @@ typedef enum DependencyType
* unless the dependent object is dropped at the same time. There are some
* additional rules however:
*
- * (a) For a SHARED_DEPENDENCY_PIN entry, there is no dependent object --
- * rather, the referenced object is an essential part of the system. This
- * applies to the initdb-created superuser. Entries of this type are only
- * created by initdb; objects in this category don't need further pg_shdepend
- * entries if more objects come to depend on them.
- *
- * (b) a SHARED_DEPENDENCY_OWNER entry means that the referenced object is
+ * (a) a SHARED_DEPENDENCY_OWNER entry means that the referenced object is
* the role owning the dependent object. The referenced object must be
* a pg_authid entry.
*
- * (c) a SHARED_DEPENDENCY_ACL entry means that the referenced object is
+ * (b) a SHARED_DEPENDENCY_ACL entry means that the referenced object is
* a role mentioned in the ACL field of the dependent object. The referenced
* object must be a pg_authid entry. (SHARED_DEPENDENCY_ACL entries are not
* created for the owner of an object; hence two objects may be linked by
* one or the other, but not both, of these dependency types.)
*
- * (d) a SHARED_DEPENDENCY_POLICY entry means that the referenced object is
+ * (c) a SHARED_DEPENDENCY_POLICY entry means that the referenced object is
* a role mentioned in a policy object. The referenced object must be a
* pg_authid entry.
*
- * (e) a SHARED_DEPENDENCY_TABLESPACE entry means that the referenced
+ * (d) a SHARED_DEPENDENCY_TABLESPACE entry means that the referenced
* object is a tablespace mentioned in a relation without storage. The
* referenced object must be a pg_tablespace entry. (Relations that have
* storage don't need this: they are protected by the existence of a physical
@@ -78,7 +71,6 @@ typedef enum DependencyType
*/
typedef enum SharedDependencyType
{
- SHARED_DEPENDENCY_PIN = 'p',
SHARED_DEPENDENCY_OWNER = 'o',
SHARED_DEPENDENCY_ACL = 'a',
SHARED_DEPENDENCY_POLICY = 'r',
diff --git a/src/include/catalog/pg_depend.h b/src/include/catalog/pg_depend.h
index f41ae3add12..90a5699b6e4 100644
--- a/src/include/catalog/pg_depend.h
+++ b/src/include/catalog/pg_depend.h
@@ -4,8 +4,9 @@
* definition of the "dependency" system catalog (pg_depend)
*
* pg_depend has no preloaded contents, so there is no pg_depend.dat
- * file; system-defined dependencies are loaded into it during a late stage
- * of the initdb process.
+ * file; dependencies for system-defined objects are loaded into it
+ * on-the-fly during initdb. Most built-in objects are pinned anyway,
+ * and hence need no explicit entries in pg_depend.
*
* NOTE: we do not represent all possible dependency pairs in pg_depend;
* for example, there's not much value in creating an explicit dependency
@@ -42,11 +43,9 @@ CATALOG(pg_depend,2608,DependRelationId)
{
/*
* Identification of the dependent (referencing) object.
- *
- * These fields are all zeroes for a DEPENDENCY_PIN entry.
*/
- Oid classid BKI_LOOKUP_OPT(pg_class); /* OID of table containing
- * object */
+ Oid classid BKI_LOOKUP(pg_class); /* OID of table containing
+ * object */
Oid objid; /* OID of object itself */
int32 objsubid; /* column number, or 0 if not used */
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index fde251fa4f3..8bf9d704b70 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3295,6 +3295,10 @@
proname => 'pg_nextoid', provolatile => 'v', proparallel => 'u',
prorettype => 'oid', proargtypes => 'regclass name regclass',
prosrc => 'pg_nextoid' },
+{ oid => '8922', descr => 'stop making pinned objects during initdb',
+ proname => 'pg_stop_making_pinned_objects', provolatile => 'v',
+ proparallel => 'u', prorettype => 'void', proargtypes => '',
+ prosrc => 'pg_stop_making_pinned_objects' },
{ oid => '1579', descr => 'I/O',
proname => 'varbit_in', prorettype => 'varbit',
diff --git a/src/include/catalog/pg_shdepend.h b/src/include/catalog/pg_shdepend.h
index c77452c5846..06616b90865 100644
--- a/src/include/catalog/pg_shdepend.h
+++ b/src/include/catalog/pg_shdepend.h
@@ -4,8 +4,9 @@
* definition of the "shared dependency" system catalog (pg_shdepend)
*
* pg_shdepend has no preloaded contents, so there is no pg_shdepend.dat
- * file; system-defined dependencies are loaded into it during a late stage
- * of the initdb process.
+ * file; dependencies for system-defined objects are loaded into it
+ * on-the-fly during initdb. Most built-in objects are pinned anyway,
+ * and hence need no explicit entries in pg_shdepend.
*
* NOTE: we do not represent all possible dependency pairs in pg_shdepend;
* for example, there's not much value in creating an explicit dependency
@@ -39,13 +40,12 @@ CATALOG(pg_shdepend,1214,SharedDependRelationId) BKI_SHARED_RELATION
/*
* Identification of the dependent (referencing) object.
*
- * These fields are all zeroes for a DEPENDENCY_PIN entry. Also, dbid can
- * be zero to denote a shared object.
+ * Note that dbid can be zero to denote a shared object.
*/
Oid dbid BKI_LOOKUP_OPT(pg_database); /* OID of database
* containing object */
- Oid classid BKI_LOOKUP_OPT(pg_class); /* OID of table containing
- * object */
+ Oid classid BKI_LOOKUP(pg_class); /* OID of table containing
+ * object */
Oid objid; /* OID of object itself */
int32 objsubid; /* column number, or 0 if not used */
diff --git a/src/test/regress/expected/misc_sanity.out b/src/test/regress/expected/misc_sanity.out
index a67f40198a4..a57fd142a94 100644
--- a/src/test/regress/expected/misc_sanity.out
+++ b/src/test/regress/expected/misc_sanity.out
@@ -11,75 +11,26 @@
-- NB: run this test early, because some later tests create bogus entries.
-- **************** pg_depend ****************
-- Look for illegal values in pg_depend fields.
--- classid/objid can be zero, but only in 'p' entries
SELECT *
FROM pg_depend as d1
WHERE refclassid = 0 OR refobjid = 0 OR
- deptype NOT IN ('a', 'e', 'i', 'n', 'p') OR
- (deptype != 'p' AND (classid = 0 OR objid = 0)) OR
- (deptype = 'p' AND (classid != 0 OR objid != 0 OR objsubid != 0));
+ classid = 0 OR objid = 0 OR
+ deptype NOT IN ('a', 'e', 'i', 'n', 'x', 'P', 'S');
classid | objid | objsubid | refclassid | refobjid | refobjsubid | deptype
---------+-------+----------+------------+----------+-------------+---------
(0 rows)
-- **************** pg_shdepend ****************
-- Look for illegal values in pg_shdepend fields.
--- classid/objid can be zero, but only in 'p' entries
SELECT *
FROM pg_shdepend as d1
WHERE refclassid = 0 OR refobjid = 0 OR
- deptype NOT IN ('a', 'o', 'p', 'r') OR
- (deptype != 'p' AND (classid = 0 OR objid = 0)) OR
- (deptype = 'p' AND (dbid != 0 OR classid != 0 OR objid != 0 OR objsubid != 0));
+ classid = 0 OR objid = 0 OR
+ deptype NOT IN ('a', 'o', 'r', 't');
dbid | classid | objid | objsubid | refclassid | refobjid | deptype
------+---------+-------+----------+------------+----------+---------
(0 rows)
--- Check each OID-containing system catalog to see if its lowest-numbered OID
--- is pinned. If not, and if that OID was generated during initdb, then
--- perhaps initdb forgot to scan that catalog for pinnable entries.
--- Generally, it's okay for a catalog to be listed in the output of this
--- test if that catalog is scanned by initdb.c's setup_depend() function;
--- whatever OID the test is complaining about must have been added later
--- in initdb, where it intentionally isn't pinned. Legitimate exceptions
--- to that rule are listed in the comments in setup_depend().
--- Currently, pg_rewrite is also listed by this check, even though it is
--- covered by setup_depend(). That happens because there are no rules in
--- the pinned data, but initdb creates some intentionally-not-pinned views.
-do $$
-declare relnm text;
- reloid oid;
- shared bool;
- lowoid oid;
- pinned bool;
-begin
-for relnm, reloid, shared in
- select relname, oid, relisshared from pg_class
- where EXISTS(
- SELECT * FROM pg_attribute
- WHERE attrelid = pg_class.oid AND attname = 'oid')
- and relkind = 'r' and oid < 16384 order by 1
-loop
- execute 'select min(oid) from ' || relnm into lowoid;
- continue when lowoid is null or lowoid >= 16384;
- if shared then
- pinned := exists(select 1 from pg_shdepend
- where refclassid = reloid and refobjid = lowoid
- and deptype = 'p');
- else
- pinned := exists(select 1 from pg_depend
- where refclassid = reloid and refobjid = lowoid
- and deptype = 'p');
- end if;
- if not pinned then
- raise notice '% contains unpinned initdb-created object(s)', relnm;
- end if;
-end loop;
-end$$;
-NOTICE: pg_database contains unpinned initdb-created object(s)
-NOTICE: pg_extension contains unpinned initdb-created object(s)
-NOTICE: pg_rewrite contains unpinned initdb-created object(s)
-NOTICE: pg_tablespace contains unpinned initdb-created object(s)
-- **************** pg_class ****************
-- Look for system tables with varlena columns but no toast table. All
-- system tables with toastable columns should have toast tables, with
diff --git a/src/test/regress/sql/misc_sanity.sql b/src/test/regress/sql/misc_sanity.sql
index 9699f5cc3b3..2c0f87a651f 100644
--- a/src/test/regress/sql/misc_sanity.sql
+++ b/src/test/regress/sql/misc_sanity.sql
@@ -14,71 +14,25 @@
-- **************** pg_depend ****************
-- Look for illegal values in pg_depend fields.
--- classid/objid can be zero, but only in 'p' entries
SELECT *
FROM pg_depend as d1
WHERE refclassid = 0 OR refobjid = 0 OR
- deptype NOT IN ('a', 'e', 'i', 'n', 'p') OR
- (deptype != 'p' AND (classid = 0 OR objid = 0)) OR
- (deptype = 'p' AND (classid != 0 OR objid != 0 OR objsubid != 0));
+ classid = 0 OR objid = 0 OR
+ deptype NOT IN ('a', 'e', 'i', 'n', 'x', 'P', 'S');
+
-- **************** pg_shdepend ****************
-- Look for illegal values in pg_shdepend fields.
--- classid/objid can be zero, but only in 'p' entries
SELECT *
FROM pg_shdepend as d1
WHERE refclassid = 0 OR refobjid = 0 OR
- deptype NOT IN ('a', 'o', 'p', 'r') OR
- (deptype != 'p' AND (classid = 0 OR objid = 0)) OR
- (deptype = 'p' AND (dbid != 0 OR classid != 0 OR objid != 0 OR objsubid != 0));
+ classid = 0 OR objid = 0 OR
+ deptype NOT IN ('a', 'o', 'r', 't');
--- Check each OID-containing system catalog to see if its lowest-numbered OID
--- is pinned. If not, and if that OID was generated during initdb, then
--- perhaps initdb forgot to scan that catalog for pinnable entries.
--- Generally, it's okay for a catalog to be listed in the output of this
--- test if that catalog is scanned by initdb.c's setup_depend() function;
--- whatever OID the test is complaining about must have been added later
--- in initdb, where it intentionally isn't pinned. Legitimate exceptions
--- to that rule are listed in the comments in setup_depend().
--- Currently, pg_rewrite is also listed by this check, even though it is
--- covered by setup_depend(). That happens because there are no rules in
--- the pinned data, but initdb creates some intentionally-not-pinned views.
-
-do $$
-declare relnm text;
- reloid oid;
- shared bool;
- lowoid oid;
- pinned bool;
-begin
-for relnm, reloid, shared in
- select relname, oid, relisshared from pg_class
- where EXISTS(
- SELECT * FROM pg_attribute
- WHERE attrelid = pg_class.oid AND attname = 'oid')
- and relkind = 'r' and oid < 16384 order by 1
-loop
- execute 'select min(oid) from ' || relnm into lowoid;
- continue when lowoid is null or lowoid >= 16384;
- if shared then
- pinned := exists(select 1 from pg_shdepend
- where refclassid = reloid and refobjid = lowoid
- and deptype = 'p');
- else
- pinned := exists(select 1 from pg_depend
- where refclassid = reloid and refobjid = lowoid
- and deptype = 'p');
- end if;
- if not pinned then
- raise notice '% contains unpinned initdb-created object(s)', relnm;
- end if;
-end loop;
-end$$;
-
-- **************** pg_class ****************
-- Look for system tables with varlena columns but no toast table. All