From 5b83720fad8c0608a4f543746bc87e923f20514d Mon Sep 17 00:00:00 2001 From: Bertrand Drouvot Date: Fri, 29 Mar 2024 15:43:26 +0000 Subject: [PATCH] Avoid orphaned objects dependencies It's currently possible to create orphaned objects dependencies, for example: Scenario 1: session 1: begin; drop schema schem; session 2: create a function in the schema schem session 1: commit; With the above, the function created in session 2 would be linked to a non existing schema. Scenario 2: session 1: begin; create a function in the schema schem session 2: drop schema schem; session 1: commit; With the above, the function created in session 1 would be linked to a non existing schema. To avoid those scenarios, a new lock (that conflicts with a lock taken by DROP) has been put in place before the dependencies are being recorded. With this in place, the drop schema in scenario 2 would be locked. Also, after the new lock attempt, the patch checks that the object still exists: with this in place session 2 in scenario 1 would be locked and would report an error once session 1 committs (that would not be the case should session 1 abort the transaction). The patch takes into account any type of objects except the ones that are pinned (they are not droppable because the system requires it). A special case is done for objects that belong to the RelationRelationId class. For those, we should be in one of the two following cases that would already prevent the relation to be dropped: 1. The relation is already locked (could be an existing relation or a relation that we are creating). 2. The relation is protected indirectly (i.e an index protected by a lock on its table, a table protected by a lock on a function that depends of the table...) To avoid any risks for the RelationRelationId class case, we acquire a lock if there is none. That may add unnecessary lock for 2. but that's worth it. The patch adds a few tests for some dependency cases (that would currently produce orphaned objects): - schema and function (as the above scenarios) - alter a dependency (function and schema) - function and arg type - function and return type - function and function - domain and domain - table and type - server and foreign data wrapper --- src/backend/catalog/aclchk.c | 1 + src/backend/catalog/dependency.c | 201 ++++++++++++++++++ src/backend/catalog/heap.c | 7 + src/backend/catalog/index.c | 26 +++ src/backend/catalog/objectaddress.c | 57 +++++ src/backend/catalog/pg_aggregate.c | 9 + src/backend/catalog/pg_attrdef.c | 1 + src/backend/catalog/pg_cast.c | 5 + src/backend/catalog/pg_collation.c | 1 + src/backend/catalog/pg_constraint.c | 26 +++ src/backend/catalog/pg_conversion.c | 2 + src/backend/catalog/pg_depend.c | 39 +++- src/backend/catalog/pg_operator.c | 19 ++ src/backend/catalog/pg_proc.c | 17 +- src/backend/catalog/pg_publication.c | 11 + src/backend/catalog/pg_range.c | 6 + src/backend/catalog/pg_type.c | 39 ++++ src/backend/catalog/toasting.c | 1 + src/backend/commands/alter.c | 4 + src/backend/commands/amcmds.c | 1 + src/backend/commands/cluster.c | 7 + src/backend/commands/event_trigger.c | 1 + src/backend/commands/extension.c | 5 + src/backend/commands/foreigncmds.c | 7 + src/backend/commands/functioncmds.c | 6 + src/backend/commands/indexcmds.c | 2 + src/backend/commands/opclasscmds.c | 18 ++ src/backend/commands/operatorcmds.c | 30 +++ src/backend/commands/policy.c | 2 + src/backend/commands/proclang.c | 3 + src/backend/commands/sequence.c | 2 + src/backend/commands/statscmds.c | 10 + src/backend/commands/tablecmds.c | 32 ++- src/backend/commands/trigger.c | 29 ++- src/backend/commands/tsearchcmds.c | 73 ++++++- src/backend/commands/typecmds.c | 84 ++++++++ src/backend/rewrite/rewriteDefine.c | 1 + src/backend/utils/errcodes.txt | 1 + src/include/catalog/dependency.h | 3 + src/include/catalog/objectaddress.h | 1 + .../expected/test_dependencies_locks.out | 129 +++++++++++ src/test/isolation/isolation_schedule | 1 + .../specs/test_dependencies_locks.spec | 89 ++++++++ src/test/regress/expected/alter_table.out | 11 +- 44 files changed, 998 insertions(+), 22 deletions(-) create mode 100644 src/test/isolation/expected/test_dependencies_locks.out create mode 100644 src/test/isolation/specs/test_dependencies_locks.spec diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 02a754cc30a7..420641633c54 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -1341,6 +1341,7 @@ SetDefaultACL(InternalDefaultACL *iacls) referenced.objectId = iacls->nspid; referenced.objectSubId = 0; + LockNotPinnedObject(NamespaceRelationId, iacls->nspid); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); } } diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 18316a3968bc..34884aa89504 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -1519,6 +1519,69 @@ AcquireDeletionLock(const ObjectAddress *object, int flags) } } +/* + * LockNotPinnedObjectById + * + * Lock the object that we are about to record a dependency on. + * After it's locked, verify that it hasn't been dropped while we + * weren't looking. If the object has been dropped, this function + * does not return! + */ +void +LockNotPinnedObjectById(const ObjectAddress *object) +{ + if (isObjectPinned(object)) + return; + + if (object->classId == RelationRelationId) + { + Assert(!IsSharedRelation(object->objectId)); + + /* + * We must be in one of the two following cases that would already + * prevent the relation to be dropped: 1. The relation is already + * locked (could be an existing relation or a relation that we are + * creating). 2. The relation is protected indirectly (i.e an index + * protected by a lock on its table, a table protected by a lock on a + * function that depends of the table...). To avoid any risks, acquire + * a lock if there is none. That may add unnecessary lock for 2. but + * that's worth it. + */ + if (!CheckRelationOidLockedByMe(object->objectId, AccessShareLock, true)) + LockRelationOid(object->objectId, AccessShareLock); + } + else + { + /* assume we should lock the whole object not a sub-object */ + LockDatabaseObject(object->classId, object->objectId, 0, AccessShareLock); + } + + /* check if object still exists */ + if (!ObjectByIdExist(object)) + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_DOES_NOT_EXIST), + errmsg("dependent object does not exist"), + errdetail("Class OID is %u and object OID is %u", + object->classId, object->objectId))); + + return; +} + +/* + * LockNotPinnedObject + * + * Lock the object that we are about to record a dependency on. + */ +void +LockNotPinnedObject(Oid classid, Oid objid) +{ + ObjectAddress object; + + ObjectAddressSet(object, classid, objid); + + LockNotPinnedObjectById(&object); +} + /* * ReleaseDeletionLock - release an object deletion lock * @@ -1730,6 +1793,7 @@ find_expr_references_walker(Node *node, if (rte->rtekind == RTE_RELATION) { /* If it's a plain relation, reference this column */ + LockNotPinnedObject(RelationRelationId, rte->relid); add_object_address(RelationRelationId, rte->relid, var->varattno, context->addrs); } @@ -1756,6 +1820,7 @@ find_expr_references_walker(Node *node, Oid objoid; /* A constant must depend on the constant's datatype */ + LockNotPinnedObject(TypeRelationId, con->consttype); add_object_address(TypeRelationId, con->consttype, 0, context->addrs); @@ -1767,8 +1832,11 @@ find_expr_references_walker(Node *node, */ if (OidIsValid(con->constcollid) && con->constcollid != DEFAULT_COLLATION_OID) + { + LockNotPinnedObject(CollationRelationId, con->constcollid); add_object_address(CollationRelationId, con->constcollid, 0, context->addrs); + } /* * If it's a regclass or similar literal referring to an existing @@ -1785,59 +1853,83 @@ find_expr_references_walker(Node *node, objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(objoid))) + { + LockNotPinnedObject(ProcedureRelationId, objoid); add_object_address(ProcedureRelationId, objoid, 0, context->addrs); + } break; case REGOPEROID: case REGOPERATOROID: objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(OPEROID, ObjectIdGetDatum(objoid))) + { + LockNotPinnedObject(OperatorRelationId, objoid); add_object_address(OperatorRelationId, objoid, 0, context->addrs); + } break; case REGCLASSOID: objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(RELOID, ObjectIdGetDatum(objoid))) + { + LockNotPinnedObject(RelationRelationId, objoid); add_object_address(RelationRelationId, objoid, 0, context->addrs); + } break; case REGTYPEOID: objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(objoid))) + { + LockNotPinnedObject(TypeRelationId, objoid); add_object_address(TypeRelationId, objoid, 0, context->addrs); + } break; case REGCOLLATIONOID: objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(COLLOID, ObjectIdGetDatum(objoid))) + { + LockNotPinnedObject(CollationRelationId, objoid); add_object_address(CollationRelationId, objoid, 0, context->addrs); + } break; case REGCONFIGOID: objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(TSCONFIGOID, ObjectIdGetDatum(objoid))) + { + LockNotPinnedObject(TSConfigRelationId, objoid); add_object_address(TSConfigRelationId, objoid, 0, context->addrs); + } break; case REGDICTIONARYOID: objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(TSDICTOID, ObjectIdGetDatum(objoid))) + { + LockNotPinnedObject(TSDictionaryRelationId, objoid); add_object_address(TSDictionaryRelationId, objoid, 0, context->addrs); + } break; case REGNAMESPACEOID: objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(objoid))) + { + LockNotPinnedObject(NamespaceRelationId, objoid); add_object_address(NamespaceRelationId, objoid, 0, context->addrs); + } break; /* @@ -1859,18 +1951,23 @@ find_expr_references_walker(Node *node, Param *param = (Param *) node; /* A parameter must depend on the parameter's datatype */ + LockNotPinnedObject(TypeRelationId, param->paramtype); add_object_address(TypeRelationId, param->paramtype, 0, context->addrs); /* and its collation, just as for Consts */ if (OidIsValid(param->paramcollid) && param->paramcollid != DEFAULT_COLLATION_OID) + { + LockNotPinnedObject(CollationRelationId, param->paramcollid); add_object_address(CollationRelationId, param->paramcollid, 0, context->addrs); + } } else if (IsA(node, FuncExpr)) { FuncExpr *funcexpr = (FuncExpr *) node; + LockNotPinnedObject(ProcedureRelationId, funcexpr->funcid); add_object_address(ProcedureRelationId, funcexpr->funcid, 0, context->addrs); /* fall through to examine arguments */ @@ -1879,6 +1976,7 @@ find_expr_references_walker(Node *node, { OpExpr *opexpr = (OpExpr *) node; + LockNotPinnedObject(OperatorRelationId, opexpr->opno); add_object_address(OperatorRelationId, opexpr->opno, 0, context->addrs); /* fall through to examine arguments */ @@ -1887,6 +1985,7 @@ find_expr_references_walker(Node *node, { DistinctExpr *distinctexpr = (DistinctExpr *) node; + LockNotPinnedObject(OperatorRelationId, distinctexpr->opno); add_object_address(OperatorRelationId, distinctexpr->opno, 0, context->addrs); /* fall through to examine arguments */ @@ -1895,6 +1994,7 @@ find_expr_references_walker(Node *node, { NullIfExpr *nullifexpr = (NullIfExpr *) node; + LockNotPinnedObject(OperatorRelationId, nullifexpr->opno); add_object_address(OperatorRelationId, nullifexpr->opno, 0, context->addrs); /* fall through to examine arguments */ @@ -1903,6 +2003,7 @@ find_expr_references_walker(Node *node, { ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; + LockNotPinnedObject(OperatorRelationId, opexpr->opno); add_object_address(OperatorRelationId, opexpr->opno, 0, context->addrs); /* fall through to examine arguments */ @@ -1911,6 +2012,7 @@ find_expr_references_walker(Node *node, { Aggref *aggref = (Aggref *) node; + LockNotPinnedObject(ProcedureRelationId, aggref->aggfnoid); add_object_address(ProcedureRelationId, aggref->aggfnoid, 0, context->addrs); /* fall through to examine arguments */ @@ -1919,6 +2021,7 @@ find_expr_references_walker(Node *node, { WindowFunc *wfunc = (WindowFunc *) node; + LockNotPinnedObject(ProcedureRelationId, wfunc->winfnoid); add_object_address(ProcedureRelationId, wfunc->winfnoid, 0, context->addrs); /* fall through to examine arguments */ @@ -1935,8 +2038,11 @@ find_expr_references_walker(Node *node, */ if (sbsref->refrestype != sbsref->refcontainertype && sbsref->refrestype != sbsref->refelemtype) + { + LockNotPinnedObject(TypeRelationId, sbsref->refrestype); add_object_address(TypeRelationId, sbsref->refrestype, 0, context->addrs); + } /* fall through to examine arguments */ } else if (IsA(node, SubPlan)) @@ -1960,16 +2066,25 @@ find_expr_references_walker(Node *node, * anywhere else in the expression. */ if (OidIsValid(reltype)) + { + LockNotPinnedObject(RelationRelationId, reltype); add_object_address(RelationRelationId, reltype, fselect->fieldnum, context->addrs); + } else + { + LockNotPinnedObject(TypeRelationId, fselect->resulttype); add_object_address(TypeRelationId, fselect->resulttype, 0, context->addrs); + } /* the collation might not be referenced anywhere else, either */ if (OidIsValid(fselect->resultcollid) && fselect->resultcollid != DEFAULT_COLLATION_OID) + { + LockNotPinnedObject(CollationRelationId, fselect->resultcollid); add_object_address(CollationRelationId, fselect->resultcollid, 0, context->addrs); + } } else if (IsA(node, FieldStore)) { @@ -1980,53 +2095,76 @@ find_expr_references_walker(Node *node, if (OidIsValid(reltype)) { ListCell *l; + bool locked = false; foreach(l, fstore->fieldnums) + { + if (!locked) + { + LockNotPinnedObject(RelationRelationId, reltype); + locked = true; + } add_object_address(RelationRelationId, reltype, lfirst_int(l), context->addrs); + } } else + { + LockNotPinnedObject(TypeRelationId, fstore->resulttype); add_object_address(TypeRelationId, fstore->resulttype, 0, context->addrs); + } } else if (IsA(node, RelabelType)) { RelabelType *relab = (RelabelType *) node; /* since there is no function dependency, need to depend on type */ + LockNotPinnedObject(TypeRelationId, relab->resulttype); add_object_address(TypeRelationId, relab->resulttype, 0, context->addrs); /* the collation might not be referenced anywhere else, either */ if (OidIsValid(relab->resultcollid) && relab->resultcollid != DEFAULT_COLLATION_OID) + { + LockNotPinnedObject(CollationRelationId, relab->resultcollid); add_object_address(CollationRelationId, relab->resultcollid, 0, context->addrs); + } } else if (IsA(node, CoerceViaIO)) { CoerceViaIO *iocoerce = (CoerceViaIO *) node; /* since there is no exposed function, need to depend on type */ + LockNotPinnedObject(TypeRelationId, iocoerce->resulttype); add_object_address(TypeRelationId, iocoerce->resulttype, 0, context->addrs); /* the collation might not be referenced anywhere else, either */ if (OidIsValid(iocoerce->resultcollid) && iocoerce->resultcollid != DEFAULT_COLLATION_OID) + { + LockNotPinnedObject(CollationRelationId, iocoerce->resultcollid); add_object_address(CollationRelationId, iocoerce->resultcollid, 0, context->addrs); + } } else if (IsA(node, ArrayCoerceExpr)) { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; /* as above, depend on type */ + LockNotPinnedObject(TypeRelationId, acoerce->resulttype); add_object_address(TypeRelationId, acoerce->resulttype, 0, context->addrs); /* the collation might not be referenced anywhere else, either */ if (OidIsValid(acoerce->resultcollid) && acoerce->resultcollid != DEFAULT_COLLATION_OID) + { + LockNotPinnedObject(CollationRelationId, acoerce->resultcollid); add_object_address(CollationRelationId, acoerce->resultcollid, 0, context->addrs); + } /* fall through to examine arguments */ } else if (IsA(node, ConvertRowtypeExpr)) @@ -2034,6 +2172,7 @@ find_expr_references_walker(Node *node, ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node; /* since there is no function dependency, need to depend on type */ + LockNotPinnedObject(TypeRelationId, cvt->resulttype); add_object_address(TypeRelationId, cvt->resulttype, 0, context->addrs); } @@ -2041,6 +2180,7 @@ find_expr_references_walker(Node *node, { CollateExpr *coll = (CollateExpr *) node; + LockNotPinnedObject(CollationRelationId, coll->collOid); add_object_address(CollationRelationId, coll->collOid, 0, context->addrs); } @@ -2048,6 +2188,7 @@ find_expr_references_walker(Node *node, { RowExpr *rowexpr = (RowExpr *) node; + LockNotPinnedObject(TypeRelationId, rowexpr->row_typeid); add_object_address(TypeRelationId, rowexpr->row_typeid, 0, context->addrs); } @@ -2058,11 +2199,13 @@ find_expr_references_walker(Node *node, foreach(l, rcexpr->opnos) { + LockNotPinnedObject(OperatorRelationId, lfirst_oid(l)); add_object_address(OperatorRelationId, lfirst_oid(l), 0, context->addrs); } foreach(l, rcexpr->opfamilies) { + LockNotPinnedObject(OperatorFamilyRelationId, lfirst_oid(l)); add_object_address(OperatorFamilyRelationId, lfirst_oid(l), 0, context->addrs); } @@ -2072,6 +2215,7 @@ find_expr_references_walker(Node *node, { CoerceToDomain *cd = (CoerceToDomain *) node; + LockNotPinnedObject(TypeRelationId, cd->resulttype); add_object_address(TypeRelationId, cd->resulttype, 0, context->addrs); } @@ -2079,6 +2223,7 @@ find_expr_references_walker(Node *node, { NextValueExpr *nve = (NextValueExpr *) node; + LockNotPinnedObject(RelationRelationId, nve->seqid); add_object_address(RelationRelationId, nve->seqid, 0, context->addrs); } @@ -2087,19 +2232,26 @@ find_expr_references_walker(Node *node, OnConflictExpr *onconflict = (OnConflictExpr *) node; if (OidIsValid(onconflict->constraint)) + { + LockNotPinnedObject(ConstraintRelationId, onconflict->constraint); add_object_address(ConstraintRelationId, onconflict->constraint, 0, context->addrs); + } /* fall through to examine arguments */ } else if (IsA(node, SortGroupClause)) { SortGroupClause *sgc = (SortGroupClause *) node; + LockNotPinnedObject(OperatorRelationId, sgc->eqop); add_object_address(OperatorRelationId, sgc->eqop, 0, context->addrs); if (OidIsValid(sgc->sortop)) + { + LockNotPinnedObject(OperatorRelationId, sgc->sortop); add_object_address(OperatorRelationId, sgc->sortop, 0, context->addrs); + } return false; } else if (IsA(node, WindowClause)) @@ -2107,15 +2259,24 @@ find_expr_references_walker(Node *node, WindowClause *wc = (WindowClause *) node; if (OidIsValid(wc->startInRangeFunc)) + { + LockNotPinnedObject(ProcedureRelationId, wc->startInRangeFunc); add_object_address(ProcedureRelationId, wc->startInRangeFunc, 0, context->addrs); + } if (OidIsValid(wc->endInRangeFunc)) + { + LockNotPinnedObject(ProcedureRelationId, wc->endInRangeFunc); add_object_address(ProcedureRelationId, wc->endInRangeFunc, 0, context->addrs); + } if (OidIsValid(wc->inRangeColl) && wc->inRangeColl != DEFAULT_COLLATION_OID) + { + LockNotPinnedObject(CollationRelationId, wc->inRangeColl); add_object_address(CollationRelationId, wc->inRangeColl, 0, context->addrs); + } /* fall through to examine substructure */ } else if (IsA(node, CTECycleClause)) @@ -2123,14 +2284,23 @@ find_expr_references_walker(Node *node, CTECycleClause *cc = (CTECycleClause *) node; if (OidIsValid(cc->cycle_mark_type)) + { + LockNotPinnedObject(TypeRelationId, cc->cycle_mark_type); add_object_address(TypeRelationId, cc->cycle_mark_type, 0, context->addrs); + } if (OidIsValid(cc->cycle_mark_collation)) + { + LockNotPinnedObject(CollationRelationId, cc->cycle_mark_collation); add_object_address(CollationRelationId, cc->cycle_mark_collation, 0, context->addrs); + } if (OidIsValid(cc->cycle_mark_neop)) + { + LockNotPinnedObject(OperatorRelationId, cc->cycle_mark_neop); add_object_address(OperatorRelationId, cc->cycle_mark_neop, 0, context->addrs); + } /* fall through to examine substructure */ } else if (IsA(node, Query)) @@ -2163,6 +2333,7 @@ find_expr_references_walker(Node *node, switch (rte->rtekind) { case RTE_RELATION: + LockNotPinnedObject(RelationRelationId, rte->relid); add_object_address(RelationRelationId, rte->relid, 0, context->addrs); break; @@ -2230,12 +2401,19 @@ find_expr_references_walker(Node *node, rte = rt_fetch(query->resultRelation, query->rtable); if (rte->rtekind == RTE_RELATION) { + bool locked = false; + foreach(lc, query->targetList) { TargetEntry *tle = (TargetEntry *) lfirst(lc); if (tle->resjunk) continue; /* ignore junk tlist items */ + if (!locked) + { + LockNotPinnedObject(RelationRelationId, rte->relid); + locked = true; + } add_object_address(RelationRelationId, rte->relid, tle->resno, context->addrs); } @@ -2247,6 +2425,7 @@ find_expr_references_walker(Node *node, */ foreach(lc, query->constraintDeps) { + LockNotPinnedObject(ConstraintRelationId, lfirst_oid(lc)); add_object_address(ConstraintRelationId, lfirst_oid(lc), 0, context->addrs); } @@ -2281,16 +2460,25 @@ find_expr_references_walker(Node *node, */ foreach(ct, rtfunc->funccoltypes) { + LockNotPinnedObject(TypeRelationId, lfirst_oid(ct)); add_object_address(TypeRelationId, lfirst_oid(ct), 0, context->addrs); } foreach(ct, rtfunc->funccolcollations) { Oid collid = lfirst_oid(ct); + bool locked = false; if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID) + { + if (!locked) + { + LockNotPinnedObject(CollationRelationId, collid); + locked = true; + } add_object_address(CollationRelationId, collid, 0, context->addrs); + } } } else if (IsA(node, TableFunc)) @@ -2303,22 +2491,32 @@ find_expr_references_walker(Node *node, */ foreach(ct, tf->coltypes) { + LockNotPinnedObject(TypeRelationId, lfirst_oid(ct)); add_object_address(TypeRelationId, lfirst_oid(ct), 0, context->addrs); } foreach(ct, tf->colcollations) { Oid collid = lfirst_oid(ct); + bool locked = false; if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID) + { + if (!locked) + { + LockNotPinnedObject(CollationRelationId, collid); + locked = true; + } add_object_address(CollationRelationId, collid, 0, context->addrs); + } } } else if (IsA(node, TableSampleClause)) { TableSampleClause *tsc = (TableSampleClause *) node; + LockNotPinnedObject(ProcedureRelationId, tsc->tsmhandler); add_object_address(ProcedureRelationId, tsc->tsmhandler, 0, context->addrs); /* fall through to examine arguments */ @@ -2369,9 +2567,12 @@ process_function_rte_ref(RangeTblEntry *rte, AttrNumber attnum, Assert(attnum - atts_done <= tupdesc->natts); if (OidIsValid(reltype)) /* can this fail? */ + { + LockNotPinnedObject(RelationRelationId, reltype); add_object_address(RelationRelationId, reltype, attnum - atts_done, context->addrs); + } return; } /* Nothing to do; function's result type is handled elsewhere */ diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index bd3554c0bfdc..08519f42c7f0 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -849,6 +849,7 @@ AddNewAttributeTuples(Oid new_rel_oid, /* Add dependency info */ ObjectAddressSubSet(myself, RelationRelationId, new_rel_oid, i + 1); ObjectAddressSet(referenced, TypeRelationId, attr->atttypid); + LockNotPinnedObject(TypeRelationId, attr->atttypid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* The default collation is pinned, so don't bother recording it */ @@ -857,6 +858,7 @@ AddNewAttributeTuples(Oid new_rel_oid, { ObjectAddressSet(referenced, CollationRelationId, attr->attcollation); + LockNotPinnedObject(CollationRelationId, attr->attcollation); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } } @@ -1466,11 +1468,13 @@ heap_create_with_catalog(const char *relname, ObjectAddressSet(referenced, NamespaceRelationId, relnamespace); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(NamespaceRelationId, relnamespace); if (reloftypeid) { ObjectAddressSet(referenced, TypeRelationId, reloftypeid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(TypeRelationId, reloftypeid); } /* @@ -1486,6 +1490,7 @@ heap_create_with_catalog(const char *relname, { ObjectAddressSet(referenced, AccessMethodRelationId, accessmtd); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(AccessMethodRelationId, accessmtd); } record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL); @@ -3871,6 +3876,7 @@ StorePartitionKey(Relation rel, { ObjectAddressSet(referenced, OperatorClassRelationId, partopclass[i]); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(OperatorClassRelationId, partopclass[i]); /* The default collation is pinned, so don't bother recording it */ if (OidIsValid(partcollation[i]) && @@ -3878,6 +3884,7 @@ StorePartitionKey(Relation rel, { ObjectAddressSet(referenced, CollationRelationId, partcollation[i]); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(CollationRelationId, partcollation[i]); } } diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 739a92bdcc1c..a942e6e68a78 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -1118,6 +1118,7 @@ index_create(Relation heapRelation, else { bool have_simple_col = false; + bool locked_object = false; addrs = new_object_addresses(); @@ -1130,6 +1131,12 @@ index_create(Relation heapRelation, heapRelationId, indexInfo->ii_IndexAttrNumbers[i]); add_exact_object_address(&referenced, addrs); + + if (!locked_object) + { + LockNotPinnedObject(RelationRelationId, heapRelationId); + locked_object = true; + } have_simple_col = true; } } @@ -1145,6 +1152,8 @@ index_create(Relation heapRelation, ObjectAddressSet(referenced, RelationRelationId, heapRelationId); add_exact_object_address(&referenced, addrs); + + LockNotPinnedObject(RelationRelationId, heapRelationId); } record_object_address_dependencies(&myself, addrs, DEPENDENCY_AUTO); @@ -1160,9 +1169,13 @@ index_create(Relation heapRelation, if (OidIsValid(parentIndexRelid)) { ObjectAddressSet(referenced, RelationRelationId, parentIndexRelid); + + LockNotPinnedObject(RelationRelationId, parentIndexRelid); recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI); ObjectAddressSet(referenced, RelationRelationId, heapRelationId); + + LockNotPinnedObject(RelationRelationId, heapRelationId); recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC); } @@ -1178,6 +1191,7 @@ index_create(Relation heapRelation, { ObjectAddressSet(referenced, CollationRelationId, collationIds[i]); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(CollationRelationId, collationIds[i]); } } @@ -1186,6 +1200,7 @@ index_create(Relation heapRelation, { ObjectAddressSet(referenced, OperatorClassRelationId, opclassIds[i]); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(OperatorClassRelationId, opclassIds[i]); } record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL); @@ -1996,6 +2011,14 @@ index_constraint_create(Relation heapRelation, */ ObjectAddressSet(myself, ConstraintRelationId, conOid); ObjectAddressSet(idxaddr, RelationRelationId, indexRelationId); + + /* + * CommandCounterIncrement() here to ensure the new constraint entry is + * visible when LockNotPinnedObject() will check its existence before + * recording the dependencies. + */ + CommandCounterIncrement(); + LockNotPinnedObject(ConstraintRelationId, conOid); recordDependencyOn(&idxaddr, &myself, DEPENDENCY_INTERNAL); /* @@ -2007,9 +2030,12 @@ index_constraint_create(Relation heapRelation, ObjectAddress referenced; ObjectAddressSet(referenced, ConstraintRelationId, parentConstraintId); + LockNotPinnedObject(ConstraintRelationId, parentConstraintId); recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI); ObjectAddressSet(referenced, RelationRelationId, RelationGetRelid(heapRelation)); + + LockNotPinnedObject(RelationRelationId, RelationGetRelid(heapRelation)); recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC); } diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index d8eb8d3deaa9..f3e82671df50 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -2595,6 +2595,63 @@ get_object_namespace(const ObjectAddress *address) return oid; } +/* + * ObjectByIdExist + * + * Return whether the given object exists. + * + * Works for most catalogs, if no special processing is needed. + */ +bool +ObjectByIdExist(const ObjectAddress *address) +{ + HeapTuple tuple; + int cache; + const ObjectPropertyType *property; + + property = get_object_property_data(address->classId); + + cache = property->oid_catcache_id; + + if (cache >= 0) + { + /* Fetch tuple from syscache. */ + tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId)); + + if (!HeapTupleIsValid(tuple)) + { + return false; + } + + ReleaseSysCache(tuple); + + return true; + } + else + { + Relation rel; + ScanKeyData skey[1]; + SysScanDesc scan; + + rel = table_open(address->classId, AccessShareLock); + + ScanKeyInit(&skey[0], + get_object_attnum_oid(address->classId), + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(address->objectId)); + + scan = systable_beginscan(rel, get_object_oid_index(address->classId), true, + NULL, 1, skey); + + /* we expect exactly one match */ + tuple = systable_getnext(scan); + systable_endscan(scan); + table_close(rel, AccessShareLock); + + return (HeapTupleIsValid(tuple)); + } +} + /* * Return ObjectType for the given object type as given by * getObjectTypeDescription; if no valid ObjectType code exists, but it's a diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index bcf4050f5b16..ce5865fac69b 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -748,12 +748,14 @@ AggregateCreate(const char *aggName, /* Depends on transition function */ ObjectAddressSet(referenced, ProcedureRelationId, transfn); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, transfn); /* Depends on final function, if any */ if (OidIsValid(finalfn)) { ObjectAddressSet(referenced, ProcedureRelationId, finalfn); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, finalfn); } /* Depends on combine function, if any */ @@ -761,6 +763,7 @@ AggregateCreate(const char *aggName, { ObjectAddressSet(referenced, ProcedureRelationId, combinefn); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, combinefn); } /* Depends on serialization function, if any */ @@ -768,6 +771,7 @@ AggregateCreate(const char *aggName, { ObjectAddressSet(referenced, ProcedureRelationId, serialfn); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, serialfn); } /* Depends on deserialization function, if any */ @@ -775,6 +779,7 @@ AggregateCreate(const char *aggName, { ObjectAddressSet(referenced, ProcedureRelationId, deserialfn); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, deserialfn); } /* Depends on forward transition function, if any */ @@ -782,6 +787,7 @@ AggregateCreate(const char *aggName, { ObjectAddressSet(referenced, ProcedureRelationId, mtransfn); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, mtransfn); } /* Depends on inverse transition function, if any */ @@ -789,6 +795,7 @@ AggregateCreate(const char *aggName, { ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, minvtransfn); } /* Depends on final function, if any */ @@ -796,6 +803,7 @@ AggregateCreate(const char *aggName, { ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, mfinalfn); } /* Depends on sort operator, if any */ @@ -803,6 +811,7 @@ AggregateCreate(const char *aggName, { ObjectAddressSet(referenced, OperatorRelationId, sortop); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(OperatorRelationId, sortop); } record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL); diff --git a/src/backend/catalog/pg_attrdef.c b/src/backend/catalog/pg_attrdef.c index 1b6270b12132..b2770bb96fdf 100644 --- a/src/backend/catalog/pg_attrdef.c +++ b/src/backend/catalog/pg_attrdef.c @@ -117,6 +117,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, colobject.objectId = RelationGetRelid(rel); colobject.objectSubId = attnum; + LockNotPinnedObject(RelationRelationId, RelationGetRelid(rel)); recordDependencyOn(&defobject, &colobject, attgenerated ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO); diff --git a/src/backend/catalog/pg_cast.c b/src/backend/catalog/pg_cast.c index 1773c9c54916..90513a39ac6f 100644 --- a/src/backend/catalog/pg_cast.c +++ b/src/backend/catalog/pg_cast.c @@ -97,16 +97,19 @@ CastCreate(Oid sourcetypeid, Oid targettypeid, /* dependency on source type */ ObjectAddressSet(referenced, TypeRelationId, sourcetypeid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(TypeRelationId, sourcetypeid); /* dependency on target type */ ObjectAddressSet(referenced, TypeRelationId, targettypeid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(TypeRelationId, targettypeid); /* dependency on function */ if (OidIsValid(funcid)) { ObjectAddressSet(referenced, ProcedureRelationId, funcid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, funcid); } /* dependencies on casts required for function */ @@ -114,11 +117,13 @@ CastCreate(Oid sourcetypeid, Oid targettypeid, { ObjectAddressSet(referenced, CastRelationId, incastid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(CastRelationId, incastid); } if (OidIsValid(outcastid)) { ObjectAddressSet(referenced, CastRelationId, outcastid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(CastRelationId, outcastid); } record_object_address_dependencies(&myself, addrs, behavior); diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c index 469635b35808..fa6fd7bf791d 100644 --- a/src/backend/catalog/pg_collation.c +++ b/src/backend/catalog/pg_collation.c @@ -218,6 +218,7 @@ CollationCreate(const char *collname, Oid collnamespace, referenced.classId = NamespaceRelationId; referenced.objectId = collnamespace; referenced.objectSubId = 0; + LockNotPinnedObject(NamespaceRelationId, collnamespace); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* create dependency on owner */ diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index ac80652baf25..79b2df100e64 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -264,17 +264,26 @@ CreateConstraintEntry(const char *constraintName, if (constraintNTotalKeys > 0) { + bool locked_object = false; + for (i = 0; i < constraintNTotalKeys; i++) { ObjectAddressSubSet(relobject, RelationRelationId, relId, constraintKey[i]); add_exact_object_address(&relobject, addrs_auto); + + if (!locked_object) + { + LockNotPinnedObject(RelationRelationId, relId); + locked_object = true; + } } } else { ObjectAddressSet(relobject, RelationRelationId, relId); add_exact_object_address(&relobject, addrs_auto); + LockNotPinnedObject(RelationRelationId, relId); } } @@ -287,6 +296,7 @@ CreateConstraintEntry(const char *constraintName, ObjectAddressSet(domobject, TypeRelationId, domainId); add_exact_object_address(&domobject, addrs_auto); + LockNotPinnedObject(TypeRelationId, domainId); } record_object_address_dependencies(&conobject, addrs_auto, @@ -306,17 +316,26 @@ CreateConstraintEntry(const char *constraintName, if (foreignNKeys > 0) { + bool locked_object = false; + for (i = 0; i < foreignNKeys; i++) { ObjectAddressSubSet(relobject, RelationRelationId, foreignRelId, foreignKey[i]); add_exact_object_address(&relobject, addrs_normal); + + if (!locked_object) + { + LockNotPinnedObject(RelationRelationId, foreignRelId); + locked_object = true; + } } } else { ObjectAddressSet(relobject, RelationRelationId, foreignRelId); add_exact_object_address(&relobject, addrs_normal); + LockNotPinnedObject(RelationRelationId, foreignRelId); } } @@ -332,6 +351,7 @@ CreateConstraintEntry(const char *constraintName, ObjectAddressSet(relobject, RelationRelationId, indexRelId); add_exact_object_address(&relobject, addrs_normal); + LockNotPinnedObject(RelationRelationId, indexRelId); } if (foreignNKeys > 0) @@ -351,15 +371,18 @@ CreateConstraintEntry(const char *constraintName, { oprobject.objectId = pfEqOp[i]; add_exact_object_address(&oprobject, addrs_normal); + LockNotPinnedObject(OperatorRelationId, pfEqOp[i]); if (ppEqOp[i] != pfEqOp[i]) { oprobject.objectId = ppEqOp[i]; add_exact_object_address(&oprobject, addrs_normal); + LockNotPinnedObject(OperatorRelationId, ppEqOp[i]); } if (ffEqOp[i] != pfEqOp[i]) { oprobject.objectId = ffEqOp[i]; add_exact_object_address(&oprobject, addrs_normal); + LockNotPinnedObject(OperatorRelationId, ffEqOp[i]); } } } @@ -1119,9 +1142,12 @@ ConstraintSetParentConstraint(Oid childConstrId, ObjectAddressSet(depender, ConstraintRelationId, childConstrId); ObjectAddressSet(referenced, ConstraintRelationId, parentConstrId); + LockNotPinnedObject(ConstraintRelationId, parentConstrId); recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI); ObjectAddressSet(referenced, RelationRelationId, childTableId); + + LockNotPinnedObject(RelationRelationId, childTableId); recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC); } else diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c index 04cc375caea8..5ac365ebd04a 100644 --- a/src/backend/catalog/pg_conversion.c +++ b/src/backend/catalog/pg_conversion.c @@ -116,12 +116,14 @@ ConversionCreate(const char *conname, Oid connamespace, referenced.classId = ProcedureRelationId; referenced.objectId = conproc; referenced.objectSubId = 0; + LockNotPinnedObject(ProcedureRelationId, conproc); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* create dependency on namespace */ referenced.classId = NamespaceRelationId; referenced.objectId = connamespace; referenced.objectSubId = 0; + LockNotPinnedObject(NamespaceRelationId, connamespace); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* create dependency on owner */ diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index c8b11f887e27..fdafffb8934a 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -20,19 +20,20 @@ #include "catalog/catalog.h" #include "catalog/dependency.h" #include "catalog/indexing.h" +#include "catalog/pg_auth_members.h" #include "catalog/pg_constraint.h" #include "catalog/pg_depend.h" #include "catalog/pg_extension.h" #include "catalog/partition.h" #include "commands/extension.h" #include "miscadmin.h" +#include "storage/lmgr.h" +#include "storage/lock.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/rel.h" -static bool isObjectPinned(const ObjectAddress *object); - /* * Record a dependency between 2 objects via their respective ObjectAddress. @@ -99,6 +100,37 @@ recordMultipleDependencies(const ObjectAddress *depender, slot_init_count = 0; for (i = 0; i < nreferenced; i++, referenced++) { +#ifdef USE_ASSERT_CHECKING + if (!isObjectPinned(referenced)) + { + if (referenced->classId != RelationRelationId) + { + LOCKTAG tag; + + SET_LOCKTAG_OBJECT(tag, + MyDatabaseId, + referenced->classId, + referenced->objectId, + 0); + /* assert the referenced object is locked */ + Assert(LockHeldByMe(&tag, AccessShareLock, false)); + } + else + { + Assert(!IsSharedRelation(referenced->objectId)); + + /* + * Assert the referenced object is locked if it should be + * visible (see the comment related to LockNotPinnedObject() + * in TypeCreate()). + */ + Assert(!ObjectByIdExist(referenced) || + CheckRelationOidLockedByMe(referenced->objectId, + AccessShareLock, true)); + } + } +#endif + /* * If the referenced object is pinned by the system, there's no real * need to record dependencies on it. This saves lots of space in @@ -238,6 +270,7 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object, extension.objectId = CurrentExtensionObject; extension.objectSubId = 0; + LockNotPinnedObject(ExtensionRelationId, CurrentExtensionObject); recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION); } } @@ -705,7 +738,7 @@ changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, * The passed subId, if any, is ignored; we assume that only whole objects * are pinned (and that this implies pinning their components). */ -static bool +bool isObjectPinned(const ObjectAddress *object) { return IsPinnedObject(object->classId, object->objectId); diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index bfcfa643464a..ba6aa332187e 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -251,6 +251,16 @@ OperatorShellMake(const char *operatorName, values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid); values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid); + /* Lock dependent objects */ + if (OidIsValid(operatorNamespace)) + LockNotPinnedObject(NamespaceRelationId, operatorNamespace); + + if (OidIsValid(leftTypeId)) + LockNotPinnedObject(TypeRelationId, leftTypeId); + + if (OidIsValid(rightTypeId)) + LockNotPinnedObject(TypeRelationId, rightTypeId); + /* * create a new operator tuple */ @@ -513,6 +523,15 @@ OperatorCreate(const char *operatorName, CatalogTupleInsert(pg_operator_desc, tup); } + /* Lock dependent objects */ + LockNotPinnedObject(NamespaceRelationId, operatorNamespace); + LockNotPinnedObject(TypeRelationId, leftTypeId); + LockNotPinnedObject(TypeRelationId, rightTypeId); + LockNotPinnedObject(TypeRelationId, operResultType); + LockNotPinnedObject(ProcedureRelationId, procedureId); + LockNotPinnedObject(ProcedureRelationId, restrictionId); + LockNotPinnedObject(ProcedureRelationId, joinId); + /* Add dependencies for the entry */ address = makeOperatorDependencies(tup, true, isUpdate); diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index fe0490259e9e..c3999bdce87d 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -593,6 +593,13 @@ ProcedureCreate(const char *procedureName, if (is_update) deleteDependencyRecordsFor(ProcedureRelationId, retval, true); + /* + * CommandCounterIncrement() here to ensure the new function entry is + * visible when LockNotPinnedObject() will check its existence before + * recording the dependencies. + */ + CommandCounterIncrement(); + addrs = new_object_addresses(); ObjectAddressSet(myself, ProcedureRelationId, retval); @@ -600,20 +607,24 @@ ProcedureCreate(const char *procedureName, /* dependency on namespace */ ObjectAddressSet(referenced, NamespaceRelationId, procNamespace); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(NamespaceRelationId, procNamespace); /* dependency on implementation language */ ObjectAddressSet(referenced, LanguageRelationId, languageObjectId); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(LanguageRelationId, languageObjectId); /* dependency on return type */ ObjectAddressSet(referenced, TypeRelationId, returnType); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(TypeRelationId, returnType); /* dependency on transform used by return type, if any */ if ((trfid = get_transform_oid(returnType, languageObjectId, true))) { ObjectAddressSet(referenced, TransformRelationId, trfid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(TransformRelationId, trfid); } /* dependency on parameter types */ @@ -621,12 +632,14 @@ ProcedureCreate(const char *procedureName, { ObjectAddressSet(referenced, TypeRelationId, allParams[i]); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(TypeRelationId, allParams[i]); /* dependency on transform used by parameter type, if any */ if ((trfid = get_transform_oid(allParams[i], languageObjectId, true))) { ObjectAddressSet(referenced, TransformRelationId, trfid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(TransformRelationId, trfid); } } @@ -635,6 +648,7 @@ ProcedureCreate(const char *procedureName, { ObjectAddressSet(referenced, ProcedureRelationId, prosupport); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, prosupport); } record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL); @@ -674,9 +688,6 @@ ProcedureCreate(const char *procedureName, ArrayType *set_items = NULL; int save_nestlevel = 0; - /* Advance command counter so new tuple can be seen by validator */ - CommandCounterIncrement(); - /* * Set per-function configuration parameters so that the validation is * done with the environment the function expects. However, if diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index d6f94db5d999..07135da2f383 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -441,6 +441,7 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri, referenced; List *relids = NIL; int i; + bool locked = false; rel = table_open(PublicationRelRelationId, RowExclusiveLock); @@ -503,10 +504,13 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri, /* Add dependency on the publication */ ObjectAddressSet(referenced, PublicationRelationId, pubid); + LockNotPinnedObject(PublicationRelationId, pubid); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); /* Add dependency on the relation */ ObjectAddressSet(referenced, RelationRelationId, relid); + + LockNotPinnedObject(RelationRelationId, relid); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); /* Add dependency on the objects mentioned in the qualifications */ @@ -520,6 +524,11 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri, while ((i = bms_next_member(attnums, i)) >= 0) { ObjectAddressSubSet(referenced, RelationRelationId, relid, i); + if (!locked) + { + LockNotPinnedObject(RelationRelationId, relid); + locked = true; + } recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } @@ -725,10 +734,12 @@ publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists) /* Add dependency on the publication */ ObjectAddressSet(referenced, PublicationRelationId, pubid); + LockNotPinnedObject(PublicationRelationId, pubid); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); /* Add dependency on the schema */ ObjectAddressSet(referenced, NamespaceRelationId, schemaid); + LockNotPinnedObject(NamespaceRelationId, schemaid); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); /* Close the table */ diff --git a/src/backend/catalog/pg_range.c b/src/backend/catalog/pg_range.c index 8df73e7ab71b..e1538c21468c 100644 --- a/src/backend/catalog/pg_range.c +++ b/src/backend/catalog/pg_range.c @@ -70,26 +70,31 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, ObjectAddressSet(referenced, TypeRelationId, rangeSubType); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(TypeRelationId, rangeSubType); ObjectAddressSet(referenced, OperatorClassRelationId, rangeSubOpclass); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(OperatorClassRelationId, rangeSubOpclass); if (OidIsValid(rangeCollation)) { ObjectAddressSet(referenced, CollationRelationId, rangeCollation); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(CollationRelationId, rangeCollation); } if (OidIsValid(rangeCanonical)) { ObjectAddressSet(referenced, ProcedureRelationId, rangeCanonical); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, rangeCanonical); } if (OidIsValid(rangeSubDiff)) { ObjectAddressSet(referenced, ProcedureRelationId, rangeSubDiff); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, rangeSubDiff); } record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL); @@ -99,6 +104,7 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, referencing.classId = TypeRelationId; referencing.objectId = multirangeTypeOid; referencing.objectSubId = 0; + LockNotPinnedObject(TypeRelationId, rangeTypeOid); recordDependencyOn(&referencing, &myself, DEPENDENCY_INTERNAL); table_close(pg_range, RowExclusiveLock); diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index b36f81afb9d3..77ff5f06030a 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -157,6 +157,12 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) * Create dependencies. We can/must skip this in bootstrap mode. */ if (!IsBootstrapProcessingMode()) + { + /* Lock dependent objects */ + LockNotPinnedObject(NamespaceRelationId, typeNamespace); + LockNotPinnedObject(ProcedureRelationId, F_SHELL_IN); + LockNotPinnedObject(ProcedureRelationId, F_SHELL_OUT); + GenerateTypeDependencies(tup, pg_type_desc, NULL, @@ -166,6 +172,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) false, true, /* make extension dependency */ false); + } /* Post creation hook for new shell type */ InvokeObjectPostCreateHook(TypeRelationId, typoid, 0); @@ -494,6 +501,37 @@ TypeCreate(Oid newTypeOid, * Create dependencies. We can/must skip this in bootstrap mode. */ if (!IsBootstrapProcessingMode()) + { + /* + * CommandCounterIncrement() here to ensure the new type entry is + * visible when LockNotPinnedObject() will check its existence before + * recording the dependencies. + */ + CommandCounterIncrement(); + + /* Lock dependent objects */ + LockNotPinnedObject(NamespaceRelationId, typeNamespace); + LockNotPinnedObject(ProcedureRelationId, inputProcedure); + LockNotPinnedObject(ProcedureRelationId, outputProcedure); + LockNotPinnedObject(ProcedureRelationId, receiveProcedure); + LockNotPinnedObject(ProcedureRelationId, sendProcedure); + LockNotPinnedObject(ProcedureRelationId, typmodinProcedure); + LockNotPinnedObject(ProcedureRelationId, typmodoutProcedure); + LockNotPinnedObject(ProcedureRelationId, analyzeProcedure); + LockNotPinnedObject(ProcedureRelationId, subscriptProcedure); + LockNotPinnedObject(TypeRelationId, baseType); + LockNotPinnedObject(CollationRelationId, typeCollation); + LockNotPinnedObject(TypeRelationId, elementType); + + /* + * No need to call LockRelationOid() (through LockNotPinnedObject()) + * on relationOid as relationOid is set to an InvalidOid or to a new + * Oid not added to pg_class yet (In heap_create_with_catalog(), + * AddNewRelationType() is called before AddNewRelationTuple()). + */ + if (relationKind == RELKIND_COMPOSITE_TYPE) + LockNotPinnedObject(TypeRelationId, typeObjectId); + GenerateTypeDependencies(tup, pg_type_desc, (defaultTypeBin ? @@ -505,6 +543,7 @@ TypeCreate(Oid newTypeOid, isDependentType, true, /* make extension dependency */ rebuildDeps); + } /* Post creation hook for new type */ InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0); diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 874a8fc89adb..b8fb22af6aec 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -383,6 +383,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, toastobject.objectId = toast_relid; toastobject.objectSubId = 0; + LockNotPinnedObject(RelationRelationId, relOid); recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL); } diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index c801c869c1cf..981d1f9b6e36 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -515,7 +515,10 @@ ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddre currexts = getAutoExtensionsOfObject(address.classId, address.objectId); if (!list_member_oid(currexts, refAddr.objectId)) + { + LockNotPinnedObject(refAddr.classId, refAddr.objectId); recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION); + } } return address; @@ -819,6 +822,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid) pfree(replaces); /* update dependency to point to the new schema */ + LockNotPinnedObject(NamespaceRelationId, nspOid); if (changeDependencyFor(classId, objid, NamespaceRelationId, oldNspOid, nspOid) != 1) elog(ERROR, "could not change schema dependency for object %u", diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c index 58ed9d216cc0..eb9b86d56337 100644 --- a/src/backend/commands/amcmds.c +++ b/src/backend/commands/amcmds.c @@ -104,6 +104,7 @@ CreateAccessMethod(CreateAmStmt *stmt) referenced.objectId = amhandler; referenced.objectSubId = 0; + LockNotPinnedObject(ProcedureRelationId, amhandler); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); recordDependencyOnCurrentExtension(&myself, false); diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 54a08e4102e1..228f126f0baf 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -1279,6 +1279,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, */ if (relam1 != relam2) { + LockNotPinnedObject(AccessMethodRelationId, relam2); if (changeDependencyFor(RelationRelationId, r1, AccessMethodRelationId, @@ -1287,6 +1288,8 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, elog(ERROR, "could not change access method dependency for relation \"%s.%s\"", get_namespace_name(get_rel_namespace(r1)), get_rel_name(r1)); + + LockNotPinnedObject(AccessMethodRelationId, relam1); if (changeDependencyFor(RelationRelationId, r2, AccessMethodRelationId, @@ -1388,6 +1391,8 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, { baseobject.objectId = r1; toastobject.objectId = relform1->reltoastrelid; + + LockNotPinnedObject(RelationRelationId, r1); recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL); } @@ -1396,6 +1401,8 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, { baseobject.objectId = r2; toastobject.objectId = relform2->reltoastrelid; + + LockNotPinnedObject(RelationRelationId, r2); recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL); } diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index edc2c988e293..14dab63ef0d7 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -327,6 +327,7 @@ insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtO referenced.classId = ProcedureRelationId; referenced.objectId = funcoid; referenced.objectSubId = 0; + LockNotPinnedObject(ProcedureRelationId, funcoid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* Depend on extension, if any. */ diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index dc38c3257701..6ef367ea7ccb 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -2121,6 +2121,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner, ObjectAddressSet(nsp, NamespaceRelationId, schemaOid); add_exact_object_address(&nsp, refobjs); + LockNotPinnedObject(NamespaceRelationId, schemaOid); foreach(lc, requiredExtensions) { @@ -2129,6 +2130,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner, ObjectAddressSet(otherext, ExtensionRelationId, reqext); add_exact_object_address(&otherext, refobjs); + LockNotPinnedObject(ExtensionRelationId, reqext); } /* Record all of them (this includes duplicate elimination) */ @@ -3183,6 +3185,7 @@ AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *o table_close(extRel, RowExclusiveLock); /* update dependency to point to the new schema */ + LockNotPinnedObject(NamespaceRelationId, nspOid); if (changeDependencyFor(ExtensionRelationId, extensionOid, NamespaceRelationId, oldNspOid, nspOid) != 1) elog(ERROR, "could not change schema dependency for extension %s", @@ -3473,6 +3476,7 @@ ApplyExtensionUpdates(Oid extensionOid, otherext.objectId = reqext; otherext.objectSubId = 0; + LockNotPinnedObject(ExtensionRelationId, reqext); recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL); } @@ -3629,6 +3633,7 @@ ExecAlterExtensionContentsRecurse(AlterExtensionContentsStmt *stmt, /* * OK, add the dependency. */ + LockNotPinnedObject(extension.classId, extension.objectId); recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION); /* diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index c14e038d54f1..d6cced22e7a1 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -642,6 +642,7 @@ CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt) referenced.classId = ProcedureRelationId; referenced.objectId = fdwhandler; referenced.objectSubId = 0; + LockNotPinnedObject(ProcedureRelationId, fdwhandler); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } @@ -650,6 +651,7 @@ CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt) referenced.classId = ProcedureRelationId; referenced.objectId = fdwvalidator; referenced.objectSubId = 0; + LockNotPinnedObject(ProcedureRelationId, fdwvalidator); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } @@ -811,6 +813,7 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt) referenced.classId = ProcedureRelationId; referenced.objectId = fdwhandler; referenced.objectSubId = 0; + LockNotPinnedObject(ProcedureRelationId, fdwhandler); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } @@ -819,6 +822,7 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt) referenced.classId = ProcedureRelationId; referenced.objectId = fdwvalidator; referenced.objectSubId = 0; + LockNotPinnedObject(ProcedureRelationId, fdwvalidator); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } } @@ -951,6 +955,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt) referenced.classId = ForeignDataWrapperRelationId; referenced.objectId = fdw->fdwid; referenced.objectSubId = 0; + LockNotPinnedObject(ForeignDataWrapperRelationId, fdw->fdwid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId); @@ -1195,6 +1200,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt) referenced.classId = ForeignServerRelationId; referenced.objectId = srv->serverid; referenced.objectSubId = 0; + LockNotPinnedObject(ForeignServerRelationId, srv->serverid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); if (OidIsValid(useId)) @@ -1472,6 +1478,7 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) referenced.classId = ForeignServerRelationId; referenced.objectId = server->serverid; referenced.objectSubId = 0; + LockNotPinnedObject(ForeignServerRelationId, server->serverid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); table_close(ftrel, RowExclusiveLock); diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index b9fd7683abb4..e2155511478f 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1461,6 +1461,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) /* Add or replace dependency on support function */ if (OidIsValid(procForm->prosupport)) { + LockNotPinnedObject(ProcedureRelationId, newsupport); if (changeDependencyFor(ProcedureRelationId, funcOid, ProcedureRelationId, procForm->prosupport, newsupport) != 1) @@ -1474,6 +1475,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) referenced.classId = ProcedureRelationId; referenced.objectId = newsupport; referenced.objectSubId = 0; + LockNotPinnedObject(ProcedureRelationId, newsupport); recordDependencyOn(&address, &referenced, DEPENDENCY_NORMAL); } @@ -1990,21 +1992,25 @@ CreateTransform(CreateTransformStmt *stmt) /* dependency on language */ ObjectAddressSet(referenced, LanguageRelationId, langid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(LanguageRelationId, langid); /* dependency on type */ ObjectAddressSet(referenced, TypeRelationId, typeid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(TypeRelationId, typeid); /* dependencies on functions */ if (OidIsValid(fromsqlfuncid)) { ObjectAddressSet(referenced, ProcedureRelationId, fromsqlfuncid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, fromsqlfuncid); } if (OidIsValid(tosqlfuncid)) { ObjectAddressSet(referenced, ProcedureRelationId, tosqlfuncid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, tosqlfuncid); } record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL); diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 89cc83e88434..7de3926a2471 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -4511,8 +4511,10 @@ IndexSetParentIndex(Relation partitionIdx, Oid parentOid) ObjectAddressSet(parentIdx, RelationRelationId, parentOid); ObjectAddressSet(partitionTbl, RelationRelationId, partitionIdx->rd_index->indrelid); + LockNotPinnedObject(RelationRelationId, parentOid); recordDependencyOn(&partIdx, &parentIdx, DEPENDENCY_PARTITION_PRI); + LockNotPinnedObject(RelationRelationId, partitionIdx->rd_index->indrelid); recordDependencyOn(&partIdx, &partitionTbl, DEPENDENCY_PARTITION_SEC); } diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 8546366ee06c..5d41f4f5c480 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -299,12 +299,14 @@ CreateOpFamily(CreateOpFamilyStmt *stmt, const char *opfname, referenced.classId = AccessMethodRelationId; referenced.objectId = amoid; referenced.objectSubId = 0; + LockNotPinnedObject(AccessMethodRelationId, amoid); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); /* dependency on namespace */ referenced.classId = NamespaceRelationId; referenced.objectId = namespaceoid; referenced.objectSubId = 0; + LockNotPinnedObject(NamespaceRelationId, namespaceoid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on owner */ @@ -726,18 +728,21 @@ DefineOpClass(CreateOpClassStmt *stmt) referenced.classId = NamespaceRelationId; referenced.objectId = namespaceoid; referenced.objectSubId = 0; + LockNotPinnedObject(NamespaceRelationId, namespaceoid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on opfamily */ referenced.classId = OperatorFamilyRelationId; referenced.objectId = opfamilyoid; referenced.objectSubId = 0; + LockNotPinnedObject(OperatorFamilyRelationId, opfamilyoid); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); /* dependency on indexed datatype */ referenced.classId = TypeRelationId; referenced.objectId = typeoid; referenced.objectSubId = 0; + LockNotPinnedObject(TypeRelationId, typeoid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on storage datatype */ @@ -746,6 +751,7 @@ DefineOpClass(CreateOpClassStmt *stmt) referenced.classId = TypeRelationId; referenced.objectId = storageoid; referenced.objectSubId = 0; + LockNotPinnedObject(TypeRelationId, storageoid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } @@ -1487,6 +1493,13 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, heap_freetuple(tup); + /* + * CommandCounterIncrement() here to ensure the new operator entry is + * visible when LockNotPinnedObject() will check its existence before + * recording the dependencies. + */ + CommandCounterIncrement(); + /* Make its dependencies */ myself.classId = AccessMethodOperatorRelationId; myself.objectId = entryoid; @@ -1497,6 +1510,7 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, referenced.objectSubId = 0; /* see comments in amapi.h about dependency strength */ + LockNotPinnedObject(OperatorRelationId, op->object); recordDependencyOn(&myself, &referenced, op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO); @@ -1505,6 +1519,7 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, referenced.objectId = op->refobjid; referenced.objectSubId = 0; + LockNotPinnedObject(referenced.classId, op->refobjid); recordDependencyOn(&myself, &referenced, op->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO); @@ -1538,6 +1553,7 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, referenced.objectId = op->sortfamily; referenced.objectSubId = 0; + LockNotPinnedObject(OperatorFamilyRelationId, op->sortfamily); recordDependencyOn(&myself, &referenced, op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO); } @@ -1621,6 +1637,7 @@ storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, referenced.objectSubId = 0; /* see comments in amapi.h about dependency strength */ + LockNotPinnedObject(ProcedureRelationId, proc->object); recordDependencyOn(&myself, &referenced, proc->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO); @@ -1629,6 +1646,7 @@ storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, referenced.objectId = proc->refobjid; referenced.objectSubId = 0; + LockNotPinnedObject(referenced.classId, proc->refobjid); recordDependencyOn(&myself, &referenced, proc->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO); diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index 673648f1fc6f..59a4715fffe9 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -33,6 +33,7 @@ #include "access/htup_details.h" #include "access/table.h" +#include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/objectaccess.h" #include "catalog/pg_namespace.h" @@ -656,11 +657,15 @@ AlterOperator(AlterOperatorStmt *stmt) { replaces[Anum_pg_operator_oprrest - 1] = true; values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid); + if (OidIsValid(restrictionOid)) + LockNotPinnedObject(ProcedureRelationId, restrictionOid); } if (updateJoin) { replaces[Anum_pg_operator_oprjoin - 1] = true; values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid); + if (OidIsValid(joinOid)) + LockNotPinnedObject(ProcedureRelationId, joinOid); } if (OidIsValid(commutatorOid)) { @@ -688,6 +693,31 @@ AlterOperator(AlterOperatorStmt *stmt) CatalogTupleUpdate(catalog, &tup->t_self, tup); + + /* Lock dependent objects */ + oprForm = (Form_pg_operator) GETSTRUCT(tup); + + if (OidIsValid(oprForm->oprnamespace)) + LockNotPinnedObject(NamespaceRelationId, oprForm->oprnamespace); + + if (OidIsValid(oprForm->oprleft)) + LockNotPinnedObject(TypeRelationId, oprForm->oprleft); + + if (OidIsValid(oprForm->oprright)) + LockNotPinnedObject(TypeRelationId, oprForm->oprright); + + if (OidIsValid(oprForm->oprresult)) + LockNotPinnedObject(TypeRelationId, oprForm->oprresult); + + if (OidIsValid(oprForm->oprcode)) + LockNotPinnedObject(ProcedureRelationId, oprForm->oprcode); + + if (OidIsValid(oprForm->oprrest)) + LockNotPinnedObject(ProcedureRelationId, oprForm->oprrest); + + if (OidIsValid(oprForm->oprjoin)) + LockNotPinnedObject(ProcedureRelationId, oprForm->oprjoin); + address = makeOperatorDependencies(tup, false, true); if (OidIsValid(commutatorOid) || OidIsValid(negatorOid)) diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c index 83056960fe47..cf5e1947929b 100644 --- a/src/backend/commands/policy.c +++ b/src/backend/commands/policy.c @@ -722,6 +722,7 @@ CreatePolicy(CreatePolicyStmt *stmt) myself.objectId = policy_id; myself.objectSubId = 0; + LockNotPinnedObject(RelationRelationId, table_id); recordDependencyOn(&myself, &target, DEPENDENCY_AUTO); recordDependencyOnExpr(&myself, qual, qual_pstate->p_rtable, @@ -1053,6 +1054,7 @@ AlterPolicy(AlterPolicyStmt *stmt) myself.objectId = policy_id; myself.objectSubId = 0; + LockNotPinnedObject(RelationRelationId, table_id); recordDependencyOn(&myself, &target, DEPENDENCY_AUTO); recordDependencyOnExpr(&myself, qual, qual_parse_rtable, DEPENDENCY_NORMAL); diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 5036ac03639d..f4a7e46b7142 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -190,12 +190,14 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) /* dependency on the PL handler function */ ObjectAddressSet(referenced, ProcedureRelationId, handlerOid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, handlerOid); /* dependency on the inline handler function, if any */ if (OidIsValid(inlineOid)) { ObjectAddressSet(referenced, ProcedureRelationId, inlineOid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, inlineOid); } /* dependency on the validator function, if any */ @@ -203,6 +205,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) { ObjectAddressSet(referenced, ProcedureRelationId, valOid); add_exact_object_address(&referenced, addrs); + LockNotPinnedObject(ProcedureRelationId, valOid); } record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL); diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 4b7c5113aabe..0248cd250e09 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -1691,6 +1691,8 @@ process_owned_by(Relation seqrel, List *owned_by, bool for_identity) depobject.classId = RelationRelationId; depobject.objectId = RelationGetRelid(seqrel); depobject.objectSubId = 0; + + LockNotPinnedObject(RelationRelationId, RelationGetRelid(tablerel)); recordDependencyOn(&depobject, &refobject, deptype); } diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c index e24d540cd45b..771ceeca5952 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -88,6 +88,7 @@ CreateStatistics(CreateStatsStmt *stmt) bool build_mcv; bool build_expressions; bool requested_type = false; + bool locked_object = false; int i; ListCell *cell; ListCell *cell2; @@ -554,6 +555,12 @@ CreateStatistics(CreateStatsStmt *stmt) for (i = 0; i < nattnums; i++) { ObjectAddressSubSet(parentobject, RelationRelationId, relid, attnums[i]); + + if (!locked_object) + { + LockNotPinnedObject(RelationRelationId, relid); + locked_object = true; + } recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO); } @@ -571,6 +578,8 @@ CreateStatistics(CreateStatsStmt *stmt) if (!nattnums) { ObjectAddressSet(parentobject, RelationRelationId, relid); + + LockNotPinnedObject(RelationRelationId, relid); recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO); } @@ -591,6 +600,7 @@ CreateStatistics(CreateStatsStmt *stmt) * than the underlying table(s). */ ObjectAddressSet(parentobject, NamespaceRelationId, namespaceId); + LockNotPinnedObject(NamespaceRelationId, namespaceId); recordDependencyOn(&myself, &parentobject, DEPENDENCY_NORMAL); recordDependencyOnOwner(StatisticExtRelationId, statoid, stxowner); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 129c97fdf28f..1a3d643e0508 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3543,6 +3543,7 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid, childobject.objectId = relationId; childobject.objectSubId = 0; + LockNotPinnedObject(RelationRelationId, parentOid); recordDependencyOn(&childobject, &parentobject, child_dependency_type(child_is_partition)); @@ -7485,7 +7486,9 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, /* * Add needed dependency entries for the new column. */ + LockNotPinnedObject(TypeRelationId, attribute->atttypid); add_column_datatype_dependency(myrelid, newattnum, attribute->atttypid); + LockNotPinnedObject(CollationRelationId, attribute->attcollation); add_column_collation_dependency(myrelid, newattnum, attribute->attcollation); /* @@ -10614,11 +10617,16 @@ addFkConstraint(addFkConstraintSides fkside, Assert(fkside != addFkBothSides); if (fkside == addFkReferencedSide) + { + LockNotPinnedObject(ConstraintRelationId, parentConstr); recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL); + } else { + LockNotPinnedObject(ConstraintRelationId, parentConstr); recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI); ObjectAddressSet(referenced, RelationRelationId, RelationGetRelid(rel)); + LockNotPinnedObject(RelationRelationId, RelationGetRelid(rel)); recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC); } } @@ -14266,7 +14274,9 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, table_close(attrelation, RowExclusiveLock); /* Install dependencies on new datatype and collation */ + LockNotPinnedObject(TypeRelationId, targettype); add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype); + LockNotPinnedObject(CollationRelationId, targetcollid); add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid); /* @@ -15844,6 +15854,7 @@ ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId) */ ObjectAddressSet(relobj, RelationRelationId, reloid); ObjectAddressSet(referenced, AccessMethodRelationId, rd_rel->relam); + LockNotPinnedObject(AccessMethodRelationId, rd_rel->relam); recordDependencyOn(&relobj, &referenced, DEPENDENCY_NORMAL); } else if (OidIsValid(oldAccessMethodId) && @@ -15863,6 +15874,7 @@ ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId) OidIsValid(rd_rel->relam)); /* Both are valid, so update the dependency */ + LockNotPinnedObject(AccessMethodRelationId, rd_rel->relam); changeDependencyFor(RelationRelationId, reloid, AccessMethodRelationId, oldAccessMethodId, rd_rel->relam); @@ -17597,6 +17609,7 @@ ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode) typeobj.classId = TypeRelationId; typeobj.objectId = typeid; typeobj.objectSubId = 0; + LockNotPinnedObject(TypeRelationId, typeid); recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL); /* Update pg_class.reloftype */ @@ -18369,14 +18382,17 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid, /* Update dependency on schema if caller said so */ - if (hasDependEntry && - changeDependencyFor(RelationRelationId, - relOid, - NamespaceRelationId, - oldNspOid, - newNspOid) != 1) - elog(ERROR, "could not change schema dependency for relation \"%s\"", - NameStr(classForm->relname)); + if (hasDependEntry) + { + LockNotPinnedObject(NamespaceRelationId, newNspOid); + if (changeDependencyFor(RelationRelationId, + relOid, + NamespaceRelationId, + oldNspOid, + newNspOid) != 1) + elog(ERROR, "could not change schema dependency for relation \"%s\"", + NameStr(classForm->relname)); + } } else UnlockTuple(classRel, &classTup->t_self, InplaceUpdateTupleLock); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index c9f61130c694..5da53e5c07d3 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -1023,8 +1023,6 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true; CatalogTupleUpdate(pgrel, &tuple->t_self, tuple); - - CommandCounterIncrement(); } else CacheInvalidateRelcacheByTuple(tuple); @@ -1032,6 +1030,13 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, heap_freetuple(tuple); table_close(pgrel, RowExclusiveLock); + /* + * CommandCounterIncrement() here to ensure the new trigger entry is + * visible when LockNotPinnedObject() will check its existence before + * recording the dependencies. + */ + CommandCounterIncrement(); + /* * If we're replacing a trigger, flush all the old dependencies before * recording new ones. @@ -1050,6 +1055,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, referenced.classId = ProcedureRelationId; referenced.objectId = funcoid; referenced.objectSubId = 0; + LockNotPinnedObject(ProcedureRelationId, funcoid); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); if (isInternal && OidIsValid(constraintOid)) @@ -1063,6 +1069,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, referenced.classId = ConstraintRelationId; referenced.objectId = constraintOid; referenced.objectSubId = 0; + LockNotPinnedObject(ConstraintRelationId, constraintOid); recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); } else @@ -1075,6 +1082,8 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, referenced.classId = RelationRelationId; referenced.objectId = RelationGetRelid(rel); referenced.objectSubId = 0; + + LockNotPinnedObject(RelationRelationId, RelationGetRelid(rel)); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); if (OidIsValid(constrrelid)) @@ -1082,6 +1091,8 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, referenced.classId = RelationRelationId; referenced.objectId = constrrelid; referenced.objectSubId = 0; + + LockNotPinnedObject(RelationRelationId, constrrelid); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); } /* Not possible to have an index dependency in this case */ @@ -1096,6 +1107,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, referenced.classId = ConstraintRelationId; referenced.objectId = constraintOid; referenced.objectSubId = 0; + LockNotPinnedObject(TriggerRelationId, trigoid); recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL); } @@ -1105,8 +1117,11 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, if (OidIsValid(parentTriggerOid)) { ObjectAddressSet(referenced, TriggerRelationId, parentTriggerOid); + LockNotPinnedObject(TriggerRelationId, parentTriggerOid); recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI); ObjectAddressSet(referenced, RelationRelationId, RelationGetRelid(rel)); + + LockNotPinnedObject(RelationRelationId, RelationGetRelid(rel)); recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC); } } @@ -1115,12 +1130,19 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, if (columns != NULL) { int i; + bool locked_object = false; referenced.classId = RelationRelationId; referenced.objectId = RelationGetRelid(rel); for (i = 0; i < ncolumns; i++) { referenced.objectSubId = columns[i]; + + if (!locked_object) + { + LockNotPinnedObject(RelationRelationId, RelationGetRelid(rel)); + locked_object = true; + } recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } } @@ -1260,9 +1282,12 @@ TriggerSetParentTrigger(Relation trigRel, ObjectAddressSet(depender, TriggerRelationId, childTrigId); ObjectAddressSet(referenced, TriggerRelationId, parentTrigId); + LockNotPinnedObject(TriggerRelationId, parentTrigId); recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI); ObjectAddressSet(referenced, RelationRelationId, childTableId); + + LockNotPinnedObject(RelationRelationId, childTableId); recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC); } else diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index ab16d42ad56b..e36c3da1023b 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -214,6 +214,7 @@ DefineTSParser(List *names, List *parameters) namestrcpy(&pname, prsname); values[Anum_pg_ts_parser_prsname - 1] = NameGetDatum(&pname); values[Anum_pg_ts_parser_prsnamespace - 1] = ObjectIdGetDatum(namespaceoid); + LockNotPinnedObject(NamespaceRelationId, namespaceoid); /* * loop over the definition list and extract the information we need. @@ -224,28 +225,48 @@ DefineTSParser(List *names, List *parameters) if (strcmp(defel->defname, "start") == 0) { + Oid procoid; + values[Anum_pg_ts_parser_prsstart - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart); + procoid = DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1]); + LockNotPinnedObject(ProcedureRelationId, procoid); } else if (strcmp(defel->defname, "gettoken") == 0) { + Oid procoid; + values[Anum_pg_ts_parser_prstoken - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken); + procoid = DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1]); + LockNotPinnedObject(ProcedureRelationId, procoid); } else if (strcmp(defel->defname, "end") == 0) { + Oid procoid; + values[Anum_pg_ts_parser_prsend - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prsend); + procoid = DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1]); + LockNotPinnedObject(ProcedureRelationId, procoid); } else if (strcmp(defel->defname, "headline") == 0) { + Oid procoid; + values[Anum_pg_ts_parser_prsheadline - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline); + procoid = DatumGetObjectId(values[Anum_pg_ts_parser_prsheadline - 1]); + LockNotPinnedObject(ProcedureRelationId, procoid); } else if (strcmp(defel->defname, "lextypes") == 0) { + Oid procoid; + values[Anum_pg_ts_parser_prslextype - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype); + procoid = DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1]); + LockNotPinnedObject(ProcedureRelationId, procoid); } else ereport(ERROR, @@ -474,6 +495,10 @@ DefineTSDictionary(List *names, List *parameters) CatalogTupleInsert(dictRel, tup); + /* Lock dependent objects */ + LockNotPinnedObject(NamespaceRelationId, namespaceoid); + LockNotPinnedObject(TSTemplateRelationId, templId); + address = makeDictionaryDependencies(tup); /* Post creation hook for new text search dictionary */ @@ -723,6 +748,7 @@ DefineTSTemplate(List *names, List *parameters) namestrcpy(&dname, tmplname); values[Anum_pg_ts_template_tmplname - 1] = NameGetDatum(&dname); values[Anum_pg_ts_template_tmplnamespace - 1] = ObjectIdGetDatum(namespaceoid); + LockNotPinnedObject(NamespaceRelationId, namespaceoid); /* * loop over the definition list and extract the information we need. @@ -733,15 +759,23 @@ DefineTSTemplate(List *names, List *parameters) if (strcmp(defel->defname, "init") == 0) { + Oid procoid; + values[Anum_pg_ts_template_tmplinit - 1] = get_ts_template_func(defel, Anum_pg_ts_template_tmplinit); nulls[Anum_pg_ts_template_tmplinit - 1] = false; + procoid = DatumGetObjectId(values[Anum_pg_ts_template_tmplinit - 1]); + LockNotPinnedObject(ProcedureRelationId, procoid); } else if (strcmp(defel->defname, "lexize") == 0) { + Oid procoid; + values[Anum_pg_ts_template_tmpllexize - 1] = get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize); nulls[Anum_pg_ts_template_tmpllexize - 1] = false; + procoid = DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1]); + LockNotPinnedObject(ProcedureRelationId, procoid); } else ereport(ERROR, @@ -998,6 +1032,10 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied) values[Anum_pg_ts_config_cfgowner - 1] = ObjectIdGetDatum(GetUserId()); values[Anum_pg_ts_config_cfgparser - 1] = ObjectIdGetDatum(prsOid); + /* Lock dependent objects */ + LockNotPinnedObject(NamespaceRelationId, namespaceoid); + LockNotPinnedObject(TSParserRelationId, prsOid); + tup = heap_form_tuple(cfgRel->rd_att, values, nulls); CatalogTupleInsert(cfgRel, tup); @@ -1063,6 +1101,7 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied) slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = cfgmap->mapseqno; slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = cfgmap->mapdict; + LockNotPinnedObject(TSDictionaryRelationId, cfgmap->mapdict); ExecStoreVirtualTuple(slot[slot_stored_count]); slot_stored_count++; @@ -1156,9 +1195,13 @@ ObjectAddress AlterTSConfiguration(AlterTSConfigurationStmt *stmt) { HeapTuple tup; + Form_pg_ts_config cfg; Oid cfgId; Relation relMap; ObjectAddress address; + ScanKeyData skey; + SysScanDesc scan; + HeapTuple maptup; /* Find the configuration */ tup = GetTSConfigTuple(stmt->cfgname); @@ -1168,7 +1211,8 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt) errmsg("text search configuration \"%s\" does not exist", NameListToString(stmt->cfgname)))); - cfgId = ((Form_pg_ts_config) GETSTRUCT(tup))->oid; + cfg = (Form_pg_ts_config) GETSTRUCT(tup); + cfgId = cfg->oid; /* must be owner */ if (!object_ownercheck(TSConfigRelationId, cfgId, GetUserId())) @@ -1183,6 +1227,28 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt) else if (stmt->tokentype) DropConfigurationMapping(stmt, tup, relMap); + /* Lock dependent objects */ + + ScanKeyInit(&skey, + Anum_pg_ts_config_map_mapcfg, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(cfgId)); + + scan = systable_beginscan(relMap, TSConfigMapIndexId, true, + NULL, 1, &skey); + + while (HeapTupleIsValid((maptup = systable_getnext(scan)))) + { + Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup); + + LockNotPinnedObject(TSDictionaryRelationId, cfgmap->mapdict); + } + + systable_endscan(scan); + + LockNotPinnedObject(NamespaceRelationId, cfg->cfgnamespace); + LockNotPinnedObject(TSParserRelationId, cfg->cfgparser); + /* Update dependencies */ makeConfigurationDependencies(tup, true, relMap); @@ -1414,6 +1480,8 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt, repl_val[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictNew); repl_repl[Anum_pg_ts_config_map_mapdict - 1] = true; + LockNotPinnedObject(TSDictionaryRelationId, dictNew); + newtup = heap_modify_tuple(maptup, RelationGetDescr(relMap), repl_val, repl_null, repl_repl); @@ -1456,6 +1524,9 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt, slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = Int32GetDatum(j + 1); slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictIds[j]); + /* Lock dependent objects */ + LockNotPinnedObject(TSDictionaryRelationId, dictIds[j]); + ExecStoreVirtualTuple(slot[slotCount]); slotCount++; diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 3cb3ca1cca1c..e36ea6d97e08 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -1820,6 +1820,7 @@ makeRangeConstructors(const char *name, Oid namespace, * that they go away silently when the type is dropped. Note that * pg_dump depends on this choice to avoid dumping the constructors. */ + LockNotPinnedObject(TypeRelationId, rangeOid); recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); } } @@ -1885,6 +1886,7 @@ makeMultirangeConstructors(const char *name, Oid namespace, * that they go away silently when the type is dropped. Note that pg_dump * depends on this choice to avoid dumping the constructors. */ + LockNotPinnedObject(TypeRelationId, multirangeOid); recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); pfree(argtypes); @@ -2698,6 +2700,45 @@ AlterDomainDefault(List *names, Node *defaultRaw) CatalogTupleUpdate(rel, &tup->t_self, newtuple); + /* Lock dependent objects */ + typTup = (Form_pg_type) GETSTRUCT(newtuple); + + if (OidIsValid(typTup->typnamespace)) + LockNotPinnedObject(NamespaceRelationId, typTup->typnamespace); + + if (OidIsValid(typTup->typinput)) + LockNotPinnedObject(ProcedureRelationId, typTup->typinput); + + if (OidIsValid(typTup->typoutput)) + LockNotPinnedObject(ProcedureRelationId, typTup->typoutput); + + if (OidIsValid(typTup->typreceive)) + LockNotPinnedObject(ProcedureRelationId, typTup->typreceive); + + if (OidIsValid(typTup->typsend)) + LockNotPinnedObject(ProcedureRelationId, typTup->typsend); + + if (OidIsValid(typTup->typmodin)) + LockNotPinnedObject(ProcedureRelationId, typTup->typmodin); + + if (OidIsValid(typTup->typmodout)) + LockNotPinnedObject(ProcedureRelationId, typTup->typmodout); + + if (OidIsValid(typTup->typanalyze)) + LockNotPinnedObject(ProcedureRelationId, typTup->typanalyze); + + if (OidIsValid(typTup->typsubscript)) + LockNotPinnedObject(ProcedureRelationId, typTup->typsubscript); + + if (OidIsValid(typTup->typbasetype)) + LockNotPinnedObject(TypeRelationId, typTup->typbasetype); + + if (OidIsValid(typTup->typcollation)) + LockNotPinnedObject(CollationRelationId, typTup->typcollation); + + if (OidIsValid(typTup->typelem)) + LockNotPinnedObject(TypeRelationId, typTup->typelem); + /* Rebuild dependencies */ GenerateTypeDependencies(newtuple, rel, @@ -4263,10 +4304,13 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, if (oldNspOid != nspOid && (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) && !isImplicitArray) + { + LockNotPinnedObject(NamespaceRelationId, nspOid); if (changeDependencyFor(TypeRelationId, typeOid, NamespaceRelationId, oldNspOid, nspOid) != 1) elog(ERROR, "could not change schema dependency for type \"%s\"", format_type_be(typeOid)); + } InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0); @@ -4558,6 +4602,7 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray, SysScanDesc scan; ScanKeyData key[1]; HeapTuple domainTup; + Form_pg_type typeForm; /* Since this function recurses, it could be driven to stack overflow */ check_stack_depth(); @@ -4606,6 +4651,45 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray, newtup = heap_modify_tuple(tup, RelationGetDescr(catalog), values, nulls, replaces); + /* Lock dependent objects */ + typeForm = (Form_pg_type) GETSTRUCT(newtup); + + if (OidIsValid(typeForm->typnamespace)) + LockNotPinnedObject(NamespaceRelationId, typeForm->typnamespace); + + if (OidIsValid(typeForm->typinput)) + LockNotPinnedObject(ProcedureRelationId, typeForm->typinput); + + if (OidIsValid(typeForm->typoutput)) + LockNotPinnedObject(ProcedureRelationId, typeForm->typoutput); + + if (OidIsValid(typeForm->typreceive)) + LockNotPinnedObject(ProcedureRelationId, typeForm->typreceive); + + if (OidIsValid(typeForm->typsend)) + LockNotPinnedObject(ProcedureRelationId, typeForm->typsend); + + if (OidIsValid(typeForm->typmodin)) + LockNotPinnedObject(ProcedureRelationId, typeForm->typmodin); + + if (OidIsValid(typeForm->typmodout)) + LockNotPinnedObject(ProcedureRelationId, typeForm->typmodout); + + if (OidIsValid(typeForm->typanalyze)) + LockNotPinnedObject(ProcedureRelationId, typeForm->typanalyze); + + if (OidIsValid(typeForm->typsubscript)) + LockNotPinnedObject(ProcedureRelationId, typeForm->typsubscript); + + if (OidIsValid(typeForm->typbasetype)) + LockNotPinnedObject(TypeRelationId, typeForm->typbasetype); + + if (OidIsValid(typeForm->typcollation)) + LockNotPinnedObject(CollationRelationId, typeForm->typcollation); + + if (OidIsValid(typeForm->typelem)) + LockNotPinnedObject(TypeRelationId, typeForm->typelem); + CatalogTupleUpdate(catalog, &newtup->t_self, newtup); /* Rebuild dependencies for this type */ diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 8aa90b0d6fb7..14a6468efcac 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -155,6 +155,7 @@ InsertRule(const char *rulname, referenced.objectId = eventrel_oid; referenced.objectSubId = 0; + LockNotPinnedObject(RelationRelationId, eventrel_oid); recordDependencyOn(&myself, &referenced, (evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO); diff --git a/src/backend/utils/errcodes.txt b/src/backend/utils/errcodes.txt index c96aa7c49efe..c664ae4977be 100644 --- a/src/backend/utils/errcodes.txt +++ b/src/backend/utils/errcodes.txt @@ -277,6 +277,7 @@ Section: Class 28 - Invalid Authorization Specification Section: Class 2B - Dependent Privilege Descriptors Still Exist 2B000 E ERRCODE_DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST dependent_privilege_descriptors_still_exist +2BP02 E ERRCODE_DEPENDENT_OBJECTS_DOES_NOT_EXIST dependent_objects_does_not_exist 2BP01 E ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST dependent_objects_still_exist Section: Class 2D - Invalid Transaction Termination diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 0ea7ccf52430..73ee2c6a7873 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -101,6 +101,8 @@ typedef struct ObjectAddresses ObjectAddresses; /* in dependency.c */ extern void AcquireDeletionLock(const ObjectAddress *object, int flags); +extern void LockNotPinnedObjectById(const ObjectAddress *object); +extern void LockNotPinnedObject(Oid classid, Oid objid); extern void ReleaseDeletionLock(const ObjectAddress *object); @@ -172,6 +174,7 @@ extern long changeDependenciesOf(Oid classId, Oid oldObjectId, extern long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId); +extern bool isObjectPinned(const ObjectAddress *object); extern Oid getExtensionOfObject(Oid classId, Oid objectId); extern List *getAutoExtensionsOfObject(Oid classId, Oid objectId); diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h index 630434b73cf1..34d5428433bf 100644 --- a/src/include/catalog/objectaddress.h +++ b/src/include/catalog/objectaddress.h @@ -53,6 +53,7 @@ extern void check_object_ownership(Oid roleid, Node *object, Relation relation); extern Oid get_object_namespace(const ObjectAddress *address); +extern bool ObjectByIdExist(const ObjectAddress *address); extern bool is_objectclass_supported(Oid class_id); extern const char *get_object_class_descr(Oid class_id); diff --git a/src/test/isolation/expected/test_dependencies_locks.out b/src/test/isolation/expected/test_dependencies_locks.out new file mode 100644 index 000000000000..820680f5e169 --- /dev/null +++ b/src/test/isolation/expected/test_dependencies_locks.out @@ -0,0 +1,129 @@ +Parsed test spec with 2 sessions + +starting permutation: s1_begin s1_create_function_in_schema s2_drop_schema s1_commit +step s1_begin: BEGIN; +step s1_create_function_in_schema: CREATE FUNCTION testschema.foo() RETURNS int AS 'select 1' LANGUAGE sql; +step s2_drop_schema: DROP SCHEMA testschema; +step s1_commit: COMMIT; +step s2_drop_schema: <... completed> +ERROR: cannot drop schema testschema because other objects depend on it + +starting permutation: s2_begin s2_drop_schema s1_create_function_in_schema s2_commit +step s2_begin: BEGIN; +step s2_drop_schema: DROP SCHEMA testschema; +step s1_create_function_in_schema: CREATE FUNCTION testschema.foo() RETURNS int AS 'select 1' LANGUAGE sql; +step s2_commit: COMMIT; +step s1_create_function_in_schema: <... completed> +ERROR: dependent object does not exist + +starting permutation: s1_begin s1_alter_function_schema s2_drop_alterschema s1_commit +step s1_begin: BEGIN; +step s1_alter_function_schema: ALTER FUNCTION public.falter() SET SCHEMA alterschema; +step s2_drop_alterschema: DROP SCHEMA alterschema; +step s1_commit: COMMIT; +step s2_drop_alterschema: <... completed> +ERROR: cannot drop schema alterschema because other objects depend on it + +starting permutation: s2_begin s2_drop_alterschema s1_alter_function_schema s2_commit +step s2_begin: BEGIN; +step s2_drop_alterschema: DROP SCHEMA alterschema; +step s1_alter_function_schema: ALTER FUNCTION public.falter() SET SCHEMA alterschema; +step s2_commit: COMMIT; +step s1_alter_function_schema: <... completed> +ERROR: dependent object does not exist + +starting permutation: s1_begin s1_create_function_with_argtype s2_drop_foo_type s1_commit +step s1_begin: BEGIN; +step s1_create_function_with_argtype: CREATE FUNCTION fooargtype(num foo) RETURNS int AS 'select 1' LANGUAGE sql; +step s2_drop_foo_type: DROP TYPE public.foo; +step s1_commit: COMMIT; +step s2_drop_foo_type: <... completed> +ERROR: cannot drop type foo because other objects depend on it + +starting permutation: s2_begin s2_drop_foo_type s1_create_function_with_argtype s2_commit +step s2_begin: BEGIN; +step s2_drop_foo_type: DROP TYPE public.foo; +step s1_create_function_with_argtype: CREATE FUNCTION fooargtype(num foo) RETURNS int AS 'select 1' LANGUAGE sql; +step s2_commit: COMMIT; +step s1_create_function_with_argtype: <... completed> +ERROR: dependent object does not exist + +starting permutation: s1_begin s1_create_function_with_rettype s2_drop_foo_rettype s1_commit +step s1_begin: BEGIN; +step s1_create_function_with_rettype: CREATE FUNCTION footrettype() RETURNS id LANGUAGE sql RETURN 1; +step s2_drop_foo_rettype: DROP DOMAIN id; +step s1_commit: COMMIT; +step s2_drop_foo_rettype: <... completed> +ERROR: cannot drop type id because other objects depend on it + +starting permutation: s2_begin s2_drop_foo_rettype s1_create_function_with_rettype s2_commit +step s2_begin: BEGIN; +step s2_drop_foo_rettype: DROP DOMAIN id; +step s1_create_function_with_rettype: CREATE FUNCTION footrettype() RETURNS id LANGUAGE sql RETURN 1; +step s2_commit: COMMIT; +step s1_create_function_with_rettype: <... completed> +ERROR: dependent object does not exist + +starting permutation: s1_begin s1_create_function_with_function s2_drop_function_f s1_commit +step s1_begin: BEGIN; +step s1_create_function_with_function: CREATE FUNCTION foofunc() RETURNS int LANGUAGE SQL RETURN f() + 1; +step s2_drop_function_f: DROP FUNCTION f(); +step s1_commit: COMMIT; +step s2_drop_function_f: <... completed> +ERROR: cannot drop function f() because other objects depend on it + +starting permutation: s2_begin s2_drop_function_f s1_create_function_with_function s2_commit +step s2_begin: BEGIN; +step s2_drop_function_f: DROP FUNCTION f(); +step s1_create_function_with_function: CREATE FUNCTION foofunc() RETURNS int LANGUAGE SQL RETURN f() + 1; +step s2_commit: COMMIT; +step s1_create_function_with_function: <... completed> +ERROR: dependent object does not exist + +starting permutation: s1_begin s1_create_domain_with_domain s2_drop_domain_id s1_commit +step s1_begin: BEGIN; +step s1_create_domain_with_domain: CREATE DOMAIN idid as id; +step s2_drop_domain_id: DROP DOMAIN id; +step s1_commit: COMMIT; +step s2_drop_domain_id: <... completed> +ERROR: cannot drop type id because other objects depend on it + +starting permutation: s2_begin s2_drop_domain_id s1_create_domain_with_domain s2_commit +step s2_begin: BEGIN; +step s2_drop_domain_id: DROP DOMAIN id; +step s1_create_domain_with_domain: CREATE DOMAIN idid as id; +step s2_commit: COMMIT; +step s1_create_domain_with_domain: <... completed> +ERROR: dependent object does not exist + +starting permutation: s1_begin s1_create_table_with_type s2_drop_footab_type s1_commit +step s1_begin: BEGIN; +step s1_create_table_with_type: CREATE TABLE tabtype(a footab); +step s2_drop_footab_type: DROP TYPE public.footab; +step s1_commit: COMMIT; +step s2_drop_footab_type: <... completed> +ERROR: cannot drop type footab because other objects depend on it + +starting permutation: s2_begin s2_drop_footab_type s1_create_table_with_type s2_commit +step s2_begin: BEGIN; +step s2_drop_footab_type: DROP TYPE public.footab; +step s1_create_table_with_type: CREATE TABLE tabtype(a footab); +step s2_commit: COMMIT; +step s1_create_table_with_type: <... completed> +ERROR: dependent object does not exist + +starting permutation: s1_begin s1_create_server_with_fdw_wrapper s2_drop_fdw_wrapper s1_commit +step s1_begin: BEGIN; +step s1_create_server_with_fdw_wrapper: CREATE SERVER srv_fdw_wrapper FOREIGN DATA WRAPPER fdw_wrapper; +step s2_drop_fdw_wrapper: DROP FOREIGN DATA WRAPPER fdw_wrapper RESTRICT; +step s1_commit: COMMIT; +step s2_drop_fdw_wrapper: <... completed> +ERROR: cannot drop foreign-data wrapper fdw_wrapper because other objects depend on it + +starting permutation: s2_begin s2_drop_fdw_wrapper s1_create_server_with_fdw_wrapper s2_commit +step s2_begin: BEGIN; +step s2_drop_fdw_wrapper: DROP FOREIGN DATA WRAPPER fdw_wrapper RESTRICT; +step s1_create_server_with_fdw_wrapper: CREATE SERVER srv_fdw_wrapper FOREIGN DATA WRAPPER fdw_wrapper; +step s2_commit: COMMIT; +step s1_create_server_with_fdw_wrapper: <... completed> +ERROR: dependent object does not exist diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule index 143109aa4da9..0e80dfecfb34 100644 --- a/src/test/isolation/isolation_schedule +++ b/src/test/isolation/isolation_schedule @@ -115,3 +115,4 @@ test: serializable-parallel-2 test: serializable-parallel-3 test: matview-write-skew test: lock-nowait +test: test_dependencies_locks diff --git a/src/test/isolation/specs/test_dependencies_locks.spec b/src/test/isolation/specs/test_dependencies_locks.spec new file mode 100644 index 000000000000..5d04dfe9dc67 --- /dev/null +++ b/src/test/isolation/specs/test_dependencies_locks.spec @@ -0,0 +1,89 @@ +setup +{ + CREATE SCHEMA testschema; + CREATE SCHEMA alterschema; + CREATE TYPE public.foo as enum ('one', 'two'); + CREATE TYPE public.footab as enum ('three', 'four'); + CREATE DOMAIN id AS int; + CREATE FUNCTION f() RETURNS int LANGUAGE SQL RETURN 1; + CREATE FUNCTION public.falter() RETURNS int LANGUAGE SQL RETURN 1; + CREATE FOREIGN DATA WRAPPER fdw_wrapper; +} + +teardown +{ + DROP FUNCTION IF EXISTS testschema.foo(); + DROP FUNCTION IF EXISTS fooargtype(num foo); + DROP FUNCTION IF EXISTS footrettype(); + DROP FUNCTION IF EXISTS foofunc(); + DROP FUNCTION IF EXISTS public.falter(); + DROP FUNCTION IF EXISTS alterschema.falter(); + DROP DOMAIN IF EXISTS idid; + DROP SERVER IF EXISTS srv_fdw_wrapper; + DROP TABLE IF EXISTS tabtype; + DROP SCHEMA IF EXISTS testschema; + DROP SCHEMA IF EXISTS alterschema; + DROP TYPE IF EXISTS public.foo; + DROP TYPE IF EXISTS public.footab; + DROP DOMAIN IF EXISTS id; + DROP FUNCTION IF EXISTS f(); + DROP FOREIGN DATA WRAPPER IF EXISTS fdw_wrapper; +} + +session "s1" + +step "s1_begin" { BEGIN; } +step "s1_create_function_in_schema" { CREATE FUNCTION testschema.foo() RETURNS int AS 'select 1' LANGUAGE sql; } +step "s1_create_function_with_argtype" { CREATE FUNCTION fooargtype(num foo) RETURNS int AS 'select 1' LANGUAGE sql; } +step "s1_create_function_with_rettype" { CREATE FUNCTION footrettype() RETURNS id LANGUAGE sql RETURN 1; } +step "s1_create_function_with_function" { CREATE FUNCTION foofunc() RETURNS int LANGUAGE SQL RETURN f() + 1; } +step "s1_alter_function_schema" { ALTER FUNCTION public.falter() SET SCHEMA alterschema; } +step "s1_create_domain_with_domain" { CREATE DOMAIN idid as id; } +step "s1_create_table_with_type" { CREATE TABLE tabtype(a footab); } +step "s1_create_server_with_fdw_wrapper" { CREATE SERVER srv_fdw_wrapper FOREIGN DATA WRAPPER fdw_wrapper; } +step "s1_commit" { COMMIT; } + +session "s2" + +step "s2_begin" { BEGIN; } +step "s2_drop_schema" { DROP SCHEMA testschema; } +step "s2_drop_alterschema" { DROP SCHEMA alterschema; } +step "s2_drop_foo_type" { DROP TYPE public.foo; } +step "s2_drop_foo_rettype" { DROP DOMAIN id; } +step "s2_drop_footab_type" { DROP TYPE public.footab; } +step "s2_drop_function_f" { DROP FUNCTION f(); } +step "s2_drop_domain_id" { DROP DOMAIN id; } +step "s2_drop_fdw_wrapper" { DROP FOREIGN DATA WRAPPER fdw_wrapper RESTRICT; } +step "s2_commit" { COMMIT; } + +# function - schema +permutation "s1_begin" "s1_create_function_in_schema" "s2_drop_schema" "s1_commit" +permutation "s2_begin" "s2_drop_schema" "s1_create_function_in_schema" "s2_commit" + +# alter function - schema +permutation "s1_begin" "s1_alter_function_schema" "s2_drop_alterschema" "s1_commit" +permutation "s2_begin" "s2_drop_alterschema" "s1_alter_function_schema" "s2_commit" + +# function - argtype +permutation "s1_begin" "s1_create_function_with_argtype" "s2_drop_foo_type" "s1_commit" +permutation "s2_begin" "s2_drop_foo_type" "s1_create_function_with_argtype" "s2_commit" + +# function - rettype +permutation "s1_begin" "s1_create_function_with_rettype" "s2_drop_foo_rettype" "s1_commit" +permutation "s2_begin" "s2_drop_foo_rettype" "s1_create_function_with_rettype" "s2_commit" + +# function - function +permutation "s1_begin" "s1_create_function_with_function" "s2_drop_function_f" "s1_commit" +permutation "s2_begin" "s2_drop_function_f" "s1_create_function_with_function" "s2_commit" + +# domain - domain +permutation "s1_begin" "s1_create_domain_with_domain" "s2_drop_domain_id" "s1_commit" +permutation "s2_begin" "s2_drop_domain_id" "s1_create_domain_with_domain" "s2_commit" + +# table - type +permutation "s1_begin" "s1_create_table_with_type" "s2_drop_footab_type" "s1_commit" +permutation "s2_begin" "s2_drop_footab_type" "s1_create_table_with_type" "s2_commit" + +# server - foreign data wrapper +permutation "s1_begin" "s1_create_server_with_fdw_wrapper" "s2_drop_fdw_wrapper" "s1_commit" +permutation "s2_begin" "s2_drop_fdw_wrapper" "s1_create_server_with_fdw_wrapper" "s2_commit" diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 362f38856d29..7c162c0d4559 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -2862,11 +2862,12 @@ begin; alter table alterlock2 add constraint alterlock2nv foreign key (f1) references alterlock (f1) NOT VALID; select * from my_locks order by 1; - relname | max_lockmode -------------+----------------------- - alterlock | ShareRowExclusiveLock - alterlock2 | ShareRowExclusiveLock -(2 rows) + relname | max_lockmode +----------------+----------------------- + alterlock | ShareRowExclusiveLock + alterlock2 | ShareRowExclusiveLock + alterlock_pkey | AccessShareLock +(3 rows) commit; begin;