Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * contrib/pg_trgm/trgm_gist.c
3 : : */
4 : : #include "postgres.h"
5 : :
6 : : #include "access/reloptions.h"
7 : : #include "access/stratnum.h"
8 : : #include "fmgr.h"
9 : : #include "port/pg_bitutils.h"
10 : : #include "trgm.h"
11 : : #include "varatt.h"
12 : :
13 : : /* gist_trgm_ops opclass options */
14 : : typedef struct
15 : : {
16 : : int32 vl_len_; /* varlena header (do not touch directly!) */
17 : : int siglen; /* signature length in bytes */
18 : : } TrgmGistOptions;
19 : :
20 : : #define GET_SIGLEN() (PG_HAS_OPCLASS_OPTIONS() ? \
21 : : ((TrgmGistOptions *) PG_GET_OPCLASS_OPTIONS())->siglen : \
22 : : SIGLEN_DEFAULT)
23 : :
24 : : typedef struct
25 : : {
26 : : /* most recent inputs to gtrgm_consistent */
27 : : StrategyNumber strategy;
28 : : text *query;
29 : : /* extracted trigrams for query */
30 : : TRGM *trigrams;
31 : : /* if a regex operator, the extracted graph */
32 : : TrgmPackedGraph *graph;
33 : :
34 : : /*
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.
37 : : */
38 : : } gtrgm_consistent_cache;
39 : :
40 : : #define GETENTRY(vec,pos) ((TRGM *) DatumGetPointer((vec)->vector[(pos)].key))
41 : :
42 : :
7958 teodor@sigaev.ru 43 :CBC 1 : PG_FUNCTION_INFO_V1(gtrgm_in);
44 : 1 : PG_FUNCTION_INFO_V1(gtrgm_out);
45 : 5 : PG_FUNCTION_INFO_V1(gtrgm_compress);
46 : 5 : PG_FUNCTION_INFO_V1(gtrgm_decompress);
47 : 5 : PG_FUNCTION_INFO_V1(gtrgm_consistent);
5580 tgl@sss.pgh.pa.us 48 : 5 : PG_FUNCTION_INFO_V1(gtrgm_distance);
7958 teodor@sigaev.ru 49 : 5 : PG_FUNCTION_INFO_V1(gtrgm_union);
50 : 5 : PG_FUNCTION_INFO_V1(gtrgm_same);
51 : 5 : PG_FUNCTION_INFO_V1(gtrgm_penalty);
52 : 5 : PG_FUNCTION_INFO_V1(gtrgm_picksplit);
2176 akorotkov@postgresql 53 : 5 : PG_FUNCTION_INFO_V1(gtrgm_options);
54 : :
55 : :
56 : : Datum
7958 teodor@sigaev.ru 57 :UBC 0 : gtrgm_in(PG_FUNCTION_ARGS)
58 : : {
1191 tgl@sss.pgh.pa.us 59 [ # # ]: 0 : ereport(ERROR,
60 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
61 : : errmsg("cannot accept a value of type %s", "gtrgm")));
62 : :
63 : : PG_RETURN_VOID(); /* keep compiler quiet */
64 : : }
65 : :
66 : : Datum
7958 teodor@sigaev.ru 67 : 0 : gtrgm_out(PG_FUNCTION_ARGS)
68 : : {
1191 tgl@sss.pgh.pa.us 69 [ # # ]: 0 : ereport(ERROR,
70 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
71 : : errmsg("cannot display a value of type %s", "gtrgm")));
72 : :
73 : : PG_RETURN_VOID(); /* keep compiler quiet */
74 : : }
75 : :
76 : : static TRGM *
2176 akorotkov@postgresql 77 :CBC 28153 : gtrgm_alloc(bool isalltrue, int siglen, BITVECP sign)
78 : : {
79 [ - + ]: 28153 : int flag = SIGNKEY | (isalltrue ? ALLISTRUE : 0);
80 [ - + + - ]: 28153 : int size = CALCGTSIZE(flag, siglen);
81 : 28153 : TRGM *res = palloc(size);
82 : :
83 : 28153 : SET_VARSIZE(res, size);
84 : 28153 : res->flag = flag;
85 : :
86 [ + - ]: 28153 : if (!isalltrue)
87 : : {
88 [ + + ]: 28153 : if (sign)
89 : 556 : memcpy(GETSIGN(res), sign, siglen);
90 : : else
91 : 27597 : memset(GETSIGN(res), 0, siglen);
92 : : }
93 : :
94 : 28153 : return res;
95 : : }
96 : :
97 : : static void
98 : 47653 : makesign(BITVECP sign, TRGM *a, int siglen)
99 : : {
100 : : int32 k,
7958 teodor@sigaev.ru 101 : 47653 : len = ARRNELEM(a);
102 : 47653 : trgm *ptr = GETARR(a);
5011 peter_e@gmx.net 103 : 47653 : int32 tmp = 0;
104 : :
1132 peter@eisentraut.org 105 [ + + + + : 47653 : MemSet(sign, 0, siglen);
+ - - + -
- ]
2176 akorotkov@postgresql 106 : 47653 : SETBIT(sign, SIGLENBIT(siglen)); /* set last unused bit */
7868 bruce@momjian.us 107 [ + + ]: 468207 : for (k = 0; k < len; k++)
108 : : {
388 peter@eisentraut.org 109 : 420554 : CPTRGM(&tmp, ptr + k);
2176 akorotkov@postgresql 110 : 420554 : HASH(sign, tmp, siglen);
111 : : }
7958 teodor@sigaev.ru 112 : 47653 : }
113 : :
114 : : Datum
115 : 27789 : gtrgm_compress(PG_FUNCTION_ARGS)
116 : : {
117 : 27789 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1949 akorotkov@postgresql 118 [ + - ]: 27789 : int siglen = GET_SIGLEN();
7958 teodor@sigaev.ru 119 : 27789 : GISTENTRY *retval = entry;
120 : :
121 [ + + ]: 27789 : if (entry->leafkey)
122 : : { /* trgm */
123 : : TRGM *res;
3290 noah@leadboat.com 124 : 24452 : text *val = DatumGetTextPP(entry->key);
125 : :
126 [ - + - - : 24452 : res = generate_trgm(VARDATA_ANY(val), VARSIZE_ANY_EXHDR(val));
- - - - +
- + - ]
100 michael@paquier.xyz 127 :GNC 24452 : retval = palloc_object(GISTENTRY);
7958 teodor@sigaev.ru 128 :CBC 24452 : gistentryinit(*retval, PointerGetDatum(res),
129 : : entry->rel, entry->page,
130 : : entry->offset, false);
131 : : }
132 [ + - ]: 3337 : else if (ISSIGNKEY(DatumGetPointer(entry->key)) &&
133 [ + - ]: 3337 : !ISALLTRUE(DatumGetPointer(entry->key)))
134 : : {
135 : : int32 i;
136 : : TRGM *res;
137 : 3337 : BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
138 : :
2176 akorotkov@postgresql 139 [ + - ]: 3596 : LOOPBYTE(siglen)
140 : : {
6694 bruce@momjian.us 141 [ + + ]: 3596 : if ((sign[i] & 0xff) != 0xff)
142 : 3337 : PG_RETURN_POINTER(retval);
143 : : }
144 : :
2176 akorotkov@postgresql 145 :UBC 0 : res = gtrgm_alloc(true, siglen, sign);
100 michael@paquier.xyz 146 :UNC 0 : retval = palloc_object(GISTENTRY);
7958 teodor@sigaev.ru 147 :UBC 0 : gistentryinit(*retval, PointerGetDatum(res),
148 : : entry->rel, entry->page,
149 : : entry->offset, false);
150 : : }
7958 teodor@sigaev.ru 151 :CBC 24452 : PG_RETURN_POINTER(retval);
152 : : }
153 : :
154 : : Datum
155 : 1362561 : gtrgm_decompress(PG_FUNCTION_ARGS)
156 : : {
6918 tgl@sss.pgh.pa.us 157 : 1362561 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
158 : : GISTENTRY *retval;
159 : : text *key;
160 : :
3290 noah@leadboat.com 161 : 1362561 : key = DatumGetTextPP(entry->key);
162 : :
6918 tgl@sss.pgh.pa.us 163 [ - + ]: 1362561 : if (key != (text *) DatumGetPointer(entry->key))
164 : : {
165 : : /* need to pass back the decompressed item */
100 michael@paquier.xyz 166 :UNC 0 : retval = palloc_object(GISTENTRY);
6918 tgl@sss.pgh.pa.us 167 :UBC 0 : gistentryinit(*retval, PointerGetDatum(key),
168 : : entry->rel, entry->page, entry->offset, entry->leafkey);
169 : 0 : PG_RETURN_POINTER(retval);
170 : : }
171 : : else
172 : : {
173 : : /* we can return the entry as-is */
6918 tgl@sss.pgh.pa.us 174 :CBC 1362561 : PG_RETURN_POINTER(entry);
175 : : }
176 : : }
177 : :
178 : : static int32
2176 akorotkov@postgresql 179 : 642 : cnt_sml_sign_common(TRGM *qtrg, BITVECP sign, int siglen)
180 : : {
5011 peter_e@gmx.net 181 : 642 : int32 count = 0;
182 : : int32 k,
5580 tgl@sss.pgh.pa.us 183 : 642 : len = ARRNELEM(qtrg);
184 : 642 : trgm *ptr = GETARR(qtrg);
5011 peter_e@gmx.net 185 : 642 : int32 tmp = 0;
186 : :
5580 tgl@sss.pgh.pa.us 187 [ + + ]: 5866 : for (k = 0; k < len; k++)
188 : : {
388 peter@eisentraut.org 189 : 5224 : CPTRGM(&tmp, ptr + k);
2176 akorotkov@postgresql 190 : 5224 : count += GETBIT(sign, HASHVAL(tmp, siglen));
191 : : }
192 : :
5580 tgl@sss.pgh.pa.us 193 : 642 : return count;
194 : : }
195 : :
196 : : Datum
7958 teodor@sigaev.ru 197 : 37638 : gtrgm_consistent(PG_FUNCTION_ARGS)
198 : : {
6544 tgl@sss.pgh.pa.us 199 : 37638 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
200 : 37638 : text *query = PG_GETARG_TEXT_P(1);
5580 201 : 37638 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
202 : : #ifdef NOT_USED
203 : : Oid subtype = PG_GETARG_OID(3);
204 : : #endif
6544 205 : 37638 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
1949 akorotkov@postgresql 206 [ + - ]: 37638 : int siglen = GET_SIGLEN();
6544 tgl@sss.pgh.pa.us 207 : 37638 : TRGM *key = (TRGM *) DatumGetPointer(entry->key);
208 : : TRGM *qtrg;
209 : : bool res;
5280 210 : 37638 : Size querysize = VARSIZE(query);
211 : : gtrgm_consistent_cache *cache;
212 : : double nlimit;
213 : :
214 : : /*
215 : : * We keep the extracted trigrams in cache, because trigram extraction is
216 : : * relatively CPU-expensive. When trying to reuse a cached value, check
217 : : * strategy number not just query itself, because trigram extraction
218 : : * depends on strategy.
219 : : *
220 : : * The cached structure is a single palloc chunk containing the
221 : : * gtrgm_consistent_cache header, then the input query (4-byte length
222 : : * word, uncompressed, starting at a MAXALIGN boundary), then the TRGM
223 : : * value (also starting at a MAXALIGN boundary). However we don't try to
224 : : * include the regex graph (if any) in that struct. (XXX currently, this
225 : : * approach can leak regex graphs across index rescans. Not clear if
226 : : * that's worth fixing.)
227 : : */
4722 228 : 37638 : cache = (gtrgm_consistent_cache *) fcinfo->flinfo->fn_extra;
5280 229 [ + + ]: 37638 : if (cache == NULL ||
4722 230 [ + - + - ]: 75164 : cache->strategy != strategy ||
231 [ + - ]: 37582 : VARSIZE(cache->query) != querysize ||
396 peter@eisentraut.org 232 [ - + ]: 37582 : memcmp(cache->query, query, querysize) != 0)
233 : : {
234 : : gtrgm_consistent_cache *newcache;
4722 tgl@sss.pgh.pa.us 235 : 56 : TrgmPackedGraph *graph = NULL;
236 : : Size qtrgsize;
237 : :
5522 238 [ + + + - ]: 56 : switch (strategy)
239 : : {
240 : 28 : case SimilarityStrategyNumber:
241 : : case WordSimilarityStrategyNumber:
242 : : case StrictWordSimilarityStrategyNumber:
243 : : case EqualStrategyNumber:
5280 244 : 28 : qtrg = generate_trgm(VARDATA(query),
245 : 28 : querysize - VARHDRSZ);
5522 246 : 28 : break;
247 : 7 : case ILikeStrategyNumber:
248 : : #ifndef IGNORECASE
249 : : elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
250 : : #endif
251 : : pg_fallthrough;
252 : : case LikeStrategyNumber:
5280 253 : 7 : qtrg = generate_wildcard_trgm(VARDATA(query),
254 : 7 : querysize - VARHDRSZ);
5522 255 : 7 : break;
4722 256 : 21 : case RegExpICaseStrategyNumber:
257 : : #ifndef IGNORECASE
258 : : elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
259 : : #endif
260 : : pg_fallthrough;
261 : : case RegExpStrategyNumber:
262 : 21 : qtrg = createTrgmNFA(query, PG_GET_COLLATION(),
263 : 21 : &graph, fcinfo->flinfo->fn_mcxt);
264 : : /* just in case an empty array is returned ... */
265 [ + + - + ]: 21 : if (qtrg && ARRNELEM(qtrg) <= 0)
266 : : {
4722 tgl@sss.pgh.pa.us 267 :UBC 0 : pfree(qtrg);
268 : 0 : qtrg = NULL;
269 : : }
4722 tgl@sss.pgh.pa.us 270 :CBC 21 : break;
5522 tgl@sss.pgh.pa.us 271 :UBC 0 : default:
272 [ # # ]: 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
273 : : qtrg = NULL; /* keep compiler quiet */
274 : : break;
275 : : }
276 : :
4722 tgl@sss.pgh.pa.us 277 [ + + ]:CBC 56 : qtrgsize = qtrg ? VARSIZE(qtrg) : 0;
278 : :
279 : : newcache = (gtrgm_consistent_cache *)
280 : 56 : MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
281 : : MAXALIGN(sizeof(gtrgm_consistent_cache)) +
282 : 56 : MAXALIGN(querysize) +
283 : : qtrgsize);
284 : :
285 : 56 : newcache->strategy = strategy;
286 : 56 : newcache->query = (text *)
287 : : ((char *) newcache + MAXALIGN(sizeof(gtrgm_consistent_cache)));
396 peter@eisentraut.org 288 : 56 : memcpy(newcache->query, query, querysize);
4722 tgl@sss.pgh.pa.us 289 [ + + ]: 56 : if (qtrg)
290 : : {
291 : 52 : newcache->trigrams = (TRGM *)
292 : 52 : ((char *) newcache->query + MAXALIGN(querysize));
396 peter@eisentraut.org 293 : 52 : memcpy((char *) newcache->trigrams, qtrg, qtrgsize);
294 : : /* release qtrg in case it was made in fn_mcxt */
4722 tgl@sss.pgh.pa.us 295 : 52 : pfree(qtrg);
296 : : }
297 : : else
298 : 4 : newcache->trigrams = NULL;
299 : 56 : newcache->graph = graph;
300 : :
6456 teodor@sigaev.ru 301 [ - + ]: 56 : if (cache)
6456 teodor@sigaev.ru 302 :UBC 0 : pfree(cache);
472 peter@eisentraut.org 303 :CBC 56 : fcinfo->flinfo->fn_extra = newcache;
4722 tgl@sss.pgh.pa.us 304 : 56 : cache = newcache;
305 : : }
306 : :
307 : 37638 : qtrg = cache->trigrams;
308 : :
5580 309 [ + + + - ]: 37638 : switch (strategy)
310 : : {
311 : 35236 : case SimilarityStrategyNumber:
312 : : case WordSimilarityStrategyNumber:
313 : : case StrictWordSimilarityStrategyNumber:
314 : :
315 : : /*
316 : : * Similarity search is exact. (Strict) word similarity search is
317 : : * inexact
318 : : */
2916 teodor@sigaev.ru 319 : 35236 : *recheck = (strategy != SimilarityStrategyNumber);
320 : :
321 : 35236 : nlimit = index_strategy_get_limit(strategy);
322 : :
5580 tgl@sss.pgh.pa.us 323 [ + + ]: 35236 : if (GIST_LEAF(entry))
324 : : { /* all leafs contains orig trgm */
3555 325 : 34632 : double tmpsml = cnt_sml(qtrg, key, *recheck);
326 : :
327 : 34632 : res = (tmpsml >= nlimit);
328 : : }
5580 329 [ - + ]: 604 : else if (ISALLTRUE(key))
330 : : { /* non-leaf contains signature */
5580 tgl@sss.pgh.pa.us 331 :UBC 0 : res = true;
332 : : }
333 : : else
334 : : { /* non-leaf contains signature */
2176 akorotkov@postgresql 335 :CBC 604 : int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
5011 peter_e@gmx.net 336 : 604 : int32 len = ARRNELEM(qtrg);
337 : :
5580 tgl@sss.pgh.pa.us 338 [ - + ]: 604 : if (len == 0)
5580 tgl@sss.pgh.pa.us 339 :UBC 0 : res = false;
340 : : else
3651 teodor@sigaev.ru 341 :CBC 604 : res = (((((float8) count) / ((float8) len))) >= nlimit);
342 : : }
5580 tgl@sss.pgh.pa.us 343 : 35236 : break;
5522 344 : 190 : case ILikeStrategyNumber:
345 : : #ifndef IGNORECASE
346 : : elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
347 : : #endif
348 : : pg_fallthrough;
349 : : case LikeStrategyNumber:
350 : : case EqualStrategyNumber:
351 : : /* Wildcard and equal search are inexact */
352 : 190 : *recheck = true;
353 : :
354 : : /*
355 : : * Check if all the extracted trigrams can be present in child
356 : : * nodes.
357 : : */
358 [ + - ]: 190 : if (GIST_LEAF(entry))
359 : : { /* all leafs contains orig trgm */
360 : 190 : res = trgm_contained_by(qtrg, key);
361 : : }
5522 tgl@sss.pgh.pa.us 362 [ # # ]:UBC 0 : else if (ISALLTRUE(key))
363 : : { /* non-leaf contains signature */
364 : 0 : res = true;
365 : : }
366 : : else
367 : : { /* non-leaf contains signature */
368 : : int32 k,
5453 bruce@momjian.us 369 : 0 : tmp = 0,
370 : 0 : len = ARRNELEM(qtrg);
371 : 0 : trgm *ptr = GETARR(qtrg);
372 : 0 : BITVECP sign = GETSIGN(key);
373 : :
5522 tgl@sss.pgh.pa.us 374 : 0 : res = true;
375 [ # # ]: 0 : for (k = 0; k < len; k++)
376 : : {
388 peter@eisentraut.org 377 : 0 : CPTRGM(&tmp, ptr + k);
2176 akorotkov@postgresql 378 [ # # ]: 0 : if (!GETBIT(sign, HASHVAL(tmp, siglen)))
379 : : {
5522 tgl@sss.pgh.pa.us 380 : 0 : res = false;
381 : 0 : break;
382 : : }
383 : : }
384 : : }
5522 tgl@sss.pgh.pa.us 385 :CBC 190 : break;
4722 386 : 2212 : case RegExpICaseStrategyNumber:
387 : : #ifndef IGNORECASE
388 : : elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
389 : : #endif
390 : : pg_fallthrough;
391 : : case RegExpStrategyNumber:
392 : : /* Regexp search is inexact */
393 : 2212 : *recheck = true;
394 : :
395 : : /* Check regex match as much as we can with available info */
396 [ + + ]: 2212 : if (qtrg)
397 : : {
398 [ + + ]: 2172 : if (GIST_LEAF(entry))
399 : : { /* all leafs contains orig trgm */
400 : : bool *check;
401 : :
402 : 2150 : check = trgm_presence_map(qtrg, key);
403 : 2150 : res = trigramsMatchGraph(cache->graph, check);
404 : 2150 : pfree(check);
405 : : }
406 [ - + ]: 22 : else if (ISALLTRUE(key))
407 : : { /* non-leaf contains signature */
4722 tgl@sss.pgh.pa.us 408 :UBC 0 : res = true;
409 : : }
410 : : else
411 : : { /* non-leaf contains signature */
412 : : int32 k,
4722 tgl@sss.pgh.pa.us 413 :CBC 22 : tmp = 0,
414 : 22 : len = ARRNELEM(qtrg);
415 : 22 : trgm *ptr = GETARR(qtrg);
416 : 22 : BITVECP sign = GETSIGN(key);
417 : : bool *check;
418 : :
419 : : /*
420 : : * GETBIT() tests may give false positives, due to limited
421 : : * size of the sign array. But since trigramsMatchGraph()
422 : : * implements a monotone boolean function, false positives
423 : : * in the check array can't lead to false negative answer.
424 : : * So we can apply trigramsMatchGraph despite uncertainty,
425 : : * and that usefully improves the quality of the search.
426 : : */
4717 427 : 22 : check = (bool *) palloc(len * sizeof(bool));
4722 428 [ + + ]: 5566 : for (k = 0; k < len; k++)
429 : : {
388 peter@eisentraut.org 430 : 5544 : CPTRGM(&tmp, ptr + k);
2176 akorotkov@postgresql 431 : 5544 : check[k] = GETBIT(sign, HASHVAL(tmp, siglen));
432 : : }
4717 tgl@sss.pgh.pa.us 433 : 22 : res = trigramsMatchGraph(cache->graph, check);
434 : 22 : pfree(check);
435 : : }
436 : : }
437 : : else
438 : : {
439 : : /* trigram-free query must be rechecked everywhere */
4722 440 : 40 : res = true;
441 : : }
442 : 2212 : break;
5580 tgl@sss.pgh.pa.us 443 :UBC 0 : default:
444 [ # # ]: 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
445 : : res = false; /* keep compiler quiet */
446 : : break;
447 : : }
448 : :
5580 tgl@sss.pgh.pa.us 449 :CBC 37638 : PG_RETURN_BOOL(res);
450 : : }
451 : :
452 : : Datum
453 : 2864 : gtrgm_distance(PG_FUNCTION_ARGS)
454 : : {
455 : 2864 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
456 : 2864 : text *query = PG_GETARG_TEXT_P(1);
457 : 2864 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
458 : : #ifdef NOT_USED
459 : : Oid subtype = PG_GETARG_OID(3);
460 : : #endif
3651 teodor@sigaev.ru 461 : 2864 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
1949 akorotkov@postgresql 462 [ + - ]: 2864 : int siglen = GET_SIGLEN();
5580 tgl@sss.pgh.pa.us 463 : 2864 : TRGM *key = (TRGM *) DatumGetPointer(entry->key);
464 : : TRGM *qtrg;
465 : : float8 res;
5280 466 : 2864 : Size querysize = VARSIZE(query);
5580 467 : 2864 : char *cache = (char *) fcinfo->flinfo->fn_extra;
468 : :
469 : : /*
470 : : * Cache the generated trigrams across multiple calls with the same query.
471 : : */
5280 472 [ + + + - ]: 5724 : if (cache == NULL ||
473 [ + - ]: 2860 : VARSIZE(cache) != querysize ||
474 [ - + ]: 2860 : memcmp(cache, query, querysize) != 0)
475 : : {
476 : : char *newcache;
477 : :
478 : 4 : qtrg = generate_trgm(VARDATA(query), querysize - VARHDRSZ);
479 : :
480 : 4 : newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
481 : 4 : MAXALIGN(querysize) +
482 : 4 : VARSIZE(qtrg));
483 : :
484 : 4 : memcpy(newcache, query, querysize);
485 : 4 : memcpy(newcache + MAXALIGN(querysize), qtrg, VARSIZE(qtrg));
486 : :
487 [ - + ]: 4 : if (cache)
5280 tgl@sss.pgh.pa.us 488 :UBC 0 : pfree(cache);
5280 tgl@sss.pgh.pa.us 489 :CBC 4 : fcinfo->flinfo->fn_extra = newcache;
490 : 4 : cache = newcache;
491 : : }
492 : :
493 : 2864 : qtrg = (TRGM *) (cache + MAXALIGN(querysize));
494 : :
5580 495 [ + - ]: 2864 : switch (strategy)
496 : : {
497 : 2864 : case DistanceStrategyNumber:
498 : : case WordDistanceStrategyNumber:
499 : : case StrictWordDistanceStrategyNumber:
500 : : /* Only plain trigram distance is exact */
2916 teodor@sigaev.ru 501 : 2864 : *recheck = (strategy != DistanceStrategyNumber);
5580 tgl@sss.pgh.pa.us 502 [ + + ]: 2864 : if (GIST_LEAF(entry))
503 : : { /* all leafs contains orig trgm */
504 : :
505 : : /*
506 : : * Prevent gcc optimizing the sml variable using volatile
507 : : * keyword. Otherwise res can differ from the
508 : : * word_similarity_dist_op() function.
509 : : */
3651 teodor@sigaev.ru 510 : 2826 : float4 volatile sml = cnt_sml(qtrg, key, *recheck);
511 : :
512 : 2826 : res = 1.0 - sml;
513 : : }
5580 tgl@sss.pgh.pa.us 514 [ - + ]: 38 : else if (ISALLTRUE(key))
515 : : { /* all leafs contains orig trgm */
5580 tgl@sss.pgh.pa.us 516 :UBC 0 : res = 0.0;
517 : : }
518 : : else
519 : : { /* non-leaf contains signature */
2176 akorotkov@postgresql 520 :CBC 38 : int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
5011 peter_e@gmx.net 521 : 38 : int32 len = ARRNELEM(qtrg);
522 : :
5580 tgl@sss.pgh.pa.us 523 [ + - ]: 38 : res = (len == 0) ? -1.0 : 1.0 - ((float8) count) / ((float8) len);
524 : : }
525 : 2864 : break;
5580 tgl@sss.pgh.pa.us 526 :UBC 0 : default:
527 [ # # ]: 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
528 : : res = 0; /* keep compiler quiet */
529 : : break;
530 : : }
531 : :
5580 tgl@sss.pgh.pa.us 532 :CBC 2864 : PG_RETURN_FLOAT8(res);
533 : : }
534 : :
535 : : static int32
2176 akorotkov@postgresql 536 : 55194 : unionkey(BITVECP sbase, TRGM *add, int siglen)
537 : : {
538 : : int32 i;
539 : :
7958 teodor@sigaev.ru 540 [ + + ]: 55194 : if (ISSIGNKEY(add))
541 : : {
542 : 27597 : BITVECP sadd = GETSIGN(add);
543 : :
544 [ - + ]: 27597 : if (ISALLTRUE(add))
7958 teodor@sigaev.ru 545 :UBC 0 : return 1;
546 : :
2176 akorotkov@postgresql 547 [ + + ]:CBC 6507433 : LOOPBYTE(siglen)
6694 bruce@momjian.us 548 : 6479836 : sbase[i] |= sadd[i];
549 : : }
550 : : else
551 : : {
7958 teodor@sigaev.ru 552 : 27597 : trgm *ptr = GETARR(add);
5011 peter_e@gmx.net 553 : 27597 : int32 tmp = 0;
554 : :
7868 bruce@momjian.us 555 [ + + ]: 275985 : for (i = 0; i < ARRNELEM(add); i++)
556 : : {
388 peter@eisentraut.org 557 : 248388 : CPTRGM(&tmp, ptr + i);
2176 akorotkov@postgresql 558 : 248388 : HASH(sbase, tmp, siglen);
559 : : }
560 : : }
7958 teodor@sigaev.ru 561 : 55194 : return 0;
562 : : }
563 : :
564 : :
565 : : Datum
566 : 27597 : gtrgm_union(PG_FUNCTION_ARGS)
567 : : {
7868 bruce@momjian.us 568 : 27597 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
5011 peter_e@gmx.net 569 : 27597 : int32 len = entryvec->n;
7958 teodor@sigaev.ru 570 : 27597 : int *size = (int *) PG_GETARG_POINTER(1);
1949 akorotkov@postgresql 571 [ + - ]: 27597 : int siglen = GET_SIGLEN();
572 : : int32 i;
2176 573 : 27597 : TRGM *result = gtrgm_alloc(false, siglen, NULL);
574 : 27597 : BITVECP base = GETSIGN(result);
575 : :
7958 teodor@sigaev.ru 576 [ + + ]: 82791 : for (i = 0; i < len; i++)
577 : : {
2176 akorotkov@postgresql 578 [ - + ]: 55194 : if (unionkey(base, GETENTRY(entryvec, i), siglen))
579 : : {
2176 akorotkov@postgresql 580 :UBC 0 : result->flag = ALLISTRUE;
581 : 0 : SET_VARSIZE(result, CALCGTSIZE(ALLISTRUE, siglen));
7958 teodor@sigaev.ru 582 : 0 : break;
583 : : }
584 : : }
585 : :
2176 akorotkov@postgresql 586 :CBC 27597 : *size = VARSIZE(result);
587 : :
7958 teodor@sigaev.ru 588 : 27597 : PG_RETURN_POINTER(result);
589 : : }
590 : :
591 : : Datum
592 : 27597 : gtrgm_same(PG_FUNCTION_ARGS)
593 : : {
7868 bruce@momjian.us 594 : 27597 : TRGM *a = (TRGM *) PG_GETARG_POINTER(0);
595 : 27597 : TRGM *b = (TRGM *) PG_GETARG_POINTER(1);
7958 teodor@sigaev.ru 596 : 27597 : bool *result = (bool *) PG_GETARG_POINTER(2);
1949 akorotkov@postgresql 597 [ + - ]: 27597 : int siglen = GET_SIGLEN();
598 : :
7958 teodor@sigaev.ru 599 [ + - ]: 27597 : if (ISSIGNKEY(a))
600 : : { /* then b also ISSIGNKEY */
601 [ - + - - ]: 27597 : if (ISALLTRUE(a) && ISALLTRUE(b))
7958 teodor@sigaev.ru 602 :UBC 0 : *result = true;
7958 teodor@sigaev.ru 603 [ - + ]:CBC 27597 : else if (ISALLTRUE(a))
7958 teodor@sigaev.ru 604 :UBC 0 : *result = false;
7958 teodor@sigaev.ru 605 [ - + ]:CBC 27597 : else if (ISALLTRUE(b))
7958 teodor@sigaev.ru 606 :UBC 0 : *result = false;
607 : : else
608 : : {
609 : : int32 i;
7958 teodor@sigaev.ru 610 :CBC 27597 : BITVECP sa = GETSIGN(a),
611 : 27597 : sb = GETSIGN(b);
612 : :
613 : 27597 : *result = true;
2176 akorotkov@postgresql 614 [ + + ]: 3185253 : LOOPBYTE(siglen)
615 : : {
6694 bruce@momjian.us 616 [ + + ]: 3160437 : if (sa[i] != sb[i])
617 : : {
618 : 2781 : *result = false;
619 : 2781 : break;
620 : : }
621 : : }
622 : : }
623 : : }
624 : : else
625 : : { /* a and b ISARRKEY */
5011 peter_e@gmx.net 626 :UBC 0 : int32 lena = ARRNELEM(a),
7958 teodor@sigaev.ru 627 : 0 : lenb = ARRNELEM(b);
628 : :
629 [ # # ]: 0 : if (lena != lenb)
630 : 0 : *result = false;
631 : : else
632 : : {
633 : 0 : trgm *ptra = GETARR(a),
634 : 0 : *ptrb = GETARR(b);
635 : : int32 i;
636 : :
637 : 0 : *result = true;
638 [ # # ]: 0 : for (i = 0; i < lena; i++)
7868 bruce@momjian.us 639 [ # # ]: 0 : if (CMPTRGM(ptra + i, ptrb + i))
640 : : {
7958 teodor@sigaev.ru 641 : 0 : *result = false;
642 : 0 : break;
643 : : }
644 : : }
645 : : }
646 : :
7958 teodor@sigaev.ru 647 :CBC 27597 : PG_RETURN_POINTER(result);
648 : : }
649 : :
650 : : static int32
2176 akorotkov@postgresql 651 :UBC 0 : sizebitvec(BITVECP sign, int siglen)
652 : : {
653 : 0 : return pg_popcount(sign, siglen);
654 : : }
655 : :
656 : : static int
2176 akorotkov@postgresql 657 :CBC 4929506 : hemdistsign(BITVECP a, BITVECP b, int siglen)
658 : : {
659 : : int i,
660 : : diff,
7868 bruce@momjian.us 661 : 4929506 : dist = 0;
662 : :
2176 akorotkov@postgresql 663 [ + + ]: 337023450 : LOOPBYTE(siglen)
664 : : {
6694 bruce@momjian.us 665 : 332093944 : diff = (unsigned char) (a[i] ^ b[i]);
666 : : /* Using the popcount functions here isn't likely to win */
2585 tgl@sss.pgh.pa.us 667 : 332093944 : dist += pg_number_of_ones[diff];
668 : : }
7958 teodor@sigaev.ru 669 : 4929506 : return dist;
670 : : }
671 : :
672 : : static int
2176 akorotkov@postgresql 673 :UBC 0 : hemdist(TRGM *a, TRGM *b, int siglen)
674 : : {
7868 bruce@momjian.us 675 [ # # ]: 0 : if (ISALLTRUE(a))
676 : : {
7958 teodor@sigaev.ru 677 [ # # ]: 0 : if (ISALLTRUE(b))
678 : 0 : return 0;
679 : : else
2176 akorotkov@postgresql 680 : 0 : return SIGLENBIT(siglen) - sizebitvec(GETSIGN(b), siglen);
681 : : }
7868 bruce@momjian.us 682 [ # # ]: 0 : else if (ISALLTRUE(b))
2176 akorotkov@postgresql 683 : 0 : return SIGLENBIT(siglen) - sizebitvec(GETSIGN(a), siglen);
684 : :
685 : 0 : return hemdistsign(GETSIGN(a), GETSIGN(b), siglen);
686 : : }
687 : :
688 : : Datum
7958 teodor@sigaev.ru 689 :CBC 1195158 : gtrgm_penalty(PG_FUNCTION_ARGS)
690 : : {
691 : 1195158 : GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
692 : 1195158 : GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
693 : 1195158 : float *penalty = (float *) PG_GETARG_POINTER(2);
1949 akorotkov@postgresql 694 [ + - ]: 1195158 : int siglen = GET_SIGLEN();
7868 bruce@momjian.us 695 : 1195158 : TRGM *origval = (TRGM *) DatumGetPointer(origentry->key);
696 : 1195158 : TRGM *newval = (TRGM *) DatumGetPointer(newentry->key);
7958 teodor@sigaev.ru 697 : 1195158 : BITVECP orig = GETSIGN(origval);
698 : :
699 : 1195158 : *penalty = 0.0;
700 : :
7868 bruce@momjian.us 701 [ + - ]: 1195158 : if (ISARRKEY(newval))
702 : : {
5280 tgl@sss.pgh.pa.us 703 : 1195158 : char *cache = (char *) fcinfo->flinfo->fn_extra;
39 john.naylor@postgres 704 : 1195158 : TRGM *cachedVal = NULL;
5280 tgl@sss.pgh.pa.us 705 : 1195158 : Size newvalsize = VARSIZE(newval);
706 : : BITVECP sign;
707 : :
39 john.naylor@postgres 708 [ + + ]: 1195158 : if (cache != NULL)
709 : 1195152 : cachedVal = (TRGM *) (cache + MAXALIGN(siglen));
710 : :
711 : : /*
712 : : * Cache the sign data across multiple calls with the same newval.
713 : : */
5280 tgl@sss.pgh.pa.us 714 [ + + + + ]: 2390310 : if (cache == NULL ||
715 [ + + ]: 1195152 : VARSIZE(cachedVal) != newvalsize ||
716 [ + + ]: 1194125 : memcmp(cachedVal, newval, newvalsize) != 0)
717 : : {
718 : : char *newcache;
719 : :
720 : 3763 : newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
2176 akorotkov@postgresql 721 : 3763 : MAXALIGN(siglen) +
722 : : newvalsize);
723 : :
724 : 3763 : makesign((BITVECP) newcache, newval, siglen);
725 : :
726 : 3763 : cachedVal = (TRGM *) (newcache + MAXALIGN(siglen));
5280 tgl@sss.pgh.pa.us 727 : 3763 : memcpy(cachedVal, newval, newvalsize);
728 : :
729 [ + + ]: 3763 : if (cache)
730 : 3757 : pfree(cache);
731 : 3763 : fcinfo->flinfo->fn_extra = newcache;
732 : 3763 : cache = newcache;
733 : : }
734 : :
735 : 1195158 : sign = (BITVECP) cache;
736 : :
7868 bruce@momjian.us 737 [ - + ]: 1195158 : if (ISALLTRUE(origval))
2176 akorotkov@postgresql 738 :UBC 0 : *penalty = ((float) (SIGLENBIT(siglen) - sizebitvec(sign, siglen))) / (float) (SIGLENBIT(siglen) + 1);
739 : : else
2176 akorotkov@postgresql 740 :CBC 1195158 : *penalty = hemdistsign(sign, orig, siglen);
741 : : }
742 : : else
2176 akorotkov@postgresql 743 :UBC 0 : *penalty = hemdist(origval, newval, siglen);
7958 teodor@sigaev.ru 744 :CBC 1195158 : PG_RETURN_POINTER(penalty);
745 : : }
746 : :
747 : : typedef struct
748 : : {
749 : : bool allistrue;
750 : : BITVECP sign;
751 : : } CACHESIGN;
752 : :
753 : : static void
2176 akorotkov@postgresql 754 : 44110 : fillcache(CACHESIGN *item, TRGM *key, BITVECP sign, int siglen)
755 : : {
7958 teodor@sigaev.ru 756 : 44110 : item->allistrue = false;
2176 akorotkov@postgresql 757 : 44110 : item->sign = sign;
7958 teodor@sigaev.ru 758 [ + + ]: 44110 : if (ISARRKEY(key))
2176 akorotkov@postgresql 759 : 43890 : makesign(item->sign, key, siglen);
7958 teodor@sigaev.ru 760 [ - + ]: 220 : else if (ISALLTRUE(key))
7958 teodor@sigaev.ru 761 :UBC 0 : item->allistrue = true;
762 : : else
1132 peter@eisentraut.org 763 :CBC 220 : memcpy(item->sign, GETSIGN(key), siglen);
7958 teodor@sigaev.ru 764 : 44110 : }
765 : :
766 : : #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
767 : : typedef struct
768 : : {
769 : : OffsetNumber pos;
770 : : int32 cost;
771 : : } SPLITCOST;
772 : :
773 : : static int
774 : 49063 : comparecost(const void *a, const void *b)
775 : : {
5299 peter_e@gmx.net 776 [ + + ]: 49063 : if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
7958 teodor@sigaev.ru 777 : 44213 : return 0;
778 : : else
5299 peter_e@gmx.net 779 [ + + ]: 4850 : return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
780 : : }
781 : :
782 : :
783 : : static int
2176 akorotkov@postgresql 784 : 3647240 : hemdistcache(CACHESIGN *a, CACHESIGN *b, int siglen)
785 : : {
7868 bruce@momjian.us 786 [ - + ]: 3647240 : if (a->allistrue)
787 : : {
7958 teodor@sigaev.ru 788 [ # # ]:UBC 0 : if (b->allistrue)
789 : 0 : return 0;
790 : : else
2176 akorotkov@postgresql 791 : 0 : return SIGLENBIT(siglen) - sizebitvec(b->sign, siglen);
792 : : }
7868 bruce@momjian.us 793 [ - + ]:CBC 3647240 : else if (b->allistrue)
2176 akorotkov@postgresql 794 :UBC 0 : return SIGLENBIT(siglen) - sizebitvec(a->sign, siglen);
795 : :
2176 akorotkov@postgresql 796 :CBC 3647240 : return hemdistsign(a->sign, b->sign, siglen);
797 : : }
798 : :
799 : : Datum
7958 teodor@sigaev.ru 800 : 278 : gtrgm_picksplit(PG_FUNCTION_ARGS)
801 : : {
7868 bruce@momjian.us 802 : 278 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
1949 rhodiumtoad@postgres 803 : 278 : OffsetNumber maxoff = entryvec->n - 1;
7958 teodor@sigaev.ru 804 : 278 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
1949 akorotkov@postgresql 805 [ + - ]: 278 : int siglen = GET_SIGLEN();
806 : : OffsetNumber k,
807 : : j;
808 : : TRGM *datum_l,
809 : : *datum_r;
810 : : BITVECP union_l,
811 : : union_r;
812 : : int32 size_alpha,
813 : : size_beta;
814 : : int32 size_waste,
7958 teodor@sigaev.ru 815 : 278 : waste = -1;
816 : : int32 nbytes;
817 : 278 : OffsetNumber seed_1 = 0,
818 : 278 : seed_2 = 0;
819 : : OffsetNumber *left,
820 : : *right;
821 : : BITVECP ptr;
822 : : int i;
823 : : CACHESIGN *cache;
824 : : char *cache_sign;
825 : : SPLITCOST *costvector;
826 : :
827 : : /* cache the sign data for each existing item */
100 michael@paquier.xyz 828 :GNC 278 : cache = palloc_array(CACHESIGN, maxoff + 1);
1949 rhodiumtoad@postgres 829 :CBC 278 : cache_sign = palloc(siglen * (maxoff + 1));
830 : :
5280 tgl@sss.pgh.pa.us 831 [ + + ]: 44388 : for (k = FirstOffsetNumber; k <= maxoff; k = OffsetNumberNext(k))
2176 akorotkov@postgresql 832 : 44110 : fillcache(&cache[k], GETENTRY(entryvec, k), &cache_sign[siglen * k],
833 : : siglen);
834 : :
835 : : /* now find the two furthest-apart items */
7868 bruce@momjian.us 836 [ + + ]: 44110 : for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
837 : : {
838 [ + + ]: 3602852 : for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
839 : : {
2176 akorotkov@postgresql 840 : 3559020 : size_waste = hemdistcache(&(cache[j]), &(cache[k]), siglen);
7868 bruce@momjian.us 841 [ + + ]: 3559020 : if (size_waste > waste)
842 : : {
7958 teodor@sigaev.ru 843 : 466 : waste = size_waste;
844 : 466 : seed_1 = k;
845 : 466 : seed_2 = j;
846 : : }
847 : : }
848 : : }
849 : :
850 : : /* just in case we didn't make a selection ... */
7868 bruce@momjian.us 851 [ + - - + ]: 278 : if (seed_1 == 0 || seed_2 == 0)
852 : : {
7958 teodor@sigaev.ru 853 :UBC 0 : seed_1 = 1;
854 : 0 : seed_2 = 2;
855 : : }
856 : :
857 : : /* initialize the result vectors */
1949 rhodiumtoad@postgres 858 :CBC 278 : nbytes = maxoff * sizeof(OffsetNumber);
5280 tgl@sss.pgh.pa.us 859 : 278 : v->spl_left = left = (OffsetNumber *) palloc(nbytes);
860 : 278 : v->spl_right = right = (OffsetNumber *) palloc(nbytes);
861 : 278 : v->spl_nleft = 0;
862 : 278 : v->spl_nright = 0;
863 : :
864 : : /* form initial .. */
2176 akorotkov@postgresql 865 : 278 : datum_l = gtrgm_alloc(cache[seed_1].allistrue, siglen, cache[seed_1].sign);
866 : 278 : datum_r = gtrgm_alloc(cache[seed_2].allistrue, siglen, cache[seed_2].sign);
867 : :
7868 bruce@momjian.us 868 : 278 : union_l = GETSIGN(datum_l);
869 : 278 : union_r = GETSIGN(datum_r);
870 : :
871 : : /* sort before ... */
100 michael@paquier.xyz 872 :GNC 278 : costvector = palloc_array(SPLITCOST, maxoff);
7868 bruce@momjian.us 873 [ + + ]:CBC 44388 : for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
874 : : {
7958 teodor@sigaev.ru 875 : 44110 : costvector[j - 1].pos = j;
2176 akorotkov@postgresql 876 : 44110 : size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]), siglen);
877 : 44110 : size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]), siglen);
7958 teodor@sigaev.ru 878 : 44110 : costvector[j - 1].cost = abs(size_alpha - size_beta);
879 : : }
1132 peter@eisentraut.org 880 : 278 : qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
881 : :
7868 bruce@momjian.us 882 [ + + ]: 44388 : for (k = 0; k < maxoff; k++)
883 : : {
7958 teodor@sigaev.ru 884 : 44110 : j = costvector[k].pos;
7868 bruce@momjian.us 885 [ + + ]: 44110 : if (j == seed_1)
886 : : {
7958 teodor@sigaev.ru 887 : 278 : *left++ = j;
888 : 278 : v->spl_nleft++;
889 : 278 : continue;
890 : : }
7868 bruce@momjian.us 891 [ + + ]: 43832 : else if (j == seed_2)
892 : : {
7958 teodor@sigaev.ru 893 : 278 : *right++ = j;
894 : 278 : v->spl_nright++;
895 : 278 : continue;
896 : : }
897 : :
7868 bruce@momjian.us 898 [ + - - + ]: 43554 : if (ISALLTRUE(datum_l) || cache[j].allistrue)
899 : : {
7868 bruce@momjian.us 900 [ # # # # ]:UBC 0 : if (ISALLTRUE(datum_l) && cache[j].allistrue)
901 : 0 : size_alpha = 0;
902 : : else
2176 akorotkov@postgresql 903 : 0 : size_alpha = SIGLENBIT(siglen) -
2236 alvherre@alvh.no-ip. 904 [ # # ]: 0 : sizebitvec((cache[j].allistrue) ? GETSIGN(datum_l) :
2176 akorotkov@postgresql 905 : 0 : GETSIGN(cache[j].sign),
906 : : siglen);
907 : : }
908 : : else
2176 akorotkov@postgresql 909 :CBC 43554 : size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l), siglen);
910 : :
7868 bruce@momjian.us 911 [ + - - + ]: 43554 : if (ISALLTRUE(datum_r) || cache[j].allistrue)
912 : : {
7868 bruce@momjian.us 913 [ # # # # ]:UBC 0 : if (ISALLTRUE(datum_r) && cache[j].allistrue)
914 : 0 : size_beta = 0;
915 : : else
2176 akorotkov@postgresql 916 : 0 : size_beta = SIGLENBIT(siglen) -
2236 alvherre@alvh.no-ip. 917 [ # # ]: 0 : sizebitvec((cache[j].allistrue) ? GETSIGN(datum_r) :
2176 akorotkov@postgresql 918 : 0 : GETSIGN(cache[j].sign),
919 : : siglen);
920 : : }
921 : : else
2176 akorotkov@postgresql 922 :CBC 43554 : size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r), siglen);
923 : :
7868 bruce@momjian.us 924 [ + + ]: 43554 : if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
925 : : {
926 [ + - - + ]: 21661 : if (ISALLTRUE(datum_l) || cache[j].allistrue)
927 : : {
7868 bruce@momjian.us 928 [ # # ]:UBC 0 : if (!ISALLTRUE(datum_l))
1132 peter@eisentraut.org 929 : 0 : memset(GETSIGN(datum_l), 0xff, siglen);
930 : : }
931 : : else
932 : : {
7868 bruce@momjian.us 933 :CBC 21661 : ptr = cache[j].sign;
2176 akorotkov@postgresql 934 [ + + ]: 2237257 : LOOPBYTE(siglen)
6694 bruce@momjian.us 935 : 2215596 : union_l[i] |= ptr[i];
936 : : }
7958 teodor@sigaev.ru 937 : 21661 : *left++ = j;
938 : 21661 : v->spl_nleft++;
939 : : }
940 : : else
941 : : {
7868 bruce@momjian.us 942 [ + - - + ]: 21893 : if (ISALLTRUE(datum_r) || cache[j].allistrue)
943 : : {
7868 bruce@momjian.us 944 [ # # ]:UBC 0 : if (!ISALLTRUE(datum_r))
1132 peter@eisentraut.org 945 : 0 : memset(GETSIGN(datum_r), 0xff, siglen);
946 : : }
947 : : else
948 : : {
7868 bruce@momjian.us 949 :CBC 21893 : ptr = cache[j].sign;
2176 akorotkov@postgresql 950 [ + + ]: 2240273 : LOOPBYTE(siglen)
6694 bruce@momjian.us 951 : 2218380 : union_r[i] |= ptr[i];
952 : : }
7958 teodor@sigaev.ru 953 : 21893 : *right++ = j;
954 : 21893 : v->spl_nright++;
955 : : }
956 : : }
957 : :
958 : 278 : v->spl_ldatum = PointerGetDatum(datum_l);
959 : 278 : v->spl_rdatum = PointerGetDatum(datum_r);
960 : :
961 : 278 : PG_RETURN_POINTER(v);
962 : : }
963 : :
964 : : Datum
2176 akorotkov@postgresql 965 : 31 : gtrgm_options(PG_FUNCTION_ARGS)
966 : : {
967 : 31 : local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
968 : :
969 : 31 : init_local_reloptions(relopts, sizeof(TrgmGistOptions));
970 : 31 : add_local_int_reloption(relopts, "siglen",
971 : : "signature length in bytes",
972 : : SIGLEN_DEFAULT, 1, SIGLEN_MAX,
973 : : offsetof(TrgmGistOptions, siglen));
974 : :
975 : 31 : PG_RETURN_VOID();
976 : : }
|