From 527f0ae3fa48c3c3a8ba1bde19039545e88a52b6 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 1 Aug 2009 20:59:17 +0000 Subject: [PATCH] Department of second thoughts: let's show the exact key during unique index build failures, too. Refactor a bit more since that error message isn't spelled the same. --- src/backend/access/index/genam.c | 38 +++++++++++++++--------------- src/backend/access/nbtree/nbtinsert.c | 12 +++++++--- src/backend/utils/sort/tuplesort.c | 12 ++++++++-- src/include/access/genam.h | 6 ++--- src/test/regress/expected/alter_table.out | 4 ++-- src/test/regress/expected/create_index.out | 2 +- 6 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index 6482aaa6a7..860e576603 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.75 2009/08/01 19:59:41 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.76 2009/08/01 20:59:17 tgl Exp $ * * NOTES * many of the old access method routines have been turned into @@ -133,13 +133,16 @@ IndexScanEnd(IndexScanDesc scan) } /* - * ReportUniqueViolation -- Report a unique-constraint violation. + * BuildIndexValueDescription * - * The index entry represented by values[]/isnull[] violates the unique - * constraint enforced by this index. Throw a suitable error. + * Construct a string describing the contents of an index entry, in the + * form "(key_name, ...)=(key_value, ...)". This is currently used + * only for building unique-constraint error messages, but we don't want + * to hardwire the spelling of the messages here. */ -void -ReportUniqueViolation(Relation indexRelation, Datum *values, bool *isnull) +char * +BuildIndexValueDescription(Relation indexRelation, + Datum *values, bool *isnull) { /* * XXX for the moment we use the index's tupdesc as a guide to the @@ -148,14 +151,14 @@ ReportUniqueViolation(Relation indexRelation, Datum *values, bool *isnull) * are ever to support non-btree unique indexes. */ TupleDesc tupdesc = RelationGetDescr(indexRelation); - char *key_names; - StringInfoData key_values; + StringInfoData buf; int i; - key_names = pg_get_indexdef_columns(RelationGetRelid(indexRelation), true); + initStringInfo(&buf); + appendStringInfo(&buf, "(%s)=(", + 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; @@ -173,16 +176,13 @@ ReportUniqueViolation(Relation indexRelation, Datum *values, bool *isnull) } if (i > 0) - appendStringInfoString(&key_values, ", "); - appendStringInfoString(&key_values, val); + appendStringInfoString(&buf, ", "); + appendStringInfoString(&buf, 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))); + appendStringInfoChar(&buf, ')'); + + return buf.data; } diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index ee3d89fd06..dd3736ad8a 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.172 2009/08/01 19:59:41 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.173 2009/08/01 20:59:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -365,7 +365,7 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel, * 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, + * BuildIndexValueDescription could make catalog accesses, * which in the worst case might touch this same index * and cause deadlocks. */ @@ -379,7 +379,13 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel, index_deform_tuple(itup, RelationGetDescr(rel), values, isnull); - ReportUniqueViolation(rel, values, isnull); + ereport(ERROR, + (errcode(ERRCODE_UNIQUE_VIOLATION), + errmsg("duplicate key value violates unique constraint \"%s\"", + RelationGetRelationName(rel)), + errdetail("Key %s already exists.", + BuildIndexValueDescription(rel, + values, isnull)))); } } else if (all_dead) diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index 6d07296d59..cb89f65a91 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -91,7 +91,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.91 2009/06/11 14:49:06 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.92 2009/08/01 20:59:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2801,11 +2801,19 @@ comparetup_index_btree(const SortTuple *a, const SortTuple *b, * error in that case. */ if (state->enforceUnique && !equal_hasnull && tuple1 != tuple2) + { + Datum values[INDEX_MAX_KEYS]; + bool isnull[INDEX_MAX_KEYS]; + + index_deform_tuple(tuple1, tupDes, values, isnull); ereport(ERROR, (errcode(ERRCODE_UNIQUE_VIOLATION), errmsg("could not create unique index \"%s\"", RelationGetRelationName(state->indexRel)), - errdetail("Table contains duplicated values."))); + errdetail("Key %s is duplicated.", + BuildIndexValueDescription(state->indexRel, + values, isnull)))); + } /* * If key values are equal, we sort on ItemPointer. This does not affect diff --git a/src/include/access/genam.h b/src/include/access/genam.h index 1902526577..068d96493d 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -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.80 2009/08/01 19:59:41 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.81 2009/08/01 20:59:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -164,8 +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); +extern char *BuildIndexValueDescription(Relation indexRelation, + Datum *values, bool *isnull); /* * heap-or-index access to system catalogs (in genam.c) diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 3c9bb6308e..20bf3de3ba 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -423,7 +423,7 @@ insert into atacc1 (test) values (2); alter table atacc1 add constraint atacc_test1 unique (test); NOTICE: ALTER TABLE / ADD UNIQUE will create implicit index "atacc_test1" for table "atacc1" ERROR: could not create unique index "atacc_test1" -DETAIL: Table contains duplicated values. +DETAIL: Key (test)=(2) is duplicated. insert into atacc1 (test) values (3); drop table atacc1; -- let's do one where the unique constraint fails @@ -494,7 +494,7 @@ insert into atacc1 (test) values (2); alter table atacc1 add constraint atacc_test1 primary key (test); NOTICE: ALTER TABLE / ADD PRIMARY KEY will create implicit index "atacc_test1" for table "atacc1" ERROR: could not create unique index "atacc_test1" -DETAIL: Table contains duplicated values. +DETAIL: Key (test)=(2) is duplicated. insert into atacc1 (test) values (3); drop table atacc1; -- let's do another one where the primary key constraint fails when added diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index 02f2474a05..079a64098c 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -685,7 +685,7 @@ 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" -DETAIL: Table contains duplicated values. +DETAIL: Key (f2)=(b) is duplicated. -- test that expression indexes and partial indexes work concurrently CREATE INDEX CONCURRENTLY concur_index4 on concur_heap(f2) WHERE f1='a'; CREATE INDEX CONCURRENTLY concur_index5 on concur_heap(f2) WHERE f1='x'; -- 2.11.0