Error message editing for foreign-key triggers.
authorTom Lane
Tue, 22 Jul 2003 22:14:57 +0000 (22:14 +0000)
committerTom Lane
Tue, 22 Jul 2003 22:14:57 +0000 (22:14 +0000)
src/backend/utils/adt/ri_triggers.c
src/include/utils/elog.h
src/test/regress/expected/alter_table.out
src/test/regress/expected/cluster.out
src/test/regress/expected/foreign_key.out

index b940315bbf18c794866fba88f4f2bf3ea995c68b..ed95d8ed6c444a4af6ba4cc1da5a7fdbeea80f52 100644 (file)
@@ -17,7 +17,7 @@
  *
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.51 2003/06/11 15:02:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.52 2003/07/22 22:14:57 tgl Exp $
  *
  * ----------
  */
@@ -204,16 +204,8 @@ RI_FKey_check(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_check", RI_TRIGTYPE_INUP);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_check()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_check()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Get the relation descriptors of the FK and PK tables and the new
@@ -221,16 +213,7 @@ RI_FKey_check(PG_FUNCTION_ARGS)
     *
     * pk_rel is opened in RowShareLock mode since that's what our eventual
     * SELECT FOR UPDATE will get on it.
-    *
-    * Error check here is needed because of ancient pg_dump bug; see notes
-    * in CreateTrigger().
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    pk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock);
    fk_rel = trigdata->tg_relation;
    if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
@@ -277,7 +260,7 @@ RI_FKey_check(PG_FUNCTION_ARGS)
                             tgnargs, tgargs);
 
        if (SPI_connect() != SPI_OK_CONNECT)
-           elog(ERROR, "SPI_connect() failed in RI_FKey_check()");
+           elog(ERROR, "SPI_connect failed");
 
        if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
        {
@@ -308,7 +291,7 @@ RI_FKey_check(PG_FUNCTION_ARGS)
                        tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
        if (SPI_finish() != SPI_OK_FINISH)
-           elog(ERROR, "SPI_finish() failed in RI_FKey_check()");
+           elog(ERROR, "SPI_finish failed");
 
        heap_close(pk_rel, RowShareLock);
 
@@ -319,10 +302,9 @@ RI_FKey_check(PG_FUNCTION_ARGS)
    match_type = ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]);
 
    if (match_type == RI_MATCH_TYPE_PARTIAL)
-   {
-       elog(ERROR, "MATCH PARTIAL not yet supported");
-       return PointerGetDatum(NULL);
-   }
+       ereport(ERROR,
+               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                errmsg("MATCH PARTIAL not yet implemented")));
 
    ri_BuildQueryKeyFull(&qkey, trigdata->tg_trigger->tgoid,
                         RI_PLAN_CHECK_LOOKUPPK, fk_rel, pk_rel,
@@ -356,10 +338,12 @@ RI_FKey_check(PG_FUNCTION_ARGS)
                     * Not allowed - MATCH FULL says either all or none of
                     * the attributes can be NULLs
                     */
-                   elog(ERROR, "%s referential integrity violation - "
-                        "MATCH FULL doesn't allow mixing of NULL "
-                        "and NON-NULL key values",
-                        tgargs[RI_CONSTRAINT_NAME_ARGNO]);
+                   ereport(ERROR,
+                           (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
+                            errmsg("insert or update on \"%s\" violates foreign key constraint \"%s\"",
+                                   RelationGetRelationName(trigdata->tg_relation),
+                                   tgargs[RI_CONSTRAINT_NAME_ARGNO]),
+                            errdetail("MATCH FULL does not allow mixing of NULL and non-NULL key values.")));
                    heap_close(pk_rel, RowShareLock);
                    return PointerGetDatum(NULL);
 
@@ -380,7 +364,9 @@ RI_FKey_check(PG_FUNCTION_ARGS)
                     * query below to only include non-null columns, or by
                     * writing a special version here)
                     */
-                   elog(ERROR, "MATCH PARTIAL not yet implemented");
+                   ereport(ERROR,
+                           (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                            errmsg("MATCH PARTIAL not yet implemented")));
                    heap_close(pk_rel, RowShareLock);
                    return PointerGetDatum(NULL);
            }
@@ -409,7 +395,7 @@ RI_FKey_check(PG_FUNCTION_ARGS)
    }
 
    if (SPI_connect() != SPI_OK_CONNECT)
-       elog(ERROR, "SPI_connect() failed in RI_FKey_check()");
+       elog(ERROR, "SPI_connect failed");
 
    /*
     * Fetch or prepare a saved plan for the real check
@@ -462,7 +448,7 @@ RI_FKey_check(PG_FUNCTION_ARGS)
                    tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
    if (SPI_finish() != SPI_OK_FINISH)
-       elog(ERROR, "SPI_finish() failed in RI_FKey_check()");
+       elog(ERROR, "SPI_finish failed");
 
    heap_close(pk_rel, RowShareLock);
 
@@ -554,7 +540,9 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
                     * query below to only include non-null columns, or by
                     * writing a special version here)
                     */
-                   elog(ERROR, "MATCH PARTIAL not yet implemented");
+                   ereport(ERROR,
+                           (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                            errmsg("MATCH PARTIAL not yet implemented")));
                    break;
            }
 
@@ -568,7 +556,7 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
    }
 
    if (SPI_connect() != SPI_OK_CONNECT)
-       elog(ERROR, "SPI_connect() failed in RI_FKey_check()");
+       elog(ERROR, "SPI_connect failed");
 
    /*
     * Fetch or prepare a saved plan for the real check
@@ -620,7 +608,7 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
                             SPI_OK_SELECT, NULL);
 
    if (SPI_finish() != SPI_OK_FINISH)
-       elog(ERROR, "SPI_finish() failed in ri_Check_Pk_Match()");
+       elog(ERROR, "SPI_finish failed");
 
    return result;
 }
@@ -656,16 +644,8 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_noaction_del", RI_TRIGTYPE_DELETE);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_noaction_del()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_noaction_del()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Nothing to do if no column names to compare given
@@ -680,12 +660,6 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
     * fk_rel is opened in RowShareLock mode since that's what our eventual
     * SELECT FOR UPDATE will get on it.
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock);
    pk_rel = trigdata->tg_relation;
    old_row = trigdata->tg_trigtuple;
@@ -740,7 +714,7 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
            }
 
            if (SPI_connect() != SPI_OK_CONNECT)
-               elog(ERROR, "SPI_connect() failed in RI_FKey_noaction_del()");
+               elog(ERROR, "SPI_connect failed");
 
            /*
             * Fetch or prepare a saved plan for the restrict delete
@@ -794,7 +768,7 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
                            tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
            if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish() failed in RI_FKey_noaction_del()");
+               elog(ERROR, "SPI_finish failed");
 
            heap_close(fk_rel, RowShareLock);
 
@@ -804,14 +778,16 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
             * Handle MATCH PARTIAL restrict delete.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            return PointerGetDatum(NULL);
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #2 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return PointerGetDatum(NULL);
 }
 
@@ -847,16 +823,8 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_noaction_upd", RI_TRIGTYPE_UPDATE);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_noaction_upd()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_noaction_upd()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Nothing to do if no column names to compare given
@@ -871,12 +839,6 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
     * fk_rel is opened in RowShareLock mode since that's what our eventual
     * SELECT FOR UPDATE will get on it.
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock);
    pk_rel = trigdata->tg_relation;
    new_row = trigdata->tg_newtuple;
@@ -943,7 +905,7 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
            }
 
            if (SPI_connect() != SPI_OK_CONNECT)
-               elog(ERROR, "SPI_connect() failed in RI_FKey_noaction_upd()");
+               elog(ERROR, "SPI_connect failed");
 
            /*
             * Fetch or prepare a saved plan for the noaction update
@@ -997,7 +959,7 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
                            tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
            if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish() failed in RI_FKey_noaction_upd()");
+               elog(ERROR, "SPI_finish failed");
 
            heap_close(fk_rel, RowShareLock);
 
@@ -1007,14 +969,16 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
             * Handle MATCH PARTIAL noaction update.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            return PointerGetDatum(NULL);
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #3 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return PointerGetDatum(NULL);
 }
 
@@ -1046,16 +1010,8 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_cascade_del", RI_TRIGTYPE_DELETE);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_cascade_del()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_cascade_del()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Nothing to do if no column names to compare given
@@ -1070,12 +1026,6 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
     * fk_rel is opened in RowExclusiveLock mode since that's what our
     * eventual DELETE will get on it.
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
    pk_rel = trigdata->tg_relation;
    old_row = trigdata->tg_trigtuple;
@@ -1117,7 +1067,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
            }
 
            if (SPI_connect() != SPI_OK_CONNECT)
-               elog(ERROR, "SPI_connect() failed in RI_FKey_cascade_del()");
+               elog(ERROR, "SPI_connect failed");
 
            /*
             * Fetch or prepare a saved plan for the cascaded delete
@@ -1171,7 +1121,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
                            tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
            if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish() failed in RI_FKey_cascade_del()");
+               elog(ERROR, "SPI_finish failed");
 
            heap_close(fk_rel, RowExclusiveLock);
 
@@ -1181,14 +1131,16 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
             * Handle MATCH PARTIAL cascaded delete.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            return PointerGetDatum(NULL);
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #4 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return PointerGetDatum(NULL);
 }
 
@@ -1222,16 +1174,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_cascade_upd", RI_TRIGTYPE_UPDATE);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_cascade_upd()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_cascade_upd()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Nothing to do if no column names to compare given
@@ -1246,12 +1190,6 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
     * fk_rel is opened in RowExclusiveLock mode since that's what our
     * eventual UPDATE will get on it.
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
    pk_rel = trigdata->tg_relation;
    new_row = trigdata->tg_newtuple;
@@ -1304,7 +1242,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
            }
 
            if (SPI_connect() != SPI_OK_CONNECT)
-               elog(ERROR, "SPI_connect() failed in RI_FKey_cascade_upd()");
+               elog(ERROR, "SPI_connect failed");
 
            /*
             * Fetch or prepare a saved plan for the cascaded update of
@@ -1367,7 +1305,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
                            tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
            if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish() failed in RI_FKey_cascade_upd()");
+               elog(ERROR, "SPI_finish failed");
 
            heap_close(fk_rel, RowExclusiveLock);
 
@@ -1377,14 +1315,16 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
             * Handle MATCH PARTIAL cascade update.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            return PointerGetDatum(NULL);
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #5 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return PointerGetDatum(NULL);
 }
 
@@ -1423,16 +1363,8 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_restrict_del", RI_TRIGTYPE_DELETE);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_restrict_del()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_restrict_del()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Nothing to do if no column names to compare given
@@ -1447,12 +1379,6 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
     * fk_rel is opened in RowShareLock mode since that's what our eventual
     * SELECT FOR UPDATE will get on it.
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock);
    pk_rel = trigdata->tg_relation;
    old_row = trigdata->tg_trigtuple;
@@ -1494,7 +1420,7 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
            }
 
            if (SPI_connect() != SPI_OK_CONNECT)
-               elog(ERROR, "SPI_connect() failed in RI_FKey_restrict_del()");
+               elog(ERROR, "SPI_connect failed");
 
            /*
             * Fetch or prepare a saved plan for the restrict delete
@@ -1548,7 +1474,7 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
                            tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
            if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish() failed in RI_FKey_restrict_del()");
+               elog(ERROR, "SPI_finish failed");
 
            heap_close(fk_rel, RowShareLock);
 
@@ -1558,14 +1484,16 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
             * Handle MATCH PARTIAL restrict delete.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            return PointerGetDatum(NULL);
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #6 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return PointerGetDatum(NULL);
 }
 
@@ -1605,16 +1533,8 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_restrict_upd", RI_TRIGTYPE_UPDATE);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_restrict_upd()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_restrict_upd()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Nothing to do if no column names to compare given
@@ -1629,12 +1549,6 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
     * fk_rel is opened in RowShareLock mode since that's what our eventual
     * SELECT FOR UPDATE will get on it.
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock);
    pk_rel = trigdata->tg_relation;
    new_row = trigdata->tg_newtuple;
@@ -1687,7 +1601,7 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
            }
 
            if (SPI_connect() != SPI_OK_CONNECT)
-               elog(ERROR, "SPI_connect() failed in RI_FKey_restrict_upd()");
+               elog(ERROR, "SPI_connect failed");
 
            /*
             * Fetch or prepare a saved plan for the restrict update
@@ -1741,7 +1655,7 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
                            tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
            if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish() failed in RI_FKey_restrict_upd()");
+               elog(ERROR, "SPI_finish failed");
 
            heap_close(fk_rel, RowShareLock);
 
@@ -1751,14 +1665,16 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
             * Handle MATCH PARTIAL restrict update.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            return PointerGetDatum(NULL);
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #7 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return PointerGetDatum(NULL);
 }
 
@@ -1790,16 +1706,8 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_setnull_del", RI_TRIGTYPE_DELETE);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_setnull_del()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_setnull_del()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Nothing to do if no column names to compare given
@@ -1814,12 +1722,6 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
     * fk_rel is opened in RowExclusiveLock mode since that's what our
     * eventual UPDATE will get on it.
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
    pk_rel = trigdata->tg_relation;
    old_row = trigdata->tg_trigtuple;
@@ -1861,7 +1763,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
            }
 
            if (SPI_connect() != SPI_OK_CONNECT)
-               elog(ERROR, "SPI_connect() failed in RI_FKey_setnull_del()");
+               elog(ERROR, "SPI_connect failed");
 
            /*
             * Fetch or prepare a saved plan for the set null delete
@@ -1923,7 +1825,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
                            tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
            if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish() failed in RI_FKey_setnull_del()");
+               elog(ERROR, "SPI_finish failed");
 
            heap_close(fk_rel, RowExclusiveLock);
 
@@ -1933,14 +1835,16 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
             * Handle MATCH PARTIAL set null delete.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            return PointerGetDatum(NULL);
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #8 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return PointerGetDatum(NULL);
 }
 
@@ -1975,16 +1879,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_setnull_upd", RI_TRIGTYPE_UPDATE);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_setnull_upd()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_setnull_upd()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Nothing to do if no column names to compare given
@@ -1999,12 +1895,6 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
     * fk_rel is opened in RowExclusiveLock mode since that's what our
     * eventual UPDATE will get on it.
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
    pk_rel = trigdata->tg_relation;
    new_row = trigdata->tg_newtuple;
@@ -2058,7 +1948,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
            }
 
            if (SPI_connect() != SPI_OK_CONNECT)
-               elog(ERROR, "SPI_connect() failed in RI_FKey_setnull_upd()");
+               elog(ERROR, "SPI_connect failed");
 
            /*
             * "MATCH " only changes columns corresponding to
@@ -2153,7 +2043,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
                            tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
            if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish() failed in RI_FKey_setnull_upd()");
+               elog(ERROR, "SPI_finish failed");
 
            heap_close(fk_rel, RowExclusiveLock);
 
@@ -2163,14 +2053,16 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
             * Handle MATCH PARTIAL set null update.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            return PointerGetDatum(NULL);
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #9 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return PointerGetDatum(NULL);
 }
 
@@ -2201,16 +2093,8 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_del", RI_TRIGTYPE_DELETE);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_setdefault_del()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_setdefault_del()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Nothing to do if no column names to compare given
@@ -2225,12 +2109,6 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
     * fk_rel is opened in RowExclusiveLock mode since that's what our
     * eventual UPDATE will get on it.
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
    pk_rel = trigdata->tg_relation;
    old_row = trigdata->tg_trigtuple;
@@ -2272,7 +2150,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
            }
 
            if (SPI_connect() != SPI_OK_CONNECT)
-               elog(ERROR, "SPI_connect() failed in RI_FKey_setdefault_del()");
+               elog(ERROR, "SPI_connect failed");
 
            /*
             * Prepare a plan for the set default delete operation.
@@ -2365,7 +2243,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
                            tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
            if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish() failed in RI_FKey_setdefault_del()");
+               elog(ERROR, "SPI_finish failed");
 
            heap_close(fk_rel, RowExclusiveLock);
 
@@ -2385,14 +2263,16 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
             * Handle MATCH PARTIAL set null delete.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            return PointerGetDatum(NULL);
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #10 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return PointerGetDatum(NULL);
 }
 
@@ -2425,16 +2305,8 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
     */
    ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_upd", RI_TRIGTYPE_UPDATE);
 
-   /*
-    * Check for the correct # of call arguments
-    */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_setdefault_upd()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_setdefault_upd()",
-            RI_MAX_NUMKEYS);
 
    /*
     * Nothing to do if no column names to compare given
@@ -2449,12 +2321,6 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
     * fk_rel is opened in RowExclusiveLock mode since that's what our
     * eventual UPDATE will get on it.
     */
-   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
-
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
    pk_rel = trigdata->tg_relation;
    new_row = trigdata->tg_newtuple;
@@ -2509,7 +2375,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
            }
 
            if (SPI_connect() != SPI_OK_CONNECT)
-               elog(ERROR, "SPI_connect() failed in RI_FKey_setdefault_upd()");
+               elog(ERROR, "SPI_connect failed");
 
            /*
             * Prepare a plan for the set default delete operation.
@@ -2612,7 +2478,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
                            tgargs[RI_CONSTRAINT_NAME_ARGNO]);
 
            if (SPI_finish() != SPI_OK_FINISH)
-               elog(ERROR, "SPI_finish() failed in RI_FKey_setdefault_upd()");
+               elog(ERROR, "SPI_finish failed");
 
            heap_close(fk_rel, RowExclusiveLock);
 
@@ -2632,14 +2498,16 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
             * Handle MATCH PARTIAL set null delete.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            return PointerGetDatum(NULL);
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #11 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return PointerGetDatum(NULL);
 }
 
@@ -2669,11 +2537,13 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
     */
    tgnargs = trigdata->tg_trigger->tgnargs;
    tgargs = trigdata->tg_trigger->tgargs;
-   if (tgnargs < 4 || (tgnargs % 2) != 0)
-       elog(ERROR, "wrong # of arguments in call to RI_FKey_keyequal_upd()");
-   if (tgnargs > RI_MAX_ARGUMENTS)
-       elog(ERROR, "too many keys (%d max) in call to RI_FKey_keyequal_upd()",
-            RI_MAX_NUMKEYS);
+   if (tgnargs < 4 ||
+       tgnargs > RI_MAX_ARGUMENTS ||
+       (tgnargs % 2) != 0)
+       ereport(ERROR,
+               (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
+                errmsg("%s() called with wrong number of trigger arguments",
+                       "RI_FKey_keyequal_upd")));
 
    /*
     * Nothing to do if no column names to compare given
@@ -2688,10 +2558,12 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
     * Use minimal locking for fk_rel here.
     */
    if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
-       elog(ERROR, "No target table given for trigger \"%s\" on \"%s\""
-            "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT",
-            trigdata->tg_trigger->tgname,
-            RelationGetRelationName(trigdata->tg_relation));
+       ereport(ERROR,
+               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                errmsg("no target table given for trigger \"%s\" on \"%s\"",
+                       trigdata->tg_trigger->tgname,
+                       RelationGetRelationName(trigdata->tg_relation)),
+                errhint("Remove this RI trigger and its mates, then do ALTER TABLE ADD CONSTRAINT.")));
 
    fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, AccessShareLock);
    pk_rel = trigdata->tg_relation;
@@ -2722,14 +2594,16 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
             * Handle MATCH PARTIAL set null delete.
             */
        case RI_MATCH_TYPE_PARTIAL:
-           elog(ERROR, "MATCH PARTIAL not yet supported");
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("MATCH PARTIAL not yet implemented")));
            break;
    }
 
    /*
     * Never reached
     */
-   elog(ERROR, "internal error #12 in ri_triggers.c");
+   elog(ERROR, "invalid match_type");
    return false;
 }
 
@@ -2794,7 +2668,7 @@ ri_DetermineMatchType(char *str)
    if (strcmp(str, "PARTIAL") == 0)
        return RI_MATCH_TYPE_PARTIAL;
 
-   elog(ERROR, "unrecognized referential integrity MATCH type '%s'", str);
+   elog(ERROR, "unrecognized referential integrity match type \"%s\"", str);
    return 0;
 }
 
@@ -2844,18 +2718,22 @@ ri_BuildQueryKeyFull(RI_QueryKey *key, Oid constr_id, int32 constr_queryno,
    {
        fno = SPI_fnumber(fk_rel->rd_att, argv[j]);
        if (fno == SPI_ERROR_NOATTRIBUTE)
-           elog(ERROR, "constraint %s: table %s does not have an attribute %s",
-                argv[RI_CONSTRAINT_NAME_ARGNO],
-                RelationGetRelationName(fk_rel),
-                argv[j]);
+           ereport(ERROR,
+                   (errcode(ERRCODE_UNDEFINED_COLUMN),
+                    errmsg("table \"%s\" does not have attribute \"%s\" referenced by constraint \"%s\"",
+                           RelationGetRelationName(fk_rel),
+                           argv[j],
+                           argv[RI_CONSTRAINT_NAME_ARGNO])));
        key->keypair[i][RI_KEYPAIR_FK_IDX] = fno;
 
        fno = SPI_fnumber(pk_rel->rd_att, argv[j + 1]);
        if (fno == SPI_ERROR_NOATTRIBUTE)
-           elog(ERROR, "constraint %s: table %s does not have an attribute %s",
-                argv[RI_CONSTRAINT_NAME_ARGNO],
-                RelationGetRelationName(pk_rel),
-                argv[j + 1]);
+           ereport(ERROR,
+                   (errcode(ERRCODE_UNDEFINED_COLUMN),
+                    errmsg("table \"%s\" does not have attribute \"%s\" referenced by constraint \"%s\"",
+                           RelationGetRelationName(pk_rel),
+                           argv[j + 1],
+                           argv[RI_CONSTRAINT_NAME_ARGNO])));
        key->keypair[i][RI_KEYPAIR_PK_IDX] = fno;
    }
 }
@@ -2867,34 +2745,75 @@ static void
 ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname, int tgkind)
 {
    TriggerData *trigdata = (TriggerData *) fcinfo->context;
+   int         tgnargs;
 
    if (!CALLED_AS_TRIGGER(fcinfo))
-       elog(ERROR, "%s() not fired by trigger manager", funcname);
+       ereport(ERROR,
+               (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
+                errmsg("%s() was not fired by trigger manager", funcname)));
+
+   /*
+    * Check proper event
+    */
    if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
        !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
-       elog(ERROR, "%s() must be fired AFTER ROW", funcname);
+       ereport(ERROR,
+               (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
+                errmsg("%s() must be fired AFTER ROW", funcname)));
 
    switch (tgkind)
    {
        case RI_TRIGTYPE_INSERT:
            if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
-               elog(ERROR, "%s() must be fired for INSERT", funcname);
+               ereport(ERROR,
+                       (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
+                        errmsg("%s() must be fired for INSERT", funcname)));
            break;
        case RI_TRIGTYPE_UPDATE:
            if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
-               elog(ERROR, "%s() must be fired for UPDATE", funcname);
+               ereport(ERROR,
+                       (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
+                        errmsg("%s() must be fired for UPDATE", funcname)));
            break;
        case RI_TRIGTYPE_INUP:
            if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event) &&
                !TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
-               elog(ERROR, "%s() must be fired for INSERT or UPDATE",
-                    funcname);
+               ereport(ERROR,
+                       (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
+                        errmsg("%s() must be fired for INSERT or UPDATE",
+                    funcname)));
            break;
        case RI_TRIGTYPE_DELETE:
            if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
-               elog(ERROR, "%s() must be fired for DELETE", funcname);
+               ereport(ERROR,
+                       (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
+                        errmsg("%s() must be fired for DELETE", funcname)));
            break;
    }
+
+   /*
+    * Check for the correct # of call arguments
+    */
+   tgnargs = trigdata->tg_trigger->tgnargs;
+   if (tgnargs < 4 ||
+       tgnargs > RI_MAX_ARGUMENTS ||
+       (tgnargs % 2) != 0)
+       ereport(ERROR,
+               (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
+                errmsg("%s() called with wrong number of trigger arguments",
+                       funcname)));
+
+   /*
+    * Check that tgconstrrelid is known.  We need to check here because of
+    * ancient pg_dump bug; see notes in CreateTrigger().
+    */
+   if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
+       ereport(ERROR,
+               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                errmsg("no target table given for trigger \"%s\" on \"%s\"",
+                       trigdata->tg_trigger->tgname,
+                       RelationGetRelationName(trigdata->tg_relation)),
+                errhint("Remove this RI trigger and its mates, then do ALTER TABLE ADD CONSTRAINT.")));
 }
 
 
@@ -3025,7 +2944,7 @@ ri_PerformCheck(RI_QueryKey *qkey, void *qplan,
 
    /* Check result */
    if (spi_result < 0)
-       elog(ERROR, "SPI_execp() failed in ri_PerformCheck()");
+       elog(ERROR, "SPI_execp failed");
 
    if (expect_OK >= 0 && spi_result != expect_OK)
        ri_ReportViolation(qkey, constrname ? constrname : "",
@@ -3069,9 +2988,9 @@ ri_ExtractValues(RI_QueryKey *qkey, int key_idx,
  *
  * If the failed constraint was on insert/update to the FK table,
  * we want the key names and values extracted from there, and the error
- * message to look like 'key blah referenced from FK not found in PK'.
+ * message to look like 'key blah is not present in PK'.
  * Otherwise, the attr names and values come from the PK table and the
- * message looks like 'key blah in PK still referenced from FK'.
+ * message looks like 'key blah is still referenced from FK'.
  */
 static void
 ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
@@ -3084,27 +3003,31 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
    char       *name_ptr = key_names;
    char       *val_ptr = key_values;
    bool        onfk;
-   Relation    rel,
-               other_rel;
+   Relation    rel;
    int         idx,
                key_idx;
 
+   if (spi_err)
+       ereport(ERROR,
+               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                errmsg("referential integrity query on \"%s\" from constraint \"%s\" on \"%s\" gave unexpected result",
+                       RelationGetRelationName(pk_rel),
+                       constrname,
+                       RelationGetRelationName(fk_rel)),
+                errhint("This is most likely due to a rule having rewritten the query.")));
+
    /*
-    * rel is set to where the tuple description is coming from, and it also
-    * is the first relation mentioned in the message, other_rel is
-    * respectively the other relation.
+    * rel is set to where the tuple description is coming from.
     */
    onfk = (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK);
    if (onfk)
    {
        rel = fk_rel;
-       other_rel = pk_rel;
        key_idx = RI_KEYPAIR_FK_IDX;
    }
    else
    {
        rel = pk_rel;
-       other_rel = fk_rel;
        key_idx = RI_KEYPAIR_PK_IDX;
    }
 
@@ -3115,14 +3038,12 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
     */
    if (qkey->nkeypairs == 0)
    {
-       if (spi_err)
-           elog(ERROR, "%s referential action on %s from %s rewritten by rule",
-                constrname,
-                RelationGetRelationName(fk_rel),
-                RelationGetRelationName(pk_rel));
-       else
-           elog(ERROR, "%s referential integrity violation - no rows found in %s",
-                constrname, RelationGetRelationName(pk_rel));
+       ereport(ERROR,
+               (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
+                errmsg("insert or update on \"%s\" violates foreign key constraint \"%s\"",
+                       RelationGetRelationName(fk_rel), constrname),
+                errdetail("No rows were found in \"%s\".",
+                          RelationGetRelationName(pk_rel))));
    }
 
    /* Get printable versions of the keys involved */
@@ -3151,24 +3072,25 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
 
        name_ptr += sprintf(name_ptr, "%s%s", idx > 0 ? "," : "", name);
        val_ptr += sprintf(val_ptr, "%s%s", idx > 0 ? "," : "", val);
-  }
-
-  if (spi_err)
-     elog(ERROR, "%s referential action on %s from %s for (%s)=(%s) rewritten by rule",
-          constrname,
-          RelationGetRelationName(fk_rel),
-          RelationGetRelationName(pk_rel),
-          key_names, key_values);
-  else if (onfk)
-     elog(ERROR, "%s referential integrity violation - key (%s)=(%s) referenced from %s not found in %s",
-          constrname, key_names, key_values,
-          RelationGetRelationName(rel),
-          RelationGetRelationName(other_rel));
-  else
-     elog(ERROR, "%s referential integrity violation - key (%s)=(%s) in %s still referenced from %s",
-          constrname, key_names, key_values,
-          RelationGetRelationName(rel),
-          RelationGetRelationName(other_rel));
+   }
+
+   if (onfk)
+     ereport(ERROR,
+             (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
+              errmsg("insert or update on \"%s\" violates foreign key constraint \"%s\"",
+                     RelationGetRelationName(fk_rel), constrname),
+              errdetail("Key (%s)=(%s) is not present in \"%s\".",
+                        key_names, key_values,
+                        RelationGetRelationName(pk_rel))));
+   else
+     ereport(ERROR,
+             (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
+              errmsg("update or delete on \"%s\" violates foreign key constraint \"%s\" on \"%s\"",
+                     RelationGetRelationName(pk_rel),
+                     constrname, RelationGetRelationName(fk_rel)),
+              errdetail("Key (%s)=(%s) is still referenced from \"%s\".",
+                        key_names, key_values,
+                        RelationGetRelationName(fk_rel))));
 }
 
 /* ----------
@@ -3215,10 +3137,12 @@ ri_BuildQueryKeyPkCheck(RI_QueryKey *key, Oid constr_id, int32 constr_queryno,
    {
        fno = SPI_fnumber(pk_rel->rd_att, argv[j]);
        if (fno == SPI_ERROR_NOATTRIBUTE)
-           elog(ERROR, "constraint %s: table %s does not have an attribute %s",
-                argv[RI_CONSTRAINT_NAME_ARGNO],
-                RelationGetRelationName(pk_rel),
-                argv[j + 1]);
+           ereport(ERROR,
+                   (errcode(ERRCODE_UNDEFINED_COLUMN),
+                    errmsg("table \"%s\" does not have attribute \"%s\" referenced by constraint \"%s\"",
+                           RelationGetRelationName(pk_rel),
+                           argv[j],
+                           argv[RI_CONSTRAINT_NAME_ARGNO])));
        key->keypair[i][RI_KEYPAIR_PK_IDX] = fno;
        key->keypair[i][RI_KEYPAIR_FK_IDX] = 0;
    }
@@ -3343,7 +3267,9 @@ ri_HashPreparedPlan(RI_QueryKey *key, void *plan)
                                              (void *) key,
                                              HASH_ENTER, &found);
    if (entry == NULL)
-       elog(ERROR, "out of memory for RI plan cache");
+       ereport(ERROR,
+               (errcode(ERRCODE_OUT_OF_MEMORY),
+                errmsg("out of memory")));
    entry->plan = plan;
 }
 
@@ -3532,7 +3458,7 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
 
        /*
         * Since fmgr_info could fail, call it *before* creating the
-        * hashtable entry --- otherwise we could elog leaving an
+        * hashtable entry --- otherwise we could ereport leaving an
         * incomplete entry in the hashtable.  Also, because this will be
         * a permanent table entry, we must make sure any subsidiary
         * structures of the fmgr record are kept in TopMemoryContext.
@@ -3543,7 +3469,9 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
                                                  (void *) &typeid,
                                                  HASH_ENTER, &found);
        if (entry == NULL)
-           elog(ERROR, "out of memory for RI operator cache");
+           ereport(ERROR,
+                   (errcode(ERRCODE_OUT_OF_MEMORY),
+                    errmsg("out of memory")));
 
        entry->typeid = typeid;
        memcpy(&(entry->oprfmgrinfo), &finfo, sizeof(FmgrInfo));
index 732b0e7cfbd0b643555e9847a31a450b0c973fd1..661187269db555e7fecd592affb59cc5dd9ee6ee 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: elog.h,v 1.54 2003/07/22 19:00:12 tgl Exp $
+ * $Id: elog.h,v 1.55 2003/07/22 22:14:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #define ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION     MAKE_SQLSTATE('2','3', '0','0','0')
 #define ERRCODE_RESTRICT_VIOLATION         MAKE_SQLSTATE('2','3', '0','0','1')
 #define ERRCODE_NOT_NULL_VIOLATION         MAKE_SQLSTATE('2','3', '5','0','2')
-#define ERRCODE_FOREIGN_KEY_VALUE_NOT_FOUND    MAKE_SQLSTATE('2','3', '5','0','3')
+#define ERRCODE_FOREIGN_KEY_VIOLATION      MAKE_SQLSTATE('2','3', '5','0','3')
 #define ERRCODE_UNIQUE_VIOLATION           MAKE_SQLSTATE('2','3', '5','0','5')
 #define ERRCODE_CHECK_VIOLATION                MAKE_SQLSTATE('2','3', '5','1','4')
 
index 677dce17ea5c2fcdcfc03946287048f111b4669c..19e60662c7f1c7446f9d0435c4401f84d84cb4ad 100644 (file)
@@ -316,7 +316,8 @@ ERROR:  column "b" referenced in foreign key constraint does not exist
 -- Try (and fail) to add constraint due to invalid data
 ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full;
 NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
-ERROR:  tmpconstr referential integrity violation - key (a)=(5) referenced from tmp3 not found in tmp2
+ERROR:  insert or update on "tmp3" violates foreign key constraint "tmpconstr"
+DETAIL:  Key (a)=(5) is not present in "tmp2".
 -- Delete failing row
 DELETE FROM tmp3 where a=5;
 -- Try (and succeed)
index 50507fc961a5fd76937f2e87f3fc7443786d0654..9a28df62d10ba65641f1ce536d15125fe8cf37dd 100644 (file)
@@ -248,7 +248,8 @@ SELECT a,b,c,substring(d for 30), length(d) from clstr_tst;
 
 -- Verify that foreign key link still works
 INSERT INTO clstr_tst (b, c) VALUES (1111, 'this should fail');
-ERROR:  clstr_tst_con referential integrity violation - key (b)=(1111) referenced from clstr_tst not found in clstr_tst_s
+ERROR:  insert or update on "clstr_tst" violates foreign key constraint "clstr_tst_con"
+DETAIL:  Key (b)=(1111) is not present in "clstr_tst_s".
 SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass;
     conname     
 ----------------
index 7ac2eb387d30add072aae0818a5e5ab7c2ee6295..cb6fc35eb6d134ad59f3490f3fb67b13e397ce96 100644 (file)
@@ -22,7 +22,8 @@ INSERT INTO FKTABLE VALUES (3, 4);
 INSERT INTO FKTABLE VALUES (NULL, 1);
 -- Insert a failed row into FK TABLE
 INSERT INTO FKTABLE VALUES (100, 2);
-ERROR:  $1 referential integrity violation - key (ftest1)=(100) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "$1"
+DETAIL:  Key (ftest1)=(100) is not present in "pktable".
 -- Check FKTABLE
 SELECT * FROM FKTABLE;
  ftest1 | ftest2 
@@ -80,13 +81,17 @@ INSERT INTO FKTABLE VALUES (3, 6, 12);
 INSERT INTO FKTABLE VALUES (NULL, NULL, 0);
 -- Insert failed rows into FK TABLE
 INSERT INTO FKTABLE VALUES (100, 2, 4);
-ERROR:  constrname referential integrity violation - key (ftest1,ftest2)=(100,2) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname"
+DETAIL:  Key (ftest1,ftest2)=(100,2) is not present in "pktable".
 INSERT INTO FKTABLE VALUES (2, 2, 4);
-ERROR:  constrname referential integrity violation - key (ftest1,ftest2)=(2,2) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname"
+DETAIL:  Key (ftest1,ftest2)=(2,2) is not present in "pktable".
 INSERT INTO FKTABLE VALUES (NULL, 2, 4);
-ERROR:  constrname referential integrity violation - MATCH FULL doesn't allow mixing of NULL and NON-NULL key values
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname"
+DETAIL:  MATCH FULL does not allow mixing of NULL and non-NULL key values.
 INSERT INTO FKTABLE VALUES (1, NULL, 4);
-ERROR:  constrname referential integrity violation - MATCH FULL doesn't allow mixing of NULL and NON-NULL key values
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname"
+DETAIL:  MATCH FULL does not allow mixing of NULL and non-NULL key values.
 -- Check FKTABLE
 SELECT * FROM FKTABLE;
  ftest1 | ftest2 | ftest3 
@@ -165,13 +170,17 @@ INSERT INTO FKTABLE VALUES (3, 6, 12);
 INSERT INTO FKTABLE VALUES (NULL, NULL, 0);
 -- Insert failed rows into FK TABLE
 INSERT INTO FKTABLE VALUES (100, 2, 4);
-ERROR:  constrname2 referential integrity violation - key (ftest1,ftest2)=(100,2) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname2"
+DETAIL:  Key (ftest1,ftest2)=(100,2) is not present in "pktable".
 INSERT INTO FKTABLE VALUES (2, 2, 4);
-ERROR:  constrname2 referential integrity violation - key (ftest1,ftest2)=(2,2) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname2"
+DETAIL:  Key (ftest1,ftest2)=(2,2) is not present in "pktable".
 INSERT INTO FKTABLE VALUES (NULL, 2, 4);
-ERROR:  constrname2 referential integrity violation - MATCH FULL doesn't allow mixing of NULL and NON-NULL key values
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname2"
+DETAIL:  MATCH FULL does not allow mixing of NULL and non-NULL key values.
 INSERT INTO FKTABLE VALUES (1, NULL, 4);
-ERROR:  constrname2 referential integrity violation - MATCH FULL doesn't allow mixing of NULL and NON-NULL key values
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname2"
+DETAIL:  MATCH FULL does not allow mixing of NULL and non-NULL key values.
 -- Check FKTABLE
 SELECT * FROM FKTABLE;
  ftest1 | ftest2 | ftest3 
@@ -250,7 +259,8 @@ INSERT INTO FKTABLE VALUES (3, 4);
 INSERT INTO FKTABLE VALUES (NULL, 1);
 -- Insert a failed row into FK TABLE
 INSERT INTO FKTABLE VALUES (100, 2);
-ERROR:  $1 referential integrity violation - key (ftest1)=(100) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "$1"
+DETAIL:  Key (ftest1)=(100) is not present in "pktable".
 -- Check FKTABLE
 SELECT * FROM FKTABLE;
  ftest1 | ftest2 
@@ -274,7 +284,8 @@ SELECT * FROM PKTABLE;
 
 -- Delete a row from PK TABLE (should fail)
 DELETE FROM PKTABLE WHERE ptest1=1;
-ERROR:  $1 referential integrity violation - key (ptest1)=(1) in pktable still referenced from fktable
+ERROR:  update or delete on "pktable" violates foreign key constraint "$1" on "fktable"
+DETAIL:  Key (ptest1)=(1) is still referenced from "fktable".
 -- Delete a row from PK TABLE (should succeed)
 DELETE FROM PKTABLE WHERE ptest1=5;
 -- Check PKTABLE for deletes
@@ -289,7 +300,8 @@ SELECT * FROM PKTABLE;
 
 -- Update a row from PK TABLE (should fail)
 UPDATE PKTABLE SET ptest1=0 WHERE ptest1=2;
-ERROR:  $1 referential integrity violation - key (ptest1)=(2) in pktable still referenced from fktable
+ERROR:  update or delete on "pktable" violates foreign key constraint "$1" on "fktable"
+DETAIL:  Key (ptest1)=(2) is still referenced from "fktable".
 -- Update a row from PK TABLE (should succeed)
 UPDATE PKTABLE SET ptest1=0 WHERE ptest1=4;
 -- Check PKTABLE for updates
@@ -324,7 +336,8 @@ INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4);
 INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5);
 -- Insert a failed values
 INSERT INTO FKTABLE VALUES (1, 2, 7, 6);
-ERROR:  constrname3 referential integrity violation - key (ftest1,ftest2,ftest3)=(1,2,7) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname3"
+DETAIL:  Key (ftest1,ftest2,ftest3)=(1,2,7) is not present in "pktable".
 -- Show FKTABLE
 SELECT * from FKTABLE;
  ftest1 | ftest2 | ftest3 | ftest4 
@@ -338,12 +351,14 @@ SELECT * from FKTABLE;
 
 -- Try to update something that should fail
 UPDATE PKTABLE set ptest2=5 where ptest2=2;
-ERROR:  constrname3 referential integrity violation - key (ptest1,ptest2,ptest3)=(1,2,3) in pktable still referenced from fktable
+ERROR:  update or delete on "pktable" violates foreign key constraint "constrname3" on "fktable"
+DETAIL:  Key (ptest1,ptest2,ptest3)=(1,2,3) is still referenced from "fktable".
 -- Try to update something that should succeed
 UPDATE PKTABLE set ptest1=1 WHERE ptest2=3;
 -- Try to delete something that should fail
 DELETE FROM PKTABLE where ptest1=1 and ptest2=2 and ptest3=3;
-ERROR:  constrname3 referential integrity violation - key (ptest1,ptest2,ptest3)=(1,2,3) in pktable still referenced from fktable
+ERROR:  update or delete on "pktable" violates foreign key constraint "constrname3" on "fktable"
+DETAIL:  Key (ptest1,ptest2,ptest3)=(1,2,3) is still referenced from "fktable".
 -- Try to delete something that should work
 DELETE FROM PKTABLE where ptest1=2;
 -- Show PKTABLE and FKTABLE
@@ -387,7 +402,8 @@ INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4);
 INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5);
 -- Insert a failed values
 INSERT INTO FKTABLE VALUES (1, 2, 7, 6);
-ERROR:  constrname3 referential integrity violation - key (ftest1,ftest2,ftest3)=(1,2,7) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname3"
+DETAIL:  Key (ftest1,ftest2,ftest3)=(1,2,7) is not present in "pktable".
 -- Show FKTABLE
 SELECT * from FKTABLE;
  ftest1 | ftest2 | ftest3 | ftest4 
@@ -485,7 +501,8 @@ INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4);
 INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5);
 -- Insert a failed values
 INSERT INTO FKTABLE VALUES (1, 2, 7, 6);
-ERROR:  constrname3 referential integrity violation - key (ftest1,ftest2,ftest3)=(1,2,7) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname3"
+DETAIL:  Key (ftest1,ftest2,ftest3)=(1,2,7) is not present in "pktable".
 -- Show FKTABLE
 SELECT * from FKTABLE;
  ftest1 | ftest2 | ftest3 | ftest4 
@@ -591,7 +608,8 @@ INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4);
 INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5);
 -- Insert a failed values
 INSERT INTO FKTABLE VALUES (1, 2, 7, 6);
-ERROR:  constrname3 referential integrity violation - key (ftest1,ftest2,ftest3)=(1,2,7) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname3"
+DETAIL:  Key (ftest1,ftest2,ftest3)=(1,2,7) is not present in "pktable".
 -- Show FKTABLE
 SELECT * from FKTABLE;
  ftest1 | ftest2 | ftest3 | ftest4 
@@ -607,7 +625,8 @@ SELECT * from FKTABLE;
 
 -- Try to update something that will fail
 UPDATE PKTABLE set ptest2=5 where ptest2=2;
-ERROR:  constrname3 referential integrity violation - key (ftest1,ftest2,ftest3)=(1,-1,3) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "constrname3"
+DETAIL:  Key (ftest1,ftest2,ftest3)=(1,-1,3) is not present in "pktable".
 -- Try to update something that will set default
 UPDATE PKTABLE set ptest1=0, ptest2=5, ptest3=10 where ptest2=2;
 UPDATE PKTABLE set ptest2=10 where ptest2=4;
@@ -819,17 +838,20 @@ insert into pktable(base1) values (1);
 insert into pktable(base1) values (2);
 --  let's insert a non-existant fktable value
 insert into fktable(ftest1) values (3);
-ERROR:  $1 referential integrity violation - key (ftest1)=(3) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "$1"
+DETAIL:  Key (ftest1)=(3) is not present in "pktable".
 --  let's make a valid row for that
 insert into pktable(base1) values (3);
 insert into fktable(ftest1) values (3);
 -- let's try removing a row that should fail from pktable
 delete from pktable where base1>2;
-ERROR:  $1 referential integrity violation - key (base1)=(3) in pktable still referenced from fktable
+ERROR:  update or delete on "pktable" violates foreign key constraint "$1" on "fktable"
+DETAIL:  Key (base1)=(3) is still referenced from "fktable".
 -- okay, let's try updating all of the base1 values to *4
 -- which should fail.
 update pktable set base1=base1*4;
-ERROR:  $1 referential integrity violation - key (base1)=(3) in pktable still referenced from fktable
+ERROR:  update or delete on "pktable" violates foreign key constraint "$1" on "fktable"
+DETAIL:  Key (base1)=(3) is still referenced from "fktable".
 -- okay, let's try an update that should work.
 update pktable set base1=base1*4 where base1<3;
 -- and a delete that should work
@@ -845,17 +867,20 @@ insert into pktable(base1, ptest1) values (1, 1);
 insert into pktable(base1, ptest1) values (2, 2);
 --  let's insert a non-existant fktable value
 insert into fktable(ftest1, ftest2) values (3, 1);
-ERROR:  $1 referential integrity violation - key (ftest1,ftest2)=(3,1) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "$1"
+DETAIL:  Key (ftest1,ftest2)=(3,1) is not present in "pktable".
 --  let's make a valid row for that
 insert into pktable(base1,ptest1) values (3, 1);
 insert into fktable(ftest1, ftest2) values (3, 1);
 -- let's try removing a row that should fail from pktable
 delete from pktable where base1>2;
-ERROR:  $1 referential integrity violation - key (base1,ptest1)=(3,1) in pktable still referenced from fktable
+ERROR:  update or delete on "pktable" violates foreign key constraint "$1" on "fktable"
+DETAIL:  Key (base1,ptest1)=(3,1) is still referenced from "fktable".
 -- okay, let's try updating all of the base1 values to *4
 -- which should fail.
 update pktable set base1=base1*4;
-ERROR:  $1 referential integrity violation - key (base1,ptest1)=(3,1) in pktable still referenced from fktable
+ERROR:  update or delete on "pktable" violates foreign key constraint "$1" on "fktable"
+DETAIL:  Key (base1,ptest1)=(3,1) is still referenced from "fktable".
 -- okay, let's try an update that should work.
 update pktable set base1=base1*4 where base1<3;
 -- and a delete that should work
@@ -876,13 +901,16 @@ insert into pktable (base1, ptest1, base2, ptest2) values (2, 2, 2, 1);
 insert into pktable (base1, ptest1, base2, ptest2) values (1, 3, 2, 2);
 -- fails (3,2) isn't in base1, ptest1
 insert into pktable (base1, ptest1, base2, ptest2) values (2, 3, 3, 2);
-ERROR:  $1 referential integrity violation - key (base2,ptest2)=(3,2) referenced from pktable not found in pktable
+ERROR:  insert or update on "pktable" violates foreign key constraint "$1"
+DETAIL:  Key (base2,ptest2)=(3,2) is not present in "pktable".
 -- fails (2,2) is being referenced
 delete from pktable where base1=2;
-ERROR:  $1 referential integrity violation - key (base1,ptest1)=(2,2) in pktable still referenced from pktable
+ERROR:  update or delete on "pktable" violates foreign key constraint "$1" on "pktable"
+DETAIL:  Key (base1,ptest1)=(2,2) is still referenced from "pktable".
 -- fails (1,1) is being referenced (twice)
 update pktable set base1=3 where base1=1;
-ERROR:  $1 referential integrity violation - key (base1,ptest1)=(1,1) in pktable still referenced from pktable
+ERROR:  update or delete on "pktable" violates foreign key constraint "$1" on "pktable"
+DETAIL:  Key (base1,ptest1)=(1,1) is still referenced from "pktable".
 -- this sequence of two deletes will work, since after the first there will be no (2,*) references
 delete from pktable where base2=2;
 delete from pktable where base1=2;
@@ -963,7 +991,8 @@ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "fktable_pkey" fo
 NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 -- default to immediate: should fail
 INSERT INTO fktable VALUES (5, 10);
-ERROR:  $1 referential integrity violation - key (fk)=(10) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "$1"
+DETAIL:  Key (fk)=(10) is not present in "pktable".
 -- explicitely defer the constraint
 BEGIN;
 SET CONSTRAINTS ALL DEFERRED;
@@ -993,7 +1022,8 @@ BEGIN;
 SET CONSTRAINTS ALL IMMEDIATE;
 -- should fail
 INSERT INTO fktable VALUES (500, 1000);
-ERROR:  $1 referential integrity violation - key (fk)=(1000) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "$1"
+DETAIL:  Key (fk)=(1000) is not present in "pktable".
 COMMIT;
 DROP TABLE fktable, pktable;
 -- tricky behavior: according to SQL99, if a deferred constraint is set
@@ -1017,7 +1047,8 @@ SET CONSTRAINTS ALL DEFERRED;
 INSERT INTO fktable VALUES (1000, 2000);
 -- should cause transaction abort, due to preceding error
 SET CONSTRAINTS ALL IMMEDIATE;
-ERROR:  $1 referential integrity violation - key (fk)=(2000) referenced from fktable not found in pktable
+ERROR:  insert or update on "fktable" violates foreign key constraint "$1"
+DETAIL:  Key (fk)=(2000) is not present in "pktable".
 INSERT INTO pktable VALUES (2000, 3); -- too late
 ERROR:  current transaction is aborted, queries ignored until end of transaction block
 COMMIT;