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 : :
7768 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);
5390 tgl@sss.pgh.pa.us 48 : 4 : PG_FUNCTION_INFO_V1(gtrgm_distance);
7768 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);
1986 akorotkov@postgresql 53 : 4 : PG_FUNCTION_INFO_V1(gtrgm_options);
54 : :
55 : :
56 : : Datum
7768 teodor@sigaev.ru 57 :UBC 0 : gtrgm_in(PG_FUNCTION_ARGS)
58 : : {
1001 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
7768 teodor@sigaev.ru 67 : 0 : gtrgm_out(PG_FUNCTION_ARGS)
68 : : {
1001 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 *
1986 akorotkov@postgresql 77 :CBC 28169 : gtrgm_alloc(bool isalltrue, int siglen, BITVECP sign)
78 : : {
79 [ - + ]: 28169 : int flag = SIGNKEY | (isalltrue ? ALLISTRUE : 0);
80 [ - + + - ]: 28169 : int size = CALCGTSIZE(flag, siglen);
81 : 28169 : TRGM *res = palloc(size);
82 : :
83 : 28169 : SET_VARSIZE(res, size);
84 : 28169 : res->flag = flag;
85 : :
86 [ + - ]: 28169 : if (!isalltrue)
87 : : {
88 [ + + ]: 28169 : if (sign)
89 : 558 : memcpy(GETSIGN(res), sign, siglen);
90 : : else
91 : 27611 : memset(GETSIGN(res), 0, siglen);
92 : : }
93 : :
94 : 28169 : return res;
95 : : }
96 : :
97 : : static void
98 : 47783 : makesign(BITVECP sign, TRGM *a, int siglen)
99 : : {
100 : : int32 k,
7768 teodor@sigaev.ru 101 : 47783 : len = ARRNELEM(a);
102 : 47783 : trgm *ptr = GETARR(a);
4821 peter_e@gmx.net 103 : 47783 : int32 tmp = 0;
104 : :
942 peter@eisentraut.org 105 [ + + + + : 47783 : MemSet(sign, 0, siglen);
+ - - + -
- ]
1986 akorotkov@postgresql 106 : 47783 : SETBIT(sign, SIGLENBIT(siglen)); /* set last unused bit */
7678 bruce@momjian.us 107 [ + + ]: 470066 : for (k = 0; k < len; k++)
108 : : {
198 peter@eisentraut.org 109 : 422283 : CPTRGM(&tmp, ptr + k);
1986 akorotkov@postgresql 110 : 422283 : HASH(sign, tmp, siglen);
111 : : }
7768 teodor@sigaev.ru 112 : 47783 : }
113 : :
114 : : Datum
115 : 27796 : gtrgm_compress(PG_FUNCTION_ARGS)
116 : : {
117 : 27796 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1759 akorotkov@postgresql 118 [ + - ]: 27796 : int siglen = GET_SIGLEN();
7768 teodor@sigaev.ru 119 : 27796 : GISTENTRY *retval = entry;
120 : :
121 [ + + ]: 27796 : if (entry->leafkey)
122 : : { /* trgm */
123 : : TRGM *res;
3100 noah@leadboat.com 124 : 24402 : text *val = DatumGetTextPP(entry->key);
125 : :
126 [ - + - - : 24402 : res = generate_trgm(VARDATA_ANY(val), VARSIZE_ANY_EXHDR(val));
- - - - +
- + - ]
7768 teodor@sigaev.ru 127 : 24402 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
128 : 24402 : gistentryinit(*retval, PointerGetDatum(res),
129 : : entry->rel, entry->page,
130 : : entry->offset, false);
131 : : }
132 [ + - ]: 3394 : else if (ISSIGNKEY(DatumGetPointer(entry->key)) &&
133 [ + - ]: 3394 : !ISALLTRUE(DatumGetPointer(entry->key)))
134 : : {
135 : : int32 i;
136 : : TRGM *res;
137 : 3394 : BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
138 : :
1986 akorotkov@postgresql 139 [ + - ]: 3584 : LOOPBYTE(siglen)
140 : : {
6504 bruce@momjian.us 141 [ + + ]: 3584 : if ((sign[i] & 0xff) != 0xff)
142 : 3394 : PG_RETURN_POINTER(retval);
143 : : }
144 : :
1986 akorotkov@postgresql 145 :UBC 0 : res = gtrgm_alloc(true, siglen, sign);
7768 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 : : }
7768 teodor@sigaev.ru 151 :CBC 24402 : PG_RETURN_POINTER(retval);
152 : : }
153 : :
154 : : Datum
155 : 1322074 : gtrgm_decompress(PG_FUNCTION_ARGS)
156 : : {
6728 tgl@sss.pgh.pa.us 157 : 1322074 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
158 : : GISTENTRY *retval;
159 : : text *key;
160 : :
3100 noah@leadboat.com 161 : 1322074 : key = DatumGetTextPP(entry->key);
162 : :
6728 tgl@sss.pgh.pa.us 163 [ - + ]: 1322074 : if (key != (text *) DatumGetPointer(entry->key))
164 : : {
165 : : /* need to pass back the decompressed item */
6728 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 */
6728 tgl@sss.pgh.pa.us 174 :CBC 1322074 : PG_RETURN_POINTER(entry);
175 : : }
176 : : }
177 : :
178 : : static int32
1986 akorotkov@postgresql 179 : 647 : cnt_sml_sign_common(TRGM *qtrg, BITVECP sign, int siglen)
180 : : {
4821 peter_e@gmx.net 181 : 647 : int32 count = 0;
182 : : int32 k,
5390 tgl@sss.pgh.pa.us 183 : 647 : len = ARRNELEM(qtrg);
184 : 647 : trgm *ptr = GETARR(qtrg);
4821 peter_e@gmx.net 185 : 647 : int32 tmp = 0;
186 : :
5390 tgl@sss.pgh.pa.us 187 [ + + ]: 5925 : for (k = 0; k < len; k++)
188 : : {
198 peter@eisentraut.org 189 : 5278 : CPTRGM(&tmp, ptr + k);
1986 akorotkov@postgresql 190 : 5278 : count += GETBIT(sign, HASHVAL(tmp, siglen));
191 : : }
192 : :
5390 tgl@sss.pgh.pa.us 193 : 647 : return count;
194 : : }
195 : :
196 : : Datum
7768 teodor@sigaev.ru 197 : 36446 : gtrgm_consistent(PG_FUNCTION_ARGS)
198 : : {
6354 tgl@sss.pgh.pa.us 199 : 36446 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
200 : 36446 : text *query = PG_GETARG_TEXT_P(1);
5390 201 : 36446 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
202 : :
203 : : /* Oid subtype = PG_GETARG_OID(3); */
6354 204 : 36446 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
1759 akorotkov@postgresql 205 [ + - ]: 36446 : int siglen = GET_SIGLEN();
6354 tgl@sss.pgh.pa.us 206 : 36446 : TRGM *key = (TRGM *) DatumGetPointer(entry->key);
207 : : TRGM *qtrg;
208 : : bool res;
5090 209 : 36446 : 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 : : */
4532 227 : 36446 : cache = (gtrgm_consistent_cache *) fcinfo->flinfo->fn_extra;
5090 228 [ + + ]: 36446 : if (cache == NULL ||
4532 229 [ + - + - ]: 72780 : cache->strategy != strategy ||
230 [ + - ]: 36390 : VARSIZE(cache->query) != querysize ||
206 peter@eisentraut.org 231 [ - + ]: 36390 : memcmp(cache->query, query, querysize) != 0)
232 : : {
233 : : gtrgm_consistent_cache *newcache;
4532 tgl@sss.pgh.pa.us 234 : 56 : TrgmPackedGraph *graph = NULL;
235 : : Size qtrgsize;
236 : :
5332 237 [ + + + - ]: 56 : switch (strategy)
238 : : {
239 : 28 : case SimilarityStrategyNumber:
240 : : case WordSimilarityStrategyNumber:
241 : : case StrictWordSimilarityStrategyNumber:
242 : : case EqualStrategyNumber:
5090 243 : 28 : qtrg = generate_trgm(VARDATA(query),
244 : 28 : querysize - VARHDRSZ);
5332 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:
5090 252 : 7 : qtrg = generate_wildcard_trgm(VARDATA(query),
253 : 7 : querysize - VARHDRSZ);
5332 254 : 7 : break;
4532 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 : : {
4532 tgl@sss.pgh.pa.us 266 :UBC 0 : pfree(qtrg);
267 : 0 : qtrg = NULL;
268 : : }
4532 tgl@sss.pgh.pa.us 269 :CBC 21 : break;
5332 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 : :
4532 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)));
206 peter@eisentraut.org 287 : 56 : memcpy(newcache->query, query, querysize);
4532 tgl@sss.pgh.pa.us 288 [ + + ]: 56 : if (qtrg)
289 : : {
290 : 52 : newcache->trigrams = (TRGM *)
291 : 52 : ((char *) newcache->query + MAXALIGN(querysize));
206 peter@eisentraut.org 292 : 52 : memcpy((char *) newcache->trigrams, qtrg, qtrgsize);
293 : : /* release qtrg in case it was made in fn_mcxt */
4532 tgl@sss.pgh.pa.us 294 : 52 : pfree(qtrg);
295 : : }
296 : : else
297 : 4 : newcache->trigrams = NULL;
298 : 56 : newcache->graph = graph;
299 : :
6266 teodor@sigaev.ru 300 [ - + ]: 56 : if (cache)
6266 teodor@sigaev.ru 301 :UBC 0 : pfree(cache);
282 peter@eisentraut.org 302 :CBC 56 : fcinfo->flinfo->fn_extra = newcache;
4532 tgl@sss.pgh.pa.us 303 : 56 : cache = newcache;
304 : : }
305 : :
306 : 36446 : qtrg = cache->trigrams;
307 : :
5390 308 [ + + + - ]: 36446 : switch (strategy)
309 : : {
310 : 34044 : case SimilarityStrategyNumber:
311 : : case WordSimilarityStrategyNumber:
312 : : case StrictWordSimilarityStrategyNumber:
313 : :
314 : : /*
315 : : * Similarity search is exact. (Strict) word similarity search is
316 : : * inexact
317 : : */
2726 teodor@sigaev.ru 318 : 34044 : *recheck = (strategy != SimilarityStrategyNumber);
319 : :
320 : 34044 : nlimit = index_strategy_get_limit(strategy);
321 : :
5390 tgl@sss.pgh.pa.us 322 [ + + ]: 34044 : if (GIST_LEAF(entry))
323 : : { /* all leafs contains orig trgm */
3365 324 : 33436 : double tmpsml = cnt_sml(qtrg, key, *recheck);
325 : :
326 : 33436 : res = (tmpsml >= nlimit);
327 : : }
5390 328 [ - + ]: 608 : else if (ISALLTRUE(key))
329 : : { /* non-leaf contains signature */
5390 tgl@sss.pgh.pa.us 330 :UBC 0 : res = true;
331 : : }
332 : : else
333 : : { /* non-leaf contains signature */
1986 akorotkov@postgresql 334 :CBC 608 : int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
4821 peter_e@gmx.net 335 : 608 : int32 len = ARRNELEM(qtrg);
336 : :
5390 tgl@sss.pgh.pa.us 337 [ - + ]: 608 : if (len == 0)
5390 tgl@sss.pgh.pa.us 338 :UBC 0 : res = false;
339 : : else
3461 teodor@sigaev.ru 340 :CBC 608 : res = (((((float8) count) / ((float8) len))) >= nlimit);
341 : : }
5390 tgl@sss.pgh.pa.us 342 : 34044 : break;
5332 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 : : }
5332 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,
5263 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 : :
5332 tgl@sss.pgh.pa.us 373 : 0 : res = true;
374 [ # # ]: 0 : for (k = 0; k < len; k++)
375 : : {
198 peter@eisentraut.org 376 : 0 : CPTRGM(&tmp, ptr + k);
1986 akorotkov@postgresql 377 [ # # ]: 0 : if (!GETBIT(sign, HASHVAL(tmp, siglen)))
378 : : {
5332 tgl@sss.pgh.pa.us 379 : 0 : res = false;
380 : 0 : break;
381 : : }
382 : : }
383 : : }
5332 tgl@sss.pgh.pa.us 384 :CBC 190 : break;
4532 385 : 2212 : 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 : 2212 : *recheck = true;
393 : :
394 : : /* Check regex match as much as we can with available info */
395 [ + + ]: 2212 : if (qtrg)
396 : : {
397 [ + + ]: 2172 : 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 [ - + ]: 22 : else if (ISALLTRUE(key))
406 : : { /* non-leaf contains signature */
4532 tgl@sss.pgh.pa.us 407 :UBC 0 : res = true;
408 : : }
409 : : else
410 : : { /* non-leaf contains signature */
411 : : int32 k,
4532 tgl@sss.pgh.pa.us 412 :CBC 22 : tmp = 0,
413 : 22 : len = ARRNELEM(qtrg);
414 : 22 : trgm *ptr = GETARR(qtrg);
415 : 22 : 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 : : */
4527 426 : 22 : check = (bool *) palloc(len * sizeof(bool));
4532 427 [ + + ]: 5566 : for (k = 0; k < len; k++)
428 : : {
198 peter@eisentraut.org 429 : 5544 : CPTRGM(&tmp, ptr + k);
1986 akorotkov@postgresql 430 : 5544 : check[k] = GETBIT(sign, HASHVAL(tmp, siglen));
431 : : }
4527 tgl@sss.pgh.pa.us 432 : 22 : res = trigramsMatchGraph(cache->graph, check);
433 : 22 : pfree(check);
434 : : }
435 : : }
436 : : else
437 : : {
438 : : /* trigram-free query must be rechecked everywhere */
4532 439 : 40 : res = true;
440 : : }
441 : 2212 : break;
5390 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 : :
5390 tgl@sss.pgh.pa.us 448 :CBC 36446 : PG_RETURN_BOOL(res);
449 : : }
450 : :
451 : : Datum
452 : 2970 : gtrgm_distance(PG_FUNCTION_ARGS)
453 : : {
454 : 2970 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
455 : 2970 : text *query = PG_GETARG_TEXT_P(1);
456 : 2970 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
457 : :
458 : : /* Oid subtype = PG_GETARG_OID(3); */
3461 teodor@sigaev.ru 459 : 2970 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
1759 akorotkov@postgresql 460 [ + - ]: 2970 : int siglen = GET_SIGLEN();
5390 tgl@sss.pgh.pa.us 461 : 2970 : TRGM *key = (TRGM *) DatumGetPointer(entry->key);
462 : : TRGM *qtrg;
463 : : float8 res;
5090 464 : 2970 : Size querysize = VARSIZE(query);
5390 465 : 2970 : char *cache = (char *) fcinfo->flinfo->fn_extra;
466 : :
467 : : /*
468 : : * Cache the generated trigrams across multiple calls with the same query.
469 : : */
5090 470 [ + + + - ]: 5936 : if (cache == NULL ||
471 [ + - ]: 2966 : VARSIZE(cache) != querysize ||
472 [ - + ]: 2966 : 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)
5090 tgl@sss.pgh.pa.us 486 :UBC 0 : pfree(cache);
5090 tgl@sss.pgh.pa.us 487 :CBC 4 : fcinfo->flinfo->fn_extra = newcache;
488 : 4 : cache = newcache;
489 : : }
490 : :
491 : 2970 : qtrg = (TRGM *) (cache + MAXALIGN(querysize));
492 : :
5390 493 [ + - ]: 2970 : switch (strategy)
494 : : {
495 : 2970 : case DistanceStrategyNumber:
496 : : case WordDistanceStrategyNumber:
497 : : case StrictWordDistanceStrategyNumber:
498 : : /* Only plain trigram distance is exact */
2726 teodor@sigaev.ru 499 : 2970 : *recheck = (strategy != DistanceStrategyNumber);
5390 tgl@sss.pgh.pa.us 500 [ + + ]: 2970 : 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 : : */
3461 teodor@sigaev.ru 508 : 2931 : float4 volatile sml = cnt_sml(qtrg, key, *recheck);
509 : :
510 : 2931 : res = 1.0 - sml;
511 : : }
5390 tgl@sss.pgh.pa.us 512 [ - + ]: 39 : else if (ISALLTRUE(key))
513 : : { /* all leafs contains orig trgm */
5390 tgl@sss.pgh.pa.us 514 :UBC 0 : res = 0.0;
515 : : }
516 : : else
517 : : { /* non-leaf contains signature */
1986 akorotkov@postgresql 518 :CBC 39 : int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
4821 peter_e@gmx.net 519 : 39 : int32 len = ARRNELEM(qtrg);
520 : :
5390 tgl@sss.pgh.pa.us 521 [ + - ]: 39 : res = (len == 0) ? -1.0 : 1.0 - ((float8) count) / ((float8) len);
522 : : }
523 : 2970 : break;
5390 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 : :
5390 tgl@sss.pgh.pa.us 530 :CBC 2970 : PG_RETURN_FLOAT8(res);
531 : : }
532 : :
533 : : static int32
1986 akorotkov@postgresql 534 : 55222 : unionkey(BITVECP sbase, TRGM *add, int siglen)
535 : : {
536 : : int32 i;
537 : :
7768 teodor@sigaev.ru 538 [ + + ]: 55222 : if (ISSIGNKEY(add))
539 : : {
540 : 27611 : BITVECP sadd = GETSIGN(add);
541 : :
542 [ - + ]: 27611 : if (ISALLTRUE(add))
7768 teodor@sigaev.ru 543 :UBC 0 : return 1;
544 : :
1986 akorotkov@postgresql 545 [ + + ]:CBC 6507615 : LOOPBYTE(siglen)
6504 bruce@momjian.us 546 : 6480004 : sbase[i] |= sadd[i];
547 : : }
548 : : else
549 : : {
7768 teodor@sigaev.ru 550 : 27611 : trgm *ptr = GETARR(add);
4821 peter_e@gmx.net 551 : 27611 : int32 tmp = 0;
552 : :
7678 bruce@momjian.us 553 [ + + ]: 276125 : for (i = 0; i < ARRNELEM(add); i++)
554 : : {
198 peter@eisentraut.org 555 : 248514 : CPTRGM(&tmp, ptr + i);
1986 akorotkov@postgresql 556 : 248514 : HASH(sbase, tmp, siglen);
557 : : }
558 : : }
7768 teodor@sigaev.ru 559 : 55222 : return 0;
560 : : }
561 : :
562 : :
563 : : Datum
564 : 27611 : gtrgm_union(PG_FUNCTION_ARGS)
565 : : {
7678 bruce@momjian.us 566 : 27611 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
4821 peter_e@gmx.net 567 : 27611 : int32 len = entryvec->n;
7768 teodor@sigaev.ru 568 : 27611 : int *size = (int *) PG_GETARG_POINTER(1);
1759 akorotkov@postgresql 569 [ + - ]: 27611 : int siglen = GET_SIGLEN();
570 : : int32 i;
1986 571 : 27611 : TRGM *result = gtrgm_alloc(false, siglen, NULL);
572 : 27611 : BITVECP base = GETSIGN(result);
573 : :
7768 teodor@sigaev.ru 574 [ + + ]: 82833 : for (i = 0; i < len; i++)
575 : : {
1986 akorotkov@postgresql 576 [ - + ]: 55222 : if (unionkey(base, GETENTRY(entryvec, i), siglen))
577 : : {
1986 akorotkov@postgresql 578 :UBC 0 : result->flag = ALLISTRUE;
579 : 0 : SET_VARSIZE(result, CALCGTSIZE(ALLISTRUE, siglen));
7768 teodor@sigaev.ru 580 : 0 : break;
581 : : }
582 : : }
583 : :
1986 akorotkov@postgresql 584 :CBC 27611 : *size = VARSIZE(result);
585 : :
7768 teodor@sigaev.ru 586 : 27611 : PG_RETURN_POINTER(result);
587 : : }
588 : :
589 : : Datum
590 : 27611 : gtrgm_same(PG_FUNCTION_ARGS)
591 : : {
7678 bruce@momjian.us 592 : 27611 : TRGM *a = (TRGM *) PG_GETARG_POINTER(0);
593 : 27611 : TRGM *b = (TRGM *) PG_GETARG_POINTER(1);
7768 teodor@sigaev.ru 594 : 27611 : bool *result = (bool *) PG_GETARG_POINTER(2);
1759 akorotkov@postgresql 595 [ + - ]: 27611 : int siglen = GET_SIGLEN();
596 : :
7768 teodor@sigaev.ru 597 [ + - ]: 27611 : if (ISSIGNKEY(a))
598 : : { /* then b also ISSIGNKEY */
599 [ - + - - ]: 27611 : if (ISALLTRUE(a) && ISALLTRUE(b))
7768 teodor@sigaev.ru 600 :UBC 0 : *result = true;
7768 teodor@sigaev.ru 601 [ - + ]:CBC 27611 : else if (ISALLTRUE(a))
7768 teodor@sigaev.ru 602 :UBC 0 : *result = false;
7768 teodor@sigaev.ru 603 [ - + ]:CBC 27611 : else if (ISALLTRUE(b))
7768 teodor@sigaev.ru 604 :UBC 0 : *result = false;
605 : : else
606 : : {
607 : : int32 i;
7768 teodor@sigaev.ru 608 :CBC 27611 : BITVECP sa = GETSIGN(a),
609 : 27611 : sb = GETSIGN(b);
610 : :
611 : 27611 : *result = true;
1986 akorotkov@postgresql 612 [ + + ]: 3149159 : LOOPBYTE(siglen)
613 : : {
6504 bruce@momjian.us 614 [ + + ]: 3124384 : if (sa[i] != sb[i])
615 : : {
616 : 2836 : *result = false;
617 : 2836 : break;
618 : : }
619 : : }
620 : : }
621 : : }
622 : : else
623 : : { /* a and b ISARRKEY */
4821 peter_e@gmx.net 624 :UBC 0 : int32 lena = ARRNELEM(a),
7768 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++)
7678 bruce@momjian.us 637 [ # # ]: 0 : if (CMPTRGM(ptra + i, ptrb + i))
638 : : {
7768 teodor@sigaev.ru 639 : 0 : *result = false;
640 : 0 : break;
641 : : }
642 : : }
643 : : }
644 : :
7768 teodor@sigaev.ru 645 :CBC 27611 : PG_RETURN_POINTER(result);
646 : : }
647 : :
648 : : static int32
1986 akorotkov@postgresql 649 :UBC 0 : sizebitvec(BITVECP sign, int siglen)
650 : : {
651 : 0 : return pg_popcount(sign, siglen);
652 : : }
653 : :
654 : : static int
1986 akorotkov@postgresql 655 :CBC 4898879 : hemdistsign(BITVECP a, BITVECP b, int siglen)
656 : : {
657 : : int i,
658 : : diff,
7678 bruce@momjian.us 659 : 4898879 : dist = 0;
660 : :
1986 akorotkov@postgresql 661 [ + + ]: 336615239 : LOOPBYTE(siglen)
662 : : {
6504 bruce@momjian.us 663 : 331716360 : diff = (unsigned char) (a[i] ^ b[i]);
664 : : /* Using the popcount functions here isn't likely to win */
2395 tgl@sss.pgh.pa.us 665 : 331716360 : dist += pg_number_of_ones[diff];
666 : : }
7768 teodor@sigaev.ru 667 : 4898879 : return dist;
668 : : }
669 : :
670 : : static int
1986 akorotkov@postgresql 671 :UBC 0 : hemdist(TRGM *a, TRGM *b, int siglen)
672 : : {
7678 bruce@momjian.us 673 [ # # ]: 0 : if (ISALLTRUE(a))
674 : : {
7768 teodor@sigaev.ru 675 [ # # ]: 0 : if (ISALLTRUE(b))
676 : 0 : return 0;
677 : : else
1986 akorotkov@postgresql 678 : 0 : return SIGLENBIT(siglen) - sizebitvec(GETSIGN(b), siglen);
679 : : }
7678 bruce@momjian.us 680 [ # # ]: 0 : else if (ISALLTRUE(b))
1986 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
7768 teodor@sigaev.ru 687 :CBC 1155585 : gtrgm_penalty(PG_FUNCTION_ARGS)
688 : : {
689 : 1155585 : GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
690 : 1155585 : GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
691 : 1155585 : float *penalty = (float *) PG_GETARG_POINTER(2);
1759 akorotkov@postgresql 692 [ + - ]: 1155585 : int siglen = GET_SIGLEN();
7678 bruce@momjian.us 693 : 1155585 : TRGM *origval = (TRGM *) DatumGetPointer(origentry->key);
694 : 1155585 : TRGM *newval = (TRGM *) DatumGetPointer(newentry->key);
7768 teodor@sigaev.ru 695 : 1155585 : BITVECP orig = GETSIGN(origval);
696 : :
697 : 1155585 : *penalty = 0.0;
698 : :
7678 bruce@momjian.us 699 [ + - ]: 1155585 : if (ISARRKEY(newval))
700 : : {
5090 tgl@sss.pgh.pa.us 701 : 1155585 : char *cache = (char *) fcinfo->flinfo->fn_extra;
1986 akorotkov@postgresql 702 : 1155585 : TRGM *cachedVal = (TRGM *) (cache + MAXALIGN(siglen));
5090 tgl@sss.pgh.pa.us 703 : 1155585 : Size newvalsize = VARSIZE(newval);
704 : : BITVECP sign;
705 : :
706 : : /*
707 : : * Cache the sign data across multiple calls with the same newval.
708 : : */
709 [ + + + + ]: 2311164 : if (cache == NULL ||
710 [ + + ]: 1155579 : VARSIZE(cachedVal) != newvalsize ||
711 [ + + ]: 1154552 : memcmp(cachedVal, newval, newvalsize) != 0)
712 : : {
713 : : char *newcache;
714 : :
715 : 3763 : newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1986 akorotkov@postgresql 716 : 3763 : MAXALIGN(siglen) +
717 : : newvalsize);
718 : :
719 : 3763 : makesign((BITVECP) newcache, newval, siglen);
720 : :
721 : 3763 : cachedVal = (TRGM *) (newcache + MAXALIGN(siglen));
5090 tgl@sss.pgh.pa.us 722 : 3763 : memcpy(cachedVal, newval, newvalsize);
723 : :
724 [ + + ]: 3763 : if (cache)
725 : 3757 : pfree(cache);
726 : 3763 : fcinfo->flinfo->fn_extra = newcache;
727 : 3763 : cache = newcache;
728 : : }
729 : :
730 : 1155585 : sign = (BITVECP) cache;
731 : :
7678 bruce@momjian.us 732 [ - + ]: 1155585 : if (ISALLTRUE(origval))
1986 akorotkov@postgresql 733 :UBC 0 : *penalty = ((float) (SIGLENBIT(siglen) - sizebitvec(sign, siglen))) / (float) (SIGLENBIT(siglen) + 1);
734 : : else
1986 akorotkov@postgresql 735 :CBC 1155585 : *penalty = hemdistsign(sign, orig, siglen);
736 : : }
737 : : else
1986 akorotkov@postgresql 738 :UBC 0 : *penalty = hemdist(origval, newval, siglen);
7768 teodor@sigaev.ru 739 :CBC 1155585 : PG_RETURN_POINTER(penalty);
740 : : }
741 : :
742 : : typedef struct
743 : : {
744 : : bool allistrue;
745 : : BITVECP sign;
746 : : } CACHESIGN;
747 : :
748 : : static void
1986 akorotkov@postgresql 749 : 44240 : fillcache(CACHESIGN *item, TRGM *key, BITVECP sign, int siglen)
750 : : {
7768 teodor@sigaev.ru 751 : 44240 : item->allistrue = false;
1986 akorotkov@postgresql 752 : 44240 : item->sign = sign;
7768 teodor@sigaev.ru 753 [ + + ]: 44240 : if (ISARRKEY(key))
1986 akorotkov@postgresql 754 : 44020 : makesign(item->sign, key, siglen);
7768 teodor@sigaev.ru 755 [ - + ]: 220 : else if (ISALLTRUE(key))
7768 teodor@sigaev.ru 756 :UBC 0 : item->allistrue = true;
757 : : else
942 peter@eisentraut.org 758 :CBC 220 : memcpy(item->sign, GETSIGN(key), siglen);
7768 teodor@sigaev.ru 759 : 44240 : }
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 : 49578 : comparecost(const void *a, const void *b)
770 : : {
5109 peter_e@gmx.net 771 [ + + ]: 49578 : if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
7768 teodor@sigaev.ru 772 : 44411 : return 0;
773 : : else
5109 peter_e@gmx.net 774 [ + + ]: 5167 : return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
775 : : }
776 : :
777 : :
778 : : static int
1986 akorotkov@postgresql 779 : 3655930 : hemdistcache(CACHESIGN *a, CACHESIGN *b, int siglen)
780 : : {
7678 bruce@momjian.us 781 [ - + ]: 3655930 : if (a->allistrue)
782 : : {
7768 teodor@sigaev.ru 783 [ # # ]:UBC 0 : if (b->allistrue)
784 : 0 : return 0;
785 : : else
1986 akorotkov@postgresql 786 : 0 : return SIGLENBIT(siglen) - sizebitvec(b->sign, siglen);
787 : : }
7678 bruce@momjian.us 788 [ - + ]:CBC 3655930 : else if (b->allistrue)
1986 akorotkov@postgresql 789 :UBC 0 : return SIGLENBIT(siglen) - sizebitvec(a->sign, siglen);
790 : :
1986 akorotkov@postgresql 791 :CBC 3655930 : return hemdistsign(a->sign, b->sign, siglen);
792 : : }
793 : :
794 : : Datum
7768 teodor@sigaev.ru 795 : 279 : gtrgm_picksplit(PG_FUNCTION_ARGS)
796 : : {
7678 bruce@momjian.us 797 : 279 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
1759 rhodiumtoad@postgres 798 : 279 : OffsetNumber maxoff = entryvec->n - 1;
7768 teodor@sigaev.ru 799 : 279 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
1759 akorotkov@postgresql 800 [ + - ]: 279 : 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,
7768 teodor@sigaev.ru 810 : 279 : waste = -1;
811 : : int32 nbytes;
812 : 279 : OffsetNumber seed_1 = 0,
813 : 279 : 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 */
1759 rhodiumtoad@postgres 823 : 279 : cache = (CACHESIGN *) palloc(sizeof(CACHESIGN) * (maxoff + 1));
824 : 279 : cache_sign = palloc(siglen * (maxoff + 1));
825 : :
5090 tgl@sss.pgh.pa.us 826 [ + + ]: 44519 : for (k = FirstOffsetNumber; k <= maxoff; k = OffsetNumberNext(k))
1986 akorotkov@postgresql 827 : 44240 : fillcache(&cache[k], GETENTRY(entryvec, k), &cache_sign[siglen * k],
828 : : siglen);
829 : :
830 : : /* now find the two furthest-apart items */
7678 bruce@momjian.us 831 [ + + ]: 44240 : for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
832 : : {
833 [ + + ]: 3611411 : for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
834 : : {
1986 akorotkov@postgresql 835 : 3567450 : size_waste = hemdistcache(&(cache[j]), &(cache[k]), siglen);
7678 bruce@momjian.us 836 [ + + ]: 3567450 : if (size_waste > waste)
837 : : {
7768 teodor@sigaev.ru 838 : 480 : waste = size_waste;
839 : 480 : seed_1 = k;
840 : 480 : seed_2 = j;
841 : : }
842 : : }
843 : : }
844 : :
845 : : /* just in case we didn't make a selection ... */
7678 bruce@momjian.us 846 [ + - - + ]: 279 : if (seed_1 == 0 || seed_2 == 0)
847 : : {
7768 teodor@sigaev.ru 848 :UBC 0 : seed_1 = 1;
849 : 0 : seed_2 = 2;
850 : : }
851 : :
852 : : /* initialize the result vectors */
1759 rhodiumtoad@postgres 853 :CBC 279 : nbytes = maxoff * sizeof(OffsetNumber);
5090 tgl@sss.pgh.pa.us 854 : 279 : v->spl_left = left = (OffsetNumber *) palloc(nbytes);
855 : 279 : v->spl_right = right = (OffsetNumber *) palloc(nbytes);
856 : 279 : v->spl_nleft = 0;
857 : 279 : v->spl_nright = 0;
858 : :
859 : : /* form initial .. */
1986 akorotkov@postgresql 860 : 279 : datum_l = gtrgm_alloc(cache[seed_1].allistrue, siglen, cache[seed_1].sign);
861 : 279 : datum_r = gtrgm_alloc(cache[seed_2].allistrue, siglen, cache[seed_2].sign);
862 : :
7678 bruce@momjian.us 863 : 279 : union_l = GETSIGN(datum_l);
864 : 279 : union_r = GETSIGN(datum_r);
865 : :
866 : : /* sort before ... */
7768 teodor@sigaev.ru 867 : 279 : costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
7678 bruce@momjian.us 868 [ + + ]: 44519 : for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
869 : : {
7768 teodor@sigaev.ru 870 : 44240 : costvector[j - 1].pos = j;
1986 akorotkov@postgresql 871 : 44240 : size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]), siglen);
872 : 44240 : size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]), siglen);
7768 teodor@sigaev.ru 873 : 44240 : costvector[j - 1].cost = abs(size_alpha - size_beta);
874 : : }
942 peter@eisentraut.org 875 : 279 : qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
876 : :
7678 bruce@momjian.us 877 [ + + ]: 44519 : for (k = 0; k < maxoff; k++)
878 : : {
7768 teodor@sigaev.ru 879 : 44240 : j = costvector[k].pos;
7678 bruce@momjian.us 880 [ + + ]: 44240 : if (j == seed_1)
881 : : {
7768 teodor@sigaev.ru 882 : 279 : *left++ = j;
883 : 279 : v->spl_nleft++;
884 : 279 : continue;
885 : : }
7678 bruce@momjian.us 886 [ + + ]: 43961 : else if (j == seed_2)
887 : : {
7768 teodor@sigaev.ru 888 : 279 : *right++ = j;
889 : 279 : v->spl_nright++;
890 : 279 : continue;
891 : : }
892 : :
7678 bruce@momjian.us 893 [ + - - + ]: 43682 : if (ISALLTRUE(datum_l) || cache[j].allistrue)
894 : : {
7678 bruce@momjian.us 895 [ # # # # ]:UBC 0 : if (ISALLTRUE(datum_l) && cache[j].allistrue)
896 : 0 : size_alpha = 0;
897 : : else
1986 akorotkov@postgresql 898 : 0 : size_alpha = SIGLENBIT(siglen) -
2046 alvherre@alvh.no-ip. 899 [ # # ]: 0 : sizebitvec((cache[j].allistrue) ? GETSIGN(datum_l) :
1986 akorotkov@postgresql 900 : 0 : GETSIGN(cache[j].sign),
901 : : siglen);
902 : : }
903 : : else
1986 akorotkov@postgresql 904 :CBC 43682 : size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l), siglen);
905 : :
7678 bruce@momjian.us 906 [ + - - + ]: 43682 : if (ISALLTRUE(datum_r) || cache[j].allistrue)
907 : : {
7678 bruce@momjian.us 908 [ # # # # ]:UBC 0 : if (ISALLTRUE(datum_r) && cache[j].allistrue)
909 : 0 : size_beta = 0;
910 : : else
1986 akorotkov@postgresql 911 : 0 : size_beta = SIGLENBIT(siglen) -
2046 alvherre@alvh.no-ip. 912 [ # # ]: 0 : sizebitvec((cache[j].allistrue) ? GETSIGN(datum_r) :
1986 akorotkov@postgresql 913 : 0 : GETSIGN(cache[j].sign),
914 : : siglen);
915 : : }
916 : : else
1986 akorotkov@postgresql 917 :CBC 43682 : size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r), siglen);
918 : :
7678 bruce@momjian.us 919 [ + + ]: 43682 : if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
920 : : {
921 [ + - - + ]: 21721 : if (ISALLTRUE(datum_l) || cache[j].allistrue)
922 : : {
7678 bruce@momjian.us 923 [ # # ]:UBC 0 : if (!ISALLTRUE(datum_l))
942 peter@eisentraut.org 924 : 0 : memset(GETSIGN(datum_l), 0xff, siglen);
925 : : }
926 : : else
927 : : {
7678 bruce@momjian.us 928 :CBC 21721 : ptr = cache[j].sign;
1986 akorotkov@postgresql 929 [ + + ]: 2250109 : LOOPBYTE(siglen)
6504 bruce@momjian.us 930 : 2228388 : union_l[i] |= ptr[i];
931 : : }
7768 teodor@sigaev.ru 932 : 21721 : *left++ = j;
933 : 21721 : v->spl_nleft++;
934 : : }
935 : : else
936 : : {
7678 bruce@momjian.us 937 [ + - - + ]: 21961 : if (ISALLTRUE(datum_r) || cache[j].allistrue)
938 : : {
7678 bruce@momjian.us 939 [ # # ]:UBC 0 : if (!ISALLTRUE(datum_r))
942 peter@eisentraut.org 940 : 0 : memset(GETSIGN(datum_r), 0xff, siglen);
941 : : }
942 : : else
943 : : {
7678 bruce@momjian.us 944 :CBC 21961 : ptr = cache[j].sign;
1986 akorotkov@postgresql 945 [ + + ]: 2229085 : LOOPBYTE(siglen)
6504 bruce@momjian.us 946 : 2207124 : union_r[i] |= ptr[i];
947 : : }
7768 teodor@sigaev.ru 948 : 21961 : *right++ = j;
949 : 21961 : v->spl_nright++;
950 : : }
951 : : }
952 : :
953 : 279 : v->spl_ldatum = PointerGetDatum(datum_l);
954 : 279 : v->spl_rdatum = PointerGetDatum(datum_r);
955 : :
956 : 279 : PG_RETURN_POINTER(v);
957 : : }
958 : :
959 : : Datum
1986 akorotkov@postgresql 960 : 28 : gtrgm_options(PG_FUNCTION_ARGS)
961 : : {
962 : 28 : local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
963 : :
964 : 28 : init_local_reloptions(relopts, sizeof(TrgmGistOptions));
965 : 28 : add_local_int_reloption(relopts, "siglen",
966 : : "signature length in bytes",
967 : : SIGLEN_DEFAULT, 1, SIGLEN_MAX,
968 : : offsetof(TrgmGistOptions, siglen));
969 : :
970 : 28 : PG_RETURN_VOID();
971 : : }
|