1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-28 18:48:04 +03:00

Replace explicit PIN entries in pg_depend with an OID range test.

As of v14, pg_depend contains almost 7000 "pin" entries recording
the OIDs of built-in objects.  This is a fair amount of bloat for
every database, and it adds time to pg_depend lookups as well as
initdb.  We can get rid of all of those entries in favor of an OID
range check, i.e. "OIDs below FirstUnpinnedObjectId are pinned".

(template1 and the public schema are exceptions.  Those exceptions
are now wired into IsPinnedObject() instead of initdb's code for
filling pg_depend, but it's the same amount of cruft either way.)

The contents of pg_shdepend are modified likewise.

Discussion: https://postgr.es/m/3737988.1618451008@sss.pgh.pa.us
This commit is contained in:
Tom Lane
2021-07-15 11:41:47 -04:00
parent e529b2dc37
commit a49d081235
25 changed files with 290 additions and 432 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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));

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}