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

Commit015e889

Browse files
Load FK defs into relcache for use by planner
Fastpath ignores this if no triggers defined.Author: Tomas Vondra, with fastpath and comments added by meReviewers: David Rowley, Simon Riggs
1 parentf2b1b30 commit015e889

File tree

7 files changed

+199
-1
lines changed

7 files changed

+199
-1
lines changed

‎src/backend/nodes/outfuncs.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2137,6 +2137,16 @@ _outIndexOptInfo(StringInfo str, const IndexOptInfo *node)
21372137
/* we don't bother with fields copied from the index AM's API struct */
21382138
}
21392139

2140+
staticvoid
2141+
_outForeignKeyOptInfo(StringInfostr,constForeignKeyOptInfo*node)
2142+
{
2143+
WRITE_NODE_TYPE("FOREIGNKEYOPTINFO");
2144+
2145+
WRITE_OID_FIELD(conrelid);
2146+
WRITE_OID_FIELD(confrelid);
2147+
WRITE_INT_FIELD(nkeys);
2148+
}
2149+
21402150
staticvoid
21412151
_outEquivalenceClass(StringInfostr,constEquivalenceClass*node)
21422152
{
@@ -3607,6 +3617,9 @@ _outNode(StringInfo str, const void *obj)
36073617
caseT_IndexOptInfo:
36083618
_outIndexOptInfo(str,obj);
36093619
break;
3620+
caseT_ForeignKeyOptInfo:
3621+
_outForeignKeyOptInfo(str,obj);
3622+
break;
36103623
caseT_EquivalenceClass:
36113624
_outEquivalenceClass(str,obj);
36123625
break;

‎src/backend/optimizer/util/plancat.c

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include"catalog/dependency.h"
2929
#include"catalog/heap.h"
3030
#include"catalog/pg_am.h"
31+
#include"catalog/pg_constraint.h"
3132
#include"foreign/fdwapi.h"
3233
#include"miscadmin.h"
3334
#include"nodes/makefuncs.h"
@@ -41,6 +42,7 @@
4142
#include"rewrite/rewriteManip.h"
4243
#include"storage/bufmgr.h"
4344
#include"utils/lsyscache.h"
45+
#include"utils/syscache.h"
4446
#include"utils/rel.h"
4547
#include"utils/snapmgr.h"
4648

@@ -94,6 +96,9 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
9496
Relationrelation;
9597
boolhasindex;
9698
List*indexinfos=NIL;
99+
List*fkinfos=NIL;
100+
List*fkoidlist;
101+
ListCell*l;
97102

98103
/*
99104
* We need not lock the relation since it was already locked, either by
@@ -141,7 +146,6 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
141146
if (hasindex)
142147
{
143148
List*indexoidlist;
144-
ListCell*l;
145149
LOCKMODElmode;
146150

147151
indexoidlist=RelationGetIndexList(relation);
@@ -388,6 +392,85 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
388392

389393
rel->indexlist=indexinfos;
390394

395+
/*
396+
* Load foreign key data. Note this is the definitional data from the
397+
* catalog only and does not lock the referenced tables here. The
398+
* precise definition of the FK is important and may affect the usage
399+
* elsewhere in the planner, e.g. if the constraint is deferred or
400+
* if the constraint is not valid then relying upon this in the executor
401+
* may not be accurate, though might be considered a useful estimate for
402+
* planning purposes.
403+
*/
404+
fkoidlist=RelationGetFKeyList(relation);
405+
406+
foreach(l,fkoidlist)
407+
{
408+
inti;
409+
ArrayType*arr;
410+
Datumadatum;
411+
boolisnull;
412+
intnumkeys;
413+
Oidfkoid=lfirst_oid(l);
414+
415+
HeapTuplehtup=SearchSysCache1(CONSTROID,ObjectIdGetDatum(fkoid));
416+
Form_pg_constraintconstraint= (Form_pg_constraint)GETSTRUCT(htup);
417+
418+
ForeignKeyOptInfo*info;
419+
420+
Assert(constraint->contype==CONSTRAINT_FOREIGN);
421+
422+
info=makeNode(ForeignKeyOptInfo);
423+
424+
info->conrelid=constraint->conrelid;
425+
info->confrelid=constraint->confrelid;
426+
427+
/* conkey */
428+
adatum=SysCacheGetAttr(CONSTROID,htup,
429+
Anum_pg_constraint_conkey,&isnull);
430+
Assert(!isnull);
431+
432+
arr=DatumGetArrayTypeP(adatum);
433+
numkeys=ARR_DIMS(arr)[0];
434+
info->conkeys= (int*)palloc0(numkeys*sizeof(int));
435+
436+
for (i=0;i<numkeys;i++)
437+
info->conkeys[i]= ((int16*)ARR_DATA_PTR(arr))[i];
438+
439+
/* confkey */
440+
adatum=SysCacheGetAttr(CONSTROID,htup,
441+
Anum_pg_constraint_confkey,&isnull);
442+
Assert(!isnull);
443+
444+
arr=DatumGetArrayTypeP(adatum);
445+
numkeys=ARR_DIMS(arr)[0];
446+
info->confkeys= (int*)palloc0(numkeys*sizeof(int));
447+
448+
for (i=0;i<numkeys;i++)
449+
info->confkeys[i]= ((int16*)ARR_DATA_PTR(arr))[i];
450+
451+
/* conpfeqop */
452+
adatum=SysCacheGetAttr(CONSTROID,htup,
453+
Anum_pg_constraint_conpfeqop,&isnull);
454+
Assert(!isnull);
455+
456+
arr=DatumGetArrayTypeP(adatum);
457+
numkeys=ARR_DIMS(arr)[0];
458+
info->conpfeqop= (Oid*)palloc0(numkeys*sizeof(Oid));
459+
460+
for (i=0;i<numkeys;i++)
461+
info->conpfeqop[i]= ((Oid*)ARR_DATA_PTR(arr))[i];
462+
463+
info->nkeys=numkeys;
464+
465+
ReleaseSysCache(htup);
466+
467+
fkinfos=lcons(info,fkinfos);
468+
}
469+
470+
list_free(fkoidlist);
471+
472+
rel->fkeylist=fkinfos;
473+
391474
/* Grab foreign-table info using the relcache, while we have it */
392475
if (relation->rd_rel->relkind==RELKIND_FOREIGN_TABLE)
393476
{

‎src/backend/utils/cache/relcache.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,6 +2031,7 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc)
20312031
FreeTupleDesc(relation->rd_att);
20322032
}
20332033
list_free(relation->rd_indexlist);
2034+
list_free(relation->rd_fkeylist);
20342035
bms_free(relation->rd_indexattr);
20352036
bms_free(relation->rd_keyattr);
20362037
bms_free(relation->rd_idattr);
@@ -3956,6 +3957,79 @@ RelationGetIndexList(Relation relation)
39563957
returnresult;
39573958
}
39583959

3960+
/*
3961+
* RelationGetFKeyList -- get a list of foreign key oids
3962+
*
3963+
* Use an index scan on pg_constraint to load in FK definitions,
3964+
* intended for use within the planner, not for enforcing FKs.
3965+
*
3966+
* Data is ordered by Oid, though this is not critical at this point
3967+
* since we do not lock the referenced relations.
3968+
*/
3969+
List*
3970+
RelationGetFKeyList(Relationrelation)
3971+
{
3972+
Relationconrel;
3973+
SysScanDescconscan;
3974+
ScanKeyDataskey;
3975+
HeapTuplehtup;
3976+
List*result;
3977+
List*oldlist;
3978+
MemoryContextoldcxt;
3979+
3980+
/* Quick exit if we already computed the list. */
3981+
if (relation->rd_fkeylist)
3982+
returnlist_copy(relation->rd_fkeylist);
3983+
3984+
/* Fast path if no FKs... if it doesn't have a trigger, it can't have a FK */
3985+
if (!relation->rd_rel->relhastriggers)
3986+
returnNIL;
3987+
/*
3988+
* We build the list we intend to return (in the caller's context) while
3989+
* doing the scan. After successfully completing the scan, we copy that
3990+
* list into the relcache entry. This avoids cache-context memory leakage
3991+
* if we get some sort of error partway through.
3992+
*/
3993+
result=NIL;
3994+
3995+
/* Prepare to scan pg_constraint for entries having conrelid = this rel. */
3996+
ScanKeyInit(&skey,
3997+
Anum_pg_constraint_conrelid,
3998+
BTEqualStrategyNumber,F_OIDEQ,
3999+
ObjectIdGetDatum(RelationGetRelid(relation)));
4000+
4001+
conrel=heap_open(ConstraintRelationId,AccessShareLock);
4002+
conscan=systable_beginscan(conrel,ConstraintRelidIndexId, true,
4003+
NULL,1,&skey);
4004+
4005+
while (HeapTupleIsValid(htup=systable_getnext(conscan)))
4006+
{
4007+
Form_pg_constraintconstraint= (Form_pg_constraint)GETSTRUCT(htup);
4008+
4009+
/* return only foreign keys */
4010+
if (constraint->contype!=CONSTRAINT_FOREIGN)
4011+
continue;
4012+
4013+
/* Add FK's OID to result list in the proper order */
4014+
result=insert_ordered_oid(result,HeapTupleGetOid(htup));
4015+
}
4016+
4017+
systable_endscan(conscan);
4018+
4019+
heap_close(conrel,AccessShareLock);
4020+
4021+
/* Now save a copy of the completed list in the relcache entry. */
4022+
oldcxt=MemoryContextSwitchTo(CacheMemoryContext);
4023+
oldlist=relation->rd_fkeylist;
4024+
relation->rd_fkeylist=list_copy(result);
4025+
MemoryContextSwitchTo(oldcxt);
4026+
4027+
/* Don't leak the old list, if there is one */
4028+
list_free(oldlist);
4029+
4030+
returnresult;
4031+
}
4032+
39594033
/*
39604034
* insert_ordered_oid
39614035
*Insert a new Oid into a sorted list of Oids, preserving ordering
@@ -4920,6 +4994,7 @@ load_relcache_init_file(bool shared)
49204994
rel->rd_indexattr=NULL;
49214995
rel->rd_keyattr=NULL;
49224996
rel->rd_idattr=NULL;
4997+
rel->rd_fkeylist=NIL;
49234998
rel->rd_createSubid=InvalidSubTransactionId;
49244999
rel->rd_newRelfilenodeSubid=InvalidSubTransactionId;
49255000
rel->rd_amcache=NULL;

‎src/include/nodes/nodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ typedef enum NodeTag
223223
T_PlannerGlobal,
224224
T_RelOptInfo,
225225
T_IndexOptInfo,
226+
T_ForeignKeyOptInfo,
226227
T_ParamPathInfo,
227228
T_Path,
228229
T_IndexPath,

‎src/include/nodes/relation.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ typedef struct RelOptInfo
516516
List*lateral_vars;/* LATERAL Vars and PHVs referenced by rel */
517517
Relidslateral_referencers;/* rels that reference me laterally */
518518
List*indexlist;/* list of IndexOptInfo */
519+
List*fkeylist;/* list of ForeignKeyOptInfo */
519520
BlockNumberpages;/* size estimates derived from pg_class */
520521
doubletuples;
521522
doubleallvisfrac;
@@ -621,6 +622,27 @@ typedef struct IndexOptInfo
621622
void(*amcostestimate) ();/* AM's cost estimator */
622623
}IndexOptInfo;
623624

625+
/*
626+
* ForeignKeyOptInfo
627+
*Per-foreign-key information for planning/optimization
628+
*
629+
* Only includes columns from pg_constraint related to foreign keys.
630+
*
631+
* conkeys[], confkeys[] and conpfeqop[] each have nkeys entries.
632+
*/
633+
typedefstructForeignKeyOptInfo
634+
{
635+
NodeTagtype;
636+
637+
Oidconrelid;/* relation constrained by the foreign key */
638+
Oidconfrelid;/* relation referenced by the foreign key */
639+
640+
intnkeys;/* number of columns in the foreign key */
641+
int*conkeys;/* attnums of columns in the constrained table */
642+
int*confkeys;/* attnums of columns in the referenced table */
643+
Oid*conpfeqop;/* OIDs of equality operators used by the FK */
644+
645+
}ForeignKeyOptInfo;
624646

625647
/*
626648
* EquivalenceClasses

‎src/include/utils/rel.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ typedef struct RelationData
9494
Oidrd_oidindex;/* OID of unique index on OID, if any */
9595
Oidrd_replidindex;/* OID of replica identity index, if any */
9696

97+
/* data managed by RelationGetFKList: */
98+
List*rd_fkeylist;/* OIDs of foreign keys */
99+
97100
/* data managed by RelationGetIndexAttrBitmap: */
98101
Bitmapset*rd_indexattr;/* identifies columns used in indexes */
99102
Bitmapset*rd_keyattr;/* cols that can be ref'd by foreign keys */

‎src/include/utils/relcache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extern void RelationClose(Relation relation);
3838
* Routines to compute/retrieve additional cached information
3939
*/
4040
externList*RelationGetIndexList(Relationrelation);
41+
externList*RelationGetFKeyList(Relationrelation);
4142
externOidRelationGetOidIndex(Relationrelation);
4243
externOidRelationGetReplicaIndex(Relationrelation);
4344
externList*RelationGetIndexExpressions(Relationrelation);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp