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