OSDN Git Service

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