Do not rely on fk cache when truncating local data (#5018)

pull/5029/head
Hanefi Onaldi 2021-06-07 11:56:48 +03:00 committed by GitHub
parent 9770a1bf00
commit 5c6069a74a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 19 deletions

View File

@ -734,8 +734,8 @@ HasForeignKeyWithLocalTable(Oid relationId)
/* /*
* GetForeignKeysWithLocalTables returns a list foreign keys for foreign key * GetForeignKeysWithLocalTables returns a list of foreign keys for foreign key
* relationaships that relation has with local tables. * relationships that relation has with local tables.
*/ */
static List * static List *
GetForeignKeysWithLocalTables(Oid relationId) GetForeignKeysWithLocalTables(Oid relationId)
@ -753,6 +753,21 @@ GetForeignKeysWithLocalTables(Oid relationId)
} }
/*
* GetForeignKeysFromLocalTables returns a list of foreign keys where the referencing
* relation is a local table.
*/
List *
GetForeignKeysFromLocalTables(Oid relationId)
{
int referencedFKeysFlag = INCLUDE_REFERENCED_CONSTRAINTS |
INCLUDE_LOCAL_TABLES;
List *referencingFKeyList = GetForeignKeyOids(relationId, referencedFKeysFlag);
return referencingFKeyList;
}
/* /*
* HasForeignKeyToCitusLocalTable returns true if any of the foreign key constraints * HasForeignKeyToCitusLocalTable returns true if any of the foreign key constraints
* on the relation with relationId references to a citus local table. * on the relation with relationId references to a citus local table.
@ -1102,6 +1117,30 @@ GetReferencedTableId(Oid foreignKeyId)
} }
/*
* GetReferencingTableId returns OID of the referencing relation for the foreign
* key with foreignKeyId. If there is no such foreign key, then this function
* returns InvalidOid.
*/
Oid
GetReferencingTableId(Oid foreignKeyId)
{
HeapTuple heapTuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(foreignKeyId));
if (!HeapTupleIsValid(heapTuple))
{
/* no such foreign key */
return InvalidOid;
}
Form_pg_constraint constraintForm = (Form_pg_constraint) GETSTRUCT(heapTuple);
Oid referencingTableId = constraintForm->conrelid;
ReleaseSysCache(heapTuple);
return referencingTableId;
}
/* /*
* IsTableTypeIncluded returns true if type of the table with relationId (distributed, * IsTableTypeIncluded returns true if type of the table with relationId (distributed,
* reference, Citus local or Postgres local) is included in the flags, false if not * reference, Citus local or Postgres local) is included in the flags, false if not

View File

@ -217,25 +217,20 @@ EnsureLocalTableCanBeTruncated(Oid relationId)
"tables."))); "tables.")));
} }
/* make sure there are no foreign key references from a local table */ List *referencingForeignConstaintsFromLocalTables =
SetForeignConstraintRelationshipGraphInvalid(); GetForeignKeysFromLocalTables(relationId);
List *referencingRelationList = ReferencingRelationIdList(relationId); if (list_length(referencingForeignConstaintsFromLocalTables) > 0)
Oid referencingRelation = InvalidOid;
foreach_oid(referencingRelation, referencingRelationList)
{ {
/* we do not truncate a table if there is a local table referencing it */ Oid foreignKeyId = linitial_oid(referencingForeignConstaintsFromLocalTables);
if (!IsCitusTable(referencingRelation)) Oid referencingRelation = GetReferencingTableId(foreignKeyId);
{ char *referencedRelationName = get_rel_name(relationId);
char *referencedRelationName = get_rel_name(relationId); char *referencingRelationName = get_rel_name(referencingRelation);
char *referencingRelationName = get_rel_name(referencingRelation);
ereport(ERROR, (errmsg("cannot truncate a table referenced in a " ereport(ERROR, (errmsg("cannot truncate a table referenced in a "
"foreign key constraint by a local table"), "foreign key constraint by a local table"),
errdetail("Table \"%s\" references \"%s\"", errdetail("Table \"%s\" references \"%s\"",
referencingRelationName, referencingRelationName,
referencedRelationName))); referencedRelationName)));
}
} }
} }

View File

@ -207,6 +207,7 @@ extern bool AnyForeignKeyDependsOnIndex(Oid indexId);
extern bool HasForeignKeyWithLocalTable(Oid relationId); extern bool HasForeignKeyWithLocalTable(Oid relationId);
extern bool HasForeignKeyToCitusLocalTable(Oid relationId); extern bool HasForeignKeyToCitusLocalTable(Oid relationId);
extern bool HasForeignKeyToReferenceTable(Oid relationOid); extern bool HasForeignKeyToReferenceTable(Oid relationOid);
extern List * GetForeignKeysFromLocalTables(Oid relationId);
extern bool TableReferenced(Oid relationOid); extern bool TableReferenced(Oid relationOid);
extern bool TableReferencing(Oid relationOid); extern bool TableReferencing(Oid relationOid);
extern bool ConstraintIsAUniquenessConstraint(char *inputConstaintName, Oid relationId); extern bool ConstraintIsAUniquenessConstraint(char *inputConstaintName, Oid relationId);
@ -217,6 +218,7 @@ extern bool ConstraintWithIdIsOfType(Oid constraintId, char targetConstraintType
extern bool TableHasExternalForeignKeys(Oid relationId); extern bool TableHasExternalForeignKeys(Oid relationId);
extern List * GetForeignKeyOids(Oid relationId, int flags); extern List * GetForeignKeyOids(Oid relationId, int flags);
extern Oid GetReferencedTableId(Oid foreignKeyId); extern Oid GetReferencedTableId(Oid foreignKeyId);
extern Oid GetReferencingTableId(Oid foreignKeyId);
extern bool RelationInvolvedInAnyNonInheritedForeignKeys(Oid relationId); extern bool RelationInvolvedInAnyNonInheritedForeignKeys(Oid relationId);