@@ -176,8 +176,7 @@ static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
176176 TupleTableSlot * oldslot ,
177177 const RI_ConstraintInfo * riinfo );
178178static Datum ri_restrict (TriggerData * trigdata , bool is_no_action );
179- static Datum ri_setnull (TriggerData * trigdata );
180- static Datum ri_setdefault (TriggerData * trigdata );
179+ static Datum ri_set (TriggerData * trigdata , bool is_set_null );
181180static void quoteOneName (char * buffer , const char * name );
182181static void quoteRelationName (char * buffer , Relation rel );
183182static void ri_GenerateQual (StringInfo buf ,
@@ -960,7 +959,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
960959 ri_CheckTrigger (fcinfo , "RI_FKey_setnull_del" , RI_TRIGTYPE_DELETE );
961960
962961 /* Share code with UPDATE case */
963- return ri_setnull ((TriggerData * ) fcinfo -> context );
962+ return ri_set ((TriggerData * ) fcinfo -> context , true );
964963}
965964
966965/*
@@ -975,119 +974,9 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
975974 ri_CheckTrigger (fcinfo , "RI_FKey_setnull_upd" , RI_TRIGTYPE_UPDATE );
976975
977976 /* Share code with DELETE case */
978- return ri_setnull ((TriggerData * ) fcinfo -> context );
977+ return ri_set ((TriggerData * ) fcinfo -> context , true );
979978}
980979
981- /*
982- * ri_setnull -
983- *
984- * Common code for ON DELETE SET NULL and ON UPDATE SET NULL
985- */
986- static Datum
987- ri_setnull (TriggerData * trigdata )
988- {
989- const RI_ConstraintInfo * riinfo ;
990- Relation fk_rel ;
991- Relation pk_rel ;
992- TupleTableSlot * oldslot ;
993- RI_QueryKey qkey ;
994- SPIPlanPtr qplan ;
995-
996- riinfo = ri_FetchConstraintInfo (trigdata -> tg_trigger ,
997- trigdata -> tg_relation , true);
998-
999- /*
1000- * Get the relation descriptors of the FK and PK tables and the old tuple.
1001- *
1002- * fk_rel is opened in RowExclusiveLock mode since that's what our
1003- * eventual UPDATE will get on it.
1004- */
1005- fk_rel = table_open (riinfo -> fk_relid , RowExclusiveLock );
1006- pk_rel = trigdata -> tg_relation ;
1007- oldslot = trigdata -> tg_trigslot ;
1008-
1009- if (SPI_connect () != SPI_OK_CONNECT )
1010- elog (ERROR , "SPI_connect failed" );
1011-
1012- /*
1013- * Fetch or prepare a saved plan for the set null operation (it's
1014- * the same query for delete and update cases)
1015- */
1016- ri_BuildQueryKey (& qkey , riinfo , RI_PLAN_SETNULL_DOUPDATE );
1017-
1018- if ((qplan = ri_FetchPreparedPlan (& qkey )) == NULL )
1019- {
1020- StringInfoData querybuf ;
1021- StringInfoData qualbuf ;
1022- char fkrelname [MAX_QUOTED_REL_NAME_LEN ];
1023- char attname [MAX_QUOTED_NAME_LEN ];
1024- char paramname [16 ];
1025- const char * querysep ;
1026- const char * qualsep ;
1027- const char * fk_only ;
1028- Oid queryoids [RI_MAX_NUMKEYS ];
1029-
1030- /* ----------
1031- * The query string built is
1032- * UPDATE [ONLY] <fktable> SET fkatt1 = NULL [, ...]
1033- * WHERE $1 = fkatt1 [AND ...]
1034- * The type id's for the $ parameters are those of the
1035- * corresponding PK attributes.
1036- * ----------
1037- */
1038- initStringInfo (& querybuf );
1039- initStringInfo (& qualbuf );
1040- fk_only = fk_rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE ?
1041- "" : "ONLY " ;
1042- quoteRelationName (fkrelname , fk_rel );
1043- appendStringInfo (& querybuf , "UPDATE %s%s SET" ,
1044- fk_only , fkrelname );
1045- querysep = "" ;
1046- qualsep = "WHERE" ;
1047- for (int i = 0 ; i < riinfo -> nkeys ; i ++ )
1048- {
1049- Oid pk_type = RIAttType (pk_rel , riinfo -> pk_attnums [i ]);
1050- Oid fk_type = RIAttType (fk_rel , riinfo -> fk_attnums [i ]);
1051-
1052- quoteOneName (attname ,
1053- RIAttName (fk_rel , riinfo -> fk_attnums [i ]));
1054- appendStringInfo (& querybuf ,
1055- "%s %s = NULL" ,
1056- querysep , attname );
1057- sprintf (paramname , "$%d" , i + 1 );
1058- ri_GenerateQual (& qualbuf , qualsep ,
1059- paramname , pk_type ,
1060- riinfo -> pf_eq_oprs [i ],
1061- attname , fk_type );
1062- querysep = "," ;
1063- qualsep = "AND" ;
1064- queryoids [i ] = pk_type ;
1065- }
1066- appendStringInfoString (& querybuf , qualbuf .data );
1067-
1068- /* Prepare and save the plan */
1069- qplan = ri_PlanCheck (querybuf .data , riinfo -> nkeys , queryoids ,
1070- & qkey , fk_rel , pk_rel , true);
1071- }
1072-
1073- /*
1074- * We have a plan now. Run it to update the existing references.
1075- */
1076- ri_PerformCheck (riinfo , & qkey , qplan ,
1077- fk_rel , pk_rel ,
1078- oldslot , NULL ,
1079- true, /* must detect new rows */
1080- SPI_OK_UPDATE );
1081-
1082- if (SPI_finish () != SPI_OK_FINISH )
1083- elog (ERROR , "SPI_finish failed" );
1084-
1085- table_close (fk_rel , RowExclusiveLock );
1086-
1087- return PointerGetDatum (NULL );
1088- }
1089-
1090-
1091980/*
1092981 * RI_FKey_setdefault_del -
1093982 *
@@ -1100,7 +989,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
1100989 ri_CheckTrigger (fcinfo , "RI_FKey_setdefault_del" , RI_TRIGTYPE_DELETE );
1101990
1102991 /* Share code with UPDATE case */
1103- return ri_setdefault ((TriggerData * ) fcinfo -> context );
992+ return ri_set ((TriggerData * ) fcinfo -> context , false );
1104993}
1105994
1106995/*
@@ -1115,16 +1004,17 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
11151004 ri_CheckTrigger (fcinfo , "RI_FKey_setdefault_upd" , RI_TRIGTYPE_UPDATE );
11161005
11171006 /* Share code with DELETE case */
1118- return ri_setdefault ((TriggerData * ) fcinfo -> context );
1007+ return ri_set ((TriggerData * ) fcinfo -> context , false );
11191008}
11201009
11211010/*
1122- * ri_setdefault -
1011+ * ri_set -
11231012 *
1124- * Common code for ON DELETE SET DEFAULT and ON UPDATE SET DEFAULT
1013+ * Common code for ON DELETE SET NULL, ON DELETE SET DEFAULT, ON UPDATE SET
1014+ * NULL, and ON UPDATE SET DEFAULT.
11251015 */
11261016static Datum
1127- ri_setdefault (TriggerData * trigdata )
1017+ ri_set (TriggerData * trigdata , bool is_set_null )
11281018{
11291019 const RI_ConstraintInfo * riinfo ;
11301020 Relation fk_rel ;
@@ -1150,10 +1040,13 @@ ri_setdefault(TriggerData *trigdata)
11501040 elog (ERROR , "SPI_connect failed" );
11511041
11521042 /*
1153- * Fetch or prepare a saved plan for the set default operation
1154- * (it's the same query for delete and update cases)
1043+ * Fetch or prepare a saved plan for the set null/ default operation (it's
1044+ * the same query for delete and update cases)
11551045 */
1156- ri_BuildQueryKey (& qkey , riinfo , RI_PLAN_SETDEFAULT_DOUPDATE );
1046+ ri_BuildQueryKey (& qkey , riinfo ,
1047+ (is_set_null
1048+ ? RI_PLAN_SETNULL_DOUPDATE
1049+ : RI_PLAN_SETDEFAULT_DOUPDATE ));
11571050
11581051 if ((qplan = ri_FetchPreparedPlan (& qkey )) == NULL )
11591052 {
@@ -1169,17 +1062,17 @@ ri_setdefault(TriggerData *trigdata)
11691062
11701063 /* ----------
11711064 * The query string built is
1172- * UPDATE [ONLY] <fktable> SET fkatt1 = DEFAULT [, ...]
1065+ * UPDATE [ONLY] <fktable> SET fkatt1 = {NULL| DEFAULT} [, ...]
11731066 * WHERE $1 = fkatt1 [AND ...]
11741067 * The type id's for the $ parameters are those of the
11751068 * corresponding PK attributes.
11761069 * ----------
11771070 */
11781071 initStringInfo (& querybuf );
11791072 initStringInfo (& qualbuf );
1180- quoteRelationName (fkrelname , fk_rel );
11811073 fk_only = fk_rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE ?
11821074 "" : "ONLY " ;
1075+ quoteRelationName (fkrelname , fk_rel );
11831076 appendStringInfo (& querybuf , "UPDATE %s%s SET" ,
11841077 fk_only , fkrelname );
11851078 querysep = "" ;
@@ -1192,8 +1085,9 @@ ri_setdefault(TriggerData *trigdata)
11921085 quoteOneName (attname ,
11931086 RIAttName (fk_rel , riinfo -> fk_attnums [i ]));
11941087 appendStringInfo (& querybuf ,
1195- "%s %s = DEFAULT" ,
1196- querysep , attname );
1088+ "%s %s = %s" ,
1089+ querysep , attname ,
1090+ is_set_null ? "NULL" : "DEFAULT" );
11971091 sprintf (paramname , "$%d" , i + 1 );
11981092 ri_GenerateQual (& qualbuf , qualsep ,
11991093 paramname , pk_type ,
@@ -1224,21 +1118,26 @@ ri_setdefault(TriggerData *trigdata)
12241118
12251119 table_close (fk_rel , RowExclusiveLock );
12261120
1227- /*
1228- * If we just deleted or updated the PK row whose key was equal to
1229- * the FK columns' default values, and a referencing row exists in
1230- * the FK table, we would have updated that row to the same values
1231- * it already had --- and RI_FKey_fk_upd_check_required would
1232- * hence believe no check is necessary. So we need to do another
1233- * lookup now and in case a reference still exists, abort the
1234- * operation. That is already implemented in the NO ACTION
1235- * trigger, so just run it. (This recheck is only needed in the
1236- * SET DEFAULT case, since CASCADE would remove such rows in case
1237- * of a DELETE operation or would change the FK key values in case
1238- * of an UPDATE, while SET NULL is certain to result in rows that
1239- * satisfy the FK constraint.)
1240- */
1241- return ri_restrict (trigdata , true);
1121+ if (is_set_null )
1122+ return PointerGetDatum (NULL );
1123+ else
1124+ {
1125+ /*
1126+ * If we just deleted or updated the PK row whose key was equal to
1127+ * the FK columns' default values, and a referencing row exists in
1128+ * the FK table, we would have updated that row to the same values
1129+ * it already had --- and RI_FKey_fk_upd_check_required would
1130+ * hence believe no check is necessary. So we need to do another
1131+ * lookup now and in case a reference still exists, abort the
1132+ * operation. That is already implemented in the NO ACTION
1133+ * trigger, so just run it. (This recheck is only needed in the
1134+ * SET DEFAULT case, since CASCADE would remove such rows in case
1135+ * of a DELETE operation or would change the FK key values in case
1136+ * of an UPDATE, while SET NULL is certain to result in rows that
1137+ * satisfy the FK constraint.)
1138+ */
1139+ return ri_restrict (trigdata , true);
1140+ }
12421141}
12431142
12441143
0 commit comments