Branch data Line data Source code
1 : : /*
2 : : * contrib/pg_trgm/trgm_gist.c
3 : : */
4 : : #include "postgres.h"
5 : :
6 : : #include "trgm.h"
7 : :
8 : : #include "access/skey.h"
9 : :
10 : :
11 : 1 : PG_FUNCTION_INFO_V1(gtrgm_in);
12 : : Datum gtrgm_in(PG_FUNCTION_ARGS);
13 : :
14 : 1 : PG_FUNCTION_INFO_V1(gtrgm_out);
15 : : Datum gtrgm_out(PG_FUNCTION_ARGS);
16 : :
17 : 2 : PG_FUNCTION_INFO_V1(gtrgm_compress);
18 : : Datum gtrgm_compress(PG_FUNCTION_ARGS);
19 : :
20 : 2 : PG_FUNCTION_INFO_V1(gtrgm_decompress);
21 : : Datum gtrgm_decompress(PG_FUNCTION_ARGS);
22 : :
23 : 2 : PG_FUNCTION_INFO_V1(gtrgm_consistent);
24 : : Datum gtrgm_consistent(PG_FUNCTION_ARGS);
25 : :
26 : 2 : PG_FUNCTION_INFO_V1(gtrgm_distance);
27 : : Datum gtrgm_distance(PG_FUNCTION_ARGS);
28 : :
29 : 2 : PG_FUNCTION_INFO_V1(gtrgm_union);
30 : : Datum gtrgm_union(PG_FUNCTION_ARGS);
31 : :
32 : 2 : PG_FUNCTION_INFO_V1(gtrgm_same);
33 : : Datum gtrgm_same(PG_FUNCTION_ARGS);
34 : :
35 : 2 : PG_FUNCTION_INFO_V1(gtrgm_penalty);
36 : : Datum gtrgm_penalty(PG_FUNCTION_ARGS);
37 : :
38 : 2 : PG_FUNCTION_INFO_V1(gtrgm_picksplit);
39 : : Datum gtrgm_picksplit(PG_FUNCTION_ARGS);
40 : :
41 : : #define GETENTRY(vec,pos) ((TRGM *) DatumGetPointer((vec)->vector[(pos)].key))
42 : :
43 : : /* Number of one-bits in an unsigned byte */
44 : : static const uint8 number_of_ones[256] = {
45 : : 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
46 : : 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
47 : : 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
48 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
49 : : 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
50 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
51 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
52 : : 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
53 : : 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
54 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
55 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
56 : : 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
57 : : 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
58 : : 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
59 : : 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
60 : : 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
61 : : };
62 : :
63 : :
64 : : Datum
65 : 0 : gtrgm_in(PG_FUNCTION_ARGS)
66 : : {
67 : 0 : elog(ERROR, "not implemented");
68 : : PG_RETURN_DATUM(0);
69 : : }
70 : :
71 : : Datum
72 : 0 : gtrgm_out(PG_FUNCTION_ARGS)
73 : : {
74 : 0 : elog(ERROR, "not implemented");
75 : : PG_RETURN_DATUM(0);
76 : : }
77 : :
78 : : static void
79 : 1984 : makesign(BITVECP sign, TRGM *a)
80 : : {
81 : : int32 k,
82 : 1984 : len = ARRNELEM(a);
83 : 1984 : trgm *ptr = GETARR(a);
84 : 1984 : int32 tmp = 0;
85 : :
86 : 1984 : MemSet((void *) sign, 0, sizeof(BITVEC));
87 : 1984 : SETBIT(sign, SIGLENBIT); /* set last unused bit */
88 [ + + ]: 25792 : for (k = 0; k < len; k++)
89 : : {
90 : 23808 : CPTRGM(((char *) &tmp), ptr + k);
91 : 23808 : HASH(sign, tmp);
92 : : }
93 : 1984 : }
94 : :
95 : : Datum
96 : 1222 : gtrgm_compress(PG_FUNCTION_ARGS)
97 : : {
98 : 1222 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
99 : 1222 : GISTENTRY *retval = entry;
100 : :
101 [ + + ]: 1222 : if (entry->leafkey)
102 : : { /* trgm */
103 : : TRGM *res;
104 : 1002 : text *val = DatumGetTextP(entry->key);
105 : :
106 : 1002 : res = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ);
107 : 1002 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
108 : 1002 : gistentryinit(*retval, PointerGetDatum(res),
109 : : entry->rel, entry->page,
110 : : entry->offset, FALSE);
111 : : }
112 [ + - ]: 220 : else if (ISSIGNKEY(DatumGetPointer(entry->key)) &&
113 : : !ISALLTRUE(DatumGetPointer(entry->key)))
114 : : {
115 : : int32 i,
116 : : len;
117 : : TRGM *res;
118 : 220 : BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
119 : :
120 [ + - ]: 235 : LOOPBYTE
121 : : {
122 [ + + ]: 235 : if ((sign[i] & 0xff) != 0xff)
123 : : PG_RETURN_POINTER(retval);
124 : : }
125 : :
126 : 0 : len = CALCGTSIZE(SIGNKEY | ALLISTRUE, 0);
127 : 0 : res = (TRGM *) palloc(len);
128 : 0 : SET_VARSIZE(res, len);
129 : 0 : res->flag = SIGNKEY | ALLISTRUE;
130 : :
131 : 0 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
132 : 0 : gistentryinit(*retval, PointerGetDatum(res),
133 : : entry->rel, entry->page,
134 : : entry->offset, FALSE);
135 : : }
136 : 1222 : PG_RETURN_POINTER(retval);
137 : : }
138 : :
139 : : Datum
140 : 12697 : gtrgm_decompress(PG_FUNCTION_ARGS)
141 : : {
142 : 12697 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
143 : : GISTENTRY *retval;
144 : : text *key;
145 : :
146 : 12697 : key = DatumGetTextP(entry->key);
147 : :
148 [ - + ]: 12697 : if (key != (text *) DatumGetPointer(entry->key))
149 : : {
150 : : /* need to pass back the decompressed item */
151 : 0 : retval = palloc(sizeof(GISTENTRY));
152 : 0 : gistentryinit(*retval, PointerGetDatum(key),
153 : : entry->rel, entry->page, entry->offset, entry->leafkey);
154 : 12697 : PG_RETURN_POINTER(retval);
155 : : }
156 : : else
157 : : {
158 : : /* we can return the entry as-is */
159 : : PG_RETURN_POINTER(entry);
160 : : }
161 : : }
162 : :
163 : : static int32
164 : 40 : cnt_sml_sign_common(TRGM *qtrg, BITVECP sign)
165 : : {
166 : 40 : int32 count = 0;
167 : : int32 k,
168 : 40 : len = ARRNELEM(qtrg);
169 : 40 : trgm *ptr = GETARR(qtrg);
170 : 40 : int32 tmp = 0;
171 : :
172 [ + + ]: 550 : for (k = 0; k < len; k++)
173 : : {
174 : 510 : CPTRGM(((char *) &tmp), ptr + k);
175 : 510 : count += GETBIT(sign, HASHVAL(tmp));
176 : : }
177 : :
178 : 40 : return count;
179 : : }
180 : :
181 : : Datum
182 : 3040 : gtrgm_consistent(PG_FUNCTION_ARGS)
183 : : {
184 : 3040 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
185 : 3040 : text *query = PG_GETARG_TEXT_P(1);
186 : 3040 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
187 : :
188 : : /* Oid subtype = PG_GETARG_OID(3); */
189 : 3040 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
190 : 3040 : TRGM *key = (TRGM *) DatumGetPointer(entry->key);
191 : : TRGM *qtrg;
192 : : bool res;
193 : 3040 : Size querysize = VARSIZE(query);
194 : 3040 : char *cache = (char *) fcinfo->flinfo->fn_extra,
195 : 3040 : *cachedQuery = cache + MAXALIGN(sizeof(StrategyNumber));
196 : :
197 : : /*
198 : : * Store both the strategy number and extracted trigrams in cache, because
199 : : * trigram extraction is relatively CPU-expensive. We must include
200 : : * strategy number because trigram extraction depends on strategy.
201 : : *
202 : : * The cached structure contains the strategy number, then the input query
203 : : * (starting at a MAXALIGN boundary), then the TRGM value (also starting
204 : : * at a MAXALIGN boundary).
205 : : */
206 [ + + ][ + - ]: 3040 : if (cache == NULL ||
207 [ + - ]: 3032 : strategy != *((StrategyNumber *) cache) ||
208 [ - + ]: 3032 : VARSIZE(cachedQuery) != querysize ||
209 : 3032 : memcmp(cachedQuery, query, querysize) != 0)
210 : : {
211 : : char *newcache;
212 : :
213 [ + + - ]: 8 : switch (strategy)
214 : : {
215 : : case SimilarityStrategyNumber:
216 : 3 : qtrg = generate_trgm(VARDATA(query),
217 : : querysize - VARHDRSZ);
218 : 3 : break;
219 : : case ILikeStrategyNumber:
220 : : #ifndef IGNORECASE
221 : : elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
222 : : #endif
223 : : /* FALL THRU */
224 : : case LikeStrategyNumber:
225 : 5 : qtrg = generate_wildcard_trgm(VARDATA(query),
226 : : querysize - VARHDRSZ);
227 : 5 : break;
228 : : default:
229 : 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
230 : : qtrg = NULL; /* keep compiler quiet */
231 : : break;
232 : : }
233 : :
234 : 8 : newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
235 : : MAXALIGN(sizeof(StrategyNumber)) +
236 : 16 : MAXALIGN(querysize) +
237 : 8 : VARSIZE(qtrg));
238 : 8 : cachedQuery = newcache + MAXALIGN(sizeof(StrategyNumber));
239 : :
240 : 8 : *((StrategyNumber *) newcache) = strategy;
241 : 8 : memcpy(cachedQuery, query, querysize);
242 : 8 : memcpy(cachedQuery + MAXALIGN(querysize), qtrg, VARSIZE(qtrg));
243 : :
244 [ - + ]: 8 : if (cache)
245 : 0 : pfree(cache);
246 : 8 : fcinfo->flinfo->fn_extra = newcache;
247 : : }
248 : :
249 : 3040 : qtrg = (TRGM *) (cachedQuery + MAXALIGN(querysize));
250 : :
251 [ + + - ]: 3040 : switch (strategy)
252 : : {
253 : : case SimilarityStrategyNumber:
254 : : /* Similarity search is exact */
255 : 3030 : *recheck = false;
256 : :
257 [ + - ][ - + ]: 3030 : if (GIST_LEAF(entry))
[ + + ]
258 : : { /* all leafs contains orig trgm */
259 : 3000 : float4 tmpsml = cnt_sml(key, qtrg);
260 : :
261 : : /* strange bug at freebsd 5.2.1 and gcc 3.3.3 */
262 [ + - ][ + + ]: 3000 : res = (*(int *) &tmpsml == *(int *) &trgm_limit || tmpsml > trgm_limit) ? true : false;
263 : : }
264 [ + - ]: 30 : else if (ISALLTRUE(key))
265 : : { /* non-leaf contains signature */
266 : : res = true;
267 : : }
268 : : else
269 : : { /* non-leaf contains signature */
270 : 30 : int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key));
271 : 30 : int32 len = ARRNELEM(qtrg);
272 : :
273 [ + - ]: 30 : if (len == 0)
274 : : res = false;
275 : : else
276 : 30 : res = (((((float8) count) / ((float8) len))) >= trgm_limit) ? true : false;
277 : : }
278 : : break;
279 : : case ILikeStrategyNumber:
280 : : #ifndef IGNORECASE
281 : : elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
282 : : #endif
283 : : /* FALL THRU */
284 : : case LikeStrategyNumber:
285 : : /* Wildcard search is inexact */
286 : 10 : *recheck = true;
287 : :
288 : : /*
289 : : * Check if all the extracted trigrams can be present in child
290 : : * nodes.
291 : : */
292 [ + - ][ - + ]: 10 : if (GIST_LEAF(entry))
[ + - ]
293 : : { /* all leafs contains orig trgm */
294 : 10 : res = trgm_contained_by(qtrg, key);
295 : : }
296 [ # # ]: 0 : else if (ISALLTRUE(key))
297 : : { /* non-leaf contains signature */
298 : : res = true;
299 : : }
300 : : else
301 : : { /* non-leaf contains signature */
302 : : int32 k,
303 : 0 : tmp = 0,
304 : 0 : len = ARRNELEM(qtrg);
305 : 0 : trgm *ptr = GETARR(qtrg);
306 : 0 : BITVECP sign = GETSIGN(key);
307 : :
308 : 0 : res = true;
309 [ # # ]: 0 : for (k = 0; k < len; k++)
310 : : {
311 : 0 : CPTRGM(((char *) &tmp), ptr + k);
312 [ # # ]: 0 : if (!GETBIT(sign, HASHVAL(tmp)))
313 : : {
314 : : res = false;
315 : : break;
316 : : }
317 : : }
318 : : }
319 : : break;
320 : : default:
321 : 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
322 : : res = false; /* keep compiler quiet */
323 : : break;
324 : : }
325 : :
326 [ + + ]: 3040 : PG_RETURN_BOOL(res);
327 : : }
328 : :
329 : : Datum
330 : 1010 : gtrgm_distance(PG_FUNCTION_ARGS)
331 : : {
332 : 1010 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
333 : 1010 : text *query = PG_GETARG_TEXT_P(1);
334 : 1010 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
335 : :
336 : : /* Oid subtype = PG_GETARG_OID(3); */
337 : 1010 : TRGM *key = (TRGM *) DatumGetPointer(entry->key);
338 : : TRGM *qtrg;
339 : : float8 res;
340 : 1010 : Size querysize = VARSIZE(query);
341 : 1010 : char *cache = (char *) fcinfo->flinfo->fn_extra;
342 : :
343 : : /*
344 : : * Cache the generated trigrams across multiple calls with the same query.
345 : : */
346 [ + + ][ + - ]: 1010 : if (cache == NULL ||
347 [ - + ]: 1009 : VARSIZE(cache) != querysize ||
348 : 1009 : memcmp(cache, query, querysize) != 0)
349 : : {
350 : : char *newcache;
351 : :
352 : 1 : qtrg = generate_trgm(VARDATA(query), querysize - VARHDRSZ);
353 : :
354 : 1 : newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
355 : 2 : MAXALIGN(querysize) +
356 : 1 : VARSIZE(qtrg));
357 : :
358 : 1 : memcpy(newcache, query, querysize);
359 : 1 : memcpy(newcache + MAXALIGN(querysize), qtrg, VARSIZE(qtrg));
360 : :
361 [ - + ]: 1 : if (cache)
362 : 0 : pfree(cache);
363 : 1 : fcinfo->flinfo->fn_extra = newcache;
364 : 1 : cache = newcache;
365 : : }
366 : :
367 : 1010 : qtrg = (TRGM *) (cache + MAXALIGN(querysize));
368 : :
369 [ + - ]: 1010 : switch (strategy)
370 : : {
371 : : case DistanceStrategyNumber:
372 [ + - ][ - + ]: 1010 : if (GIST_LEAF(entry))
[ + + ]
373 : : { /* all leafs contains orig trgm */
374 : 1000 : res = 1.0 - cnt_sml(key, qtrg);
375 : : }
376 [ + - ]: 10 : else if (ISALLTRUE(key))
377 : : { /* all leafs contains orig trgm */
378 : : res = 0.0;
379 : : }
380 : : else
381 : : { /* non-leaf contains signature */
382 : 10 : int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key));
383 : 10 : int32 len = ARRNELEM(qtrg);
384 : :
385 [ + - ]: 10 : res = (len == 0) ? -1.0 : 1.0 - ((float8) count) / ((float8) len);
386 : : }
387 : : break;
388 : : default:
389 : 0 : elog(ERROR, "unrecognized strategy number: %d", strategy);
390 : : res = 0; /* keep compiler quiet */
391 : : break;
392 : : }
393 : :
394 : 1010 : PG_RETURN_FLOAT8(res);
395 : : }
396 : :
397 : : static int32
398 : 1754 : unionkey(BITVECP sbase, TRGM *add)
399 : : {
400 : : int32 i;
401 : :
402 [ + + ]: 1754 : if (ISSIGNKEY(add))
403 : : {
404 : 877 : BITVECP sadd = GETSIGN(add);
405 : :
406 [ + - ]: 877 : if (ISALLTRUE(add))
407 : : return 1;
408 : :
409 [ + + ]: 11401 : LOOPBYTE
410 : 10524 : sbase[i] |= sadd[i];
411 : : }
412 : : else
413 : : {
414 : 877 : trgm *ptr = GETARR(add);
415 : 877 : int32 tmp = 0;
416 : :
417 [ + + ]: 12278 : for (i = 0; i < ARRNELEM(add); i++)
418 : : {
419 : 10524 : CPTRGM(((char *) &tmp), ptr + i);
420 : 10524 : HASH(sbase, tmp);
421 : : }
422 : : }
423 : : return 0;
424 : : }
425 : :
426 : :
427 : : Datum
428 : 877 : gtrgm_union(PG_FUNCTION_ARGS)
429 : : {
430 : 877 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
431 : 877 : int32 len = entryvec->n;
432 : 877 : int *size = (int *) PG_GETARG_POINTER(1);
433 : : BITVEC base;
434 : : int32 i;
435 : 877 : int32 flag = 0;
436 : : TRGM *result;
437 : :
438 : 877 : MemSet((void *) base, 0, sizeof(BITVEC));
439 [ + + ]: 2631 : for (i = 0; i < len; i++)
440 : : {
441 [ + - ]: 1754 : if (unionkey(base, GETENTRY(entryvec, i)))
442 : : {
443 : : flag = ALLISTRUE;
444 : : break;
445 : : }
446 : : }
447 : :
448 : 877 : flag |= SIGNKEY;
449 [ + - ]: 877 : len = CALCGTSIZE(flag, 0);
450 : 877 : result = (TRGM *) palloc(len);
451 : 877 : SET_VARSIZE(result, len);
452 : 877 : result->flag = flag;
453 [ + - ]: 877 : if (!ISALLTRUE(result))
454 : 877 : memcpy((void *) GETSIGN(result), (void *) base, sizeof(BITVEC));
455 : 877 : *size = len;
456 : :
457 : 877 : PG_RETURN_POINTER(result);
458 : : }
459 : :
460 : : Datum
461 : 877 : gtrgm_same(PG_FUNCTION_ARGS)
462 : : {
463 : 877 : TRGM *a = (TRGM *) PG_GETARG_POINTER(0);
464 : 877 : TRGM *b = (TRGM *) PG_GETARG_POINTER(1);
465 : 877 : bool *result = (bool *) PG_GETARG_POINTER(2);
466 : :
467 [ + - ]: 877 : if (ISSIGNKEY(a))
468 : : { /* then b also ISSIGNKEY */
469 [ - + ][ # # ]: 877 : if (ISALLTRUE(a) && ISALLTRUE(b))
470 : 0 : *result = true;
471 [ - + ]: 877 : else if (ISALLTRUE(a))
472 : 0 : *result = false;
473 [ - + ]: 877 : else if (ISALLTRUE(b))
474 : 0 : *result = false;
475 : : else
476 : : {
477 : : int32 i;
478 : 877 : BITVECP sa = GETSIGN(a),
479 : 877 : sb = GETSIGN(b);
480 : :
481 : 877 : *result = true;
482 [ + + ]: 10124 : LOOPBYTE
483 : : {
484 [ + + ]: 9449 : if (sa[i] != sb[i])
485 : : {
486 : 202 : *result = false;
487 : 202 : break;
488 : : }
489 : : }
490 : : }
491 : : }
492 : : else
493 : : { /* a and b ISARRKEY */
494 : 0 : int32 lena = ARRNELEM(a),
495 : 0 : lenb = ARRNELEM(b);
496 : :
497 [ # # ]: 0 : if (lena != lenb)
498 : 0 : *result = false;
499 : : else
500 : : {
501 : 0 : trgm *ptra = GETARR(a),
502 : 0 : *ptrb = GETARR(b);
503 : : int32 i;
504 : :
505 : 0 : *result = true;
506 [ # # ]: 0 : for (i = 0; i < lena; i++)
507 [ # # ][ # # ]: 0 : if (CMPTRGM(ptra + i, ptrb + i))
[ # # ]
508 : : {
509 : 0 : *result = false;
510 : 0 : break;
511 : : }
512 : : }
513 : : }
514 : :
515 : 877 : PG_RETURN_POINTER(result);
516 : : }
517 : :
518 : : static int32
519 : 0 : sizebitvec(BITVECP sign)
520 : : {
521 : 0 : int32 size = 0,
522 : : i;
523 : :
524 [ # # ]: 0 : LOOPBYTE
525 : 0 : size += number_of_ones[(unsigned char) sign[i]];
526 : 0 : return size;
527 : : }
528 : :
529 : : static int
530 : 75730 : hemdistsign(BITVECP a, BITVECP b)
531 : : {
532 : : int i,
533 : : diff,
534 : 75730 : dist = 0;
535 : :
536 [ + + ]: 984490 : LOOPBYTE
537 : : {
538 : 908760 : diff = (unsigned char) (a[i] ^ b[i]);
539 : 908760 : dist += number_of_ones[diff];
540 : : }
541 : 75730 : return dist;
542 : : }
543 : :
544 : : static int
545 : 0 : hemdist(TRGM *a, TRGM *b)
546 : : {
547 [ # # ]: 0 : if (ISALLTRUE(a))
548 : : {
549 [ # # ]: 0 : if (ISALLTRUE(b))
550 : : return 0;
551 : : else
552 : 0 : return SIGLENBIT - sizebitvec(GETSIGN(b));
553 : : }
554 [ # # ]: 0 : else if (ISALLTRUE(b))
555 : 0 : return SIGLENBIT - sizebitvec(GETSIGN(a));
556 : :
557 : 0 : return hemdistsign(GETSIGN(a), GETSIGN(b));
558 : : }
559 : :
560 : : Datum
561 : 4909 : gtrgm_penalty(PG_FUNCTION_ARGS)
562 : : {
563 : 4909 : GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
564 : 4909 : GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
565 : 4909 : float *penalty = (float *) PG_GETARG_POINTER(2);
566 : 4909 : TRGM *origval = (TRGM *) DatumGetPointer(origentry->key);
567 : 4909 : TRGM *newval = (TRGM *) DatumGetPointer(newentry->key);
568 : 4909 : BITVECP orig = GETSIGN(origval);
569 : :
570 : 4909 : *penalty = 0.0;
571 : :
572 [ + - ]: 4909 : if (ISARRKEY(newval))
573 : : {
574 : 4909 : char *cache = (char *) fcinfo->flinfo->fn_extra;
575 : 4909 : TRGM *cachedVal = (TRGM *) (cache + MAXALIGN(sizeof(BITVEC)));
576 : 4909 : Size newvalsize = VARSIZE(newval);
577 : : BITVECP sign;
578 : :
579 : : /*
580 : : * Cache the sign data across multiple calls with the same newval.
581 : : */
582 [ + + ][ + - ]: 4909 : if (cache == NULL ||
583 [ + + ]: 4908 : VARSIZE(cachedVal) != newvalsize ||
584 : 4908 : memcmp(cachedVal, newval, newvalsize) != 0)
585 : : {
586 : : char *newcache;
587 : :
588 : 877 : newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
589 : : MAXALIGN(sizeof(BITVEC)) +
590 : : newvalsize);
591 : :
592 : 877 : makesign((BITVECP) newcache, newval);
593 : :
594 : 877 : cachedVal = (TRGM *) (newcache + MAXALIGN(sizeof(BITVEC)));
595 : 877 : memcpy(cachedVal, newval, newvalsize);
596 : :
597 [ + + ]: 877 : if (cache)
598 : 876 : pfree(cache);
599 : 877 : fcinfo->flinfo->fn_extra = newcache;
600 : 877 : cache = newcache;
601 : : }
602 : :
603 : 4909 : sign = (BITVECP) cache;
604 : :
605 [ - + ]: 4909 : if (ISALLTRUE(origval))
606 : 0 : *penalty = ((float) (SIGLENBIT - sizebitvec(sign))) / (float) (SIGLENBIT + 1);
607 : : else
608 : 4909 : *penalty = hemdistsign(sign, orig);
609 : : }
610 : : else
611 : 0 : *penalty = hemdist(origval, newval);
612 : 4909 : PG_RETURN_POINTER(penalty);
613 : : }
614 : :
615 : : typedef struct
616 : : {
617 : : bool allistrue;
618 : : BITVEC sign;
619 : : } CACHESIGN;
620 : :
621 : : static void
622 : 1107 : fillcache(CACHESIGN *item, TRGM *key)
623 : : {
624 : 1107 : item->allistrue = false;
625 [ + - ]: 1107 : if (ISARRKEY(key))
626 : 1107 : makesign(item->sign, key);
627 [ # # ]: 0 : else if (ISALLTRUE(key))
628 : 0 : item->allistrue = true;
629 : : else
630 : 0 : memcpy((void *) item->sign, (void *) GETSIGN(key), sizeof(BITVEC));
631 : 1107 : }
632 : :
633 : : #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
634 : : typedef struct
635 : : {
636 : : OffsetNumber pos;
637 : : int32 cost;
638 : : } SPLITCOST;
639 : :
640 : : static int
641 : 1849 : comparecost(const void *a, const void *b)
642 : : {
643 [ + + ]: 1849 : if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
644 : : return 0;
645 : : else
646 [ + + ]: 1849 : return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
647 : : }
648 : :
649 : :
650 : : static int
651 : 68643 : hemdistcache(CACHESIGN *a, CACHESIGN *b)
652 : : {
653 [ - + ]: 68643 : if (a->allistrue)
654 : : {
655 [ # # ]: 0 : if (b->allistrue)
656 : : return 0;
657 : : else
658 : 0 : return SIGLENBIT - sizebitvec(b->sign);
659 : : }
660 [ - + ]: 68643 : else if (b->allistrue)
661 : 0 : return SIGLENBIT - sizebitvec(a->sign);
662 : :
663 : 68643 : return hemdistsign(a->sign, b->sign);
664 : : }
665 : :
666 : : Datum
667 : 9 : gtrgm_picksplit(PG_FUNCTION_ARGS)
668 : : {
669 : 9 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
670 : 9 : OffsetNumber maxoff = entryvec->n - 2;
671 : 9 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
672 : : OffsetNumber k,
673 : : j;
674 : : TRGM *datum_l,
675 : : *datum_r;
676 : : BITVECP union_l,
677 : : union_r;
678 : : int32 size_alpha,
679 : : size_beta;
680 : : int32 size_waste,
681 : 9 : waste = -1;
682 : : int32 nbytes;
683 : 9 : OffsetNumber seed_1 = 0,
684 : 9 : seed_2 = 0;
685 : : OffsetNumber *left,
686 : : *right;
687 : : BITVECP ptr;
688 : : int i;
689 : : CACHESIGN *cache;
690 : : SPLITCOST *costvector;
691 : :
692 : : /* cache the sign data for each existing item */
693 : 9 : cache = (CACHESIGN *) palloc(sizeof(CACHESIGN) * (maxoff + 2));
694 [ + + ]: 1107 : for (k = FirstOffsetNumber; k <= maxoff; k = OffsetNumberNext(k))
695 : 1098 : fillcache(&cache[k], GETENTRY(entryvec, k));
696 : :
697 : : /* now find the two furthest-apart items */
698 [ + + ]: 1098 : for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
699 : : {
700 [ + + ]: 67527 : for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
701 : : {
702 : 66429 : size_waste = hemdistcache(&(cache[j]), &(cache[k]));
703 [ + + ]: 66429 : if (size_waste > waste)
704 : : {
705 : 34 : waste = size_waste;
706 : 34 : seed_1 = k;
707 : 34 : seed_2 = j;
708 : : }
709 : : }
710 : : }
711 : :
712 : : /* just in case we didn't make a selection ... */
713 [ - + ]: 9 : if (seed_1 == 0 || seed_2 == 0)
714 : : {
715 : 0 : seed_1 = 1;
716 : 0 : seed_2 = 2;
717 : : }
718 : :
719 : : /* initialize the result vectors */
720 : 9 : nbytes = (maxoff + 2) * sizeof(OffsetNumber);
721 : 9 : v->spl_left = left = (OffsetNumber *) palloc(nbytes);
722 : 9 : v->spl_right = right = (OffsetNumber *) palloc(nbytes);
723 : 9 : v->spl_nleft = 0;
724 : 9 : v->spl_nright = 0;
725 : :
726 : : /* form initial .. */
727 [ - + ]: 9 : if (cache[seed_1].allistrue)
728 : : {
729 : 0 : datum_l = (TRGM *) palloc(CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
730 : 0 : SET_VARSIZE(datum_l, CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
731 : 0 : datum_l->flag = SIGNKEY | ALLISTRUE;
732 : : }
733 : : else
734 : : {
735 : 9 : datum_l = (TRGM *) palloc(CALCGTSIZE(SIGNKEY, 0));
736 : 9 : SET_VARSIZE(datum_l, CALCGTSIZE(SIGNKEY, 0));
737 : 9 : datum_l->flag = SIGNKEY;
738 : 9 : memcpy((void *) GETSIGN(datum_l), (void *) cache[seed_1].sign, sizeof(BITVEC));
739 : : }
740 [ - + ]: 9 : if (cache[seed_2].allistrue)
741 : : {
742 : 0 : datum_r = (TRGM *) palloc(CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
743 : 0 : SET_VARSIZE(datum_r, CALCGTSIZE(SIGNKEY | ALLISTRUE, 0));
744 : 0 : datum_r->flag = SIGNKEY | ALLISTRUE;
745 : : }
746 : : else
747 : : {
748 : 9 : datum_r = (TRGM *) palloc(CALCGTSIZE(SIGNKEY, 0));
749 : 9 : SET_VARSIZE(datum_r, CALCGTSIZE(SIGNKEY, 0));
750 : 9 : datum_r->flag = SIGNKEY;
751 : 9 : memcpy((void *) GETSIGN(datum_r), (void *) cache[seed_2].sign, sizeof(BITVEC));
752 : : }
753 : :
754 : 9 : union_l = GETSIGN(datum_l);
755 : 9 : union_r = GETSIGN(datum_r);
756 : 9 : maxoff = OffsetNumberNext(maxoff);
757 : 9 : fillcache(&cache[maxoff], GETENTRY(entryvec, maxoff));
758 : : /* sort before ... */
759 : 9 : costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
760 [ + + ]: 1116 : for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
761 : : {
762 : 1107 : costvector[j - 1].pos = j;
763 : 1107 : size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]));
764 : 1107 : size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]));
765 : 1107 : costvector[j - 1].cost = abs(size_alpha - size_beta);
766 : : }
767 : 9 : qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
768 : :
769 [ + + ]: 1116 : for (k = 0; k < maxoff; k++)
770 : : {
771 : 1107 : j = costvector[k].pos;
772 [ + + ]: 1107 : if (j == seed_1)
773 : : {
774 : 9 : *left++ = j;
775 : 9 : v->spl_nleft++;
776 : 9 : continue;
777 : : }
778 [ + + ]: 1098 : else if (j == seed_2)
779 : : {
780 : 9 : *right++ = j;
781 : 9 : v->spl_nright++;
782 : 9 : continue;
783 : : }
784 : :
785 [ + - ][ - + ]: 1089 : if (ISALLTRUE(datum_l) || cache[j].allistrue)
786 : : {
787 [ # # ][ # # ]: 0 : if (ISALLTRUE(datum_l) && cache[j].allistrue)
788 : : size_alpha = 0;
789 : : else
790 [ # # ]: 0 : size_alpha = SIGLENBIT - sizebitvec(
791 : 0 : (cache[j].allistrue) ? GETSIGN(datum_l) : GETSIGN(cache[j].sign)
792 : : );
793 : : }
794 : : else
795 : 1089 : size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l));
796 : :
797 [ + - ][ - + ]: 1089 : if (ISALLTRUE(datum_r) || cache[j].allistrue)
798 : : {
799 [ # # ][ # # ]: 0 : if (ISALLTRUE(datum_r) && cache[j].allistrue)
800 : : size_beta = 0;
801 : : else
802 [ # # ]: 0 : size_beta = SIGLENBIT - sizebitvec(
803 : 0 : (cache[j].allistrue) ? GETSIGN(datum_r) : GETSIGN(cache[j].sign)
804 : : );
805 : : }
806 : : else
807 : 1089 : size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r));
808 : :
809 [ + + ]: 1089 : if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
810 : : {
811 [ + - ][ + - ]: 543 : if (ISALLTRUE(datum_l) || cache[j].allistrue)
812 : : {
813 [ # # ]: 0 : if (!ISALLTRUE(datum_l))
814 : 0 : MemSet((void *) GETSIGN(datum_l), 0xff, sizeof(BITVEC));
815 : : }
816 : : else
817 : : {
818 : : ptr = cache[j].sign;
819 [ + + ]: 7059 : LOOPBYTE
820 : 6516 : union_l[i] |= ptr[i];
821 : : }
822 : 543 : *left++ = j;
823 : 543 : v->spl_nleft++;
824 : : }
825 : : else
826 : : {
827 [ + - ][ + - ]: 546 : if (ISALLTRUE(datum_r) || cache[j].allistrue)
828 : : {
829 [ # # ]: 0 : if (!ISALLTRUE(datum_r))
830 : 0 : MemSet((void *) GETSIGN(datum_r), 0xff, sizeof(BITVEC));
831 : : }
832 : : else
833 : : {
834 : : ptr = cache[j].sign;
835 [ + + ]: 7098 : LOOPBYTE
836 : 6552 : union_r[i] |= ptr[i];
837 : : }
838 : 546 : *right++ = j;
839 : 546 : v->spl_nright++;
840 : : }
841 : : }
842 : :
843 : 9 : *right = *left = FirstOffsetNumber;
844 : 9 : v->spl_ldatum = PointerGetDatum(datum_l);
845 : 9 : v->spl_rdatum = PointerGetDatum(datum_r);
846 : :
847 : 9 : PG_RETURN_POINTER(v);
848 : : }
|