aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ri_triggers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/ri_triggers.c')
-rw-r--r--src/backend/utils/adt/ri_triggers.c187
1 files changed, 110 insertions, 77 deletions
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index e1aa3d0044f..5b4579fe83e 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -192,7 +192,7 @@ static int ri_constraint_cache_valid_count = 0;
* ----------
*/
static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
- HeapTuple old_row,
+ TupleTableSlot *oldslot,
const RI_ConstraintInfo *riinfo);
static Datum ri_restrict(TriggerData *trigdata, bool is_no_action);
static Datum ri_setnull(TriggerData *trigdata);
@@ -205,12 +205,12 @@ static void ri_GenerateQual(StringInfo buf,
Oid opoid,
const char *rightop, Oid rightoptype);
static void ri_GenerateQualCollation(StringInfo buf, Oid collation);
-static int ri_NullCheck(TupleDesc tupdesc, HeapTuple tup,
+static int ri_NullCheck(TupleDesc tupdesc, TupleTableSlot *slot,
const RI_ConstraintInfo *riinfo, bool rel_is_pk);
static void ri_BuildQueryKey(RI_QueryKey *key,
const RI_ConstraintInfo *riinfo,
int32 constr_queryno);
-static bool ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
+static bool ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot,
const RI_ConstraintInfo *riinfo, bool rel_is_pk);
static bool ri_AttributesEqual(Oid eq_opr, Oid typeid,
Datum oldvalue, Datum newvalue);
@@ -232,14 +232,14 @@ static SPIPlanPtr ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo,
RI_QueryKey *qkey, SPIPlanPtr qplan,
Relation fk_rel, Relation pk_rel,
- HeapTuple old_tuple, HeapTuple new_tuple,
+ TupleTableSlot *oldslot, TupleTableSlot *newslot,
bool detectNewRows, int expect_OK);
-static void ri_ExtractValues(Relation rel, HeapTuple tup,
+static void ri_ExtractValues(Relation rel, TupleTableSlot *slot,
const RI_ConstraintInfo *riinfo, bool rel_is_pk,
Datum *vals, char *nulls);
static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
Relation pk_rel, Relation fk_rel,
- HeapTuple violator, TupleDesc tupdesc,
+ TupleTableSlot *violator, TupleDesc tupdesc,
int queryno) pg_attribute_noreturn();
@@ -255,8 +255,7 @@ RI_FKey_check(TriggerData *trigdata)
const RI_ConstraintInfo *riinfo;
Relation fk_rel;
Relation pk_rel;
- HeapTuple new_row;
- Buffer new_row_buf;
+ TupleTableSlot *newslot;
RI_QueryKey qkey;
SPIPlanPtr qplan;
int i;
@@ -268,15 +267,9 @@ RI_FKey_check(TriggerData *trigdata)
trigdata->tg_relation, false);
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
- {
- new_row = trigdata->tg_newtuple;
- new_row_buf = trigdata->tg_newtuplebuf;
- }
+ newslot = trigdata->tg_newslot;
else
- {
- new_row = trigdata->tg_trigtuple;
- new_row_buf = trigdata->tg_trigtuplebuf;
- }
+ newslot = trigdata->tg_trigslot;
/*
* We should not even consider checking the row if it is no longer valid,
@@ -285,14 +278,26 @@ RI_FKey_check(TriggerData *trigdata)
* checked). Test its liveness according to SnapshotSelf. We need pin
* and lock on the buffer to call HeapTupleSatisfiesVisibility. Caller
* should be holding pin, but not lock.
+ *
+ * XXX: Note that the buffer-tuple specificity will be removed in the near
+ * future.
*/
- LockBuffer(new_row_buf, BUFFER_LOCK_SHARE);
- if (!HeapTupleSatisfiesVisibility(new_row, SnapshotSelf, new_row_buf))
+ if (TTS_IS_BUFFERTUPLE(newslot))
{
- LockBuffer(new_row_buf, BUFFER_LOCK_UNLOCK);
- return PointerGetDatum(NULL);
+ BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) newslot;
+
+ Assert(BufferIsValid(bslot->buffer));
+
+ LockBuffer(bslot->buffer, BUFFER_LOCK_SHARE);
+ if (!HeapTupleSatisfiesVisibility(bslot->base.tuple, SnapshotSelf, bslot->buffer))
+ {
+ LockBuffer(bslot->buffer, BUFFER_LOCK_UNLOCK);
+ return PointerGetDatum(NULL);
+ }
+ LockBuffer(bslot->buffer, BUFFER_LOCK_UNLOCK);
}
- LockBuffer(new_row_buf, BUFFER_LOCK_UNLOCK);
+ else
+ elog(ERROR, "expected buffer tuple");
/*
* Get the relation descriptors of the FK and PK tables.
@@ -308,7 +313,7 @@ RI_FKey_check(TriggerData *trigdata)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented")));
- switch (ri_NullCheck(RelationGetDescr(fk_rel), new_row, riinfo, false))
+ switch (ri_NullCheck(RelationGetDescr(fk_rel), newslot, riinfo, false))
{
case RI_KEYS_ALL_NULL:
@@ -438,7 +443,7 @@ RI_FKey_check(TriggerData *trigdata)
*/
ri_PerformCheck(riinfo, &qkey, qplan,
fk_rel, pk_rel,
- NULL, new_row,
+ NULL, newslot,
false,
SPI_OK_SELECT);
@@ -506,7 +511,7 @@ RI_FKey_check_upd(PG_FUNCTION_ARGS)
*/
static bool
ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
- HeapTuple old_row,
+ TupleTableSlot *oldslot,
const RI_ConstraintInfo *riinfo)
{
SPIPlanPtr qplan;
@@ -515,7 +520,7 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
bool result;
/* Only called for non-null rows */
- Assert(ri_NullCheck(RelationGetDescr(pk_rel), old_row, riinfo, true) == RI_KEYS_NONE_NULL);
+ Assert(ri_NullCheck(RelationGetDescr(pk_rel), oldslot, riinfo, true) == RI_KEYS_NONE_NULL);
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect failed");
@@ -573,7 +578,7 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
*/
result = ri_PerformCheck(riinfo, &qkey, qplan,
fk_rel, pk_rel,
- old_row, NULL,
+ oldslot, NULL,
true, /* treat like update */
SPI_OK_SELECT);
@@ -691,7 +696,7 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
const RI_ConstraintInfo *riinfo;
Relation fk_rel;
Relation pk_rel;
- HeapTuple old_row;
+ TupleTableSlot *old_slot;
RI_QueryKey qkey;
SPIPlanPtr qplan;
@@ -709,7 +714,7 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
*/
fk_rel = table_open(riinfo->fk_relid, RowShareLock);
pk_rel = trigdata->tg_relation;
- old_row = trigdata->tg_trigtuple;
+ old_slot = trigdata->tg_trigslot;
switch (riinfo->confmatchtype)
{
@@ -733,7 +738,7 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
* allow another row to be substituted.
*/
if (is_no_action &&
- ri_Check_Pk_Match(pk_rel, fk_rel, old_row, riinfo))
+ ri_Check_Pk_Match(pk_rel, fk_rel, old_slot, riinfo))
{
table_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL);
@@ -801,7 +806,7 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
*/
ri_PerformCheck(riinfo, &qkey, qplan,
fk_rel, pk_rel,
- old_row, NULL,
+ old_slot, NULL,
true, /* must detect new rows */
SPI_OK_SELECT);
@@ -845,7 +850,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
const RI_ConstraintInfo *riinfo;
Relation fk_rel;
Relation pk_rel;
- HeapTuple old_row;
+ TupleTableSlot *old_slot;
RI_QueryKey qkey;
SPIPlanPtr qplan;
int i;
@@ -869,7 +874,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
*/
fk_rel = table_open(riinfo->fk_relid, RowExclusiveLock);
pk_rel = trigdata->tg_relation;
- old_row = trigdata->tg_trigtuple;
+ old_slot = trigdata->tg_trigslot;
switch (riinfo->confmatchtype)
{
@@ -941,7 +946,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
*/
ri_PerformCheck(riinfo, &qkey, qplan,
fk_rel, pk_rel,
- old_row, NULL,
+ old_slot, NULL,
true, /* must detect new rows */
SPI_OK_DELETE);
@@ -985,8 +990,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
const RI_ConstraintInfo *riinfo;
Relation fk_rel;
Relation pk_rel;
- HeapTuple new_row;
- HeapTuple old_row;
+ TupleTableSlot *new_slot;
+ TupleTableSlot *old_slot;
RI_QueryKey qkey;
SPIPlanPtr qplan;
int i;
@@ -1012,8 +1017,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
*/
fk_rel = table_open(riinfo->fk_relid, RowExclusiveLock);
pk_rel = trigdata->tg_relation;
- new_row = trigdata->tg_newtuple;
- old_row = trigdata->tg_trigtuple;
+ new_slot = trigdata->tg_newslot;
+ old_slot = trigdata->tg_trigslot;
switch (riinfo->confmatchtype)
{
@@ -1097,7 +1102,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
*/
ri_PerformCheck(riinfo, &qkey, qplan,
fk_rel, pk_rel,
- old_row, new_row,
+ old_slot, new_slot,
true, /* must detect new rows */
SPI_OK_UPDATE);
@@ -1180,7 +1185,7 @@ ri_setnull(TriggerData *trigdata)
const RI_ConstraintInfo *riinfo;
Relation fk_rel;
Relation pk_rel;
- HeapTuple old_row;
+ TupleTableSlot *old_slot;
RI_QueryKey qkey;
SPIPlanPtr qplan;
int i;
@@ -1199,7 +1204,7 @@ ri_setnull(TriggerData *trigdata)
*/
fk_rel = table_open(riinfo->fk_relid, RowExclusiveLock);
pk_rel = trigdata->tg_relation;
- old_row = trigdata->tg_trigtuple;
+ old_slot = trigdata->tg_trigslot;
switch (riinfo->confmatchtype)
{
@@ -1284,7 +1289,7 @@ ri_setnull(TriggerData *trigdata)
*/
ri_PerformCheck(riinfo, &qkey, qplan,
fk_rel, pk_rel,
- old_row, NULL,
+ old_slot, NULL,
true, /* must detect new rows */
SPI_OK_UPDATE);
@@ -1367,7 +1372,7 @@ ri_setdefault(TriggerData *trigdata)
const RI_ConstraintInfo *riinfo;
Relation fk_rel;
Relation pk_rel;
- HeapTuple old_row;
+ TupleTableSlot *old_slot;
RI_QueryKey qkey;
SPIPlanPtr qplan;
@@ -1385,7 +1390,7 @@ ri_setdefault(TriggerData *trigdata)
*/
fk_rel = table_open(riinfo->fk_relid, RowExclusiveLock);
pk_rel = trigdata->tg_relation;
- old_row = trigdata->tg_trigtuple;
+ old_slot = trigdata->tg_trigslot;
switch (riinfo->confmatchtype)
{
@@ -1471,7 +1476,7 @@ ri_setdefault(TriggerData *trigdata)
*/
ri_PerformCheck(riinfo, &qkey, qplan,
fk_rel, pk_rel,
- old_row, NULL,
+ old_slot, NULL,
true, /* must detect new rows */
SPI_OK_UPDATE);
@@ -1530,7 +1535,7 @@ ri_setdefault(TriggerData *trigdata)
*/
bool
RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel,
- HeapTuple old_row, HeapTuple new_row)
+ TupleTableSlot *old_slot, TupleTableSlot *new_slot)
{
const RI_ConstraintInfo *riinfo;
@@ -1548,11 +1553,11 @@ RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel,
* If any old key value is NULL, the row could not have been
* referenced by an FK row, so no check is needed.
*/
- if (ri_NullCheck(RelationGetDescr(pk_rel), old_row, riinfo, true) != RI_KEYS_NONE_NULL)
+ if (ri_NullCheck(RelationGetDescr(pk_rel), old_slot, riinfo, true) != RI_KEYS_NONE_NULL)
return false;
/* If all old and new key values are equal, no check is needed */
- if (new_row && ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true))
+ if (new_slot && ri_KeysEqual(pk_rel, old_slot, new_slot, riinfo, true))
return false;
/* Else we need to fire the trigger. */
@@ -1587,9 +1592,12 @@ RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel,
*/
bool
RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
- HeapTuple old_row, HeapTuple new_row)
+ TupleTableSlot *old_slot, TupleTableSlot *new_slot)
{
const RI_ConstraintInfo *riinfo;
+ Datum xminDatum;
+ TransactionId xmin;
+ bool isnull;
/*
* Get arguments.
@@ -1604,7 +1612,7 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
* 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_row, riinfo, false) != RI_KEYS_NONE_NULL)
+ if (ri_NullCheck(RelationGetDescr(fk_rel), new_slot, riinfo, false) != RI_KEYS_NONE_NULL)
return false;
/*
@@ -1615,11 +1623,14 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
* UPDATE check. (We could skip this if we knew the INSERT
* trigger already fired, but there is no easy way to know that.)
*/
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data)))
+ 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_row, new_row, riinfo, false))
+ if (ri_KeysEqual(fk_rel, old_slot, new_slot, riinfo, false))
return false;
/* Else we need to fire the trigger. */
@@ -1635,7 +1646,7 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
* invalidated before the constraint is to be checked, but we
* should queue the event to apply the check later.
*/
- switch (ri_NullCheck(RelationGetDescr(fk_rel), new_row, riinfo, false))
+ switch (ri_NullCheck(RelationGetDescr(fk_rel), new_slot, riinfo, false))
{
case RI_KEYS_ALL_NULL:
return false;
@@ -1653,11 +1664,14 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
* UPDATE check. (We could skip this if we knew the INSERT
* trigger already fired, but there is no easy way to know that.)
*/
- if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data)))
+ 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_row, new_row, riinfo, false))
+ if (ri_KeysEqual(fk_rel, old_slot, new_slot, riinfo, false))
return false;
/* Else we need to fire the trigger. */
@@ -1911,10 +1925,17 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
/* Did we find a tuple violating the constraint? */
if (SPI_processed > 0)
{
+ TupleTableSlot *slot;
HeapTuple tuple = SPI_tuptable->vals[0];
TupleDesc tupdesc = SPI_tuptable->tupdesc;
RI_ConstraintInfo fake_riinfo;
+ slot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual);
+
+ heap_deform_tuple(tuple, tupdesc,
+ slot->tts_values, slot->tts_isnull);
+ ExecStoreVirtualTuple(slot);
+
/*
* The columns to look at in the result tuple are 1..N, not whatever
* they are in the fk_rel. Hack up riinfo so that the subroutines
@@ -1934,7 +1955,7 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
* disallows partially-null FK rows.
*/
if (fake_riinfo.confmatchtype == FKCONSTR_MATCH_FULL &&
- ri_NullCheck(tupdesc, tuple, &fake_riinfo, false) != RI_KEYS_NONE_NULL)
+ ri_NullCheck(tupdesc, slot, &fake_riinfo, false) != RI_KEYS_NONE_NULL)
ereport(ERROR,
(errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
@@ -1951,8 +1972,10 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
*/
ri_ReportViolation(&fake_riinfo,
pk_rel, fk_rel,
- tuple, tupdesc,
+ slot, tupdesc,
RI_PLAN_CHECK_LOOKUPPK);
+
+ ExecDropSingleTupleTableSlot(slot);
}
if (SPI_finish() != SPI_OK_FINISH)
@@ -2355,7 +2378,7 @@ static bool
ri_PerformCheck(const RI_ConstraintInfo *riinfo,
RI_QueryKey *qkey, SPIPlanPtr qplan,
Relation fk_rel, Relation pk_rel,
- HeapTuple old_tuple, HeapTuple new_tuple,
+ TupleTableSlot *old_slot, TupleTableSlot *new_slot,
bool detectNewRows, int expect_OK)
{
Relation query_rel,
@@ -2398,17 +2421,17 @@ ri_PerformCheck(const RI_ConstraintInfo *riinfo,
}
/* Extract the parameters to be passed into the query */
- if (new_tuple)
+ if (new_slot)
{
- ri_ExtractValues(source_rel, new_tuple, riinfo, source_is_pk,
+ ri_ExtractValues(source_rel, new_slot, riinfo, source_is_pk,
vals, nulls);
- if (old_tuple)
- ri_ExtractValues(source_rel, old_tuple, riinfo, source_is_pk,
+ if (old_slot)
+ ri_ExtractValues(source_rel, old_slot, riinfo, source_is_pk,
vals + riinfo->nkeys, nulls + riinfo->nkeys);
}
else
{
- ri_ExtractValues(source_rel, old_tuple, riinfo, source_is_pk,
+ ri_ExtractValues(source_rel, old_slot, riinfo, source_is_pk,
vals, nulls);
}
@@ -2478,7 +2501,7 @@ ri_PerformCheck(const RI_ConstraintInfo *riinfo,
(SPI_processed == 0) == (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK))
ri_ReportViolation(riinfo,
pk_rel, fk_rel,
- new_tuple ? new_tuple : old_tuple,
+ new_slot ? new_slot : old_slot,
NULL,
qkey->constr_queryno);
@@ -2489,11 +2512,10 @@ ri_PerformCheck(const RI_ConstraintInfo *riinfo,
* Extract fields from a tuple into Datum/nulls arrays
*/
static void
-ri_ExtractValues(Relation rel, HeapTuple tup,
+ri_ExtractValues(Relation rel, TupleTableSlot *slot,
const RI_ConstraintInfo *riinfo, bool rel_is_pk,
Datum *vals, char *nulls)
{
- TupleDesc tupdesc = rel->rd_att;
const int16 *attnums;
int i;
bool isnull;
@@ -2505,8 +2527,7 @@ ri_ExtractValues(Relation rel, HeapTuple tup,
for (i = 0; i < riinfo->nkeys; i++)
{
- vals[i] = heap_getattr(tup, attnums[i], tupdesc,
- &isnull);
+ vals[i] = slot_getattr(slot, attnums[i], &isnull);
nulls[i] = isnull ? 'n' : ' ';
}
}
@@ -2523,7 +2544,7 @@ ri_ExtractValues(Relation rel, HeapTuple tup,
static void
ri_ReportViolation(const RI_ConstraintInfo *riinfo,
Relation pk_rel, Relation fk_rel,
- HeapTuple violator, TupleDesc tupdesc,
+ TupleTableSlot *violatorslot, TupleDesc tupdesc,
int queryno)
{
StringInfoData key_names;
@@ -2598,12 +2619,24 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo,
for (idx = 0; idx < riinfo->nkeys; idx++)
{
int fnum = attnums[idx];
+ Form_pg_attribute att = TupleDescAttr(tupdesc, fnum - 1);
char *name,
*val;
+ Datum datum;
+ bool isnull;
- name = SPI_fname(tupdesc, fnum);
- val = SPI_getvalue(violator, tupdesc, fnum);
- if (!val)
+ name = NameStr(att->attname);
+
+ datum = slot_getattr(violatorslot, fnum, &isnull);
+ if (!isnull)
+ {
+ Oid foutoid;
+ bool typisvarlena;
+
+ getTypeOutputInfo(att->atttypid, &foutoid, &typisvarlena);
+ val = OidOutputFunctionCall(foutoid, datum);
+ }
+ else
val = "null";
if (idx > 0)
@@ -2656,7 +2689,7 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo,
*/
static int
ri_NullCheck(TupleDesc tupDesc,
- HeapTuple tup,
+ TupleTableSlot *slot,
const RI_ConstraintInfo *riinfo, bool rel_is_pk)
{
const int16 *attnums;
@@ -2671,7 +2704,7 @@ ri_NullCheck(TupleDesc tupDesc,
for (i = 0; i < riinfo->nkeys; i++)
{
- if (heap_attisnull(tup, attnums[i], tupDesc))
+ if (slot_attisnull(slot, attnums[i]))
nonenull = false;
else
allnull = false;
@@ -2822,10 +2855,9 @@ ri_HashPreparedPlan(RI_QueryKey *key, SPIPlanPtr plan)
* ----------
*/
static bool
-ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
+ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot,
const RI_ConstraintInfo *riinfo, bool rel_is_pk)
{
- TupleDesc tupdesc = RelationGetDescr(rel);
const int16 *attnums;
const Oid *eq_oprs;
int i;
@@ -2841,6 +2873,7 @@ ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
eq_oprs = riinfo->ff_eq_oprs;
}
+ /* XXX: could be worthwhile to fetch all necessary attrs at once */
for (i = 0; i < riinfo->nkeys; i++)
{
Datum oldvalue;
@@ -2850,14 +2883,14 @@ ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
/*
* Get one attribute's oldvalue. If it is NULL - they're not equal.
*/
- oldvalue = heap_getattr(oldtup, attnums[i], tupdesc, &isnull);
+ oldvalue = slot_getattr(oldslot, attnums[i], &isnull);
if (isnull)
return false;
/*
* Get one attribute's newvalue. If it is NULL - they're not equal.
*/
- newvalue = heap_getattr(newtup, attnums[i], tupdesc, &isnull);
+ newvalue = slot_getattr(newslot, attnums[i], &isnull);
if (isnull)
return false;