6 #include "access/gist.h"
7 #include "access/itup.h"
8 #include "access/skey.h"
15 #define SIGLENINT 4 /* >122 => key will toast, so very slow!!! */
16 #define SIGLEN ( sizeof(int)*SIGLENINT )
17 #define SIGLENBIT (SIGLEN*BITBYTE)
19 typedef char BITVEC
[SIGLEN
];
20 typedef char *BITVECP
;
22 #define SIGPTR(x) ( (BITVECP) ARR_DATA_PTR(x) )
29 for(i=0;i<SIGLENBIT;i++)
31 /* beware of multiple evaluation of arguments to these macros! */
32 #define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) )
33 #define GETBITBYTE(x,i) ( (*((char*)(x)) >> (i)) & 0x01 )
34 #define CLRBIT(x,i) GETBYTE(x,i) &= ~( 0x01 << ( (i) % BITBYTE ) )
35 #define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITBYTE ) )
36 #define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITBYTE )) & 0x01 )
37 #define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT)
38 #define HASH(sign, val) SETBIT((sign), HASHVAL(val))
42 int32 vl_len_
; /* varlena header (do not touch directly!) */
47 #define ALLISTRUE 0x04
49 #define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE )
51 #define GTHDRSIZE (VARHDRSZ + sizeof(int4))
52 #define CALCGTSIZE(flag) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : SIGLEN) )
54 #define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) )
56 #define SUMBIT(val) ( \
57 GETBITBYTE((val),0) + \
58 GETBITBYTE((val),1) + \
59 GETBITBYTE((val),2) + \
60 GETBITBYTE((val),3) + \
61 GETBITBYTE((val),4) + \
62 GETBITBYTE((val),5) + \
63 GETBITBYTE((val),6) + \
67 #define GETENTRY(vec,pos) ((GISTTYPE *) DatumGetPointer((vec)->vector[(pos)].key))
69 #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
71 PG_FUNCTION_INFO_V1(ghstore_in
);
72 Datum
ghstore_in(PG_FUNCTION_ARGS
);
74 PG_FUNCTION_INFO_V1(ghstore_out
);
75 Datum
ghstore_out(PG_FUNCTION_ARGS
);
79 ghstore_in(PG_FUNCTION_ARGS
)
81 elog(ERROR
, "Not implemented");
86 ghstore_out(PG_FUNCTION_ARGS
)
88 elog(ERROR
, "Not implemented");
92 PG_FUNCTION_INFO_V1(ghstore_consistent
);
93 PG_FUNCTION_INFO_V1(ghstore_compress
);
94 PG_FUNCTION_INFO_V1(ghstore_decompress
);
95 PG_FUNCTION_INFO_V1(ghstore_penalty
);
96 PG_FUNCTION_INFO_V1(ghstore_picksplit
);
97 PG_FUNCTION_INFO_V1(ghstore_union
);
98 PG_FUNCTION_INFO_V1(ghstore_same
);
100 Datum
ghstore_consistent(PG_FUNCTION_ARGS
);
101 Datum
ghstore_compress(PG_FUNCTION_ARGS
);
102 Datum
ghstore_decompress(PG_FUNCTION_ARGS
);
103 Datum
ghstore_penalty(PG_FUNCTION_ARGS
);
104 Datum
ghstore_picksplit(PG_FUNCTION_ARGS
);
105 Datum
ghstore_union(PG_FUNCTION_ARGS
);
106 Datum
ghstore_same(PG_FUNCTION_ARGS
);
109 ghstore_compress(PG_FUNCTION_ARGS
)
111 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
112 GISTENTRY
*retval
= entry
;
116 GISTTYPE
*res
= (GISTTYPE
*) palloc0(CALCGTSIZE(0));
117 HStore
*toastedval
= (HStore
*) DatumGetPointer(entry
->key
);
118 HStore
*val
= (HStore
*) DatumGetPointer(PG_DETOAST_DATUM(entry
->key
));
119 HEntry
*ptr
= ARRPTR(val
);
120 char *words
= STRPTR(val
);
122 SET_VARSIZE(res
, CALCGTSIZE(0));
124 while (ptr
- ARRPTR(val
) < val
->size
)
128 h
= crc32_sz((char *) (words
+ ptr
->pos
), ptr
->keylen
);
129 HASH(GETSIGN(res
), h
);
132 h
= crc32_sz((char *) (words
+ ptr
->pos
+ ptr
->keylen
), ptr
->vallen
);
133 HASH(GETSIGN(res
), h
);
138 if (val
!= toastedval
)
141 retval
= (GISTENTRY
*) palloc(sizeof(GISTENTRY
));
142 gistentryinit(*retval
, PointerGetDatum(res
),
143 entry
->rel
, entry
->page
,
147 else if (!ISALLTRUE(DatumGetPointer(entry
->key
)))
151 BITVECP sign
= GETSIGN(DatumGetPointer(entry
->key
));
155 if ((sign
[i
] & 0xff) != 0xff)
156 PG_RETURN_POINTER(retval
);
159 res
= (GISTTYPE
*) palloc(CALCGTSIZE(ALLISTRUE
));
160 SET_VARSIZE(res
, CALCGTSIZE(ALLISTRUE
));
161 res
->flag
= ALLISTRUE
;
163 retval
= (GISTENTRY
*) palloc(sizeof(GISTENTRY
));
164 gistentryinit(*retval
, PointerGetDatum(res
),
165 entry
->rel
, entry
->page
,
170 PG_RETURN_POINTER(retval
);
174 ghstore_decompress(PG_FUNCTION_ARGS
)
176 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
180 key
= (HStore
*) PG_DETOAST_DATUM(entry
->key
);
182 if (key
!= (HStore
*) DatumGetPointer(entry
->key
))
184 /* need to pass back the decompressed item */
185 retval
= palloc(sizeof(GISTENTRY
));
186 gistentryinit(*retval
, PointerGetDatum(key
),
187 entry
->rel
, entry
->page
, entry
->offset
, entry
->leafkey
);
188 PG_RETURN_POINTER(retval
);
192 /* we can return the entry as-is */
193 PG_RETURN_POINTER(entry
);
198 ghstore_same(PG_FUNCTION_ARGS
)
200 GISTTYPE
*a
= (GISTTYPE
*) PG_GETARG_POINTER(0);
201 GISTTYPE
*b
= (GISTTYPE
*) PG_GETARG_POINTER(1);
202 bool *result
= (bool *) PG_GETARG_POINTER(2);
204 if (ISALLTRUE(a
) && ISALLTRUE(b
))
206 else if (ISALLTRUE(a
))
208 else if (ISALLTRUE(b
))
213 BITVECP sa
= GETSIGN(a
),
226 PG_RETURN_POINTER(result
);
230 sizebitvec(BITVECP sign
)
237 size
+= SUMBIT(sign
);
238 sign
= (BITVECP
) (((char *) sign
) + 1);
244 hemdistsign(BITVECP a
, BITVECP b
)
251 if (GETBIT(a
, i
) != GETBIT(b
, i
))
258 hemdist(GISTTYPE
* a
, GISTTYPE
* b
)
265 return SIGLENBIT
- sizebitvec(GETSIGN(b
));
267 else if (ISALLTRUE(b
))
268 return SIGLENBIT
- sizebitvec(GETSIGN(a
));
270 return hemdistsign(GETSIGN(a
), GETSIGN(b
));
274 unionkey(BITVECP sbase
, GISTTYPE
* add
)
277 BITVECP sadd
= GETSIGN(add
);
287 ghstore_union(PG_FUNCTION_ARGS
)
289 GistEntryVector
*entryvec
= (GistEntryVector
*) PG_GETARG_POINTER(0);
290 int4 len
= entryvec
->n
;
292 int *size
= (int *) PG_GETARG_POINTER(1);
298 MemSet((void *) base
, 0, sizeof(BITVEC
));
299 for (i
= 0; i
< len
; i
++)
301 if (unionkey(base
, GETENTRY(entryvec
, i
)))
308 len
= CALCGTSIZE(flag
);
309 result
= (GISTTYPE
*) palloc(len
);
310 SET_VARSIZE(result
, len
);
312 if (!ISALLTRUE(result
))
313 memcpy((void *) GETSIGN(result
), (void *) base
, sizeof(BITVEC
));
316 PG_RETURN_POINTER(result
);
320 ghstore_penalty(PG_FUNCTION_ARGS
)
322 GISTENTRY
*origentry
= (GISTENTRY
*) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
323 GISTENTRY
*newentry
= (GISTENTRY
*) PG_GETARG_POINTER(1);
324 float *penalty
= (float *) PG_GETARG_POINTER(2);
325 GISTTYPE
*origval
= (GISTTYPE
*) DatumGetPointer(origentry
->key
);
326 GISTTYPE
*newval
= (GISTTYPE
*) DatumGetPointer(newentry
->key
);
328 *penalty
= hemdist(origval
, newval
);
329 PG_RETURN_POINTER(penalty
);
340 comparecost(const void *a
, const void *b
)
342 return ((SPLITCOST
*) a
)->cost
- ((SPLITCOST
*) b
)->cost
;
347 ghstore_picksplit(PG_FUNCTION_ARGS
)
349 GistEntryVector
*entryvec
= (GistEntryVector
*) PG_GETARG_POINTER(0);
350 OffsetNumber maxoff
= entryvec
->n
- 2;
352 GIST_SPLITVEC
*v
= (GIST_SPLITVEC
*) PG_GETARG_POINTER(1);
364 OffsetNumber seed_1
= 0,
370 SPLITCOST
*costvector
;
374 nbytes
= (maxoff
+ 2) * sizeof(OffsetNumber
);
375 v
->spl_left
= (OffsetNumber
*) palloc(nbytes
);
376 v
->spl_right
= (OffsetNumber
*) palloc(nbytes
);
378 for (k
= FirstOffsetNumber
; k
< maxoff
; k
= OffsetNumberNext(k
))
380 _k
= GETENTRY(entryvec
, k
);
381 for (j
= OffsetNumberNext(k
); j
<= maxoff
; j
= OffsetNumberNext(j
))
383 size_waste
= hemdist(_k
, GETENTRY(entryvec
, j
));
384 if (size_waste
> waste
)
395 right
= v
->spl_right
;
398 if (seed_1
== 0 || seed_2
== 0)
404 /* form initial .. */
405 if (ISALLTRUE(GETENTRY(entryvec
, seed_1
)))
407 datum_l
= (GISTTYPE
*) palloc(GTHDRSIZE
);
408 SET_VARSIZE(datum_l
, GTHDRSIZE
);
409 datum_l
->flag
= ALLISTRUE
;
413 datum_l
= (GISTTYPE
*) palloc(GTHDRSIZE
+ SIGLEN
);
414 SET_VARSIZE(datum_l
, GTHDRSIZE
+ SIGLEN
);
416 memcpy((void *) GETSIGN(datum_l
), (void *) GETSIGN(GETENTRY(entryvec
, seed_1
)), sizeof(BITVEC
))
419 if (ISALLTRUE(GETENTRY(entryvec
, seed_2
)))
421 datum_r
= (GISTTYPE
*) palloc(GTHDRSIZE
);
422 SET_VARSIZE(datum_r
, GTHDRSIZE
);
423 datum_r
->flag
= ALLISTRUE
;
427 datum_r
= (GISTTYPE
*) palloc(GTHDRSIZE
+ SIGLEN
);
428 SET_VARSIZE(datum_r
, GTHDRSIZE
+ SIGLEN
);
430 memcpy((void *) GETSIGN(datum_r
), (void *) GETSIGN(GETENTRY(entryvec
, seed_2
)), sizeof(BITVEC
));
433 maxoff
= OffsetNumberNext(maxoff
);
434 /* sort before ... */
435 costvector
= (SPLITCOST
*) palloc(sizeof(SPLITCOST
) * maxoff
);
436 for (j
= FirstOffsetNumber
; j
<= maxoff
; j
= OffsetNumberNext(j
))
438 costvector
[j
- 1].pos
= j
;
439 _j
= GETENTRY(entryvec
, j
);
440 size_alpha
= hemdist(datum_l
, _j
);
441 size_beta
= hemdist(datum_r
, _j
);
442 costvector
[j
- 1].cost
= abs(size_alpha
- size_beta
);
444 qsort((void *) costvector
, maxoff
, sizeof(SPLITCOST
), comparecost
);
446 union_l
= GETSIGN(datum_l
);
447 union_r
= GETSIGN(datum_r
);
449 for (k
= 0; k
< maxoff
; k
++)
451 j
= costvector
[k
].pos
;
458 else if (j
== seed_2
)
464 _j
= GETENTRY(entryvec
, j
);
465 size_alpha
= hemdist(datum_l
, _j
);
466 size_beta
= hemdist(datum_r
, _j
);
468 if (size_alpha
< size_beta
+ WISH_F(v
->spl_nleft
, v
->spl_nright
, 0.0001))
470 if (ISALLTRUE(datum_l
) || ISALLTRUE(_j
))
472 if (!ISALLTRUE(datum_l
))
473 MemSet((void *) union_l
, 0xff, sizeof(BITVEC
));
479 union_l
[i
] |= ptr
[i
];
486 if (ISALLTRUE(datum_r
) || ISALLTRUE(_j
))
488 if (!ISALLTRUE(datum_r
))
489 MemSet((void *) union_r
, 0xff, sizeof(BITVEC
));
495 union_r
[i
] |= ptr
[i
];
502 *right
= *left
= FirstOffsetNumber
;
505 v
->spl_ldatum
= PointerGetDatum(datum_l
);
506 v
->spl_rdatum
= PointerGetDatum(datum_r
);
508 PG_RETURN_POINTER(v
);
513 ghstore_consistent(PG_FUNCTION_ARGS
)
515 GISTTYPE
*entry
= (GISTTYPE
*) DatumGetPointer(((GISTENTRY
*) PG_GETARG_POINTER(0))->key
);
516 StrategyNumber strategy
= (StrategyNumber
) PG_GETARG_UINT16(2);
517 /* Oid subtype = PG_GETARG_OID(3); */
518 bool *recheck
= (bool *) PG_GETARG_POINTER(4);
522 /* All cases served by this function are inexact */
525 if (ISALLTRUE(entry
))
526 PG_RETURN_BOOL(true);
528 sign
= GETSIGN(entry
);
530 if (strategy
== HStoreContainsStrategyNumber
|| strategy
== 13 /* hack for old strats */ )
532 HStore
*query
= PG_GETARG_HS(1);
533 HEntry
*qe
= ARRPTR(query
);
534 char *qv
= STRPTR(query
);
536 while (res
&& qe
- ARRPTR(query
) < query
->size
)
538 int crc
= crc32_sz((char *) (qv
+ qe
->pos
), qe
->keylen
);
540 if (GETBIT(sign
, HASHVAL(crc
)))
544 crc
= crc32_sz((char *) (qv
+ qe
->pos
+ qe
->keylen
), qe
->vallen
);
545 if (!GETBIT(sign
, HASHVAL(crc
)))
554 else if (strategy
== HStoreExistsStrategyNumber
)
556 text
*query
= PG_GETARG_TEXT_P(1);
557 int crc
= crc32_sz(VARDATA(query
), VARSIZE(query
) - VARHDRSZ
);
559 res
= (GETBIT(sign
, HASHVAL(crc
))) ? true : false;
562 elog(ERROR
, "Unsupported strategy number: %d", strategy
);