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