char *buf2; /* 2nd string, or abbreviation strxfrm() buf */
int buflen1;
int buflen2;
+ bool collate_c;
hyperLogLogState abbr_card; /* Abbreviated key cardinality state */
hyperLogLogState full_card; /* Full key cardinality state */
#ifdef HAVE_LOCALE_T
btsortsupport_worker(SortSupport ssup, Oid collid)
{
bool abbreviate = ssup->abbreviate;
- bool locale_aware = false;
+ bool collate_c = false;
TextSortSupport *tss;
#ifdef HAVE_LOCALE_T
* bttextcmp() via the fmgr trampoline.
*/
if (lc_collate_is_c(collid))
+ {
ssup->comparator = bttextfastcmp_c;
+ collate_c = true;
+ }
#ifdef WIN32
else if (GetDatabaseEncoding() == PG_UTF8)
return;
else
{
ssup->comparator = bttextfastcmp_locale;
- locale_aware = true;
/*
* We need a collation-sensitive comparison. To make things faster,
errhint("Use the COLLATE clause to set the collation explicitly.")));
}
#ifdef HAVE_LOCALE_T
- tss->locale = pg_newlocale_from_collation(collid);
+ locale = pg_newlocale_from_collation(collid);
#endif
}
}
* will make use of the temporary buffers we initialize here for scratch
* space, and the abbreviation case requires additional state.
*/
- if (abbreviate || locale_aware)
+ if (abbreviate || !collate_c)
{
tss = palloc(sizeof(TextSortSupport));
tss->buf1 = palloc(TEXTBUFLEN);
#ifdef HAVE_LOCALE_T
tss->locale = locale;
#endif
+ tss->collate_c = collate_c;
ssup->ssup_extra = tss;
/*
memset(pres, 0, sizeof(Datum));
len = VARSIZE_ANY_EXHDR(authoritative);
- /* By convention, we use buffer 1 to store and NUL-terminate text */
- if (len >= tss->buflen1)
+ /*
+ * If we're using the C collation, use memcmp(), rather than strxfrm(),
+ * to abbreviated keys. The full comparator for the C locale is always
+ * memcmp(), and we can't risk having this give a different answer.
+ * Besides, this should be faster, too.
+ */
+ if (tss->collate_c)
+ memcpy(pres, VARDATA_ANY(authoritative), Min(len, sizeof(Datum)));
+ else
{
- pfree(tss->buf1);
- tss->buflen1 = Max(len + 1, Min(tss->buflen1 * 2, MaxAllocSize));
- tss->buf1 = palloc(tss->buflen1);
- }
+ /*
+ * We're not using the C collation, so fall back on strxfrm.
+ */
- /* Just like strcoll(), strxfrm() expects a NUL-terminated string */
- memcpy(tss->buf1, VARDATA_ANY(authoritative), len);
- tss->buf1[len] = '\0';
+ /* By convention, we use buffer 1 to store and NUL-terminate text */
+ if (len >= tss->buflen1)
+ {
+ pfree(tss->buf1);
+ tss->buflen1 = Max(len + 1, Min(tss->buflen1 * 2, MaxAllocSize));
+ tss->buf1 = palloc(tss->buflen1);
+ }
- /* Don't leak memory here */
- if (PointerGetDatum(authoritative) != original)
- pfree(authoritative);
+ /* Just like strcoll(), strxfrm() expects a NUL-terminated string */
+ memcpy(tss->buf1, VARDATA_ANY(authoritative), len);
+ tss->buf1[len] = '\0';
-retry:
+ /* Don't leak memory here */
+ if (PointerGetDatum(authoritative) != original)
+ pfree(authoritative);
- /*
- * There is no special handling of the C locale here, unlike with
- * varstr_cmp(). strxfrm() is used indifferently.
- */
+ for (;;)
+ {
#ifdef HAVE_LOCALE_T
- if (tss->locale)
- bsize = strxfrm_l(tss->buf2, tss->buf1, tss->buflen2, tss->locale);
- else
+ if (tss->locale)
+ bsize = strxfrm_l(tss->buf2, tss->buf1,
+ tss->buflen2, tss->locale);
+ else
#endif
- bsize = strxfrm(tss->buf2, tss->buf1, tss->buflen2);
+ bsize = strxfrm(tss->buf2, tss->buf1, tss->buflen2);
- if (bsize >= tss->buflen2)
- {
- /*
- * The C standard states that the contents of the buffer is now
- * unspecified. Grow buffer, and retry.
- */
- pfree(tss->buf2);
- tss->buflen2 = Max(bsize + 1, Min(tss->buflen2 * 2, MaxAllocSize));
- tss->buf2 = palloc(tss->buflen2);
- goto retry;
+ if (bsize < tss->buflen2)
+ break;
+
+ /*
+ * The C standard states that the contents of the buffer is now
+ * unspecified. Grow buffer, and retry.
+ */
+ pfree(tss->buf2);
+ tss->buflen2 = Max(bsize + 1,
+ Min(tss->buflen2 * 2, MaxAllocSize));
+ tss->buf2 = palloc(tss->buflen2);
+ }
}
/*