Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * dict_ispell.c
4 : * Ispell dictionary interface
5 : *
6 : * Portions Copyright (c) 1996-2017, 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_utils.h"
20 : #include "utils/builtins.h"
21 :
22 :
23 : typedef struct
24 : {
25 : StopList stoplist;
26 : IspellDict obj;
27 : } DictISpell;
28 :
29 : Datum
30 13 : dispell_init(PG_FUNCTION_ARGS)
31 : {
32 13 : List *dictoptions = (List *) PG_GETARG_POINTER(0);
33 : DictISpell *d;
34 13 : bool affloaded = false,
35 13 : dictloaded = false,
36 13 : stoploaded = false;
37 : ListCell *l;
38 :
39 13 : d = (DictISpell *) palloc0(sizeof(DictISpell));
40 :
41 13 : NIStartBuild(&(d->obj));
42 :
43 39 : foreach(l, dictoptions)
44 : {
45 26 : DefElem *defel = (DefElem *) lfirst(l);
46 :
47 26 : if (pg_strcasecmp(defel->defname, "DictFile") == 0)
48 : {
49 13 : if (dictloaded)
50 0 : ereport(ERROR,
51 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
52 : errmsg("multiple DictFile parameters")));
53 13 : NIImportDictionary(&(d->obj),
54 13 : get_tsearch_config_filename(defGetString(defel),
55 : "dict"));
56 13 : dictloaded = true;
57 : }
58 13 : else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
59 : {
60 13 : if (affloaded)
61 0 : ereport(ERROR,
62 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
63 : errmsg("multiple AffFile parameters")));
64 13 : NIImportAffixes(&(d->obj),
65 13 : get_tsearch_config_filename(defGetString(defel),
66 : "affix"));
67 13 : affloaded = true;
68 : }
69 0 : else if (pg_strcasecmp(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 0 : ereport(ERROR,
81 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
82 : errmsg("unrecognized Ispell parameter: \"%s\"",
83 : defel->defname)));
84 : }
85 : }
86 :
87 13 : if (affloaded && dictloaded)
88 : {
89 13 : NISortDictionary(&(d->obj));
90 13 : 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 13 : NIFinishBuild(&(d->obj));
106 :
107 13 : PG_RETURN_POINTER(d);
108 : }
109 :
110 : Datum
111 120 : dispell_lexize(PG_FUNCTION_ARGS)
112 : {
113 120 : DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0);
114 120 : char *in = (char *) PG_GETARG_POINTER(1);
115 120 : int32 len = PG_GETARG_INT32(2);
116 : char *txt;
117 : TSLexeme *res;
118 : TSLexeme *ptr,
119 : *cptr;
120 :
121 120 : if (len <= 0)
122 0 : PG_RETURN_POINTER(NULL);
123 :
124 120 : txt = lowerstr_with_len(in, len);
125 120 : res = NINormalizeWord(&(d->obj), txt);
126 :
127 120 : if (res == NULL)
128 24 : PG_RETURN_POINTER(NULL);
129 :
130 96 : cptr = res;
131 308 : for (ptr = cptr; ptr->lexeme; ptr++)
132 : {
133 212 : if (searchstoplist(&(d->stoplist), ptr->lexeme))
134 : {
135 0 : pfree(ptr->lexeme);
136 0 : ptr->lexeme = NULL;
137 : }
138 : else
139 : {
140 212 : if (cptr != ptr)
141 0 : memcpy(cptr, ptr, sizeof(TSLexeme));
142 212 : cptr++;
143 : }
144 : }
145 96 : cptr->lexeme = NULL;
146 :
147 96 : PG_RETURN_POINTER(res);
148 : }
|