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