diff -cpr head/src/backend/access/common/indextuple.c report_dupkey/src/backend/access/common/indextuple.c
*** head/src/backend/access/common/indextuple.c	2009-07-21 13:25:59.100113842 +0900
--- report_dupkey/src/backend/access/common/indextuple.c	2009-07-21 13:26:10.311181100 +0900
***************
*** 19,24 ****
--- 19,26 ----
  #include "access/heapam.h"
  #include "access/itup.h"
  #include "access/tuptoaster.h"
+ #include "utils/lsyscache.h"
+ #include "utils/rel.h"
  
  
  /* ----------------------------------------------------------------
*************** CopyIndexTuple(IndexTuple source)
*** 446,448 ****
--- 448,502 ----
  	memcpy(result, source, size);
  	return result;
  }
+ 
+ /*
+  * Report duplicated key error.
+  */
+ void
+ report_unique_violation(Relation rel, IndexTuple itup)
+ {
+ 	StringInfoData	key_names;
+ 	StringInfoData	key_values;
+ 	int				i;
+ 	TupleDesc		tupdesc = rel->rd_att;
+ 
+ 	/* Get printable versions of the keys involved */
+ 	initStringInfo(&key_names);
+ 	initStringInfo(&key_values);
+ 	for (i = 0; i < tupdesc->natts; i++)
+ 	{
+ 		char	   *name;
+ 		char	   *val;
+ 		Datum		value;
+ 		bool		isnull;
+ 
+ 		name = NameStr(tupdesc->attrs[i]->attname);
+ 		value = index_getattr(itup, i + 1, tupdesc, &isnull);
+ 		if (isnull)
+ 			val = "null";
+ 		else
+ 		{
+ 			Oid			foutoid;
+ 			bool		typisvarlena;
+ 
+ 			getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
+ 							  &foutoid, &typisvarlena);
+ 			val = OidOutputFunctionCall(foutoid, value);
+ 		}
+ 
+ 		if (i > 0)
+ 		{
+ 			appendStringInfoChar(&key_names, ',');
+ 			appendStringInfoChar(&key_values, ',');
+ 		}
+ 		appendStringInfoString(&key_names, name);
+ 		appendStringInfoString(&key_values, val);
+ 	}
+ 
+ 	ereport(ERROR,
+ 			(errcode(ERRCODE_UNIQUE_VIOLATION),
+ 			 errmsg("duplicate key value violates unique constraint \"%s\"",
+ 					RelationGetRelationName(rel)),
+ 		errdetail("Key (%s)=(%s) already exists.",
+ 				  key_names.data, key_values.data)));
+ }
diff -cpr head/src/backend/access/nbtree/nbtinsert.c report_dupkey/src/backend/access/nbtree/nbtinsert.c
*** head/src/backend/access/nbtree/nbtinsert.c	2009-07-21 13:25:59.099109481 +0900
--- report_dupkey/src/backend/access/nbtree/nbtinsert.c	2009-07-21 13:26:10.312077984 +0900
*************** _bt_check_unique(Relation rel, IndexTupl
*** 295,304 ****
  						break;
  					}
  
! 					ereport(ERROR,
! 							(errcode(ERRCODE_UNIQUE_VIOLATION),
! 							 errmsg("duplicate key value violates unique constraint \"%s\"",
! 									RelationGetRelationName(rel))));
  				}
  				else if (all_dead)
  				{
--- 295,302 ----
  						break;
  					}
  
! 					/* duplicate key error */
! 					report_unique_violation(rel, itup);
  				}
  				else if (all_dead)
  				{
diff -cpr head/src/backend/utils/adt/ri_triggers.c report_dupkey/src/backend/utils/adt/ri_triggers.c
*** head/src/backend/utils/adt/ri_triggers.c	2009-07-21 13:25:59.067110675 +0900
--- report_dupkey/src/backend/utils/adt/ri_triggers.c	2009-07-21 13:26:10.313181065 +0900
*************** ri_ReportViolation(RI_QueryKey *qkey, co
*** 3413,3426 ****
  				   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;
! 	bool		onfk;
! 	int			idx,
! 				key_idx;
  
  	if (spi_err)
  		ereport(ERROR,
--- 3413,3423 ----
  				   HeapTuple violator, TupleDesc tupdesc,
  				   bool spi_err)
  {
! 	StringInfoData	key_names;
! 	StringInfoData	key_values;
! 	bool			onfk;
! 	int				idx,
! 					key_idx;
  
  	if (spi_err)
  		ereport(ERROR,
*************** ri_ReportViolation(RI_QueryKey *qkey, co
*** 3465,3495 ****
  	}
  
  	/* Get printable versions of the keys involved */
  	for (idx = 0; idx < qkey->nkeypairs; idx++)
  	{
  		int			fnum = qkey->keypair[idx][key_idx];
! 		char	   *name,
! 				   *val;
  
  		name = SPI_fname(tupdesc, fnum);
  		val = SPI_getvalue(violator, tupdesc, fnum);
  		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)
  		{
! 			sprintf(name_ptr, "...");
! 			sprintf(val_ptr, "...");
! 			break;
  		}
! 
! 		name_ptr += sprintf(name_ptr, "%s%s", idx > 0 ? "," : "", name);
! 		val_ptr += sprintf(val_ptr, "%s%s", idx > 0 ? "," : "", val);
  	}
  
  	if (onfk)
--- 3462,3487 ----
  	}
  
  	/* 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];
! 		char	   *name;
! 		char	   *val;
  
  		name = SPI_fname(tupdesc, fnum);
  		val = SPI_getvalue(violator, tupdesc, fnum);
  		if (!val)
  			val = "null";
  
! 		if (idx > 0)
  		{
! 			appendStringInfoChar(&key_names, ',');
! 			appendStringInfoChar(&key_values, ',');
  		}
! 		appendStringInfoString(&key_names, name);
! 		appendStringInfoString(&key_values, val);
  	}
  
  	if (onfk)
*************** ri_ReportViolation(RI_QueryKey *qkey, co
*** 3498,3504 ****
  				 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,
  						   RelationGetRelationName(pk_rel))));
  	else
  		ereport(ERROR,
--- 3490,3496 ----
  				 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.data, key_values.data,
  						   RelationGetRelationName(pk_rel))));
  	else
  		ereport(ERROR,
*************** ri_ReportViolation(RI_QueryKey *qkey, co
*** 3507,3513 ****
  						RelationGetRelationName(pk_rel),
  						constrname, RelationGetRelationName(fk_rel)),
  			errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
! 					  key_names, key_values,
  					  RelationGetRelationName(fk_rel))));
  }
  
--- 3499,3505 ----
  						RelationGetRelationName(pk_rel),
  						constrname, RelationGetRelationName(fk_rel)),
  			errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
! 					  key_names.data, key_values.data,
  					  RelationGetRelationName(fk_rel))));
  }
  
diff -cpr head/src/include/access/itup.h report_dupkey/src/include/access/itup.h
*** head/src/include/access/itup.h	2009-07-21 13:25:59.126109412 +0900
--- report_dupkey/src/include/access/itup.h	2009-07-21 13:26:10.313181065 +0900
***************
*** 18,23 ****
--- 18,24 ----
  #include "access/tupmacs.h"
  #include "storage/bufpage.h"
  #include "storage/itemptr.h"
+ #include "utils/relcache.h"
  
  /*
   * Index tuple header structure
*************** extern IndexTuple index_form_tuple(Tuple
*** 144,148 ****
--- 145,150 ----
  extern Datum nocache_index_getattr(IndexTuple tup, int attnum,
  					  TupleDesc tupleDesc, bool *isnull);
  extern IndexTuple CopyIndexTuple(IndexTuple source);
+ extern void report_unique_violation(Relation rel, IndexTuple itup);
  
  #endif   /* ITUP_H */
diff -cpr head/src/test/regress/expected/alter_table.out report_dupkey/src/test/regress/expected/alter_table.out
*** head/src/test/regress/expected/alter_table.out	2009-07-21 13:25:59.166236124 +0900
--- report_dupkey/src/test/regress/expected/alter_table.out	2009-07-21 13:28:53.321058000 +0900
*************** insert into atacc1 (test) values (2);
*** 407,412 ****
--- 407,413 ----
  -- 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
*************** insert into atacc1 (test,test2) values (
*** 442,447 ****
--- 443,449 ----
  -- 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);
*************** NOTICE:  ALTER TABLE / ADD UNIQUE will c
*** 456,461 ****
--- 458,464 ----
  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;
*************** insert into atacc1 (test) values (2);
*** 467,472 ****
--- 470,476 ----
  -- 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
*************** insert into atacc1 (test,test2) values (
*** 534,539 ****
--- 538,544 ----
  -- 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);
*************** NOTICE:  CREATE TABLE / PRIMARY KEY will
*** 552,557 ****
--- 557,563 ----
  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;
diff -cpr head/src/test/regress/expected/arrays.out report_dupkey/src/test/regress/expected/arrays.out
*** head/src/test/regress/expected/arrays.out	2009-07-21 13:25:59.163208473 +0900
--- report_dupkey/src/test/regress/expected/arrays.out	2009-07-21 13:28:48.187241000 +0900
*************** insert into arr_tbl values ('{1,2}');
*** 713,718 ****
--- 713,719 ----
  -- 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}');
diff -cpr head/src/test/regress/expected/create_index.out report_dupkey/src/test/regress/expected/create_index.out
*** head/src/test/regress/expected/create_index.out	2009-07-21 13:25:59.162211307 +0900
--- report_dupkey/src/test/regress/expected/create_index.out	2009-07-21 13:28:47.262113000 +0900
*************** INSERT INTO func_index_heap VALUES('QWE'
*** 562,567 ****
--- 562,568 ----
  -- 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 (pg_expression_1)=(ABCDEF) already exists.
  -- but this shouldn't:
  INSERT INTO func_index_heap VALUES('QWERTY');
  --
*************** INSERT INTO func_index_heap VALUES('QWE'
*** 576,581 ****
--- 577,583 ----
  -- 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 (pg_expression_1)=(ABCDEF) already exists.
  -- but this shouldn't:
  INSERT INTO func_index_heap VALUES('QWERTY');
  --
*************** CREATE UNIQUE INDEX CONCURRENTLY concur_
*** 600,605 ****
--- 602,608 ----
  -- 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"
diff -cpr head/src/test/regress/expected/inherit.out report_dupkey/src/test/regress/expected/inherit.out
*** head/src/test/regress/expected/inherit.out	2009-07-21 13:25:59.161085870 +0900
--- report_dupkey/src/test/regress/expected/inherit.out	2009-07-21 13:28:46.989122000 +0900
*************** NOTICE:  CREATE TABLE / PRIMARY KEY will
*** 638,643 ****
--- 638,644 ----
  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 */
*************** INSERT INTO inhg (xx, yy, x) VALUES ('te
*** 653,658 ****
--- 654,660 ----
  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
diff -cpr head/src/test/regress/expected/plpgsql.out report_dupkey/src/test/regress/expected/plpgsql.out
*** head/src/test/regress/expected/plpgsql.out	2009-07-21 13:25:59.164211909 +0900
--- report_dupkey/src/test/regress/expected/plpgsql.out	2009-07-21 13:28:55.247245000 +0900
*************** select * from PField_v1 where pfname = '
*** 1517,1522 ****
--- 1517,1523 ----
  --
  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
*************** ERROR:  illegal slotlink beginning with 
*** 1531,1536 ****
--- 1532,1538 ----
  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;
diff -cpr head/src/test/regress/expected/transactions.out report_dupkey/src/test/regress/expected/transactions.out
*** head/src/test/regress/expected/transactions.out	2009-07-21 13:25:59.167113594 +0900
--- report_dupkey/src/test/regress/expected/transactions.out	2009-07-21 13:28:48.185503000 +0900
*************** NOTICE:  CREATE TABLE / UNIQUE will crea
*** 468,479 ****
--- 468,481 ----
  		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;
diff -cpr head/src/test/regress/expected/uuid.out report_dupkey/src/test/regress/expected/uuid.out
*** head/src/test/regress/expected/uuid.out	2009-07-21 13:25:59.164211909 +0900
--- report_dupkey/src/test/regress/expected/uuid.out	2009-07-21 13:28:45.614492000 +0900
*************** CREATE UNIQUE INDEX guid1_unique_BTREE O
*** 119,124 ****
--- 119,125 ----
  -- 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 
diff -cpr head/src/test/regress/output/constraints.source report_dupkey/src/test/regress/output/constraints.source
*** head/src/test/regress/output/constraints.source	2009-07-21 13:25:59.159206402 +0900
--- report_dupkey/src/test/regress/output/constraints.source	2009-07-21 13:46:00.794458000 +0900
*************** INSERT INTO PRIMARY_TBL VALUES (1, 'one'
*** 294,299 ****
--- 294,300 ----
  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');
*************** INSERT INTO UNIQUE_TBL VALUES (1, 'one')
*** 338,343 ****
--- 339,345 ----
  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');
*************** INSERT INTO UNIQUE_TBL VALUES (2, 'two')
*** 362,367 ****
--- 364,370 ----
  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;
diff -cpr head/src/test/regress/output/tablespace.source report_dupkey/src/test/regress/output/tablespace.source
*** head/src/test/regress/output/tablespace.source	2009-07-21 13:25:59.159206402 +0900
--- report_dupkey/src/test/regress/output/tablespace.source	2009-07-21 13:45:22.251108818 +0900
*************** ALTER INDEX testschema.anindex SET TABLE
*** 49,54 ****
--- 49,55 ----
  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 
  -------