]> granicus.if.org Git - postgresql/blob - src/backend/tsearch/wparser.c
Update copyright for the year 2010.
[postgresql] / src / backend / tsearch / wparser.c
1 /*-------------------------------------------------------------------------
2  *
3  * wparser.c
4  *              Standard interface to word parser
5  *
6  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
7  *
8  *
9  * IDENTIFICATION
10  *        $PostgreSQL: pgsql/src/backend/tsearch/wparser.c,v 1.12 2010/01/02 16:57:53 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
16 #include "funcapi.h"
17 #include "access/genam.h"
18 #include "access/skey.h"
19 #include "catalog/indexing.h"
20 #include "catalog/namespace.h"
21 #include "catalog/pg_ts_parser.h"
22 #include "catalog/pg_type.h"
23 #include "commands/defrem.h"
24 #include "tsearch/ts_cache.h"
25 #include "tsearch/ts_public.h"
26 #include "tsearch/ts_utils.h"
27 #include "utils/builtins.h"
28 #include "utils/fmgroids.h"
29 #include "utils/rel.h"
30 #include "utils/syscache.h"
31
32
33 /******sql-level interface******/
34
35 typedef struct
36 {
37         int                     cur;
38         LexDescr   *list;
39 } TSTokenTypeStorage;
40
41 static void
42 tt_setup_firstcall(FuncCallContext *funcctx, Oid prsid)
43 {
44         TupleDesc       tupdesc;
45         MemoryContext oldcontext;
46         TSTokenTypeStorage *st;
47         TSParserCacheEntry *prs = lookup_ts_parser_cache(prsid);
48
49         if (!OidIsValid(prs->lextypeOid))
50                 elog(ERROR, "method lextype isn't defined for text search parser %u",
51                          prsid);
52
53         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
54
55         st = (TSTokenTypeStorage *) palloc(sizeof(TSTokenTypeStorage));
56         st->cur = 0;
57         /* OidFunctionCall0 is absent */
58         st->list = (LexDescr *) DatumGetPointer(OidFunctionCall1(prs->lextypeOid,
59                                                                                                                          (Datum) 0));
60         funcctx->user_fctx = (void *) st;
61
62         tupdesc = CreateTemplateTupleDesc(3, false);
63         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid",
64                                            INT4OID, -1, 0);
65         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "alias",
66                                            TEXTOID, -1, 0);
67         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description",
68                                            TEXTOID, -1, 0);
69
70         funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
71         MemoryContextSwitchTo(oldcontext);
72 }
73
74 static Datum
75 tt_process_call(FuncCallContext *funcctx)
76 {
77         TSTokenTypeStorage *st;
78
79         st = (TSTokenTypeStorage *) funcctx->user_fctx;
80         if (st->list && st->list[st->cur].lexid)
81         {
82                 Datum           result;
83                 char       *values[3];
84                 char            txtid[16];
85                 HeapTuple       tuple;
86
87                 sprintf(txtid, "%d", st->list[st->cur].lexid);
88                 values[0] = txtid;
89                 values[1] = st->list[st->cur].alias;
90                 values[2] = st->list[st->cur].descr;
91
92                 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
93                 result = HeapTupleGetDatum(tuple);
94
95                 pfree(values[1]);
96                 pfree(values[2]);
97                 st->cur++;
98                 return result;
99         }
100         if (st->list)
101                 pfree(st->list);
102         pfree(st);
103         return (Datum) 0;
104 }
105
106 Datum
107 ts_token_type_byid(PG_FUNCTION_ARGS)
108 {
109         FuncCallContext *funcctx;
110         Datum           result;
111
112         if (SRF_IS_FIRSTCALL())
113         {
114                 funcctx = SRF_FIRSTCALL_INIT();
115                 tt_setup_firstcall(funcctx, PG_GETARG_OID(0));
116         }
117
118         funcctx = SRF_PERCALL_SETUP();
119
120         if ((result = tt_process_call(funcctx)) != (Datum) 0)
121                 SRF_RETURN_NEXT(funcctx, result);
122         SRF_RETURN_DONE(funcctx);
123 }
124
125 Datum
126 ts_token_type_byname(PG_FUNCTION_ARGS)
127 {
128         FuncCallContext *funcctx;
129         Datum           result;
130
131         if (SRF_IS_FIRSTCALL())
132         {
133                 text       *prsname = PG_GETARG_TEXT_P(0);
134                 Oid                     prsId;
135
136                 funcctx = SRF_FIRSTCALL_INIT();
137                 prsId = TSParserGetPrsid(textToQualifiedNameList(prsname), false);
138                 tt_setup_firstcall(funcctx, prsId);
139         }
140
141         funcctx = SRF_PERCALL_SETUP();
142
143         if ((result = tt_process_call(funcctx)) != (Datum) 0)
144                 SRF_RETURN_NEXT(funcctx, result);
145         SRF_RETURN_DONE(funcctx);
146 }
147
148 typedef struct
149 {
150         int                     type;
151         char       *lexeme;
152 } LexemeEntry;
153
154 typedef struct
155 {
156         int                     cur;
157         int                     len;
158         LexemeEntry *list;
159 } PrsStorage;
160
161
162 static void
163 prs_setup_firstcall(FuncCallContext *funcctx, Oid prsid, text *txt)
164 {
165         TupleDesc       tupdesc;
166         MemoryContext oldcontext;
167         PrsStorage *st;
168         TSParserCacheEntry *prs = lookup_ts_parser_cache(prsid);
169         char       *lex = NULL;
170         int                     llen = 0,
171                                 type = 0;
172         void       *prsdata;
173
174         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
175
176         st = (PrsStorage *) palloc(sizeof(PrsStorage));
177         st->cur = 0;
178         st->len = 16;
179         st->list = (LexemeEntry *) palloc(sizeof(LexemeEntry) * st->len);
180
181         prsdata = (void *) DatumGetPointer(FunctionCall2(&prs->prsstart,
182                                                                                            PointerGetDatum(VARDATA(txt)),
183                                                                         Int32GetDatum(VARSIZE(txt) - VARHDRSZ)));
184
185         while ((type = DatumGetInt32(FunctionCall3(&prs->prstoken,
186                                                                                            PointerGetDatum(prsdata),
187                                                                                            PointerGetDatum(&lex),
188                                                                                            PointerGetDatum(&llen)))) != 0)
189         {
190                 if (st->cur >= st->len)
191                 {
192                         st->len = 2 * st->len;
193                         st->list = (LexemeEntry *) repalloc(st->list, sizeof(LexemeEntry) * st->len);
194                 }
195                 st->list[st->cur].lexeme = palloc(llen + 1);
196                 memcpy(st->list[st->cur].lexeme, lex, llen);
197                 st->list[st->cur].lexeme[llen] = '\0';
198                 st->list[st->cur].type = type;
199                 st->cur++;
200         }
201
202         FunctionCall1(&prs->prsend, PointerGetDatum(prsdata));
203
204         st->len = st->cur;
205         st->cur = 0;
206
207         funcctx->user_fctx = (void *) st;
208         tupdesc = CreateTemplateTupleDesc(2, false);
209         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid",
210                                            INT4OID, -1, 0);
211         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "token",
212                                            TEXTOID, -1, 0);
213
214         funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
215         MemoryContextSwitchTo(oldcontext);
216 }
217
218 static Datum
219 prs_process_call(FuncCallContext *funcctx)
220 {
221         PrsStorage *st;
222
223         st = (PrsStorage *) funcctx->user_fctx;
224         if (st->cur < st->len)
225         {
226                 Datum           result;
227                 char       *values[2];
228                 char            tid[16];
229                 HeapTuple       tuple;
230
231                 values[0] = tid;
232                 sprintf(tid, "%d", st->list[st->cur].type);
233                 values[1] = st->list[st->cur].lexeme;
234                 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
235                 result = HeapTupleGetDatum(tuple);
236
237                 pfree(values[1]);
238                 st->cur++;
239                 return result;
240         }
241         else
242         {
243                 if (st->list)
244                         pfree(st->list);
245                 pfree(st);
246         }
247         return (Datum) 0;
248 }
249
250 Datum
251 ts_parse_byid(PG_FUNCTION_ARGS)
252 {
253         FuncCallContext *funcctx;
254         Datum           result;
255
256         if (SRF_IS_FIRSTCALL())
257         {
258                 text       *txt = PG_GETARG_TEXT_P(1);
259
260                 funcctx = SRF_FIRSTCALL_INIT();
261                 prs_setup_firstcall(funcctx, PG_GETARG_OID(0), txt);
262                 PG_FREE_IF_COPY(txt, 1);
263         }
264
265         funcctx = SRF_PERCALL_SETUP();
266
267         if ((result = prs_process_call(funcctx)) != (Datum) 0)
268                 SRF_RETURN_NEXT(funcctx, result);
269         SRF_RETURN_DONE(funcctx);
270 }
271
272 Datum
273 ts_parse_byname(PG_FUNCTION_ARGS)
274 {
275         FuncCallContext *funcctx;
276         Datum           result;
277
278         if (SRF_IS_FIRSTCALL())
279         {
280                 text       *prsname = PG_GETARG_TEXT_P(0);
281                 text       *txt = PG_GETARG_TEXT_P(1);
282                 Oid                     prsId;
283
284                 funcctx = SRF_FIRSTCALL_INIT();
285                 prsId = TSParserGetPrsid(textToQualifiedNameList(prsname), false);
286                 prs_setup_firstcall(funcctx, prsId, txt);
287         }
288
289         funcctx = SRF_PERCALL_SETUP();
290
291         if ((result = prs_process_call(funcctx)) != (Datum) 0)
292                 SRF_RETURN_NEXT(funcctx, result);
293         SRF_RETURN_DONE(funcctx);
294 }
295
296 Datum
297 ts_headline_byid_opt(PG_FUNCTION_ARGS)
298 {
299         text       *in = PG_GETARG_TEXT_P(1);
300         TSQuery         query = PG_GETARG_TSQUERY(2);
301         text       *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
302         HeadlineParsedText prs;
303         List       *prsoptions;
304         text       *out;
305         TSConfigCacheEntry *cfg;
306         TSParserCacheEntry *prsobj;
307
308         cfg = lookup_ts_config_cache(PG_GETARG_OID(0));
309         prsobj = lookup_ts_parser_cache(cfg->prsId);
310
311         if (!OidIsValid(prsobj->headlineOid))
312                 ereport(ERROR,
313                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
314                    errmsg("text search parser does not support headline creation")));
315
316         memset(&prs, 0, sizeof(HeadlineParsedText));
317         prs.lenwords = 32;
318         prs.words = (HeadlineWordEntry *) palloc(sizeof(HeadlineWordEntry) * prs.lenwords);
319
320         hlparsetext(cfg->cfgId, &prs, query, VARDATA(in), VARSIZE(in) - VARHDRSZ);
321
322         if (opt)
323                 prsoptions = deserialize_deflist(PointerGetDatum(opt));
324         else
325                 prsoptions = NIL;
326
327         FunctionCall3(&(prsobj->prsheadline),
328                                   PointerGetDatum(&prs),
329                                   PointerGetDatum(prsoptions),
330                                   PointerGetDatum(query));
331
332         out = generateHeadline(&prs);
333
334         PG_FREE_IF_COPY(in, 1);
335         PG_FREE_IF_COPY(query, 2);
336         if (opt)
337                 PG_FREE_IF_COPY(opt, 3);
338         pfree(prs.words);
339         pfree(prs.startsel);
340         pfree(prs.stopsel);
341
342         PG_RETURN_POINTER(out);
343 }
344
345 Datum
346 ts_headline_byid(PG_FUNCTION_ARGS)
347 {
348         PG_RETURN_DATUM(DirectFunctionCall3(ts_headline_byid_opt,
349                                                                                 PG_GETARG_DATUM(0),
350                                                                                 PG_GETARG_DATUM(1),
351                                                                                 PG_GETARG_DATUM(2)));
352 }
353
354 Datum
355 ts_headline(PG_FUNCTION_ARGS)
356 {
357         PG_RETURN_DATUM(DirectFunctionCall3(ts_headline_byid_opt,
358                                                                   ObjectIdGetDatum(getTSCurrentConfig(true)),
359                                                                                 PG_GETARG_DATUM(0),
360                                                                                 PG_GETARG_DATUM(1)));
361 }
362
363 Datum
364 ts_headline_opt(PG_FUNCTION_ARGS)
365 {
366         PG_RETURN_DATUM(DirectFunctionCall4(ts_headline_byid_opt,
367                                                                   ObjectIdGetDatum(getTSCurrentConfig(true)),
368                                                                                 PG_GETARG_DATUM(0),
369                                                                                 PG_GETARG_DATUM(1),
370                                                                                 PG_GETARG_DATUM(2)));
371 }