/src/postgres/src/backend/tsearch/dict_ispell.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * dict_ispell.c |
4 | | * Ispell dictionary interface |
5 | | * |
6 | | * Portions Copyright (c) 1996-2025, 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 | | dispell_init(PG_FUNCTION_ARGS) |
32 | 0 | { |
33 | 0 | List *dictoptions = (List *) PG_GETARG_POINTER(0); |
34 | 0 | DictISpell *d; |
35 | 0 | bool affloaded = false, |
36 | 0 | dictloaded = false, |
37 | 0 | stoploaded = false; |
38 | 0 | ListCell *l; |
39 | |
|
40 | 0 | d = (DictISpell *) palloc0(sizeof(DictISpell)); |
41 | |
|
42 | 0 | NIStartBuild(&(d->obj)); |
43 | |
|
44 | 0 | foreach(l, dictoptions) |
45 | 0 | { |
46 | 0 | DefElem *defel = (DefElem *) lfirst(l); |
47 | |
|
48 | 0 | if (strcmp(defel->defname, "dictfile") == 0) |
49 | 0 | { |
50 | 0 | char *filename; |
51 | |
|
52 | 0 | if (dictloaded) |
53 | 0 | ereport(ERROR, |
54 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
55 | 0 | errmsg("multiple DictFile parameters"))); |
56 | 0 | filename = get_tsearch_config_filename(defGetString(defel), |
57 | 0 | "dict"); |
58 | 0 | NIImportDictionary(&(d->obj), filename); |
59 | 0 | pfree(filename); |
60 | 0 | dictloaded = true; |
61 | 0 | } |
62 | 0 | else if (strcmp(defel->defname, "afffile") == 0) |
63 | 0 | { |
64 | 0 | char *filename; |
65 | |
|
66 | 0 | if (affloaded) |
67 | 0 | ereport(ERROR, |
68 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
69 | 0 | errmsg("multiple AffFile parameters"))); |
70 | 0 | filename = get_tsearch_config_filename(defGetString(defel), |
71 | 0 | "affix"); |
72 | 0 | NIImportAffixes(&(d->obj), filename); |
73 | 0 | pfree(filename); |
74 | 0 | affloaded = true; |
75 | 0 | } |
76 | 0 | else if (strcmp(defel->defname, "stopwords") == 0) |
77 | 0 | { |
78 | 0 | if (stoploaded) |
79 | 0 | ereport(ERROR, |
80 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
81 | 0 | errmsg("multiple StopWords parameters"))); |
82 | 0 | readstoplist(defGetString(defel), &(d->stoplist), str_tolower); |
83 | 0 | stoploaded = true; |
84 | 0 | } |
85 | 0 | else |
86 | 0 | { |
87 | 0 | ereport(ERROR, |
88 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
89 | 0 | errmsg("unrecognized Ispell parameter: \"%s\"", |
90 | 0 | defel->defname))); |
91 | 0 | } |
92 | 0 | } |
93 | | |
94 | 0 | if (affloaded && dictloaded) |
95 | 0 | { |
96 | 0 | NISortDictionary(&(d->obj)); |
97 | 0 | NISortAffixes(&(d->obj)); |
98 | 0 | } |
99 | 0 | else if (!affloaded) |
100 | 0 | { |
101 | 0 | ereport(ERROR, |
102 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
103 | 0 | errmsg("missing AffFile parameter"))); |
104 | 0 | } |
105 | 0 | else |
106 | 0 | { |
107 | 0 | ereport(ERROR, |
108 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
109 | 0 | errmsg("missing DictFile parameter"))); |
110 | 0 | } |
111 | | |
112 | 0 | NIFinishBuild(&(d->obj)); |
113 | |
|
114 | 0 | PG_RETURN_POINTER(d); |
115 | 0 | } |
116 | | |
117 | | Datum |
118 | | dispell_lexize(PG_FUNCTION_ARGS) |
119 | 0 | { |
120 | 0 | DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0); |
121 | 0 | char *in = (char *) PG_GETARG_POINTER(1); |
122 | 0 | int32 len = PG_GETARG_INT32(2); |
123 | 0 | char *txt; |
124 | 0 | TSLexeme *res; |
125 | 0 | TSLexeme *ptr, |
126 | 0 | *cptr; |
127 | |
|
128 | 0 | if (len <= 0) |
129 | 0 | PG_RETURN_POINTER(NULL); |
130 | | |
131 | 0 | txt = str_tolower(in, len, DEFAULT_COLLATION_OID); |
132 | 0 | res = NINormalizeWord(&(d->obj), txt); |
133 | |
|
134 | 0 | if (res == NULL) |
135 | 0 | PG_RETURN_POINTER(NULL); |
136 | | |
137 | 0 | cptr = res; |
138 | 0 | for (ptr = cptr; ptr->lexeme; ptr++) |
139 | 0 | { |
140 | 0 | if (searchstoplist(&(d->stoplist), ptr->lexeme)) |
141 | 0 | { |
142 | 0 | pfree(ptr->lexeme); |
143 | 0 | ptr->lexeme = NULL; |
144 | 0 | } |
145 | 0 | else |
146 | 0 | { |
147 | 0 | if (cptr != ptr) |
148 | 0 | memcpy(cptr, ptr, sizeof(TSLexeme)); |
149 | 0 | cptr++; |
150 | 0 | } |
151 | 0 | } |
152 | 0 | cptr->lexeme = NULL; |
153 | |
|
154 | 0 | PG_RETURN_POINTER(res); |
155 | 0 | } |