mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-15 08:20:16 +08:00
More fixes for abbreviated keys infrastructure.
First, when LC_COLLATE = C, bttext_abbrev_convert should use memcpy() rather than strxfrm() to construct the abbreviated key, because the authoritative comparator uses memcpy(). If we do anything else here, we might get inconsistent answers, and the buildfarm says this risk is not theoretical. It should be faster this way, too. Second, while I'm looking at bttext_abbrev_convert, convert a needless use of goto into the loop it's trying to implement into an actual loop. Both of the above problems date to the original commit of abbreviated keys, commit4ea51cdfe8
. Third, fix a bogus assignment to tss->locale before tss is set up. That's a new goof in commitb529b65d1b
.
This commit is contained in:
parent
b529b65d1b
commit
b181a91981
@ -63,6 +63,7 @@ typedef struct
|
||||
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
|
||||
@ -1744,7 +1745,7 @@ static void
|
||||
btsortsupport_worker(SortSupport ssup, Oid collid)
|
||||
{
|
||||
bool abbreviate = ssup->abbreviate;
|
||||
bool locale_aware = false;
|
||||
bool collate_c = false;
|
||||
TextSortSupport *tss;
|
||||
|
||||
#ifdef HAVE_LOCALE_T
|
||||
@ -1769,7 +1770,10 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
|
||||
* 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;
|
||||
@ -1777,7 +1781,6 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
|
||||
else
|
||||
{
|
||||
ssup->comparator = bttextfastcmp_locale;
|
||||
locale_aware = true;
|
||||
|
||||
/*
|
||||
* We need a collation-sensitive comparison. To make things faster,
|
||||
@ -1798,7 +1801,7 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -1828,7 +1831,7 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
|
||||
* 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);
|
||||
@ -1838,6 +1841,7 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
|
||||
#ifdef HAVE_LOCALE_T
|
||||
tss->locale = locale;
|
||||
#endif
|
||||
tss->collate_c = collate_c;
|
||||
ssup->ssup_extra = tss;
|
||||
|
||||
/*
|
||||
@ -2011,45 +2015,58 @@ bttext_abbrev_convert(Datum original, SortSupport ssup)
|
||||
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)
|
||||
{
|
||||
pfree(tss->buf1);
|
||||
tss->buflen1 = Max(len + 1, Min(tss->buflen1 * 2, MaxAllocSize));
|
||||
tss->buf1 = palloc(tss->buflen1);
|
||||
}
|
||||
|
||||
/* Just like strcoll(), strxfrm() expects a NUL-terminated string */
|
||||
memcpy(tss->buf1, VARDATA_ANY(authoritative), len);
|
||||
tss->buf1[len] = '\0';
|
||||
|
||||
/* Don't leak memory here */
|
||||
if (PointerGetDatum(authoritative) != original)
|
||||
pfree(authoritative);
|
||||
|
||||
retry:
|
||||
|
||||
/*
|
||||
* There is no special handling of the C locale here, unlike with
|
||||
* varstr_cmp(). strxfrm() is used indifferently.
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_LOCALE_T
|
||||
if (tss->locale)
|
||||
bsize = strxfrm_l(tss->buf2, tss->buf1, tss->buflen2, tss->locale);
|
||||
if (tss->collate_c)
|
||||
memcpy(pres, VARDATA_ANY(authoritative), Min(len, sizeof(Datum)));
|
||||
else
|
||||
#endif
|
||||
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.
|
||||
* We're not using the C collation, so fall back on strxfrm.
|
||||
*/
|
||||
pfree(tss->buf2);
|
||||
tss->buflen2 = Max(bsize + 1, Min(tss->buflen2 * 2, MaxAllocSize));
|
||||
tss->buf2 = palloc(tss->buflen2);
|
||||
goto retry;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Just like strcoll(), strxfrm() expects a NUL-terminated string */
|
||||
memcpy(tss->buf1, VARDATA_ANY(authoritative), len);
|
||||
tss->buf1[len] = '\0';
|
||||
|
||||
/* Don't leak memory here */
|
||||
if (PointerGetDatum(authoritative) != original)
|
||||
pfree(authoritative);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
#ifdef HAVE_LOCALE_T
|
||||
if (tss->locale)
|
||||
bsize = strxfrm_l(tss->buf2, tss->buf1,
|
||||
tss->buflen2, tss->locale);
|
||||
else
|
||||
#endif
|
||||
bsize = strxfrm(tss->buf2, tss->buf1, tss->buflen2);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user