6 #include "catalog/pg_type.h"
8 #include "utils/array.h"
9 #include "utils/builtins.h"
15 findkey(HStore
* hs
, char *key
, int keylen
)
17 HEntry
*StopLow
= ARRPTR(hs
);
18 HEntry
*StopHigh
= StopLow
+ hs
->size
;
21 char *base
= STRPTR(hs
);
23 while (StopLow
< StopHigh
)
25 StopMiddle
= StopLow
+ (StopHigh
- StopLow
) / 2;
27 if (StopMiddle
->keylen
== keylen
)
28 difference
= strncmp(base
+ StopMiddle
->pos
, key
, StopMiddle
->keylen
);
30 difference
= (StopMiddle
->keylen
> keylen
) ? 1 : -1;
34 else if (difference
< 0)
35 StopLow
= StopMiddle
+ 1;
37 StopHigh
= StopMiddle
;
43 PG_FUNCTION_INFO_V1(fetchval
);
44 Datum
fetchval(PG_FUNCTION_ARGS
);
46 fetchval(PG_FUNCTION_ARGS
)
48 HStore
*hs
= PG_GETARG_HS(0);
49 text
*key
= PG_GETARG_TEXT_P(1);
53 if ((entry
= findkey(hs
, VARDATA(key
), VARSIZE(key
) - VARHDRSZ
)) == NULL
|| entry
->valisnull
)
55 PG_FREE_IF_COPY(hs
, 0);
56 PG_FREE_IF_COPY(key
, 1);
60 out
= cstring_to_text_with_len(STRPTR(hs
) + entry
->pos
+ entry
->keylen
,
63 PG_FREE_IF_COPY(hs
, 0);
64 PG_FREE_IF_COPY(key
, 1);
65 PG_RETURN_TEXT_P(out
);
68 PG_FUNCTION_INFO_V1(exists
);
69 Datum
exists(PG_FUNCTION_ARGS
);
71 exists(PG_FUNCTION_ARGS
)
73 HStore
*hs
= PG_GETARG_HS(0);
74 text
*key
= PG_GETARG_TEXT_P(1);
77 entry
= findkey(hs
, VARDATA(key
), VARSIZE(key
) - VARHDRSZ
);
79 PG_FREE_IF_COPY(hs
, 0);
80 PG_FREE_IF_COPY(key
, 1);
82 PG_RETURN_BOOL(entry
);
85 PG_FUNCTION_INFO_V1(defined
);
86 Datum
defined(PG_FUNCTION_ARGS
);
88 defined(PG_FUNCTION_ARGS
)
90 HStore
*hs
= PG_GETARG_HS(0);
91 text
*key
= PG_GETARG_TEXT_P(1);
95 entry
= findkey(hs
, VARDATA(key
), VARSIZE(key
) - VARHDRSZ
);
97 res
= (entry
&& !entry
->valisnull
) ? true : false;
99 PG_FREE_IF_COPY(hs
, 0);
100 PG_FREE_IF_COPY(key
, 1);
105 PG_FUNCTION_INFO_V1(delete);
106 Datum
delete(PG_FUNCTION_ARGS
);
108 delete(PG_FUNCTION_ARGS
)
110 HStore
*hs
= PG_GETARG_HS(0);
111 text
*key
= PG_GETARG_TEXT_P(1);
112 HStore
*out
= palloc(VARSIZE(hs
));
118 SET_VARSIZE(out
, VARSIZE(hs
));
119 out
->size
= hs
->size
; /* temporary! */
126 while (es
- ARRPTR(hs
) < hs
->size
)
128 if (!(es
->keylen
== VARSIZE(key
) - VARHDRSZ
&& strncmp(ptrs
, VARDATA(key
), es
->keylen
) == 0))
130 memcpy(ed
, es
, sizeof(HEntry
));
131 memcpy(ptrd
, ptrs
, es
->keylen
+ ((es
->valisnull
) ? 0 : es
->vallen
));
132 ed
->pos
= ptrd
- STRPTR(out
);
133 ptrd
+= es
->keylen
+ ((es
->valisnull
) ? 0 : es
->vallen
);
136 ptrs
+= es
->keylen
+ ((es
->valisnull
) ? 0 : es
->vallen
);
140 if (ed
- ARRPTR(out
) != out
->size
)
142 int buflen
= ptrd
- STRPTR(out
);
146 out
->size
= ed
- ARRPTR(out
);
148 memmove(STRPTR(out
), ptrd
, buflen
);
149 SET_VARSIZE(out
, CALCDATASIZE(out
->size
, buflen
));
153 PG_FREE_IF_COPY(hs
, 0);
154 PG_FREE_IF_COPY(key
, 1);
156 PG_RETURN_POINTER(out
);
159 PG_FUNCTION_INFO_V1(hs_concat
);
160 Datum
hs_concat(PG_FUNCTION_ARGS
);
162 hs_concat(PG_FUNCTION_ARGS
)
164 HStore
*s1
= PG_GETARG_HS(0);
165 HStore
*s2
= PG_GETARG_HS(1);
166 HStore
*out
= palloc(VARSIZE(s1
) + VARSIZE(s2
));
174 SET_VARSIZE(out
, VARSIZE(s1
) + VARSIZE(s2
));
175 out
->size
= s1
->size
+ s2
->size
;
184 while (es1
- ARRPTR(s1
) < s1
->size
&& es2
- ARRPTR(s2
) < s2
->size
)
188 if (es1
->keylen
== es2
->keylen
)
189 difference
= strncmp(ps1
, ps2
, es1
->keylen
);
191 difference
= (es1
->keylen
> es2
->keylen
) ? 1 : -1;
195 memcpy(ed
, es2
, sizeof(HEntry
));
196 memcpy(pd
, ps2
, es2
->keylen
+ ((es2
->valisnull
) ? 0 : es2
->vallen
));
197 ed
->pos
= pd
- STRPTR(out
);
198 pd
+= es2
->keylen
+ ((es2
->valisnull
) ? 0 : es2
->vallen
);
201 ps1
+= es1
->keylen
+ ((es1
->valisnull
) ? 0 : es1
->vallen
);
203 ps2
+= es2
->keylen
+ ((es2
->valisnull
) ? 0 : es2
->vallen
);
206 else if (difference
> 0)
208 memcpy(ed
, es2
, sizeof(HEntry
));
209 memcpy(pd
, ps2
, es2
->keylen
+ ((es2
->valisnull
) ? 0 : es2
->vallen
));
210 ed
->pos
= pd
- STRPTR(out
);
211 pd
+= es2
->keylen
+ ((es2
->valisnull
) ? 0 : es2
->vallen
);
214 ps2
+= es2
->keylen
+ ((es2
->valisnull
) ? 0 : es2
->vallen
);
219 memcpy(ed
, es1
, sizeof(HEntry
));
220 memcpy(pd
, ps1
, es1
->keylen
+ ((es1
->valisnull
) ? 0 : es1
->vallen
));
221 ed
->pos
= pd
- STRPTR(out
);
222 pd
+= es1
->keylen
+ ((es1
->valisnull
) ? 0 : es1
->vallen
);
225 ps1
+= es1
->keylen
+ ((es1
->valisnull
) ? 0 : es1
->vallen
);
230 while (es1
- ARRPTR(s1
) < s1
->size
)
232 memcpy(ed
, es1
, sizeof(HEntry
));
233 memcpy(pd
, ps1
, es1
->keylen
+ ((es1
->valisnull
) ? 0 : es1
->vallen
));
234 ed
->pos
= pd
- STRPTR(out
);
235 pd
+= es1
->keylen
+ ((es1
->valisnull
) ? 0 : es1
->vallen
);
238 ps1
+= es1
->keylen
+ ((es1
->valisnull
) ? 0 : es1
->vallen
);
242 while (es2
- ARRPTR(s2
) < s2
->size
)
244 memcpy(ed
, es2
, sizeof(HEntry
));
245 memcpy(pd
, ps2
, es2
->keylen
+ ((es2
->valisnull
) ? 0 : es2
->vallen
));
246 ed
->pos
= pd
- STRPTR(out
);
247 pd
+= es2
->keylen
+ ((es2
->valisnull
) ? 0 : es2
->vallen
);
250 ps2
+= es2
->keylen
+ ((es2
->valisnull
) ? 0 : es2
->vallen
);
254 if (ed
- ARRPTR(out
) != out
->size
)
256 int buflen
= pd
- STRPTR(out
);
260 out
->size
= ed
- ARRPTR(out
);
262 memmove(STRPTR(out
), pd
, buflen
);
263 SET_VARSIZE(out
, CALCDATASIZE(out
->size
, buflen
));
266 PG_FREE_IF_COPY(s1
, 0);
267 PG_FREE_IF_COPY(s2
, 1);
269 PG_RETURN_POINTER(out
);
272 PG_FUNCTION_INFO_V1(tconvert
);
273 Datum
tconvert(PG_FUNCTION_ARGS
);
275 tconvert(PG_FUNCTION_ARGS
)
285 key
= PG_GETARG_TEXT_P(0);
288 len
= CALCDATASIZE(1, VARSIZE(key
));
291 val
= PG_GETARG_TEXT_P(1);
292 len
= CALCDATASIZE(1, VARSIZE(key
) + VARSIZE(val
) - 2 * VARHDRSZ
);
295 SET_VARSIZE(out
, len
);
298 ARRPTR(out
)->keylen
= VARSIZE(key
) - VARHDRSZ
;
301 ARRPTR(out
)->vallen
= 0;
302 ARRPTR(out
)->valisnull
= true;
306 ARRPTR(out
)->vallen
= VARSIZE(val
) - VARHDRSZ
;
307 ARRPTR(out
)->valisnull
= false;
309 ARRPTR(out
)->pos
= 0;
311 memcpy(STRPTR(out
), VARDATA(key
), ARRPTR(out
)->keylen
);
312 if (!PG_ARGISNULL(1))
314 memcpy(STRPTR(out
) + ARRPTR(out
)->keylen
, VARDATA(val
), ARRPTR(out
)->vallen
);
315 PG_FREE_IF_COPY(val
, 1);
318 PG_FREE_IF_COPY(key
, 0);
320 PG_RETURN_POINTER(out
);
323 PG_FUNCTION_INFO_V1(akeys
);
324 Datum
akeys(PG_FUNCTION_ARGS
);
326 akeys(PG_FUNCTION_ARGS
)
328 HStore
*hs
= PG_GETARG_HS(0);
331 HEntry
*ptr
= ARRPTR(hs
);
332 char *base
= STRPTR(hs
);
334 d
= (Datum
*) palloc(sizeof(Datum
) * (hs
->size
+ 1));
335 while (ptr
- ARRPTR(hs
) < hs
->size
)
339 item
= cstring_to_text_with_len(base
+ ptr
->pos
, ptr
->keylen
);
340 d
[ptr
- ARRPTR(hs
)] = PointerGetDatum(item
);
344 a
= construct_array(d
,
352 while (ptr
- ARRPTR(hs
) < hs
->size
)
354 pfree(DatumGetPointer(d
[ptr
- ARRPTR(hs
)]));
359 PG_FREE_IF_COPY(hs
, 0);
361 PG_RETURN_POINTER(a
);
364 PG_FUNCTION_INFO_V1(avals
);
365 Datum
avals(PG_FUNCTION_ARGS
);
367 avals(PG_FUNCTION_ARGS
)
369 HStore
*hs
= PG_GETARG_HS(0);
372 HEntry
*ptr
= ARRPTR(hs
);
373 char *base
= STRPTR(hs
);
375 d
= (Datum
*) palloc(sizeof(Datum
) * (hs
->size
+ 1));
376 while (ptr
- ARRPTR(hs
) < hs
->size
)
380 item
= cstring_to_text_with_len(base
+ ptr
->pos
+ ptr
->keylen
,
381 (ptr
->valisnull
) ? 0 : ptr
->vallen
);
382 d
[ptr
- ARRPTR(hs
)] = PointerGetDatum(item
);
386 a
= construct_array(d
,
394 while (ptr
- ARRPTR(hs
) < hs
->size
)
396 pfree(DatumGetPointer(d
[ptr
- ARRPTR(hs
)]));
401 PG_FREE_IF_COPY(hs
, 0);
403 PG_RETURN_POINTER(a
);
413 setup_firstcall(FuncCallContext
*funcctx
, HStore
* hs
)
415 MemoryContext oldcontext
;
418 oldcontext
= MemoryContextSwitchTo(funcctx
->multi_call_memory_ctx
);
420 st
= (AKStore
*) palloc(sizeof(AKStore
));
422 st
->hs
= (HStore
*) palloc(VARSIZE(hs
));
423 memcpy(st
->hs
, hs
, VARSIZE(hs
));
425 funcctx
->user_fctx
= (void *) st
;
426 MemoryContextSwitchTo(oldcontext
);
429 PG_FUNCTION_INFO_V1(skeys
);
430 Datum
skeys(PG_FUNCTION_ARGS
);
432 skeys(PG_FUNCTION_ARGS
)
434 FuncCallContext
*funcctx
;
437 if (SRF_IS_FIRSTCALL())
439 HStore
*hs
= PG_GETARG_HS(0);
441 funcctx
= SRF_FIRSTCALL_INIT();
442 setup_firstcall(funcctx
, hs
);
443 PG_FREE_IF_COPY(hs
, 0);
446 funcctx
= SRF_PERCALL_SETUP();
447 st
= (AKStore
*) funcctx
->user_fctx
;
449 if (st
->i
< st
->hs
->size
)
451 HEntry
*ptr
= &(ARRPTR(st
->hs
)[st
->i
]);
454 item
= cstring_to_text_with_len(STRPTR(st
->hs
) + ptr
->pos
,
458 SRF_RETURN_NEXT(funcctx
, PointerGetDatum(item
));
464 SRF_RETURN_DONE(funcctx
);
467 PG_FUNCTION_INFO_V1(svals
);
468 Datum
svals(PG_FUNCTION_ARGS
);
470 svals(PG_FUNCTION_ARGS
)
472 FuncCallContext
*funcctx
;
475 if (SRF_IS_FIRSTCALL())
477 HStore
*hs
= PG_GETARG_HS(0);
479 funcctx
= SRF_FIRSTCALL_INIT();
480 setup_firstcall(funcctx
, hs
);
481 PG_FREE_IF_COPY(hs
, 0);
484 funcctx
= SRF_PERCALL_SETUP();
485 st
= (AKStore
*) funcctx
->user_fctx
;
487 if (st
->i
< st
->hs
->size
)
489 HEntry
*ptr
= &(ARRPTR(st
->hs
)[st
->i
]);
496 (funcctx
)->call_cntr
++;
497 rsi
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
498 rsi
->isDone
= ExprMultipleResult
;
505 item
= cstring_to_text_with_len(STRPTR(st
->hs
) + ptr
->pos
+ ptr
->keylen
,
509 SRF_RETURN_NEXT(funcctx
, PointerGetDatum(item
));
516 SRF_RETURN_DONE(funcctx
);
519 PG_FUNCTION_INFO_V1(hs_contains
);
520 Datum
hs_contains(PG_FUNCTION_ARGS
);
522 hs_contains(PG_FUNCTION_ARGS
)
524 HStore
*val
= PG_GETARG_HS(0);
525 HStore
*tmpl
= PG_GETARG_HS(1);
527 HEntry
*te
= ARRPTR(tmpl
);
528 char *vv
= STRPTR(val
);
529 char *tv
= STRPTR(tmpl
);
531 while (res
&& te
- ARRPTR(tmpl
) < tmpl
->size
)
533 HEntry
*entry
= findkey(val
, tv
+ te
->pos
, te
->keylen
);
537 if (te
->valisnull
|| entry
->valisnull
)
539 if (!(te
->valisnull
&& entry
->valisnull
))
542 else if (te
->vallen
!= entry
->vallen
||
544 vv
+ entry
->pos
+ entry
->keylen
,
545 tv
+ te
->pos
+ te
->keylen
,
555 PG_FREE_IF_COPY(val
, 0);
556 PG_FREE_IF_COPY(tmpl
, 1);
561 PG_FUNCTION_INFO_V1(hs_contained
);
562 Datum
hs_contained(PG_FUNCTION_ARGS
);
564 hs_contained(PG_FUNCTION_ARGS
)
566 PG_RETURN_DATUM(DirectFunctionCall2(
573 PG_FUNCTION_INFO_V1(each
);
574 Datum
each(PG_FUNCTION_ARGS
);
576 each(PG_FUNCTION_ARGS
)
578 FuncCallContext
*funcctx
;
581 if (SRF_IS_FIRSTCALL())
584 MemoryContext oldcontext
;
585 HStore
*hs
= PG_GETARG_HS(0);
587 funcctx
= SRF_FIRSTCALL_INIT();
588 oldcontext
= MemoryContextSwitchTo(funcctx
->multi_call_memory_ctx
);
589 st
= (AKStore
*) palloc(sizeof(AKStore
));
591 st
->hs
= (HStore
*) palloc(VARSIZE(hs
));
592 memcpy(st
->hs
, hs
, VARSIZE(hs
));
593 funcctx
->user_fctx
= (void *) st
;
595 /* Build a tuple descriptor for our result type */
596 if (get_call_result_type(fcinfo
, NULL
, &tupdesc
) != TYPEFUNC_COMPOSITE
)
597 elog(ERROR
, "return type must be a row type");
599 funcctx
->attinmeta
= TupleDescGetAttInMetadata(tupdesc
);
601 MemoryContextSwitchTo(oldcontext
);
602 PG_FREE_IF_COPY(hs
, 0);
605 funcctx
= SRF_PERCALL_SETUP();
606 st
= (AKStore
*) funcctx
->user_fctx
;
608 if (st
->i
< st
->hs
->size
)
610 HEntry
*ptr
= &(ARRPTR(st
->hs
)[st
->i
]);
613 char nulls
[] = {' ', ' '};
617 item
= cstring_to_text_with_len(STRPTR(st
->hs
) + ptr
->pos
, ptr
->keylen
);
618 dvalues
[0] = PointerGetDatum(item
);
622 dvalues
[1] = (Datum
) 0;
627 item
= cstring_to_text_with_len(STRPTR(st
->hs
) + ptr
->pos
+ ptr
->keylen
,
629 dvalues
[1] = PointerGetDatum(item
);
633 tuple
= heap_formtuple(funcctx
->attinmeta
->tupdesc
, dvalues
, nulls
);
634 res
= HeapTupleGetDatum(tuple
);
636 pfree(DatumGetPointer(dvalues
[0]));
638 pfree(DatumGetPointer(dvalues
[1]));
640 SRF_RETURN_NEXT(funcctx
, PointerGetDatum(res
));
646 SRF_RETURN_DONE(funcctx
);