@ -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 , Heap Tuple tup ,
static int ri_NullCheck ( TupleDesc tupdesc , TupleTableSlot * slo t,
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 , Heap Tuple oldtup , Heap Tuple newtup ,
static bool ri_KeysEqual ( Relation rel , TupleTableSlot * oldslo t , TupleTableSlot * newslo t ,
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 , Heap Tuple tup ,
static void ri_ExtractValues ( Relation rel , TupleTableSlot * slo t,
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 ,
Heap Tuple 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_trigslo t ;
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_trigslo t ;
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_newslo t ;
old_slot = trigdata - > tg_trigslo t ;
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_trigslo t ;
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_trigslo t ;
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 , slo t, & 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 ,
slo t, 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 ,
Heap Tuple old_tuple , Heap Tuple new_tuple ,
TupleTableSlot * old_slo t , TupleTableSlot * new_slo t ,
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_slo t )
{
ri_ExtractValues ( source_rel , new_tuple , riinfo , source_is_pk ,
ri_ExtractValues ( source_rel , new_slo t , riinfo , source_is_pk ,
vals , nulls ) ;
if ( old_tuple )
ri_ExtractValues ( source_rel , old_tuple , riinfo , source_is_pk ,
if ( old_slo t )
ri_ExtractValues ( source_rel , old_slo t , 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_slo t , 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_slo t ? new_slo t : old_slo t ,
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 , Heap Tuple tup ,
ri_ExtractValues ( Relation rel , TupleTableSlot * slo t,
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 ,
Heap Tuple 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 ,
Heap Tuple tup ,
TupleTableSlot * slo t,
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( slo t, attnums [ i ] ) )
nonenull = false ;
else
allnull = false ;
@ -2822,10 +2855,9 @@ ri_HashPreparedPlan(RI_QueryKey *key, SPIPlanPtr plan)
* - - - - - - - - - -
*/
static bool
ri_KeysEqual ( Relation rel , Heap Tuple oldtup , Heap Tuple newtup ,
ri_KeysEqual ( Relation rel , TupleTableSlot * oldslo t , TupleTableSlot * newslo t ,
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( oldslo t , 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( newslo t , attnums [ i ] , & isnull ) ;
if ( isnull )
return false ;