OSDN Git Service

Improve unique-constraint-violation error messages to include the exact
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 1 Aug 2009 19:59:41 +0000 (19:59 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 1 Aug 2009 19:59:41 +0000 (19:59 +0000)
values being complained of.

In passing, also remove the arbitrary length limitation in the similar
error detail message for foreign key violations.

Itagaki Takahiro

20 files changed:
contrib/citext/expected/citext.out
contrib/citext/expected/citext_1.out
src/backend/access/common/indextuple.c
src/backend/access/index/genam.c
src/backend/access/nbtree/nbtinsert.c
src/backend/utils/adt/ri_triggers.c
src/backend/utils/adt/ruleutils.c
src/include/access/genam.h
src/include/access/itup.h
src/include/utils/builtins.h
src/interfaces/ecpg/test/expected/compat_informix-test_informix.stderr
src/test/regress/expected/alter_table.out
src/test/regress/expected/arrays.out
src/test/regress/expected/create_index.out
src/test/regress/expected/inherit.out
src/test/regress/expected/plpgsql.out
src/test/regress/expected/transactions.out
src/test/regress/expected/uuid.out
src/test/regress/output/constraints.source
src/test/regress/output/tablespace.source

index 3694cb8..34ce3da 100644 (file)
@@ -271,10 +271,13 @@ SELECT name, 'A' = name AS t      FROM try where name = 'A';
 -- expected failures on duplicate key
 INSERT INTO try (name) VALUES ('a');
 ERROR:  duplicate key value violates unique constraint "try_pkey"
+DETAIL:  Key (name)=(a) already exists.
 INSERT INTO try (name) VALUES ('A');
 ERROR:  duplicate key value violates unique constraint "try_pkey"
+DETAIL:  Key (name)=(A) already exists.
 INSERT INTO try (name) VALUES ('aB');
 ERROR:  duplicate key value violates unique constraint "try_pkey"
+DETAIL:  Key (name)=(aB) already exists.
 -- Make sure that citext_smaller() and citext_lager() work properly.
 SELECT citext_smaller( 'aa'::citext, 'ab'::citext ) = 'aa' AS t;
  t 
index 1a6bcdf..cc03e23 100644 (file)
@@ -271,10 +271,13 @@ SELECT name, 'A' = name AS t      FROM try where name = 'A';
 -- expected failures on duplicate key
 INSERT INTO try (name) VALUES ('a');
 ERROR:  duplicate key value violates unique constraint "try_pkey"
+DETAIL:  Key (name)=(a) already exists.
 INSERT INTO try (name) VALUES ('A');
 ERROR:  duplicate key value violates unique constraint "try_pkey"
+DETAIL:  Key (name)=(A) already exists.
 INSERT INTO try (name) VALUES ('aB');
 ERROR:  duplicate key value violates unique constraint "try_pkey"
+DETAIL:  Key (name)=(aB) already exists.
 -- Make sure that citext_smaller() and citext_lager() work properly.
 SELECT citext_smaller( 'aa'::citext, 'ab'::citext ) = 'aa' AS t;
  t 
index cd3b886..a49ec34 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/common/indextuple.c,v 1.88 2009/06/11 14:48:53 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/common/indextuple.c,v 1.89 2009/08/01 19:59:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -433,6 +433,27 @@ nocache_index_getattr(IndexTuple tup,
 }
 
 /*
+ * Convert an index tuple into Datum/isnull arrays.
+ *
+ * The caller must allocate sufficient storage for the output arrays.
+ * (INDEX_MAX_KEYS entries should be enough.)
+ */
+void
+index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,
+                                  Datum *values, bool *isnull)
+{
+       int                     i;
+
+       /* Assert to protect callers who allocate fixed-size arrays */
+       Assert(tupleDescriptor->natts <= INDEX_MAX_KEYS);
+
+       for (i = 0; i < tupleDescriptor->natts; i++)
+       {
+               values[i] = index_getattr(tup, i + 1, tupleDescriptor, &isnull[i]);
+       }
+}
+
+/*
  * Create a palloc'd copy of an index tuple.
  */
 IndexTuple
index a79c392..6482aaa 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.74 2009/06/11 14:48:54 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.75 2009/08/01 19:59:41 tgl Exp $
  *
  * NOTES
  *       many of the old access method routines have been turned into
@@ -24,6 +24,8 @@
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "storage/bufmgr.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/rel.h"
 #include "utils/tqual.h"
 
@@ -130,6 +132,59 @@ IndexScanEnd(IndexScanDesc scan)
        pfree(scan);
 }
 
+/*
+ * ReportUniqueViolation -- Report a unique-constraint violation.
+ *
+ * The index entry represented by values[]/isnull[] violates the unique
+ * constraint enforced by this index.  Throw a suitable error.
+ */
+void
+ReportUniqueViolation(Relation indexRelation, Datum *values, bool *isnull)
+{
+       /*
+        * XXX for the moment we use the index's tupdesc as a guide to the
+        * datatypes of the values.  This is okay for btree indexes but is in
+        * fact the wrong thing in general.  This will have to be fixed if we
+        * are ever to support non-btree unique indexes.
+        */
+       TupleDesc       tupdesc = RelationGetDescr(indexRelation);
+       char       *key_names;
+       StringInfoData key_values;
+       int                     i;
+
+       key_names = pg_get_indexdef_columns(RelationGetRelid(indexRelation), true);
+
+       /* Get printable versions of the key values */
+       initStringInfo(&key_values);
+       for (i = 0; i < tupdesc->natts; i++)
+       {
+               char   *val;
+
+               if (isnull[i])
+                       val = "null";
+               else
+               {
+                       Oid             foutoid;
+                       bool    typisvarlena;
+
+                       getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
+                                                         &foutoid, &typisvarlena);
+                       val = OidOutputFunctionCall(foutoid, values[i]);
+               }
+
+               if (i > 0)
+                       appendStringInfoString(&key_values, ", ");
+               appendStringInfoString(&key_values, val);
+       }
+
+       ereport(ERROR,
+                       (errcode(ERRCODE_UNIQUE_VIOLATION),
+                        errmsg("duplicate key value violates unique constraint \"%s\"",
+                                       RelationGetRelationName(indexRelation)),
+                        errdetail("Key (%s)=(%s) already exists.",
+                                          key_names, key_values.data)));
+}
+
 
 /* ----------------------------------------------------------------
  *             heap-or-index-scan access to system catalogs
index f013718..ee3d89f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.171 2009/07/29 20:56:18 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.172 2009/08/01 19:59:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -362,12 +362,25 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
                                        }
 
                                        /*
-                                        * This is a definite conflict.
+                                        * This is a definite conflict.  Break the tuple down
+                                        * into datums and report the error.  But first, make
+                                        * sure we release the buffer locks we're holding ---
+                                        * the error reporting code could make catalog accesses,
+                                        * which in the worst case might touch this same index
+                                        * and cause deadlocks.
                                         */
-                                       ereport(ERROR,
-                                                       (errcode(ERRCODE_UNIQUE_VIOLATION),
-                                                        errmsg("duplicate key value violates unique constraint \"%s\"",
-                                                                       RelationGetRelationName(rel))));
+                                       if (nbuf != InvalidBuffer)
+                                               _bt_relbuf(rel, nbuf);
+                                       _bt_relbuf(rel, buf);
+
+                                       {
+                                               Datum   values[INDEX_MAX_KEYS];
+                                               bool    isnull[INDEX_MAX_KEYS];
+
+                                               index_deform_tuple(itup, RelationGetDescr(rel),
+                                                                                  values, isnull);
+                                               ReportUniqueViolation(rel, values, isnull);
+                                       }
                                }
                                else if (all_dead)
                                {
index 5bcbd63..c89553c 100644 (file)
@@ -15,7 +15,7 @@
  *
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.113 2009/06/11 14:49:04 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.114 2009/08/01 19:59:41 tgl Exp $
  *
  * ----------
  */
@@ -3413,11 +3413,8 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
                                   HeapTuple violator, TupleDesc tupdesc,
                                   bool spi_err)
 {
-#define BUFLENGTH      512
-       char            key_names[BUFLENGTH];
-       char            key_values[BUFLENGTH];
-       char       *name_ptr = key_names;
-       char       *val_ptr = key_values;
+       StringInfoData key_names;
+       StringInfoData key_values;
        bool            onfk;
        int                     idx,
                                key_idx;
@@ -3465,6 +3462,8 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
        }
 
        /* Get printable versions of the keys involved */
+       initStringInfo(&key_names);
+       initStringInfo(&key_values);
        for (idx = 0; idx < qkey->nkeypairs; idx++)
        {
                int                     fnum = qkey->keypair[idx][key_idx];
@@ -3476,20 +3475,13 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
                if (!val)
                        val = "null";
 
-               /*
-                * Go to "..." if name or value doesn't fit in buffer.  We reserve 5
-                * bytes to ensure we can add comma, "...", null.
-                */
-               if (strlen(name) >= (key_names + BUFLENGTH - 5) - name_ptr ||
-                       strlen(val) >= (key_values + BUFLENGTH - 5) - val_ptr)
+               if (idx > 0)
                {
-                       sprintf(name_ptr, "...");
-                       sprintf(val_ptr, "...");
-                       break;
+                       appendStringInfoString(&key_names, ", ");
+                       appendStringInfoString(&key_values, ", ");
                }
-
-               name_ptr += sprintf(name_ptr, "%s%s", idx > 0 ? "," : "", name);
-               val_ptr += sprintf(val_ptr, "%s%s", idx > 0 ? "," : "", val);
+               appendStringInfoString(&key_names, name);
+               appendStringInfoString(&key_values, val);
        }
 
        if (onfk)
@@ -3498,7 +3490,7 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
                                 errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
                                                RelationGetRelationName(fk_rel), constrname),
                                 errdetail("Key (%s)=(%s) is not present in table \"%s\".",
-                                                  key_names, key_values,
+                                                  key_names.data, key_values.data,
                                                   RelationGetRelationName(pk_rel))));
        else
                ereport(ERROR,
@@ -3507,7 +3499,7 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
                                                RelationGetRelationName(pk_rel),
                                                constrname, RelationGetRelationName(fk_rel)),
                        errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
-                                         key_names, key_values,
+                                         key_names.data, key_values.data,
                                          RelationGetRelationName(fk_rel))));
 }
 
index 752e84d..38057a0 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.305 2009/07/29 20:56:19 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.306 2009/08/01 19:59:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -142,7 +142,8 @@ static char *pg_get_viewdef_worker(Oid viewoid, int prettyFlags);
 static void decompile_column_index_array(Datum column_index_array, Oid relId,
                                                         StringInfo buf);
 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
-static char *pg_get_indexdef_worker(Oid indexrelid, int colno, bool showTblSpc,
+static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
+                                          bool attrsOnly, bool showTblSpc,
                                           int prettyFlags);
 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
                                                        int prettyFlags);
@@ -613,7 +614,7 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
        Oid                     indexrelid = PG_GETARG_OID(0);
 
        PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0,
-                                                                                                                  false, 0)));
+                                                                                                                  false, false, 0)));
 }
 
 Datum
@@ -626,18 +627,31 @@ pg_get_indexdef_ext(PG_FUNCTION_ARGS)
 
        prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
        PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno,
-                                                                                                          false, prettyFlags)));
+                                                                                                                  colno != 0,
+                                                                                                                  false,
+                                                                                                                  prettyFlags)));
 }
 
 /* Internal version that returns a palloc'd C string */
 char *
 pg_get_indexdef_string(Oid indexrelid)
 {
-       return pg_get_indexdef_worker(indexrelid, 0, true, 0);
+       return pg_get_indexdef_worker(indexrelid, 0, false, true, 0);
+}
+
+/* Internal version that just reports the column definitions */
+char *
+pg_get_indexdef_columns(Oid indexrelid, bool pretty)
+{
+       int                     prettyFlags;
+
+       prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
+       return pg_get_indexdef_worker(indexrelid, 0, true, false, prettyFlags);
 }
 
 static char *
-pg_get_indexdef_worker(Oid indexrelid, int colno, bool showTblSpc,
+pg_get_indexdef_worker(Oid indexrelid, int colno,
+                                          bool attrsOnly, bool showTblSpc,
                                           int prettyFlags)
 {
        HeapTuple       ht_idx;
@@ -736,7 +750,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, bool showTblSpc,
         */
        initStringInfo(&buf);
 
-       if (!colno)
+       if (!attrsOnly)
                appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                                                 idxrec->indisunique ? "UNIQUE " : "",
                                                 quote_identifier(NameStr(idxrelrec->relname)),
@@ -790,8 +804,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, bool showTblSpc,
                        keycoltype = exprType(indexkey);
                }
 
-               /* Provide decoration only in the colno=0 case */
-               if (!colno)
+               if (!attrsOnly && (!colno || colno == keyno + 1))
                {
                        /* Add the operator class name, if not default */
                        get_opclass_name(indclass->values[keyno], keycoltype, &buf);
@@ -816,7 +829,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, bool showTblSpc,
                }
        }
 
-       if (!colno)
+       if (!attrsOnly)
        {
                appendStringInfoChar(&buf, ')');
 
index a8c0e02..1902526 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.79 2009/07/29 20:56:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.80 2009/08/01 19:59:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -164,6 +164,8 @@ extern FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum,
 extern IndexScanDesc RelationGetIndexScan(Relation indexRelation,
                                         int nkeys, ScanKey key);
 extern void IndexScanEnd(IndexScanDesc scan);
+extern void ReportUniqueViolation(Relation indexRelation,
+                                                                 Datum *values, bool *isnull);
 
 /*
  * heap-or-index access to system catalogs (in genam.c)
index 8527de6..ead628f 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/itup.h,v 1.51 2009/01/01 17:23:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/itup.h,v 1.52 2009/08/01 19:59:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -143,6 +143,8 @@ extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor,
                                 Datum *values, bool *isnull);
 extern Datum nocache_index_getattr(IndexTuple tup, int attnum,
                                          TupleDesc tupleDesc, bool *isnull);
+extern void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,
+                                Datum *values, bool *isnull);
 extern IndexTuple CopyIndexTuple(IndexTuple source);
 
 #endif   /* ITUP_H */
index 72b39f7..481eacf 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.335 2009/07/29 20:56:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.336 2009/08/01 19:59:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -575,6 +575,7 @@ extern Datum pg_get_viewdef_name_ext(PG_FUNCTION_ARGS);
 extern Datum pg_get_indexdef(PG_FUNCTION_ARGS);
 extern Datum pg_get_indexdef_ext(PG_FUNCTION_ARGS);
 extern char *pg_get_indexdef_string(Oid indexrelid);
+extern char *pg_get_indexdef_columns(Oid indexrelid, bool pretty);
 extern Datum pg_get_triggerdef(PG_FUNCTION_ARGS);
 extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS);
 extern Datum pg_get_constraintdef_ext(PG_FUNCTION_ARGS);
index c9322e5..f57f88b 100644 (file)
@@ -23,6 +23,7 @@
 [NO_PID]: ecpg_execute on line 31: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_check_PQresult on line 31: ERROR:  duplicate key value violates unique constraint "test_pkey"
+DETAIL:  Key (i)=(7) already exists.
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: raising sqlstate 23505 (sqlcode -239) on line 31: duplicate key value violates unique constraint "test_pkey" on line 31
 [NO_PID]: sqlca: code: -239, state: 23505
index 031e59c..3c9bb63 100644 (file)
@@ -407,6 +407,7 @@ insert into atacc1 (test) values (2);
 -- should fail
 insert into atacc1 (test) values (2);
 ERROR:  duplicate key value violates unique constraint "atacc_test1"
+DETAIL:  Key (test)=(2) already exists.
 -- should succeed
 insert into atacc1 (test) values (4);
 -- try adding a unique oid constraint
@@ -442,6 +443,7 @@ insert into atacc1 (test,test2) values (4,4);
 -- should fail
 insert into atacc1 (test,test2) values (4,4);
 ERROR:  duplicate key value violates unique constraint "atacc_test1"
+DETAIL:  Key (test, test2)=(4, 4) already exists.
 -- should all succeed
 insert into atacc1 (test,test2) values (4,5);
 insert into atacc1 (test,test2) values (5,4);
@@ -456,6 +458,7 @@ NOTICE:  ALTER TABLE / ADD UNIQUE will create implicit index "atacc1_test2_key"
 insert into atacc1 (test2, test) values (3, 3);
 insert into atacc1 (test2, test) values (2, 3);
 ERROR:  duplicate key value violates unique constraint "atacc1_test_key"
+DETAIL:  Key (test)=(3) already exists.
 drop table atacc1;
 -- test primary key constraint adding
 create table atacc1 ( test int ) with oids;
@@ -467,6 +470,7 @@ insert into atacc1 (test) values (2);
 -- should fail
 insert into atacc1 (test) values (2);
 ERROR:  duplicate key value violates unique constraint "atacc_test1"
+DETAIL:  Key (test)=(2) already exists.
 -- should succeed
 insert into atacc1 (test) values (4);
 -- inserting NULL should fail
@@ -534,6 +538,7 @@ insert into atacc1 (test,test2) values (4,4);
 -- should fail
 insert into atacc1 (test,test2) values (4,4);
 ERROR:  duplicate key value violates unique constraint "atacc_test1"
+DETAIL:  Key (test, test2)=(4, 4) already exists.
 insert into atacc1 (test,test2) values (NULL,3);
 ERROR:  null value in column "test" violates not-null constraint
 insert into atacc1 (test,test2) values (3, NULL);
@@ -552,6 +557,7 @@ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "atacc1_pkey" for
 insert into atacc1 (test2, test) values (3, 3);
 insert into atacc1 (test2, test) values (2, 3);
 ERROR:  duplicate key value violates unique constraint "atacc1_pkey"
+DETAIL:  Key (test)=(3) already exists.
 insert into atacc1 (test2, test) values (1, NULL);
 ERROR:  null value in column "test" violates not-null constraint
 drop table atacc1;
index 15f3f60..7225d6e 100644 (file)
@@ -713,6 +713,7 @@ insert into arr_tbl values ('{1,2}');
 -- failure expected:
 insert into arr_tbl values ('{1,2,3}');
 ERROR:  duplicate key value violates unique constraint "arr_tbl_f1_key"
+DETAIL:  Key (f1)=({1,2,3}) already exists.
 insert into arr_tbl values ('{2,3,4}');
 insert into arr_tbl values ('{1,5,3}');
 insert into arr_tbl values ('{1,2,10}');
index 6e06be5..02f2474 100644 (file)
@@ -641,6 +641,7 @@ INSERT INTO func_index_heap VALUES('QWE','RTY');
 -- this should fail because of unique index:
 INSERT INTO func_index_heap VALUES('ABCD', 'EF');
 ERROR:  duplicate key value violates unique constraint "func_index_index"
+DETAIL:  Key (textcat(f1, f2))=(ABCDEF) already exists.
 -- but this shouldn't:
 INSERT INTO func_index_heap VALUES('QWERTY');
 --
@@ -655,6 +656,7 @@ INSERT INTO func_index_heap VALUES('QWE','RTY');
 -- this should fail because of unique index:
 INSERT INTO func_index_heap VALUES('ABCD', 'EF');
 ERROR:  duplicate key value violates unique constraint "func_index_index"
+DETAIL:  Key ((f1 || f2))=(ABCDEF) already exists.
 -- but this shouldn't:
 INSERT INTO func_index_heap VALUES('QWERTY');
 --
@@ -679,6 +681,7 @@ CREATE UNIQUE INDEX CONCURRENTLY concur_index2 ON concur_heap(f1);
 -- check if constraint is set up properly to be enforced
 INSERT INTO concur_heap VALUES ('b','x');
 ERROR:  duplicate key value violates unique constraint "concur_index2"
+DETAIL:  Key (f1)=(b) already exists.
 -- check if constraint is enforced properly at build time
 CREATE UNIQUE INDEX CONCURRENTLY concur_index3 ON concur_heap(f2);
 ERROR:  could not create unique index "concur_index3"
index 100edb3..1b98ce9 100644 (file)
@@ -638,6 +638,7 @@ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "inhg_pkey" for t
 INSERT INTO inhg VALUES (5, 10);
 INSERT INTO inhg VALUES (20, 10); -- should fail
 ERROR:  duplicate key value violates unique constraint "inhg_pkey"
+DETAIL:  Key (xx)=(10) already exists.
 DROP TABLE inhg;
 /* Multiple primary keys creation should fail */
 CREATE TABLE inhg (x text, LIKE inhx INCLUDING INDEXES, PRIMARY KEY(x)); /* fails */
@@ -653,6 +654,7 @@ INSERT INTO inhg (xx, yy, x) VALUES ('test', 5, 10);
 INSERT INTO inhg (xx, yy, x) VALUES ('test', 10, 15);
 INSERT INTO inhg (xx, yy, x) VALUES ('foo', 10, 15); -- should fail
 ERROR:  duplicate key value violates unique constraint "inhg_x_key"
+DETAIL:  Key (x)=(15) already exists.
 DROP TABLE inhg;
 DROP TABLE inhz;
 -- Test changing the type of inherited columns
index 0446f51..84a5943 100644 (file)
@@ -1517,6 +1517,7 @@ select * from PField_v1 where pfname = 'PF0_2' order by slotname;
 --
 insert into PField values ('PF1_1', 'should fail due to unique index');
 ERROR:  duplicate key value violates unique constraint "pfield_name"
+DETAIL:  Key (name)=(PF1_1) already exists.
 update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
 ERROR:  WS.not.there         does not exist
 CONTEXT:  PL/pgSQL function "tg_backlink_a" line 16 at assignment
@@ -1531,6 +1532,7 @@ ERROR:  illegal slotlink beginning with XX
 CONTEXT:  PL/pgSQL function "tg_slotlink_a" line 16 at assignment
 insert into HSlot values ('HS', 'base.hub1', 1, '');
 ERROR:  duplicate key value violates unique constraint "hslot_name"
+DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
 insert into HSlot values ('HS', 'base.hub1', 20, '');
 ERROR:  no manual manipulation of HSlot
 delete from HSlot;
index 51bb366..fc98f01 100644 (file)
@@ -468,12 +468,14 @@ NOTICE:  CREATE TABLE / UNIQUE will create implicit index "koju_a_key" for table
                INSERT INTO koju VALUES (1);
                INSERT INTO koju VALUES (1);
 ERROR:  duplicate key value violates unique constraint "koju_a_key"
+DETAIL:  Key (a)=(1) already exists.
        rollback to x;
        CREATE TABLE koju (a INT UNIQUE);
 NOTICE:  CREATE TABLE / UNIQUE will create implicit index "koju_a_key" for table "koju"
        INSERT INTO koju VALUES (1);
        INSERT INTO koju VALUES (1);
 ERROR:  duplicate key value violates unique constraint "koju_a_key"
+DETAIL:  Key (a)=(1) already exists.
 ROLLBACK;
 DROP TABLE foo;
 DROP TABLE baz;
index 03bd73b..da230fe 100644 (file)
@@ -119,6 +119,7 @@ CREATE UNIQUE INDEX guid1_unique_BTREE ON guid1 USING BTREE (guid_field);
 -- should fail
 INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
 ERROR:  duplicate key value violates unique constraint "guid1_unique_btree"
+DETAIL:  Key (guid_field)=(11111111-1111-1111-1111-111111111111) already exists.
 -- check to see whether the new indexes are actually there
 SELECT count(*) FROM pg_class WHERE relkind='i' AND relname LIKE 'guid%';
  count 
index e21aa6b..56dbf7a 100644 (file)
@@ -294,6 +294,7 @@ INSERT INTO PRIMARY_TBL VALUES (1, 'one');
 INSERT INTO PRIMARY_TBL VALUES (2, 'two');
 INSERT INTO PRIMARY_TBL VALUES (1, 'three');
 ERROR:  duplicate key value violates unique constraint "primary_tbl_pkey"
+DETAIL:  Key (i)=(1) already exists.
 INSERT INTO PRIMARY_TBL VALUES (4, 'three');
 INSERT INTO PRIMARY_TBL VALUES (5, 'one');
 INSERT INTO PRIMARY_TBL (t) VALUES ('six');
@@ -338,6 +339,7 @@ INSERT INTO UNIQUE_TBL VALUES (1, 'one');
 INSERT INTO UNIQUE_TBL VALUES (2, 'two');
 INSERT INTO UNIQUE_TBL VALUES (1, 'three');
 ERROR:  duplicate key value violates unique constraint "unique_tbl_i_key"
+DETAIL:  Key (i)=(1) already exists.
 INSERT INTO UNIQUE_TBL VALUES (4, 'four');
 INSERT INTO UNIQUE_TBL VALUES (5, 'one');
 INSERT INTO UNIQUE_TBL (t) VALUES ('six');
@@ -362,6 +364,7 @@ INSERT INTO UNIQUE_TBL VALUES (2, 'two');
 INSERT INTO UNIQUE_TBL VALUES (1, 'three');
 INSERT INTO UNIQUE_TBL VALUES (1, 'one');
 ERROR:  duplicate key value violates unique constraint "unique_tbl_i_key"
+DETAIL:  Key (i, t)=(1, one) already exists.
 INSERT INTO UNIQUE_TBL VALUES (5, 'one');
 INSERT INTO UNIQUE_TBL (t) VALUES ('six');
 SELECT '' AS five, * FROM UNIQUE_TBL;
@@ -389,6 +392,7 @@ BEGIN;
 -- default is immediate so this should fail right away
 UPDATE unique_tbl SET i = 1 WHERE i = 0;
 ERROR:  duplicate key value violates unique constraint "unique_tbl_i_key"
+DETAIL:  Key (i)=(1) already exists.
 ROLLBACK;
 -- check is done at end of statement, so this should succeed
 UPDATE unique_tbl SET i = i+1;
@@ -446,11 +450,13 @@ BEGIN;
 INSERT INTO unique_tbl VALUES (3, 'Three'); -- should succeed for now
 COMMIT; -- should fail
 ERROR:  duplicate key value violates unique constraint "unique_tbl_i_key"
+DETAIL:  Key (i)=(3) already exists.
 -- make constraint check immediate
 BEGIN;
 SET CONSTRAINTS ALL IMMEDIATE;
 INSERT INTO unique_tbl VALUES (3, 'Three'); -- should fail
 ERROR:  duplicate key value violates unique constraint "unique_tbl_i_key"
+DETAIL:  Key (i)=(3) already exists.
 COMMIT;
 -- forced check when SET CONSTRAINTS is called
 BEGIN;
@@ -458,6 +464,7 @@ SET CONSTRAINTS ALL DEFERRED;
 INSERT INTO unique_tbl VALUES (3, 'Three'); -- should succeed for now
 SET CONSTRAINTS ALL IMMEDIATE; -- should fail
 ERROR:  duplicate key value violates unique constraint "unique_tbl_i_key"
+DETAIL:  Key (i)=(3) already exists.
 COMMIT;
 -- test a HOT update that invalidates the conflicting tuple.
 -- the trigger should still fire and catch the violation
@@ -466,6 +473,7 @@ INSERT INTO unique_tbl VALUES (3, 'Three'); -- should succeed for now
 UPDATE unique_tbl SET t = 'THREE' WHERE i = 3 AND t = 'Three';
 COMMIT; -- should fail
 ERROR:  duplicate key value violates unique constraint "unique_tbl_i_key"
+DETAIL:  Key (i)=(3) already exists.
 SELECT * FROM unique_tbl;
  i |   t   
 ---+-------
index 8065505..e57ad2b 100644 (file)
@@ -49,6 +49,7 @@ ALTER INDEX testschema.anindex SET TABLESPACE testspace;
 INSERT INTO testschema.atable VALUES(3);       -- ok
 INSERT INTO testschema.atable VALUES(1);       -- fail (checks index)
 ERROR:  duplicate key value violates unique constraint "anindex"
+DETAIL:  Key (column1)=(1) already exists.
 SELECT COUNT(*) FROM testschema.atable;                -- checks heap
  count 
 -------