Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * dict_ispell.c
4 : : * Ispell dictionary interface
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : *
8 : : *
9 : : * IDENTIFICATION
10 : : * src/backend/tsearch/dict_ispell.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : : #include "postgres.h"
15 : :
16 : : #include "catalog/pg_collation_d.h"
17 : : #include "commands/defrem.h"
18 : : #include "tsearch/dicts/spell.h"
19 : : #include "tsearch/ts_public.h"
20 : : #include "utils/fmgrprotos.h"
21 : : #include "utils/formatting.h"
22 : :
23 : :
24 : : typedef struct
25 : : {
26 : : StopList stoplist;
27 : : IspellDict obj;
28 : : } DictISpell;
29 : :
30 : : Datum
31 : 20 : dispell_init(PG_FUNCTION_ARGS)
32 : : {
33 : 20 : List *dictoptions = (List *) PG_GETARG_POINTER(0);
34 : 20 : DictISpell *d;
35 : 40 : bool affloaded = false,
36 : 20 : dictloaded = false,
37 : 20 : stoploaded = false;
38 : 20 : ListCell *l;
39 : :
40 : 20 : d = palloc0_object(DictISpell);
41 : :
42 : 20 : NIStartBuild(&(d->obj));
43 : :
44 [ + - + + : 58 : foreach(l, dictoptions)
+ + ]
45 : : {
46 : 39 : DefElem *defel = (DefElem *) lfirst(l);
47 : :
48 [ + + ]: 39 : if (strcmp(defel->defname, "dictfile") == 0)
49 : : {
50 : 19 : char *filename;
51 : :
52 [ + - ]: 19 : if (dictloaded)
53 [ # # # # ]: 0 : ereport(ERROR,
54 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
55 : : errmsg("multiple DictFile parameters")));
56 : 19 : filename = get_tsearch_config_filename(defGetString(defel),
57 : : "dict");
58 : 19 : NIImportDictionary(&(d->obj), filename);
59 : 19 : pfree(filename);
60 : 19 : dictloaded = true;
61 : 19 : }
62 [ + + ]: 20 : else if (strcmp(defel->defname, "afffile") == 0)
63 : : {
64 : 19 : char *filename;
65 : :
66 [ + - ]: 19 : if (affloaded)
67 [ # # # # ]: 0 : ereport(ERROR,
68 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
69 : : errmsg("multiple AffFile parameters")));
70 : 19 : filename = get_tsearch_config_filename(defGetString(defel),
71 : : "affix");
72 : 19 : NIImportAffixes(&(d->obj), filename);
73 : 19 : pfree(filename);
74 : 19 : affloaded = true;
75 : 19 : }
76 [ - + ]: 1 : else if (strcmp(defel->defname, "stopwords") == 0)
77 : : {
78 [ # # ]: 0 : if (stoploaded)
79 [ # # # # ]: 0 : ereport(ERROR,
80 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
81 : : errmsg("multiple StopWords parameters")));
82 : 0 : readstoplist(defGetString(defel), &(d->stoplist), str_tolower);
83 : 0 : stoploaded = true;
84 : 0 : }
85 : : else
86 : : {
87 [ + - + - ]: 1 : ereport(ERROR,
88 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
89 : : errmsg("unrecognized Ispell parameter: \"%s\"",
90 : : defel->defname)));
91 : : }
92 : 38 : }
93 : :
94 [ + - ]: 19 : if (affloaded && dictloaded)
95 : : {
96 : 19 : NISortDictionary(&(d->obj));
97 : 19 : NISortAffixes(&(d->obj));
98 : 19 : }
99 [ # # ]: 0 : else if (!affloaded)
100 : : {
101 [ # # # # ]: 0 : ereport(ERROR,
102 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
103 : : errmsg("missing AffFile parameter")));
104 : 0 : }
105 : : else
106 : : {
107 [ # # # # ]: 0 : ereport(ERROR,
108 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
109 : : errmsg("missing DictFile parameter")));
110 : : }
111 : :
112 : 19 : NIFinishBuild(&(d->obj));
113 : :
114 : 38 : PG_RETURN_POINTER(d);
115 : 19 : }
116 : :
117 : : Datum
118 : 125 : dispell_lexize(PG_FUNCTION_ARGS)
119 : : {
120 : 125 : DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0);
121 : 125 : char *in = (char *) PG_GETARG_POINTER(1);
122 : 125 : int32 len = PG_GETARG_INT32(2);
123 : 125 : char *txt;
124 : 125 : TSLexeme *res;
125 : 125 : TSLexeme *ptr,
126 : : *cptr;
127 : :
128 [ - + ]: 125 : if (len <= 0)
129 : 0 : PG_RETURN_POINTER(NULL);
130 : :
131 : 125 : txt = str_tolower(in, len, DEFAULT_COLLATION_OID);
132 : 125 : res = NINormalizeWord(&(d->obj), txt);
133 : :
134 [ + + ]: 125 : if (res == NULL)
135 : 24 : PG_RETURN_POINTER(NULL);
136 : :
137 : 101 : cptr = res;
138 [ + + ]: 320 : for (ptr = cptr; ptr->lexeme; ptr++)
139 : : {
140 [ - + ]: 219 : if (searchstoplist(&(d->stoplist), ptr->lexeme))
141 : : {
142 : 0 : pfree(ptr->lexeme);
143 : 0 : ptr->lexeme = NULL;
144 : 0 : }
145 : : else
146 : : {
147 [ + - ]: 219 : if (cptr != ptr)
148 : 0 : memcpy(cptr, ptr, sizeof(TSLexeme));
149 : 219 : cptr++;
150 : : }
151 : 219 : }
152 : 101 : cptr->lexeme = NULL;
153 : :
154 : 101 : PG_RETURN_POINTER(res);
155 : 125 : }
|