@@ -176,8 +176,7 @@ static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
176
176
TupleTableSlot * oldslot ,
177
177
const RI_ConstraintInfo * riinfo );
178
178
static 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 );
181
180
static void quoteOneName (char * buffer , const char * name );
182
181
static void quoteRelationName (char * buffer , Relation rel );
183
182
static void ri_GenerateQual (StringInfo buf ,
@@ -960,7 +959,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
960
959
ri_CheckTrigger (fcinfo , "RI_FKey_setnull_del" , RI_TRIGTYPE_DELETE );
961
960
962
961
/* Share code with UPDATE case */
963
- return ri_setnull ((TriggerData * ) fcinfo -> context );
962
+ return ri_set ((TriggerData * ) fcinfo -> context , true );
964
963
}
965
964
966
965
/*
@@ -975,119 +974,9 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
975
974
ri_CheckTrigger (fcinfo , "RI_FKey_setnull_upd" , RI_TRIGTYPE_UPDATE );
976
975
977
976
/* Share code with DELETE case */
978
- return ri_setnull ((TriggerData * ) fcinfo -> context );
977
+ return ri_set ((TriggerData * ) fcinfo -> context , true );
979
978
}
980
979
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
-
1091
980
/*
1092
981
* RI_FKey_setdefault_del -
1093
982
*
@@ -1100,7 +989,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
1100
989
ri_CheckTrigger (fcinfo , "RI_FKey_setdefault_del" , RI_TRIGTYPE_DELETE );
1101
990
1102
991
/* Share code with UPDATE case */
1103
- return ri_setdefault ((TriggerData * ) fcinfo -> context );
992
+ return ri_set ((TriggerData * ) fcinfo -> context , false );
1104
993
}
1105
994
1106
995
/*
@@ -1115,16 +1004,17 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
1115
1004
ri_CheckTrigger (fcinfo , "RI_FKey_setdefault_upd" , RI_TRIGTYPE_UPDATE );
1116
1005
1117
1006
/* Share code with DELETE case */
1118
- return ri_setdefault ((TriggerData * ) fcinfo -> context );
1007
+ return ri_set ((TriggerData * ) fcinfo -> context , false );
1119
1008
}
1120
1009
1121
1010
/*
1122
- * ri_setdefault -
1011
+ * ri_set -
1123
1012
*
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.
1125
1015
*/
1126
1016
static Datum
1127
- ri_setdefault (TriggerData * trigdata )
1017
+ ri_set (TriggerData * trigdata , bool is_set_null )
1128
1018
{
1129
1019
const RI_ConstraintInfo * riinfo ;
1130
1020
Relation fk_rel ;
@@ -1150,10 +1040,13 @@ ri_setdefault(TriggerData *trigdata)
1150
1040
elog (ERROR , "SPI_connect failed" );
1151
1041
1152
1042
/*
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)
1155
1045
*/
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 ));
1157
1050
1158
1051
if ((qplan = ri_FetchPreparedPlan (& qkey )) == NULL )
1159
1052
{
@@ -1169,17 +1062,17 @@ ri_setdefault(TriggerData *trigdata)
1169
1062
1170
1063
/* ----------
1171
1064
* The query string built is
1172
- * UPDATE [ONLY] <fktable> SET fkatt1 = DEFAULT [, ...]
1065
+ * UPDATE [ONLY] <fktable> SET fkatt1 = {NULL| DEFAULT} [, ...]
1173
1066
* WHERE $1 = fkatt1 [AND ...]
1174
1067
* The type id's for the $ parameters are those of the
1175
1068
* corresponding PK attributes.
1176
1069
* ----------
1177
1070
*/
1178
1071
initStringInfo (& querybuf );
1179
1072
initStringInfo (& qualbuf );
1180
- quoteRelationName (fkrelname , fk_rel );
1181
1073
fk_only = fk_rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE ?
1182
1074
"" : "ONLY " ;
1075
+ quoteRelationName (fkrelname , fk_rel );
1183
1076
appendStringInfo (& querybuf , "UPDATE %s%s SET" ,
1184
1077
fk_only , fkrelname );
1185
1078
querysep = "" ;
@@ -1192,8 +1085,9 @@ ri_setdefault(TriggerData *trigdata)
1192
1085
quoteOneName (attname ,
1193
1086
RIAttName (fk_rel , riinfo -> fk_attnums [i ]));
1194
1087
appendStringInfo (& querybuf ,
1195
- "%s %s = DEFAULT" ,
1196
- querysep , attname );
1088
+ "%s %s = %s" ,
1089
+ querysep , attname ,
1090
+ is_set_null ? "NULL" : "DEFAULT" );
1197
1091
sprintf (paramname , "$%d" , i + 1 );
1198
1092
ri_GenerateQual (& qualbuf , qualsep ,
1199
1093
paramname , pk_type ,
@@ -1224,21 +1118,26 @@ ri_setdefault(TriggerData *trigdata)
1224
1118
1225
1119
table_close (fk_rel , RowExclusiveLock );
1226
1120
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
+ }
1242
1141
}
1243
1142
1244
1143
0 commit comments