aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/sort/tuplesort.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 636fdedcdb4..549ca8c484e 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -78,7 +78,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.41 2004/02/03 17:34:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.42 2004/03/17 22:24:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2020,7 +2020,8 @@ comparetup_index(Tuplesortstate *state, const void *a, const void *b)
{
/*
* This is almost the same as _bt_tuplecompare(), but we need to keep
- * track of whether any null fields are present.
+ * track of whether any null fields are present. Also see the special
+ * treatment for equal keys at the end.
*/
IndexTuple tuple1 = (IndexTuple) a;
IndexTuple tuple2 = (IndexTuple) b;
@@ -2081,6 +2082,27 @@ comparetup_index(Tuplesortstate *state, const void *a, const void *b)
errmsg("could not create unique index"),
errdetail("Table contains duplicated values.")));
+ /*
+ * If key values are equal, we sort on ItemPointer. This does not
+ * affect validity of the finished index, but it offers cheap insurance
+ * against performance problems with bad qsort implementations that have
+ * trouble with large numbers of equal keys.
+ */
+ {
+ BlockNumber blk1 = ItemPointerGetBlockNumber(&tuple1->t_tid);
+ BlockNumber blk2 = ItemPointerGetBlockNumber(&tuple2->t_tid);
+
+ if (blk1 != blk2)
+ return (blk1 < blk2) ? -1 : 1;
+ }
+ {
+ OffsetNumber pos1 = ItemPointerGetOffsetNumber(&tuple1->t_tid);
+ OffsetNumber pos2 = ItemPointerGetOffsetNumber(&tuple2->t_tid);
+
+ if (pos1 != pos2)
+ return (pos1 < pos2) ? -1 : 1;
+ }
+
return 0;
}