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

Commit03afae2

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 parent0080396 commit03afae2

File tree

3 files changed

+306
-307
lines changed

3 files changed

+306
-307
lines changed

‎src/backend/catalog/pg_constraint.c

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

4141

42-
staticvoidclone_fk_constraints(Relationpg_constraint,RelationparentRel,
43-
RelationpartRel,List*clone,List**cloned);
44-
45-
4642
/*
4743
* CreateConstraintEntry
4844
*Create a constraint table entry.
@@ -377,306 +373,6 @@ CreateConstraintEntry(const char *constraintName,
377373
returnconOid;
378374
}
379375

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp