@@ -303,60 +303,6 @@ RI_FKey_check(TriggerData *trigdata)
303303fk_rel = trigdata -> tg_relation ;
304304pk_rel = heap_open (riinfo -> pk_relid ,RowShareLock );
305305
306- /* ----------
307- * SQL:2008 4.17.3 <Table constraints>
308- *If Rf and Rt are empty (no columns to compare given)
309- *constraint is true if 0 < (SELECT COUNT(*) FROM T)
310- *
311- *Note: The special case that no columns are given cannot
312- *occur at present in Postgres (and is disallowed by the
313- *standard too); it's just there for future enhancements.
314- * ----------
315- */
316- if (riinfo -> nkeys == 0 )
317- {
318- if (SPI_connect ()!= SPI_OK_CONNECT )
319- elog (ERROR ,"SPI_connect failed" );
320-
321- ri_BuildQueryKey (& qkey ,riinfo ,RI_PLAN_CHECK_LOOKUPPK );
322-
323- if ((qplan = ri_FetchPreparedPlan (& qkey ))== NULL )
324- {
325- char querystr [MAX_QUOTED_REL_NAME_LEN + 100 ];
326- char pkrelname [MAX_QUOTED_REL_NAME_LEN ];
327-
328- /* ---------
329- * The query string built is
330- *SELECT 1 FROM ONLY <pktable>
331- * ----------
332- */
333- quoteRelationName (pkrelname ,pk_rel );
334- snprintf (querystr ,sizeof (querystr ),
335- "SELECT 1 FROM ONLY %s x FOR SHARE OF x" ,
336- pkrelname );
337-
338- /* Prepare and save the plan */
339- qplan = ri_PlanCheck (querystr ,0 ,NULL ,
340- & qkey ,fk_rel ,pk_rel , true);
341- }
342-
343- /*
344- * Execute the plan
345- */
346- ri_PerformCheck (riinfo ,& qkey ,qplan ,
347- fk_rel ,pk_rel ,
348- NULL ,NULL ,
349- false,
350- SPI_OK_SELECT );
351-
352- if (SPI_finish ()!= SPI_OK_FINISH )
353- elog (ERROR ,"SPI_finish failed" );
354-
355- heap_close (pk_rel ,RowShareLock );
356-
357- return PointerGetDatum (NULL );
358- }
359-
360306if (riinfo -> confmatchtype == FKCONSTR_MATCH_PARTIAL )
361307ereport (ERROR ,
362308(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
@@ -704,12 +650,6 @@ ri_restrict_del(TriggerData *trigdata, bool is_no_action)
704650riinfo = ri_FetchConstraintInfo (trigdata -> tg_trigger ,
705651trigdata -> tg_relation , true);
706652
707- /*
708- * Nothing to do if no column names to compare given
709- */
710- if (riinfo -> nkeys == 0 )
711- return PointerGetDatum (NULL );
712-
713653/*
714654 * Get the relation descriptors of the FK and PK tables and the old tuple.
715655 *
@@ -922,12 +862,6 @@ ri_restrict_upd(TriggerData *trigdata, bool is_no_action)
922862riinfo = ri_FetchConstraintInfo (trigdata -> tg_trigger ,
923863trigdata -> tg_relation , true);
924864
925- /*
926- * Nothing to do if no column names to compare given
927- */
928- if (riinfo -> nkeys == 0 )
929- return PointerGetDatum (NULL );
930-
931865/*
932866 * Get the relation descriptors of the FK and PK tables and the new and
933867 * old tuple.
@@ -1109,12 +1043,6 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
11091043riinfo = ri_FetchConstraintInfo (trigdata -> tg_trigger ,
11101044trigdata -> tg_relation , true);
11111045
1112- /*
1113- * Nothing to do if no column names to compare given
1114- */
1115- if (riinfo -> nkeys == 0 )
1116- return PointerGetDatum (NULL );
1117-
11181046/*
11191047 * Get the relation descriptors of the FK and PK tables and the old tuple.
11201048 *
@@ -1273,12 +1201,6 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
12731201riinfo = ri_FetchConstraintInfo (trigdata -> tg_trigger ,
12741202trigdata -> tg_relation , true);
12751203
1276- /*
1277- * Nothing to do if no column names to compare given
1278- */
1279- if (riinfo -> nkeys == 0 )
1280- return PointerGetDatum (NULL );
1281-
12821204/*
12831205 * Get the relation descriptors of the FK and PK tables and the new and
12841206 * old tuple.
@@ -1458,12 +1380,6 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
14581380riinfo = ri_FetchConstraintInfo (trigdata -> tg_trigger ,
14591381trigdata -> tg_relation , true);
14601382
1461- /*
1462- * Nothing to do if no column names to compare given
1463- */
1464- if (riinfo -> nkeys == 0 )
1465- return PointerGetDatum (NULL );
1466-
14671383/*
14681384 * Get the relation descriptors of the FK and PK tables and the old tuple.
14691385 *
@@ -1630,12 +1546,6 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
16301546riinfo = ri_FetchConstraintInfo (trigdata -> tg_trigger ,
16311547trigdata -> tg_relation , true);
16321548
1633- /*
1634- * Nothing to do if no column names to compare given
1635- */
1636- if (riinfo -> nkeys == 0 )
1637- return PointerGetDatum (NULL );
1638-
16391549/*
16401550 * Get the relation descriptors of the FK and PK tables and the old tuple.
16411551 *
@@ -1810,12 +1720,6 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
18101720riinfo = ri_FetchConstraintInfo (trigdata -> tg_trigger ,
18111721trigdata -> tg_relation , true);
18121722
1813- /*
1814- * Nothing to do if no column names to compare given
1815- */
1816- if (riinfo -> nkeys == 0 )
1817- return PointerGetDatum (NULL );
1818-
18191723/*
18201724 * Get the relation descriptors of the FK and PK tables and the old tuple.
18211725 *
@@ -1997,12 +1901,6 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
19971901riinfo = ri_FetchConstraintInfo (trigdata -> tg_trigger ,
19981902trigdata -> tg_relation , true);
19991903
2000- /*
2001- * Nothing to do if no column names to compare given
2002- */
2003- if (riinfo -> nkeys == 0 )
2004- return PointerGetDatum (NULL );
2005-
20061904/*
20071905 * Get the relation descriptors of the FK and PK tables and the old tuple.
20081906 *
@@ -2186,13 +2084,6 @@ RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel,
21862084 */
21872085riinfo = ri_FetchConstraintInfo (trigger ,pk_rel , true);
21882086
2189- /*
2190- * Nothing to do if no columns (satisfaction of such a constraint only
2191- * requires existence of a PK row, and this update won't change that).
2192- */
2193- if (riinfo -> nkeys == 0 )
2194- return false;
2195-
21962087switch (riinfo -> confmatchtype )
21972088{
21982089case FKCONSTR_MATCH_SIMPLE :
@@ -2250,13 +2141,6 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
22502141 */
22512142riinfo = ri_FetchConstraintInfo (trigger ,fk_rel , false);
22522143
2253- /*
2254- * Nothing to do if no columns (satisfaction of such a constraint only
2255- * requires existence of a PK row, and this update won't change that).
2256- */
2257- if (riinfo -> nkeys == 0 )
2258- return false;
2259-
22602144switch (riinfo -> confmatchtype )
22612145{
22622146case FKCONSTR_MATCH_SIMPLE :
@@ -2945,13 +2829,13 @@ ri_LoadConstraintInfo(Oid constraintOid)
29452829if (isNull )
29462830elog (ERROR ,"null conkey for constraint %u" ,constraintOid );
29472831arr = DatumGetArrayTypeP (adatum );/* ensure not toasted */
2948- numkeys = ARR_DIMS (arr )[0 ];
29492832if (ARR_NDIM (arr )!= 1 ||
2950- numkeys < 0 ||
2951- numkeys > RI_MAX_NUMKEYS ||
29522833ARR_HASNULL (arr )||
29532834ARR_ELEMTYPE (arr )!= INT2OID )
29542835elog (ERROR ,"conkey is not a 1-D smallint array" );
2836+ numkeys = ARR_DIMS (arr )[0 ];
2837+ if (numkeys <=0 || numkeys > RI_MAX_NUMKEYS )
2838+ elog (ERROR ,"foreign key constraint cannot have %d columns" ,numkeys );
29552839riinfo -> nkeys = numkeys ;
29562840memcpy (riinfo -> fk_attnums ,ARR_DATA_PTR (arr ),numkeys * sizeof (int16 ));
29572841if ((Pointer )arr != DatumGetPointer (adatum ))
@@ -2962,10 +2846,8 @@ ri_LoadConstraintInfo(Oid constraintOid)
29622846if (isNull )
29632847elog (ERROR ,"null confkey for constraint %u" ,constraintOid );
29642848arr = DatumGetArrayTypeP (adatum );/* ensure not toasted */
2965- numkeys = ARR_DIMS (arr )[0 ];
29662849if (ARR_NDIM (arr )!= 1 ||
2967- numkeys != riinfo -> nkeys ||
2968- numkeys > RI_MAX_NUMKEYS ||
2850+ ARR_DIMS (arr )[0 ]!= numkeys ||
29692851ARR_HASNULL (arr )||
29702852ARR_ELEMTYPE (arr )!= INT2OID )
29712853elog (ERROR ,"confkey is not a 1-D smallint array" );
@@ -2978,11 +2860,9 @@ ri_LoadConstraintInfo(Oid constraintOid)
29782860if (isNull )
29792861elog (ERROR ,"null conpfeqop for constraint %u" ,constraintOid );
29802862arr = DatumGetArrayTypeP (adatum );/* ensure not toasted */
2981- numkeys = ARR_DIMS (arr )[0 ];
29822863/* see TryReuseForeignKey if you change the test below */
29832864if (ARR_NDIM (arr )!= 1 ||
2984- numkeys != riinfo -> nkeys ||
2985- numkeys > RI_MAX_NUMKEYS ||
2865+ ARR_DIMS (arr )[0 ]!= numkeys ||
29862866ARR_HASNULL (arr )||
29872867ARR_ELEMTYPE (arr )!= OIDOID )
29882868elog (ERROR ,"conpfeqop is not a 1-D Oid array" );
@@ -2995,10 +2875,8 @@ ri_LoadConstraintInfo(Oid constraintOid)
29952875if (isNull )
29962876elog (ERROR ,"null conppeqop for constraint %u" ,constraintOid );
29972877arr = DatumGetArrayTypeP (adatum );/* ensure not toasted */
2998- numkeys = ARR_DIMS (arr )[0 ];
29992878if (ARR_NDIM (arr )!= 1 ||
3000- numkeys != riinfo -> nkeys ||
3001- numkeys > RI_MAX_NUMKEYS ||
2879+ ARR_DIMS (arr )[0 ]!= numkeys ||
30022880ARR_HASNULL (arr )||
30032881ARR_ELEMTYPE (arr )!= OIDOID )
30042882elog (ERROR ,"conppeqop is not a 1-D Oid array" );
@@ -3011,10 +2889,8 @@ ri_LoadConstraintInfo(Oid constraintOid)
30112889if (isNull )
30122890elog (ERROR ,"null conffeqop for constraint %u" ,constraintOid );
30132891arr = DatumGetArrayTypeP (adatum );/* ensure not toasted */
3014- numkeys = ARR_DIMS (arr )[0 ];
30152892if (ARR_NDIM (arr )!= 1 ||
3016- numkeys != riinfo -> nkeys ||
3017- numkeys > RI_MAX_NUMKEYS ||
2893+ ARR_DIMS (arr )[0 ]!= numkeys ||
30182894ARR_HASNULL (arr )||
30192895ARR_ELEMTYPE (arr )!= OIDOID )
30202896elog (ERROR ,"conffeqop is not a 1-D Oid array" );
@@ -3311,22 +3187,6 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo,
33113187tupdesc = pk_rel -> rd_att ;
33123188}
33133189
3314- /*
3315- * Special case - if there are no keys at all, this is a 'no column'
3316- * constraint - no need to try to extract the values, and the message in
3317- * this case looks different.
3318- */
3319- if (riinfo -> nkeys == 0 )
3320- {
3321- ereport (ERROR ,
3322- (errcode (ERRCODE_FOREIGN_KEY_VIOLATION ),
3323- errmsg ("insert or update on table \"%s\" violates foreign key constraint \"%s\"" ,
3324- RelationGetRelationName (fk_rel ),
3325- NameStr (riinfo -> conname )),
3326- errdetail ("No rows were found in \"%s\"." ,
3327- RelationGetRelationName (pk_rel ))));
3328- }
3329-
33303190/* Get printable versions of the keys involved */
33313191initStringInfo (& key_names );
33323192initStringInfo (& key_values );