Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * ts_parse.c
4 : * main parse functions for tsearch
5 : *
6 : * Portions Copyright (c) 1996-2023, 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
5624 bruce 61 GIC 2348 : LexizeInit(LexizeData *ld, TSConfigCacheEntry *cfg)
5710 tgl 62 ECB : {
5710 tgl 63 GIC 2348 : ld->cfg = cfg;
5710 tgl 64 CBC 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 : }
5710 tgl 71 ECB :
72 : static void
5624 bruce 73 GIC 27646 : LPLAddTail(ListParsedLex *list, ParsedLex *newpl)
5710 tgl 74 ECB : {
5710 tgl 75 GIC 27646 : if (list->tail)
5710 tgl 76 ECB : {
5710 tgl 77 GIC 111 : list->tail->next = newpl;
5710 tgl 78 CBC 111 : list->tail = newpl;
5710 tgl 79 ECB : }
80 : else
5710 tgl 81 GIC 27535 : list->head = list->tail = newpl;
5710 tgl 82 CBC 27646 : newpl->next = NULL;
83 27646 : }
5710 tgl 84 ECB :
85 : static ParsedLex *
5624 bruce 86 GIC 13823 : LPLRemoveHead(ListParsedLex *list)
5710 tgl 87 ECB : {
5710 tgl 88 GIC 13823 : ParsedLex *res = list->head;
5710 tgl 89 ECB :
5710 tgl 90 GIC 13823 : if (list->head)
5710 tgl 91 CBC 13823 : list->head = list->head->next;
5710 tgl 92 ECB :
5710 tgl 93 GIC 13823 : if (list->head == NULL)
5710 tgl 94 CBC 13760 : list->tail = NULL;
5710 tgl 95 ECB :
5710 tgl 96 GIC 13823 : return res;
5710 tgl 97 ECB : }
98 :
99 : static void
5624 bruce 100 GIC 13823 : LexizeAddLemm(LexizeData *ld, int type, char *lemm, int lenlemm)
5710 tgl 101 ECB : {
5710 tgl 102 GIC 13823 : ParsedLex *newpl = (ParsedLex *) palloc(sizeof(ParsedLex));
5710 tgl 103 ECB :
5710 tgl 104 GIC 13823 : newpl->type = type;
5710 tgl 105 CBC 13823 : newpl->lemm = lemm;
106 13823 : newpl->lenlemm = lenlemm;
107 13823 : LPLAddTail(&ld->towork, newpl);
108 13823 : ld->curSub = ld->towork.tail;
109 13823 : }
5710 tgl 110 ECB :
111 : static void
5624 bruce 112 GIC 13823 : RemoveHead(LexizeData *ld)
5710 tgl 113 ECB : {
5710 tgl 114 GIC 13823 : LPLAddTail(&ld->waste, LPLRemoveHead(&ld->towork));
5710 tgl 115 ECB :
5710 tgl 116 GIC 13823 : ld->posDict = 0;
5710 tgl 117 CBC 13823 : }
5710 tgl 118 ECB :
119 : static void
5624 bruce 120 GIC 20556 : setCorrLex(LexizeData *ld, ParsedLex **correspondLexem)
5710 tgl 121 ECB : {
5710 tgl 122 GIC 20556 : if (correspondLexem)
5710 tgl 123 ECB : {
5710 tgl 124 GIC 7545 : *correspondLexem = ld->waste.head;
5710 tgl 125 ECB : }
126 : else
127 : {
128 : ParsedLex *tmp,
5710 tgl 129 GIC 13011 : *ptr = ld->waste.head;
5710 tgl 130 ECB :
5710 tgl 131 GIC 21763 : while (ptr)
5710 tgl 132 ECB : {
5710 tgl 133 GIC 8752 : tmp = ptr->next;
5710 tgl 134 CBC 8752 : pfree(ptr);
135 8752 : ptr = tmp;
5710 tgl 136 ECB : }
137 : }
5710 tgl 138 GIC 20556 : ld->waste.head = ld->waste.tail = NULL;
5710 tgl 139 CBC 20556 : }
5710 tgl 140 ECB :
141 : static void
5624 bruce 142 GIC 24 : moveToWaste(LexizeData *ld, ParsedLex *stop)
5710 tgl 143 ECB : {
5710 tgl 144 GIC 24 : bool go = true;
5710 tgl 145 ECB :
5710 tgl 146 GIC 90 : while (ld->towork.head && go)
5710 tgl 147 ECB : {
5710 tgl 148 GIC 66 : if (ld->towork.head == stop)
5710 tgl 149 ECB : {
5710 tgl 150 GIC 24 : ld->curSub = stop->next;
5710 tgl 151 CBC 24 : go = false;
5710 tgl 152 ECB : }
5710 tgl 153 GIC 66 : RemoveHead(ld);
5710 tgl 154 ECB : }
5710 tgl 155 GIC 24 : }
5710 tgl 156 ECB :
157 : static void
5624 bruce 158 GIC 24 : setNewTmpRes(LexizeData *ld, ParsedLex *lex, TSLexeme *res)
5710 tgl 159 ECB : {
5710 tgl 160 GIC 24 : if (ld->tmpRes)
5710 tgl 161 ECB : {
162 : TSLexeme *ptr;
163 :
5710 tgl 164 GIC 12 : for (ptr = ld->tmpRes; ptr->lexeme; ptr++)
5710 tgl 165 CBC 6 : pfree(ptr->lexeme);
166 6 : pfree(ld->tmpRes);
5710 tgl 167 ECB : }
5710 tgl 168 GIC 24 : ld->tmpRes = res;
5710 tgl 169 CBC 24 : ld->lastRes = lex;
170 24 : }
5710 tgl 171 ECB :
172 : static TSLexeme *
5624 bruce 173 GIC 20580 : LexizeExec(LexizeData *ld, ParsedLex **correspondLexem)
5710 tgl 174 ECB : {
175 : int i;
176 : ListDictionary *map;
177 : TSDictionaryCacheEntry *dict;
178 : TSLexeme *res;
179 :
5710 tgl 180 GIC 20580 : if (ld->curDictId == InvalidOid)
5710 tgl 181 ECB : {
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 :
5710 tgl 187 GIC 27541 : while (ld->towork.head)
5710 tgl 188 ECB : {
5710 tgl 189 GIC 13781 : ParsedLex *curVal = ld->towork.head;
4982 teodor 190 CBC 13781 : char *curValLemm = curVal->lemm;
4790 bruce 191 13781 : int curValLenLemm = curVal->lenlemm;
5710 tgl 192 ECB :
5710 tgl 193 GIC 13781 : map = ld->cfg->map + curVal->type;
5710 tgl 194 ECB :
5710 tgl 195 GIC 13781 : if (curVal->type == 0 || curVal->type >= ld->cfg->lenmap || map->len == 0)
5710 tgl 196 ECB : {
197 : /* skip this type of lexeme */
5710 tgl 198 GIC 7048 : RemoveHead(ld);
5710 tgl 199 CBC 7048 : continue;
5710 tgl 200 ECB : }
201 :
5710 tgl 202 GIC 6979 : for (i = ld->posDict; i < map->len; i++)
5710 tgl 203 ECB : {
5710 tgl 204 GIC 6979 : dict = lookup_ts_dictionary_cache(map->dictIds[i]);
5710 tgl 205 ECB :
5710 tgl 206 GIC 6979 : ld->dictState.isend = ld->dictState.getnext = false;
5015 peter_e 207 CBC 6979 : ld->dictState.private_state = NULL;
1165 alvherre 208 6979 : res = (TSLexeme *) DatumGetPointer(FunctionCall4(&(dict->lexize),
2118 tgl 209 ECB : PointerGetDatum(dict->dictData),
210 : PointerGetDatum(curValLemm),
211 : Int32GetDatum(curValLenLemm),
212 : PointerGetDatum(&ld->dictState)));
213 :
5710 tgl 214 GIC 6979 : if (ld->dictState.getnext)
5710 tgl 215 ECB : {
216 : /*
217 : * dictionary wants next word, so setup and store current
218 : * position and go to multiword mode
219 : */
220 :
5710 tgl 221 GIC 24 : ld->curDictId = DatumGetObjectId(map->dictIds[i]);
5710 tgl 222 CBC 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);
5710 tgl 227 ECB : }
228 :
5710 tgl 229 GIC 6955 : if (!res) /* dictionary doesn't know this lexeme */
5710 tgl 230 CBC 246 : continue;
5710 tgl 231 ECB :
4790 bruce 232 GIC 6709 : if (res->flags & TSL_FILTER)
4982 teodor 233 ECB : {
4982 teodor 234 UIC 0 : curValLemm = res->lexeme;
4982 teodor 235 UBC 0 : curValLenLemm = strlen(res->lexeme);
236 0 : continue;
4982 teodor 237 EUB : }
238 :
5710 tgl 239 GIC 6709 : RemoveHead(ld);
5710 tgl 240 CBC 6709 : setCorrLex(ld, correspondLexem);
241 6709 : return res;
5710 tgl 242 ECB : }
243 :
5710 tgl 244 UIC 0 : RemoveHead(ld);
5710 tgl 245 EUB : }
246 : }
247 : else
248 : { /* curDictId is valid */
5710 tgl 249 GIC 87 : dict = lookup_ts_dictionary_cache(ld->curDictId);
5710 tgl 250 ECB :
251 : /*
252 : * Dictionary ld->curDictId asks us about following words
253 : */
254 :
5710 tgl 255 GIC 126 : while (ld->curSub)
5710 tgl 256 ECB : {
5710 tgl 257 GIC 63 : ParsedLex *curVal = ld->curSub;
5710 tgl 258 ECB :
5710 tgl 259 GIC 63 : map = ld->cfg->map + curVal->type;
5710 tgl 260 ECB :
5710 tgl 261 GIC 63 : if (curVal->type != 0)
5710 tgl 262 ECB : {
5710 tgl 263 GIC 60 : bool dictExists = false;
5710 tgl 264 ECB :
5710 tgl 265 GIC 60 : if (curVal->type >= ld->cfg->lenmap || map->len == 0)
5710 tgl 266 ECB : {
267 : /* skip this type of lexeme */
5710 tgl 268 GIC 30 : ld->curSub = curVal->next;
5710 tgl 269 CBC 30 : continue;
5710 tgl 270 ECB : }
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 : */
5710 tgl 277 GIC 90 : for (i = 0; i < map->len && !dictExists; i++)
5710 tgl 278 CBC 60 : if (ld->curDictId == DatumGetObjectId(map->dictIds[i]))
279 30 : dictExists = true;
5710 tgl 280 ECB :
5710 tgl 281 GIC 30 : if (!dictExists)
5710 tgl 282 ECB : {
283 : /*
284 : * Dictionary can't work with current type of lexeme,
285 : * return to basic mode and redo all stored lexemes
286 : */
5710 tgl 287 UIC 0 : ld->curDictId = InvalidOid;
5710 tgl 288 UBC 0 : return LexizeExec(ld, correspondLexem);
5710 tgl 289 EUB : }
290 : }
291 :
578 michael 292 GIC 33 : ld->dictState.isend = (curVal->type == 0);
5710 tgl 293 CBC 33 : ld->dictState.getnext = false;
5710 tgl 294 ECB :
1165 alvherre 295 GIC 33 : res = (TSLexeme *) DatumGetPointer(FunctionCall4(&(dict->lexize),
2118 tgl 296 ECB : PointerGetDatum(dict->dictData),
297 : PointerGetDatum(curVal->lemm),
298 : Int32GetDatum(curVal->lenlemm),
299 : PointerGetDatum(&ld->dictState)));
300 :
5710 tgl 301 GIC 33 : if (ld->dictState.getnext)
5710 tgl 302 ECB : {
303 : /* Dictionary wants one more */
5710 tgl 304 GIC 9 : ld->curSub = curVal->next;
5710 tgl 305 CBC 9 : if (res)
306 6 : setNewTmpRes(ld, curVal, res);
307 9 : continue;
5710 tgl 308 ECB : }
309 :
5710 tgl 310 GIC 24 : if (res || ld->tmpRes)
5710 tgl 311 ECB : {
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 : */
5710 tgl 317 GIC 24 : if (res)
5710 tgl 318 ECB : {
5710 tgl 319 GIC 12 : moveToWaste(ld, ld->curSub);
5710 tgl 320 ECB : }
321 : else
322 : {
5710 tgl 323 GIC 12 : res = ld->tmpRes;
5710 tgl 324 CBC 12 : moveToWaste(ld, ld->lastRes);
5710 tgl 325 ECB : }
326 :
327 : /* reset to initial state */
5710 tgl 328 GIC 24 : ld->curDictId = InvalidOid;
5710 tgl 329 CBC 24 : ld->posDict = 0;
330 24 : ld->lastRes = NULL;
331 24 : ld->tmpRes = NULL;
332 24 : setCorrLex(ld, correspondLexem);
333 24 : return res;
5710 tgl 334 ECB : }
335 :
336 : /*
337 : * Dict don't want next lexem and didn't recognize anything, redo
338 : * from ld->towork.head
339 : */
5710 tgl 340 UIC 0 : ld->curDictId = InvalidOid;
5710 tgl 341 UBC 0 : return LexizeExec(ld, correspondLexem);
5710 tgl 342 EUB : }
343 : }
344 :
5710 tgl 345 GIC 13823 : setCorrLex(ld, correspondLexem);
5710 tgl 346 CBC 13823 : return NULL;
5710 tgl 347 ECB : }
348 :
349 : /*
350 : * Parse string and lexize words.
351 : *
352 : * prs will be filled in.
353 : */
354 : void
5624 bruce 355 GIC 2161 : parsetext(Oid cfgId, ParsedText *prs, char *buf, int buflen)
5710 tgl 356 ECB : {
357 : int type,
194 peter 358 GNC 2161 : lenlemm = 0; /* silence compiler warning */
5710 tgl 359 CBC 2161 : char *lemm = NULL;
5710 tgl 360 ECB : LexizeData ldata;
361 : TSLexeme *norms;
362 : TSConfigCacheEntry *cfg;
363 : TSParserCacheEntry *prsobj;
364 : void *prsdata;
365 :
5710 tgl 366 GIC 2161 : cfg = lookup_ts_config_cache(cfgId);
5710 tgl 367 CBC 2161 : prsobj = lookup_ts_parser_cache(cfg->prsId);
5710 tgl 368 ECB :
5710 tgl 369 GIC 2161 : prsdata = (void *) DatumGetPointer(FunctionCall2(&prsobj->prsstart,
5710 tgl 370 ECB : PointerGetDatum(buf),
371 : Int32GetDatum(buflen)));
372 :
5710 tgl 373 GIC 2161 : LexizeInit(&ldata, cfg);
5710 tgl 374 ECB :
375 : do
376 : {
5710 tgl 377 GIC 8752 : type = DatumGetInt32(FunctionCall3(&(prsobj->prstoken),
5710 tgl 378 ECB : PointerGetDatum(prsdata),
379 : PointerGetDatum(&lemm),
380 : PointerGetDatum(&lenlemm)));
381 :
5710 tgl 382 GIC 8752 : if (type > 0 && lenlemm >= MAXSTRLEN)
5710 tgl 383 ECB : {
384 : #ifdef IGNORE_LONGLEXEME
5710 tgl 385 UIC 0 : ereport(NOTICE,
5611 tgl 386 EUB : (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)));
5710 tgl 390 UIC 0 : continue;
5710 tgl 391 EUB : #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 :
5710 tgl 400 GIC 8752 : LexizeAddLemm(&ldata, type, lemm, lenlemm);
5710 tgl 401 ECB :
5710 tgl 402 GIC 13011 : while ((norms = LexizeExec(&ldata, NULL)) != NULL)
5710 tgl 403 ECB : {
5710 tgl 404 GIC 4259 : TSLexeme *ptr = norms;
5710 tgl 405 ECB :
5710 tgl 406 GIC 4259 : prs->pos++; /* set pos */
5710 tgl 407 ECB :
5710 tgl 408 GIC 7915 : while (ptr->lexeme)
5710 tgl 409 ECB : {
5710 tgl 410 GIC 3656 : if (prs->curwords == prs->lenwords)
5710 tgl 411 ECB : {
5710 tgl 412 GIC 166 : prs->lenwords *= 2;
61 peter 413 GNC 166 : prs->words = (ParsedWord *) repalloc(prs->words, prs->lenwords * sizeof(ParsedWord));
5710 tgl 414 ECB : }
415 :
5710 tgl 416 GIC 3656 : if (ptr->flags & TSL_ADDPOS)
5710 tgl 417 CBC 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;
5441 421 3656 : prs->words[prs->curwords].flags = ptr->flags & TSL_PREFIX;
5710 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++;
5710 tgl 426 ECB : }
5710 tgl 427 GIC 4259 : pfree(norms);
5710 tgl 428 ECB : }
5710 tgl 429 GIC 8752 : } while (type > 0);
5710 tgl 430 ECB :
5710 tgl 431 GIC 2161 : FunctionCall1(&(prsobj->prsend), PointerGetDatum(prsdata));
5710 tgl 432 CBC 2161 : }
5710 tgl 433 ECB :
434 : /*
435 : * Headline framework
436 : */
437 :
438 : /* Add a word to prs->words[] */
439 : static void
5624 bruce 440 GIC 4884 : hladdword(HeadlineParsedText *prs, char *buf, int buflen, int type)
5710 tgl 441 ECB : {
647 drowley 442 GIC 4884 : if (prs->curwords >= prs->lenwords)
5710 tgl 443 ECB : {
5710 tgl 444 GIC 27 : prs->lenwords *= 2;
61 peter 445 GNC 27 : prs->words = (HeadlineWordEntry *) repalloc(prs->words, prs->lenwords * sizeof(HeadlineWordEntry));
5710 tgl 446 ECB : }
5706 tgl 447 GIC 4884 : memset(&(prs->words[prs->curwords]), 0, sizeof(HeadlineWordEntry));
5710 tgl 448 CBC 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 : }
5710 tgl 454 ECB :
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
2558 teodor 464 GIC 1574 : hlfinditem(HeadlineParsedText *prs, TSQuery query, int32 pos, char *buf, int buflen)
5710 tgl 465 ECB : {
466 : int i;
5710 tgl 467 GIC 1574 : QueryItem *item = GETQUERY(query);
5706 tgl 468 ECB : HeadlineWordEntry *word;
469 :
5710 tgl 470 GIC 1640 : while (prs->curwords + query->size >= prs->lenwords)
5710 tgl 471 ECB : {
5710 tgl 472 GIC 66 : prs->lenwords *= 2;
61 peter 473 GNC 66 : prs->words = (HeadlineWordEntry *) repalloc(prs->words, prs->lenwords * sizeof(HeadlineWordEntry));
5710 tgl 474 ECB : }
475 :
5710 tgl 476 GIC 1574 : word = &(prs->words[prs->curwords - 1]);
2558 teodor 477 CBC 1574 : word->pos = LIMITPOS(pos);
5710 tgl 478 7474 : for (i = 0; i < query->size; i++)
5710 tgl 479 ECB : {
5693 teodor 480 GIC 9556 : if (item->type == QI_VAL &&
5015 peter_e 481 CBC 3656 : tsCompareString(GETOPERAND(query) + item->qoperand.distance, item->qoperand.length,
482 3656 : buf, buflen, item->qoperand.prefix) == 0)
5710 tgl 483 ECB : {
5710 tgl 484 GIC 307 : if (word->item)
5710 tgl 485 ECB : {
5706 tgl 486 UIC 0 : memcpy(&(prs->words[prs->curwords]), word, sizeof(HeadlineWordEntry));
5015 peter_e 487 UBC 0 : prs->words[prs->curwords].item = &item->qoperand;
5710 tgl 488 0 : prs->words[prs->curwords].repeated = 1;
489 0 : prs->curwords++;
5710 tgl 490 EUB : }
491 : else
5015 peter_e 492 GIC 307 : word->item = &item->qoperand;
5710 tgl 493 ECB : }
5710 tgl 494 GIC 5900 : item++;
5710 tgl 495 ECB : }
5710 tgl 496 GIC 1574 : }
5710 tgl 497 ECB :
498 : static void
5624 bruce 499 GIC 7545 : addHLParsedLex(HeadlineParsedText *prs, TSQuery query, ParsedLex *lexs, TSLexeme *norms)
5710 tgl 500 ECB : {
501 : ParsedLex *tmplexs;
502 : TSLexeme *ptr;
503 : int32 savedpos;
504 :
5710 tgl 505 GIC 12616 : while (lexs)
5710 tgl 506 ECB : {
5710 tgl 507 GIC 5071 : if (lexs->type > 0)
5710 tgl 508 CBC 4884 : hladdword(prs, lexs->lemm, lexs->lenlemm, lexs->type);
5710 tgl 509 ECB :
5710 tgl 510 GIC 5071 : ptr = norms;
2558 teodor 511 CBC 5071 : savedpos = prs->vectorpos;
5710 tgl 512 6645 : while (ptr && ptr->lexeme)
5710 tgl 513 ECB : {
2558 teodor 514 GIC 1574 : if (ptr->flags & TSL_ADDPOS)
2558 teodor 515 LBC 0 : savedpos++;
2558 teodor 516 GBC 1574 : hlfinditem(prs, query, savedpos, ptr->lexeme, strlen(ptr->lexeme));
5710 tgl 517 CBC 1574 : ptr++;
5710 tgl 518 ECB : }
519 :
5710 tgl 520 GIC 5071 : tmplexs = lexs->next;
5710 tgl 521 CBC 5071 : pfree(lexs);
522 5071 : lexs = tmplexs;
5710 tgl 523 ECB : }
524 :
5710 tgl 525 GIC 7545 : if (norms)
5710 tgl 526 ECB : {
5710 tgl 527 GIC 2474 : ptr = norms;
5710 tgl 528 CBC 4048 : while (ptr->lexeme)
5710 tgl 529 ECB : {
2558 teodor 530 GIC 1574 : if (ptr->flags & TSL_ADDPOS)
2558 teodor 531 LBC 0 : prs->vectorpos++;
5710 tgl 532 GBC 1574 : pfree(ptr->lexeme);
5710 tgl 533 CBC 1574 : ptr++;
5710 tgl 534 ECB : }
5710 tgl 535 GIC 2474 : pfree(norms);
5710 tgl 536 ECB : }
5710 tgl 537 GIC 7545 : }
5710 tgl 538 ECB :
539 : void
5624 bruce 540 GIC 187 : hlparsetext(Oid cfgId, HeadlineParsedText *prs, TSQuery query, char *buf, int buflen)
5710 tgl 541 ECB : {
542 : int type,
194 peter 543 GNC 187 : lenlemm = 0; /* silence compiler warning */
5710 tgl 544 CBC 187 : char *lemm = NULL;
5710 tgl 545 ECB : LexizeData ldata;
546 : TSLexeme *norms;
547 : ParsedLex *lexs;
548 : TSConfigCacheEntry *cfg;
549 : TSParserCacheEntry *prsobj;
550 : void *prsdata;
551 :
5710 tgl 552 GIC 187 : cfg = lookup_ts_config_cache(cfgId);
5710 tgl 553 CBC 187 : prsobj = lookup_ts_parser_cache(cfg->prsId);
5710 tgl 554 ECB :
5710 tgl 555 GIC 187 : prsdata = (void *) DatumGetPointer(FunctionCall2(&(prsobj->prsstart),
5710 tgl 556 ECB : PointerGetDatum(buf),
557 : Int32GetDatum(buflen)));
558 :
5710 tgl 559 GIC 187 : LexizeInit(&ldata, cfg);
5710 tgl 560 ECB :
561 : do
562 : {
5710 tgl 563 GIC 5071 : type = DatumGetInt32(FunctionCall3(&(prsobj->prstoken),
5710 tgl 564 ECB : PointerGetDatum(prsdata),
565 : PointerGetDatum(&lemm),
566 : PointerGetDatum(&lenlemm)));
567 :
5710 tgl 568 GIC 5071 : if (type > 0 && lenlemm >= MAXSTRLEN)
5710 tgl 569 ECB : {
570 : #ifdef IGNORE_LONGLEXEME
5710 tgl 571 UIC 0 : ereport(NOTICE,
5611 tgl 572 EUB : (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)));
5710 tgl 576 UIC 0 : continue;
5710 tgl 577 EUB : #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 :
5710 tgl 586 GIC 5071 : LexizeAddLemm(&ldata, type, lemm, lenlemm);
5710 tgl 587 ECB :
588 : do
589 : {
5710 tgl 590 GIC 7545 : if ((norms = LexizeExec(&ldata, &lexs)) != NULL)
2558 teodor 591 ECB : {
2558 teodor 592 GIC 2474 : prs->vectorpos++;
5710 tgl 593 CBC 2474 : addHLParsedLex(prs, query, lexs, norms);
2558 teodor 594 ECB : }
595 : else
5710 tgl 596 GIC 5071 : addHLParsedLex(prs, query, lexs, NULL);
5710 tgl 597 CBC 7545 : } while (norms);
598 5071 : } while (type > 0);
5710 tgl 599 ECB :
5710 tgl 600 GIC 187 : FunctionCall1(&(prsobj->prsend), PointerGetDatum(prsdata));
5710 tgl 601 CBC 187 : }
5710 tgl 602 ECB :
603 : /*
604 : * Generate the headline, as a text object, from HeadlineParsedText.
605 : */
606 : text *
5624 bruce 607 GIC 187 : generateHeadline(HeadlineParsedText *prs)
5710 tgl 608 ECB : {
609 : text *out;
610 : char *ptr;
5050 bruce 611 GIC 187 : int len = 128;
5050 bruce 612 CBC 187 : int numfragments = 0;
3940 peter_e 613 187 : int16 infrag = 0;
5287 teodor 614 ECB :
5706 tgl 615 GIC 187 : HeadlineWordEntry *wrd = prs->words;
5710 tgl 616 ECB :
5710 tgl 617 GIC 187 : out = (text *) palloc(len);
5710 tgl 618 CBC 187 : ptr = ((char *) out) + VARHDRSZ;
5710 tgl 619 ECB :
5710 tgl 620 GIC 5071 : while (wrd - prs->words < prs->curwords)
5710 tgl 621 ECB : {
5287 teodor 622 GIC 4932 : while (wrd->len + prs->stopsellen + prs->startsellen + prs->fragdelimlen + (ptr - ((char *) out)) >= len)
5710 tgl 623 ECB : {
5710 tgl 624 GIC 48 : int dist = ptr - ((char *) out);
5710 tgl 625 ECB :
5710 tgl 626 GIC 48 : len *= 2;
5710 tgl 627 CBC 48 : out = (text *) repalloc(out, len);
628 48 : ptr = ((char *) out) + dist;
5710 tgl 629 ECB : }
630 :
5710 tgl 631 GIC 4884 : if (wrd->in && !wrd->repeated)
5710 tgl 632 ECB : {
5287 teodor 633 GIC 2634 : if (!infrag)
5287 teodor 634 ECB : {
635 :
636 : /* start of a new fragment */
5287 teodor 637 GIC 190 : infrag = 1;
5050 bruce 638 CBC 190 : numfragments++;
2253 heikki.linnakangas 639 ECB : /* add a fragment delimiter if this is after the first one */
5287 teodor 640 GIC 190 : if (numfragments > 1)
5287 teodor 641 ECB : {
5287 teodor 642 GIC 6 : memcpy(ptr, prs->fragdelim, prs->fragdelimlen);
5287 teodor 643 CBC 6 : ptr += prs->fragdelimlen;
5050 bruce 644 ECB : }
645 : }
5710 tgl 646 GIC 2634 : if (wrd->replace)
5710 tgl 647 ECB : {
5710 tgl 648 UIC 0 : *ptr = ' ';
5710 tgl 649 UBC 0 : ptr++;
5710 tgl 650 EUB : }
5197 teodor 651 GIC 2634 : else if (!wrd->skip)
5710 tgl 652 ECB : {
5710 tgl 653 GIC 2631 : if (wrd->selected)
5710 tgl 654 ECB : {
5710 tgl 655 GIC 250 : memcpy(ptr, prs->startsel, prs->startsellen);
5710 tgl 656 CBC 250 : ptr += prs->startsellen;
5710 tgl 657 ECB : }
5710 tgl 658 GIC 2631 : memcpy(ptr, wrd->word, wrd->len);
5710 tgl 659 CBC 2631 : ptr += wrd->len;
660 2631 : if (wrd->selected)
5710 tgl 661 ECB : {
5710 tgl 662 GIC 250 : memcpy(ptr, prs->stopsel, prs->stopsellen);
5710 tgl 663 CBC 250 : ptr += prs->stopsellen;
5710 tgl 664 ECB : }
665 : }
666 : }
5710 tgl 667 GIC 2250 : else if (!wrd->repeated)
5287 teodor 668 ECB : {
5287 teodor 669 GIC 2250 : if (infrag)
5287 teodor 670 CBC 60 : infrag = 0;
5710 tgl 671 2250 : pfree(wrd->word);
5050 bruce 672 ECB : }
673 :
5710 tgl 674 GIC 4884 : wrd++;
5710 tgl 675 ECB : }
676 :
5710 tgl 677 GIC 187 : SET_VARSIZE(out, ptr - ((char *) out));
5710 tgl 678 CBC 187 : return out;
5710 tgl 679 ECB : }
|