Skip to content

Commit 3f61999

Browse files
committed
Merge near-duplicate code in RI triggers
Merge ri_setnull and ri_setdefault into one function ri_set. These functions were to a large part identical. This is a continuation in spirit of 4797f9b. Author: Corey Huinker <corey.huinker@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/0ccdd3e1-10b0-dd05-d8a7-183507c11eb1%402ndquadrant.com
1 parent c94fb8e commit 3f61999

File tree

1 file changed

+40
-141
lines changed

1 file changed

+40
-141
lines changed

src/backend/utils/adt/ri_triggers.c

Lines changed: 40 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,7 @@ static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
176176
TupleTableSlot *oldslot,
177177
const RI_ConstraintInfo *riinfo);
178178
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);
181180
static void quoteOneName(char *buffer, const char *name);
182181
static void quoteRelationName(char *buffer, Relation rel);
183182
static 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
*/
11261016
static 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

Comments
 (0)