diff --git a/contrib/unaccent/unaccent.c b/contrib/unaccent/unaccent.c index c7d54b205e..7c4072ed93 100644 --- a/contrib/unaccent/unaccent.c +++ b/contrib/unaccent/unaccent.c @@ -15,6 +15,7 @@ #include "catalog/namespace.h" #include "commands/defrem.h" +#include "lib/stringinfo.h" #include "tsearch/ts_cache.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_public.h" @@ -309,9 +310,12 @@ unaccent_lexize(PG_FUNCTION_ARGS) TrieChar *rootTrie = (TrieChar *) PG_GETARG_POINTER(0); char *srcchar = (char *) PG_GETARG_POINTER(1); int32 len = PG_GETARG_INT32(2); - char *srcstart = srcchar, - *trgchar = NULL; - TSLexeme *res = NULL; + char *srcstart = srcchar; + TSLexeme *res; + StringInfoData buf; + + /* we allocate storage for the buffer only if needed */ + buf.data = NULL; while (len > 0) { @@ -322,37 +326,36 @@ unaccent_lexize(PG_FUNCTION_ARGS) &matchlen); if (node && node->replaceTo) { - if (!res) + if (buf.data == NULL) { - /* allocate res only if it's needed */ - res = palloc0(sizeof(TSLexeme) * 2); - res->lexeme = trgchar = palloc(len * pg_database_encoding_max_length() + 1 /* \0 */ ); - res->flags = TSL_FILTER; + /* initialize buffer */ + initStringInfo(&buf); + /* insert any data we already skipped over */ if (srcchar != srcstart) - { - memcpy(trgchar, srcstart, srcchar - srcstart); - trgchar += (srcchar - srcstart); - } + appendBinaryStringInfo(&buf, srcstart, srcchar - srcstart); } - memcpy(trgchar, node->replaceTo, node->replacelen); - trgchar += node->replacelen; + appendBinaryStringInfo(&buf, node->replaceTo, node->replacelen); } else { matchlen = pg_mblen(srcchar); - if (res) - { - memcpy(trgchar, srcchar, matchlen); - trgchar += matchlen; - } + if (buf.data != NULL) + appendBinaryStringInfo(&buf, srcchar, matchlen); } srcchar += matchlen; len -= matchlen; } - if (res) - *trgchar = '\0'; + /* return a result only if we made at least one substitution */ + if (buf.data != NULL) + { + res = (TSLexeme *) palloc0(sizeof(TSLexeme) * 2); + res->lexeme = buf.data; + res->flags = TSL_FILTER; + } + else + res = NULL; PG_RETURN_POINTER(res); }