14
14
#include "miscadmin.h"
15
15
16
16
#include "access/htup_details.h"
17
+ #include "access/relscan.h"
17
18
#include "access/sysattr.h"
18
19
#include "access/xact.h"
19
20
#include "catalog/pg_am.h"
@@ -163,6 +164,11 @@ static void create_fk_constraint_internal(Oid fk_table, AttrNumber fk_attnum, Oi
163
164
static void createForeignKeyTriggers (Relation rel , Oid refRelOid ,
164
165
Oid constraintOid , Oid indexOid );
165
166
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 );
166
172
167
173
168
174
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,
1257
1263
char * fkname ;
1258
1264
Oid constrOid ;
1259
1265
1260
- Relation fkrel ;
1261
- Relation pkrel ;
1266
+ Relation fkrel ;
1267
+ Relation pkrel ;
1262
1268
1263
1269
HeapTuple cla_ht ;
1264
1270
Form_pg_opclass cla_tup ;
@@ -1267,8 +1273,8 @@ create_fk_constraint_internal(Oid fk_table, AttrNumber fk_attnum, Oid pk_table,
1267
1273
Oid ppeqop ;
1268
1274
Oid ffeqop ;
1269
1275
1270
- Oid opfamily ;
1271
- Oid opcintype ;
1276
+ Oid opfamily ;
1277
+ Oid opcintype ;
1272
1278
1273
1279
1274
1280
fkrel = heap_open (fk_table , ShareRowExclusiveLock );
@@ -1365,8 +1371,12 @@ create_fk_constraint_internal(Oid fk_table, AttrNumber fk_attnum, Oid pk_table,
1365
1371
/* Make changes-so-far visible */
1366
1372
CommandCounterIncrement ();
1367
1373
1374
+ /* Add RI triggers */
1368
1375
createForeignKeyTriggers (fkrel , pk_table , constrOid , indexOid );
1369
1376
1377
+ /* Go through fk table and apply RI trigger on each row */
1378
+ validateForeignKeyConstraint (fkname , fkrel , pkrel , indexOid , constrOid );
1379
+
1370
1380
heap_close (fkrel , ShareRowExclusiveLock );
1371
1381
heap_close (pkrel , ShareRowExclusiveLock );
1372
1382
}
@@ -1616,4 +1626,74 @@ get_index_for_key(Relation rel, AttrNumber attnum, Oid *index_id)
1616
1626
list_free (indexoidlist );
1617
1627
1618
1628
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