2 * $PostgreSQL: pgsql/contrib/hstore/hstore_gist.c,v 1.12 2010/02/26 02:00:32 momjian Exp $
6 #include "access/gist.h"
7 #include "access/itup.h"
8 #include "access/skey.h"
9 #include "catalog/pg_type.h"
16 #define SIGLENINT 4 /* >122 => key will toast, so very slow!!! */
17 #define SIGLEN ( sizeof(int)*SIGLENINT )
18 #define SIGLENBIT (SIGLEN*BITBYTE)
20 typedef char BITVEC[SIGLEN];
21 typedef char *BITVECP;
23 #define SIGPTR(x) ( (BITVECP) ARR_DATA_PTR(x) )
30 for(i=0;i<SIGLENBIT;i++)
32 /* beware of multiple evaluation of arguments to these macros! */
33 #define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) )
34 #define GETBITBYTE(x,i) ( (*((char*)(x)) >> (i)) & 0x01 )
35 #define CLRBIT(x,i) GETBYTE(x,i) &= ~( 0x01 << ( (i) % BITBYTE ) )
36 #define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITBYTE ) )
37 #define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITBYTE )) & 0x01 )
38 #define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT)
39 #define HASH(sign, val) SETBIT((sign), HASHVAL(val))
43 int32 vl_len_; /* varlena header (do not touch directly!) */
48 #define ALLISTRUE 0x04
50 #define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE )
52 #define GTHDRSIZE (VARHDRSZ + sizeof(int4))
53 #define CALCGTSIZE(flag) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : SIGLEN) )
55 #define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) )
57 #define SUMBIT(val) ( \
58 GETBITBYTE((val),0) + \
59 GETBITBYTE((val),1) + \
60 GETBITBYTE((val),2) + \
61 GETBITBYTE((val),3) + \
62 GETBITBYTE((val),4) + \
63 GETBITBYTE((val),5) + \
64 GETBITBYTE((val),6) + \
68 #define GETENTRY(vec,pos) ((GISTTYPE *) DatumGetPointer((vec)->vector[(pos)].key))
70 #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
72 PG_FUNCTION_INFO_V1(ghstore_in);
73 Datum ghstore_in(PG_FUNCTION_ARGS);
75 PG_FUNCTION_INFO_V1(ghstore_out);
76 Datum ghstore_out(PG_FUNCTION_ARGS);
80 ghstore_in(PG_FUNCTION_ARGS)
82 elog(ERROR, "Not implemented");
87 ghstore_out(PG_FUNCTION_ARGS)
89 elog(ERROR, "Not implemented");
93 PG_FUNCTION_INFO_V1(ghstore_consistent);
94 PG_FUNCTION_INFO_V1(ghstore_compress);
95 PG_FUNCTION_INFO_V1(ghstore_decompress);
96 PG_FUNCTION_INFO_V1(ghstore_penalty);
97 PG_FUNCTION_INFO_V1(ghstore_picksplit);
98 PG_FUNCTION_INFO_V1(ghstore_union);
99 PG_FUNCTION_INFO_V1(ghstore_same);
101 Datum ghstore_consistent(PG_FUNCTION_ARGS);
102 Datum ghstore_compress(PG_FUNCTION_ARGS);
103 Datum ghstore_decompress(PG_FUNCTION_ARGS);
104 Datum ghstore_penalty(PG_FUNCTION_ARGS);
105 Datum ghstore_picksplit(PG_FUNCTION_ARGS);
106 Datum ghstore_union(PG_FUNCTION_ARGS);
107 Datum ghstore_same(PG_FUNCTION_ARGS);
110 ghstore_compress(PG_FUNCTION_ARGS)
112 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
113 GISTENTRY *retval = entry;
117 GISTTYPE *res = (GISTTYPE *) palloc0(CALCGTSIZE(0));
118 HStore *val = DatumGetHStoreP(entry->key);
119 HEntry *hsent = ARRPTR(val);
120 char *ptr = STRPTR(val);
121 int count = HS_COUNT(val);
124 SET_VARSIZE(res, CALCGTSIZE(0));
126 for (i = 0; i < count; ++i)
130 h = crc32_sz((char *) HS_KEY(hsent, ptr, i), HS_KEYLEN(hsent, i));
131 HASH(GETSIGN(res), h);
132 if (!HS_VALISNULL(hsent, i))
134 h = crc32_sz((char *) HS_VAL(hsent, ptr, i), HS_VALLEN(hsent, i));
135 HASH(GETSIGN(res), h);
139 retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
140 gistentryinit(*retval, PointerGetDatum(res),
141 entry->rel, entry->page,
145 else if (!ISALLTRUE(DatumGetPointer(entry->key)))
149 BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
153 if ((sign[i] & 0xff) != 0xff)
154 PG_RETURN_POINTER(retval);
157 res = (GISTTYPE *) palloc(CALCGTSIZE(ALLISTRUE));
158 SET_VARSIZE(res, CALCGTSIZE(ALLISTRUE));
159 res->flag = ALLISTRUE;
161 retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
162 gistentryinit(*retval, PointerGetDatum(res),
163 entry->rel, entry->page,
168 PG_RETURN_POINTER(retval);
172 ghstore_decompress(PG_FUNCTION_ARGS)
174 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
178 key = DatumGetHStoreP(entry->key);
180 if (key != (HStore *) DatumGetPointer(entry->key))
182 /* need to pass back the decompressed item */
183 retval = palloc(sizeof(GISTENTRY));
184 gistentryinit(*retval, PointerGetDatum(key),
185 entry->rel, entry->page, entry->offset, entry->leafkey);
186 PG_RETURN_POINTER(retval);
190 /* we can return the entry as-is */
191 PG_RETURN_POINTER(entry);
196 ghstore_same(PG_FUNCTION_ARGS)
198 GISTTYPE *a = (GISTTYPE *) PG_GETARG_POINTER(0);
199 GISTTYPE *b = (GISTTYPE *) PG_GETARG_POINTER(1);
200 bool *result = (bool *) PG_GETARG_POINTER(2);
202 if (ISALLTRUE(a) && ISALLTRUE(b))
204 else if (ISALLTRUE(a))
206 else if (ISALLTRUE(b))
211 BITVECP sa = GETSIGN(a),
224 PG_RETURN_POINTER(result);
228 sizebitvec(BITVECP sign)
235 size += SUMBIT(sign);
236 sign = (BITVECP) (((char *) sign) + 1);
242 hemdistsign(BITVECP a, BITVECP b)
249 if (GETBIT(a, i) != GETBIT(b, i))
256 hemdist(GISTTYPE *a, GISTTYPE *b)
263 return SIGLENBIT - sizebitvec(GETSIGN(b));
265 else if (ISALLTRUE(b))
266 return SIGLENBIT - sizebitvec(GETSIGN(a));
268 return hemdistsign(GETSIGN(a), GETSIGN(b));
272 unionkey(BITVECP sbase, GISTTYPE *add)
275 BITVECP sadd = GETSIGN(add);
285 ghstore_union(PG_FUNCTION_ARGS)
287 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
288 int4 len = entryvec->n;
290 int *size = (int *) PG_GETARG_POINTER(1);
296 MemSet((void *) base, 0, sizeof(BITVEC));
297 for (i = 0; i < len; i++)
299 if (unionkey(base, GETENTRY(entryvec, i)))
306 len = CALCGTSIZE(flag);
307 result = (GISTTYPE *) palloc(len);
308 SET_VARSIZE(result, len);
310 if (!ISALLTRUE(result))
311 memcpy((void *) GETSIGN(result), (void *) base, sizeof(BITVEC));
314 PG_RETURN_POINTER(result);
318 ghstore_penalty(PG_FUNCTION_ARGS)
320 GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
321 GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
322 float *penalty = (float *) PG_GETARG_POINTER(2);
323 GISTTYPE *origval = (GISTTYPE *) DatumGetPointer(origentry->key);
324 GISTTYPE *newval = (GISTTYPE *) DatumGetPointer(newentry->key);
326 *penalty = hemdist(origval, newval);
327 PG_RETURN_POINTER(penalty);
338 comparecost(const void *a, const void *b)
340 return ((SPLITCOST *) a)->cost - ((SPLITCOST *) b)->cost;
345 ghstore_picksplit(PG_FUNCTION_ARGS)
347 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
348 OffsetNumber maxoff = entryvec->n - 2;
350 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
362 OffsetNumber seed_1 = 0,
368 SPLITCOST *costvector;
372 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
373 v->spl_left = (OffsetNumber *) palloc(nbytes);
374 v->spl_right = (OffsetNumber *) palloc(nbytes);
376 for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
378 _k = GETENTRY(entryvec, k);
379 for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
381 size_waste = hemdist(_k, GETENTRY(entryvec, j));
382 if (size_waste > waste)
393 right = v->spl_right;
396 if (seed_1 == 0 || seed_2 == 0)
402 /* form initial .. */
403 if (ISALLTRUE(GETENTRY(entryvec, seed_1)))
405 datum_l = (GISTTYPE *) palloc(GTHDRSIZE);
406 SET_VARSIZE(datum_l, GTHDRSIZE);
407 datum_l->flag = ALLISTRUE;
411 datum_l = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
412 SET_VARSIZE(datum_l, GTHDRSIZE + SIGLEN);
414 memcpy((void *) GETSIGN(datum_l), (void *) GETSIGN(GETENTRY(entryvec, seed_1)), sizeof(BITVEC))
417 if (ISALLTRUE(GETENTRY(entryvec, seed_2)))
419 datum_r = (GISTTYPE *) palloc(GTHDRSIZE);
420 SET_VARSIZE(datum_r, GTHDRSIZE);
421 datum_r->flag = ALLISTRUE;
425 datum_r = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
426 SET_VARSIZE(datum_r, GTHDRSIZE + SIGLEN);
428 memcpy((void *) GETSIGN(datum_r), (void *) GETSIGN(GETENTRY(entryvec, seed_2)), sizeof(BITVEC));
431 maxoff = OffsetNumberNext(maxoff);
432 /* sort before ... */
433 costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
434 for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
436 costvector[j - 1].pos = j;
437 _j = GETENTRY(entryvec, j);
438 size_alpha = hemdist(datum_l, _j);
439 size_beta = hemdist(datum_r, _j);
440 costvector[j - 1].cost = abs(size_alpha - size_beta);
442 qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
444 union_l = GETSIGN(datum_l);
445 union_r = GETSIGN(datum_r);
447 for (k = 0; k < maxoff; k++)
449 j = costvector[k].pos;
456 else if (j == seed_2)
462 _j = GETENTRY(entryvec, j);
463 size_alpha = hemdist(datum_l, _j);
464 size_beta = hemdist(datum_r, _j);
466 if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.0001))
468 if (ISALLTRUE(datum_l) || ISALLTRUE(_j))
470 if (!ISALLTRUE(datum_l))
471 MemSet((void *) union_l, 0xff, sizeof(BITVEC));
477 union_l[i] |= ptr[i];
484 if (ISALLTRUE(datum_r) || ISALLTRUE(_j))
486 if (!ISALLTRUE(datum_r))
487 MemSet((void *) union_r, 0xff, sizeof(BITVEC));
493 union_r[i] |= ptr[i];
500 *right = *left = FirstOffsetNumber;
502 v->spl_ldatum = PointerGetDatum(datum_l);
503 v->spl_rdatum = PointerGetDatum(datum_r);
505 PG_RETURN_POINTER(v);
510 ghstore_consistent(PG_FUNCTION_ARGS)
512 GISTTYPE *entry = (GISTTYPE *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
513 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
515 /* Oid subtype = PG_GETARG_OID(3); */
516 bool *recheck = (bool *) PG_GETARG_POINTER(4);
520 /* All cases served by this function are inexact */
523 if (ISALLTRUE(entry))
524 PG_RETURN_BOOL(true);
526 sign = GETSIGN(entry);
528 if (strategy == HStoreContainsStrategyNumber ||
529 strategy == HStoreOldContainsStrategyNumber)
531 HStore *query = PG_GETARG_HS(1);
532 HEntry *qe = ARRPTR(query);
533 char *qv = STRPTR(query);
534 int count = HS_COUNT(query);
537 for (i = 0; res && i < count; ++i)
539 int crc = crc32_sz((char *) HS_KEY(qe, qv, i), HS_KEYLEN(qe, i));
541 if (GETBIT(sign, HASHVAL(crc)))
543 if (!HS_VALISNULL(qe, i))
545 crc = crc32_sz((char *) HS_VAL(qe, qv, i), HS_VALLEN(qe, i));
546 if (!GETBIT(sign, HASHVAL(crc)))
554 else if (strategy == HStoreExistsStrategyNumber)
556 text *query = PG_GETARG_TEXT_PP(1);
557 int crc = crc32_sz(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query));
559 res = (GETBIT(sign, HASHVAL(crc))) ? true : false;
561 else if (strategy == HStoreExistsAllStrategyNumber)
563 ArrayType *query = PG_GETARG_ARRAYTYPE_P(1);
569 deconstruct_array(query,
570 TEXTOID, -1, false, 'i',
571 &key_datums, &key_nulls, &key_count);
573 for (i = 0; res && i < key_count; ++i)
579 crc = crc32_sz(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ);
580 if (!(GETBIT(sign, HASHVAL(crc))))
584 else if (strategy == HStoreExistsAnyStrategyNumber)
586 ArrayType *query = PG_GETARG_ARRAYTYPE_P(1);
592 deconstruct_array(query,
593 TEXTOID, -1, false, 'i',
594 &key_datums, &key_nulls, &key_count);
598 for (i = 0; !res && i < key_count; ++i)
604 crc = crc32_sz(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ);
605 if (GETBIT(sign, HASHVAL(crc)))
610 elog(ERROR, "Unsupported strategy number: %d", strategy);