]> granicus.if.org Git - postgresql/blob - contrib/tsearch2/dict.c
Update misleading comment about the use of lanpltrusted ... it is
[postgresql] / contrib / tsearch2 / dict.c
1 /*
2  * interface functions to dictionary
3  * Teodor Sigaev <teodor@sigaev.ru>
4  */
5 #include <errno.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <ctype.h>
9
10 #include "postgres.h"
11 #include "fmgr.h"
12 #include "utils/array.h"
13 #include "catalog/pg_type.h"
14 #include "executor/spi.h"
15
16 #include "dict.h"
17 #include "common.h"
18 #include "snmap.h"
19
20 /*********top interface**********/
21
22 void
23 init_dict(Oid id, DictInfo * dict)
24 {
25         Oid                     arg[1];
26         bool            isnull;
27         Datum           pars[1];
28         int                     stat;
29         void       *plan;
30         char            buf[1024];
31         char       *nsp = get_namespace(TSNSP_FunctionOid);
32
33         arg[0] = OIDOID;
34         pars[0] = ObjectIdGetDatum(id);
35
36         memset(dict, 0, sizeof(DictInfo));
37         SPI_connect();
38         sprintf(buf, "select dict_init, dict_initoption, dict_lexize from %s.pg_ts_dict where oid = $1", nsp);
39         pfree(nsp);
40         plan = SPI_prepare(buf, 1, arg);
41         if (!plan)
42                 ts_error(ERROR, "SPI_prepare() failed");
43
44         stat = SPI_execp(plan, pars, " ", 1);
45         if (stat < 0)
46                 ts_error(ERROR, "SPI_execp return %d", stat);
47         if (SPI_processed > 0)
48         {
49                 Datum           opt;
50                 Oid                     oid = InvalidOid;
51
52                 oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
53                 if (!(isnull || oid == InvalidOid))
54                 {
55                         opt = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull);
56                         dict->dictionary = (void *) DatumGetPointer(OidFunctionCall1(oid, opt));
57                 }
58                 oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull));
59                 if (isnull || oid == InvalidOid)
60                         ts_error(ERROR, "Null dict_lexize for dictonary %d", id);
61                 fmgr_info_cxt(oid, &(dict->lexize_info), TopMemoryContext);
62                 dict->dict_id = id;
63         }
64         else
65                 ts_error(ERROR, "No dictionary with id %d", id);
66         SPI_freeplan(plan);
67         SPI_finish();
68 }
69
70 typedef struct
71 {
72         DictInfo   *last_dict;
73         int                     len;
74         int                     reallen;
75         DictInfo   *list;
76         SNMap           name2id_map;
77 }       DictList;
78
79 static DictList DList = {NULL, 0, 0, NULL, {0, 0, NULL}};
80
81 void
82 reset_dict(void)
83 {
84         freeSNMap(&(DList.name2id_map));
85         /* XXX need to free DList.list[*].dictionary */
86         if (DList.list)
87                 free(DList.list);
88         memset(&DList, 0, sizeof(DictList));
89 }
90
91
92 static int
93 comparedict(const void *a, const void *b)
94 {
95         if ( ((DictInfo *) a)->dict_id == ((DictInfo *) b)->dict_id )
96                 return 0;
97         return ( ((DictInfo *) a)->dict_id < ((DictInfo *) b)->dict_id ) ? -1 : 1;
98 }
99
100 DictInfo *
101 finddict(Oid id)
102 {
103         /* last used dict */
104         if (DList.last_dict && DList.last_dict->dict_id == id)
105                 return DList.last_dict;
106
107
108         /* already used dict */
109         if (DList.len != 0)
110         {
111                 DictInfo        key;
112
113                 key.dict_id = id;
114                 DList.last_dict = bsearch(&key, DList.list, DList.len, sizeof(DictInfo), comparedict);
115                 if (DList.last_dict != NULL)
116                         return DList.last_dict;
117         }
118
119         /* last chance */
120         if (DList.len == DList.reallen)
121         {
122                 DictInfo   *tmp;
123                 int                     reallen = (DList.reallen) ? 2 * DList.reallen : 16;
124
125                 tmp = (DictInfo *) realloc(DList.list, sizeof(DictInfo) * reallen);
126                 if (!tmp)
127                         ts_error(ERROR, "No memory");
128                 DList.reallen = reallen;
129                 DList.list = tmp;
130         }
131         DList.last_dict = &(DList.list[DList.len]);
132         init_dict(id, DList.last_dict);
133
134         DList.len++;
135         qsort(DList.list, DList.len, sizeof(DictInfo), comparedict);
136         return finddict(id); /* qsort changed order!! */ ;
137 }
138
139 Oid
140 name2id_dict(text *name)
141 {
142         Oid                     arg[1];
143         bool            isnull;
144         Datum           pars[1];
145         int                     stat;
146         Oid                     id = findSNMap_t(&(DList.name2id_map), name);
147         void       *plan;
148         char            buf[1024],
149                            *nsp;
150
151         arg[0] = TEXTOID;
152         pars[0] = PointerGetDatum(name);
153
154         if (id)
155                 return id;
156
157         nsp = get_namespace(TSNSP_FunctionOid);
158         SPI_connect();
159         sprintf(buf, "select oid from %s.pg_ts_dict where dict_name = $1", nsp);
160         pfree(nsp);
161         plan = SPI_prepare(buf, 1, arg);
162         if (!plan)
163                 ts_error(ERROR, "SPI_prepare() failed");
164
165         stat = SPI_execp(plan, pars, " ", 1);
166         if (stat < 0)
167                 ts_error(ERROR, "SPI_execp return %d", stat);
168         if (SPI_processed > 0)
169                 id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
170         else
171                 ts_error(ERROR, "No dictionary with name '%s'", text2char(name));
172         SPI_freeplan(plan);
173         SPI_finish();
174         addSNMap_t(&(DList.name2id_map), name, id);
175         return id;
176 }
177
178
179 /******sql-level interface******/
180 PG_FUNCTION_INFO_V1(lexize);
181 Datum           lexize(PG_FUNCTION_ARGS);
182
183 Datum
184 lexize(PG_FUNCTION_ARGS)
185 {
186         text       *in = PG_GETARG_TEXT_P(1);
187         DictInfo   *dict;
188         TSLexeme          *res,
189                           *ptr;
190         Datum      *da;
191         ArrayType  *a;
192
193         SET_FUNCOID();
194         dict = finddict(PG_GETARG_OID(0));
195
196         ptr = res = (TSLexeme *) DatumGetPointer(
197                                                                           FunctionCall3(&(dict->lexize_info),
198                                                                            PointerGetDatum(dict->dictionary),
199                                                                                         PointerGetDatum(VARDATA(in)),
200                                                                         Int32GetDatum(VARSIZE(in) - VARHDRSZ)
201                                                                                                         )
202                 );
203         PG_FREE_IF_COPY(in, 1);
204         if (!res)
205         {
206                 if (PG_NARGS() > 2)
207                         PG_RETURN_POINTER(NULL);
208                 else
209                         PG_RETURN_NULL();
210         }
211
212         while (ptr->lexeme)
213                 ptr++;
214         da = (Datum *) palloc(sizeof(Datum) * (ptr - res + 1));
215         ptr = res;
216         while (ptr->lexeme)
217         {
218                 da[ptr - res] = PointerGetDatum(char2text(ptr->lexeme));
219                 ptr++;
220         }
221
222         a = construct_array(
223                                                 da,
224                                                 ptr - res,
225                                                 TEXTOID,
226                                                 -1,
227                                                 false,
228                                                 'i'
229                 );
230
231         ptr = res;
232         while (ptr->lexeme)
233         {
234                 pfree(DatumGetPointer(da[ptr - res]));
235                 pfree(ptr->lexeme);
236                 ptr++;
237         }
238         pfree(res);
239         pfree(da);
240
241         PG_RETURN_POINTER(a);
242 }
243
244 PG_FUNCTION_INFO_V1(lexize_byname);
245 Datum           lexize_byname(PG_FUNCTION_ARGS);
246 Datum
247 lexize_byname(PG_FUNCTION_ARGS)
248 {
249         text       *dictname = PG_GETARG_TEXT_P(0);
250         Datum           res;
251
252         SET_FUNCOID();
253
254         res = DirectFunctionCall3(
255                                                           lexize,
256                                                           ObjectIdGetDatum(name2id_dict(dictname)),
257                                                           PG_GETARG_DATUM(1),
258                                                           (Datum) 0
259                 );
260         PG_FREE_IF_COPY(dictname, 0);
261         if (res)
262                 PG_RETURN_DATUM(res);
263         else
264                 PG_RETURN_NULL();
265 }
266
267 static Oid      currect_dictionary_id = 0;
268
269 PG_FUNCTION_INFO_V1(set_curdict);
270 Datum           set_curdict(PG_FUNCTION_ARGS);
271 Datum
272 set_curdict(PG_FUNCTION_ARGS)
273 {
274         SET_FUNCOID();
275         finddict(PG_GETARG_OID(0));
276         currect_dictionary_id = PG_GETARG_OID(0);
277         PG_RETURN_VOID();
278 }
279
280 PG_FUNCTION_INFO_V1(set_curdict_byname);
281 Datum           set_curdict_byname(PG_FUNCTION_ARGS);
282 Datum
283 set_curdict_byname(PG_FUNCTION_ARGS)
284 {
285         text       *dictname = PG_GETARG_TEXT_P(0);
286
287         SET_FUNCOID();
288         DirectFunctionCall1(
289                                                 set_curdict,
290                                                 ObjectIdGetDatum(name2id_dict(dictname))
291                 );
292         PG_FREE_IF_COPY(dictname, 0);
293         PG_RETURN_VOID();
294 }
295
296 PG_FUNCTION_INFO_V1(lexize_bycurrent);
297 Datum           lexize_bycurrent(PG_FUNCTION_ARGS);
298 Datum
299 lexize_bycurrent(PG_FUNCTION_ARGS)
300 {
301         Datum           res;
302
303         SET_FUNCOID();
304         if (currect_dictionary_id == 0)
305                 ereport(ERROR,
306                                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
307                                  errmsg("no currect dictionary"),
308                                  errhint("Execute select set_curdict().")));
309
310         res = DirectFunctionCall3(
311                                                           lexize,
312                                                           ObjectIdGetDatum(currect_dictionary_id),
313                                                           PG_GETARG_DATUM(0),
314                                                           (Datum) 0
315                 );
316         if (res)
317                 PG_RETURN_DATUM(res);
318         else
319                 PG_RETURN_NULL();
320 }