aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/opclasscmds.c98
-rw-r--r--src/include/access/amapi.h4
2 files changed, 102 insertions, 0 deletions
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 5f7ee238863..3c0acfafbd2 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -66,6 +66,7 @@ static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *operators, bool isAdd);
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *procedures, bool isAdd);
+static bool typeDepNeeded(Oid typid, OpFamilyMember *member);
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *operators);
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
@@ -1508,6 +1509,29 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
recordDependencyOn(&myself, &referenced,
op->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
+ if (typeDepNeeded(op->lefttype, op))
+ {
+ referenced.classId = TypeRelationId;
+ referenced.objectId = op->lefttype;
+ referenced.objectSubId = 0;
+
+ /* see comments in amapi.h about dependency strength */
+ recordDependencyOn(&myself, &referenced,
+ op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
+ }
+
+ if (op->lefttype != op->righttype &&
+ typeDepNeeded(op->righttype, op))
+ {
+ referenced.classId = TypeRelationId;
+ referenced.objectId = op->righttype;
+ referenced.objectSubId = 0;
+
+ /* see comments in amapi.h about dependency strength */
+ recordDependencyOn(&myself, &referenced,
+ op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
+ }
+
/* A search operator also needs a dep on the referenced opfamily */
if (OidIsValid(op->sortfamily))
{
@@ -1609,6 +1633,29 @@ storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
recordDependencyOn(&myself, &referenced,
proc->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
+ if (typeDepNeeded(proc->lefttype, proc))
+ {
+ referenced.classId = TypeRelationId;
+ referenced.objectId = proc->lefttype;
+ referenced.objectSubId = 0;
+
+ /* see comments in amapi.h about dependency strength */
+ recordDependencyOn(&myself, &referenced,
+ proc->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
+ }
+
+ if (proc->lefttype != proc->righttype &&
+ typeDepNeeded(proc->righttype, proc))
+ {
+ referenced.classId = TypeRelationId;
+ referenced.objectId = proc->righttype;
+ referenced.objectSubId = 0;
+
+ /* see comments in amapi.h about dependency strength */
+ recordDependencyOn(&myself, &referenced,
+ proc->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
+ }
+
/* Post create hook of access method procedure */
InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
entryoid, 0);
@@ -1617,6 +1664,57 @@ storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
table_close(rel, RowExclusiveLock);
}
+/*
+ * Detect whether a pg_amop or pg_amproc entry needs an explicit dependency
+ * on its lefttype or righttype.
+ *
+ * We make such a dependency unless the entry has an indirect dependency
+ * via its referenced operator or function. That's nearly always true
+ * for operators, but might well not be true for support functions.
+ */
+static bool
+typeDepNeeded(Oid typid, OpFamilyMember *member)
+{
+ bool result = true;
+
+ /*
+ * If the type is pinned, we don't need a dependency. This is a bit of a
+ * layering violation perhaps (recordDependencyOn would ignore the request
+ * anyway), but it's a cheap test and will frequently save a syscache
+ * lookup here.
+ */
+ if (IsPinnedObject(TypeRelationId, typid))
+ return false;
+
+ /* Nope, so check the input types of the function or operator. */
+ if (member->is_func)
+ {
+ Oid *argtypes;
+ int nargs;
+
+ (void) get_func_signature(member->object, &argtypes, &nargs);
+ for (int i = 0; i < nargs; i++)
+ {
+ if (typid == argtypes[i])
+ {
+ result = false; /* match, no dependency needed */
+ break;
+ }
+ }
+ pfree(argtypes);
+ }
+ else
+ {
+ Oid lefttype,
+ righttype;
+
+ op_input_types(member->object, &lefttype, &righttype);
+ if (typid == lefttype || typid == righttype)
+ result = false; /* match, no dependency needed */
+ }
+ return result;
+}
+
/*
* Remove operator entries from an opfamily.
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
index 4476ff7fba1..2d70c5678c3 100644
--- a/src/include/access/amapi.h
+++ b/src/include/access/amapi.h
@@ -76,6 +76,10 @@ typedef enum IndexAMProperty
* opfamily. This allows ALTER OPERATOR FAMILY DROP, and causes that to
* happen automatically if the operator or support func is dropped. This
* is the right behavior for inessential ("loose") objects.
+ *
+ * We also make dependencies on lefttype/righttype, of the same strength as
+ * the dependency on the operator or support func, unless these dependencies
+ * are redundant with the dependency on the operator or support func.
*/
typedef struct OpFamilyMember
{