From 3668492e145a01a969b7c540d999f6da322a6943 Mon Sep 17 00:00:00 2001 From: Burak Velioglu Date: Fri, 4 Mar 2022 12:33:15 +0300 Subject: [PATCH] Error out if adding a new object causes a circular dependency --- .../distributed/commands/dependencies.c | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/backend/distributed/commands/dependencies.c b/src/backend/distributed/commands/dependencies.c index fe6e651fa..bc5724ad0 100644 --- a/src/backend/distributed/commands/dependencies.c +++ b/src/backend/distributed/commands/dependencies.c @@ -31,6 +31,7 @@ typedef bool (*AddressPredicate)(const ObjectAddress *); +static void ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress); static int ObjectAddressComparator(const void *a, const void *b); static List * GetDependencyCreateDDLCommands(const ObjectAddress *dependency); static List * FilterObjectAddressListByPredicate(List *objectAddressList, @@ -56,6 +57,13 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target) List *dependenciesWithCommands = NIL; List *ddlCommands = NULL; + /* + * Having circular dependency between distributed objects prevents Citus from + * adding a new node. So, error out if circular dependency exists for the given + * target object. + */ + ErrorIfCircularDependencyExists(target); + /* collect all dependencies in creation order and get their ddl commands */ List *dependencies = GetDependenciesForObject(target); ObjectAddress *dependency = NULL; @@ -135,6 +143,40 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target) } +/* + * ErrorIfCircularDependencyExists checks whether given object has circular dependency + * with itself via existing objects of pg_dist_object. + */ +static void +ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress) +{ + List *dependencies = GetAllSupportedDependenciesForObject(objectAddress); + + ObjectAddress *dependency = NULL; + foreach_ptr(dependency, dependencies) + { + if (dependency->classId == objectAddress->classId && + dependency->objectId == objectAddress->objectId && + dependency->objectSubId == objectAddress->objectSubId) + { + char *objectDescription = NULL; + + #if PG_VERSION_NUM >= PG_VERSION_14 + objectDescription = getObjectDescription(objectAddress, false); + #else + objectDescription = getObjectDescription(objectAddress); + #endif + + ereport(ERROR, (errmsg("Citus can not handle circular dependencies " + "between distributed objects"), + errdetail("\"%s\" circularly depends itself, resolve " + "circular dependency first", + objectDescription))); + } + } +} + + /* * Copied from PG object_address_comparator function to compare ObjectAddresses. */