2 #include "utils/array.h"
3 #include "catalog/pg_type.h"
5 #include <access/heapam.h>
10 findkey(HStore *hs, char *key, int keylen) {
11 HEntry *StopLow = ARRPTR(hs);
12 HEntry *StopHigh = StopLow + hs->size;
15 char *base = STRPTR(hs);
17 while (StopLow < StopHigh) {
18 StopMiddle = StopLow + (StopHigh - StopLow) / 2;
20 if ( StopMiddle->keylen == keylen )
21 difference=strncmp(base+StopMiddle->pos, key, StopMiddle->keylen);
23 difference=(StopMiddle->keylen > keylen) ? 1 : -1;
27 else if (difference < 0)
28 StopLow = StopMiddle + 1;
30 StopHigh = StopMiddle;
36 PG_FUNCTION_INFO_V1(fetchval);
37 Datum fetchval(PG_FUNCTION_ARGS);
39 fetchval(PG_FUNCTION_ARGS) {
40 HStore *hs = PG_GETARG_HS(0);
41 text *key = PG_GETARG_TEXT_P(1);
45 if ((entry=findkey(hs,VARDATA(key), VARSIZE(key)-VARHDRSZ))==NULL || entry->valisnull) {
46 PG_FREE_IF_COPY(hs,0);
47 PG_FREE_IF_COPY(key,1);
51 out=palloc(VARHDRSZ+entry->vallen);
52 memcpy(VARDATA(out),STRPTR(hs) + entry->pos + entry->keylen, entry->vallen);
53 VARATT_SIZEP(out) = VARHDRSZ+entry->vallen;
55 PG_FREE_IF_COPY(hs,0);
56 PG_FREE_IF_COPY(key,1);
57 PG_RETURN_POINTER(out);
60 PG_FUNCTION_INFO_V1(exists);
61 Datum exists(PG_FUNCTION_ARGS);
63 exists(PG_FUNCTION_ARGS) {
64 HStore *hs = PG_GETARG_HS(0);
65 text *key = PG_GETARG_TEXT_P(1);
68 entry=findkey(hs,VARDATA(key), VARSIZE(key)-VARHDRSZ);
70 PG_FREE_IF_COPY(hs,0);
71 PG_FREE_IF_COPY(key,1);
73 PG_RETURN_BOOL(entry);
76 PG_FUNCTION_INFO_V1(defined);
77 Datum defined(PG_FUNCTION_ARGS);
79 defined(PG_FUNCTION_ARGS) {
80 HStore *hs = PG_GETARG_HS(0);
81 text *key = PG_GETARG_TEXT_P(1);
85 entry=findkey(hs,VARDATA(key), VARSIZE(key)-VARHDRSZ);
87 res = ( entry && !entry->valisnull ) ? true : false;
89 PG_FREE_IF_COPY(hs,0);
90 PG_FREE_IF_COPY(key,1);
95 PG_FUNCTION_INFO_V1(delete);
96 Datum delete(PG_FUNCTION_ARGS);
98 delete(PG_FUNCTION_ARGS) {
99 HStore *hs = PG_GETARG_HS(0);
100 text *key = PG_GETARG_TEXT_P(1);
101 HStore *out = palloc(hs->len);
106 out->size=hs->size; /* temprorary! */
113 while( es - ARRPTR(hs) < hs->size ) {
114 if ( !(es->keylen == VARSIZE(key) - VARHDRSZ && strncmp(ptrs, VARDATA(key), es->keylen)==0) ) {
115 memcpy( ed, es, sizeof(HEntry) );
116 memcpy( ptrd, ptrs, es->keylen + ( (es->valisnull) ? 0 : es->vallen ) );
117 ed->pos = ptrd - STRPTR(out);
118 ptrd += es->keylen + ( (es->valisnull) ? 0 : es->vallen );
121 ptrs += es->keylen + ( (es->valisnull) ? 0 : es->vallen );
125 if ( ed - ARRPTR(out) != out->size ) {
126 int buflen=ptrd-STRPTR(out);
129 out->size = ed - ARRPTR(out);
131 memmove( STRPTR(out), ptrd, buflen);
132 out->len = CALCDATASIZE(out->size, buflen);
136 PG_FREE_IF_COPY(hs,0);
137 PG_FREE_IF_COPY(key,1);
139 PG_RETURN_POINTER(out);
142 PG_FUNCTION_INFO_V1(hs_concat);
143 Datum hs_concat(PG_FUNCTION_ARGS);
145 hs_concat(PG_FUNCTION_ARGS) {
146 HStore *s1 = PG_GETARG_HS(0);
147 HStore *s2 = PG_GETARG_HS(1);
148 HStore *out = palloc( s1->len + s2->len );
149 char *ps1, *ps2, *pd;
150 HEntry *es1, *es2, *ed;
152 out->len = s1->len + s2->len;
153 out->size = s1->size + s2->size;
162 while( es1 - ARRPTR(s1) < s1->size && es2 - ARRPTR(s2) < s2->size ) {
164 if ( es1->keylen == es2->keylen )
165 difference=strncmp(ps1, ps2, es1->keylen);
167 difference=(es1->keylen > es2->keylen) ? 1 : -1;
169 if ( difference == 0 ) {
170 memcpy( ed, es2, sizeof(HEntry) );
171 memcpy( pd, ps2, es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ) );
172 ed->pos = pd - STRPTR(out);
173 pd += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
176 ps1 += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen );
178 ps2 += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
180 } else if ( difference > 0 ) {
181 memcpy( ed, es2, sizeof(HEntry) );
182 memcpy( pd, ps2, es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ) );
183 ed->pos = pd - STRPTR(out);
184 pd += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
187 ps2 += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
190 memcpy( ed, es1, sizeof(HEntry) );
191 memcpy( pd, ps1, es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen ) );
192 ed->pos = pd - STRPTR(out);
193 pd += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen );
196 ps1 += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen );
201 while( es1 - ARRPTR(s1) < s1->size ) {
202 memcpy( ed, es1, sizeof(HEntry) );
203 memcpy( pd, ps1, es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen ) );
204 ed->pos = pd - STRPTR(out);
205 pd += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen );
208 ps1 += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen );
212 while( es2 - ARRPTR(s2) < s2->size ) {
213 memcpy( ed, es2, sizeof(HEntry) );
214 memcpy( pd, ps2, es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ) );
215 ed->pos = pd - STRPTR(out);
216 pd += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
219 ps2 += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
223 if ( ed - ARRPTR(out) != out->size ) {
224 int buflen=pd-STRPTR(out);
227 out->size = ed - ARRPTR(out);
229 memmove( STRPTR(out), pd, buflen);
230 out->len = CALCDATASIZE(out->size, buflen);
233 PG_FREE_IF_COPY(s1,0);
234 PG_FREE_IF_COPY(s2,1);
236 PG_RETURN_POINTER(out);
239 PG_FUNCTION_INFO_V1(tconvert);
240 Datum tconvert(PG_FUNCTION_ARGS);
242 tconvert(PG_FUNCTION_ARGS) {
243 text *key = PG_GETARG_TEXT_P(0);
244 text *val = PG_GETARG_TEXT_P(1);
248 len=CALCDATASIZE(1, VARSIZE(key) + VARSIZE(val) - 2*VARHDRSZ);
253 ARRPTR(out)->keylen = VARSIZE(key) - VARHDRSZ;
254 ARRPTR(out)->vallen = VARSIZE(val) - VARHDRSZ;
255 ARRPTR(out)->valisnull = false;
258 memcpy( STRPTR(out), VARDATA(key), ARRPTR(out)->keylen );
259 memcpy( STRPTR(out) + ARRPTR(out)->keylen, VARDATA(val), ARRPTR(out)->vallen );
261 PG_FREE_IF_COPY(key,0);
262 PG_FREE_IF_COPY(val,1);
264 PG_RETURN_POINTER(out);
267 PG_FUNCTION_INFO_V1(akeys);
268 Datum akeys(PG_FUNCTION_ARGS);
270 akeys(PG_FUNCTION_ARGS) {
271 HStore *hs = PG_GETARG_HS(0);
274 HEntry *ptr=ARRPTR(hs);
275 char *base=STRPTR(hs);
277 d=(Datum*)palloc(sizeof(Datum)*(hs->size+1));
278 while( ptr-ARRPTR(hs) < hs->size ) {
279 text *item=(text*)palloc(VARHDRSZ + ptr->keylen);
280 VARATT_SIZEP(item) = VARHDRSZ+ptr->keylen;
281 memcpy(VARDATA(item), base + ptr->pos, ptr->keylen);
282 d[ ptr-ARRPTR(hs) ] = PointerGetDatum(item);
296 while( ptr-ARRPTR(hs) < hs->size ) {
297 pfree(DatumGetPointer(d[ ptr-ARRPTR(hs) ]));
302 PG_FREE_IF_COPY(hs,0);
304 PG_RETURN_POINTER(a);
307 PG_FUNCTION_INFO_V1(avals);
308 Datum avals(PG_FUNCTION_ARGS);
310 avals(PG_FUNCTION_ARGS) {
311 HStore *hs = PG_GETARG_HS(0);
314 HEntry *ptr=ARRPTR(hs);
315 char *base=STRPTR(hs);
317 d=(Datum*)palloc(sizeof(Datum)*(hs->size+1));
318 while( ptr-ARRPTR(hs) < hs->size ) {
319 int vallen = (ptr->valisnull) ? 0 : ptr->vallen;
320 text *item=(text*)palloc(VARHDRSZ + vallen);
321 VARATT_SIZEP(item) = VARHDRSZ+vallen;
322 memcpy(VARDATA(item), base + ptr->pos + ptr->keylen, vallen);
323 d[ ptr-ARRPTR(hs) ] = PointerGetDatum(item);
337 while( ptr-ARRPTR(hs) < hs->size ) {
338 pfree(DatumGetPointer(d[ ptr-ARRPTR(hs) ]));
343 PG_FREE_IF_COPY(hs,0);
345 PG_RETURN_POINTER(a);
354 setup_firstcall(FuncCallContext *funcctx, HStore *hs) {
355 MemoryContext oldcontext;
358 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
360 st=(AKStore*)palloc( sizeof(AKStore) );
362 st->hs = (HStore*)palloc(hs->len);
363 memcpy( st->hs, hs, hs->len );
365 funcctx->user_fctx = (void*)st;
366 MemoryContextSwitchTo(oldcontext);
369 PG_FUNCTION_INFO_V1(skeys);
370 Datum skeys(PG_FUNCTION_ARGS);
372 skeys(PG_FUNCTION_ARGS) {
373 FuncCallContext *funcctx;
376 if (SRF_IS_FIRSTCALL()) {
377 HStore *hs = PG_GETARG_HS(0);
378 funcctx = SRF_FIRSTCALL_INIT();
379 setup_firstcall(funcctx, hs);
380 PG_FREE_IF_COPY(hs,0);
383 funcctx = SRF_PERCALL_SETUP();
384 st = (AKStore*)funcctx->user_fctx;
386 if ( st->i < st->hs->size ) {
387 HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
388 text *item=(text*)palloc(VARHDRSZ + ptr->keylen);
390 VARATT_SIZEP(item) = VARHDRSZ+ptr->keylen;
391 memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos, ptr->keylen);
394 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
400 SRF_RETURN_DONE(funcctx);
403 PG_FUNCTION_INFO_V1(svals);
404 Datum svals(PG_FUNCTION_ARGS);
406 svals(PG_FUNCTION_ARGS) {
407 FuncCallContext *funcctx;
410 if (SRF_IS_FIRSTCALL()) {
411 HStore *hs = PG_GETARG_HS(0);
412 funcctx = SRF_FIRSTCALL_INIT();
413 setup_firstcall(funcctx, hs);
414 PG_FREE_IF_COPY(hs,0);
417 funcctx = SRF_PERCALL_SETUP();
418 st = (AKStore*)funcctx->user_fctx;
420 if ( st->i < st->hs->size ) {
421 HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
423 if ( ptr->valisnull ) {
427 (funcctx)->call_cntr++;
428 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
429 rsi->isDone = ExprMultipleResult;
432 int vallen = ptr->vallen;
433 text *item=(text*)palloc(VARHDRSZ + vallen);
435 VARATT_SIZEP(item) = VARHDRSZ+vallen;
436 memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos + ptr->keylen, vallen);
439 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
446 SRF_RETURN_DONE(funcctx);
449 PG_FUNCTION_INFO_V1(hs_contains);
450 Datum hs_contains(PG_FUNCTION_ARGS);
452 hs_contains(PG_FUNCTION_ARGS) {
453 HStore *val = PG_GETARG_HS(0);
454 HStore *tmpl = PG_GETARG_HS(1);
456 HEntry *te = ARRPTR(tmpl);
457 char *vv = STRPTR(val);
458 char *tv = STRPTR(tmpl);
460 while(res && te-ARRPTR(tmpl) < tmpl->size) {
461 HEntry *entry = findkey(val, tv + te->pos, te->keylen);
463 if ( ! te->valisnull ) {
464 if ( entry->valisnull || !(
465 te->vallen==entry->vallen &&
467 vv + entry->pos + entry->keylen,
468 tv + te->pos + te->keylen,
478 PG_FREE_IF_COPY(val,0);
479 PG_FREE_IF_COPY(tmpl,1);
484 PG_FUNCTION_INFO_V1(hs_contained);
485 Datum hs_contained(PG_FUNCTION_ARGS);
487 hs_contained(PG_FUNCTION_ARGS) {
488 PG_RETURN_DATUM( DirectFunctionCall2(
495 PG_FUNCTION_INFO_V1(each);
496 Datum each(PG_FUNCTION_ARGS);
498 each(PG_FUNCTION_ARGS) {
499 FuncCallContext *funcctx;
502 if (SRF_IS_FIRSTCALL()) {
504 MemoryContext oldcontext;
505 HStore *hs = PG_GETARG_HS(0);
507 funcctx = SRF_FIRSTCALL_INIT();
508 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
509 st=(AKStore*)palloc( sizeof(AKStore) );
511 st->hs = (HStore*)palloc(hs->len);
512 memcpy( st->hs, hs, hs->len );
513 funcctx->user_fctx = (void*)st;
515 tupdesc = RelationNameGetTupleDesc("hs_each");
516 funcctx->slot = TupleDescGetSlot(tupdesc);
517 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
519 MemoryContextSwitchTo(oldcontext);
520 PG_FREE_IF_COPY(hs,0);
523 funcctx = SRF_PERCALL_SETUP();
524 st = (AKStore*)funcctx->user_fctx;
526 if ( st->i < st->hs->size ) {
527 HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
528 Datum res, dvalues[2];
529 char nulls[] = {' ', ' '};
533 item=(text*)palloc(VARHDRSZ + ptr->keylen);
534 VARATT_SIZEP(item) = VARHDRSZ+ptr->keylen;
535 memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos, ptr->keylen);
536 dvalues[0] = PointerGetDatum(item);
538 if ( ptr->valisnull ) {
542 int vallen = ptr->vallen;
544 item=(text*)palloc(VARHDRSZ + vallen);
545 VARATT_SIZEP(item) = VARHDRSZ+vallen;
546 memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos + ptr->keylen, vallen);
547 dvalues[1] = PointerGetDatum(item);
551 tuple = heap_formtuple(funcctx->attinmeta->tupdesc, dvalues, nulls);
552 res = TupleGetDatum(funcctx->slot, tuple);
554 pfree( DatumGetPointer(dvalues[0]) );
555 if ( nulls[1] != 'n' )
556 pfree( DatumGetPointer(dvalues[1]) );
558 SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
564 SRF_RETURN_DONE(funcctx);