Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * tsvector.c
4 : * I/O functions for tsvector
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : *
8 : *
9 : * IDENTIFICATION
10 : * src/backend/utils/adt/tsvector.c
11 : *
12 : *-------------------------------------------------------------------------
13 : */
14 :
15 : #include "postgres.h"
16 :
17 : #include "libpq/pqformat.h"
18 : #include "nodes/miscnodes.h"
19 : #include "tsearch/ts_locale.h"
20 : #include "tsearch/ts_utils.h"
21 : #include "utils/builtins.h"
22 : #include "utils/memutils.h"
23 : #include "varatt.h"
24 :
25 : typedef struct
26 : {
27 : WordEntry entry; /* must be first! */
28 : WordEntryPos *pos;
29 : int poslen; /* number of elements in pos */
30 : } WordEntryIN;
31 :
32 :
33 : /* Compare two WordEntryPos values for qsort */
34 : int
2557 teodor 35 GIC 504 : compareWordEntryPos(const void *a, const void *b)
36 : {
5624 bruce 37 CBC 504 : int apos = WEP_GETPOS(*(const WordEntryPos *) a);
5624 bruce 38 GIC 504 : int bpos = WEP_GETPOS(*(const WordEntryPos *) b);
5693 teodor 39 ECB :
5693 teodor 40 CBC 504 : if (apos == bpos)
5710 tgl 41 GIC 12 : return 0;
5693 teodor 42 CBC 492 : return (apos > bpos) ? 1 : -1;
5710 tgl 43 ECB : }
44 :
45 : /*
46 : * Removes duplicate pos entries. If there's two entries with same pos but
47 : * different weight, the higher weight is retained, so we can't use
48 : * qunique here.
49 : *
50 : * Returns new length.
51 : */
52 : static int
5624 bruce 53 GIC 4803 : uniquePos(WordEntryPos *a, int l)
54 : {
5710 tgl 55 ECB : WordEntryPos *ptr,
56 : *res;
57 :
5693 teodor 58 GIC 4803 : if (l <= 1)
5710 tgl 59 4536 : return l;
5710 tgl 60 ECB :
61 peter 61 GNC 267 : qsort(a, l, sizeof(WordEntryPos), compareWordEntryPos);
62 :
5647 tgl 63 CBC 267 : res = a;
5710 tgl 64 GIC 267 : ptr = a + 1;
5710 tgl 65 CBC 726 : while (ptr - a < l)
5710 tgl 66 ECB : {
5710 tgl 67 CBC 459 : if (WEP_GETPOS(*ptr) != WEP_GETPOS(*res))
68 : {
69 447 : res++;
5710 tgl 70 GIC 447 : *res = *ptr;
5647 tgl 71 CBC 447 : if (res - a >= MAXNUMPOS - 1 ||
72 447 : WEP_GETPOS(*res) == MAXENTRYPOS - 1)
5710 tgl 73 ECB : break;
74 : }
5710 tgl 75 GIC 12 : else if (WEP_GETWEIGHT(*ptr) > WEP_GETWEIGHT(*res))
76 3 : WEP_SETWEIGHT(*res, WEP_GETWEIGHT(*ptr));
5710 tgl 77 CBC 459 : ptr++;
5710 tgl 78 ECB : }
79 :
5710 tgl 80 GIC 267 : return res + 1 - a;
81 : }
5710 tgl 82 ECB :
83 : /* Compare two WordEntryIN values for qsort */
84 : static int
5693 teodor 85 GIC 536253 : compareentry(const void *va, const void *vb, void *arg)
86 : {
5647 tgl 87 CBC 536253 : const WordEntryIN *a = (const WordEntryIN *) va;
5647 tgl 88 GIC 536253 : const WordEntryIN *b = (const WordEntryIN *) vb;
5710 tgl 89 CBC 536253 : char *BufferStr = (char *) arg;
5710 tgl 90 ECB :
5050 bruce 91 CBC 1072506 : return tsCompareString(&BufferStr[a->entry.pos], a->entry.len,
5050 bruce 92 GIC 536253 : &BufferStr[b->entry.pos], b->entry.len,
5050 bruce 93 ECB : false);
5710 tgl 94 : }
95 :
96 : /*
97 : * Sort an array of WordEntryIN, remove duplicates.
98 : * *outbuflen receives the amount of space needed for strings and positions.
99 : */
100 : static int
5624 bruce 101 GIC 1853 : uniqueentry(WordEntryIN *a, int l, char *buf, int *outbuflen)
102 : {
5624 bruce 103 ECB : int buflen;
104 : WordEntryIN *ptr,
105 : *res;
106 :
5693 teodor 107 GIC 1853 : Assert(l >= 1);
108 :
5647 tgl 109 CBC 1853 : if (l > 1)
61 peter 110 GNC 1802 : qsort_arg(a, l, sizeof(WordEntryIN), compareentry, buf);
5693 teodor 111 ECB :
5647 tgl 112 GIC 1853 : buflen = 0;
5693 teodor 113 CBC 1853 : res = a;
5710 tgl 114 1853 : ptr = a + 1;
115 90414 : while (ptr - a < l)
5710 tgl 116 ECB : {
5710 tgl 117 GIC 88561 : if (!(ptr->entry.len == res->entry.len &&
5647 tgl 118 CBC 88027 : strncmp(&buf[ptr->entry.pos], &buf[res->entry.pos],
119 88027 : res->entry.len) == 0))
5710 tgl 120 ECB : {
121 : /* done accumulating data into *res, count space needed */
5647 tgl 122 GIC 85798 : buflen += res->entry.len;
5710 tgl 123 CBC 85798 : if (res->entry.haspos)
5710 tgl 124 ECB : {
5693 teodor 125 GIC 4497 : res->poslen = uniquePos(res->pos, res->poslen);
5647 tgl 126 CBC 4497 : buflen = SHORTALIGN(buflen);
127 4497 : buflen += res->poslen * sizeof(WordEntryPos) + sizeof(uint16);
5710 tgl 128 ECB : }
5710 tgl 129 GIC 85798 : res++;
3320 heikki.linnakangas 130 CBC 85798 : if (res != ptr)
131 44286 : memcpy(res, ptr, sizeof(WordEntryIN));
5710 tgl 132 ECB : }
5710 tgl 133 GIC 2763 : else if (ptr->entry.haspos)
5710 tgl 134 ECB : {
5710 tgl 135 GIC 159 : if (res->entry.haspos)
5710 tgl 136 ECB : {
137 : /* append ptr's positions to res's positions */
5624 bruce 138 GIC 156 : int newlen = ptr->poslen + res->poslen;
5693 teodor 139 ECB :
5647 tgl 140 GIC 156 : res->pos = (WordEntryPos *)
5647 tgl 141 CBC 156 : repalloc(res->pos, newlen * sizeof(WordEntryPos));
142 156 : memcpy(&res->pos[res->poslen], ptr->pos,
143 156 : ptr->poslen * sizeof(WordEntryPos));
5693 teodor 144 156 : res->poslen = newlen;
5710 tgl 145 156 : pfree(ptr->pos);
5710 tgl 146 ECB : }
147 : else
148 : {
149 : /* just give ptr's positions to pos */
5710 tgl 150 GIC 3 : res->entry.haspos = 1;
5710 tgl 151 CBC 3 : res->pos = ptr->pos;
5647 152 3 : res->poslen = ptr->poslen;
5710 tgl 153 ECB : }
154 : }
5710 tgl 155 GIC 88561 : ptr++;
5710 tgl 156 ECB : }
157 :
158 : /* count space needed for last item */
5647 tgl 159 GIC 1853 : buflen += res->entry.len;
5710 tgl 160 CBC 1853 : if (res->entry.haspos)
5710 tgl 161 ECB : {
5693 teodor 162 GIC 306 : res->poslen = uniquePos(res->pos, res->poslen);
5647 tgl 163 CBC 306 : buflen = SHORTALIGN(buflen);
164 306 : buflen += res->poslen * sizeof(WordEntryPos) + sizeof(uint16);
5710 tgl 165 ECB : }
166 :
5647 tgl 167 GIC 1853 : *outbuflen = buflen;
5710 tgl 168 CBC 1853 : return res + 1 - a;
5710 tgl 169 ECB : }
170 :
171 : static int
5624 bruce 172 UIC 0 : WordEntryCMP(WordEntry *a, WordEntry *b, char *buf)
5710 tgl 173 EUB : {
5710 tgl 174 UIC 0 : return compareentry(a, b, buf);
5710 tgl 175 EUB : }
176 :
177 :
178 : Datum
5710 tgl 179 GIC 1886 : tsvectorin(PG_FUNCTION_ARGS)
5710 tgl 180 ECB : {
5710 tgl 181 GIC 1886 : char *buf = PG_GETARG_CSTRING(0);
103 tgl 182 GNC 1886 : Node *escontext = fcinfo->context;
5710 tgl 183 ECB : TSVectorParseState state;
184 : WordEntryIN *arr;
185 : int totallen;
186 : int arrlen; /* allocated size of arr */
187 : WordEntry *inarr;
5693 teodor 188 GIC 1886 : int len = 0;
189 : TSVector in;
5693 teodor 190 ECB : int i;
191 : char *token;
192 : int toklen;
193 : WordEntryPos *pos;
194 : int poslen;
195 : char *strbuf;
196 : int stroff;
197 :
198 : /*
199 : * Tokens are appended to tmpbuf, cur is a pointer to the end of used
200 : * space in tmpbuf.
201 : */
202 : char *tmpbuf;
203 : char *cur;
5624 bruce 204 GIC 1886 : int buflen = 256; /* allocated size of tmpbuf */
205 :
103 tgl 206 GNC 1886 : state = init_tsvector_parser(buf, 0, escontext);
207 :
5693 teodor 208 CBC 1886 : arrlen = 64;
5693 teodor 209 GIC 1886 : arr = (WordEntryIN *) palloc(sizeof(WordEntryIN) * arrlen);
5710 tgl 210 CBC 1886 : cur = tmpbuf = (char *) palloc(buflen);
5710 tgl 211 ECB :
5693 teodor 212 CBC 92300 : while (gettoken_tsvector(state, &token, &toklen, &pos, &poslen, NULL))
213 : {
214 90414 : if (toklen >= MAXSTRLEN)
103 tgl 215 UNC 0 : ereturn(escontext, (Datum) 0,
5647 tgl 216 ECB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5710 tgl 217 EUB : errmsg("word is too long (%ld bytes, max %ld bytes)",
218 : (long) toklen,
219 : (long) (MAXSTRLEN - 1))));
220 :
5710 tgl 221 GIC 90414 : if (cur - tmpbuf > MAXSTRPOS)
103 tgl 222 UNC 0 : ereturn(escontext, (Datum) 0,
5647 tgl 223 ECB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5050 bruce 224 EUB : errmsg("string is too long for tsvector (%ld bytes, max %ld bytes)",
225 : (long) (cur - tmpbuf), (long) MAXSTRPOS)));
226 :
227 : /*
228 : * Enlarge buffers if needed
229 : */
5693 teodor 230 GIC 90414 : if (len >= arrlen)
231 : {
5693 teodor 232 CBC 657 : arrlen *= 2;
233 : arr = (WordEntryIN *)
61 peter 234 GNC 657 : repalloc(arr, sizeof(WordEntryIN) * arrlen);
235 : }
5693 teodor 236 CBC 90414 : while ((cur - tmpbuf) + toklen >= buflen)
237 : {
5624 bruce 238 LBC 0 : int dist = cur - tmpbuf;
239 :
5693 teodor 240 UBC 0 : buflen *= 2;
61 peter 241 UNC 0 : tmpbuf = (char *) repalloc(tmpbuf, buflen);
5693 teodor 242 UBC 0 : cur = tmpbuf + dist;
5693 teodor 243 EUB : }
5693 teodor 244 GBC 90414 : arr[len].entry.len = toklen;
5710 tgl 245 GIC 90414 : arr[len].entry.pos = cur - tmpbuf;
61 peter 246 GNC 90414 : memcpy(cur, token, toklen);
5693 teodor 247 CBC 90414 : cur += toklen;
5710 tgl 248 ECB :
5693 teodor 249 CBC 90414 : if (poslen != 0)
250 : {
5710 tgl 251 4959 : arr[len].entry.haspos = 1;
5693 teodor 252 GIC 4959 : arr[len].pos = pos;
5693 teodor 253 CBC 4959 : arr[len].poslen = poslen;
5710 tgl 254 ECB : }
255 : else
256 : {
5710 tgl 257 GIC 85455 : arr[len].entry.haspos = 0;
5647 258 85455 : arr[len].pos = NULL;
5647 tgl 259 CBC 85455 : arr[len].poslen = 0;
5647 tgl 260 ECB : }
5710 tgl 261 CBC 90414 : len++;
262 : }
5693 teodor 263 ECB :
5693 teodor 264 GIC 1883 : close_tsvector_parser(state);
265 :
266 : /* Did gettoken_tsvector fail? */
103 tgl 267 GNC 1883 : if (SOFT_ERROR_OCCURRED(escontext))
268 6 : PG_RETURN_NULL();
269 :
5710 tgl 270 CBC 1877 : if (len > 0)
5710 tgl 271 GIC 1853 : len = uniqueentry(arr, len, tmpbuf, &buflen);
272 : else
5710 tgl 273 CBC 24 : buflen = 0;
5647 tgl 274 ECB :
5647 tgl 275 GIC 1877 : if (buflen > MAXSTRPOS)
103 tgl 276 UNC 0 : ereturn(escontext, (Datum) 0,
5647 tgl 277 ECB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
278 : errmsg("string is too long for tsvector (%d bytes, max %d bytes)", buflen, MAXSTRPOS)));
279 :
5710 tgl 280 GIC 1877 : totallen = CALCDATASIZE(len, buflen);
5710 tgl 281 CBC 1877 : in = (TSVector) palloc0(totallen);
5710 tgl 282 GBC 1877 : SET_VARSIZE(in, totallen);
5710 tgl 283 GIC 1877 : in->size = len;
284 1877 : inarr = ARRPTR(in);
5647 285 1877 : strbuf = STRPTR(in);
5647 tgl 286 CBC 1877 : stroff = 0;
5710 287 89528 : for (i = 0; i < len; i++)
5710 tgl 288 ECB : {
5647 tgl 289 CBC 87651 : memcpy(strbuf + stroff, &tmpbuf[arr[i].entry.pos], arr[i].entry.len);
290 87651 : arr[i].entry.pos = stroff;
291 87651 : stroff += arr[i].entry.len;
5710 292 87651 : if (arr[i].entry.haspos)
5710 tgl 293 ECB : {
294 : /* This should be unreachable because of MAXNUMPOS restrictions */
5647 tgl 295 GIC 4803 : if (arr[i].poslen > 0xFFFF)
5693 teodor 296 LBC 0 : elog(ERROR, "positions array too long");
5693 teodor 297 ECB :
5647 tgl 298 : /* Copy number of positions */
5647 tgl 299 CBC 4803 : stroff = SHORTALIGN(stroff);
5647 tgl 300 GIC 4803 : *(uint16 *) (strbuf + stroff) = (uint16) arr[i].poslen;
301 4803 : stroff += sizeof(uint16);
5693 teodor 302 ECB :
5693 teodor 303 EUB : /* Copy positions */
5647 tgl 304 GIC 4803 : memcpy(strbuf + stroff, arr[i].pos, arr[i].poslen * sizeof(WordEntryPos));
305 4803 : stroff += arr[i].poslen * sizeof(WordEntryPos);
5693 teodor 306 ECB :
5710 tgl 307 CBC 4803 : pfree(arr[i].pos);
5710 tgl 308 ECB : }
5710 tgl 309 GIC 87651 : inarr[i] = arr[i].entry;
310 : }
5710 tgl 311 ECB :
5647 tgl 312 CBC 1877 : Assert((strbuf + stroff - (char *) in) == totallen);
313 :
5710 314 1877 : PG_RETURN_TSVECTOR(in);
315 : }
5710 tgl 316 ECB :
317 : Datum
5710 tgl 318 GIC 2378 : tsvectorout(PG_FUNCTION_ARGS)
5710 tgl 319 ECB : {
5710 tgl 320 GIC 2378 : TSVector out = PG_GETARG_TSVECTOR(0);
5710 tgl 321 ECB : char *outbuf;
322 : int32 i,
5710 tgl 323 GIC 2378 : lenbuf = 0,
324 : pp;
5710 tgl 325 CBC 2378 : WordEntry *ptr = ARRPTR(out);
326 : char *curbegin,
5710 tgl 327 ECB : *curin,
328 : *curout;
329 :
5710 tgl 330 CBC 2378 : lenbuf = out->size * 2 /* '' */ + out->size - 1 /* space */ + 2 /* \0 */ ;
5710 tgl 331 GIC 118939 : for (i = 0; i < out->size; i++)
5710 tgl 332 ECB : {
5710 tgl 333 GIC 116561 : lenbuf += ptr[i].len * 2 * pg_database_encoding_max_length() /* for escape */ ;
334 116561 : if (ptr[i].haspos)
335 6559 : lenbuf += 1 /* : */ + 7 /* int2 + , + weight */ * POSDATALEN(out, &(ptr[i]));
336 : }
5710 tgl 337 ECB :
5710 tgl 338 CBC 2378 : curout = outbuf = (char *) palloc(lenbuf);
5710 tgl 339 GIC 118939 : for (i = 0; i < out->size; i++)
5710 tgl 340 ECB : {
5710 tgl 341 CBC 116561 : curbegin = curin = STRPTR(out) + ptr->pos;
342 116561 : if (i != 0)
5710 tgl 343 GIC 114276 : *curout++ = ' ';
344 116561 : *curout++ = '\'';
5710 tgl 345 CBC 353066 : while (curin - curbegin < ptr->len)
5710 tgl 346 ECB : {
5710 tgl 347 GIC 236505 : int len = pg_mblen(curin);
5710 tgl 348 ECB :
5710 tgl 349 CBC 236505 : if (t_iseq(curin, '\''))
350 13 : *curout++ = '\'';
5623 teodor 351 236492 : else if (t_iseq(curin, '\\'))
352 45 : *curout++ = '\\';
353 :
5710 tgl 354 473010 : while (len--)
5710 tgl 355 GIC 236505 : *curout++ = *curin++;
5710 tgl 356 ECB : }
357 :
5710 tgl 358 CBC 116561 : *curout++ = '\'';
359 116561 : if ((pp = POSDATALEN(out, ptr)) != 0)
360 : {
5710 tgl 361 ECB : WordEntryPos *wptr;
362 :
5710 tgl 363 GIC 6559 : *curout++ = ':';
364 6559 : wptr = POSDATAPTR(out, ptr);
5710 tgl 365 CBC 13584 : while (pp)
5710 tgl 366 ECB : {
5710 tgl 367 GIC 7025 : curout += sprintf(curout, "%d", WEP_GETPOS(*wptr));
368 7025 : switch (WEP_GETWEIGHT(*wptr))
369 : {
5710 tgl 370 CBC 58 : case 3:
371 58 : *curout++ = 'A';
372 58 : break;
5710 tgl 373 GIC 34 : case 2:
5710 tgl 374 CBC 34 : *curout++ = 'B';
375 34 : break;
5710 tgl 376 GIC 115 : case 1:
5710 tgl 377 CBC 115 : *curout++ = 'C';
378 115 : break;
379 6818 : case 0:
5710 tgl 380 ECB : default:
5710 tgl 381 CBC 6818 : break;
5710 tgl 382 ECB : }
383 :
5710 tgl 384 CBC 7025 : if (pp > 1)
385 466 : *curout++ = ',';
386 7025 : pp--;
5710 tgl 387 GIC 7025 : wptr++;
5710 tgl 388 ECB : }
389 : }
5710 tgl 390 GIC 116561 : ptr++;
5710 tgl 391 ECB : }
392 :
5710 tgl 393 CBC 2378 : *curout = '\0';
394 2378 : PG_FREE_IF_COPY(out, 0);
5710 tgl 395 GIC 2378 : PG_RETURN_CSTRING(outbuf);
396 : }
5710 tgl 397 ECB :
398 : /*
399 : * Binary Input / Output functions. The binary format is as follows:
5693 teodor 400 : *
401 : * uint32 number of lexemes
5624 bruce 402 : *
403 : * for each lexeme:
404 : * lexeme text in client encoding, null-terminated
405 : * uint16 number of positions
406 : * for each position:
407 : * uint16 WordEntryPos
408 : */
409 :
410 : Datum
5710 tgl 411 UIC 0 : tsvectorsend(PG_FUNCTION_ARGS)
412 : {
413 0 : TSVector vec = PG_GETARG_TSVECTOR(0);
414 : StringInfoData buf;
415 : int i,
416 : j;
417 0 : WordEntry *weptr = ARRPTR(vec);
5710 tgl 418 EUB :
5710 tgl 419 UIC 0 : pq_begintypsend(&buf);
5710 tgl 420 EUB :
2006 andres 421 UIC 0 : pq_sendint32(&buf, vec->size);
5710 tgl 422 0 : for (i = 0; i < vec->size; i++)
423 : {
5624 bruce 424 EUB : uint16 npos;
425 :
426 : /*
427 : * the strings in the TSVector array are not null-terminated, so we
428 : * have to send the null-terminator separately
5710 tgl 429 : */
5693 teodor 430 UIC 0 : pq_sendtext(&buf, STRPTR(vec) + weptr->pos, weptr->len);
431 0 : pq_sendbyte(&buf, '\0');
432 :
433 0 : npos = POSDATALEN(vec, weptr);
2006 andres 434 0 : pq_sendint16(&buf, npos);
435 :
5624 bruce 436 0 : if (npos > 0)
5710 tgl 437 EUB : {
5710 tgl 438 UBC 0 : WordEntryPos *wepptr = POSDATAPTR(vec, weptr);
439 :
5693 teodor 440 0 : for (j = 0; j < npos; j++)
2006 andres 441 0 : pq_sendint16(&buf, wepptr[j]);
442 : }
5710 tgl 443 0 : weptr++;
444 : }
5710 tgl 445 EUB :
5710 tgl 446 UIC 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
5710 tgl 447 EUB : }
448 :
449 : Datum
5710 tgl 450 UBC 0 : tsvectorrecv(PG_FUNCTION_ARGS)
451 : {
5710 tgl 452 UIC 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
5710 tgl 453 EUB : TSVector vec;
454 : int i;
455 : int32 nentries;
456 : int datalen; /* number of bytes used in the variable size
5624 bruce 457 : * area after fixed size TSVector header and
458 : * WordEntries */
5693 teodor 459 : Size hdrlen;
460 : Size len; /* allocated size of vec */
5071 teodor 461 UIC 0 : bool needSort = false;
462 :
5693 463 0 : nentries = pq_getmsgint(buf, sizeof(int32));
464 0 : if (nentries < 0 || nentries > (MaxAllocSize / sizeof(WordEntry)))
5710 tgl 465 0 : elog(ERROR, "invalid size of tsvector");
466 :
5693 teodor 467 0 : hdrlen = DATAHDRSIZE + sizeof(WordEntry) * nentries;
5710 tgl 468 EUB :
5624 bruce 469 UIC 0 : len = hdrlen * 2; /* times two to make room for lexemes */
5710 tgl 470 UBC 0 : vec = (TSVector) palloc0(len);
5693 teodor 471 0 : vec->size = nentries;
5710 tgl 472 EUB :
5693 teodor 473 UIC 0 : datalen = 0;
5693 teodor 474 UBC 0 : for (i = 0; i < nentries; i++)
475 : {
5693 teodor 476 EUB : const char *lexeme;
5624 bruce 477 : uint16 npos;
478 : size_t lex_len;
479 :
5693 teodor 480 UBC 0 : lexeme = pq_getmsgstring(buf);
481 0 : npos = (uint16) pq_getmsgint(buf, sizeof(uint16));
482 :
483 : /* sanity checks */
484 :
5693 teodor 485 UIC 0 : lex_len = strlen(lexeme);
5071 meskes 486 0 : if (lex_len > MAXSTRLEN)
5611 tgl 487 UBC 0 : elog(ERROR, "invalid tsvector: lexeme too long");
5693 teodor 488 EUB :
5693 teodor 489 UIC 0 : if (datalen > MAXSTRPOS)
5611 tgl 490 0 : elog(ERROR, "invalid tsvector: maximum total lexeme length exceeded");
491 :
5693 teodor 492 UBC 0 : if (npos > MAXNUMPOS)
5611 tgl 493 0 : elog(ERROR, "unexpected number of tsvector positions");
5710 tgl 494 EUB :
495 : /*
5693 teodor 496 : * Looks valid. Fill the WordEntry struct, and copy lexeme.
497 : *
498 : * But make sure the buffer is large enough first.
5710 tgl 499 : */
5693 teodor 500 UBC 0 : while (hdrlen + SHORTALIGN(datalen + lex_len) +
5693 teodor 501 UIC 0 : (npos + 1) * sizeof(WordEntryPos) >= len)
502 : {
5710 tgl 503 0 : len *= 2;
504 0 : vec = (TSVector) repalloc(vec, len);
505 : }
506 :
5693 teodor 507 UBC 0 : vec->entries[i].haspos = (npos > 0) ? 1 : 0;
508 0 : vec->entries[i].len = lex_len;
5693 teodor 509 UIC 0 : vec->entries[i].pos = datalen;
5693 teodor 510 EUB :
5693 teodor 511 UBC 0 : memcpy(STRPTR(vec) + datalen, lexeme, lex_len);
512 :
5693 teodor 513 UIC 0 : datalen += lex_len;
5710 tgl 514 EUB :
5647 tgl 515 UBC 0 : if (i > 0 && WordEntryCMP(&vec->entries[i],
516 0 : &vec->entries[i - 1],
5647 tgl 517 UIC 0 : STRPTR(vec)) <= 0)
5071 teodor 518 UBC 0 : needSort = true;
519 :
5693 teodor 520 EUB : /* Receive positions */
5693 teodor 521 UIC 0 : if (npos > 0)
5710 tgl 522 EUB : {
5693 teodor 523 : uint16 j;
5710 tgl 524 : WordEntryPos *wepptr;
525 :
526 : /*
527 : * Pad to 2-byte alignment if necessary. Though we used palloc0
5624 bruce 528 : * for the initial allocation, subsequent repalloc'd memory areas
529 : * are not initialized to zero.
530 : */
5693 teodor 531 UIC 0 : if (datalen != SHORTALIGN(datalen))
532 : {
533 0 : *(STRPTR(vec) + datalen) = '\0';
534 0 : datalen = SHORTALIGN(datalen);
535 : }
536 :
537 0 : memcpy(STRPTR(vec) + datalen, &npos, sizeof(uint16));
5693 teodor 538 EUB :
5693 teodor 539 UIC 0 : wepptr = POSDATAPTR(vec, &vec->entries[i]);
5710 tgl 540 UBC 0 : for (j = 0; j < npos; j++)
5710 tgl 541 EUB : {
5693 teodor 542 UIC 0 : wepptr[j] = (WordEntryPos) pq_getmsgint(buf, sizeof(WordEntryPos));
5710 tgl 543 0 : if (j > 0 && WEP_GETPOS(wepptr[j]) <= WEP_GETPOS(wepptr[j - 1]))
5649 tgl 544 UBC 0 : elog(ERROR, "position information is misordered");
545 : }
5710 tgl 546 EUB :
5710 tgl 547 UBC 0 : datalen += (npos + 1) * sizeof(WordEntry);
548 : }
5710 tgl 549 EUB : }
550 :
5693 teodor 551 UBC 0 : SET_VARSIZE(vec, hdrlen + datalen);
552 :
5071 teodor 553 UIC 0 : if (needSort)
61 peter 554 UNC 0 : qsort_arg(ARRPTR(vec), vec->size, sizeof(WordEntry),
555 0 : compareentry, STRPTR(vec));
556 :
5710 tgl 557 UIC 0 : PG_RETURN_TSVECTOR(vec);
5710 tgl 558 EUB : }
|