~ubuntu-branches/ubuntu/hardy/postgresql-8.4/hardy-backports

« back to all changes in this revision

Viewing changes to src/backend/tsearch/wparser.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * wparser.c
 
4
 *              Standard interface to word parser
 
5
 *
 
6
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 
7
 *
 
8
 *
 
9
 * IDENTIFICATION
 
10
 *        $PostgreSQL$
 
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
}