diff --git a/src/backend/distributed/commands/citus_add_local_table_to_metadata.c b/src/backend/distributed/commands/citus_add_local_table_to_metadata.c index 6752a3ee3..e447a2be1 100644 --- a/src/backend/distributed/commands/citus_add_local_table_to_metadata.c +++ b/src/backend/distributed/commands/citus_add_local_table_to_metadata.c @@ -318,7 +318,6 @@ CreateCitusLocalTable(Oid relationId, bool cascadeViaForeignKeys, bool autoConve * Ensure dependencies exist as we will create shell table on the other nodes * in the MX case. */ - EnsureRelationDependenciesCanBeDistributed(&tableAddress); EnsureDependenciesExistOnAllNodes(&tableAddress); /* diff --git a/src/backend/distributed/commands/create_distributed_table.c b/src/backend/distributed/commands/create_distributed_table.c index 64734fff8..c639d836c 100644 --- a/src/backend/distributed/commands/create_distributed_table.c +++ b/src/backend/distributed/commands/create_distributed_table.c @@ -444,7 +444,6 @@ CreateDistributedTable(Oid relationId, char *distributionColumnName, ObjectAddress tableAddress = { 0 }; ObjectAddressSet(tableAddress, RelationRelationId, relationId); - EnsureRelationDependenciesCanBeDistributed(&tableAddress); EnsureDependenciesExistOnAllNodes(&tableAddress); char replicationModel = DecideReplicationModel(distributionMethod, diff --git a/src/backend/distributed/commands/dependencies.c b/src/backend/distributed/commands/dependencies.c index bc5724ad0..c8f70a010 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 EnsureDependenciesCanBeDistributed(const ObjectAddress *relationAddress); static void ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress); static int ObjectAddressComparator(const void *a, const void *b); static List * GetDependencyCreateDDLCommands(const ObjectAddress *dependency); @@ -58,11 +59,10 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target) 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. + * If there is any unsupported dependency or circular dependency exists, Citus can + * not ensure dependencies will exist on all nodes. */ - ErrorIfCircularDependencyExists(target); + EnsureDependenciesCanBeDistributed(target); /* collect all dependencies in creation order and get their ddl commands */ List *dependencies = GetDependenciesForObject(target); @@ -143,6 +143,61 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target) } +/* + * EnsureDependenciesCanBeDistributed ensures all dependencies of the given object + * can be distributed. + */ +static void +EnsureDependenciesCanBeDistributed(const ObjectAddress *objectAddress) +{ + /* If an object circularcly depends to itself, Citus can not handle it */ + ErrorIfCircularDependencyExists(objectAddress); + + /* If any of the dependency of the object can not be distributed, error out */ + ObjectAddress *undistributableDependency = GetUndistributableDependency( + objectAddress); + if (undistributableDependency != NULL) + { + if (SupportedDependencyByCitus(undistributableDependency)) + { + /* + * Citus can't distribute some relations as dependency, although those + * types as supported by Citus. So we can use get_rel_name directly + * + * For now the relations are the only type that is supported by Citus + * but can not be distributed as dependency, though we've added an + * explicit check below as well to not to break the logic here in case + * GetUndistributableDependency changes. + */ + if (getObjectClass(undistributableDependency) == OCLASS_CLASS) + { + char *tableName = get_rel_name(objectAddress->objectId); + char *dependentRelationName = get_rel_name( + undistributableDependency->objectId); + + ereport(ERROR, (errmsg("Relation \"%s\" has dependency to a table" + " \"%s\" that is not in Citus' metadata", + tableName, dependentRelationName), + errhint("Distribute dependent relation first."))); + } + } + + char *dependencyDescription = NULL; + char *objectDescription = NULL; + #if PG_VERSION_NUM >= PG_VERSION_14 + dependencyDescription = getObjectDescription(undistributableDependency, false); + objectDescription = getObjectDescription(objectAddress, false); + #else + dependencyDescription = getObjectDescription(undistributableDependency); + objectDescription = getObjectDescription(objectAddress); + #endif + ereport(ERROR, (errmsg("Object \"%s\" has dependency on unsupported " + "object \"%s\"", objectDescription, + dependencyDescription))); + } +} + + /* * ErrorIfCircularDependencyExists checks whether given object has circular dependency * with itself via existing objects of pg_dist_object. diff --git a/src/backend/distributed/commands/table.c b/src/backend/distributed/commands/table.c index fe1e21daf..4bf1ff373 100644 --- a/src/backend/distributed/commands/table.c +++ b/src/backend/distributed/commands/table.c @@ -1955,7 +1955,6 @@ PostprocessAlterTableStmt(AlterTableStmt *alterTableStatement) /* changing a relation could introduce new dependencies */ ObjectAddress tableAddress = { 0 }; ObjectAddressSet(tableAddress, RelationRelationId, relationId); - EnsureRelationDependenciesCanBeDistributed(&tableAddress); EnsureDependenciesExistOnAllNodes(&tableAddress); } diff --git a/src/backend/distributed/metadata/dependency.c b/src/backend/distributed/metadata/dependency.c index 5994c5d51..d7bff1ae1 100644 --- a/src/backend/distributed/metadata/dependency.c +++ b/src/backend/distributed/metadata/dependency.c @@ -741,61 +741,12 @@ SupportedDependencyByCitus(const ObjectAddress *address) } -/* - * EnsureRelationDependenciesCanBeDistributed ensures all dependencies of the relation - * can be distributed. - */ -void -EnsureRelationDependenciesCanBeDistributed(ObjectAddress *relationAddress) -{ - ObjectAddress *undistributableDependency = - GetUndistributableDependency(relationAddress); - - if (undistributableDependency != NULL) - { - char *tableName = get_rel_name(relationAddress->objectId); - - if (SupportedDependencyByCitus(undistributableDependency)) - { - /* - * Citus can't distribute some relations as dependency, although those - * types as supported by Citus. So we can use get_rel_name directly - * - * For now the relations are the only type that is supported by Citus - * but can not be distributed as dependency, though we've added an - * explicit check below as well to not to break the logic here in case - * GetUndistributableDependency changes. - */ - if (getObjectClass(undistributableDependency) == OCLASS_CLASS) - { - char *dependentRelationName = get_rel_name( - undistributableDependency->objectId); - - ereport(ERROR, (errmsg("Relation \"%s\" has dependency to a table" - " \"%s\" that is not in Citus' metadata", - tableName, dependentRelationName), - errhint("Distribute dependent relation first."))); - } - } - - char *objectType = NULL; - #if PG_VERSION_NUM >= PG_VERSION_14 - objectType = getObjectDescription(undistributableDependency, false); - #else - objectType = getObjectDescription(undistributableDependency); - #endif - ereport(ERROR, (errmsg("Relation \"%s\" has dependency on unsupported " - "object \"%s\"", tableName, objectType))); - } -} - - /* * GetUndistributableDependency checks whether object has any non-distributable * dependency. If any one found, it will be returned. */ ObjectAddress * -GetUndistributableDependency(ObjectAddress *objectAddress) +GetUndistributableDependency(const ObjectAddress *objectAddress) { List *dependencies = GetAllDependenciesForObject(objectAddress); ObjectAddress *dependency = NULL; diff --git a/src/include/distributed/commands.h b/src/include/distributed/commands.h index 8ec3d9e8a..660220324 100644 --- a/src/include/distributed/commands.h +++ b/src/include/distributed/commands.h @@ -267,7 +267,6 @@ extern List * PreprocessCreateFunctionStmt(Node *stmt, const char *queryString, ProcessUtilityContext processUtilityContext); extern List * PostprocessCreateFunctionStmt(Node *stmt, const char *queryString); -extern ObjectAddress * GetUndistributableDependency(ObjectAddress *functionAddress); extern ObjectAddress CreateFunctionStmtObjectAddress(Node *stmt, bool missing_ok); extern ObjectAddress DefineAggregateStmtObjectAddress(Node *stmt, diff --git a/src/include/distributed/metadata/dependency.h b/src/include/distributed/metadata/dependency.h index 92714f6cb..79a8575d9 100644 --- a/src/include/distributed/metadata/dependency.h +++ b/src/include/distributed/metadata/dependency.h @@ -21,8 +21,7 @@ extern List * GetUniqueDependenciesList(List *objectAddressesList); extern List * GetDependenciesForObject(const ObjectAddress *target); extern List * GetAllSupportedDependenciesForObject(const ObjectAddress *target); extern List * GetAllDependenciesForObject(const ObjectAddress *target); -extern void EnsureRelationDependenciesCanBeDistributed(ObjectAddress *relationAddress); -extern ObjectAddress * GetUndistributableDependency(ObjectAddress *target); +extern ObjectAddress * GetUndistributableDependency(const ObjectAddress *target); extern List * OrderObjectAddressListInDependencyOrder(List *objectAddressList); extern bool SupportedDependencyByCitus(const ObjectAddress *address); extern List * GetPgDependTuplesForDependingObjects(Oid targetObjectClassId,