diff options
Diffstat (limited to 'src/backend/utils/adt/ri_triggers.c')
-rw-r--r-- | src/backend/utils/adt/ri_triggers.c | 115 |
1 files changed, 85 insertions, 30 deletions
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 96269fc2adb..8ebb2a50a11 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -73,11 +73,14 @@ #define RI_PLAN_CHECK_LOOKUPPK_FROM_PK 2 #define RI_PLAN_LAST_ON_PK RI_PLAN_CHECK_LOOKUPPK_FROM_PK /* these queries are executed against the FK (referencing) table: */ -#define RI_PLAN_CASCADE_DEL_DODELETE 3 -#define RI_PLAN_CASCADE_UPD_DOUPDATE 4 -#define RI_PLAN_RESTRICT_CHECKREF 5 -#define RI_PLAN_SETNULL_DOUPDATE 6 -#define RI_PLAN_SETDEFAULT_DOUPDATE 7 +#define RI_PLAN_CASCADE_ONDELETE 3 +#define RI_PLAN_CASCADE_ONUPDATE 4 +/* For RESTRICT, the same plan can be used for both ON DELETE and ON UPDATE triggers. */ +#define RI_PLAN_RESTRICT 5 +#define RI_PLAN_SETNULL_ONDELETE 6 +#define RI_PLAN_SETNULL_ONUPDATE 7 +#define RI_PLAN_SETDEFAULT_ONDELETE 8 +#define RI_PLAN_SETDEFAULT_ONUPDATE 9 #define MAX_QUOTED_NAME_LEN (NAMEDATALEN*2+3) #define MAX_QUOTED_REL_NAME_LEN (MAX_QUOTED_NAME_LEN*2) @@ -110,6 +113,8 @@ typedef struct RI_ConstraintInfo Oid fk_relid; /* referencing relation */ char confupdtype; /* foreign key's ON UPDATE action */ char confdeltype; /* foreign key's ON DELETE action */ + int ndelsetcols; /* number of columns referenced in ON DELETE SET clause */ + int16 confdelsetcols[RI_MAX_NUMKEYS]; /* attnums of cols to set on delete */ char confmatchtype; /* foreign key's match type */ int nkeys; /* number of key columns */ int16 pk_attnums[RI_MAX_NUMKEYS]; /* attnums of referenced cols */ @@ -180,7 +185,7 @@ static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, TupleTableSlot *oldslot, const RI_ConstraintInfo *riinfo); static Datum ri_restrict(TriggerData *trigdata, bool is_no_action); -static Datum ri_set(TriggerData *trigdata, bool is_set_null); +static Datum ri_set(TriggerData *trigdata, bool is_set_null, int tgkind); static void quoteOneName(char *buffer, const char *name); static void quoteRelationName(char *buffer, Relation rel); static void ri_GenerateQual(StringInfo buf, @@ -660,7 +665,7 @@ ri_restrict(TriggerData *trigdata, bool is_no_action) * Fetch or prepare a saved plan for the restrict lookup (it's the same * query for delete and update cases) */ - ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_RESTRICT_CHECKREF); + ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_RESTRICT); if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) { @@ -767,7 +772,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) elog(ERROR, "SPI_connect failed"); /* Fetch or prepare a saved plan for the cascaded delete */ - ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CASCADE_DEL_DODELETE); + ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CASCADE_ONDELETE); if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) { @@ -876,7 +881,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) elog(ERROR, "SPI_connect failed"); /* Fetch or prepare a saved plan for the cascaded update */ - ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CASCADE_UPD_DOUPDATE); + ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CASCADE_ONUPDATE); if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) { @@ -970,7 +975,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) ri_CheckTrigger(fcinfo, "RI_FKey_setnull_del", RI_TRIGTYPE_DELETE); /* Share code with UPDATE case */ - return ri_set((TriggerData *) fcinfo->context, true); + return ri_set((TriggerData *) fcinfo->context, true, RI_TRIGTYPE_DELETE); } /* @@ -985,7 +990,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) ri_CheckTrigger(fcinfo, "RI_FKey_setnull_upd", RI_TRIGTYPE_UPDATE); /* Share code with DELETE case */ - return ri_set((TriggerData *) fcinfo->context, true); + return ri_set((TriggerData *) fcinfo->context, true, RI_TRIGTYPE_UPDATE); } /* @@ -1000,7 +1005,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_del", RI_TRIGTYPE_DELETE); /* Share code with UPDATE case */ - return ri_set((TriggerData *) fcinfo->context, false); + return ri_set((TriggerData *) fcinfo->context, false, RI_TRIGTYPE_DELETE); } /* @@ -1015,7 +1020,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_upd", RI_TRIGTYPE_UPDATE); /* Share code with DELETE case */ - return ri_set((TriggerData *) fcinfo->context, false); + return ri_set((TriggerData *) fcinfo->context, false, RI_TRIGTYPE_UPDATE); } /* @@ -1025,7 +1030,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) * NULL, and ON UPDATE SET DEFAULT. */ static Datum -ri_set(TriggerData *trigdata, bool is_set_null) +ri_set(TriggerData *trigdata, bool is_set_null, int tgkind) { const RI_ConstraintInfo *riinfo; Relation fk_rel; @@ -1033,6 +1038,7 @@ ri_set(TriggerData *trigdata, bool is_set_null) TupleTableSlot *oldslot; RI_QueryKey qkey; SPIPlanPtr qplan; + int32 queryno; riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger, trigdata->tg_relation, true); @@ -1051,18 +1057,28 @@ ri_set(TriggerData *trigdata, bool is_set_null) elog(ERROR, "SPI_connect failed"); /* - * Fetch or prepare a saved plan for the set null/default operation (it's - * the same query for delete and update cases) + * Fetch or prepare a saved plan for the trigger. */ - ri_BuildQueryKey(&qkey, riinfo, - (is_set_null - ? RI_PLAN_SETNULL_DOUPDATE - : RI_PLAN_SETDEFAULT_DOUPDATE)); + switch (tgkind) { + case RI_TRIGTYPE_UPDATE: + queryno = is_set_null + ? RI_PLAN_SETNULL_ONUPDATE + : RI_PLAN_SETDEFAULT_ONUPDATE; + break; + case RI_TRIGTYPE_DELETE: + queryno = is_set_null + ? RI_PLAN_SETNULL_ONDELETE + : RI_PLAN_SETDEFAULT_ONDELETE; + break; + default: + elog(ERROR, "invalid tgkind passed to ri_set"); + } + + ri_BuildQueryKey(&qkey, riinfo, queryno); if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) { StringInfoData querybuf; - StringInfoData qualbuf; char fkrelname[MAX_QUOTED_REL_NAME_LEN]; char attname[MAX_QUOTED_NAME_LEN]; char paramname[16]; @@ -1070,6 +1086,32 @@ ri_set(TriggerData *trigdata, bool is_set_null) const char *qualsep; Oid queryoids[RI_MAX_NUMKEYS]; const char *fk_only; + int num_cols_to_set; + const int16 *set_cols; + + switch (tgkind) { + case RI_TRIGTYPE_UPDATE: + num_cols_to_set = riinfo->nkeys; + set_cols = riinfo->fk_attnums; + break; + case RI_TRIGTYPE_DELETE: + /* + * If confdelsetcols are present, then we only update + * the columns specified in that array, otherwise we + * update all the referencing columns. + */ + if (riinfo->ndelsetcols != 0) { + num_cols_to_set = riinfo->ndelsetcols; + set_cols = riinfo->confdelsetcols; + } + else { + num_cols_to_set = riinfo->nkeys; + set_cols = riinfo->fk_attnums; + } + break; + default: + elog(ERROR, "invalid tgkind passed to ri_set"); + } /* ---------- * The query string built is @@ -1080,13 +1122,29 @@ ri_set(TriggerData *trigdata, bool is_set_null) * ---------- */ initStringInfo(&querybuf); - initStringInfo(&qualbuf); fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY "; quoteRelationName(fkrelname, fk_rel); appendStringInfo(&querybuf, "UPDATE %s%s SET", fk_only, fkrelname); + + /* + * Add assignment clauses + */ querysep = ""; + for (int i = 0; i < num_cols_to_set; i++) + { + quoteOneName(attname, RIAttName(fk_rel, set_cols[i])); + appendStringInfo(&querybuf, + "%s %s = %s", + querysep, attname, + is_set_null ? "NULL" : "DEFAULT"); + querysep = ","; + } + + /* + * Add WHERE clause + */ qualsep = "WHERE"; for (int i = 0; i < riinfo->nkeys; i++) { @@ -1097,22 +1155,17 @@ ri_set(TriggerData *trigdata, bool is_set_null) quoteOneName(attname, RIAttName(fk_rel, riinfo->fk_attnums[i])); - appendStringInfo(&querybuf, - "%s %s = %s", - querysep, attname, - is_set_null ? "NULL" : "DEFAULT"); + sprintf(paramname, "$%d", i + 1); - ri_GenerateQual(&qualbuf, qualsep, + ri_GenerateQual(&querybuf, qualsep, paramname, pk_type, riinfo->pf_eq_oprs[i], attname, fk_type); if (pk_coll != fk_coll && !get_collation_isdeterministic(pk_coll)) ri_GenerateQualCollation(&querybuf, pk_coll); - querysep = ","; qualsep = "AND"; queryoids[i] = pk_type; } - appendBinaryStringInfo(&querybuf, qualbuf.data, qualbuf.len); /* Prepare and save the plan */ qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids, @@ -2098,7 +2151,9 @@ ri_LoadConstraintInfo(Oid constraintOid) riinfo->pk_attnums, riinfo->pf_eq_oprs, riinfo->pp_eq_oprs, - riinfo->ff_eq_oprs); + riinfo->ff_eq_oprs, + &riinfo->ndelsetcols, + riinfo->confdelsetcols); ReleaseSysCache(tup); |