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