2 * contrib/hstore/hstore_gist.c
6 #include "access/gist.h"
7 #include "access/skey.h"
8 #include "catalog/pg_type.h"
9 #include "utils/builtins.h"
10 #include "utils/pg_crc.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(int32))
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 crc32_HStoreValue(HStoreValue *v, uint32 r)
132 COMP_CRC32(crc, &flag, 1);
137 COMP_CRC32(crc, v->string.val, v->string.len);
140 flag = (v->boolean) ? 't' : 'f';
141 COMP_CRC32(crc, &flag, 1);
144 crc = DatumGetInt32(DirectFunctionCall1(hash_numeric,
145 NumericGetDatum(v->numeric)));
148 elog(PANIC, "impossible value %d", v->type);
156 crc32_Key(char *buf, int sz)
163 COMP_CRC32(crc, &flag, 1);
164 COMP_CRC32(crc, buf, sz);
171 ghstore_compress(PG_FUNCTION_ARGS)
173 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
174 GISTENTRY *retval = entry;
178 GISTTYPE *res = (GISTTYPE *) palloc0(CALCGTSIZE(0));
179 HStore *val = DatumGetHStoreP(entry->key);
181 SET_VARSIZE(res, CALCGTSIZE(0));
183 if (!HS_ISEMPTY(val))
186 HStoreIterator *it = HStoreIteratorInit(VARDATA(val));
189 while((r = HStoreIteratorGet(&it, &v, false)) != 0)
191 if ((r == WHS_ELEM || r == WHS_KEY || r == WHS_VALUE) &&
194 int h = crc32_HStoreValue(&v, r);
196 HASH(GETSIGN(res), h);
201 retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
202 gistentryinit(*retval, PointerGetDatum(res),
203 entry->rel, entry->page,
207 else if (!ISALLTRUE(DatumGetPointer(entry->key)))
211 BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
215 if ((sign[i] & 0xff) != 0xff)
216 PG_RETURN_POINTER(retval);
219 res = (GISTTYPE *) palloc(CALCGTSIZE(ALLISTRUE));
220 SET_VARSIZE(res, CALCGTSIZE(ALLISTRUE));
221 res->flag = ALLISTRUE;
223 retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
224 gistentryinit(*retval, PointerGetDatum(res),
225 entry->rel, entry->page,
230 PG_RETURN_POINTER(retval);
234 * Since type ghstore isn't toastable (and doesn't need to be),
235 * this function can be a no-op.
238 ghstore_decompress(PG_FUNCTION_ARGS)
240 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
244 ghstore_same(PG_FUNCTION_ARGS)
246 GISTTYPE *a = (GISTTYPE *) PG_GETARG_POINTER(0);
247 GISTTYPE *b = (GISTTYPE *) PG_GETARG_POINTER(1);
248 bool *result = (bool *) PG_GETARG_POINTER(2);
250 if (ISALLTRUE(a) && ISALLTRUE(b))
252 else if (ISALLTRUE(a))
254 else if (ISALLTRUE(b))
259 BITVECP sa = GETSIGN(a),
272 PG_RETURN_POINTER(result);
276 sizebitvec(BITVECP sign)
283 size += SUMBIT(sign);
284 sign = (BITVECP) (((char *) sign) + 1);
290 hemdistsign(BITVECP a, BITVECP b)
297 if (GETBIT(a, i) != GETBIT(b, i))
304 hemdist(GISTTYPE *a, GISTTYPE *b)
311 return SIGLENBIT - sizebitvec(GETSIGN(b));
313 else if (ISALLTRUE(b))
314 return SIGLENBIT - sizebitvec(GETSIGN(a));
316 return hemdistsign(GETSIGN(a), GETSIGN(b));
320 unionkey(BITVECP sbase, GISTTYPE *add)
323 BITVECP sadd = GETSIGN(add);
333 ghstore_union(PG_FUNCTION_ARGS)
335 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
336 int32 len = entryvec->n;
338 int *size = (int *) PG_GETARG_POINTER(1);
344 MemSet((void *) base, 0, sizeof(BITVEC));
345 for (i = 0; i < len; i++)
347 if (unionkey(base, GETENTRY(entryvec, i)))
354 len = CALCGTSIZE(flag);
355 result = (GISTTYPE *) palloc(len);
356 SET_VARSIZE(result, len);
358 if (!ISALLTRUE(result))
359 memcpy((void *) GETSIGN(result), (void *) base, sizeof(BITVEC));
362 PG_RETURN_POINTER(result);
366 ghstore_penalty(PG_FUNCTION_ARGS)
368 GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
369 GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
370 float *penalty = (float *) PG_GETARG_POINTER(2);
371 GISTTYPE *origval = (GISTTYPE *) DatumGetPointer(origentry->key);
372 GISTTYPE *newval = (GISTTYPE *) DatumGetPointer(newentry->key);
374 *penalty = hemdist(origval, newval);
375 PG_RETURN_POINTER(penalty);
386 comparecost(const void *a, const void *b)
388 return ((const SPLITCOST *) a)->cost - ((const SPLITCOST *) b)->cost;
393 ghstore_picksplit(PG_FUNCTION_ARGS)
395 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
396 OffsetNumber maxoff = entryvec->n - 2;
398 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
410 OffsetNumber seed_1 = 0,
416 SPLITCOST *costvector;
420 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
421 v->spl_left = (OffsetNumber *) palloc(nbytes);
422 v->spl_right = (OffsetNumber *) palloc(nbytes);
424 for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
426 _k = GETENTRY(entryvec, k);
427 for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
429 size_waste = hemdist(_k, GETENTRY(entryvec, j));
430 if (size_waste > waste)
441 right = v->spl_right;
444 if (seed_1 == 0 || seed_2 == 0)
450 /* form initial .. */
451 if (ISALLTRUE(GETENTRY(entryvec, seed_1)))
453 datum_l = (GISTTYPE *) palloc(GTHDRSIZE);
454 SET_VARSIZE(datum_l, GTHDRSIZE);
455 datum_l->flag = ALLISTRUE;
459 datum_l = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
460 SET_VARSIZE(datum_l, GTHDRSIZE + SIGLEN);
462 memcpy((void *) GETSIGN(datum_l),
463 (void *) GETSIGN(GETENTRY(entryvec, seed_1)), sizeof(BITVEC))
466 if (ISALLTRUE(GETENTRY(entryvec, seed_2)))
468 datum_r = (GISTTYPE *) palloc(GTHDRSIZE);
469 SET_VARSIZE(datum_r, GTHDRSIZE);
470 datum_r->flag = ALLISTRUE;
474 datum_r = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
475 SET_VARSIZE(datum_r, GTHDRSIZE + SIGLEN);
477 memcpy((void *) GETSIGN(datum_r),
478 (void *) GETSIGN(GETENTRY(entryvec, seed_2)), sizeof(BITVEC));
481 maxoff = OffsetNumberNext(maxoff);
482 /* sort before ... */
483 costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
484 for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
486 costvector[j - 1].pos = j;
487 _j = GETENTRY(entryvec, j);
488 size_alpha = hemdist(datum_l, _j);
489 size_beta = hemdist(datum_r, _j);
490 costvector[j - 1].cost = abs(size_alpha - size_beta);
492 qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
494 union_l = GETSIGN(datum_l);
495 union_r = GETSIGN(datum_r);
497 for (k = 0; k < maxoff; k++)
499 j = costvector[k].pos;
506 else if (j == seed_2)
512 _j = GETENTRY(entryvec, j);
513 size_alpha = hemdist(datum_l, _j);
514 size_beta = hemdist(datum_r, _j);
516 if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.0001))
518 if (ISALLTRUE(datum_l) || ISALLTRUE(_j))
520 if (!ISALLTRUE(datum_l))
521 MemSet((void *) union_l, 0xff, sizeof(BITVEC));
527 union_l[i] |= ptr[i];
534 if (ISALLTRUE(datum_r) || ISALLTRUE(_j))
536 if (!ISALLTRUE(datum_r))
537 MemSet((void *) union_r, 0xff, sizeof(BITVEC));
543 union_r[i] |= ptr[i];
550 *right = *left = FirstOffsetNumber;
552 v->spl_ldatum = PointerGetDatum(datum_l);
553 v->spl_rdatum = PointerGetDatum(datum_r);
555 PG_RETURN_POINTER(v);
559 ghstore_consistent(PG_FUNCTION_ARGS)
561 GISTTYPE *entry = (GISTTYPE *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
562 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
564 /* Oid subtype = PG_GETARG_OID(3); */
565 bool *recheck = (bool *) PG_GETARG_POINTER(4);
569 /* All cases served by this function are inexact */
572 if (ISALLTRUE(entry))
573 PG_RETURN_BOOL(true);
575 sign = GETSIGN(entry);
577 if (strategy == HStoreContainsStrategyNumber ||
578 strategy == HStoreOldContainsStrategyNumber)
583 qe = fcinfo->flinfo->fn_extra;
586 HStore *query = PG_GETARG_HS(1);
588 qe = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(BITVEC));
589 memset(qe, 0, sizeof(BITVEC));
591 if (!HS_ISEMPTY(query))
594 HStoreIterator *it = HStoreIteratorInit(VARDATA(query));
597 while((r = HStoreIteratorGet(&it, &v, false)) != 0)
599 if ((r == WHS_ELEM || r == WHS_KEY || r == WHS_VALUE) && v.type != hsvNull)
601 int crc = crc32_HStoreValue(&v, r);
608 fcinfo->flinfo->fn_extra = qe;
613 if ((sign[i] & qe[i]) != qe[i])
620 else if (strategy == HStoreExistsStrategyNumber)
624 qval = fcinfo->flinfo->fn_extra;
627 text *query = PG_GETARG_TEXT_PP(1);
628 int crc = crc32_Key(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query));
630 qval = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(*qval));
631 *qval = HASHVAL(crc);
633 fcinfo->flinfo->fn_extra = qval;
636 res = (GETBIT(sign, *qval)) ? true : false;
638 else if (strategy == HStoreExistsAllStrategyNumber ||
639 strategy == HStoreExistsAnyStrategyNumber)
644 arrentry = fcinfo->flinfo->fn_extra;
645 if (arrentry == NULL)
647 ArrayType *query = PG_GETARG_ARRAYTYPE_P(1);
652 arrentry = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
654 memset(arrentry, 0, sizeof(BITVEC));
656 deconstruct_array(query,
657 TEXTOID, -1, false, 'i',
658 &key_datums, &key_nulls, &key_count);
660 for (i = 0; i < key_count; ++i)
666 crc = crc32_Key(VARDATA(key_datums[i]),
667 VARSIZE(key_datums[i]) - VARHDRSZ);
671 fcinfo->flinfo->fn_extra = arrentry;
674 if (strategy == HStoreExistsAllStrategyNumber)
678 if ((sign[i] & arrentry[i]) != arrentry[i])
685 else /* HStoreExistsAnyStrategyNumber */
691 if (sign[i] & arrentry[i])
700 elog(ERROR, "Unsupported strategy number: %d", strategy);