2 * contrib/pg_trgm/trgm_gist.c
6 #include "access/reloptions.h"
7 #include "access/stratnum.h"
9 #include "port/pg_bitutils.h"
13 /* gist_trgm_ops opclass options */
16 int32 vl_len_
; /* varlena header (do not touch directly!) */
17 int siglen
; /* signature length in bytes */
20 #define GET_SIGLEN() (PG_HAS_OPCLASS_OPTIONS() ? \
21 ((TrgmGistOptions *) PG_GET_OPCLASS_OPTIONS())->siglen : \
26 /* most recent inputs to gtrgm_consistent */
27 StrategyNumber strategy
;
29 /* extracted trigrams for query */
31 /* if a regex operator, the extracted graph */
32 TrgmPackedGraph
*graph
;
35 * The "query" and "trigrams" are stored in the same palloc block as this
36 * cache struct, at MAXALIGN'ed offsets. The graph however isn't.
38 } gtrgm_consistent_cache
;
40 #define GETENTRY(vec,pos) ((TRGM *) DatumGetPointer((vec)->vector[(pos)].key))
43 PG_FUNCTION_INFO_V1(gtrgm_in
);
44 PG_FUNCTION_INFO_V1(gtrgm_out
);
45 PG_FUNCTION_INFO_V1(gtrgm_compress
);
46 PG_FUNCTION_INFO_V1(gtrgm_decompress
);
47 PG_FUNCTION_INFO_V1(gtrgm_consistent
);
48 PG_FUNCTION_INFO_V1(gtrgm_distance
);
49 PG_FUNCTION_INFO_V1(gtrgm_union
);
50 PG_FUNCTION_INFO_V1(gtrgm_same
);
51 PG_FUNCTION_INFO_V1(gtrgm_penalty
);
52 PG_FUNCTION_INFO_V1(gtrgm_picksplit
);
53 PG_FUNCTION_INFO_V1(gtrgm_options
);
57 gtrgm_in(PG_FUNCTION_ARGS
)
60 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
61 errmsg("cannot accept a value of type %s", "gtrgm")));
63 PG_RETURN_VOID(); /* keep compiler quiet */
67 gtrgm_out(PG_FUNCTION_ARGS
)
70 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
71 errmsg("cannot display a value of type %s", "gtrgm")));
73 PG_RETURN_VOID(); /* keep compiler quiet */
77 gtrgm_alloc(bool isalltrue
, int siglen
, BITVECP sign
)
79 int flag
= SIGNKEY
| (isalltrue
? ALLISTRUE
: 0);
80 int size
= CALCGTSIZE(flag
, siglen
);
81 TRGM
*res
= palloc(size
);
83 SET_VARSIZE(res
, size
);
89 memcpy(GETSIGN(res
), sign
, siglen
);
91 memset(GETSIGN(res
), 0, siglen
);
98 makesign(BITVECP sign
, TRGM
*a
, int siglen
)
102 trgm
*ptr
= GETARR(a
);
105 MemSet(sign
, 0, siglen
);
106 SETBIT(sign
, SIGLENBIT(siglen
)); /* set last unused bit */
107 for (k
= 0; k
< len
; k
++)
109 CPTRGM(((char *) &tmp
), ptr
+ k
);
110 HASH(sign
, tmp
, siglen
);
115 gtrgm_compress(PG_FUNCTION_ARGS
)
117 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
118 int siglen
= GET_SIGLEN();
119 GISTENTRY
*retval
= entry
;
124 text
*val
= DatumGetTextPP(entry
->key
);
126 res
= generate_trgm(VARDATA_ANY(val
), VARSIZE_ANY_EXHDR(val
));
127 retval
= (GISTENTRY
*) palloc(sizeof(GISTENTRY
));
128 gistentryinit(*retval
, PointerGetDatum(res
),
129 entry
->rel
, entry
->page
,
130 entry
->offset
, false);
132 else if (ISSIGNKEY(DatumGetPointer(entry
->key
)) &&
133 !ISALLTRUE(DatumGetPointer(entry
->key
)))
137 BITVECP sign
= GETSIGN(DatumGetPointer(entry
->key
));
141 if ((sign
[i
] & 0xff) != 0xff)
142 PG_RETURN_POINTER(retval
);
145 res
= gtrgm_alloc(true, siglen
, sign
);
146 retval
= (GISTENTRY
*) palloc(sizeof(GISTENTRY
));
147 gistentryinit(*retval
, PointerGetDatum(res
),
148 entry
->rel
, entry
->page
,
149 entry
->offset
, false);
151 PG_RETURN_POINTER(retval
);
155 gtrgm_decompress(PG_FUNCTION_ARGS
)
157 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
161 key
= DatumGetTextPP(entry
->key
);
163 if (key
!= (text
*) DatumGetPointer(entry
->key
))
165 /* need to pass back the decompressed item */
166 retval
= palloc(sizeof(GISTENTRY
));
167 gistentryinit(*retval
, PointerGetDatum(key
),
168 entry
->rel
, entry
->page
, entry
->offset
, entry
->leafkey
);
169 PG_RETURN_POINTER(retval
);
173 /* we can return the entry as-is */
174 PG_RETURN_POINTER(entry
);
179 cnt_sml_sign_common(TRGM
*qtrg
, BITVECP sign
, int siglen
)
183 len
= ARRNELEM(qtrg
);
184 trgm
*ptr
= GETARR(qtrg
);
187 for (k
= 0; k
< len
; k
++)
189 CPTRGM(((char *) &tmp
), ptr
+ k
);
190 count
+= GETBIT(sign
, HASHVAL(tmp
, siglen
));
197 gtrgm_consistent(PG_FUNCTION_ARGS
)
199 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
200 text
*query
= PG_GETARG_TEXT_P(1);
201 StrategyNumber strategy
= (StrategyNumber
) PG_GETARG_UINT16(2);
203 /* Oid subtype = PG_GETARG_OID(3); */
204 bool *recheck
= (bool *) PG_GETARG_POINTER(4);
205 int siglen
= GET_SIGLEN();
206 TRGM
*key
= (TRGM
*) DatumGetPointer(entry
->key
);
209 Size querysize
= VARSIZE(query
);
210 gtrgm_consistent_cache
*cache
;
214 * We keep the extracted trigrams in cache, because trigram extraction is
215 * relatively CPU-expensive. When trying to reuse a cached value, check
216 * strategy number not just query itself, because trigram extraction
217 * depends on strategy.
219 * The cached structure is a single palloc chunk containing the
220 * gtrgm_consistent_cache header, then the input query (4-byte length
221 * word, uncompressed, starting at a MAXALIGN boundary), then the TRGM
222 * value (also starting at a MAXALIGN boundary). However we don't try to
223 * include the regex graph (if any) in that struct. (XXX currently, this
224 * approach can leak regex graphs across index rescans. Not clear if
225 * that's worth fixing.)
227 cache
= (gtrgm_consistent_cache
*) fcinfo
->flinfo
->fn_extra
;
229 cache
->strategy
!= strategy
||
230 VARSIZE(cache
->query
) != querysize
||
231 memcmp((char *) cache
->query
, (char *) query
, querysize
) != 0)
233 gtrgm_consistent_cache
*newcache
;
234 TrgmPackedGraph
*graph
= NULL
;
239 case SimilarityStrategyNumber
:
240 case WordSimilarityStrategyNumber
:
241 case StrictWordSimilarityStrategyNumber
:
242 case EqualStrategyNumber
:
243 qtrg
= generate_trgm(VARDATA(query
),
244 querysize
- VARHDRSZ
);
246 case ILikeStrategyNumber
:
248 elog(ERROR
, "cannot handle ~~* with case-sensitive trigrams");
251 case LikeStrategyNumber
:
252 qtrg
= generate_wildcard_trgm(VARDATA(query
),
253 querysize
- VARHDRSZ
);
255 case RegExpICaseStrategyNumber
:
257 elog(ERROR
, "cannot handle ~* with case-sensitive trigrams");
260 case RegExpStrategyNumber
:
261 qtrg
= createTrgmNFA(query
, PG_GET_COLLATION(),
262 &graph
, fcinfo
->flinfo
->fn_mcxt
);
263 /* just in case an empty array is returned ... */
264 if (qtrg
&& ARRNELEM(qtrg
) <= 0)
271 elog(ERROR
, "unrecognized strategy number: %d", strategy
);
272 qtrg
= NULL
; /* keep compiler quiet */
276 qtrgsize
= qtrg
? VARSIZE(qtrg
) : 0;
278 newcache
= (gtrgm_consistent_cache
*)
279 MemoryContextAlloc(fcinfo
->flinfo
->fn_mcxt
,
280 MAXALIGN(sizeof(gtrgm_consistent_cache
)) +
281 MAXALIGN(querysize
) +
284 newcache
->strategy
= strategy
;
285 newcache
->query
= (text
*)
286 ((char *) newcache
+ MAXALIGN(sizeof(gtrgm_consistent_cache
)));
287 memcpy((char *) newcache
->query
, (char *) query
, querysize
);
290 newcache
->trigrams
= (TRGM
*)
291 ((char *) newcache
->query
+ MAXALIGN(querysize
));
292 memcpy((char *) newcache
->trigrams
, (char *) qtrg
, qtrgsize
);
293 /* release qtrg in case it was made in fn_mcxt */
297 newcache
->trigrams
= NULL
;
298 newcache
->graph
= graph
;
302 fcinfo
->flinfo
->fn_extra
= (void *) newcache
;
306 qtrg
= cache
->trigrams
;
310 case SimilarityStrategyNumber
:
311 case WordSimilarityStrategyNumber
:
312 case StrictWordSimilarityStrategyNumber
:
315 * Similarity search is exact. (Strict) word similarity search is
318 *recheck
= (strategy
!= SimilarityStrategyNumber
);
320 nlimit
= index_strategy_get_limit(strategy
);
322 if (GIST_LEAF(entry
))
323 { /* all leafs contains orig trgm */
324 double tmpsml
= cnt_sml(qtrg
, key
, *recheck
);
326 res
= (tmpsml
>= nlimit
);
328 else if (ISALLTRUE(key
))
329 { /* non-leaf contains signature */
333 { /* non-leaf contains signature */
334 int32 count
= cnt_sml_sign_common(qtrg
, GETSIGN(key
), siglen
);
335 int32 len
= ARRNELEM(qtrg
);
340 res
= (((((float8
) count
) / ((float8
) len
))) >= nlimit
);
343 case ILikeStrategyNumber
:
345 elog(ERROR
, "cannot handle ~~* with case-sensitive trigrams");
348 case LikeStrategyNumber
:
349 case EqualStrategyNumber
:
350 /* Wildcard and equal search are inexact */
354 * Check if all the extracted trigrams can be present in child
357 if (GIST_LEAF(entry
))
358 { /* all leafs contains orig trgm */
359 res
= trgm_contained_by(qtrg
, key
);
361 else if (ISALLTRUE(key
))
362 { /* non-leaf contains signature */
366 { /* non-leaf contains signature */
369 len
= ARRNELEM(qtrg
);
370 trgm
*ptr
= GETARR(qtrg
);
371 BITVECP sign
= GETSIGN(key
);
374 for (k
= 0; k
< len
; k
++)
376 CPTRGM(((char *) &tmp
), ptr
+ k
);
377 if (!GETBIT(sign
, HASHVAL(tmp
, siglen
)))
385 case RegExpICaseStrategyNumber
:
387 elog(ERROR
, "cannot handle ~* with case-sensitive trigrams");
390 case RegExpStrategyNumber
:
391 /* Regexp search is inexact */
394 /* Check regex match as much as we can with available info */
397 if (GIST_LEAF(entry
))
398 { /* all leafs contains orig trgm */
401 check
= trgm_presence_map(qtrg
, key
);
402 res
= trigramsMatchGraph(cache
->graph
, check
);
405 else if (ISALLTRUE(key
))
406 { /* non-leaf contains signature */
410 { /* non-leaf contains signature */
413 len
= ARRNELEM(qtrg
);
414 trgm
*ptr
= GETARR(qtrg
);
415 BITVECP sign
= GETSIGN(key
);
419 * GETBIT() tests may give false positives, due to limited
420 * size of the sign array. But since trigramsMatchGraph()
421 * implements a monotone boolean function, false positives
422 * in the check array can't lead to false negative answer.
423 * So we can apply trigramsMatchGraph despite uncertainty,
424 * and that usefully improves the quality of the search.
426 check
= (bool *) palloc(len
* sizeof(bool));
427 for (k
= 0; k
< len
; k
++)
429 CPTRGM(((char *) &tmp
), ptr
+ k
);
430 check
[k
] = GETBIT(sign
, HASHVAL(tmp
, siglen
));
432 res
= trigramsMatchGraph(cache
->graph
, check
);
438 /* trigram-free query must be rechecked everywhere */
443 elog(ERROR
, "unrecognized strategy number: %d", strategy
);
444 res
= false; /* keep compiler quiet */
452 gtrgm_distance(PG_FUNCTION_ARGS
)
454 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
455 text
*query
= PG_GETARG_TEXT_P(1);
456 StrategyNumber strategy
= (StrategyNumber
) PG_GETARG_UINT16(2);
458 /* Oid subtype = PG_GETARG_OID(3); */
459 bool *recheck
= (bool *) PG_GETARG_POINTER(4);
460 int siglen
= GET_SIGLEN();
461 TRGM
*key
= (TRGM
*) DatumGetPointer(entry
->key
);
464 Size querysize
= VARSIZE(query
);
465 char *cache
= (char *) fcinfo
->flinfo
->fn_extra
;
468 * Cache the generated trigrams across multiple calls with the same query.
471 VARSIZE(cache
) != querysize
||
472 memcmp(cache
, query
, querysize
) != 0)
476 qtrg
= generate_trgm(VARDATA(query
), querysize
- VARHDRSZ
);
478 newcache
= MemoryContextAlloc(fcinfo
->flinfo
->fn_mcxt
,
479 MAXALIGN(querysize
) +
482 memcpy(newcache
, query
, querysize
);
483 memcpy(newcache
+ MAXALIGN(querysize
), qtrg
, VARSIZE(qtrg
));
487 fcinfo
->flinfo
->fn_extra
= newcache
;
491 qtrg
= (TRGM
*) (cache
+ MAXALIGN(querysize
));
495 case DistanceStrategyNumber
:
496 case WordDistanceStrategyNumber
:
497 case StrictWordDistanceStrategyNumber
:
498 /* Only plain trigram distance is exact */
499 *recheck
= (strategy
!= DistanceStrategyNumber
);
500 if (GIST_LEAF(entry
))
501 { /* all leafs contains orig trgm */
504 * Prevent gcc optimizing the sml variable using volatile
505 * keyword. Otherwise res can differ from the
506 * word_similarity_dist_op() function.
508 float4
volatile sml
= cnt_sml(qtrg
, key
, *recheck
);
512 else if (ISALLTRUE(key
))
513 { /* all leafs contains orig trgm */
517 { /* non-leaf contains signature */
518 int32 count
= cnt_sml_sign_common(qtrg
, GETSIGN(key
), siglen
);
519 int32 len
= ARRNELEM(qtrg
);
521 res
= (len
== 0) ? -1.0 : 1.0 - ((float8
) count
) / ((float8
) len
);
525 elog(ERROR
, "unrecognized strategy number: %d", strategy
);
526 res
= 0; /* keep compiler quiet */
530 PG_RETURN_FLOAT8(res
);
534 unionkey(BITVECP sbase
, TRGM
*add
, int siglen
)
540 BITVECP sadd
= GETSIGN(add
);
550 trgm
*ptr
= GETARR(add
);
553 for (i
= 0; i
< ARRNELEM(add
); i
++)
555 CPTRGM(((char *) &tmp
), ptr
+ i
);
556 HASH(sbase
, tmp
, siglen
);
564 gtrgm_union(PG_FUNCTION_ARGS
)
566 GistEntryVector
*entryvec
= (GistEntryVector
*) PG_GETARG_POINTER(0);
567 int32 len
= entryvec
->n
;
568 int *size
= (int *) PG_GETARG_POINTER(1);
569 int siglen
= GET_SIGLEN();
571 TRGM
*result
= gtrgm_alloc(false, siglen
, NULL
);
572 BITVECP base
= GETSIGN(result
);
574 for (i
= 0; i
< len
; i
++)
576 if (unionkey(base
, GETENTRY(entryvec
, i
), siglen
))
578 result
->flag
= ALLISTRUE
;
579 SET_VARSIZE(result
, CALCGTSIZE(ALLISTRUE
, siglen
));
584 *size
= VARSIZE(result
);
586 PG_RETURN_POINTER(result
);
590 gtrgm_same(PG_FUNCTION_ARGS
)
592 TRGM
*a
= (TRGM
*) PG_GETARG_POINTER(0);
593 TRGM
*b
= (TRGM
*) PG_GETARG_POINTER(1);
594 bool *result
= (bool *) PG_GETARG_POINTER(2);
595 int siglen
= GET_SIGLEN();
598 { /* then b also ISSIGNKEY */
599 if (ISALLTRUE(a
) && ISALLTRUE(b
))
601 else if (ISALLTRUE(a
))
603 else if (ISALLTRUE(b
))
608 BITVECP sa
= GETSIGN(a
),
623 { /* a and b ISARRKEY */
624 int32 lena
= ARRNELEM(a
),
631 trgm
*ptra
= GETARR(a
),
636 for (i
= 0; i
< lena
; i
++)
637 if (CMPTRGM(ptra
+ i
, ptrb
+ i
))
645 PG_RETURN_POINTER(result
);
649 sizebitvec(BITVECP sign
, int siglen
)
651 return pg_popcount(sign
, siglen
);
655 hemdistsign(BITVECP a
, BITVECP b
, int siglen
)
663 diff
= (unsigned char) (a
[i
] ^ b
[i
]);
664 /* Using the popcount functions here isn't likely to win */
665 dist
+= pg_number_of_ones
[diff
];
671 hemdist(TRGM
*a
, TRGM
*b
, int siglen
)
678 return SIGLENBIT(siglen
) - sizebitvec(GETSIGN(b
), siglen
);
680 else if (ISALLTRUE(b
))
681 return SIGLENBIT(siglen
) - sizebitvec(GETSIGN(a
), siglen
);
683 return hemdistsign(GETSIGN(a
), GETSIGN(b
), siglen
);
687 gtrgm_penalty(PG_FUNCTION_ARGS
)
689 GISTENTRY
*origentry
= (GISTENTRY
*) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
690 GISTENTRY
*newentry
= (GISTENTRY
*) PG_GETARG_POINTER(1);
691 float *penalty
= (float *) PG_GETARG_POINTER(2);
692 int siglen
= GET_SIGLEN();
693 TRGM
*origval
= (TRGM
*) DatumGetPointer(origentry
->key
);
694 TRGM
*newval
= (TRGM
*) DatumGetPointer(newentry
->key
);
695 BITVECP orig
= GETSIGN(origval
);
699 if (ISARRKEY(newval
))
701 char *cache
= (char *) fcinfo
->flinfo
->fn_extra
;
702 TRGM
*cachedVal
= (TRGM
*) (cache
+ MAXALIGN(siglen
));
703 Size newvalsize
= VARSIZE(newval
);
707 * Cache the sign data across multiple calls with the same newval.
710 VARSIZE(cachedVal
) != newvalsize
||
711 memcmp(cachedVal
, newval
, newvalsize
) != 0)
715 newcache
= MemoryContextAlloc(fcinfo
->flinfo
->fn_mcxt
,
719 makesign((BITVECP
) newcache
, newval
, siglen
);
721 cachedVal
= (TRGM
*) (newcache
+ MAXALIGN(siglen
));
722 memcpy(cachedVal
, newval
, newvalsize
);
726 fcinfo
->flinfo
->fn_extra
= newcache
;
730 sign
= (BITVECP
) cache
;
732 if (ISALLTRUE(origval
))
733 *penalty
= ((float) (SIGLENBIT(siglen
) - sizebitvec(sign
, siglen
))) / (float) (SIGLENBIT(siglen
) + 1);
735 *penalty
= hemdistsign(sign
, orig
, siglen
);
738 *penalty
= hemdist(origval
, newval
, siglen
);
739 PG_RETURN_POINTER(penalty
);
749 fillcache(CACHESIGN
*item
, TRGM
*key
, BITVECP sign
, int siglen
)
751 item
->allistrue
= false;
754 makesign(item
->sign
, key
, siglen
);
755 else if (ISALLTRUE(key
))
756 item
->allistrue
= true;
758 memcpy(item
->sign
, GETSIGN(key
), siglen
);
761 #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
769 comparecost(const void *a
, const void *b
)
771 if (((const SPLITCOST
*) a
)->cost
== ((const SPLITCOST
*) b
)->cost
)
774 return (((const SPLITCOST
*) a
)->cost
> ((const SPLITCOST
*) b
)->cost
) ? 1 : -1;
779 hemdistcache(CACHESIGN
*a
, CACHESIGN
*b
, int siglen
)
786 return SIGLENBIT(siglen
) - sizebitvec(b
->sign
, siglen
);
788 else if (b
->allistrue
)
789 return SIGLENBIT(siglen
) - sizebitvec(a
->sign
, siglen
);
791 return hemdistsign(a
->sign
, b
->sign
, siglen
);
795 gtrgm_picksplit(PG_FUNCTION_ARGS
)
797 GistEntryVector
*entryvec
= (GistEntryVector
*) PG_GETARG_POINTER(0);
798 OffsetNumber maxoff
= entryvec
->n
- 1;
799 GIST_SPLITVEC
*v
= (GIST_SPLITVEC
*) PG_GETARG_POINTER(1);
800 int siglen
= GET_SIGLEN();
812 OffsetNumber seed_1
= 0,
820 SPLITCOST
*costvector
;
822 /* cache the sign data for each existing item */
823 cache
= (CACHESIGN
*) palloc(sizeof(CACHESIGN
) * (maxoff
+ 1));
824 cache_sign
= palloc(siglen
* (maxoff
+ 1));
826 for (k
= FirstOffsetNumber
; k
<= maxoff
; k
= OffsetNumberNext(k
))
827 fillcache(&cache
[k
], GETENTRY(entryvec
, k
), &cache_sign
[siglen
* k
],
830 /* now find the two furthest-apart items */
831 for (k
= FirstOffsetNumber
; k
< maxoff
; k
= OffsetNumberNext(k
))
833 for (j
= OffsetNumberNext(k
); j
<= maxoff
; j
= OffsetNumberNext(j
))
835 size_waste
= hemdistcache(&(cache
[j
]), &(cache
[k
]), siglen
);
836 if (size_waste
> waste
)
845 /* just in case we didn't make a selection ... */
846 if (seed_1
== 0 || seed_2
== 0)
852 /* initialize the result vectors */
853 nbytes
= maxoff
* sizeof(OffsetNumber
);
854 v
->spl_left
= left
= (OffsetNumber
*) palloc(nbytes
);
855 v
->spl_right
= right
= (OffsetNumber
*) palloc(nbytes
);
859 /* form initial .. */
860 datum_l
= gtrgm_alloc(cache
[seed_1
].allistrue
, siglen
, cache
[seed_1
].sign
);
861 datum_r
= gtrgm_alloc(cache
[seed_2
].allistrue
, siglen
, cache
[seed_2
].sign
);
863 union_l
= GETSIGN(datum_l
);
864 union_r
= GETSIGN(datum_r
);
866 /* sort before ... */
867 costvector
= (SPLITCOST
*) palloc(sizeof(SPLITCOST
) * maxoff
);
868 for (j
= FirstOffsetNumber
; j
<= maxoff
; j
= OffsetNumberNext(j
))
870 costvector
[j
- 1].pos
= j
;
871 size_alpha
= hemdistcache(&(cache
[seed_1
]), &(cache
[j
]), siglen
);
872 size_beta
= hemdistcache(&(cache
[seed_2
]), &(cache
[j
]), siglen
);
873 costvector
[j
- 1].cost
= abs(size_alpha
- size_beta
);
875 qsort(costvector
, maxoff
, sizeof(SPLITCOST
), comparecost
);
877 for (k
= 0; k
< maxoff
; k
++)
879 j
= costvector
[k
].pos
;
886 else if (j
== seed_2
)
893 if (ISALLTRUE(datum_l
) || cache
[j
].allistrue
)
895 if (ISALLTRUE(datum_l
) && cache
[j
].allistrue
)
898 size_alpha
= SIGLENBIT(siglen
) -
899 sizebitvec((cache
[j
].allistrue
) ? GETSIGN(datum_l
) :
900 GETSIGN(cache
[j
].sign
),
904 size_alpha
= hemdistsign(cache
[j
].sign
, GETSIGN(datum_l
), siglen
);
906 if (ISALLTRUE(datum_r
) || cache
[j
].allistrue
)
908 if (ISALLTRUE(datum_r
) && cache
[j
].allistrue
)
911 size_beta
= SIGLENBIT(siglen
) -
912 sizebitvec((cache
[j
].allistrue
) ? GETSIGN(datum_r
) :
913 GETSIGN(cache
[j
].sign
),
917 size_beta
= hemdistsign(cache
[j
].sign
, GETSIGN(datum_r
), siglen
);
919 if (size_alpha
< size_beta
+ WISH_F(v
->spl_nleft
, v
->spl_nright
, 0.1))
921 if (ISALLTRUE(datum_l
) || cache
[j
].allistrue
)
923 if (!ISALLTRUE(datum_l
))
924 memset(GETSIGN(datum_l
), 0xff, siglen
);
930 union_l
[i
] |= ptr
[i
];
937 if (ISALLTRUE(datum_r
) || cache
[j
].allistrue
)
939 if (!ISALLTRUE(datum_r
))
940 memset(GETSIGN(datum_r
), 0xff, siglen
);
946 union_r
[i
] |= ptr
[i
];
953 v
->spl_ldatum
= PointerGetDatum(datum_l
);
954 v
->spl_rdatum
= PointerGetDatum(datum_r
);
956 PG_RETURN_POINTER(v
);
960 gtrgm_options(PG_FUNCTION_ARGS
)
962 local_relopts
*relopts
= (local_relopts
*) PG_GETARG_POINTER(0);
964 init_local_reloptions(relopts
, sizeof(TrgmGistOptions
));
965 add_local_int_reloption(relopts
, "siglen",
966 "signature length in bytes",
967 SIGLEN_DEFAULT
, 1, SIGLEN_MAX
,
968 offsetof(TrgmGistOptions
, siglen
));