Start background writer during archive recovery. Background writer now performs
[PostgreSQL.git] / contrib / hstore / hstore_gist.c
blobdc9405cb1018c7cda43f93357677ab7670e43cd3
1 /*
2 * $PostgreSQL$
3 */
4 #include "postgres.h"
6 #include "access/gist.h"
7 #include "access/itup.h"
8 #include "access/skey.h"
9 #include "crc32.h"
11 #include "hstore.h"
13 /* bigint defines */
14 #define BITBYTE 8
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) )
25 #define LOOPBYTE \
26 for(i=0;i<SIGLEN;i++)
28 #define LOOPBIT \
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))
40 typedef struct
42 int32 vl_len_; /* varlena header (do not touch directly!) */
43 int4 flag;
44 char data[1];
45 } GISTTYPE;
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) + \
64 GETBITBYTE((val),7) \
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);
78 Datum
79 ghstore_in(PG_FUNCTION_ARGS)
81 elog(ERROR, "Not implemented");
82 PG_RETURN_DATUM(0);
85 Datum
86 ghstore_out(PG_FUNCTION_ARGS)
88 elog(ERROR, "Not implemented");
89 PG_RETURN_DATUM(0);
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);
108 Datum
109 ghstore_compress(PG_FUNCTION_ARGS)
111 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
112 GISTENTRY *retval = entry;
114 if (entry->leafkey)
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)
126 int h;
128 h = crc32_sz((char *) (words + ptr->pos), ptr->keylen);
129 HASH(GETSIGN(res), h);
130 if (!ptr->valisnull)
132 h = crc32_sz((char *) (words + ptr->pos + ptr->keylen), ptr->vallen);
133 HASH(GETSIGN(res), h);
135 ptr++;
138 if (val != toastedval)
139 pfree(val);
141 retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
142 gistentryinit(*retval, PointerGetDatum(res),
143 entry->rel, entry->page,
144 entry->offset,
145 FALSE);
147 else if (!ISALLTRUE(DatumGetPointer(entry->key)))
149 int4 i;
150 GISTTYPE *res;
151 BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
153 LOOPBYTE
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,
166 entry->offset,
167 FALSE);
170 PG_RETURN_POINTER(retval);
173 Datum
174 ghstore_decompress(PG_FUNCTION_ARGS)
176 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
177 GISTENTRY *retval;
178 HStore *key;
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);
190 else
192 /* we can return the entry as-is */
193 PG_RETURN_POINTER(entry);
197 Datum
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))
205 *result = true;
206 else if (ISALLTRUE(a))
207 *result = false;
208 else if (ISALLTRUE(b))
209 *result = false;
210 else
212 int4 i;
213 BITVECP sa = GETSIGN(a),
214 sb = GETSIGN(b);
216 *result = true;
217 LOOPBYTE
219 if (sa[i] != sb[i])
221 *result = false;
222 break;
226 PG_RETURN_POINTER(result);
229 static int4
230 sizebitvec(BITVECP sign)
232 int4 size = 0,
235 LOOPBYTE
237 size += SUMBIT(sign);
238 sign = (BITVECP) (((char *) sign) + 1);
240 return size;
243 static int
244 hemdistsign(BITVECP a, BITVECP b)
246 int i,
247 dist = 0;
249 LOOPBIT
251 if (GETBIT(a, i) != GETBIT(b, i))
252 dist++;
254 return dist;
257 static int
258 hemdist(GISTTYPE * a, GISTTYPE * b)
260 if (ISALLTRUE(a))
262 if (ISALLTRUE(b))
263 return 0;
264 else
265 return SIGLENBIT - sizebitvec(GETSIGN(b));
267 else if (ISALLTRUE(b))
268 return SIGLENBIT - sizebitvec(GETSIGN(a));
270 return hemdistsign(GETSIGN(a), GETSIGN(b));
273 static int4
274 unionkey(BITVECP sbase, GISTTYPE * add)
276 int4 i;
277 BITVECP sadd = GETSIGN(add);
279 if (ISALLTRUE(add))
280 return 1;
281 LOOPBYTE
282 sbase[i] |= sadd[i];
283 return 0;
286 Datum
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);
293 BITVEC base;
294 int4 i;
295 int4 flag = 0;
296 GISTTYPE *result;
298 MemSet((void *) base, 0, sizeof(BITVEC));
299 for (i = 0; i < len; i++)
301 if (unionkey(base, GETENTRY(entryvec, i)))
303 flag = ALLISTRUE;
304 break;
308 len = CALCGTSIZE(flag);
309 result = (GISTTYPE *) palloc(len);
310 SET_VARSIZE(result, len);
311 result->flag = flag;
312 if (!ISALLTRUE(result))
313 memcpy((void *) GETSIGN(result), (void *) base, sizeof(BITVEC));
314 *size = len;
316 PG_RETURN_POINTER(result);
319 Datum
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);
333 typedef struct
335 OffsetNumber pos;
336 int4 cost;
337 } SPLITCOST;
339 static int
340 comparecost(const void *a, const void *b)
342 return ((SPLITCOST *) a)->cost - ((SPLITCOST *) b)->cost;
346 Datum
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);
353 OffsetNumber k,
355 GISTTYPE *datum_l,
356 *datum_r;
357 BITVECP union_l,
358 union_r;
359 int4 size_alpha,
360 size_beta;
361 int4 size_waste,
362 waste = -1;
363 int4 nbytes;
364 OffsetNumber seed_1 = 0,
365 seed_2 = 0;
366 OffsetNumber *left,
367 *right;
368 BITVECP ptr;
369 int i;
370 SPLITCOST *costvector;
371 GISTTYPE *_k,
372 *_j;
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)
386 waste = size_waste;
387 seed_1 = k;
388 seed_2 = j;
393 left = v->spl_left;
394 v->spl_nleft = 0;
395 right = v->spl_right;
396 v->spl_nright = 0;
398 if (seed_1 == 0 || seed_2 == 0)
400 seed_1 = 1;
401 seed_2 = 2;
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;
411 else
413 datum_l = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
414 SET_VARSIZE(datum_l, GTHDRSIZE + SIGLEN);
415 datum_l->flag = 0;
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;
425 else
427 datum_r = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
428 SET_VARSIZE(datum_r, GTHDRSIZE + SIGLEN);
429 datum_r->flag = 0;
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;
452 if (j == seed_1)
454 *left++ = j;
455 v->spl_nleft++;
456 continue;
458 else if (j == seed_2)
460 *right++ = j;
461 v->spl_nright++;
462 continue;
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));
475 else
477 ptr = GETSIGN(_j);
478 LOOPBYTE
479 union_l[i] |= ptr[i];
481 *left++ = j;
482 v->spl_nleft++;
484 else
486 if (ISALLTRUE(datum_r) || ISALLTRUE(_j))
488 if (!ISALLTRUE(datum_r))
489 MemSet((void *) union_r, 0xff, sizeof(BITVEC));
491 else
493 ptr = GETSIGN(_j);
494 LOOPBYTE
495 union_r[i] |= ptr[i];
497 *right++ = j;
498 v->spl_nright++;
502 *right = *left = FirstOffsetNumber;
503 pfree(costvector);
505 v->spl_ldatum = PointerGetDatum(datum_l);
506 v->spl_rdatum = PointerGetDatum(datum_r);
508 PG_RETURN_POINTER(v);
512 Datum
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);
519 bool res = true;
520 BITVECP sign;
522 /* All cases served by this function are inexact */
523 *recheck = true;
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)))
542 if (!qe->valisnull)
544 crc = crc32_sz((char *) (qv + qe->pos + qe->keylen), qe->vallen);
545 if (!GETBIT(sign, HASHVAL(crc)))
546 res = false;
549 else
550 res = false;
551 qe++;
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;
561 else
562 elog(ERROR, "Unsupported strategy number: %d", strategy);
564 PG_RETURN_BOOL(res);