diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c index 32fb32519ec..22f2c185370 100644 --- a/src/backend/access/gist/gistproc.c +++ b/src/backend/access/gist/gistproc.c @@ -37,7 +37,6 @@ static uint64 part_bits32_by2(uint32 x); static uint32 ieee_float32_to_uint32(float f); static int gist_bbox_zorder_cmp(Datum a, Datum b, SortSupport ssup); static Datum gist_bbox_zorder_abbrev_convert(Datum original, SortSupport ssup); -static int gist_bbox_zorder_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup); static bool gist_bbox_zorder_abbrev_abort(int memtupcount, SortSupport ssup); @@ -1726,21 +1725,6 @@ gist_bbox_zorder_abbrev_convert(Datum original, SortSupport ssup) #endif } -static int -gist_bbox_zorder_cmp_abbrev(Datum z1, Datum z2, SortSupport ssup) -{ - /* - * Compare the pre-computed Z-orders as unsigned integers. Datum is a - * typedef for 'uintptr_t', so no casting is required. - */ - if (z1 > z2) - return 1; - else if (z1 < z2) - return -1; - else - return 0; -} - /* * We never consider aborting the abbreviation. * @@ -1764,7 +1748,7 @@ gist_point_sortsupport(PG_FUNCTION_ARGS) if (ssup->abbreviate) { - ssup->comparator = gist_bbox_zorder_cmp_abbrev; + ssup->comparator = ssup_datum_unsigned_cmp; ssup->abbrev_converter = gist_bbox_zorder_abbrev_convert; ssup->abbrev_abort = gist_bbox_zorder_abbrev_abort; ssup->abbrev_full_comparator = gist_bbox_zorder_cmp; diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c index da4ce7b4f1f..40de3878fe5 100644 --- a/src/backend/access/nbtree/nbtcompare.c +++ b/src/backend/access/nbtree/nbtcompare.c @@ -119,26 +119,12 @@ btint4cmp(PG_FUNCTION_ARGS) PG_RETURN_INT32(A_LESS_THAN_B); } -static int -btint4fastcmp(Datum x, Datum y, SortSupport ssup) -{ - int32 a = DatumGetInt32(x); - int32 b = DatumGetInt32(y); - - if (a > b) - return A_GREATER_THAN_B; - else if (a == b) - return 0; - else - return A_LESS_THAN_B; -} - Datum btint4sortsupport(PG_FUNCTION_ARGS) { SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); - ssup->comparator = btint4fastcmp; + ssup->comparator = ssup_datum_int32_cmp; PG_RETURN_VOID(); } @@ -156,6 +142,7 @@ btint8cmp(PG_FUNCTION_ARGS) PG_RETURN_INT32(A_LESS_THAN_B); } +#ifndef USE_FLOAT8_BYVAL static int btint8fastcmp(Datum x, Datum y, SortSupport ssup) { @@ -169,13 +156,18 @@ btint8fastcmp(Datum x, Datum y, SortSupport ssup) else return A_LESS_THAN_B; } +#endif Datum btint8sortsupport(PG_FUNCTION_ARGS) { SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); +#ifdef USE_FLOAT8_BYVAL + ssup->comparator = ssup_datum_signed_cmp; +#else ssup->comparator = btint8fastcmp; +#endif PG_RETURN_VOID(); } diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index fee610916f7..081dfa2450f 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -439,25 +439,12 @@ date_cmp(PG_FUNCTION_ARGS) PG_RETURN_INT32(0); } -static int -date_fastcmp(Datum x, Datum y, SortSupport ssup) -{ - DateADT a = DatumGetDateADT(x); - DateADT b = DatumGetDateADT(y); - - if (a < b) - return -1; - else if (a > b) - return 1; - return 0; -} - Datum date_sortsupport(PG_FUNCTION_ARGS) { SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); - ssup->comparator = date_fastcmp; + ssup->comparator = ssup_datum_int32_cmp; PG_RETURN_VOID(); } diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c index 88a1698cf96..ac7342cfca7 100644 --- a/src/backend/utils/adt/mac.c +++ b/src/backend/utils/adt/mac.c @@ -44,7 +44,6 @@ typedef struct static int macaddr_cmp_internal(macaddr *a1, macaddr *a2); static int macaddr_fast_cmp(Datum x, Datum y, SortSupport ssup); -static int macaddr_cmp_abbrev(Datum x, Datum y, SortSupport ssup); static bool macaddr_abbrev_abort(int memtupcount, SortSupport ssup); static Datum macaddr_abbrev_convert(Datum original, SortSupport ssup); @@ -381,7 +380,7 @@ macaddr_sortsupport(PG_FUNCTION_ARGS) ssup->ssup_extra = uss; - ssup->comparator = macaddr_cmp_abbrev; + ssup->comparator = ssup_datum_unsigned_cmp; ssup->abbrev_converter = macaddr_abbrev_convert; ssup->abbrev_abort = macaddr_abbrev_abort; ssup->abbrev_full_comparator = macaddr_fast_cmp; @@ -405,22 +404,6 @@ macaddr_fast_cmp(Datum x, Datum y, SortSupport ssup) return macaddr_cmp_internal(arg1, arg2); } -/* - * SortSupport abbreviated key comparison function. Compares two MAC addresses - * quickly by treating them like integers, and without having to go to the - * heap. - */ -static int -macaddr_cmp_abbrev(Datum x, Datum y, SortSupport ssup) -{ - if (x > y) - return 1; - else if (x == y) - return 0; - else - return -1; -} - /* * Callback for estimating effectiveness of abbreviated key optimization. * @@ -537,8 +520,8 @@ macaddr_abbrev_convert(Datum original, SortSupport ssup) /* * Byteswap on little-endian machines. * - * This is needed so that macaddr_cmp_abbrev() (an unsigned integer 3-way - * comparator) works correctly on all platforms. Without this, the + * This is needed so that ssup_datum_unsigned_cmp() (an unsigned integer + * 3-way comparator) works correctly on all platforms. Without this, the * comparator would have to call memcmp() with a pair of pointers to the * first byte of each abbreviated key, which is slower. */ diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index 0ab54316f8e..ea1c7390d0d 100644 --- a/src/backend/utils/adt/network.c +++ b/src/backend/utils/adt/network.c @@ -53,7 +53,6 @@ typedef struct static int32 network_cmp_internal(inet *a1, inet *a2); static int network_fast_cmp(Datum x, Datum y, SortSupport ssup); -static int network_cmp_abbrev(Datum x, Datum y, SortSupport ssup); static bool network_abbrev_abort(int memtupcount, SortSupport ssup); static Datum network_abbrev_convert(Datum original, SortSupport ssup); static List *match_network_function(Node *leftop, @@ -456,7 +455,7 @@ network_sortsupport(PG_FUNCTION_ARGS) ssup->ssup_extra = uss; - ssup->comparator = network_cmp_abbrev; + ssup->comparator = ssup_datum_unsigned_cmp; ssup->abbrev_converter = network_abbrev_convert; ssup->abbrev_abort = network_abbrev_abort; ssup->abbrev_full_comparator = network_fast_cmp; @@ -479,20 +478,6 @@ network_fast_cmp(Datum x, Datum y, SortSupport ssup) return network_cmp_internal(arg1, arg2); } -/* - * Abbreviated key comparison func - */ -static int -network_cmp_abbrev(Datum x, Datum y, SortSupport ssup) -{ - if (x > y) - return 1; - else if (x == y) - return 0; - else - return -1; -} - /* * Callback for estimating effectiveness of abbreviated key optimization. * diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index ae36ff33285..2ba8d41284f 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -37,6 +37,7 @@ #include "utils/datetime.h" #include "utils/float.h" #include "utils/numeric.h" +#include "utils/sortsupport.h" /* * gcc's -ffast-math switch breaks routines that expect exact results from @@ -2155,6 +2156,7 @@ timestamp_cmp(PG_FUNCTION_ARGS) PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2)); } +#ifndef USE_FLOAT8_BYVAL /* note: this is used for timestamptz also */ static int timestamp_fastcmp(Datum x, Datum y, SortSupport ssup) @@ -2164,13 +2166,22 @@ timestamp_fastcmp(Datum x, Datum y, SortSupport ssup) return timestamp_cmp_internal(a, b); } +#endif Datum timestamp_sortsupport(PG_FUNCTION_ARGS) { SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); +#ifdef USE_FLOAT8_BYVAL + /* + * If this build has pass-by-value timestamps, then we can use a standard + * comparator function. + */ + ssup->comparator = ssup_datum_signed_cmp; +#else ssup->comparator = timestamp_fastcmp; +#endif PG_RETURN_VOID(); } diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c index 9e06d9ba123..a157f864e12 100644 --- a/src/backend/utils/adt/uuid.c +++ b/src/backend/utils/adt/uuid.c @@ -34,7 +34,6 @@ typedef struct static void string_to_uuid(const char *source, pg_uuid_t *uuid); static int uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2); static int uuid_fast_cmp(Datum x, Datum y, SortSupport ssup); -static int uuid_cmp_abbrev(Datum x, Datum y, SortSupport ssup); static bool uuid_abbrev_abort(int memtupcount, SortSupport ssup); static Datum uuid_abbrev_convert(Datum original, SortSupport ssup); @@ -255,7 +254,7 @@ uuid_sortsupport(PG_FUNCTION_ARGS) ssup->ssup_extra = uss; - ssup->comparator = uuid_cmp_abbrev; + ssup->comparator = ssup_datum_unsigned_cmp; ssup->abbrev_converter = uuid_abbrev_convert; ssup->abbrev_abort = uuid_abbrev_abort; ssup->abbrev_full_comparator = uuid_fast_cmp; @@ -278,20 +277,6 @@ uuid_fast_cmp(Datum x, Datum y, SortSupport ssup) return uuid_internal_cmp(arg1, arg2); } -/* - * Abbreviated key comparison func - */ -static int -uuid_cmp_abbrev(Datum x, Datum y, SortSupport ssup) -{ - if (x > y) - return 1; - else if (x == y) - return 0; - else - return -1; -} - /* * Callback for estimating effectiveness of abbreviated key optimization. * @@ -390,10 +375,10 @@ uuid_abbrev_convert(Datum original, SortSupport ssup) /* * Byteswap on little-endian machines. * - * This is needed so that uuid_cmp_abbrev() (an unsigned integer 3-way - * comparator) works correctly on all platforms. If we didn't do this, - * the comparator would have to call memcmp() with a pair of pointers to - * the first byte of each abbreviated key, which is slower. + * This is needed so that ssup_datum_unsigned_cmp() (an unsigned integer + * 3-way comparator) works correctly on all platforms. If we didn't do + * this, the comparator would have to call memcmp() with a pair of pointers + * to the first byte of each abbreviated key, which is slower. */ res = DatumBigEndianToNative(res); diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 22ab5a4329f..cfc135c7beb 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -126,7 +126,6 @@ static int namefastcmp_c(Datum x, Datum y, SortSupport ssup); static int varlenafastcmp_locale(Datum x, Datum y, SortSupport ssup); static int namefastcmp_locale(Datum x, Datum y, SortSupport ssup); static int varstrfastcmp_locale(char *a1p, int len1, char *a2p, int len2, SortSupport ssup); -static int varstrcmp_abbrev(Datum x, Datum y, SortSupport ssup); static Datum varstr_abbrev_convert(Datum original, SortSupport ssup); static bool varstr_abbrev_abort(int memtupcount, SortSupport ssup); static int32 text_length(Datum str); @@ -2159,7 +2158,7 @@ varstr_sortsupport(SortSupport ssup, Oid typid, Oid collid) initHyperLogLog(&sss->abbr_card, 10); initHyperLogLog(&sss->full_card, 10); ssup->abbrev_full_comparator = ssup->comparator; - ssup->comparator = varstrcmp_abbrev; + ssup->comparator = ssup_datum_unsigned_cmp; ssup->abbrev_converter = varstr_abbrev_convert; ssup->abbrev_abort = varstr_abbrev_abort; } @@ -2445,27 +2444,6 @@ varstrfastcmp_locale(char *a1p, int len1, char *a2p, int len2, SortSupport ssup) return result; } -/* - * Abbreviated key comparison func - */ -static int -varstrcmp_abbrev(Datum x, Datum y, SortSupport ssup) -{ - /* - * When 0 is returned, the core system will call varstrfastcmp_c() - * (bpcharfastcmp_c() in BpChar case) or varlenafastcmp_locale(). Even a - * strcmp() on two non-truncated strxfrm() blobs cannot indicate *equality* - * authoritatively, for the same reason that there is a strcoll() - * tie-breaker call to strcmp() in varstr_cmp(). - */ - if (x > y) - return 1; - else if (x == y) - return 0; - else - return -1; -} - /* * Conversion routine for sortsupport. Converts original to abbreviated key * representation. Our encoding strategy is simple -- pack the first 8 bytes @@ -2504,7 +2482,7 @@ varstr_abbrev_convert(Datum original, SortSupport ssup) * strings may contain NUL bytes. Besides, this should be faster, too. * * More generally, it's okay that bytea callers can have NUL bytes in - * strings because varstrcmp_abbrev() need not make a distinction between + * strings because abbreviated cmp need not make a distinction between * terminating NUL bytes, and NUL bytes representing actual NULs in the * authoritative representation. Hopefully a comparison at or past one * abbreviated key's terminating NUL byte will resolve the comparison @@ -2694,10 +2672,10 @@ done: /* * Byteswap on little-endian machines. * - * This is needed so that varstrcmp_abbrev() (an unsigned integer 3-way - * comparator) works correctly on all platforms. If we didn't do this, - * the comparator would have to call memcmp() with a pair of pointers to - * the first byte of each abbreviated key, which is slower. + * This is needed so that ssup_datum_unsigned_cmp() (an unsigned integer + * 3-way comparator) works correctly on all platforms. If we didn't do + * this, the comparator would have to call memcmp() with a pair of pointers + * to the first byte of each abbreviated key, which is slower. */ res = DatumBigEndianToNative(res); diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index 086e948fca6..361527098f9 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -669,14 +669,101 @@ static void free_sort_tuple(Tuplesortstate *state, SortTuple *stup); static void tuplesort_free(Tuplesortstate *state); static void tuplesort_updatemax(Tuplesortstate *state); +/* + * Specialized comparators that we can inline into specialized sorts. The goal + * is to try to sort two tuples without having to follow the pointers to the + * comparator or the tuple. + * + * XXX: For now, these fall back to comparator functions that will compare the + * leading datum a second time. + * + * XXX: For now, there is no specialization for cases where datum1 is + * authoritative and we don't even need to fall back to a callback at all (that + * would be true for types like int4/int8/timestamp/date, but not true for + * abbreviations of text or multi-key sorts. There could be! Is it worth it? + */ + +/* Used if first key's comparator is ssup_datum_unsigned_compare */ +static pg_attribute_always_inline int +qsort_tuple_unsigned_compare(SortTuple *a, SortTuple *b, Tuplesortstate *state) +{ + int compare; + + compare = ApplyUnsignedSortComparator(a->datum1, a->isnull1, + b->datum1, b->isnull1, + &state->sortKeys[0]); + if (compare != 0) + return compare; + + return state->comparetup(a, b, state); +} + +/* Used if first key's comparator is ssup_datum_signed_compare */ +static pg_attribute_always_inline int +qsort_tuple_signed_compare(SortTuple *a, SortTuple *b, Tuplesortstate *state) +{ + int compare; + + compare = ApplySignedSortComparator(a->datum1, a->isnull1, + b->datum1, b->isnull1, + &state->sortKeys[0]); + if (compare != 0) + return compare; + + return state->comparetup(a, b, state); +} + +/* Used if first key's comparator is ssup_datum_int32_compare */ +static pg_attribute_always_inline int +qsort_tuple_int32_compare(SortTuple *a, SortTuple *b, Tuplesortstate *state) +{ + int compare; + + compare = ApplyInt32SortComparator(a->datum1, a->isnull1, + b->datum1, b->isnull1, + &state->sortKeys[0]); + if (compare != 0) + return compare; + + return state->comparetup(a, b, state); +} + /* * Special versions of qsort just for SortTuple objects. qsort_tuple() sorts * any variant of SortTuples, using the appropriate comparetup function. * qsort_ssup() is specialized for the case where the comparetup function * reduces to ApplySortComparator(), that is single-key MinimalTuple sorts - * and Datum sorts. + * and Datum sorts. qsort_tuple_{unsigned,signed,int32} are specialized for + * common comparison functions on pass-by-value leading datums. */ +#define ST_SORT qsort_tuple_unsigned +#define ST_ELEMENT_TYPE SortTuple +#define ST_COMPARE(a, b, state) qsort_tuple_unsigned_compare(a, b, state) +#define ST_COMPARE_ARG_TYPE Tuplesortstate +#define ST_CHECK_FOR_INTERRUPTS +#define ST_SCOPE static +#define ST_DEFINE +#include "lib/sort_template.h" + +#define ST_SORT qsort_tuple_signed +#define ST_ELEMENT_TYPE SortTuple +#define ST_COMPARE(a, b, state) qsort_tuple_signed_compare(a, b, state) +#define ST_COMPARE_ARG_TYPE Tuplesortstate +#define ST_CHECK_FOR_INTERRUPTS +#define ST_SCOPE static +#define ST_DEFINE +#include "lib/sort_template.h" + +#define ST_SORT qsort_tuple_int32 +#define ST_ELEMENT_TYPE SortTuple +#define ST_COMPARE(a, b, state) qsort_tuple_int32_compare(a, b, state) +#define ST_COMPARE_ARG_TYPE Tuplesortstate +#define ST_CHECK_FOR_INTERRUPTS +#define ST_SCOPE static +#define ST_DEFINE +#include "lib/sort_template.h" + #define ST_SORT qsort_tuple #define ST_ELEMENT_TYPE SortTuple #define ST_COMPARE_RUNTIME_POINTER @@ -3506,15 +3593,40 @@ tuplesort_sort_memtuples(Tuplesortstate *state) if (state->memtupcount > 1) { + /* Do we have a specialization for the leading column's comparator? */ + if (state->sortKeys && + state->sortKeys[0].comparator == ssup_datum_unsigned_cmp) + { + elog(DEBUG1, "qsort_tuple_unsigned"); + qsort_tuple_unsigned(state->memtuples, state->memtupcount, state); + } + else if (state->sortKeys && + state->sortKeys[0].comparator == ssup_datum_signed_cmp) + { + elog(DEBUG1, "qsort_tuple_signed"); + qsort_tuple_signed(state->memtuples, state->memtupcount, state); + } + else if (state->sortKeys && + state->sortKeys[0].comparator == ssup_datum_int32_cmp) + { + elog(DEBUG1, "qsort_tuple_int32"); + qsort_tuple_int32(state->memtuples, state->memtupcount, state); + } /* Can we use the single-key sort function? */ - if (state->onlyKey != NULL) + else if (state->onlyKey != NULL) + { + elog(DEBUG1, "qsort_ssup"); qsort_ssup(state->memtuples, state->memtupcount, state->onlyKey); + } else + { + elog(DEBUG1, "qsort_tuple"); qsort_tuple(state->memtuples, state->memtupcount, state->comparetup, state); + } } } @@ -4700,3 +4812,47 @@ free_sort_tuple(Tuplesortstate *state, SortTuple *stup) stup->tuple = NULL; } } + +int +ssup_datum_unsigned_cmp(Datum x, Datum y, SortSupport ssup) +{ + if (x < y) + return -1; + else if (x > y) + return 1; + else + return 0; +} + +int +ssup_datum_signed_cmp(Datum x, Datum y, SortSupport ssup) +{ +#if SIZEOF_DATUM == 8 + int64 xx = (int64) x; + int64 yy = (int64) y; +#else + int32 xx = (int32) x; + int32 yy = (int32) y; +#endif + + if (xx < yy) + return -1; + else if (xx > yy) + return 1; + else + return 0; +} + +int +ssup_datum_int32_cmp(Datum x, Datum y, SortSupport ssup) +{ + int32 xx = (int32) x; + int32 yy = (int32) y; + + if (xx < yy) + return -1; + else if (xx > yy) + return 1; + else + return 0; +} diff --git a/src/include/utils/sortsupport.h b/src/include/utils/sortsupport.h index 6e3cab82d25..60e5f9940d4 100644 --- a/src/include/utils/sortsupport.h +++ b/src/include/utils/sortsupport.h @@ -229,6 +229,112 @@ ApplySortComparator(Datum datum1, bool isNull1, return compare; } +static inline int +ApplyUnsignedSortComparator(Datum datum1, bool isNull1, + Datum datum2, bool isNull2, + SortSupport ssup) +{ + int compare; + + if (isNull1) + { + if (isNull2) + compare = 0; /* NULL "=" NULL */ + else if (ssup->ssup_nulls_first) + compare = -1; /* NULL "<" NOT_NULL */ + else + compare = 1; /* NULL ">" NOT_NULL */ + } + else if (isNull2) + { + if (ssup->ssup_nulls_first) + compare = 1; /* NOT_NULL ">" NULL */ + else + compare = -1; /* NOT_NULL "<" NULL */ + } + else + { + compare = datum1 < datum2 ? -1 : datum1 > datum2 ? 1 : 0; + if (ssup->ssup_reverse) + INVERT_COMPARE_RESULT(compare); + } + + return compare; +} + +static inline int +ApplySignedSortComparator(Datum datum1, bool isNull1, + Datum datum2, bool isNull2, + SortSupport ssup) +{ + int compare; + + if (isNull1) + { + if (isNull2) + compare = 0; /* NULL "=" NULL */ + else if (ssup->ssup_nulls_first) + compare = -1; /* NULL "<" NOT_NULL */ + else + compare = 1; /* NULL ">" NOT_NULL */ + } + else if (isNull2) + { + if (ssup->ssup_nulls_first) + compare = 1; /* NOT_NULL ">" NULL */ + else + compare = -1; /* NOT_NULL "<" NULL */ + } + else + { +#if SIZEOF_DATUM == 8 + compare = (int64) datum1 < (int64) datum2 ? -1 : + (int64) datum1 > (int64) datum2 ? 1 : 0; +#else + compare = (int32) datum1 < (int32) datum2 ? -1 : + (int32) datum1 > (int32) datum2 ? 1 : 0; +#endif + if (ssup->ssup_reverse) + INVERT_COMPARE_RESULT(compare); + } + + return compare; +} + +static inline int +ApplyInt32SortComparator(Datum datum1, bool isNull1, + Datum datum2, bool isNull2, + SortSupport ssup) +{ + int compare; + + if (isNull1) + { + if (isNull2) + compare = 0; /* NULL "=" NULL */ + else if (ssup->ssup_nulls_first) + compare = -1; /* NULL "<" NOT_NULL */ + else + compare = 1; /* NULL ">" NOT_NULL */ + } + else if (isNull2) + { + if (ssup->ssup_nulls_first) + compare = 1; /* NOT_NULL ">" NULL */ + else + compare = -1; /* NOT_NULL "<" NULL */ + } + else + { + compare = (int32) datum1 < (int32) datum2 ? -1 : + (int32) datum1 > (int32) datum2 ? 1 : 0; + if (ssup->ssup_reverse) + INVERT_COMPARE_RESULT(compare); + } + + return compare; +} + /* * Apply a sort comparator function and return a 3-way comparison using full, * authoritative comparator. This takes care of handling reverse-sort and @@ -267,6 +373,15 @@ ApplySortAbbrevFullComparator(Datum datum1, bool isNull1, return compare; } +/* + * Datum comparison functions that we have specialized sort routines for. + * Datatypes that install these as their comparator or abbrevated comparator + * are eligible for faster sorting. + */ +extern int ssup_datum_unsigned_cmp(Datum x, Datum y, SortSupport ssup); +extern int ssup_datum_signed_cmp(Datum x, Datum y, SortSupport ssup); +extern int ssup_datum_int32_cmp(Datum x, Datum y, SortSupport ssup); + /* Other functions in utils/sort/sortsupport.c */ extern void PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup); extern void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup);