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