Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()
[PostgreSQL.git] / contrib / hstore / hstore_op.c
blob4f285ee633953d3ab5c13d2a26856183112912fa
1 /*
2 * $PostgreSQL
3 */
4 #include "postgres.h"
6 #include "catalog/pg_type.h"
7 #include "funcapi.h"
8 #include "utils/array.h"
9 #include "utils/builtins.h"
11 #include "hstore.h"
14 static HEntry *
15 findkey(HStore * hs, char *key, int keylen)
17 HEntry *StopLow = ARRPTR(hs);
18 HEntry *StopHigh = StopLow + hs->size;
19 HEntry *StopMiddle;
20 int difference;
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);
29 else
30 difference = (StopMiddle->keylen > keylen) ? 1 : -1;
32 if (difference == 0)
33 return StopMiddle;
34 else if (difference < 0)
35 StopLow = StopMiddle + 1;
36 else
37 StopHigh = StopMiddle;
40 return NULL;
43 PG_FUNCTION_INFO_V1(fetchval);
44 Datum fetchval(PG_FUNCTION_ARGS);
45 Datum
46 fetchval(PG_FUNCTION_ARGS)
48 HStore *hs = PG_GETARG_HS(0);
49 text *key = PG_GETARG_TEXT_P(1);
50 HEntry *entry;
51 text *out;
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);
57 PG_RETURN_NULL();
60 out = cstring_to_text_with_len(STRPTR(hs) + entry->pos + entry->keylen,
61 entry->vallen);
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);
70 Datum
71 exists(PG_FUNCTION_ARGS)
73 HStore *hs = PG_GETARG_HS(0);
74 text *key = PG_GETARG_TEXT_P(1);
75 HEntry *entry;
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);
87 Datum
88 defined(PG_FUNCTION_ARGS)
90 HStore *hs = PG_GETARG_HS(0);
91 text *key = PG_GETARG_TEXT_P(1);
92 HEntry *entry;
93 bool res;
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);
102 PG_RETURN_BOOL(res);
105 PG_FUNCTION_INFO_V1(delete);
106 Datum delete(PG_FUNCTION_ARGS);
107 Datum
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));
113 char *ptrs,
114 *ptrd;
115 HEntry *es,
116 *ed;
118 SET_VARSIZE(out, VARSIZE(hs));
119 out->size = hs->size; /* temporary! */
121 ptrs = STRPTR(hs);
122 es = ARRPTR(hs);
123 ptrd = STRPTR(out);
124 ed = ARRPTR(out);
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);
134 ed++;
136 ptrs += es->keylen + ((es->valisnull) ? 0 : es->vallen);
137 es++;
140 if (ed - ARRPTR(out) != out->size)
142 int buflen = ptrd - STRPTR(out);
144 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);
161 Datum
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));
167 char *ps1,
168 *ps2,
169 *pd;
170 HEntry *es1,
171 *es2,
172 *ed;
174 SET_VARSIZE(out, VARSIZE(s1) + VARSIZE(s2));
175 out->size = s1->size + s2->size;
177 ps1 = STRPTR(s1);
178 ps2 = STRPTR(s2);
179 pd = STRPTR(out);
180 es1 = ARRPTR(s1);
181 es2 = ARRPTR(s2);
182 ed = ARRPTR(out);
184 while (es1 - ARRPTR(s1) < s1->size && es2 - ARRPTR(s2) < s2->size)
186 int difference;
188 if (es1->keylen == es2->keylen)
189 difference = strncmp(ps1, ps2, es1->keylen);
190 else
191 difference = (es1->keylen > es2->keylen) ? 1 : -1;
193 if (difference == 0)
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);
199 ed++;
201 ps1 += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
202 es1++;
203 ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
204 es2++;
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);
212 ed++;
214 ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
215 es2++;
217 else
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);
223 ed++;
225 ps1 += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
226 es1++;
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);
236 ed++;
238 ps1 += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
239 es1++;
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);
248 ed++;
250 ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
251 es2++;
254 if (ed - ARRPTR(out) != out->size)
256 int buflen = pd - STRPTR(out);
258 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);
274 Datum
275 tconvert(PG_FUNCTION_ARGS)
277 text *key;
278 text *val = NULL;
279 int len;
280 HStore *out;
282 if (PG_ARGISNULL(0))
283 PG_RETURN_NULL();
285 key = PG_GETARG_TEXT_P(0);
287 if (PG_ARGISNULL(1))
288 len = CALCDATASIZE(1, VARSIZE(key));
289 else
291 val = PG_GETARG_TEXT_P(1);
292 len = CALCDATASIZE(1, VARSIZE(key) + VARSIZE(val) - 2 * VARHDRSZ);
294 out = palloc(len);
295 SET_VARSIZE(out, len);
296 out->size = 1;
298 ARRPTR(out)->keylen = VARSIZE(key) - VARHDRSZ;
299 if (PG_ARGISNULL(1))
301 ARRPTR(out)->vallen = 0;
302 ARRPTR(out)->valisnull = true;
304 else
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);
325 Datum
326 akeys(PG_FUNCTION_ARGS)
328 HStore *hs = PG_GETARG_HS(0);
329 Datum *d;
330 ArrayType *a;
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)
337 text *item;
339 item = cstring_to_text_with_len(base + ptr->pos, ptr->keylen);
340 d[ptr - ARRPTR(hs)] = PointerGetDatum(item);
341 ptr++;
344 a = construct_array(d,
345 hs->size,
346 TEXTOID,
348 false,
349 'i');
351 ptr = ARRPTR(hs);
352 while (ptr - ARRPTR(hs) < hs->size)
354 pfree(DatumGetPointer(d[ptr - ARRPTR(hs)]));
355 ptr++;
358 pfree(d);
359 PG_FREE_IF_COPY(hs, 0);
361 PG_RETURN_POINTER(a);
364 PG_FUNCTION_INFO_V1(avals);
365 Datum avals(PG_FUNCTION_ARGS);
366 Datum
367 avals(PG_FUNCTION_ARGS)
369 HStore *hs = PG_GETARG_HS(0);
370 Datum *d;
371 ArrayType *a;
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)
378 text *item;
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);
383 ptr++;
386 a = construct_array(d,
387 hs->size,
388 TEXTOID,
390 false,
391 'i');
393 ptr = ARRPTR(hs);
394 while (ptr - ARRPTR(hs) < hs->size)
396 pfree(DatumGetPointer(d[ptr - ARRPTR(hs)]));
397 ptr++;
400 pfree(d);
401 PG_FREE_IF_COPY(hs, 0);
403 PG_RETURN_POINTER(a);
406 typedef struct
408 HStore *hs;
409 int i;
410 } AKStore;
412 static void
413 setup_firstcall(FuncCallContext *funcctx, HStore * hs)
415 MemoryContext oldcontext;
416 AKStore *st;
418 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
420 st = (AKStore *) palloc(sizeof(AKStore));
421 st->i = 0;
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);
431 Datum
432 skeys(PG_FUNCTION_ARGS)
434 FuncCallContext *funcctx;
435 AKStore *st;
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]);
452 text *item;
454 item = cstring_to_text_with_len(STRPTR(st->hs) + ptr->pos,
455 ptr->keylen);
456 st->i++;
458 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
461 pfree(st->hs);
462 pfree(st);
464 SRF_RETURN_DONE(funcctx);
467 PG_FUNCTION_INFO_V1(svals);
468 Datum svals(PG_FUNCTION_ARGS);
469 Datum
470 svals(PG_FUNCTION_ARGS)
472 FuncCallContext *funcctx;
473 AKStore *st;
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]);
491 if (ptr->valisnull)
493 ReturnSetInfo *rsi;
495 st->i++;
496 (funcctx)->call_cntr++;
497 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
498 rsi->isDone = ExprMultipleResult;
499 PG_RETURN_NULL();
501 else
503 text *item;
505 item = cstring_to_text_with_len(STRPTR(st->hs) + ptr->pos + ptr->keylen,
506 ptr->vallen);
507 st->i++;
509 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
513 pfree(st->hs);
514 pfree(st);
516 SRF_RETURN_DONE(funcctx);
519 PG_FUNCTION_INFO_V1(hs_contains);
520 Datum hs_contains(PG_FUNCTION_ARGS);
521 Datum
522 hs_contains(PG_FUNCTION_ARGS)
524 HStore *val = PG_GETARG_HS(0);
525 HStore *tmpl = PG_GETARG_HS(1);
526 bool res = true;
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);
535 if (entry)
537 if (te->valisnull || entry->valisnull)
539 if (!(te->valisnull && entry->valisnull))
540 res = false;
542 else if (te->vallen != entry->vallen ||
543 strncmp(
544 vv + entry->pos + entry->keylen,
545 tv + te->pos + te->keylen,
546 te->vallen)
548 res = false;
550 else
551 res = false;
552 te++;
555 PG_FREE_IF_COPY(val, 0);
556 PG_FREE_IF_COPY(tmpl, 1);
558 PG_RETURN_BOOL(res);
561 PG_FUNCTION_INFO_V1(hs_contained);
562 Datum hs_contained(PG_FUNCTION_ARGS);
563 Datum
564 hs_contained(PG_FUNCTION_ARGS)
566 PG_RETURN_DATUM(DirectFunctionCall2(
567 hs_contains,
568 PG_GETARG_DATUM(1),
569 PG_GETARG_DATUM(0)
573 PG_FUNCTION_INFO_V1(each);
574 Datum each(PG_FUNCTION_ARGS);
575 Datum
576 each(PG_FUNCTION_ARGS)
578 FuncCallContext *funcctx;
579 AKStore *st;
581 if (SRF_IS_FIRSTCALL())
583 TupleDesc tupdesc;
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));
590 st->i = 0;
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]);
611 Datum res,
612 dvalues[2];
613 char nulls[] = {' ', ' '};
614 text *item;
615 HeapTuple tuple;
617 item = cstring_to_text_with_len(STRPTR(st->hs) + ptr->pos, ptr->keylen);
618 dvalues[0] = PointerGetDatum(item);
620 if (ptr->valisnull)
622 dvalues[1] = (Datum) 0;
623 nulls[1] = 'n';
625 else
627 item = cstring_to_text_with_len(STRPTR(st->hs) + ptr->pos + ptr->keylen,
628 ptr->vallen);
629 dvalues[1] = PointerGetDatum(item);
631 st->i++;
633 tuple = heap_formtuple(funcctx->attinmeta->tupdesc, dvalues, nulls);
634 res = HeapTupleGetDatum(tuple);
636 pfree(DatumGetPointer(dvalues[0]));
637 if (nulls[1] != 'n')
638 pfree(DatumGetPointer(dvalues[1]));
640 SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
643 pfree(st->hs);
644 pfree(st);
646 SRF_RETURN_DONE(funcctx);