@ -430,8 +430,8 @@ static void AlterConstrUpdateConstraintEntry(ATAlterConstraint *cmdcon, Relation
static ObjectAddress ATExecValidateConstraint ( List * * wqueue ,
Relation rel , char * constrName ,
bool recurse , bool recursing , LOCKMODE lockmode ) ;
static void QueueFKConstraintValidation ( List * * wqueue , Relation conrel , Relation rel ,
HeapTuple contuple , LOCKMODE lockmode ) ;
static void QueueFKConstraintValidation ( List * * wqueue , Relation conrel , Relation fk rel,
Oid pkrelid , HeapTuple contuple , LOCKMODE lockmode ) ;
static void QueueCheckConstraintValidation ( List * * wqueue , Relation conrel , Relation rel ,
char * constrName , HeapTuple contuple ,
bool recurse , bool recursing , LOCKMODE lockmode ) ;
@ -11858,6 +11858,7 @@ AttachPartitionForeignKey(List **wqueue,
if ( queueValidation )
{
Relation conrel ;
Oid confrelid ;
conrel = table_open ( ConstraintRelationId , RowExclusiveLock ) ;
@ -11865,9 +11866,11 @@ AttachPartitionForeignKey(List **wqueue,
if ( ! HeapTupleIsValid ( partcontup ) )
elog ( ERROR , " cache lookup failed for constraint %u " , partConstrOid ) ;
confrelid = ( ( Form_pg_constraint ) GETSTRUCT ( partcontup ) ) - > confrelid ;
/* Use the same lock as for AT_ValidateConstraint */
QueueFKConstraintValidation ( wqueue , conrel , partition , partcontup ,
ShareUpdateExclusiveLock ) ;
QueueFKConstraintValidation ( wqueue , conrel , partition , confrelid ,
partcontup , ShareUpdateExclusiveLock ) ;
ReleaseSysCache ( partcontup ) ;
table_close ( conrel , RowExclusiveLock ) ;
}
@ -12919,7 +12922,8 @@ ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
{
if ( con - > contype = = CONSTRAINT_FOREIGN )
{
QueueFKConstraintValidation ( wqueue , conrel , rel , tuple , lockmode ) ;
QueueFKConstraintValidation ( wqueue , conrel , rel , con - > confrelid ,
tuple , lockmode ) ;
}
else if ( con - > contype = = CONSTRAINT_CHECK )
{
@ -12952,8 +12956,8 @@ ATExecValidateConstraint(List **wqueue, Relation rel, char *constrName,
* for the specified relation and all its children .
*/
static void
QueueFKConstraintValidation ( List * * wqueue , Relation conrel , Relation rel ,
HeapTuple contuple , LOCKMODE lockmode )
QueueFKConstraintValidation ( List * * wqueue , Relation conrel , Relation fk rel,
Oid pkrelid , HeapTuple contuple , LOCKMODE lockmode )
{
Form_pg_constraint con ;
AlteredTableInfo * tab ;
@ -12964,7 +12968,17 @@ QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation rel,
Assert ( con - > contype = = CONSTRAINT_FOREIGN ) ;
Assert ( ! con - > convalidated ) ;
if ( rel - > rd_rel - > relkind = = RELKIND_RELATION )
/*
* Add the validation to phase 3 ' s queue ; not needed for partitioned
* tables themselves , only for their partitions .
*
* When the referenced table ( pkrelid ) is partitioned , the referencing
* table ( fkrel ) has one pg_constraint row pointing to each partition
* thereof . These rows are there only to support action triggers and no
* table scan is needed , therefore skip this for them as well .
*/
if ( fkrel - > rd_rel - > relkind = = RELKIND_RELATION & &
con - > confrelid = = pkrelid )
{
NewConstraint * newcon ;
Constraint * fkconstraint ;
@ -12983,15 +12997,16 @@ QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation rel,
newcon - > qual = ( Node * ) fkconstraint ;
/* Find or create work queue entry for this table */
tab = ATGetQueueEntry ( wqueue , rel ) ;
tab = ATGetQueueEntry ( wqueue , fk rel) ;
tab - > constraints = lappend ( tab - > constraints , newcon ) ;
}
/*
* If the table at either end of the constraint is partitioned , we need to
* recurse and handle every constraint that is a child of this constraint .
* recurse and handle every unvalidate constraint that is a child of this
* constraint .
*/
if ( rel - > rd_rel - > relkind = = RELKIND_PARTITIONED_TABLE | |
if ( fk rel- > rd_rel - > relkind = = RELKIND_PARTITIONED_TABLE | |
get_rel_relkind ( con - > confrelid ) = = RELKIND_PARTITIONED_TABLE )
{
ScanKeyData pkey ;
@ -13023,8 +13038,12 @@ QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation rel,
childrel = table_open ( childcon - > conrelid , lockmode ) ;
QueueFKConstraintValidation ( wqueue , conrel , childrel , childtup ,
lockmode ) ;
/*
* NB : Note that pkrelid should be passed as - is during recursion ,
* as it is required to identify the root referenced table .
*/
QueueFKConstraintValidation ( wqueue , conrel , childrel , pkrelid ,
childtup , lockmode ) ;
table_close ( childrel , NoLock ) ;
}
@ -13032,7 +13051,11 @@ QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation rel,
}
/*
* Now update the catalog , while we have the door open .
* Now mark the pg_constraint row as validated ( even if we didn ' t check ,
* notably the ones for partitions on the referenced side ) .
*
* We rely on transaction abort to roll back this change if phase 3
* ultimately finds violating rows . This is a bit ugly .
*/
copyTuple = heap_copytuple ( contuple ) ;
copy_con = ( Form_pg_constraint ) GETSTRUCT ( copyTuple ) ;