Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit da38676

Browse files
committed
foreign key constraint validation added
1 parent 72b900d commit da38676

File tree

1 file changed

+85
-5
lines changed

1 file changed

+85
-5
lines changed

src/ref_integrity.c

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "miscadmin.h"
1515

1616
#include "access/htup_details.h"
17+
#include "access/relscan.h"
1718
#include "access/sysattr.h"
1819
#include "access/xact.h"
1920
#include "catalog/pg_am.h"
@@ -163,6 +164,11 @@ static void create_fk_constraint_internal(Oid fk_table, AttrNumber fk_attnum, Oi
163164
static void createForeignKeyTriggers(Relation rel, Oid refRelOid,
164165
Oid constraintOid, Oid indexOid);
165166
static HeapTuple get_index_for_key(Relation rel, AttrNumber attnum, Oid *index_id);
167+
static void validateForeignKeyConstraint(char *conname,
168+
Relation rel,
169+
Relation pkrel,
170+
Oid pkindOid,
171+
Oid constraintOid);
166172

167173

168174
PG_FUNCTION_INFO_V1(pathman_fkey_check_ins);
@@ -1257,8 +1263,8 @@ create_fk_constraint_internal(Oid fk_table, AttrNumber fk_attnum, Oid pk_table,
12571263
char *fkname;
12581264
Oid constrOid;
12591265

1260-
Relation fkrel;
1261-
Relation pkrel;
1266+
Relation fkrel;
1267+
Relation pkrel;
12621268

12631269
HeapTuple cla_ht;
12641270
Form_pg_opclass cla_tup;
@@ -1267,8 +1273,8 @@ create_fk_constraint_internal(Oid fk_table, AttrNumber fk_attnum, Oid pk_table,
12671273
Oid ppeqop;
12681274
Oid ffeqop;
12691275

1270-
Oid opfamily;
1271-
Oid opcintype;
1276+
Oid opfamily;
1277+
Oid opcintype;
12721278

12731279

12741280
fkrel = heap_open(fk_table, ShareRowExclusiveLock);
@@ -1365,8 +1371,12 @@ create_fk_constraint_internal(Oid fk_table, AttrNumber fk_attnum, Oid pk_table,
13651371
/* Make changes-so-far visible */
13661372
CommandCounterIncrement();
13671373

1374+
/* Add RI triggers */
13681375
createForeignKeyTriggers(fkrel, pk_table, constrOid, indexOid);
13691376

1377+
/* Go through fk table and apply RI trigger on each row */
1378+
validateForeignKeyConstraint(fkname, fkrel, pkrel, indexOid, constrOid);
1379+
13701380
heap_close(fkrel, ShareRowExclusiveLock);
13711381
heap_close(pkrel, ShareRowExclusiveLock);
13721382
}
@@ -1616,4 +1626,74 @@ get_index_for_key(Relation rel, AttrNumber attnum, Oid *index_id)
16161626
list_free(indexoidlist);
16171627

16181628
return NULL;
1619-
}
1629+
}
1630+
1631+
/*
1632+
* Scan the existing rows in a table to verify they meet a proposed FK
1633+
* constraint.
1634+
*/
1635+
static void
1636+
validateForeignKeyConstraint(char *conname,
1637+
Relation rel,
1638+
Relation pkrel,
1639+
Oid pkindOid,
1640+
Oid constraintOid)
1641+
{
1642+
HeapScanDesc scan;
1643+
HeapTuple tuple;
1644+
Trigger trig;
1645+
Snapshot snapshot;
1646+
1647+
/* Build a trigger call structure */
1648+
MemSet(&trig, 0, sizeof(trig));
1649+
trig.tgoid = InvalidOid;
1650+
trig.tgname = conname;
1651+
trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
1652+
trig.tgisinternal = TRUE;
1653+
trig.tgconstrrelid = RelationGetRelid(pkrel);
1654+
trig.tgconstrindid = pkindOid;
1655+
trig.tgconstraint = constraintOid;
1656+
trig.tgdeferrable = FALSE;
1657+
trig.tginitdeferred = FALSE;
1658+
/* we needn't fill in tgargs or tgqual */
1659+
1660+
/*
1661+
* Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
1662+
* if that tuple had just been inserted. If any of those fail, it should
1663+
* ereport(ERROR) and that's that.
1664+
*/
1665+
snapshot = RegisterSnapshot(GetLatestSnapshot());
1666+
scan = heap_beginscan(rel, snapshot, 0, NULL);
1667+
1668+
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1669+
{
1670+
FunctionCallInfoData fcinfo;
1671+
TriggerData trigdata;
1672+
1673+
/*
1674+
* Make a call to the trigger function
1675+
*
1676+
* No parameters are passed, but we do set a context
1677+
*/
1678+
MemSet(&fcinfo, 0, sizeof(fcinfo));
1679+
1680+
/*
1681+
* We assume RI_FKey_check_ins won't look at flinfo...
1682+
*/
1683+
trigdata.type = T_TriggerData;
1684+
trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
1685+
trigdata.tg_relation = rel;
1686+
trigdata.tg_trigtuple = tuple;
1687+
trigdata.tg_newtuple = NULL;
1688+
trigdata.tg_trigger = &trig;
1689+
trigdata.tg_trigtuplebuf = scan->rs_cbuf;
1690+
trigdata.tg_newtuplebuf = InvalidBuffer;
1691+
1692+
fcinfo.context = (Node *) &trigdata;
1693+
1694+
pathman_fkey_check_ins(&fcinfo);
1695+
}
1696+
1697+
heap_endscan(scan);
1698+
UnregisterSnapshot(snapshot);
1699+
}

0 commit comments

Comments
 (0)