agora inbox for [email protected]
help / color / mirror / Atom feedFrom: Bertrand Drouvot <[email protected]>
Subject: [PATCH v9] Avoid orphaned objects dependencies
Date: Fri, 29 Mar 2024 15:43:26 +0000
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 when 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).
If the object is dropped before the new lock attempt is triggered then the patch
would also report an error (but with less details).
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 | 83 +++++++++--
src/backend/catalog/heap.c | 7 +-
src/backend/catalog/index.c | 16 ++-
src/backend/catalog/objectaddress.c | 57 ++++++++
src/backend/catalog/pg_aggregate.c | 2 +-
src/backend/catalog/pg_attrdef.c | 1 +
src/backend/catalog/pg_cast.c | 2 +-
src/backend/catalog/pg_collation.c | 1 +
src/backend/catalog/pg_constraint.c | 10 +-
src/backend/catalog/pg_conversion.c | 2 +
src/backend/catalog/pg_depend.c | 34 ++++-
src/backend/catalog/pg_operator.c | 2 +-
src/backend/catalog/pg_proc.c | 12 +-
src/backend/catalog/pg_publication.c | 5 +
src/backend/catalog/pg_range.c | 3 +-
src/backend/catalog/pg_type.c | 18 ++-
src/backend/catalog/toasting.c | 1 +
src/backend/commands/alter.c | 3 +
src/backend/commands/amcmds.c | 1 +
src/backend/commands/cluster.c | 2 +
src/backend/commands/event_trigger.c | 1 +
src/backend/commands/extension.c | 4 +-
src/backend/commands/foreigncmds.c | 7 +
src/backend/commands/functioncmds.c | 3 +-
src/backend/commands/indexcmds.c | 2 +
src/backend/commands/opclasscmds.c | 18 +++
src/backend/commands/policy.c | 2 +
src/backend/commands/proclang.c | 2 +-
src/backend/commands/sequence.c | 1 +
src/backend/commands/statscmds.c | 3 +
src/backend/commands/tablecmds.c | 10 ++
src/backend/commands/trigger.c | 18 ++-
src/backend/commands/tsearchcmds.c | 8 +-
src/backend/commands/typecmds.c | 4 +
src/backend/rewrite/rewriteDefine.c | 1 +
src/backend/utils/errcodes.txt | 1 +
src/include/catalog/dependency.h | 9 +-
src/include/catalog/objectaddress.h | 1 +
.../expected/test_dependencies_locks.out | 129 ++++++++++++++++++
src/test/isolation/isolation_schedule | 1 +
.../specs/test_dependencies_locks.spec | 89 ++++++++++++
42 files changed, 534 insertions(+), 43 deletions(-)
34.8% src/backend/catalog/
16.2% src/backend/commands/
28.0% src/test/isolation/expected/
17.4% src/test/isolation/specs/
3.3% src/
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 143876b77f..6b91402a9f 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -1413,6 +1413,7 @@ SetDefaultACL(InternalDefaultACL *iacls)
referenced.objectId = iacls->nspid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
}
}
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index d4b5b2ade1..42293220fd 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1517,6 +1517,68 @@ AcquireDeletionLock(const ObjectAddress *object, int flags)
}
}
+/*
+ * depLockAndCheckObject
+ *
+ * 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
+depLockAndCheckObject(const ObjectAddress *object)
+{
+ char *object_description;
+
+ if (isObjectPinned(object))
+ return;
+
+ /*
+ * Those don't rely on LockDatabaseObject() when being dropped (see
+ * AcquireDeletionLock()). Also it looks like they can not produce
+ * orphaned dependent objects when being dropped.
+ */
+ if (object->classId == RelationRelationId || object->classId == AuthMemRelationId)
+ return;
+
+ object_description = getObjectDescription(object, true);
+
+ /* 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))
+ {
+ if (object_description)
+ ereport(ERROR,
+ (errcode(ERRCODE_DEPENDENT_OBJECTS_DOES_NOT_EXIST),
+ errmsg("%s does not exist", object_description)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_DEPENDENT_OBJECTS_DOES_NOT_EXIST),
+ errmsg("a dependent object does not exist")));
+ }
+
+ if (object_description)
+ pfree(object_description);
+
+ return;
+}
+
+void
+depLockAndCheckObjects(const ObjectAddress *object, int nobject)
+{
+ int i;
+
+ if (nobject < 0)
+ return;
+
+ for (i = 0; i < nobject; i++, object++)
+ depLockAndCheckObject(object);
+
+ return;
+}
+
/*
* ReleaseDeletionLock - release an object deletion lock
*
@@ -1562,13 +1624,8 @@ recordDependencyOnExpr(const ObjectAddress *depender,
/* Scan the expression tree for referenceable objects */
find_expr_references_walker(expr, &context);
- /* Remove any duplicates */
- eliminate_duplicate_dependencies(context.addrs);
-
- /* And record 'em */
- recordMultipleDependencies(depender,
- context.addrs->refs, context.addrs->numrefs,
- behavior);
+ /* Record all of them (this includes duplicate elimination) */
+ lock_record_object_address_dependencies(depender, context.addrs, behavior);
free_object_addresses(context.addrs);
}
@@ -1652,9 +1709,12 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
/* Record the self-dependencies with the appropriate direction */
if (!reverse_self)
+ {
+ depLockAndCheckObjects(self_addrs->refs, self_addrs->numrefs);
recordMultipleDependencies(depender,
self_addrs->refs, self_addrs->numrefs,
self_behavior);
+ }
else
{
/* Can't use recordMultipleDependencies, so do it the hard way */
@@ -1664,6 +1724,7 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
{
ObjectAddress *thisobj = self_addrs->refs + selfref;
+ depLockAndCheckObject(depender);
recordDependencyOn(thisobj, depender, self_behavior);
}
}
@@ -1672,6 +1733,7 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
}
/* Record the external dependencies */
+ depLockAndCheckObjects(context.addrs->refs, context.addrs->numrefs);
recordMultipleDependencies(depender,
context.addrs->refs, context.addrs->numrefs,
behavior);
@@ -2737,11 +2799,12 @@ stack_address_present_add_flags(const ObjectAddress *object,
* removing any duplicates.
*/
void
-record_object_address_dependencies(const ObjectAddress *depender,
- ObjectAddresses *referenced,
- DependencyType behavior)
+lock_record_object_address_dependencies(const ObjectAddress *depender,
+ ObjectAddresses *referenced,
+ DependencyType behavior)
{
eliminate_duplicate_dependencies(referenced);
+ depLockAndCheckObjects(referenced->refs, referenced->numrefs);
recordMultipleDependencies(depender,
referenced->refs, referenced->numrefs,
behavior);
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index a122bbffce..113b275fe1 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -843,6 +843,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
ObjectAddressSubSet(myself, RelationRelationId, new_rel_oid, i + 1);
ObjectAddressSet(referenced, TypeRelationId,
tupdesc->attrs[i].atttypid);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* The default collation is pinned, so don't bother recording it */
@@ -851,6 +852,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
{
ObjectAddressSet(referenced, CollationRelationId,
tupdesc->attrs[i].attcollation);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
}
@@ -1471,7 +1473,7 @@ heap_create_with_catalog(const char *relname,
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
}
@@ -3393,7 +3395,7 @@ StorePartitionKey(Relation rel,
}
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
/*
@@ -3409,6 +3411,7 @@ StorePartitionKey(Relation rel,
ObjectAddressSubSet(referenced, RelationRelationId,
RelationGetRelid(rel), partattrs[i]);
+ depLockAndCheckObject(&myself);
recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
}
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 55fdde4b24..26201e7610 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1144,7 +1144,7 @@ index_create(Relation heapRelation,
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_AUTO);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_AUTO);
free_object_addresses(addrs);
}
@@ -1157,9 +1157,11 @@ index_create(Relation heapRelation,
if (OidIsValid(parentIndexRelid))
{
ObjectAddressSet(referenced, RelationRelationId, parentIndexRelid);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
ObjectAddressSet(referenced, RelationRelationId, heapRelationId);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
}
@@ -1185,7 +1187,7 @@ index_create(Relation heapRelation,
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
/* Store dependencies on anything mentioned in index expressions */
@@ -1987,6 +1989,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 we'll check of object existence when recording the
+ * dependencies.
+ */
+ CommandCounterIncrement();
+ depLockAndCheckObject(&myself);
recordDependencyOn(&idxaddr, &myself, DEPENDENCY_INTERNAL);
/*
@@ -1998,9 +2008,11 @@ index_constraint_create(Relation heapRelation,
ObjectAddress referenced;
ObjectAddressSet(referenced, ConstraintRelationId, parentConstraintId);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
ObjectAddressSet(referenced, RelationRelationId,
RelationGetRelid(heapRelation));
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
}
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 7b536ac6fd..6d7abd3738 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2590,6 +2590,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 90fc7db949..9b5c8c8fb0 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -805,7 +805,7 @@ AggregateCreate(const char *aggName,
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
return myself;
}
diff --git a/src/backend/catalog/pg_attrdef.c b/src/backend/catalog/pg_attrdef.c
index 003ae70b4d..47b7fe75ad 100644
--- a/src/backend/catalog/pg_attrdef.c
+++ b/src/backend/catalog/pg_attrdef.c
@@ -178,6 +178,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum,
colobject.objectId = RelationGetRelid(rel);
colobject.objectSubId = attnum;
+ depLockAndCheckObject(&colobject);
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 5a5b855d51..2593bb3634 100644
--- a/src/backend/catalog/pg_cast.c
+++ b/src/backend/catalog/pg_cast.c
@@ -121,7 +121,7 @@ CastCreate(Oid sourcetypeid, Oid targettypeid,
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, behavior);
+ lock_record_object_address_dependencies(&myself, addrs, behavior);
free_object_addresses(addrs);
/* dependency on extension */
diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c
index 7f2f701229..43ceb426d4 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;
+ depLockAndCheckObject(&referenced);
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 3baf9231ed..91af823ee5 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -277,8 +277,8 @@ CreateConstraintEntry(const char *constraintName,
add_exact_object_address(&domobject, addrs_auto);
}
- record_object_address_dependencies(&conobject, addrs_auto,
- DEPENDENCY_AUTO);
+ lock_record_object_address_dependencies(&conobject, addrs_auto,
+ DEPENDENCY_AUTO);
free_object_addresses(addrs_auto);
/* Handle set of normal dependencies */
@@ -352,8 +352,8 @@ CreateConstraintEntry(const char *constraintName,
}
}
- record_object_address_dependencies(&conobject, addrs_normal,
- DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&conobject, addrs_normal,
+ DEPENDENCY_NORMAL);
free_object_addresses(addrs_normal);
/*
@@ -858,9 +858,11 @@ ConstraintSetParentConstraint(Oid childConstrId,
ObjectAddressSet(depender, ConstraintRelationId, childConstrId);
ObjectAddressSet(referenced, ConstraintRelationId, parentConstrId);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI);
ObjectAddressSet(referenced, RelationRelationId, childTableId);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC);
}
else
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 0770878eac..479dd528eb 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;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* create dependency on namespace */
referenced.classId = NamespaceRelationId;
referenced.objectId = connamespace;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
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 cfd7ef51df..47968ee8c8 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -20,21 +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/lock.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/rel.h"
-static bool isObjectPinned(const ObjectAddress *object);
-
-
/*
* Record a dependency between 2 objects via their respective objectAddress.
* The first argument is the dependent object, the second the one it
@@ -100,6 +99,25 @@ recordMultipleDependencies(const ObjectAddress *depender,
slot_init_count = 0;
for (i = 0; i < nreferenced; i++, referenced++)
{
+#ifdef USE_ASSERT_CHECKING
+ LOCKTAG tag;
+
+ SET_LOCKTAG_OBJECT(tag,
+ MyDatabaseId,
+ referenced->classId,
+ referenced->objectId,
+ 0);
+
+ /*
+ * Assert the referenced object is locked (see
+ * depLockAndCheckObject()) when recording the dependency.
+ */
+ Assert(isObjectPinned(referenced) ||
+ referenced->classId == RelationRelationId ||
+ referenced->classId == AuthMemRelationId ||
+ LockHeldByMe(&tag, AccessShareLock));
+#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
@@ -239,6 +257,7 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object,
extension.objectId = CurrentExtensionObject;
extension.objectSubId = 0;
+ depLockAndCheckObject(&extension);
recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
}
}
@@ -501,11 +520,18 @@ changeDependencyFor(Oid classId, Oid objectId,
depAddr.classId = classId;
depAddr.objectId = objectId;
depAddr.objectSubId = 0;
+ depLockAndCheckObject(&objAddr);
recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL);
return 1;
}
+ /*
+ * Acquire a lock and check object still exists while changing the
+ * dependency.
+ */
+ depLockAndCheckObject(&objAddr);
+
depRel = table_open(DependRelationId, RowExclusiveLock);
/* There should be existing dependency record(s), so search. */
@@ -706,7 +732,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 65b45a424a..7e40471baf 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -930,7 +930,7 @@ makeOperatorDependencies(HeapTuple tuple,
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
/* Dependency on owner */
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 528c17cd7f..aa36a07648 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 we'll check of object existence when recording the
+ * dependencies.
+ */
+ CommandCounterIncrement();
+
addrs = new_object_addresses();
ObjectAddressSet(myself, ProcedureRelationId, retval);
@@ -637,7 +644,7 @@ ProcedureCreate(const char *procedureName,
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
/* dependency on SQL routine body */
@@ -674,9 +681,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 0602398a54..6654b65f41 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -438,10 +438,12 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
/* Add dependency on the publication */
ObjectAddressSet(referenced, PublicationRelationId, pubid);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
/* Add dependency on the relation */
ObjectAddressSet(referenced, RelationRelationId, relid);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
/* Add dependency on the objects mentioned in the qualifications */
@@ -454,6 +456,7 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
for (int i = 0; i < natts; i++)
{
ObjectAddressSubSet(referenced, RelationRelationId, relid, attarray[i]);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
@@ -661,10 +664,12 @@ publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)
/* Add dependency on the publication */
ObjectAddressSet(referenced, PublicationRelationId, pubid);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
/* Add dependency on the schema */
ObjectAddressSet(referenced, NamespaceRelationId, schemaid);
+ depLockAndCheckObject(&referenced);
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 501a6ba410..a2f343a81a 100644
--- a/src/backend/catalog/pg_range.c
+++ b/src/backend/catalog/pg_range.c
@@ -92,13 +92,14 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation,
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
/* record multirange type's dependency on the range type */
referencing.classId = TypeRelationId;
referencing.objectId = multirangeTypeOid;
referencing.objectSubId = 0;
+ depLockAndCheckObject(&myself);
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 395dec8ed8..91139e275f 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -494,6 +494,14 @@ 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 we'll check of object existence when recording the
+ * dependencies.
+ */
+ CommandCounterIncrement();
+
GenerateTypeDependencies(tup,
pg_type_desc,
(defaultTypeBin ?
@@ -505,6 +513,7 @@ TypeCreate(Oid newTypeOid,
isDependentType,
true, /* make extension dependency */
rebuildDeps);
+ }
/* Post creation hook for new type */
InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
@@ -703,7 +712,7 @@ GenerateTypeDependencies(HeapTuple typeTuple,
add_exact_object_address(&referenced, addrs_normal);
}
- record_object_address_dependencies(&myself, addrs_normal, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs_normal, DEPENDENCY_NORMAL);
free_object_addresses(addrs_normal);
/* Normal dependency on the default expression. */
@@ -724,9 +733,15 @@ GenerateTypeDependencies(HeapTuple typeTuple,
ObjectAddressSet(referenced, RelationRelationId, typeForm->typrelid);
if (relationKind != RELKIND_COMPOSITE_TYPE)
+ {
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+ }
else
+ {
+ depLockAndCheckObject(&myself);
recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
+ }
}
/*
@@ -737,6 +752,7 @@ GenerateTypeDependencies(HeapTuple typeTuple,
if (OidIsValid(typeForm->typelem))
{
ObjectAddressSet(referenced, TypeRelationId, typeForm->typelem);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced,
isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
}
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 738bc46ae8..a471833efe 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -367,6 +367,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
toastobject.objectId = toast_relid;
toastobject.objectSubId = 0;
+ depLockAndCheckObject(&baseobject);
recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL);
}
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 4f99ebb447..e3ad5db529 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -501,7 +501,10 @@ ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddre
currexts = getAutoExtensionsOfObject(address.classId,
address.objectId);
if (!list_member_oid(currexts, refAddr.objectId))
+ {
+ depLockAndCheckObject(&refAddr);
recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION);
+ }
}
return address;
diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c
index aaa0f9a1dc..0b4e44131a 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;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
recordDependencyOnCurrentExtension(&myself, false);
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 78f96789b0..73bcd68a1f 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -1381,6 +1381,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
{
baseobject.objectId = r1;
toastobject.objectId = relform1->reltoastrelid;
+ depLockAndCheckObject(&baseobject);
recordDependencyOn(&toastobject, &baseobject,
DEPENDENCY_INTERNAL);
}
@@ -1389,6 +1390,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
{
baseobject.objectId = r2;
toastobject.objectId = relform2->reltoastrelid;
+ depLockAndCheckObject(&baseobject);
recordDependencyOn(&toastobject, &baseobject,
DEPENDENCY_INTERNAL);
}
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 7a5ed6b985..ddcba91c92 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;
+ depLockAndCheckObject(&referenced);
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 1643c8c69a..fdcffcea01 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1935,7 +1935,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner,
}
/* Record all of them (this includes duplicate elimination) */
- record_object_address_dependencies(&myself, refobjs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, refobjs, DEPENDENCY_NORMAL);
free_object_addresses(refobjs);
/* Post creation hook for new extension */
@@ -3258,6 +3258,7 @@ ApplyExtensionUpdates(Oid extensionOid,
otherext.objectId = reqext;
otherext.objectSubId = 0;
+ depLockAndCheckObject(&otherext);
recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
}
@@ -3414,6 +3415,7 @@ ExecAlterExtensionContentsRecurse(AlterExtensionContentsStmt *stmt,
/*
* OK, add the dependency.
*/
+ depLockAndCheckObject(&extension);
recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
/*
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index cf61bbac1f..5e98f3d0d6 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;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
@@ -650,6 +651,7 @@ CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt)
referenced.classId = ProcedureRelationId;
referenced.objectId = fdwvalidator;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
@@ -811,6 +813,7 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt)
referenced.classId = ProcedureRelationId;
referenced.objectId = fdwhandler;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
@@ -819,6 +822,7 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt)
referenced.classId = ProcedureRelationId;
referenced.objectId = fdwvalidator;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
}
@@ -951,6 +955,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
referenced.classId = ForeignDataWrapperRelationId;
referenced.objectId = fdw->fdwid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
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;
+ depLockAndCheckObject(&referenced);
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;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
table_close(ftrel, RowExclusiveLock);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 6593fd7d81..2a378a53d8 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1459,6 +1459,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
referenced.classId = ProcedureRelationId;
referenced.objectId = newsupport;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&address, &referenced, DEPENDENCY_NORMAL);
}
@@ -1979,7 +1980,7 @@ CreateTransform(CreateTransformStmt *stmt)
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
/* dependency on extension */
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 309389e20d..487708d885 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -4377,8 +4377,10 @@ IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
ObjectAddressSet(partitionTbl, RelationRelationId,
partitionIdx->rd_index->indrelid);
+ depLockAndCheckObject(&parentIdx);
recordDependencyOn(&partIdx, &parentIdx,
DEPENDENCY_PARTITION_PRI);
+ depLockAndCheckObject(&partitionTbl);
recordDependencyOn(&partIdx, &partitionTbl,
DEPENDENCY_PARTITION_SEC);
}
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index b8b5c147c5..e7b1cb911e 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -298,12 +298,14 @@ CreateOpFamily(CreateOpFamilyStmt *stmt, const char *opfname,
referenced.classId = AccessMethodRelationId;
referenced.objectId = amoid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
/* dependency on namespace */
referenced.classId = NamespaceRelationId;
referenced.objectId = namespaceoid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on owner */
@@ -725,18 +727,21 @@ DefineOpClass(CreateOpClassStmt *stmt)
referenced.classId = NamespaceRelationId;
referenced.objectId = namespaceoid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on opfamily */
referenced.classId = OperatorFamilyRelationId;
referenced.objectId = opfamilyoid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
/* dependency on indexed datatype */
referenced.classId = TypeRelationId;
referenced.objectId = typeoid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on storage datatype */
@@ -745,6 +750,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
referenced.classId = TypeRelationId;
referenced.objectId = storageoid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
@@ -1486,6 +1492,13 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
heap_freetuple(tup);
+ /*
+ * CommandCounterIncrement here to ensure the new operator entry is
+ * visible when we'll check of object existence when recording the
+ * dependencies.
+ */
+ CommandCounterIncrement();
+
/* Make its dependencies */
myself.classId = AccessMethodOperatorRelationId;
myself.objectId = entryoid;
@@ -1496,6 +1509,7 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
referenced.objectSubId = 0;
/* see comments in amapi.h about dependency strength */
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced,
op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
@@ -1504,6 +1518,7 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
referenced.objectId = op->refobjid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced,
op->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
@@ -1514,6 +1529,7 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
referenced.objectId = op->sortfamily;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced,
op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
}
@@ -1597,6 +1613,7 @@ storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
referenced.objectSubId = 0;
/* see comments in amapi.h about dependency strength */
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced,
proc->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
@@ -1605,6 +1622,7 @@ storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
referenced.objectId = proc->refobjid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced,
proc->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 6ff3eba824..5a50ad73fb 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;
+ depLockAndCheckObject(&target);
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;
+ depLockAndCheckObject(&target);
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 881f90017e..679155162e 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -205,7 +205,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
/* Post creation hook for new procedural language */
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 28f8522264..0d37576d22 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1681,6 +1681,7 @@ process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
depobject.classId = RelationRelationId;
depobject.objectId = RelationGetRelid(seqrel);
depobject.objectSubId = 0;
+ depLockAndCheckObject(&refobject);
recordDependencyOn(&depobject, &refobject, deptype);
}
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index 1db3ef69d2..455ec046f8 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -536,6 +536,7 @@ CreateStatistics(CreateStatsStmt *stmt)
for (i = 0; i < nattnums; i++)
{
ObjectAddressSubSet(parentobject, RelationRelationId, relid, attnums[i]);
+ depLockAndCheckObject(&parentobject);
recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
}
@@ -553,6 +554,7 @@ CreateStatistics(CreateStatsStmt *stmt)
if (!nattnums)
{
ObjectAddressSet(parentobject, RelationRelationId, relid);
+ depLockAndCheckObject(&parentobject);
recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
}
@@ -573,6 +575,7 @@ CreateStatistics(CreateStatsStmt *stmt)
* than the underlying table(s).
*/
ObjectAddressSet(parentobject, NamespaceRelationId, namespaceId);
+ depLockAndCheckObject(&parentobject);
recordDependencyOn(&myself, &parentobject, DEPENDENCY_NORMAL);
recordDependencyOnOwner(StatisticExtRelationId, statoid, stxowner);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 7b6c69b7a5..73696a4210 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3437,6 +3437,7 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
childobject.objectId = relationId;
childobject.objectSubId = 0;
+ depLockAndCheckObject(&parentobject);
recordDependencyOn(&childobject, &parentobject,
child_dependency_type(child_is_partition));
@@ -7440,6 +7441,7 @@ add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
referenced.classId = TypeRelationId;
referenced.objectId = typid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
@@ -7461,6 +7463,7 @@ add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
referenced.classId = CollationRelationId;
referenced.objectId = collid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
}
@@ -10140,6 +10143,7 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
ObjectAddress referenced;
ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
}
@@ -10431,8 +10435,10 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
*/
ObjectAddressSet(address, ConstraintRelationId, constrOid);
ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
ObjectAddressSet(referenced, RelationRelationId, partitionId);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
/* Make all this visible before recursing */
@@ -10933,9 +10939,11 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
/* Set up partition dependencies for the new constraint */
ObjectAddressSet(address, ConstraintRelationId, constrOid);
ObjectAddressSet(referenced, ConstraintRelationId, parentConstrOid);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
ObjectAddressSet(referenced, RelationRelationId,
RelationGetRelid(partRel));
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
/* Done with the cloned constraint's tuple */
@@ -14782,6 +14790,7 @@ ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId)
*/
ObjectAddressSet(relobj, RelationRelationId, reloid);
ObjectAddressSet(referenced, AccessMethodRelationId, rd_rel->relam);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&relobj, &referenced, DEPENDENCY_NORMAL);
}
else if (OidIsValid(oldAccessMethodId) &&
@@ -16400,6 +16409,7 @@ ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
typeobj.classId = TypeRelationId;
typeobj.objectId = typeid;
typeobj.objectSubId = 0;
+ depLockAndCheckObject(&typeobj);
recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
/* Update pg_class.reloftype */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 95de402fa6..c0e7ddff1c 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -1018,8 +1018,6 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
CatalogTupleUpdate(pgrel, &tuple->t_self, tuple);
-
- CommandCounterIncrement();
}
else
CacheInvalidateRelcacheByTuple(tuple);
@@ -1027,6 +1025,12 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
heap_freetuple(tuple);
table_close(pgrel, RowExclusiveLock);
+ /*
+ * CommandCounterIncrement here to ensure the new trigger entry is visible
+ * when we'll check of object existence when recording the dependencies.
+ */
+ CommandCounterIncrement();
+
/*
* If we're replacing a trigger, flush all the old dependencies before
* recording new ones.
@@ -1045,6 +1049,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
referenced.classId = ProcedureRelationId;
referenced.objectId = funcoid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
if (isInternal && OidIsValid(constraintOid))
@@ -1058,6 +1063,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
referenced.classId = ConstraintRelationId;
referenced.objectId = constraintOid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
}
else
@@ -1070,6 +1076,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
referenced.classId = RelationRelationId;
referenced.objectId = RelationGetRelid(rel);
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
if (OidIsValid(constrrelid))
@@ -1077,6 +1084,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
referenced.classId = RelationRelationId;
referenced.objectId = constrrelid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
}
/* Not possible to have an index dependency in this case */
@@ -1091,6 +1099,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
referenced.classId = ConstraintRelationId;
referenced.objectId = constraintOid;
referenced.objectSubId = 0;
+ depLockAndCheckObject(&myself);
recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
}
@@ -1100,8 +1109,10 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
if (OidIsValid(parentTriggerOid))
{
ObjectAddressSet(referenced, TriggerRelationId, parentTriggerOid);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
ObjectAddressSet(referenced, RelationRelationId, RelationGetRelid(rel));
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
}
}
@@ -1116,6 +1127,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
for (i = 0; i < ncolumns; i++)
{
referenced.objectSubId = columns[i];
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
}
@@ -1255,9 +1267,11 @@ TriggerSetParentTrigger(Relation trigRel,
ObjectAddressSet(depender, TriggerRelationId, childTrigId);
ObjectAddressSet(referenced, TriggerRelationId, parentTrigId);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI);
ObjectAddressSet(referenced, RelationRelationId, childTableId);
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC);
}
else
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index b7b5019f1e..a62c997725 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -171,7 +171,7 @@ makeParserDependencies(HeapTuple tuple)
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
return myself;
@@ -329,7 +329,7 @@ makeDictionaryDependencies(HeapTuple tuple)
ObjectAddressSet(referenced, TSTemplateRelationId, dict->dicttemplate);
add_exact_object_address(&referenced, addrs);
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
return myself;
@@ -677,7 +677,7 @@ makeTSTemplateDependencies(HeapTuple tuple)
add_exact_object_address(&referenced, addrs);
}
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
return myself;
@@ -885,7 +885,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
}
/* Record 'em (this includes duplicate elimination) */
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+ lock_record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 2a1e713335..cbb61c1207 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -1794,6 +1794,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.
*/
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
}
}
@@ -1859,6 +1860,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.
*/
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
pfree(argtypes);
@@ -1898,6 +1900,7 @@ makeMultirangeConstructors(const char *name, Oid namespace,
1.0, /* procost */
0.0); /* prorows */
/* ditto */
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
pfree(argtypes);
*castFuncOid = myself.objectId;
@@ -1936,6 +1939,7 @@ makeMultirangeConstructors(const char *name, Oid namespace,
1.0, /* procost */
0.0); /* prorows */
/* ditto */
+ depLockAndCheckObject(&referenced);
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
pfree(argtypes);
pfree(allParameterTypes);
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 6cc9a8d8bf..53308dceb6 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;
+ depLockAndCheckObject(&referenced);
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 3250d539e1..60e8539fe3 100644
--- a/src/backend/utils/errcodes.txt
+++ b/src/backend/utils/errcodes.txt
@@ -271,6 +271,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 7eee66f810..f404a92fb4 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 depLockAndCheckObject(const ObjectAddress *object);
+extern void depLockAndCheckObjects(const ObjectAddress *object, int nobject);
extern void ReleaseDeletionLock(const ObjectAddress *object);
@@ -128,9 +130,9 @@ extern void add_exact_object_address(const ObjectAddress *object,
extern bool object_address_present(const ObjectAddress *object,
const ObjectAddresses *addrs);
-extern void record_object_address_dependencies(const ObjectAddress *depender,
- ObjectAddresses *referenced,
- DependencyType behavior);
+extern void lock_record_object_address_dependencies(const ObjectAddress *depender,
+ ObjectAddresses *referenced,
+ DependencyType behavior);
extern void sort_object_addresses(ObjectAddresses *addrs);
@@ -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 3a70d80e32..56f746264b 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 0000000000..9b645d7aa5
--- /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; <waiting ...>
+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; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_function_in_schema: <... completed>
+ERROR: schema testschema 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; <waiting ...>
+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; <waiting ...>
+step s2_commit: COMMIT;
+step s1_alter_function_schema: <... completed>
+ERROR: schema alterschema 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; <waiting ...>
+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; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_function_with_argtype: <... completed>
+ERROR: type foo 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; <waiting ...>
+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; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_function_with_rettype: <... completed>
+ERROR: type id 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(); <waiting ...>
+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; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_function_with_function: <... completed>
+ERROR: function f() 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; <waiting ...>
+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; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_domain_with_domain: <... completed>
+ERROR: type id 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; <waiting ...>
+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); <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_table_with_type: <... completed>
+ERROR: type footab 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; <waiting ...>
+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; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_server_with_fdw_wrapper: <... completed>
+ERROR: foreign-data wrapper fdw_wrapper does not exist
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 0342eb39e4..1b67f0bffe 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -114,3 +114,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 0000000000..5d04dfe9dc
--- /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"
--
2.34.1
--xlZXO4tPcOr9Z9/W--
view thread (17190+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: [PATCH v9] Avoid orphaned objects dependencies
In-Reply-To: <no-message-id-180977@localhost>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox