Remove unnecessary unused MATCH PARTIAL code

ri_triggers.c spends a lot of space catering to a not-yet-implemented
MATCH PARTIAL option.  An actual implementation would probably not use
the existing code structure anyway, so let's just simplify this for
now.

First, have ri_FetchConstraintInfo() check that riinfo->confmatchtype
is valid.  Then we don't have to repeat that everywhere.

In the various referential action functions, we don't need to pay
attention to the match type at all right now, so remove all that code.
A future MATCH PARTIAL implementation would probably have some
conditions added to the present code, but it won't need an entirely
separate switch branch in each case.

In RI_FKey_fk_upd_check_required(), reorganize the code to make it
much simpler.

Reviewed-by: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/0ccdd3e1-10b0-dd05-d8a7-183507c11eb1%402ndquadrant.com
This commit is contained in:
Peter Eisentraut 2019-02-28 10:54:44 +01:00
parent 22c0d52b8d
commit 0afdecc1e5
1 changed files with 461 additions and 677 deletions

View File

@ -20,14 +20,6 @@
* ----------
*/
/* ----------
* Internal TODO:
*
* Add MATCH PARTIAL logic.
* ----------
*/
#include "postgres.h"
#include "access/heapam.h"
@ -308,11 +300,6 @@ RI_FKey_check(TriggerData *trigdata)
fk_rel = trigdata->tg_relation;
pk_rel = table_open(riinfo->pk_relid, RowShareLock);
if (riinfo->confmatchtype == FKCONSTR_MATCH_PARTIAL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
switch (ri_NullCheck(RelationGetDescr(fk_rel), newslot, riinfo, false))
{
case RI_KEYS_ALL_NULL:
@ -358,6 +345,7 @@ RI_FKey_check(TriggerData *trigdata)
table_close(pk_rel, RowShareLock);
return PointerGetDatum(NULL);
#ifdef NOT_USED
case FKCONSTR_MATCH_PARTIAL:
/*
@ -366,16 +354,8 @@ RI_FKey_check(TriggerData *trigdata)
* to only include non-null columns, or by writing a
* special version here)
*/
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
table_close(pk_rel, RowShareLock);
return PointerGetDatum(NULL);
default:
elog(ERROR, "unrecognized confmatchtype: %d",
riinfo->confmatchtype);
break;
#endif
}
case RI_KEYS_NONE_NULL:
@ -716,21 +696,6 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
pk_rel = trigdata->tg_relation;
old_slot = trigdata->tg_trigslot;
switch (riinfo->confmatchtype)
{
/* ----------
* SQL:2008 15.17 <Execution of referential actions>
* General rules 9) a) iv):
* MATCH SIMPLE/FULL
* ... ON DELETE RESTRICT
* General rules 10) a) iv):
* MATCH SIMPLE/FULL
* ... ON UPDATE RESTRICT
* ----------
*/
case FKCONSTR_MATCH_SIMPLE:
case FKCONSTR_MATCH_FULL:
/*
* If another PK row now exists providing the old key values, we
* should not do anything. However, this check should only be
@ -816,24 +781,6 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
table_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL);
/*
* Handle MATCH PARTIAL restrict delete or update.
*/
case FKCONSTR_MATCH_PARTIAL:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
return PointerGetDatum(NULL);
default:
elog(ERROR, "unrecognized confmatchtype: %d",
riinfo->confmatchtype);
break;
}
/* Never reached */
return PointerGetDatum(NULL);
}
@ -876,17 +823,6 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
pk_rel = trigdata->tg_relation;
old_slot = trigdata->tg_trigslot;
switch (riinfo->confmatchtype)
{
/* ----------
* SQL:2008 15.17 <Execution of referential actions>
* General rules 9) a) i):
* MATCH SIMPLE/FULL
* ... ON DELETE CASCADE
* ----------
*/
case FKCONSTR_MATCH_SIMPLE:
case FKCONSTR_MATCH_FULL:
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect failed");
@ -956,24 +892,6 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
table_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL);
/*
* Handle MATCH PARTIAL cascaded delete.
*/
case FKCONSTR_MATCH_PARTIAL:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
return PointerGetDatum(NULL);
default:
elog(ERROR, "unrecognized confmatchtype: %d",
riinfo->confmatchtype);
break;
}
/* Never reached */
return PointerGetDatum(NULL);
}
@ -1020,17 +938,6 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
new_slot = trigdata->tg_newslot;
old_slot = trigdata->tg_trigslot;
switch (riinfo->confmatchtype)
{
/* ----------
* SQL:2008 15.17 <Execution of referential actions>
* General rules 10) a) i):
* MATCH SIMPLE/FULL
* ... ON UPDATE CASCADE
* ----------
*/
case FKCONSTR_MATCH_SIMPLE:
case FKCONSTR_MATCH_FULL:
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect failed");
@ -1112,24 +1019,6 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
table_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL);
/*
* Handle MATCH PARTIAL cascade update.
*/
case FKCONSTR_MATCH_PARTIAL:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
return PointerGetDatum(NULL);
default:
elog(ERROR, "unrecognized confmatchtype: %d",
riinfo->confmatchtype);
break;
}
/* Never reached */
return PointerGetDatum(NULL);
}
@ -1206,20 +1095,6 @@ ri_setnull(TriggerData *trigdata)
pk_rel = trigdata->tg_relation;
old_slot = trigdata->tg_trigslot;
switch (riinfo->confmatchtype)
{
/* ----------
* SQL:2008 15.17 <Execution of referential actions>
* General rules 9) a) ii):
* MATCH SIMPLE/FULL
* ... ON DELETE SET NULL
* General rules 10) a) ii):
* MATCH SIMPLE/FULL
* ... ON UPDATE SET NULL
* ----------
*/
case FKCONSTR_MATCH_SIMPLE:
case FKCONSTR_MATCH_FULL:
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect failed");
@ -1299,24 +1174,6 @@ ri_setnull(TriggerData *trigdata)
table_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL);
/*
* Handle MATCH PARTIAL set null delete or update.
*/
case FKCONSTR_MATCH_PARTIAL:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
return PointerGetDatum(NULL);
default:
elog(ERROR, "unrecognized confmatchtype: %d",
riinfo->confmatchtype);
break;
}
/* Never reached */
return PointerGetDatum(NULL);
}
@ -1392,20 +1249,6 @@ ri_setdefault(TriggerData *trigdata)
pk_rel = trigdata->tg_relation;
old_slot = trigdata->tg_trigslot;
switch (riinfo->confmatchtype)
{
/* ----------
* SQL:2008 15.17 <Execution of referential actions>
* General rules 9) a) iii):
* MATCH SIMPLE/FULL
* ... ON DELETE SET DEFAULT
* General rules 10) a) iii):
* MATCH SIMPLE/FULL
* ... ON UPDATE SET DEFAULT
* ----------
*/
case FKCONSTR_MATCH_SIMPLE:
case FKCONSTR_MATCH_FULL:
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect failed");
@ -1500,24 +1343,6 @@ ri_setdefault(TriggerData *trigdata)
* satisfy the FK constraint.)
*/
return ri_restrict(trigdata, true);
/*
* Handle MATCH PARTIAL set default delete or update.
*/
case FKCONSTR_MATCH_PARTIAL:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
return PointerGetDatum(NULL);
default:
elog(ERROR, "unrecognized confmatchtype: %d",
riinfo->confmatchtype);
break;
}
/* Never reached */
return PointerGetDatum(NULL);
}
@ -1544,11 +1369,6 @@ RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel,
*/
riinfo = ri_FetchConstraintInfo(trigger, pk_rel, true);
switch (riinfo->confmatchtype)
{
case FKCONSTR_MATCH_SIMPLE:
case FKCONSTR_MATCH_FULL:
/*
* If any old key value is NULL, the row could not have been
* referenced by an FK row, so no check is needed.
@ -1562,22 +1382,6 @@ RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel,
/* Else we need to fire the trigger. */
return true;
/* Handle MATCH PARTIAL check. */
case FKCONSTR_MATCH_PARTIAL:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
break;
default:
elog(ERROR, "unrecognized confmatchtype: %d",
riinfo->confmatchtype);
break;
}
/* Never reached */
return false;
}
/* ----------
@ -1595,6 +1399,7 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
TupleTableSlot *old_slot, TupleTableSlot *new_slot)
{
const RI_ConstraintInfo *riinfo;
int ri_nullcheck;
Datum xminDatum;
TransactionId xmin;
bool isnull;
@ -1604,57 +1409,50 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
*/
riinfo = ri_FetchConstraintInfo(trigger, fk_rel, false);
ri_nullcheck = ri_NullCheck(RelationGetDescr(fk_rel), new_slot, riinfo, false);
/*
* If all new key values are NULL, the row satisfies the constraint, so no
* check is needed.
*/
if (ri_nullcheck == RI_KEYS_ALL_NULL)
return false;
/*
* If some new key values are NULL, the behavior depends on the match type.
*/
else if (ri_nullcheck == RI_KEYS_SOME_NULL)
{
switch (riinfo->confmatchtype)
{
case FKCONSTR_MATCH_SIMPLE:
/*
* If any new key value is NULL, the row must satisfy the
* constraint, so no check is needed.
*/
if (ri_NullCheck(RelationGetDescr(fk_rel), new_slot, riinfo, false) != RI_KEYS_NONE_NULL)
return false;
case FKCONSTR_MATCH_PARTIAL:
/*
* If the original row was inserted by our own transaction, we
* must fire the trigger whether or not the keys are equal. This
* is because our UPDATE will invalidate the INSERT so that the
* INSERT RI trigger will not do anything; so we had better do the
* UPDATE check. (We could skip this if we knew the INSERT
* trigger already fired, but there is no easy way to know that.)
* Don't know, must run full check.
*/
xminDatum = slot_getsysattr(old_slot, MinTransactionIdAttributeNumber, &isnull);
Assert(!isnull);
xmin = DatumGetTransactionId(xminDatum);
if (TransactionIdIsCurrentTransactionId(xmin))
return true;
/* If all old and new key values are equal, no check is needed */
if (ri_KeysEqual(fk_rel, old_slot, new_slot, riinfo, false))
return false;
/* Else we need to fire the trigger. */
return true;
break;
case FKCONSTR_MATCH_FULL:
/*
* If some new key values are NULL, the row fails the
* constraint. We must not throw error here, because the row
* might get invalidated before the constraint is to be
* checked, but we should queue the event to apply the check
* later.
*/
return true;
}
}
/*
* If all new key values are NULL, the row must satisfy the
* constraint, so no check is needed. On the other hand, if only
* some of them are NULL, the row must fail the constraint. We
* must not throw error here, because the row might get
* invalidated before the constraint is to be checked, but we
* should queue the event to apply the check later.
* Continues here for no new key values are NULL, or we couldn't decide
* yet.
*/
switch (ri_NullCheck(RelationGetDescr(fk_rel), new_slot, riinfo, false))
{
case RI_KEYS_ALL_NULL:
return false;
case RI_KEYS_SOME_NULL:
return true;
case RI_KEYS_NONE_NULL:
break; /* continue with the check */
}
/*
* If the original row was inserted by our own transaction, we
@ -1676,22 +1474,6 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
/* Else we need to fire the trigger. */
return true;
/* Handle MATCH PARTIAL check. */
case FKCONSTR_MATCH_PARTIAL:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
break;
default:
elog(ERROR, "unrecognized confmatchtype: %d",
riinfo->confmatchtype);
break;
}
/* Never reached */
return false;
}
/* ----------
@ -1860,15 +1642,6 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
case FKCONSTR_MATCH_FULL:
sep = " OR ";
break;
case FKCONSTR_MATCH_PARTIAL:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
break;
default:
elog(ERROR, "unrecognized confmatchtype: %d",
riinfo->confmatchtype);
break;
}
}
appendStringInfoChar(&querybuf, ')');
@ -2199,6 +1972,17 @@ ri_FetchConstraintInfo(Trigger *trigger, Relation trig_rel, bool rel_is_pk)
trigger->tgname, RelationGetRelationName(trig_rel));
}
if (riinfo->confmatchtype != FKCONSTR_MATCH_FULL &&
riinfo->confmatchtype != FKCONSTR_MATCH_PARTIAL &&
riinfo->confmatchtype != FKCONSTR_MATCH_SIMPLE)
elog(ERROR, "unrecognized confmatchtype: %d",
riinfo->confmatchtype);
if (riinfo->confmatchtype == FKCONSTR_MATCH_PARTIAL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
return riinfo;
}