1/*-------------------------------------------------------------------------
2 *
3 * tsgistidx.c
4 * GiST support functions for tsvector_ops
5 *
6 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7 *
8 *
9 * IDENTIFICATION
10 * src/backend/utils/adt/tsgistidx.c
11 *
12 *-------------------------------------------------------------------------
13 */
14
15#include "postgres.h"
16
17#include "access/gist.h"
18#include "access/tuptoaster.h"
19#include "port/pg_bitutils.h"
20#include "tsearch/ts_utils.h"
21#include "utils/builtins.h"
22#include "utils/pg_crc.h"
23
24
25#define SIGLENINT 31 /* >121 => key will toast, so it will not work
26 * !!! */
27
28#define SIGLEN ( sizeof(int32) * SIGLENINT )
29#define SIGLENBIT (SIGLEN * BITS_PER_BYTE)
30
31typedef char BITVEC[SIGLEN];
32typedef char *BITVECP;
33
34#define LOOPBYTE \
35 for(i=0;i<SIGLEN;i++)
36
37#define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITS_PER_BYTE ) ) )
38#define GETBITBYTE(x,i) ( ((char)(x)) >> (i) & 0x01 )
39#define CLRBIT(x,i) GETBYTE(x,i) &= ~( 0x01 << ( (i) % BITS_PER_BYTE ) )
40#define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITS_PER_BYTE ) )
41#define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITS_PER_BYTE )) & 0x01 )
42
43#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT)
44#define HASH(sign, val) SETBIT((sign), HASHVAL(val))
45
46#define GETENTRY(vec,pos) ((SignTSVector *) DatumGetPointer((vec)->vector[(pos)].key))
47
48/*
49 * type of GiST index key
50 */
51
52typedef struct
53{
54 int32 vl_len_; /* varlena header (do not touch directly!) */
55 int32 flag;
56 char data[FLEXIBLE_ARRAY_MEMBER];
57} SignTSVector;
58
59#define ARRKEY 0x01
60#define SIGNKEY 0x02
61#define ALLISTRUE 0x04
62
63#define ISARRKEY(x) ( ((SignTSVector*)(x))->flag & ARRKEY )
64#define ISSIGNKEY(x) ( ((SignTSVector*)(x))->flag & SIGNKEY )
65#define ISALLTRUE(x) ( ((SignTSVector*)(x))->flag & ALLISTRUE )
66
67#define GTHDRSIZE ( VARHDRSZ + sizeof(int32) )
68#define CALCGTSIZE(flag, len) ( GTHDRSIZE + ( ( (flag) & ARRKEY ) ? ((len)*sizeof(int32)) : (((flag) & ALLISTRUE) ? 0 : SIGLEN) ) )
69
70#define GETSIGN(x) ( (BITVECP)( (char*)(x)+GTHDRSIZE ) )
71#define GETARR(x) ( (int32*)( (char*)(x)+GTHDRSIZE ) )
72#define ARRNELEM(x) ( ( VARSIZE(x) - GTHDRSIZE )/sizeof(int32) )
73
74static int32 sizebitvec(BITVECP sign);
75
76Datum
77gtsvectorin(PG_FUNCTION_ARGS)
78{
79 ereport(ERROR,
80 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
81 errmsg("gtsvector_in not implemented")));
82 PG_RETURN_DATUM(0);
83}
84
85#define SINGOUTSTR "%d true bits, %d false bits"
86#define ARROUTSTR "%d unique words"
87#define EXTRALEN ( 2*13 )
88
89static int outbuf_maxlen = 0;
90
91Datum
92gtsvectorout(PG_FUNCTION_ARGS)
93{
94 SignTSVector *key = (SignTSVector *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
95 char *outbuf;
96
97 if (outbuf_maxlen == 0)
98 outbuf_maxlen = 2 * EXTRALEN + Max(strlen(SINGOUTSTR), strlen(ARROUTSTR)) + 1;
99 outbuf = palloc(outbuf_maxlen);
100
101 if (ISARRKEY(key))
102 sprintf(outbuf, ARROUTSTR, (int) ARRNELEM(key));
103 else
104 {
105 int cnttrue = (ISALLTRUE(key)) ? SIGLENBIT : sizebitvec(GETSIGN(key));
106
107 sprintf(outbuf, SINGOUTSTR, cnttrue, (int) SIGLENBIT - cnttrue);
108 }
109
110 PG_FREE_IF_COPY(key, 0);
111 PG_RETURN_POINTER(outbuf);
112}
113
114static int
115compareint(const void *va, const void *vb)
116{
117 int32 a = *((const int32 *) va);
118 int32 b = *((const int32 *) vb);
119
120 if (a == b)
121 return 0;
122 return (a > b) ? 1 : -1;
123}
124
125/*
126 * Removes duplicates from an array of int32. 'l' is
127 * size of the input array. Returns the new size of the array.
128 */
129static int
130uniqueint(int32 *a, int32 l)
131{
132 int32 *ptr,
133 *res;
134
135 if (l <= 1)
136 return l;
137
138 ptr = res = a;
139
140 qsort((void *) a, l, sizeof(int32), compareint);
141
142 while (ptr - a < l)
143 if (*ptr != *res)
144 *(++res) = *ptr++;
145 else
146 ptr++;
147 return res + 1 - a;
148}
149
150static void
151makesign(BITVECP sign, SignTSVector *a)
152{
153 int32 k,
154 len = ARRNELEM(a);
155 int32 *ptr = GETARR(a);
156
157 MemSet((void *) sign, 0, sizeof(BITVEC));
158 for (k = 0; k < len; k++)
159 HASH(sign, ptr[k]);
160}
161
162Datum
163gtsvector_compress(PG_FUNCTION_ARGS)
164{
165 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
166 GISTENTRY *retval = entry;
167
168 if (entry->leafkey)
169 { /* tsvector */
170 SignTSVector *res;
171 TSVector val = DatumGetTSVector(entry->key);
172 int32 len;
173 int32 *arr;
174 WordEntry *ptr = ARRPTR(val);
175 char *words = STRPTR(val);
176
177 len = CALCGTSIZE(ARRKEY, val->size);
178 res = (SignTSVector *) palloc(len);
179 SET_VARSIZE(res, len);
180 res->flag = ARRKEY;
181 arr = GETARR(res);
182 len = val->size;
183 while (len--)
184 {
185 pg_crc32 c;
186
187 INIT_LEGACY_CRC32(c);
188 COMP_LEGACY_CRC32(c, words + ptr->pos, ptr->len);
189 FIN_LEGACY_CRC32(c);
190
191 *arr = *(int32 *) &c;
192 arr++;
193 ptr++;
194 }
195
196 len = uniqueint(GETARR(res), val->size);
197 if (len != val->size)
198 {
199 /*
200 * there is a collision of hash-function; len is always less than
201 * val->size
202 */
203 len = CALCGTSIZE(ARRKEY, len);
204 res = (SignTSVector *) repalloc((void *) res, len);
205 SET_VARSIZE(res, len);
206 }
207
208 /* make signature, if array is too long */
209 if (VARSIZE(res) > TOAST_INDEX_TARGET)
210 {
211 SignTSVector *ressign;
212
213 len = CALCGTSIZE(SIGNKEY, 0);
214 ressign = (SignTSVector *) palloc(len);
215 SET_VARSIZE(ressign, len);
216 ressign->flag = SIGNKEY;
217 makesign(GETSIGN(ressign), res);
218 res = ressign;
219 }
220
221 retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
222 gistentryinit(*retval, PointerGetDatum(res),
223 entry->rel, entry->page,
224 entry->offset, false);
225 }
226 else if (ISSIGNKEY(DatumGetPointer(entry->key)) &&
227 !ISALLTRUE(DatumGetPointer(entry->key)))
228 {
229 int32 i,
230 len;
231 SignTSVector *res;
232 BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
233
234 LOOPBYTE
235 {
236 if ((sign[i] & 0xff) != 0xff)
237 PG_RETURN_POINTER(retval);
238 }
239
240 len = CALCGTSIZE(SIGNKEY | ALLISTRUE, 0);
241 res = (SignTSVector *) palloc(len);
242 SET_VARSIZE(res, len);
243 res->flag = SIGNKEY | ALLISTRUE;
244
245 retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
246 gistentryinit(*retval, PointerGetDatum(res),
247 entry->rel, entry->page,
248 entry->offset, false);
249 }
250 PG_RETURN_POINTER(retval);
251}
252
253Datum
254gtsvector_decompress(PG_FUNCTION_ARGS)
255{
256 /*
257 * We need to detoast the stored value, because the other gtsvector
258 * support functions don't cope with toasted values.
259 */
260 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
261 SignTSVector *key = (SignTSVector *) PG_DETOAST_DATUM(entry->key);
262
263 if (key != (SignTSVector *) DatumGetPointer(entry->key))
264 {
265 GISTENTRY *retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
266
267 gistentryinit(*retval, PointerGetDatum(key),
268 entry->rel, entry->page,
269 entry->offset, false);
270
271 PG_RETURN_POINTER(retval);
272 }
273
274 PG_RETURN_POINTER(entry);
275}
276
277typedef struct
278{
279 int32 *arrb;
280 int32 *arre;
281} CHKVAL;
282
283/*
284 * is there value 'val' in array or not ?
285 */
286static bool
287checkcondition_arr(void *checkval, QueryOperand *val, ExecPhraseData *data)
288{
289 int32 *StopLow = ((CHKVAL *) checkval)->arrb;
290 int32 *StopHigh = ((CHKVAL *) checkval)->arre;
291 int32 *StopMiddle;
292
293 /* Loop invariant: StopLow <= val < StopHigh */
294
295 /*
296 * we are not able to find a prefix by hash value
297 */
298 if (val->prefix)
299 return true;
300
301 while (StopLow < StopHigh)
302 {
303 StopMiddle = StopLow + (StopHigh - StopLow) / 2;
304 if (*StopMiddle == val->valcrc)
305 return true;
306 else if (*StopMiddle < val->valcrc)
307 StopLow = StopMiddle + 1;
308 else
309 StopHigh = StopMiddle;
310 }
311
312 return false;
313}
314
315static bool
316checkcondition_bit(void *checkval, QueryOperand *val, ExecPhraseData *data)
317{
318 /*
319 * we are not able to find a prefix in signature tree
320 */
321 if (val->prefix)
322 return true;
323 return GETBIT(checkval, HASHVAL(val->valcrc));
324}
325
326Datum
327gtsvector_consistent(PG_FUNCTION_ARGS)
328{
329 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
330 TSQuery query = PG_GETARG_TSQUERY(1);
331
332 /* StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); */
333 /* Oid subtype = PG_GETARG_OID(3); */
334 bool *recheck = (bool *) PG_GETARG_POINTER(4);
335 SignTSVector *key = (SignTSVector *) DatumGetPointer(entry->key);
336
337 /* All cases served by this function are inexact */
338 *recheck = true;
339
340 if (!query->size)
341 PG_RETURN_BOOL(false);
342
343 if (ISSIGNKEY(key))
344 {
345 if (ISALLTRUE(key))
346 PG_RETURN_BOOL(true);
347
348 /* since signature is lossy, cannot specify CALC_NOT here */
349 PG_RETURN_BOOL(TS_execute(GETQUERY(query),
350 (void *) GETSIGN(key),
351 TS_EXEC_PHRASE_NO_POS,
352 checkcondition_bit));
353 }
354 else
355 { /* only leaf pages */
356 CHKVAL chkval;
357
358 chkval.arrb = GETARR(key);
359 chkval.arre = chkval.arrb + ARRNELEM(key);
360 PG_RETURN_BOOL(TS_execute(GETQUERY(query),
361 (void *) &chkval,
362 TS_EXEC_PHRASE_NO_POS | TS_EXEC_CALC_NOT,
363 checkcondition_arr));
364 }
365}
366
367static int32
368unionkey(BITVECP sbase, SignTSVector *add)
369{
370 int32 i;
371
372 if (ISSIGNKEY(add))
373 {
374 BITVECP sadd = GETSIGN(add);
375
376 if (ISALLTRUE(add))
377 return 1;
378
379 LOOPBYTE
380 sbase[i] |= sadd[i];
381 }
382 else
383 {
384 int32 *ptr = GETARR(add);
385
386 for (i = 0; i < ARRNELEM(add); i++)
387 HASH(sbase, ptr[i]);
388 }
389 return 0;
390}
391
392
393Datum
394gtsvector_union(PG_FUNCTION_ARGS)
395{
396 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
397 int *size = (int *) PG_GETARG_POINTER(1);
398 BITVEC base;
399 int32 i,
400 len;
401 int32 flag = 0;
402 SignTSVector *result;
403
404 MemSet((void *) base, 0, sizeof(BITVEC));
405 for (i = 0; i < entryvec->n; i++)
406 {
407 if (unionkey(base, GETENTRY(entryvec, i)))
408 {
409 flag = ALLISTRUE;
410 break;
411 }
412 }
413
414 flag |= SIGNKEY;
415 len = CALCGTSIZE(flag, 0);
416 result = (SignTSVector *) palloc(len);
417 *size = len;
418 SET_VARSIZE(result, len);
419 result->flag = flag;
420 if (!ISALLTRUE(result))
421 memcpy((void *) GETSIGN(result), (void *) base, sizeof(BITVEC));
422
423 PG_RETURN_POINTER(result);
424}
425
426Datum
427gtsvector_same(PG_FUNCTION_ARGS)
428{
429 SignTSVector *a = (SignTSVector *) PG_GETARG_POINTER(0);
430 SignTSVector *b = (SignTSVector *) PG_GETARG_POINTER(1);
431 bool *result = (bool *) PG_GETARG_POINTER(2);
432
433 if (ISSIGNKEY(a))
434 { /* then b also ISSIGNKEY */
435 if (ISALLTRUE(a) && ISALLTRUE(b))
436 *result = true;
437 else if (ISALLTRUE(a))
438 *result = false;
439 else if (ISALLTRUE(b))
440 *result = false;
441 else
442 {
443 int32 i;
444 BITVECP sa = GETSIGN(a),
445 sb = GETSIGN(b);
446
447 *result = true;
448 LOOPBYTE
449 {
450 if (sa[i] != sb[i])
451 {
452 *result = false;
453 break;
454 }
455 }
456 }
457 }
458 else
459 { /* a and b ISARRKEY */
460 int32 lena = ARRNELEM(a),
461 lenb = ARRNELEM(b);
462
463 if (lena != lenb)
464 *result = false;
465 else
466 {
467 int32 *ptra = GETARR(a),
468 *ptrb = GETARR(b);
469 int32 i;
470
471 *result = true;
472 for (i = 0; i < lena; i++)
473 if (ptra[i] != ptrb[i])
474 {
475 *result = false;
476 break;
477 }
478 }
479 }
480
481 PG_RETURN_POINTER(result);
482}
483
484static int32
485sizebitvec(BITVECP sign)
486{
487 return pg_popcount(sign, SIGLEN);
488}
489
490static int
491hemdistsign(BITVECP a, BITVECP b)
492{
493 int i,
494 diff,
495 dist = 0;
496
497 LOOPBYTE
498 {
499 diff = (unsigned char) (a[i] ^ b[i]);
500 /* Using the popcount functions here isn't likely to win */
501 dist += pg_number_of_ones[diff];
502 }
503 return dist;
504}
505
506static int
507hemdist(SignTSVector *a, SignTSVector *b)
508{
509 if (ISALLTRUE(a))
510 {
511 if (ISALLTRUE(b))
512 return 0;
513 else
514 return SIGLENBIT - sizebitvec(GETSIGN(b));
515 }
516 else if (ISALLTRUE(b))
517 return SIGLENBIT - sizebitvec(GETSIGN(a));
518
519 return hemdistsign(GETSIGN(a), GETSIGN(b));
520}
521
522Datum
523gtsvector_penalty(PG_FUNCTION_ARGS)
524{
525 GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
526 GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
527 float *penalty = (float *) PG_GETARG_POINTER(2);
528 SignTSVector *origval = (SignTSVector *) DatumGetPointer(origentry->key);
529 SignTSVector *newval = (SignTSVector *) DatumGetPointer(newentry->key);
530 BITVECP orig = GETSIGN(origval);
531
532 *penalty = 0.0;
533
534 if (ISARRKEY(newval))
535 {
536 BITVEC sign;
537
538 makesign(sign, newval);
539
540 if (ISALLTRUE(origval))
541 *penalty = ((float) (SIGLENBIT - sizebitvec(sign))) / (float) (SIGLENBIT + 1);
542 else
543 *penalty = hemdistsign(sign, orig);
544 }
545 else
546 *penalty = hemdist(origval, newval);
547 PG_RETURN_POINTER(penalty);
548}
549
550typedef struct
551{
552 bool allistrue;
553 BITVEC sign;
554} CACHESIGN;
555
556static void
557fillcache(CACHESIGN *item, SignTSVector *key)
558{
559 item->allistrue = false;
560 if (ISARRKEY(key))
561 makesign(item->sign, key);
562 else if (ISALLTRUE(key))
563 item->allistrue = true;
564 else
565 memcpy((void *) item->sign, (void *) GETSIGN(key), sizeof(BITVEC));
566}
567
568#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
569typedef struct
570{
571 OffsetNumber pos;
572 int32 cost;
573} SPLITCOST;
574
575static int
576comparecost(const void *va, const void *vb)
577{
578 const SPLITCOST *a = (const SPLITCOST *) va;
579 const SPLITCOST *b = (const SPLITCOST *) vb;
580
581 if (a->cost == b->cost)
582 return 0;
583 else
584 return (a->cost > b->cost) ? 1 : -1;
585}
586
587
588static int
589hemdistcache(CACHESIGN *a, CACHESIGN *b)
590{
591 if (a->allistrue)
592 {
593 if (b->allistrue)
594 return 0;
595 else
596 return SIGLENBIT - sizebitvec(b->sign);
597 }
598 else if (b->allistrue)
599 return SIGLENBIT - sizebitvec(a->sign);
600
601 return hemdistsign(a->sign, b->sign);
602}
603
604Datum
605gtsvector_picksplit(PG_FUNCTION_ARGS)
606{
607 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
608 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
609 OffsetNumber k,
610 j;
611 SignTSVector *datum_l,
612 *datum_r;
613 BITVECP union_l,
614 union_r;
615 int32 size_alpha,
616 size_beta;
617 int32 size_waste,
618 waste = -1;
619 int32 nbytes;
620 OffsetNumber seed_1 = 0,
621 seed_2 = 0;
622 OffsetNumber *left,
623 *right;
624 OffsetNumber maxoff;
625 BITVECP ptr;
626 int i;
627 CACHESIGN *cache;
628 SPLITCOST *costvector;
629
630 maxoff = entryvec->n - 2;
631 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
632 v->spl_left = (OffsetNumber *) palloc(nbytes);
633 v->spl_right = (OffsetNumber *) palloc(nbytes);
634
635 cache = (CACHESIGN *) palloc(sizeof(CACHESIGN) * (maxoff + 2));
636 fillcache(&cache[FirstOffsetNumber], GETENTRY(entryvec, FirstOffsetNumber));
637
638 for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
639 {
640 for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
641 {
642 if (k == FirstOffsetNumber)
643 fillcache(&cache[j], GETENTRY(entryvec, j));
644
645 size_waste = hemdistcache(&(cache[j]), &(cache[k]));
646 if (size_waste > waste)
647 {
648 waste = size_waste;
649 seed_1 = k;
650 seed_2 = j;
651 }
652 }
653 }
654
655 left = v->spl_left;
656 v->spl_nleft = 0;
657 right = v->spl_right;
658 v->spl_nright = 0;
659
660 if (seed_1 == 0 || seed_2 == 0)
661 {
662 seed_1 = 1;
663 seed_2 = 2;
664 }
665
666 /* form initial .. */
667 if (cache[seed_1].allistrue)
668 {
669 datum_l = (SignTSVector *) palloc(CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
670 SET_VARSIZE(datum_l, CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
671 datum_l->flag = SIGNKEY | ALLISTRUE;
672 }
673 else
674 {
675 datum_l = (SignTSVector *) palloc(CALCGTSIZE(SIGNKEY, 0));
676 SET_VARSIZE(datum_l, CALCGTSIZE(SIGNKEY, 0));
677 datum_l->flag = SIGNKEY;
678 memcpy((void *) GETSIGN(datum_l), (void *) cache[seed_1].sign, sizeof(BITVEC));
679 }
680 if (cache[seed_2].allistrue)
681 {
682 datum_r = (SignTSVector *) palloc(CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
683 SET_VARSIZE(datum_r, CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
684 datum_r->flag = SIGNKEY | ALLISTRUE;
685 }
686 else
687 {
688 datum_r = (SignTSVector *) palloc(CALCGTSIZE(SIGNKEY, 0));
689 SET_VARSIZE(datum_r, CALCGTSIZE(SIGNKEY, 0));
690 datum_r->flag = SIGNKEY;
691 memcpy((void *) GETSIGN(datum_r), (void *) cache[seed_2].sign, sizeof(BITVEC));
692 }
693
694 union_l = GETSIGN(datum_l);
695 union_r = GETSIGN(datum_r);
696 maxoff = OffsetNumberNext(maxoff);
697 fillcache(&cache[maxoff], GETENTRY(entryvec, maxoff));
698 /* sort before ... */
699 costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
700 for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
701 {
702 costvector[j - 1].pos = j;
703 size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]));
704 size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]));
705 costvector[j - 1].cost = Abs(size_alpha - size_beta);
706 }
707 qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
708
709 for (k = 0; k < maxoff; k++)
710 {
711 j = costvector[k].pos;
712 if (j == seed_1)
713 {
714 *left++ = j;
715 v->spl_nleft++;
716 continue;
717 }
718 else if (j == seed_2)
719 {
720 *right++ = j;
721 v->spl_nright++;
722 continue;
723 }
724
725 if (ISALLTRUE(datum_l) || cache[j].allistrue)
726 {
727 if (ISALLTRUE(datum_l) && cache[j].allistrue)
728 size_alpha = 0;
729 else
730 size_alpha = SIGLENBIT - sizebitvec(
731 (cache[j].allistrue) ? GETSIGN(datum_l) : GETSIGN(cache[j].sign)
732 );
733 }
734 else
735 size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l));
736
737 if (ISALLTRUE(datum_r) || cache[j].allistrue)
738 {
739 if (ISALLTRUE(datum_r) && cache[j].allistrue)
740 size_beta = 0;
741 else
742 size_beta = SIGLENBIT - sizebitvec(
743 (cache[j].allistrue) ? GETSIGN(datum_r) : GETSIGN(cache[j].sign)
744 );
745 }
746 else
747 size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r));
748
749 if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
750 {
751 if (ISALLTRUE(datum_l) || cache[j].allistrue)
752 {
753 if (!ISALLTRUE(datum_l))
754 MemSet((void *) GETSIGN(datum_l), 0xff, sizeof(BITVEC));
755 }
756 else
757 {
758 ptr = cache[j].sign;
759 LOOPBYTE
760 union_l[i] |= ptr[i];
761 }
762 *left++ = j;
763 v->spl_nleft++;
764 }
765 else
766 {
767 if (ISALLTRUE(datum_r) || cache[j].allistrue)
768 {
769 if (!ISALLTRUE(datum_r))
770 MemSet((void *) GETSIGN(datum_r), 0xff, sizeof(BITVEC));
771 }
772 else
773 {
774 ptr = cache[j].sign;
775 LOOPBYTE
776 union_r[i] |= ptr[i];
777 }
778 *right++ = j;
779 v->spl_nright++;
780 }
781 }
782
783 *right = *left = FirstOffsetNumber;
784 v->spl_ldatum = PointerGetDatum(datum_l);
785 v->spl_rdatum = PointerGetDatum(datum_r);
786
787 PG_RETURN_POINTER(v);
788}
789
790/*
791 * Formerly, gtsvector_consistent was declared in pg_proc.h with arguments
792 * that did not match the documented conventions for GiST support functions.
793 * We fixed that, but we still need a pg_proc entry with the old signature
794 * to support reloading pre-9.6 contrib/tsearch2 opclass declarations.
795 * This compatibility function should go away eventually.
796 */
797Datum
798gtsvector_consistent_oldsig(PG_FUNCTION_ARGS)
799{
800 return gtsvector_consistent(fcinfo);
801}
802