--- pgsql-clean/src/include/access/itup.h 2005-10-02 21:30:20.327464320 +0200 +++ pgsql-sort/src/include/access/itup.h 2005-10-02 16:04:00.000000000 +0200 @@ -126,6 +126,34 @@ ) \ ) +#define index_get_attr(tup, attnum, tupleDesc, attbyval, attlen, isnull) \ +( \ + AssertMacro(PointerIsValid(isnull) && (attnum) > 0), \ + *(isnull) = false, \ + !IndexTupleHasNulls(tup) ? \ + ( \ + (tupleDesc)->attrs[(attnum)-1]->attcacheoff >= 0 ? \ + ( \ + fetch_att((char *) (tup) + IndexInfoFindDataOffset((tup)->t_info) \ + + (tupleDesc)->attrs[(attnum)-1]->attcacheoff, attbyval, attlen) \ + ) \ + : \ + nocache_index_getattr((tup), (attnum), (tupleDesc), (isnull)) \ + ) \ + : \ + ( \ + (att_isnull((attnum)-1, (char *)(tup) + sizeof(IndexTupleData))) ? \ + ( \ + *(isnull) = true, \ + (Datum)NULL \ + ) \ + : \ + ( \ + nocache_index_getattr((tup), (attnum), (tupleDesc), (isnull)) \ + ) \ + ) \ +) + /* routines in indextuple.c */ extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor, --- pgsql-clean/src/backend/utils/sort/tuplesort.c 2005-09-24 23:23:39.000000000 +0200 +++ pgsql-sort/src/backend/utils/sort/tuplesort.c 2005-10-02 21:29:39.349086302 +0200 @@ -375,6 +375,8 @@ unsigned int len); static int comparetup_index(Tuplesortstate *state, const void *a, const void *b); +static int comparetup_index_fastbyval4(Tuplesortstate *state, + const void *a, const void *b); static void *copytup_index(Tuplesortstate *state, void *tup); static void writetup_index(Tuplesortstate *state, int tapenum, void *tup); static void *readtup_index(Tuplesortstate *state, int tapenum, @@ -498,8 +500,12 @@ int workMem, bool randomAccess) { Tuplesortstate *state = tuplesort_begin_common(workMem, randomAccess); + TupleDesc tupDes = RelationGetDescr(indexRel); - state->comparetup = comparetup_index; + if( tupDes->natts == 1 && tupDes->attrs[0]->attbyval == 1 && tupDes->attrs[0]->attlen == 4 ) + state->comparetup = comparetup_index_fastbyval4; + else + state->comparetup = comparetup_index; state->copytup = copytup_index; state->writetup = writetup_index; state->readtup = readtup_index; @@ -2102,6 +2108,92 @@ return 0; } +static int +comparetup_index_fastbyval4(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. Also see the special + * treatment for equal keys at the end. + */ + IndexTuple tuple1 = (IndexTuple) a; + IndexTuple tuple2 = (IndexTuple) b; + Relation rel = state->indexRel; + ScanKey scankey = state->indexScanKey; + TupleDesc tupDes; + bool equal_hasnull = false; + + tupDes = RelationGetDescr(rel); + + ScanKey entry = &scankey[0]; + Datum datum1, + datum2; + bool isnull1, + isnull2; + int32 compare; + + datum1 = index_get_attr(tuple1, 1, tupDes, 1, 4, &isnull1); + datum2 = index_get_attr(tuple2, 1, tupDes, 1, 4, &isnull2); + + /* see comments about NULLs handling in btbuild */ + + /* the comparison function is always of CMP type */ + compare = inlineApplySortFunction(&entry->sk_func, SORTFUNC_CMP, + datum1, isnull1, + datum2, isnull2); + + if (compare != 0) + return (int) compare; /* done when we find unequal + * attributes */ + + /* they are equal, so we only need to examine one null flag */ + if (isnull1) + equal_hasnull = true; + + /* + * If btree has asked us to enforce uniqueness, complain if two equal + * tuples are detected (unless there was at least one NULL field). + * + * It is sufficient to make the test here, because if two tuples are + * equal they *must* get compared at some stage of the sort --- + * otherwise the sort algorithm wouldn't have checked whether one must + * appear before the other. + * + * Some rather brain-dead implementations of qsort will sometimes call + * the comparison routine to compare a value to itself. (At this + * writing only QNX 4 is known to do such silly things.) Don't raise + * a bogus error in that case. + */ + if (state->enforceUnique && !equal_hasnull && tuple1 != tuple2) + ereport(ERROR, + (errcode(ERRCODE_UNIQUE_VIOLATION), + 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; +} + static void * copytup_index(Tuplesortstate *state, void *tup) {