1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-18 02:02:55 +03:00
Files
postgres/src/backend/tsearch/dict_ispell.c
Tom Lane 7f6ededa76 Suppress complaints about leaks in TS dictionary loading.
Like the situation with function cache loading, text search
dictionary loading functions tend to leak some cruft into the
dictionary's long-lived cache context.  To judge by the examples in
the core regression tests, not very many bytes are at stake.
Moreover, I don't see a way to prevent such leaks without changing the
API for TS template initialization functions: right now they do not
have to worry about making sure that their results are long-lived.

Hence, I think we should install a suppression rule rather than trying
to fix this completely.  However, I did grab some low-hanging fruit:
several places were leaking the result of get_tsearch_config_filename.
This seems worth doing mostly because they are inconsistent with other
dictionaries that were freeing it already.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/285483.1746756246@sss.pgh.pa.us
2025-08-02 21:59:46 -04:00

156 lines
3.3 KiB
C

/*-------------------------------------------------------------------------
*
* dict_ispell.c
* Ispell dictionary interface
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
* src/backend/tsearch/dict_ispell.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/pg_collation_d.h"
#include "commands/defrem.h"
#include "tsearch/dicts/spell.h"
#include "tsearch/ts_public.h"
#include "utils/fmgrprotos.h"
#include "utils/formatting.h"
typedef struct
{
StopList stoplist;
IspellDict obj;
} DictISpell;
Datum
dispell_init(PG_FUNCTION_ARGS)
{
List *dictoptions = (List *) PG_GETARG_POINTER(0);
DictISpell *d;
bool affloaded = false,
dictloaded = false,
stoploaded = false;
ListCell *l;
d = (DictISpell *) palloc0(sizeof(DictISpell));
NIStartBuild(&(d->obj));
foreach(l, dictoptions)
{
DefElem *defel = (DefElem *) lfirst(l);
if (strcmp(defel->defname, "dictfile") == 0)
{
char *filename;
if (dictloaded)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("multiple DictFile parameters")));
filename = get_tsearch_config_filename(defGetString(defel),
"dict");
NIImportDictionary(&(d->obj), filename);
pfree(filename);
dictloaded = true;
}
else if (strcmp(defel->defname, "afffile") == 0)
{
char *filename;
if (affloaded)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("multiple AffFile parameters")));
filename = get_tsearch_config_filename(defGetString(defel),
"affix");
NIImportAffixes(&(d->obj), filename);
pfree(filename);
affloaded = true;
}
else if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("multiple StopWords parameters")));
readstoplist(defGetString(defel), &(d->stoplist), str_tolower);
stoploaded = true;
}
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized Ispell parameter: \"%s\"",
defel->defname)));
}
}
if (affloaded && dictloaded)
{
NISortDictionary(&(d->obj));
NISortAffixes(&(d->obj));
}
else if (!affloaded)
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("missing AffFile parameter")));
}
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("missing DictFile parameter")));
}
NIFinishBuild(&(d->obj));
PG_RETURN_POINTER(d);
}
Datum
dispell_lexize(PG_FUNCTION_ARGS)
{
DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0);
char *in = (char *) PG_GETARG_POINTER(1);
int32 len = PG_GETARG_INT32(2);
char *txt;
TSLexeme *res;
TSLexeme *ptr,
*cptr;
if (len <= 0)
PG_RETURN_POINTER(NULL);
txt = str_tolower(in, len, DEFAULT_COLLATION_OID);
res = NINormalizeWord(&(d->obj), txt);
if (res == NULL)
PG_RETURN_POINTER(NULL);
cptr = res;
for (ptr = cptr; ptr->lexeme; ptr++)
{
if (searchstoplist(&(d->stoplist), ptr->lexeme))
{
pfree(ptr->lexeme);
ptr->lexeme = NULL;
}
else
{
if (cptr != ptr)
memcpy(cptr, ptr, sizeof(TSLexeme));
cptr++;
}
}
cptr->lexeme = NULL;
PG_RETURN_POINTER(res);
}