Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * ts_parse.c
4 : : * main parse functions for tsearch
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : *
8 : : *
9 : : * IDENTIFICATION
10 : : * src/backend/tsearch/ts_parse.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : :
15 : : #include "postgres.h"
16 : :
17 : : #include "tsearch/ts_cache.h"
18 : : #include "tsearch/ts_utils.h"
19 : : #include "varatt.h"
20 : :
21 : : #define IGNORE_LONGLEXEME 1
22 : :
23 : : /*
24 : : * Lexize subsystem
25 : : */
26 : :
27 : : typedef struct ParsedLex
28 : : {
29 : : int type;
30 : : char *lemm;
31 : : int lenlemm;
32 : : struct ParsedLex *next;
33 : : } ParsedLex;
34 : :
35 : : typedef struct ListParsedLex
36 : : {
37 : : ParsedLex *head;
38 : : ParsedLex *tail;
39 : : } ListParsedLex;
40 : :
41 : : typedef struct
42 : : {
43 : : TSConfigCacheEntry *cfg;
44 : : Oid curDictId;
45 : : int posDict;
46 : : DictSubState dictState;
47 : : ParsedLex *curSub;
48 : : ListParsedLex towork; /* current list to work */
49 : : ListParsedLex waste; /* list of lexemes that already lexized */
50 : :
51 : : /*
52 : : * fields to store last variant to lexize (basically, thesaurus or similar
53 : : * to, which wants several lexemes
54 : : */
55 : :
56 : : ParsedLex *lastRes;
57 : : TSLexeme *tmpRes;
58 : : } LexizeData;
59 : :
60 : : static void
5995 bruce@momjian.us 61 :CBC 2348 : LexizeInit(LexizeData *ld, TSConfigCacheEntry *cfg)
62 : : {
6081 tgl@sss.pgh.pa.us 63 : 2348 : ld->cfg = cfg;
64 : 2348 : ld->curDictId = InvalidOid;
65 : 2348 : ld->posDict = 0;
66 : 2348 : ld->towork.head = ld->towork.tail = ld->curSub = NULL;
67 : 2348 : ld->waste.head = ld->waste.tail = NULL;
68 : 2348 : ld->lastRes = NULL;
69 : 2348 : ld->tmpRes = NULL;
70 : 2348 : }
71 : :
72 : : static void
5995 bruce@momjian.us 73 : 27646 : LPLAddTail(ListParsedLex *list, ParsedLex *newpl)
74 : : {
6081 tgl@sss.pgh.pa.us 75 [ + + ]: 27646 : if (list->tail)
76 : : {
77 : 111 : list->tail->next = newpl;
78 : 111 : list->tail = newpl;
79 : : }
80 : : else
81 : 27535 : list->head = list->tail = newpl;
82 : 27646 : newpl->next = NULL;
83 : 27646 : }
84 : :
85 : : static ParsedLex *
5995 bruce@momjian.us 86 : 13823 : LPLRemoveHead(ListParsedLex *list)
87 : : {
6081 tgl@sss.pgh.pa.us 88 : 13823 : ParsedLex *res = list->head;
89 : :
90 [ + - ]: 13823 : if (list->head)
91 : 13823 : list->head = list->head->next;
92 : :
93 [ + + ]: 13823 : if (list->head == NULL)
94 : 13760 : list->tail = NULL;
95 : :
96 : 13823 : return res;
97 : : }
98 : :
99 : : static void
5995 bruce@momjian.us 100 : 13823 : LexizeAddLemm(LexizeData *ld, int type, char *lemm, int lenlemm)
101 : : {
6081 tgl@sss.pgh.pa.us 102 : 13823 : ParsedLex *newpl = (ParsedLex *) palloc(sizeof(ParsedLex));
103 : :
104 : 13823 : newpl->type = type;
105 : 13823 : newpl->lemm = lemm;
106 : 13823 : newpl->lenlemm = lenlemm;
107 : 13823 : LPLAddTail(&ld->towork, newpl);
108 : 13823 : ld->curSub = ld->towork.tail;
109 : 13823 : }
110 : :
111 : : static void
5995 bruce@momjian.us 112 : 13823 : RemoveHead(LexizeData *ld)
113 : : {
6081 tgl@sss.pgh.pa.us 114 : 13823 : LPLAddTail(&ld->waste, LPLRemoveHead(&ld->towork));
115 : :
116 : 13823 : ld->posDict = 0;
117 : 13823 : }
118 : :
119 : : static void
5995 bruce@momjian.us 120 : 20556 : setCorrLex(LexizeData *ld, ParsedLex **correspondLexem)
121 : : {
6081 tgl@sss.pgh.pa.us 122 [ + + ]: 20556 : if (correspondLexem)
123 : : {
124 : 7545 : *correspondLexem = ld->waste.head;
125 : : }
126 : : else
127 : : {
128 : : ParsedLex *tmp,
129 : 13011 : *ptr = ld->waste.head;
130 : :
131 [ + + ]: 21763 : while (ptr)
132 : : {
133 : 8752 : tmp = ptr->next;
134 : 8752 : pfree(ptr);
135 : 8752 : ptr = tmp;
136 : : }
137 : : }
138 : 20556 : ld->waste.head = ld->waste.tail = NULL;
139 : 20556 : }
140 : :
141 : : static void
5995 bruce@momjian.us 142 : 24 : moveToWaste(LexizeData *ld, ParsedLex *stop)
143 : : {
6081 tgl@sss.pgh.pa.us 144 : 24 : bool go = true;
145 : :
146 [ + + + + ]: 90 : while (ld->towork.head && go)
147 : : {
148 [ + + ]: 66 : if (ld->towork.head == stop)
149 : : {
150 : 24 : ld->curSub = stop->next;
151 : 24 : go = false;
152 : : }
153 : 66 : RemoveHead(ld);
154 : : }
155 : 24 : }
156 : :
157 : : static void
5995 bruce@momjian.us 158 : 24 : setNewTmpRes(LexizeData *ld, ParsedLex *lex, TSLexeme *res)
159 : : {
6081 tgl@sss.pgh.pa.us 160 [ + + ]: 24 : if (ld->tmpRes)
161 : : {
162 : : TSLexeme *ptr;
163 : :
164 [ + + ]: 12 : for (ptr = ld->tmpRes; ptr->lexeme; ptr++)
165 : 6 : pfree(ptr->lexeme);
166 : 6 : pfree(ld->tmpRes);
167 : : }
168 : 24 : ld->tmpRes = res;
169 : 24 : ld->lastRes = lex;
170 : 24 : }
171 : :
172 : : static TSLexeme *
5995 bruce@momjian.us 173 : 20580 : LexizeExec(LexizeData *ld, ParsedLex **correspondLexem)
174 : : {
175 : : int i;
176 : : ListDictionary *map;
177 : : TSDictionaryCacheEntry *dict;
178 : : TSLexeme *res;
179 : :
6081 tgl@sss.pgh.pa.us 180 [ + + ]: 20580 : if (ld->curDictId == InvalidOid)
181 : : {
182 : : /*
183 : : * usual mode: dictionary wants only one word, but we should keep in
184 : : * mind that we should go through all stack
185 : : */
186 : :
187 [ + + ]: 27541 : while (ld->towork.head)
188 : : {
189 : 13781 : ParsedLex *curVal = ld->towork.head;
5353 teodor@sigaev.ru 190 : 13781 : char *curValLemm = curVal->lemm;
5161 bruce@momjian.us 191 : 13781 : int curValLenLemm = curVal->lenlemm;
192 : :
6081 tgl@sss.pgh.pa.us 193 : 13781 : map = ld->cfg->map + curVal->type;
194 : :
195 [ + + + + : 13781 : if (curVal->type == 0 || curVal->type >= ld->cfg->lenmap || map->len == 0)
+ + ]
196 : : {
197 : : /* skip this type of lexeme */
198 : 7048 : RemoveHead(ld);
199 : 7048 : continue;
200 : : }
201 : :
202 [ + - ]: 6979 : for (i = ld->posDict; i < map->len; i++)
203 : : {
204 : 6979 : dict = lookup_ts_dictionary_cache(map->dictIds[i]);
205 : :
206 : 6979 : ld->dictState.isend = ld->dictState.getnext = false;
5386 peter_e@gmx.net 207 : 6979 : ld->dictState.private_state = NULL;
1536 alvherre@alvh.no-ip. 208 : 6979 : res = (TSLexeme *) DatumGetPointer(FunctionCall4(&(dict->lexize),
209 : : PointerGetDatum(dict->dictData),
210 : : PointerGetDatum(curValLemm),
211 : : Int32GetDatum(curValLenLemm),
212 : : PointerGetDatum(&ld->dictState)));
213 : :
6081 tgl@sss.pgh.pa.us 214 [ + + ]: 6979 : if (ld->dictState.getnext)
215 : : {
216 : : /*
217 : : * dictionary wants next word, so setup and store current
218 : : * position and go to multiword mode
219 : : */
220 : :
221 : 24 : ld->curDictId = DatumGetObjectId(map->dictIds[i]);
222 : 24 : ld->posDict = i + 1;
223 : 24 : ld->curSub = curVal->next;
224 [ + + ]: 24 : if (res)
225 : 18 : setNewTmpRes(ld, curVal, res);
226 : 24 : return LexizeExec(ld, correspondLexem);
227 : : }
228 : :
229 [ + + ]: 6955 : if (!res) /* dictionary doesn't know this lexeme */
230 : 246 : continue;
231 : :
5161 bruce@momjian.us 232 [ - + ]: 6709 : if (res->flags & TSL_FILTER)
233 : : {
5353 teodor@sigaev.ru 234 :UBC 0 : curValLemm = res->lexeme;
235 : 0 : curValLenLemm = strlen(res->lexeme);
236 : 0 : continue;
237 : : }
238 : :
6081 tgl@sss.pgh.pa.us 239 :CBC 6709 : RemoveHead(ld);
240 : 6709 : setCorrLex(ld, correspondLexem);
241 : 6709 : return res;
242 : : }
243 : :
6081 tgl@sss.pgh.pa.us 244 :UBC 0 : RemoveHead(ld);
245 : : }
246 : : }
247 : : else
248 : : { /* curDictId is valid */
6081 tgl@sss.pgh.pa.us 249 :CBC 87 : dict = lookup_ts_dictionary_cache(ld->curDictId);
250 : :
251 : : /*
252 : : * Dictionary ld->curDictId asks us about following words
253 : : */
254 : :
255 [ + + ]: 126 : while (ld->curSub)
256 : : {
257 : 63 : ParsedLex *curVal = ld->curSub;
258 : :
259 : 63 : map = ld->cfg->map + curVal->type;
260 : :
261 [ + + ]: 63 : if (curVal->type != 0)
262 : : {
263 : 60 : bool dictExists = false;
264 : :
265 [ + - + + ]: 60 : if (curVal->type >= ld->cfg->lenmap || map->len == 0)
266 : : {
267 : : /* skip this type of lexeme */
268 : 30 : ld->curSub = curVal->next;
269 : 30 : continue;
270 : : }
271 : :
272 : : /*
273 : : * We should be sure that current type of lexeme is recognized
274 : : * by our dictionary: we just check is it exist in list of
275 : : * dictionaries ?
276 : : */
277 [ + - + + ]: 90 : for (i = 0; i < map->len && !dictExists; i++)
278 [ + + ]: 60 : if (ld->curDictId == DatumGetObjectId(map->dictIds[i]))
279 : 30 : dictExists = true;
280 : :
281 [ - + ]: 30 : if (!dictExists)
282 : : {
283 : : /*
284 : : * Dictionary can't work with current type of lexeme,
285 : : * return to basic mode and redo all stored lexemes
286 : : */
6081 tgl@sss.pgh.pa.us 287 :UBC 0 : ld->curDictId = InvalidOid;
288 : 0 : return LexizeExec(ld, correspondLexem);
289 : : }
290 : : }
291 : :
949 michael@paquier.xyz 292 :CBC 33 : ld->dictState.isend = (curVal->type == 0);
6081 tgl@sss.pgh.pa.us 293 : 33 : ld->dictState.getnext = false;
294 : :
1536 alvherre@alvh.no-ip. 295 : 33 : res = (TSLexeme *) DatumGetPointer(FunctionCall4(&(dict->lexize),
296 : : PointerGetDatum(dict->dictData),
297 : : PointerGetDatum(curVal->lemm),
298 : : Int32GetDatum(curVal->lenlemm),
299 : : PointerGetDatum(&ld->dictState)));
300 : :
6081 tgl@sss.pgh.pa.us 301 [ + + ]: 33 : if (ld->dictState.getnext)
302 : : {
303 : : /* Dictionary wants one more */
304 : 9 : ld->curSub = curVal->next;
305 [ + + ]: 9 : if (res)
306 : 6 : setNewTmpRes(ld, curVal, res);
307 : 9 : continue;
308 : : }
309 : :
310 [ + + + - ]: 24 : if (res || ld->tmpRes)
311 : : {
312 : : /*
313 : : * Dictionary normalizes lexemes, so we remove from stack all
314 : : * used lexemes, return to basic mode and redo end of stack
315 : : * (if it exists)
316 : : */
317 [ + + ]: 24 : if (res)
318 : : {
319 : 12 : moveToWaste(ld, ld->curSub);
320 : : }
321 : : else
322 : : {
323 : 12 : res = ld->tmpRes;
324 : 12 : moveToWaste(ld, ld->lastRes);
325 : : }
326 : :
327 : : /* reset to initial state */
328 : 24 : ld->curDictId = InvalidOid;
329 : 24 : ld->posDict = 0;
330 : 24 : ld->lastRes = NULL;
331 : 24 : ld->tmpRes = NULL;
332 : 24 : setCorrLex(ld, correspondLexem);
333 : 24 : return res;
334 : : }
335 : :
336 : : /*
337 : : * Dict don't want next lexem and didn't recognize anything, redo
338 : : * from ld->towork.head
339 : : */
6081 tgl@sss.pgh.pa.us 340 :UBC 0 : ld->curDictId = InvalidOid;
341 : 0 : return LexizeExec(ld, correspondLexem);
342 : : }
343 : : }
344 : :
6081 tgl@sss.pgh.pa.us 345 :CBC 13823 : setCorrLex(ld, correspondLexem);
346 : 13823 : return NULL;
347 : : }
348 : :
349 : : /*
350 : : * Parse string and lexize words.
351 : : *
352 : : * prs will be filled in.
353 : : */
354 : : void
5995 bruce@momjian.us 355 : 2161 : parsetext(Oid cfgId, ParsedText *prs, char *buf, int buflen)
356 : : {
357 : : int type,
565 peter@eisentraut.org 358 : 2161 : lenlemm = 0; /* silence compiler warning */
6081 tgl@sss.pgh.pa.us 359 : 2161 : char *lemm = NULL;
360 : : LexizeData ldata;
361 : : TSLexeme *norms;
362 : : TSConfigCacheEntry *cfg;
363 : : TSParserCacheEntry *prsobj;
364 : : void *prsdata;
365 : :
366 : 2161 : cfg = lookup_ts_config_cache(cfgId);
367 : 2161 : prsobj = lookup_ts_parser_cache(cfg->prsId);
368 : :
369 : 2161 : prsdata = (void *) DatumGetPointer(FunctionCall2(&prsobj->prsstart,
370 : : PointerGetDatum(buf),
371 : : Int32GetDatum(buflen)));
372 : :
373 : 2161 : LexizeInit(&ldata, cfg);
374 : :
375 : : do
376 : : {
377 : 8752 : type = DatumGetInt32(FunctionCall3(&(prsobj->prstoken),
378 : : PointerGetDatum(prsdata),
379 : : PointerGetDatum(&lemm),
380 : : PointerGetDatum(&lenlemm)));
381 : :
382 [ + + - + ]: 8752 : if (type > 0 && lenlemm >= MAXSTRLEN)
383 : : {
384 : : #ifdef IGNORE_LONGLEXEME
6081 tgl@sss.pgh.pa.us 385 [ # # ]:UBC 0 : ereport(NOTICE,
386 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
387 : : errmsg("word is too long to be indexed"),
388 : : errdetail("Words longer than %d characters are ignored.",
389 : : MAXSTRLEN)));
390 : 0 : continue;
391 : : #else
392 : : ereport(ERROR,
393 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
394 : : errmsg("word is too long to be indexed"),
395 : : errdetail("Words longer than %d characters are ignored.",
396 : : MAXSTRLEN)));
397 : : #endif
398 : : }
399 : :
6081 tgl@sss.pgh.pa.us 400 :CBC 8752 : LexizeAddLemm(&ldata, type, lemm, lenlemm);
401 : :
402 [ + + ]: 13011 : while ((norms = LexizeExec(&ldata, NULL)) != NULL)
403 : : {
404 : 4259 : TSLexeme *ptr = norms;
405 : :
406 : 4259 : prs->pos++; /* set pos */
407 : :
408 [ + + ]: 7915 : while (ptr->lexeme)
409 : : {
410 [ + + ]: 3656 : if (prs->curwords == prs->lenwords)
411 : : {
412 : 166 : prs->lenwords *= 2;
432 peter@eisentraut.org 413 : 166 : prs->words = (ParsedWord *) repalloc(prs->words, prs->lenwords * sizeof(ParsedWord));
414 : : }
415 : :
6081 tgl@sss.pgh.pa.us 416 [ + + ]: 3656 : if (ptr->flags & TSL_ADDPOS)
417 : 12 : prs->pos++;
418 : 3656 : prs->words[prs->curwords].len = strlen(ptr->lexeme);
419 : 3656 : prs->words[prs->curwords].word = ptr->lexeme;
420 : 3656 : prs->words[prs->curwords].nvariant = ptr->nvariant;
5812 421 : 3656 : prs->words[prs->curwords].flags = ptr->flags & TSL_PREFIX;
6081 422 : 3656 : prs->words[prs->curwords].alen = 0;
423 : 3656 : prs->words[prs->curwords].pos.pos = LIMITPOS(prs->pos);
424 : 3656 : ptr++;
425 : 3656 : prs->curwords++;
426 : : }
427 : 4259 : pfree(norms);
428 : : }
429 [ + + ]: 8752 : } while (type > 0);
430 : :
431 : 2161 : FunctionCall1(&(prsobj->prsend), PointerGetDatum(prsdata));
432 : 2161 : }
433 : :
434 : : /*
435 : : * Headline framework
436 : : */
437 : :
438 : : /* Add a word to prs->words[] */
439 : : static void
5995 bruce@momjian.us 440 : 4884 : hladdword(HeadlineParsedText *prs, char *buf, int buflen, int type)
441 : : {
1018 drowley@postgresql.o 442 [ + + ]: 4884 : if (prs->curwords >= prs->lenwords)
443 : : {
6081 tgl@sss.pgh.pa.us 444 : 27 : prs->lenwords *= 2;
432 peter@eisentraut.org 445 : 27 : prs->words = (HeadlineWordEntry *) repalloc(prs->words, prs->lenwords * sizeof(HeadlineWordEntry));
446 : : }
6077 tgl@sss.pgh.pa.us 447 : 4884 : memset(&(prs->words[prs->curwords]), 0, sizeof(HeadlineWordEntry));
6081 448 : 4884 : prs->words[prs->curwords].type = (uint8) type;
449 : 4884 : prs->words[prs->curwords].len = buflen;
450 : 4884 : prs->words[prs->curwords].word = palloc(buflen);
451 : 4884 : memcpy(prs->words[prs->curwords].word, buf, buflen);
452 : 4884 : prs->curwords++;
453 : 4884 : }
454 : :
455 : : /*
456 : : * Add pos and matching-query-item data to the just-added word.
457 : : * Here, buf/buflen represent a processed lexeme, not raw token text.
458 : : *
459 : : * If the query contains more than one matching item, we replicate
460 : : * the last-added word so that each item can be pointed to. The
461 : : * duplicate entries are marked with repeated = 1.
462 : : */
463 : : static void
2929 teodor@sigaev.ru 464 : 1574 : hlfinditem(HeadlineParsedText *prs, TSQuery query, int32 pos, char *buf, int buflen)
465 : : {
466 : : int i;
6081 tgl@sss.pgh.pa.us 467 : 1574 : QueryItem *item = GETQUERY(query);
468 : : HeadlineWordEntry *word;
469 : :
470 [ + + ]: 1640 : while (prs->curwords + query->size >= prs->lenwords)
471 : : {
472 : 66 : prs->lenwords *= 2;
432 peter@eisentraut.org 473 : 66 : prs->words = (HeadlineWordEntry *) repalloc(prs->words, prs->lenwords * sizeof(HeadlineWordEntry));
474 : : }
475 : :
6081 tgl@sss.pgh.pa.us 476 : 1574 : word = &(prs->words[prs->curwords - 1]);
2929 teodor@sigaev.ru 477 : 1574 : word->pos = LIMITPOS(pos);
6081 tgl@sss.pgh.pa.us 478 [ + + ]: 7474 : for (i = 0; i < query->size; i++)
479 : : {
6064 teodor@sigaev.ru 480 [ + + + + ]: 9556 : if (item->type == QI_VAL &&
5386 peter_e@gmx.net 481 : 3656 : tsCompareString(GETOPERAND(query) + item->qoperand.distance, item->qoperand.length,
482 : 3656 : buf, buflen, item->qoperand.prefix) == 0)
483 : : {
6081 tgl@sss.pgh.pa.us 484 [ - + ]: 307 : if (word->item)
485 : : {
6077 tgl@sss.pgh.pa.us 486 :UBC 0 : memcpy(&(prs->words[prs->curwords]), word, sizeof(HeadlineWordEntry));
5386 peter_e@gmx.net 487 : 0 : prs->words[prs->curwords].item = &item->qoperand;
6081 tgl@sss.pgh.pa.us 488 : 0 : prs->words[prs->curwords].repeated = 1;
489 : 0 : prs->curwords++;
490 : : }
491 : : else
5386 peter_e@gmx.net 492 :CBC 307 : word->item = &item->qoperand;
493 : : }
6081 tgl@sss.pgh.pa.us 494 : 5900 : item++;
495 : : }
496 : 1574 : }
497 : :
498 : : static void
5995 bruce@momjian.us 499 : 7545 : addHLParsedLex(HeadlineParsedText *prs, TSQuery query, ParsedLex *lexs, TSLexeme *norms)
500 : : {
501 : : ParsedLex *tmplexs;
502 : : TSLexeme *ptr;
503 : : int32 savedpos;
504 : :
6081 tgl@sss.pgh.pa.us 505 [ + + ]: 12616 : while (lexs)
506 : : {
507 [ + + ]: 5071 : if (lexs->type > 0)
508 : 4884 : hladdword(prs, lexs->lemm, lexs->lenlemm, lexs->type);
509 : :
510 : 5071 : ptr = norms;
2929 teodor@sigaev.ru 511 : 5071 : savedpos = prs->vectorpos;
6081 tgl@sss.pgh.pa.us 512 [ + + + + ]: 6645 : while (ptr && ptr->lexeme)
513 : : {
2929 teodor@sigaev.ru 514 [ - + ]: 1574 : if (ptr->flags & TSL_ADDPOS)
2929 teodor@sigaev.ru 515 :UBC 0 : savedpos++;
2929 teodor@sigaev.ru 516 :CBC 1574 : hlfinditem(prs, query, savedpos, ptr->lexeme, strlen(ptr->lexeme));
6081 tgl@sss.pgh.pa.us 517 : 1574 : ptr++;
518 : : }
519 : :
520 : 5071 : tmplexs = lexs->next;
521 : 5071 : pfree(lexs);
522 : 5071 : lexs = tmplexs;
523 : : }
524 : :
525 [ + + ]: 7545 : if (norms)
526 : : {
527 : 2474 : ptr = norms;
528 [ + + ]: 4048 : while (ptr->lexeme)
529 : : {
2929 teodor@sigaev.ru 530 [ - + ]: 1574 : if (ptr->flags & TSL_ADDPOS)
2929 teodor@sigaev.ru 531 :UBC 0 : prs->vectorpos++;
6081 tgl@sss.pgh.pa.us 532 :CBC 1574 : pfree(ptr->lexeme);
533 : 1574 : ptr++;
534 : : }
535 : 2474 : pfree(norms);
536 : : }
537 : 7545 : }
538 : :
539 : : void
5995 bruce@momjian.us 540 : 187 : hlparsetext(Oid cfgId, HeadlineParsedText *prs, TSQuery query, char *buf, int buflen)
541 : : {
542 : : int type,
565 peter@eisentraut.org 543 : 187 : lenlemm = 0; /* silence compiler warning */
6081 tgl@sss.pgh.pa.us 544 : 187 : char *lemm = NULL;
545 : : LexizeData ldata;
546 : : TSLexeme *norms;
547 : : ParsedLex *lexs;
548 : : TSConfigCacheEntry *cfg;
549 : : TSParserCacheEntry *prsobj;
550 : : void *prsdata;
551 : :
552 : 187 : cfg = lookup_ts_config_cache(cfgId);
553 : 187 : prsobj = lookup_ts_parser_cache(cfg->prsId);
554 : :
555 : 187 : prsdata = (void *) DatumGetPointer(FunctionCall2(&(prsobj->prsstart),
556 : : PointerGetDatum(buf),
557 : : Int32GetDatum(buflen)));
558 : :
559 : 187 : LexizeInit(&ldata, cfg);
560 : :
561 : : do
562 : : {
563 : 5071 : type = DatumGetInt32(FunctionCall3(&(prsobj->prstoken),
564 : : PointerGetDatum(prsdata),
565 : : PointerGetDatum(&lemm),
566 : : PointerGetDatum(&lenlemm)));
567 : :
568 [ + + - + ]: 5071 : if (type > 0 && lenlemm >= MAXSTRLEN)
569 : : {
570 : : #ifdef IGNORE_LONGLEXEME
6081 tgl@sss.pgh.pa.us 571 [ # # ]:UBC 0 : ereport(NOTICE,
572 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
573 : : errmsg("word is too long to be indexed"),
574 : : errdetail("Words longer than %d characters are ignored.",
575 : : MAXSTRLEN)));
576 : 0 : continue;
577 : : #else
578 : : ereport(ERROR,
579 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
580 : : errmsg("word is too long to be indexed"),
581 : : errdetail("Words longer than %d characters are ignored.",
582 : : MAXSTRLEN)));
583 : : #endif
584 : : }
585 : :
6081 tgl@sss.pgh.pa.us 586 :CBC 5071 : LexizeAddLemm(&ldata, type, lemm, lenlemm);
587 : :
588 : : do
589 : : {
590 [ + + ]: 7545 : if ((norms = LexizeExec(&ldata, &lexs)) != NULL)
591 : : {
2929 teodor@sigaev.ru 592 : 2474 : prs->vectorpos++;
6081 tgl@sss.pgh.pa.us 593 : 2474 : addHLParsedLex(prs, query, lexs, norms);
594 : : }
595 : : else
596 : 5071 : addHLParsedLex(prs, query, lexs, NULL);
597 [ + + ]: 7545 : } while (norms);
598 [ + + ]: 5071 : } while (type > 0);
599 : :
600 : 187 : FunctionCall1(&(prsobj->prsend), PointerGetDatum(prsdata));
601 : 187 : }
602 : :
603 : : /*
604 : : * Generate the headline, as a text object, from HeadlineParsedText.
605 : : */
606 : : text *
5995 bruce@momjian.us 607 : 187 : generateHeadline(HeadlineParsedText *prs)
608 : : {
609 : : text *out;
610 : : char *ptr;
5421 611 : 187 : int len = 128;
612 : 187 : int numfragments = 0;
4311 peter_e@gmx.net 613 : 187 : int16 infrag = 0;
614 : :
6077 tgl@sss.pgh.pa.us 615 : 187 : HeadlineWordEntry *wrd = prs->words;
616 : :
6081 617 : 187 : out = (text *) palloc(len);
618 : 187 : ptr = ((char *) out) + VARHDRSZ;
619 : :
620 [ + + ]: 5071 : while (wrd - prs->words < prs->curwords)
621 : : {
5658 teodor@sigaev.ru 622 [ + + ]: 4932 : while (wrd->len + prs->stopsellen + prs->startsellen + prs->fragdelimlen + (ptr - ((char *) out)) >= len)
623 : : {
6081 tgl@sss.pgh.pa.us 624 : 48 : int dist = ptr - ((char *) out);
625 : :
626 : 48 : len *= 2;
627 : 48 : out = (text *) repalloc(out, len);
628 : 48 : ptr = ((char *) out) + dist;
629 : : }
630 : :
631 [ + + + - ]: 4884 : if (wrd->in && !wrd->repeated)
632 : : {
5658 teodor@sigaev.ru 633 [ + + ]: 2634 : if (!infrag)
634 : : {
635 : :
636 : : /* start of a new fragment */
637 : 190 : infrag = 1;
5421 bruce@momjian.us 638 : 190 : numfragments++;
639 : : /* add a fragment delimiter if this is after the first one */
5658 teodor@sigaev.ru 640 [ + + ]: 190 : if (numfragments > 1)
641 : : {
642 : 6 : memcpy(ptr, prs->fragdelim, prs->fragdelimlen);
643 : 6 : ptr += prs->fragdelimlen;
644 : : }
645 : : }
6081 tgl@sss.pgh.pa.us 646 [ - + ]: 2634 : if (wrd->replace)
647 : : {
6081 tgl@sss.pgh.pa.us 648 :UBC 0 : *ptr = ' ';
649 : 0 : ptr++;
650 : : }
5568 teodor@sigaev.ru 651 [ + + ]:CBC 2634 : else if (!wrd->skip)
652 : : {
6081 tgl@sss.pgh.pa.us 653 [ + + ]: 2631 : if (wrd->selected)
654 : : {
655 : 250 : memcpy(ptr, prs->startsel, prs->startsellen);
656 : 250 : ptr += prs->startsellen;
657 : : }
658 : 2631 : memcpy(ptr, wrd->word, wrd->len);
659 : 2631 : ptr += wrd->len;
660 [ + + ]: 2631 : if (wrd->selected)
661 : : {
662 : 250 : memcpy(ptr, prs->stopsel, prs->stopsellen);
663 : 250 : ptr += prs->stopsellen;
664 : : }
665 : : }
666 : : }
667 [ + - ]: 2250 : else if (!wrd->repeated)
668 : : {
5658 teodor@sigaev.ru 669 [ + + ]: 2250 : if (infrag)
670 : 60 : infrag = 0;
6081 tgl@sss.pgh.pa.us 671 : 2250 : pfree(wrd->word);
672 : : }
673 : :
674 : 4884 : wrd++;
675 : : }
676 : :
677 : 187 : SET_VARSIZE(out, ptr - ((char *) out));
678 : 187 : return out;
679 : : }
|