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 : :
7258 teodor@sigaev.ru 43 :CBC 1 : PG_FUNCTION_INFO_V1(gtrgm_in);
44 : 1 : PG_FUNCTION_INFO_V1(gtrgm_out);
45 : 4 : PG_FUNCTION_INFO_V1(gtrgm_compress);
46 : 4 : PG_FUNCTION_INFO_V1(gtrgm_decompress);
47 : 4 : PG_FUNCTION_INFO_V1(gtrgm_consistent);
4880 tgl@sss.pgh.pa.us 48 : 4 : PG_FUNCTION_INFO_V1(gtrgm_distance);
7258 teodor@sigaev.ru 49 : 4 : PG_FUNCTION_INFO_V1(gtrgm_union);
50 : 4 : PG_FUNCTION_INFO_V1(gtrgm_same);
51 : 4 : PG_FUNCTION_INFO_V1(gtrgm_penalty);
52 : 4 : PG_FUNCTION_INFO_V1(gtrgm_picksplit);
1476 akorotkov@postgresql 53 : 4 : PG_FUNCTION_INFO_V1(gtrgm_options);
54 : :
55 : :
56 : : Datum
7258 teodor@sigaev.ru 57 :UBC 0 : gtrgm_in(PG_FUNCTION_ARGS)
58 : : {
491 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
7258 teodor@sigaev.ru 67 : 0 : gtrgm_out(PG_FUNCTION_ARGS)
68 : : {
491 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 *
1476 akorotkov@postgresql 77 :CBC 26596 : gtrgm_alloc(bool isalltrue, int siglen, BITVECP sign)
78 : : {
79 [ - + ]: 26596 : int flag = SIGNKEY | (isalltrue ? ALLISTRUE : 0);
80 [ - + + - ]: 26596 : int size = CALCGTSIZE(flag, siglen);
81 : 26596 : TRGM *res = palloc(size);
82 : :
83 : 26596 : SET_VARSIZE(res, size);
84 : 26596 : res->flag = flag;
85 : :
86 [ + - ]: 26596 : if (!isalltrue)
87 : : {
88 [ + + ]: 26596 : if (sign)
89 : 538 : memcpy(GETSIGN(res), sign, siglen);
90 : : else
91 : 26058 : memset(GETSIGN(res), 0, siglen);
92 : : }
93 : :
94 : 26596 : return res;
95 : : }
96 : :
97 : : static void
98 : 45615 : makesign(BITVECP sign, TRGM *a, int siglen)
99 : : {
100 : : int32 k,
7258 teodor@sigaev.ru 101 : 45615 : len = ARRNELEM(a);
102 : 45615 : trgm *ptr = GETARR(a);
4311 peter_e@gmx.net 103 : 45615 : int32 tmp = 0;
104 : :
432 peter@eisentraut.org 105 [ + + + + : 45615 : MemSet(sign, 0, siglen);
+ - - + -
- ]
1476 akorotkov@postgresql 106 : 45615 : SETBIT(sign, SIGLENBIT(siglen)); /* set last unused bit */
7168 bruce@momjian.us 107 [ + + ]: 442424 : for (k = 0; k < len; k++)
108 : : {
109 : 396809 : CPTRGM(((char *) &tmp), ptr + k);
1476 akorotkov@postgresql 110 : 396809 : HASH(sign, tmp, siglen);
111 : : }
7258 teodor@sigaev.ru 112 : 45615 : }
113 : :
114 : : Datum
115 : 25518 : gtrgm_compress(PG_FUNCTION_ARGS)
116 : : {
117 : 25518 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1249 akorotkov@postgresql 118 [ + - ]: 25518 : int siglen = GET_SIGLEN();
7258 teodor@sigaev.ru 119 : 25518 : GISTENTRY *retval = entry;
120 : :
121 [ + + ]: 25518 : if (entry->leafkey)
122 : : { /* trgm */
123 : : TRGM *res;
2590 noah@leadboat.com 124 : 23402 : text *val = DatumGetTextPP(entry->key);
125 : :
126 [ - + - - : 23402 : res = generate_trgm(VARDATA_ANY(val), VARSIZE_ANY_EXHDR(val));
- - - - +
- + - ]
7258 teodor@sigaev.ru 127 : 23402 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
128 : 23402 : gistentryinit(*retval, PointerGetDatum(res),
129 : : entry->rel, entry->page,
130 : : entry->offset, false);
131 : : }
132 [ + - ]: 2116 : else if (ISSIGNKEY(DatumGetPointer(entry->key)) &&
133 [ + - ]: 2116 : !ISALLTRUE(DatumGetPointer(entry->key)))
134 : : {
135 : : int32 i;
136 : : TRGM *res;
137 : 2116 : BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
138 : :
1476 akorotkov@postgresql 139 [ + - ]: 2329 : LOOPBYTE(siglen)
140 : : {
5994 bruce@momjian.us 141 [ + + ]: 2329 : if ((sign[i] & 0xff) != 0xff)
142 : 2116 : PG_RETURN_POINTER(retval);
143 : : }
144 : :
1476 akorotkov@postgresql 145 :UBC 0 : res = gtrgm_alloc(true, siglen, sign);
7258 teodor@sigaev.ru 146 : 0 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
147 : 0 : gistentryinit(*retval, PointerGetDatum(res),
148 : : entry->rel, entry->page,
149 : : entry->offset, false);
150 : : }
7258 teodor@sigaev.ru 151 :CBC 23402 : PG_RETURN_POINTER(retval);
152 : : }
153 : :
154 : : Datum
155 : 1355149 : gtrgm_decompress(PG_FUNCTION_ARGS)
156 : : {
6218 tgl@sss.pgh.pa.us 157 : 1355149 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
158 : : GISTENTRY *retval;
159 : : text *key;
160 : :
2590 noah@leadboat.com 161 : 1355149 : key = DatumGetTextPP(entry->key);
162 : :
6218 tgl@sss.pgh.pa.us 163 [ - + ]: 1355149 : if (key != (text *) DatumGetPointer(entry->key))
164 : : {
165 : : /* need to pass back the decompressed item */
6218 tgl@sss.pgh.pa.us 166 :UBC 0 : retval = palloc(sizeof(GISTENTRY));
167 : 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 */
6218 tgl@sss.pgh.pa.us 174 :CBC 1355149 : PG_RETURN_POINTER(entry);
175 : : }
176 : : }
177 : :
178 : : static int32
1476 akorotkov@postgresql 179 : 649 : cnt_sml_sign_common(TRGM *qtrg, BITVECP sign, int siglen)
180 : : {
4311 peter_e@gmx.net 181 : 649 : int32 count = 0;
182 : : int32 k,
4880 tgl@sss.pgh.pa.us 183 : 649 : len = ARRNELEM(qtrg);
184 : 649 : trgm *ptr = GETARR(qtrg);
4311 peter_e@gmx.net 185 : 649 : int32 tmp = 0;
186 : :
4880 tgl@sss.pgh.pa.us 187 [ + + ]: 5967 : for (k = 0; k < len; k++)
188 : : {
189 : 5318 : CPTRGM(((char *) &tmp), ptr + k);
1476 akorotkov@postgresql 190 : 5318 : count += GETBIT(sign, HASHVAL(tmp, siglen));
191 : : }
192 : :
4880 tgl@sss.pgh.pa.us 193 : 649 : return count;
194 : : }
195 : :
196 : : Datum
7258 teodor@sigaev.ru 197 : 37714 : gtrgm_consistent(PG_FUNCTION_ARGS)
198 : : {
5844 tgl@sss.pgh.pa.us 199 : 37714 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
200 : 37714 : text *query = PG_GETARG_TEXT_P(1);
4880 201 : 37714 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
202 : :
203 : : /* Oid subtype = PG_GETARG_OID(3); */
5844 204 : 37714 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
1249 akorotkov@postgresql 205 [ + - ]: 37714 : int siglen = GET_SIGLEN();
5844 tgl@sss.pgh.pa.us 206 : 37714 : TRGM *key = (TRGM *) DatumGetPointer(entry->key);
207 : : TRGM *qtrg;
208 : : bool res;
4580 209 : 37714 : Size querysize = VARSIZE(query);
210 : : gtrgm_consistent_cache *cache;
211 : : double nlimit;
212 : :
213 : : /*
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.
218 : : *
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.)
226 : : */
4022 227 : 37714 : cache = (gtrgm_consistent_cache *) fcinfo->flinfo->fn_extra;
4580 228 [ + + ]: 37714 : if (cache == NULL ||
4022 229 [ + - ]: 37658 : cache->strategy != strategy ||
230 [ + - ]: 37658 : VARSIZE(cache->query) != querysize ||
231 [ - + ]: 37658 : memcmp((char *) cache->query, (char *) query, querysize) != 0)
232 : : {
233 : : gtrgm_consistent_cache *newcache;
234 : 56 : TrgmPackedGraph *graph = NULL;
235 : : Size qtrgsize;
236 : :
4822 237 [ + + + - ]: 56 : switch (strategy)
238 : : {
239 : 28 : case SimilarityStrategyNumber:
240 : : case WordSimilarityStrategyNumber:
241 : : case StrictWordSimilarityStrategyNumber:
242 : : case EqualStrategyNumber:
4580 243 : 28 : qtrg = generate_trgm(VARDATA(query),
244 : 28 : querysize - VARHDRSZ);
4822 245 : 28 : break;
246 : 7 : case ILikeStrategyNumber:
247 : : #ifndef IGNORECASE
248 : : elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
249 : : #endif
250 : : /* FALL THRU */
251 : : case LikeStrategyNumber:
4580 252 : 7 : qtrg = generate_wildcard_trgm(VARDATA(query),
253 : 7 : querysize - VARHDRSZ);
4822 254 : 7 : break;
4022 255 : 21 : case RegExpICaseStrategyNumber:
256 : : #ifndef IGNORECASE
257 : : elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
258 : : #endif
259 : : /* FALL THRU */
260 : : case RegExpStrategyNumber:
261 : 21 : qtrg = createTrgmNFA(query, PG_GET_COLLATION(),
262 : 21 : &graph, fcinfo->flinfo->fn_mcxt);
263 : : /* just in case an empty array is returned ... */
264 [ + + - + ]: 21 : if (qtrg && ARRNELEM(qtrg) <= 0)
265 : : {
4022 tgl@sss.pgh.pa.us 266 :UBC 0 : pfree(qtrg);
267 : 0 : qtrg = NULL;
268 : : }
4022 tgl@sss.pgh.pa.us 269 :CBC 21 : break;
4822 tgl@sss.pgh.pa.us 270 :UBC 0 : default:
271 [ # # ]: 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
272 : : qtrg = NULL; /* keep compiler quiet */
273 : : break;
274 : : }
275 : :
4022 tgl@sss.pgh.pa.us 276 [ + + ]:CBC 56 : qtrgsize = qtrg ? VARSIZE(qtrg) : 0;
277 : :
278 : : newcache = (gtrgm_consistent_cache *)
279 : 56 : MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
280 : : MAXALIGN(sizeof(gtrgm_consistent_cache)) +
281 : 56 : MAXALIGN(querysize) +
282 : : qtrgsize);
283 : :
284 : 56 : newcache->strategy = strategy;
285 : 56 : newcache->query = (text *)
286 : : ((char *) newcache + MAXALIGN(sizeof(gtrgm_consistent_cache)));
287 : 56 : memcpy((char *) newcache->query, (char *) query, querysize);
288 [ + + ]: 56 : if (qtrg)
289 : : {
290 : 52 : newcache->trigrams = (TRGM *)
291 : 52 : ((char *) newcache->query + MAXALIGN(querysize));
292 : 52 : memcpy((char *) newcache->trigrams, (char *) qtrg, qtrgsize);
293 : : /* release qtrg in case it was made in fn_mcxt */
294 : 52 : pfree(qtrg);
295 : : }
296 : : else
297 : 4 : newcache->trigrams = NULL;
298 : 56 : newcache->graph = graph;
299 : :
5756 teodor@sigaev.ru 300 [ - + ]: 56 : if (cache)
5756 teodor@sigaev.ru 301 :UBC 0 : pfree(cache);
4022 tgl@sss.pgh.pa.us 302 :CBC 56 : fcinfo->flinfo->fn_extra = (void *) newcache;
303 : 56 : cache = newcache;
304 : : }
305 : :
306 : 37714 : qtrg = cache->trigrams;
307 : :
4880 308 [ + + + - ]: 37714 : switch (strategy)
309 : : {
310 : 35309 : case SimilarityStrategyNumber:
311 : : case WordSimilarityStrategyNumber:
312 : : case StrictWordSimilarityStrategyNumber:
313 : :
314 : : /*
315 : : * Similarity search is exact. (Strict) word similarity search is
316 : : * inexact
317 : : */
2216 teodor@sigaev.ru 318 : 35309 : *recheck = (strategy != SimilarityStrategyNumber);
319 : :
320 : 35309 : nlimit = index_strategy_get_limit(strategy);
321 : :
4880 tgl@sss.pgh.pa.us 322 [ + + ]: 35309 : if (GIST_LEAF(entry))
323 : : { /* all leafs contains orig trgm */
2855 324 : 34698 : double tmpsml = cnt_sml(qtrg, key, *recheck);
325 : :
326 : 34698 : res = (tmpsml >= nlimit);
327 : : }
4880 328 [ - + ]: 611 : else if (ISALLTRUE(key))
329 : : { /* non-leaf contains signature */
4880 tgl@sss.pgh.pa.us 330 :UBC 0 : res = true;
331 : : }
332 : : else
333 : : { /* non-leaf contains signature */
1476 akorotkov@postgresql 334 :CBC 611 : int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
4311 peter_e@gmx.net 335 : 611 : int32 len = ARRNELEM(qtrg);
336 : :
4880 tgl@sss.pgh.pa.us 337 [ - + ]: 611 : if (len == 0)
4880 tgl@sss.pgh.pa.us 338 :UBC 0 : res = false;
339 : : else
2951 teodor@sigaev.ru 340 :CBC 611 : res = (((((float8) count) / ((float8) len))) >= nlimit);
341 : : }
4880 tgl@sss.pgh.pa.us 342 : 35309 : break;
4822 343 : 190 : case ILikeStrategyNumber:
344 : : #ifndef IGNORECASE
345 : : elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
346 : : #endif
347 : : /* FALL THRU */
348 : : case LikeStrategyNumber:
349 : : case EqualStrategyNumber:
350 : : /* Wildcard and equal search are inexact */
351 : 190 : *recheck = true;
352 : :
353 : : /*
354 : : * Check if all the extracted trigrams can be present in child
355 : : * nodes.
356 : : */
357 [ + - ]: 190 : if (GIST_LEAF(entry))
358 : : { /* all leafs contains orig trgm */
359 : 190 : res = trgm_contained_by(qtrg, key);
360 : : }
4822 tgl@sss.pgh.pa.us 361 [ # # ]:UBC 0 : else if (ISALLTRUE(key))
362 : : { /* non-leaf contains signature */
363 : 0 : res = true;
364 : : }
365 : : else
366 : : { /* non-leaf contains signature */
367 : : int32 k,
4753 bruce@momjian.us 368 : 0 : tmp = 0,
369 : 0 : len = ARRNELEM(qtrg);
370 : 0 : trgm *ptr = GETARR(qtrg);
371 : 0 : BITVECP sign = GETSIGN(key);
372 : :
4822 tgl@sss.pgh.pa.us 373 : 0 : res = true;
374 [ # # ]: 0 : for (k = 0; k < len; k++)
375 : : {
376 : 0 : CPTRGM(((char *) &tmp), ptr + k);
1476 akorotkov@postgresql 377 [ # # ]: 0 : if (!GETBIT(sign, HASHVAL(tmp, siglen)))
378 : : {
4822 tgl@sss.pgh.pa.us 379 : 0 : res = false;
380 : 0 : break;
381 : : }
382 : : }
383 : : }
4822 tgl@sss.pgh.pa.us 384 :CBC 190 : break;
4022 385 : 2215 : case RegExpICaseStrategyNumber:
386 : : #ifndef IGNORECASE
387 : : elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
388 : : #endif
389 : : /* FALL THRU */
390 : : case RegExpStrategyNumber:
391 : : /* Regexp search is inexact */
392 : 2215 : *recheck = true;
393 : :
394 : : /* Check regex match as much as we can with available info */
395 [ + + ]: 2215 : if (qtrg)
396 : : {
397 [ + + ]: 2175 : if (GIST_LEAF(entry))
398 : : { /* all leafs contains orig trgm */
399 : : bool *check;
400 : :
401 : 2150 : check = trgm_presence_map(qtrg, key);
402 : 2150 : res = trigramsMatchGraph(cache->graph, check);
403 : 2150 : pfree(check);
404 : : }
405 [ - + ]: 25 : else if (ISALLTRUE(key))
406 : : { /* non-leaf contains signature */
4022 tgl@sss.pgh.pa.us 407 :UBC 0 : res = true;
408 : : }
409 : : else
410 : : { /* non-leaf contains signature */
411 : : int32 k,
4022 tgl@sss.pgh.pa.us 412 :CBC 25 : tmp = 0,
413 : 25 : len = ARRNELEM(qtrg);
414 : 25 : trgm *ptr = GETARR(qtrg);
415 : 25 : BITVECP sign = GETSIGN(key);
416 : : bool *check;
417 : :
418 : : /*
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.
425 : : */
4017 426 : 25 : check = (bool *) palloc(len * sizeof(bool));
4022 427 [ + + ]: 6325 : for (k = 0; k < len; k++)
428 : : {
429 : 6300 : CPTRGM(((char *) &tmp), ptr + k);
1476 akorotkov@postgresql 430 : 6300 : check[k] = GETBIT(sign, HASHVAL(tmp, siglen));
431 : : }
4017 tgl@sss.pgh.pa.us 432 : 25 : res = trigramsMatchGraph(cache->graph, check);
433 : 25 : pfree(check);
434 : : }
435 : : }
436 : : else
437 : : {
438 : : /* trigram-free query must be rechecked everywhere */
4022 439 : 40 : res = true;
440 : : }
441 : 2215 : break;
4880 tgl@sss.pgh.pa.us 442 :UBC 0 : default:
443 [ # # ]: 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
444 : : res = false; /* keep compiler quiet */
445 : : break;
446 : : }
447 : :
4880 tgl@sss.pgh.pa.us 448 :CBC 37714 : PG_RETURN_BOOL(res);
449 : : }
450 : :
451 : : Datum
452 : 2882 : gtrgm_distance(PG_FUNCTION_ARGS)
453 : : {
454 : 2882 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
455 : 2882 : text *query = PG_GETARG_TEXT_P(1);
456 : 2882 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
457 : :
458 : : /* Oid subtype = PG_GETARG_OID(3); */
2951 teodor@sigaev.ru 459 : 2882 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
1249 akorotkov@postgresql 460 [ + - ]: 2882 : int siglen = GET_SIGLEN();
4880 tgl@sss.pgh.pa.us 461 : 2882 : TRGM *key = (TRGM *) DatumGetPointer(entry->key);
462 : : TRGM *qtrg;
463 : : float8 res;
4580 464 : 2882 : Size querysize = VARSIZE(query);
4880 465 : 2882 : char *cache = (char *) fcinfo->flinfo->fn_extra;
466 : :
467 : : /*
468 : : * Cache the generated trigrams across multiple calls with the same query.
469 : : */
4580 470 [ + + ]: 2882 : if (cache == NULL ||
471 [ + - ]: 2878 : VARSIZE(cache) != querysize ||
472 [ - + ]: 2878 : memcmp(cache, query, querysize) != 0)
473 : : {
474 : : char *newcache;
475 : :
476 : 4 : qtrg = generate_trgm(VARDATA(query), querysize - VARHDRSZ);
477 : :
478 : 4 : newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
479 : 4 : MAXALIGN(querysize) +
480 : 4 : VARSIZE(qtrg));
481 : :
482 : 4 : memcpy(newcache, query, querysize);
483 : 4 : memcpy(newcache + MAXALIGN(querysize), qtrg, VARSIZE(qtrg));
484 : :
485 [ - + ]: 4 : if (cache)
4580 tgl@sss.pgh.pa.us 486 :UBC 0 : pfree(cache);
4580 tgl@sss.pgh.pa.us 487 :CBC 4 : fcinfo->flinfo->fn_extra = newcache;
488 : 4 : cache = newcache;
489 : : }
490 : :
491 : 2882 : qtrg = (TRGM *) (cache + MAXALIGN(querysize));
492 : :
4880 493 [ + - ]: 2882 : switch (strategy)
494 : : {
495 : 2882 : case DistanceStrategyNumber:
496 : : case WordDistanceStrategyNumber:
497 : : case StrictWordDistanceStrategyNumber:
498 : : /* Only plain trigram distance is exact */
2216 teodor@sigaev.ru 499 : 2882 : *recheck = (strategy != DistanceStrategyNumber);
4880 tgl@sss.pgh.pa.us 500 [ + + ]: 2882 : if (GIST_LEAF(entry))
501 : : { /* all leafs contains orig trgm */
502 : :
503 : : /*
504 : : * Prevent gcc optimizing the sml variable using volatile
505 : : * keyword. Otherwise res can differ from the
506 : : * word_similarity_dist_op() function.
507 : : */
2951 teodor@sigaev.ru 508 : 2844 : float4 volatile sml = cnt_sml(qtrg, key, *recheck);
509 : :
510 : 2844 : res = 1.0 - sml;
511 : : }
4880 tgl@sss.pgh.pa.us 512 [ - + ]: 38 : else if (ISALLTRUE(key))
513 : : { /* all leafs contains orig trgm */
4880 tgl@sss.pgh.pa.us 514 :UBC 0 : res = 0.0;
515 : : }
516 : : else
517 : : { /* non-leaf contains signature */
1476 akorotkov@postgresql 518 :CBC 38 : int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
4311 peter_e@gmx.net 519 : 38 : int32 len = ARRNELEM(qtrg);
520 : :
4880 tgl@sss.pgh.pa.us 521 [ + - ]: 38 : res = (len == 0) ? -1.0 : 1.0 - ((float8) count) / ((float8) len);
522 : : }
523 : 2882 : break;
4880 tgl@sss.pgh.pa.us 524 :UBC 0 : default:
525 [ # # ]: 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
526 : : res = 0; /* keep compiler quiet */
527 : : break;
528 : : }
529 : :
4880 tgl@sss.pgh.pa.us 530 :CBC 2882 : PG_RETURN_FLOAT8(res);
531 : : }
532 : :
533 : : static int32
1476 akorotkov@postgresql 534 : 52116 : unionkey(BITVECP sbase, TRGM *add, int siglen)
535 : : {
536 : : int32 i;
537 : :
7258 teodor@sigaev.ru 538 [ + + ]: 52116 : if (ISSIGNKEY(add))
539 : : {
540 : 26058 : BITVECP sadd = GETSIGN(add);
541 : :
542 [ - + ]: 26058 : if (ISALLTRUE(add))
7258 teodor@sigaev.ru 543 :UBC 0 : return 1;
544 : :
1476 akorotkov@postgresql 545 [ + + ]:CBC 3451318 : LOOPBYTE(siglen)
5994 bruce@momjian.us 546 : 3425260 : sbase[i] |= sadd[i];
547 : : }
548 : : else
549 : : {
7258 teodor@sigaev.ru 550 : 26058 : trgm *ptr = GETARR(add);
4311 peter_e@gmx.net 551 : 26058 : int32 tmp = 0;
552 : :
7168 bruce@momjian.us 553 [ + + ]: 256068 : for (i = 0; i < ARRNELEM(add); i++)
554 : : {
555 : 230010 : CPTRGM(((char *) &tmp), ptr + i);
1476 akorotkov@postgresql 556 : 230010 : HASH(sbase, tmp, siglen);
557 : : }
558 : : }
7258 teodor@sigaev.ru 559 : 52116 : return 0;
560 : : }
561 : :
562 : :
563 : : Datum
564 : 26058 : gtrgm_union(PG_FUNCTION_ARGS)
565 : : {
7168 bruce@momjian.us 566 : 26058 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
4311 peter_e@gmx.net 567 : 26058 : int32 len = entryvec->n;
7258 teodor@sigaev.ru 568 : 26058 : int *size = (int *) PG_GETARG_POINTER(1);
1249 akorotkov@postgresql 569 [ + - ]: 26058 : int siglen = GET_SIGLEN();
570 : : int32 i;
1476 571 : 26058 : TRGM *result = gtrgm_alloc(false, siglen, NULL);
572 : 26058 : BITVECP base = GETSIGN(result);
573 : :
7258 teodor@sigaev.ru 574 [ + + ]: 78174 : for (i = 0; i < len; i++)
575 : : {
1476 akorotkov@postgresql 576 [ - + ]: 52116 : if (unionkey(base, GETENTRY(entryvec, i), siglen))
577 : : {
1476 akorotkov@postgresql 578 :UBC 0 : result->flag = ALLISTRUE;
579 : 0 : SET_VARSIZE(result, CALCGTSIZE(ALLISTRUE, siglen));
7258 teodor@sigaev.ru 580 : 0 : break;
581 : : }
582 : : }
583 : :
1476 akorotkov@postgresql 584 :CBC 26058 : *size = VARSIZE(result);
585 : :
7258 teodor@sigaev.ru 586 : 26058 : PG_RETURN_POINTER(result);
587 : : }
588 : :
589 : : Datum
590 : 26058 : gtrgm_same(PG_FUNCTION_ARGS)
591 : : {
7168 bruce@momjian.us 592 : 26058 : TRGM *a = (TRGM *) PG_GETARG_POINTER(0);
593 : 26058 : TRGM *b = (TRGM *) PG_GETARG_POINTER(1);
7258 teodor@sigaev.ru 594 : 26058 : bool *result = (bool *) PG_GETARG_POINTER(2);
1249 akorotkov@postgresql 595 [ + - ]: 26058 : int siglen = GET_SIGLEN();
596 : :
7258 teodor@sigaev.ru 597 [ + - ]: 26058 : if (ISSIGNKEY(a))
598 : : { /* then b also ISSIGNKEY */
599 [ - + - - ]: 26058 : if (ISALLTRUE(a) && ISALLTRUE(b))
7258 teodor@sigaev.ru 600 :UBC 0 : *result = true;
7258 teodor@sigaev.ru 601 [ - + ]:CBC 26058 : else if (ISALLTRUE(a))
7258 teodor@sigaev.ru 602 :UBC 0 : *result = false;
7258 teodor@sigaev.ru 603 [ - + ]:CBC 26058 : else if (ISALLTRUE(b))
7258 teodor@sigaev.ru 604 :UBC 0 : *result = false;
605 : : else
606 : : {
607 : : int32 i;
7258 teodor@sigaev.ru 608 :CBC 26058 : BITVECP sa = GETSIGN(a),
609 : 26058 : sb = GETSIGN(b);
610 : :
611 : 26058 : *result = true;
1476 akorotkov@postgresql 612 [ + + ]: 1748201 : LOOPBYTE(siglen)
613 : : {
5994 bruce@momjian.us 614 [ + + ]: 1723721 : if (sa[i] != sb[i])
615 : : {
616 : 1578 : *result = false;
617 : 1578 : break;
618 : : }
619 : : }
620 : : }
621 : : }
622 : : else
623 : : { /* a and b ISARRKEY */
4311 peter_e@gmx.net 624 :UBC 0 : int32 lena = ARRNELEM(a),
7258 teodor@sigaev.ru 625 : 0 : lenb = ARRNELEM(b);
626 : :
627 [ # # ]: 0 : if (lena != lenb)
628 : 0 : *result = false;
629 : : else
630 : : {
631 : 0 : trgm *ptra = GETARR(a),
632 : 0 : *ptrb = GETARR(b);
633 : : int32 i;
634 : :
635 : 0 : *result = true;
636 [ # # ]: 0 : for (i = 0; i < lena; i++)
7168 bruce@momjian.us 637 [ # # # # : 0 : if (CMPTRGM(ptra + i, ptrb + i))
# # ]
638 : : {
7258 teodor@sigaev.ru 639 : 0 : *result = false;
640 : 0 : break;
641 : : }
642 : : }
643 : : }
644 : :
7258 teodor@sigaev.ru 645 :CBC 26058 : PG_RETURN_POINTER(result);
646 : : }
647 : :
648 : : static int32
1476 akorotkov@postgresql 649 :UBC 0 : sizebitvec(BITVECP sign, int siglen)
650 : : {
651 : 0 : return pg_popcount(sign, siglen);
652 : : }
653 : :
654 : : static int
1476 akorotkov@postgresql 655 :CBC 4848126 : hemdistsign(BITVECP a, BITVECP b, int siglen)
656 : : {
657 : : int i,
658 : : diff,
7168 bruce@momjian.us 659 : 4848126 : dist = 0;
660 : :
1476 akorotkov@postgresql 661 [ + + ]: 215653946 : LOOPBYTE(siglen)
662 : : {
5994 bruce@momjian.us 663 : 210805820 : diff = (unsigned char) (a[i] ^ b[i]);
664 : : /* Using the popcount functions here isn't likely to win */
1885 tgl@sss.pgh.pa.us 665 : 210805820 : dist += pg_number_of_ones[diff];
666 : : }
7258 teodor@sigaev.ru 667 : 4848126 : return dist;
668 : : }
669 : :
670 : : static int
1476 akorotkov@postgresql 671 :UBC 0 : hemdist(TRGM *a, TRGM *b, int siglen)
672 : : {
7168 bruce@momjian.us 673 [ # # ]: 0 : if (ISALLTRUE(a))
674 : : {
7258 teodor@sigaev.ru 675 [ # # ]: 0 : if (ISALLTRUE(b))
676 : 0 : return 0;
677 : : else
1476 akorotkov@postgresql 678 : 0 : return SIGLENBIT(siglen) - sizebitvec(GETSIGN(b), siglen);
679 : : }
7168 bruce@momjian.us 680 [ # # ]: 0 : else if (ISALLTRUE(b))
1476 akorotkov@postgresql 681 : 0 : return SIGLENBIT(siglen) - sizebitvec(GETSIGN(a), siglen);
682 : :
683 : 0 : return hemdistsign(GETSIGN(a), GETSIGN(b), siglen);
684 : : }
685 : :
686 : : Datum
7258 teodor@sigaev.ru 687 :CBC 1193430 : gtrgm_penalty(PG_FUNCTION_ARGS)
688 : : {
689 : 1193430 : GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
690 : 1193430 : GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
691 : 1193430 : float *penalty = (float *) PG_GETARG_POINTER(2);
1249 akorotkov@postgresql 692 [ + - ]: 1193430 : int siglen = GET_SIGLEN();
7168 bruce@momjian.us 693 : 1193430 : TRGM *origval = (TRGM *) DatumGetPointer(origentry->key);
694 : 1193430 : TRGM *newval = (TRGM *) DatumGetPointer(newentry->key);
7258 teodor@sigaev.ru 695 : 1193430 : BITVECP orig = GETSIGN(origval);
696 : :
697 : 1193430 : *penalty = 0.0;
698 : :
7168 bruce@momjian.us 699 [ + - ]: 1193430 : if (ISARRKEY(newval))
700 : : {
4580 tgl@sss.pgh.pa.us 701 : 1193430 : char *cache = (char *) fcinfo->flinfo->fn_extra;
1476 akorotkov@postgresql 702 : 1193430 : TRGM *cachedVal = (TRGM *) (cache + MAXALIGN(siglen));
4580 tgl@sss.pgh.pa.us 703 : 1193430 : Size newvalsize = VARSIZE(newval);
704 : : BITVECP sign;
705 : :
706 : : /*
707 : : * Cache the sign data across multiple calls with the same newval.
708 : : */
709 [ + + ]: 1193430 : if (cache == NULL ||
710 [ + + ]: 1193425 : VARSIZE(cachedVal) != newvalsize ||
711 [ + + ]: 1192398 : memcmp(cachedVal, newval, newvalsize) != 0)
712 : : {
713 : : char *newcache;
714 : :
715 : 2886 : newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1476 akorotkov@postgresql 716 : 2886 : MAXALIGN(siglen) +
717 : : newvalsize);
718 : :
719 : 2886 : makesign((BITVECP) newcache, newval, siglen);
720 : :
721 : 2886 : cachedVal = (TRGM *) (newcache + MAXALIGN(siglen));
4580 tgl@sss.pgh.pa.us 722 : 2886 : memcpy(cachedVal, newval, newvalsize);
723 : :
724 [ + + ]: 2886 : if (cache)
725 : 2881 : pfree(cache);
726 : 2886 : fcinfo->flinfo->fn_extra = newcache;
727 : 2886 : cache = newcache;
728 : : }
729 : :
730 : 1193430 : sign = (BITVECP) cache;
731 : :
7168 bruce@momjian.us 732 [ - + ]: 1193430 : if (ISALLTRUE(origval))
1476 akorotkov@postgresql 733 :UBC 0 : *penalty = ((float) (SIGLENBIT(siglen) - sizebitvec(sign, siglen))) / (float) (SIGLENBIT(siglen) + 1);
734 : : else
1476 akorotkov@postgresql 735 :CBC 1193430 : *penalty = hemdistsign(sign, orig, siglen);
736 : : }
737 : : else
1476 akorotkov@postgresql 738 :UBC 0 : *penalty = hemdist(origval, newval, siglen);
7258 teodor@sigaev.ru 739 :CBC 1193430 : PG_RETURN_POINTER(penalty);
740 : : }
741 : :
742 : : typedef struct
743 : : {
744 : : bool allistrue;
745 : : BITVECP sign;
746 : : } CACHESIGN;
747 : :
748 : : static void
1476 akorotkov@postgresql 749 : 42949 : fillcache(CACHESIGN *item, TRGM *key, BITVECP sign, int siglen)
750 : : {
7258 teodor@sigaev.ru 751 : 42949 : item->allistrue = false;
1476 akorotkov@postgresql 752 : 42949 : item->sign = sign;
7258 teodor@sigaev.ru 753 [ + + ]: 42949 : if (ISARRKEY(key))
1476 akorotkov@postgresql 754 : 42729 : makesign(item->sign, key, siglen);
7258 teodor@sigaev.ru 755 [ - + ]: 220 : else if (ISALLTRUE(key))
7258 teodor@sigaev.ru 756 :UBC 0 : item->allistrue = true;
757 : : else
432 peter@eisentraut.org 758 :CBC 220 : memcpy(item->sign, GETSIGN(key), siglen);
7258 teodor@sigaev.ru 759 : 42949 : }
760 : :
761 : : #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
762 : : typedef struct
763 : : {
764 : : OffsetNumber pos;
765 : : int32 cost;
766 : : } SPLITCOST;
767 : :
768 : : static int
769 : 47650 : comparecost(const void *a, const void *b)
770 : : {
4599 peter_e@gmx.net 771 [ + + ]: 47650 : if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
7258 teodor@sigaev.ru 772 : 42981 : return 0;
773 : : else
4599 peter_e@gmx.net 774 [ + + ]: 4669 : return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
775 : : }
776 : :
777 : :
778 : : static int
1476 akorotkov@postgresql 779 : 3569874 : hemdistcache(CACHESIGN *a, CACHESIGN *b, int siglen)
780 : : {
7168 bruce@momjian.us 781 [ - + ]: 3569874 : if (a->allistrue)
782 : : {
7258 teodor@sigaev.ru 783 [ # # ]:UBC 0 : if (b->allistrue)
784 : 0 : return 0;
785 : : else
1476 akorotkov@postgresql 786 : 0 : return SIGLENBIT(siglen) - sizebitvec(b->sign, siglen);
787 : : }
7168 bruce@momjian.us 788 [ - + ]:CBC 3569874 : else if (b->allistrue)
1476 akorotkov@postgresql 789 :UBC 0 : return SIGLENBIT(siglen) - sizebitvec(a->sign, siglen);
790 : :
1476 akorotkov@postgresql 791 :CBC 3569874 : return hemdistsign(a->sign, b->sign, siglen);
792 : : }
793 : :
794 : : Datum
7258 teodor@sigaev.ru 795 : 269 : gtrgm_picksplit(PG_FUNCTION_ARGS)
796 : : {
7168 bruce@momjian.us 797 : 269 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
1249 rhodiumtoad@postgres 798 : 269 : OffsetNumber maxoff = entryvec->n - 1;
7258 teodor@sigaev.ru 799 : 269 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
1249 akorotkov@postgresql 800 [ + - ]: 269 : int siglen = GET_SIGLEN();
801 : : OffsetNumber k,
802 : : j;
803 : : TRGM *datum_l,
804 : : *datum_r;
805 : : BITVECP union_l,
806 : : union_r;
807 : : int32 size_alpha,
808 : : size_beta;
809 : : int32 size_waste,
7258 teodor@sigaev.ru 810 : 269 : waste = -1;
811 : : int32 nbytes;
812 : 269 : OffsetNumber seed_1 = 0,
813 : 269 : seed_2 = 0;
814 : : OffsetNumber *left,
815 : : *right;
816 : : BITVECP ptr;
817 : : int i;
818 : : CACHESIGN *cache;
819 : : char *cache_sign;
820 : : SPLITCOST *costvector;
821 : :
822 : : /* cache the sign data for each existing item */
1249 rhodiumtoad@postgres 823 : 269 : cache = (CACHESIGN *) palloc(sizeof(CACHESIGN) * (maxoff + 1));
824 : 269 : cache_sign = palloc(siglen * (maxoff + 1));
825 : :
4580 tgl@sss.pgh.pa.us 826 [ + + ]: 43218 : for (k = FirstOffsetNumber; k <= maxoff; k = OffsetNumberNext(k))
1476 akorotkov@postgresql 827 : 42949 : fillcache(&cache[k], GETENTRY(entryvec, k), &cache_sign[siglen * k],
828 : : siglen);
829 : :
830 : : /* now find the two furthest-apart items */
7168 bruce@momjian.us 831 [ + + ]: 42949 : for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
832 : : {
833 [ + + ]: 3526656 : for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
834 : : {
1476 akorotkov@postgresql 835 : 3483976 : size_waste = hemdistcache(&(cache[j]), &(cache[k]), siglen);
7168 bruce@momjian.us 836 [ + + ]: 3483976 : if (size_waste > waste)
837 : : {
7258 teodor@sigaev.ru 838 : 451 : waste = size_waste;
839 : 451 : seed_1 = k;
840 : 451 : seed_2 = j;
841 : : }
842 : : }
843 : : }
844 : :
845 : : /* just in case we didn't make a selection ... */
7168 bruce@momjian.us 846 [ + - - + ]: 269 : if (seed_1 == 0 || seed_2 == 0)
847 : : {
7258 teodor@sigaev.ru 848 :UBC 0 : seed_1 = 1;
849 : 0 : seed_2 = 2;
850 : : }
851 : :
852 : : /* initialize the result vectors */
1249 rhodiumtoad@postgres 853 :CBC 269 : nbytes = maxoff * sizeof(OffsetNumber);
4580 tgl@sss.pgh.pa.us 854 : 269 : v->spl_left = left = (OffsetNumber *) palloc(nbytes);
855 : 269 : v->spl_right = right = (OffsetNumber *) palloc(nbytes);
856 : 269 : v->spl_nleft = 0;
857 : 269 : v->spl_nright = 0;
858 : :
859 : : /* form initial .. */
1476 akorotkov@postgresql 860 : 269 : datum_l = gtrgm_alloc(cache[seed_1].allistrue, siglen, cache[seed_1].sign);
861 : 269 : datum_r = gtrgm_alloc(cache[seed_2].allistrue, siglen, cache[seed_2].sign);
862 : :
7168 bruce@momjian.us 863 : 269 : union_l = GETSIGN(datum_l);
864 : 269 : union_r = GETSIGN(datum_r);
865 : :
866 : : /* sort before ... */
7258 teodor@sigaev.ru 867 : 269 : costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
7168 bruce@momjian.us 868 [ + + ]: 43218 : for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
869 : : {
7258 teodor@sigaev.ru 870 : 42949 : costvector[j - 1].pos = j;
1476 akorotkov@postgresql 871 : 42949 : size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]), siglen);
872 : 42949 : size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]), siglen);
7258 teodor@sigaev.ru 873 : 42949 : costvector[j - 1].cost = abs(size_alpha - size_beta);
874 : : }
432 peter@eisentraut.org 875 : 269 : qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
876 : :
7168 bruce@momjian.us 877 [ + + ]: 43218 : for (k = 0; k < maxoff; k++)
878 : : {
7258 teodor@sigaev.ru 879 : 42949 : j = costvector[k].pos;
7168 bruce@momjian.us 880 [ + + ]: 42949 : if (j == seed_1)
881 : : {
7258 teodor@sigaev.ru 882 : 269 : *left++ = j;
883 : 269 : v->spl_nleft++;
884 : 269 : continue;
885 : : }
7168 bruce@momjian.us 886 [ + + ]: 42680 : else if (j == seed_2)
887 : : {
7258 teodor@sigaev.ru 888 : 269 : *right++ = j;
889 : 269 : v->spl_nright++;
890 : 269 : continue;
891 : : }
892 : :
7168 bruce@momjian.us 893 [ + - - + ]: 42411 : if (ISALLTRUE(datum_l) || cache[j].allistrue)
894 : : {
7168 bruce@momjian.us 895 [ # # # # ]:UBC 0 : if (ISALLTRUE(datum_l) && cache[j].allistrue)
896 : 0 : size_alpha = 0;
897 : : else
1476 akorotkov@postgresql 898 : 0 : size_alpha = SIGLENBIT(siglen) -
1536 alvherre@alvh.no-ip. 899 [ # # ]: 0 : sizebitvec((cache[j].allistrue) ? GETSIGN(datum_l) :
1476 akorotkov@postgresql 900 : 0 : GETSIGN(cache[j].sign),
901 : : siglen);
902 : : }
903 : : else
1476 akorotkov@postgresql 904 :CBC 42411 : size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l), siglen);
905 : :
7168 bruce@momjian.us 906 [ + - - + ]: 42411 : if (ISALLTRUE(datum_r) || cache[j].allistrue)
907 : : {
7168 bruce@momjian.us 908 [ # # # # ]:UBC 0 : if (ISALLTRUE(datum_r) && cache[j].allistrue)
909 : 0 : size_beta = 0;
910 : : else
1476 akorotkov@postgresql 911 : 0 : size_beta = SIGLENBIT(siglen) -
1536 alvherre@alvh.no-ip. 912 [ # # ]: 0 : sizebitvec((cache[j].allistrue) ? GETSIGN(datum_r) :
1476 akorotkov@postgresql 913 : 0 : GETSIGN(cache[j].sign),
914 : : siglen);
915 : : }
916 : : else
1476 akorotkov@postgresql 917 :CBC 42411 : size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r), siglen);
918 : :
7168 bruce@momjian.us 919 [ + + ]: 42411 : if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
920 : : {
921 [ + - - + ]: 21083 : if (ISALLTRUE(datum_l) || cache[j].allistrue)
922 : : {
7168 bruce@momjian.us 923 [ # # ]:UBC 0 : if (!ISALLTRUE(datum_l))
432 peter@eisentraut.org 924 : 0 : memset(GETSIGN(datum_l), 0xff, siglen);
925 : : }
926 : : else
927 : : {
7168 bruce@momjian.us 928 :CBC 21083 : ptr = cache[j].sign;
1476 akorotkov@postgresql 929 [ + + ]: 1384703 : LOOPBYTE(siglen)
5994 bruce@momjian.us 930 : 1363620 : union_l[i] |= ptr[i];
931 : : }
7258 teodor@sigaev.ru 932 : 21083 : *left++ = j;
933 : 21083 : v->spl_nleft++;
934 : : }
935 : : else
936 : : {
7168 bruce@momjian.us 937 [ + - - + ]: 21328 : if (ISALLTRUE(datum_r) || cache[j].allistrue)
938 : : {
7168 bruce@momjian.us 939 [ # # ]:UBC 0 : if (!ISALLTRUE(datum_r))
432 peter@eisentraut.org 940 : 0 : memset(GETSIGN(datum_r), 0xff, siglen);
941 : : }
942 : : else
943 : : {
7168 bruce@momjian.us 944 :CBC 21328 : ptr = cache[j].sign;
1476 akorotkov@postgresql 945 [ + + ]: 1373804 : LOOPBYTE(siglen)
5994 bruce@momjian.us 946 : 1352476 : union_r[i] |= ptr[i];
947 : : }
7258 teodor@sigaev.ru 948 : 21328 : *right++ = j;
949 : 21328 : v->spl_nright++;
950 : : }
951 : : }
952 : :
953 : 269 : v->spl_ldatum = PointerGetDatum(datum_l);
954 : 269 : v->spl_rdatum = PointerGetDatum(datum_r);
955 : :
956 : 269 : PG_RETURN_POINTER(v);
957 : : }
958 : :
959 : : Datum
1476 akorotkov@postgresql 960 : 22 : gtrgm_options(PG_FUNCTION_ARGS)
961 : : {
962 : 22 : local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
963 : :
964 : 22 : init_local_reloptions(relopts, sizeof(TrgmGistOptions));
965 : 22 : add_local_int_reloption(relopts, "siglen",
966 : : "signature length in bytes",
967 : : SIGLEN_DEFAULT, 1, SIGLEN_MAX,
968 : : offsetof(TrgmGistOptions, siglen));
969 : :
970 : 22 : PG_RETURN_VOID();
971 : : }
|