Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfca6cab

Browse files
committed
Move CloneForeignKeyConstraints to tablecmds.c
My commit3de241d introduced some code to create a clone of aforeign key to a partition, but I put it in pg_constraint.c because itwas too close to the contents of the pg_constraint row. With theprevious commit that split out the constraint tuple deconstruction intoits own routine, it makes more sense to have the FK-cloning function intablecmds.c, mostly because its static subroutine can then be used by afuture bugfix.My initial posting of this patch had this routine as static intablecmds.c, but sadly this function is already part of the Postgres 11ABI as exported from pg_constraint.c, so keep it as exported also justto avoid breaking any possible users of it.
1 parente974f22 commitfca6cab

File tree

4 files changed

+307
-305
lines changed

4 files changed

+307
-305
lines changed

‎src/backend/catalog/pg_constraint.c

Lines changed: 0 additions & 302 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@
3838
#include"utils/tqual.h"
3939

4040

41-
staticvoidclone_fk_constraints(Relationpg_constraint,RelationparentRel,
42-
RelationpartRel,List*clone,List**cloned);
43-
44-
4541
/*
4642
* CreateConstraintEntry
4743
*Create a constraint table entry.
@@ -385,304 +381,6 @@ CreateConstraintEntry(const char *constraintName,
385381
returnconOid;
386382
}
387383

388-
/*
389-
* CloneForeignKeyConstraints
390-
*Clone foreign keys from a partitioned table to a newly acquired
391-
*partition.
392-
*
393-
* relationId is a partition of parentId, so we can be certain that it has the
394-
* same columns with the same datatypes. The columns may be in different
395-
* order, though.
396-
*
397-
* The *cloned list is appended ClonedConstraint elements describing what was
398-
* created.
399-
*/
400-
void
401-
CloneForeignKeyConstraints(OidparentId,OidrelationId,List**cloned)
402-
{
403-
Relationpg_constraint;
404-
RelationparentRel;
405-
Relationrel;
406-
ScanKeyDatakey;
407-
SysScanDescscan;
408-
HeapTupletuple;
409-
List*clone=NIL;
410-
411-
parentRel=heap_open(parentId,NoLock);/* already got lock */
412-
/* see ATAddForeignKeyConstraint about lock level */
413-
rel=heap_open(relationId,AccessExclusiveLock);
414-
pg_constraint=heap_open(ConstraintRelationId,RowShareLock);
415-
416-
/* Obtain the list of constraints to clone or attach */
417-
ScanKeyInit(&key,
418-
Anum_pg_constraint_conrelid,BTEqualStrategyNumber,
419-
F_OIDEQ,ObjectIdGetDatum(parentId));
420-
scan=systable_beginscan(pg_constraint,ConstraintRelidTypidNameIndexId, true,
421-
NULL,1,&key);
422-
while ((tuple=systable_getnext(scan))!=NULL)
423-
clone=lappend_oid(clone,HeapTupleGetOid(tuple));
424-
systable_endscan(scan);
425-
426-
/* Do the actual work, recursing to partitions as needed */
427-
clone_fk_constraints(pg_constraint,parentRel,rel,clone,cloned);
428-
429-
/* We're done. Clean up */
430-
heap_close(parentRel,NoLock);
431-
heap_close(rel,NoLock);/* keep lock till commit */
432-
heap_close(pg_constraint,RowShareLock);
433-
}
434-
435-
/*
436-
* clone_fk_constraints
437-
*Recursive subroutine for CloneForeignKeyConstraints
438-
*
439-
* Clone the given list of FK constraints when a partition is attached.
440-
*
441-
* When cloning foreign keys to a partition, it may happen that equivalent
442-
* constraints already exist in the partition for some of them. We can skip
443-
* creating a clone in that case, and instead just attach the existing
444-
* constraint to the one in the parent.
445-
*
446-
* This function recurses to partitions, if the new partition is partitioned;
447-
* of course, only do this for FKs that were actually cloned.
448-
*/
449-
staticvoid
450-
clone_fk_constraints(Relationpg_constraint,RelationparentRel,
451-
RelationpartRel,List*clone,List**cloned)
452-
{
453-
AttrNumber*attmap;
454-
List*partFKs;
455-
List*subclone=NIL;
456-
ListCell*cell;
457-
458-
/*
459-
* The constraint key may differ, if the columns in the partition are
460-
* different. This map is used to convert them.
461-
*/
462-
attmap=convert_tuples_by_name_map(RelationGetDescr(partRel),
463-
RelationGetDescr(parentRel),
464-
gettext_noop("could not convert row type"));
465-
466-
partFKs=copyObject(RelationGetFKeyList(partRel));
467-
468-
foreach(cell,clone)
469-
{
470-
OidparentConstrOid=lfirst_oid(cell);
471-
Form_pg_constraintconstrForm;
472-
HeapTupletuple;
473-
AttrNumberconkey[INDEX_MAX_KEYS];
474-
AttrNumbermapped_conkey[INDEX_MAX_KEYS];
475-
AttrNumberconfkey[INDEX_MAX_KEYS];
476-
Oidconpfeqop[INDEX_MAX_KEYS];
477-
Oidconppeqop[INDEX_MAX_KEYS];
478-
Oidconffeqop[INDEX_MAX_KEYS];
479-
Constraint*fkconstraint;
480-
boolattach_it;
481-
OidconstrOid;
482-
ObjectAddressparentAddr,
483-
childAddr;
484-
intnelem;
485-
ListCell*cell;
486-
inti;
487-
488-
tuple=SearchSysCache1(CONSTROID,parentConstrOid);
489-
if (!tuple)
490-
elog(ERROR,"cache lookup failed for constraint %u",
491-
parentConstrOid);
492-
constrForm= (Form_pg_constraint)GETSTRUCT(tuple);
493-
494-
/* only foreign keys */
495-
if (constrForm->contype!=CONSTRAINT_FOREIGN)
496-
{
497-
ReleaseSysCache(tuple);
498-
continue;
499-
}
500-
501-
ObjectAddressSet(parentAddr,ConstraintRelationId,parentConstrOid);
502-
503-
DeconstructFkConstraintRow(tuple,&nelem,conkey,confkey,
504-
conpfeqop,conppeqop,conffeqop);
505-
for (i=0;i<nelem;i++)
506-
mapped_conkey[i]=attmap[conkey[i]-1];
507-
508-
/*
509-
* Before creating a new constraint, see whether any existing FKs are
510-
* fit for the purpose. If one is, attach the parent constraint to it,
511-
* and don't clone anything. This way we avoid the expensive
512-
* verification step and don't end up with a duplicate FK. This also
513-
* means we don't consider this constraint when recursing to
514-
* partitions.
515-
*/
516-
attach_it= false;
517-
foreach(cell,partFKs)
518-
{
519-
ForeignKeyCacheInfo*fk=lfirst_node(ForeignKeyCacheInfo,cell);
520-
Form_pg_constraintpartConstr;
521-
HeapTuplepartcontup;
522-
523-
attach_it= true;
524-
525-
/*
526-
* Do some quick & easy initial checks. If any of these fail, we
527-
* cannot use this constraint, but keep looking.
528-
*/
529-
if (fk->confrelid!=constrForm->confrelid||fk->nkeys!=nelem)
530-
{
531-
attach_it= false;
532-
continue;
533-
}
534-
for (i=0;i<nelem;i++)
535-
{
536-
if (fk->conkey[i]!=mapped_conkey[i]||
537-
fk->confkey[i]!=confkey[i]||
538-
fk->conpfeqop[i]!=conpfeqop[i])
539-
{
540-
attach_it= false;
541-
break;
542-
}
543-
}
544-
if (!attach_it)
545-
continue;
546-
547-
/*
548-
* Looks good so far; do some more extensive checks. Presumably
549-
* the check for 'convalidated' could be dropped, since we don't
550-
* really care about that, but let's be careful for now.
551-
*/
552-
partcontup=SearchSysCache1(CONSTROID,
553-
ObjectIdGetDatum(fk->conoid));
554-
if (!partcontup)
555-
elog(ERROR,"cache lookup failed for constraint %u",
556-
fk->conoid);
557-
partConstr= (Form_pg_constraint)GETSTRUCT(partcontup);
558-
if (OidIsValid(partConstr->conparentid)||
559-
!partConstr->convalidated||
560-
partConstr->condeferrable!=constrForm->condeferrable||
561-
partConstr->condeferred!=constrForm->condeferred||
562-
partConstr->confupdtype!=constrForm->confupdtype||
563-
partConstr->confdeltype!=constrForm->confdeltype||
564-
partConstr->confmatchtype!=constrForm->confmatchtype)
565-
{
566-
ReleaseSysCache(partcontup);
567-
attach_it= false;
568-
continue;
569-
}
570-
571-
ReleaseSysCache(partcontup);
572-
573-
/* looks good! Attach this constraint */
574-
ConstraintSetParentConstraint(fk->conoid,
575-
HeapTupleGetOid(tuple));
576-
CommandCounterIncrement();
577-
attach_it= true;
578-
break;
579-
}
580-
581-
/*
582-
* If we attached to an existing constraint, there is no need to
583-
* create a new one. In fact, there's no need to recurse for this
584-
* constraint to partitions, either.
585-
*/
586-
if (attach_it)
587-
{
588-
ReleaseSysCache(tuple);
589-
continue;
590-
}
591-
592-
constrOid=
593-
CreateConstraintEntry(NameStr(constrForm->conname),
594-
constrForm->connamespace,
595-
CONSTRAINT_FOREIGN,
596-
constrForm->condeferrable,
597-
constrForm->condeferred,
598-
constrForm->convalidated,
599-
HeapTupleGetOid(tuple),
600-
RelationGetRelid(partRel),
601-
mapped_conkey,
602-
nelem,
603-
nelem,
604-
InvalidOid,/* not a domain constraint */
605-
constrForm->conindid,/* same index */
606-
constrForm->confrelid,/* same foreign rel */
607-
confkey,
608-
conpfeqop,
609-
conppeqop,
610-
conffeqop,
611-
nelem,
612-
constrForm->confupdtype,
613-
constrForm->confdeltype,
614-
constrForm->confmatchtype,
615-
NULL,
616-
NULL,
617-
NULL,
618-
NULL,
619-
false,
620-
1, false, true);
621-
subclone=lappend_oid(subclone,constrOid);
622-
623-
ObjectAddressSet(childAddr,ConstraintRelationId,constrOid);
624-
recordDependencyOn(&childAddr,&parentAddr,DEPENDENCY_INTERNAL_AUTO);
625-
626-
fkconstraint=makeNode(Constraint);
627-
/* for now this is all we need */
628-
fkconstraint->conname=pstrdup(NameStr(constrForm->conname));
629-
fkconstraint->fk_upd_action=constrForm->confupdtype;
630-
fkconstraint->fk_del_action=constrForm->confdeltype;
631-
fkconstraint->deferrable=constrForm->condeferrable;
632-
fkconstraint->initdeferred=constrForm->condeferred;
633-
634-
createForeignKeyTriggers(partRel,constrForm->confrelid,fkconstraint,
635-
constrOid,constrForm->conindid, false);
636-
637-
if (cloned)
638-
{
639-
ClonedConstraint*newc;
640-
641-
/*
642-
* Feed back caller about the constraints we created, so that they
643-
* can set up constraint verification.
644-
*/
645-
newc=palloc(sizeof(ClonedConstraint));
646-
newc->relid=RelationGetRelid(partRel);
647-
newc->refrelid=constrForm->confrelid;
648-
newc->conindid=constrForm->conindid;
649-
newc->conid=constrOid;
650-
newc->constraint=fkconstraint;
651-
652-
*cloned=lappend(*cloned,newc);
653-
}
654-
655-
ReleaseSysCache(tuple);
656-
}
657-
658-
pfree(attmap);
659-
list_free_deep(partFKs);
660-
661-
/*
662-
* If the partition is partitioned, recurse to handle any constraints that
663-
* were cloned.
664-
*/
665-
if (partRel->rd_rel->relkind==RELKIND_PARTITIONED_TABLE&&
666-
subclone!=NIL)
667-
{
668-
PartitionDescpartdesc=RelationGetPartitionDesc(partRel);
669-
inti;
670-
671-
for (i=0;i<partdesc->nparts;i++)
672-
{
673-
RelationchildRel;
674-
675-
childRel=heap_open(partdesc->oids[i],AccessExclusiveLock);
676-
clone_fk_constraints(pg_constraint,
677-
partRel,
678-
childRel,
679-
subclone,
680-
cloned);
681-
heap_close(childRel,NoLock);/* keep lock till commit */
682-
}
683-
}
684-
}
685-
686384
/*
687385
* Test whether given name is currently used as a constraint name
688386
* for the given object (relation or domain).

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp