1 /*
2 * contrib/hstore/hstore_op.c
3 */
4 #include "postgres.h"
5
6 #include "access/hash.h"
7 #include "access/htup_details.h"
8 #include "catalog/pg_type.h"
9 #include "funcapi.h"
10 #include "utils/builtins.h"
11 #include "utils/memutils.h"
12
13 #include "hstore.h"
14
15 /* old names for C functions */
16 HSTORE_POLLUTE(hstore_fetchval, fetchval);
17 HSTORE_POLLUTE(hstore_exists, exists);
18 HSTORE_POLLUTE(hstore_defined, defined);
19 HSTORE_POLLUTE(hstore_delete, delete);
20 HSTORE_POLLUTE(hstore_concat, hs_concat);
21 HSTORE_POLLUTE(hstore_contains, hs_contains);
22 HSTORE_POLLUTE(hstore_contained, hs_contained);
23 HSTORE_POLLUTE(hstore_akeys, akeys);
24 HSTORE_POLLUTE(hstore_avals, avals);
25 HSTORE_POLLUTE(hstore_skeys, skeys);
26 HSTORE_POLLUTE(hstore_svals, svals);
27 HSTORE_POLLUTE(hstore_each, each);
28
29
30 /*
31 * We're often finding a sequence of keys in ascending order. The
32 * "lowbound" parameter is used to cache lower bounds of searches
33 * between calls, based on this assumption. Pass NULL for it for
34 * one-off or unordered searches.
35 */
36 int
hstoreFindKey(HStore * hs,int * lowbound,char * key,int keylen)37 hstoreFindKey(HStore *hs, int *lowbound, char *key, int keylen)
38 {
39 HEntry *entries = ARRPTR(hs);
40 int stopLow = lowbound ? *lowbound : 0;
41 int stopHigh = HS_COUNT(hs);
42 int stopMiddle;
43 char *base = STRPTR(hs);
44
45 while (stopLow < stopHigh)
46 {
47 int difference;
48
49 stopMiddle = stopLow + (stopHigh - stopLow) / 2;
50
51 if (HSTORE_KEYLEN(entries, stopMiddle) == keylen)
52 difference = memcmp(HSTORE_KEY(entries, base, stopMiddle), key, keylen);
53 else
54 difference = (HSTORE_KEYLEN(entries, stopMiddle) > keylen) ? 1 : -1;
55
56 if (difference == 0)
57 {
58 if (lowbound)
59 *lowbound = stopMiddle + 1;
60 return stopMiddle;
61 }
62 else if (difference < 0)
63 stopLow = stopMiddle + 1;
64 else
65 stopHigh = stopMiddle;
66 }
67
68 if (lowbound)
69 *lowbound = stopLow;
70 return -1;
71 }
72
73 Pairs *
hstoreArrayToPairs(ArrayType * a,int * npairs)74 hstoreArrayToPairs(ArrayType *a, int *npairs)
75 {
76 Datum *key_datums;
77 bool *key_nulls;
78 int key_count;
79 Pairs *key_pairs;
80 int bufsiz;
81 int i,
82 j;
83
84 deconstruct_array(a,
85 TEXTOID, -1, false, 'i',
86 &key_datums, &key_nulls, &key_count);
87
88 if (key_count == 0)
89 {
90 *npairs = 0;
91 return NULL;
92 }
93
94 /*
95 * A text array uses at least eight bytes per element, so any overflow in
96 * "key_count * sizeof(Pairs)" is small enough for palloc() to catch.
97 * However, credible improvements to the array format could invalidate
98 * that assumption. Therefore, use an explicit check rather than relying
99 * on palloc() to complain.
100 */
101 if (key_count > MaxAllocSize / sizeof(Pairs))
102 ereport(ERROR,
103 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
104 errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
105 key_count, (int) (MaxAllocSize / sizeof(Pairs)))));
106
107 key_pairs = palloc(sizeof(Pairs) * key_count);
108
109 for (i = 0, j = 0; i < key_count; i++)
110 {
111 if (!key_nulls[i])
112 {
113 key_pairs[j].key = VARDATA(key_datums[i]);
114 key_pairs[j].keylen = VARSIZE(key_datums[i]) - VARHDRSZ;
115 key_pairs[j].val = NULL;
116 key_pairs[j].vallen = 0;
117 key_pairs[j].needfree = 0;
118 key_pairs[j].isnull = 1;
119 j++;
120 }
121 }
122
123 *npairs = hstoreUniquePairs(key_pairs, j, &bufsiz);
124
125 return key_pairs;
126 }
127
128
129 PG_FUNCTION_INFO_V1(hstore_fetchval);
130 Datum
hstore_fetchval(PG_FUNCTION_ARGS)131 hstore_fetchval(PG_FUNCTION_ARGS)
132 {
133 HStore *hs = PG_GETARG_HS(0);
134 text *key = PG_GETARG_TEXT_PP(1);
135 HEntry *entries = ARRPTR(hs);
136 text *out;
137 int idx = hstoreFindKey(hs, NULL,
138 VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
139
140 if (idx < 0 || HSTORE_VALISNULL(entries, idx))
141 PG_RETURN_NULL();
142
143 out = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), idx),
144 HSTORE_VALLEN(entries, idx));
145
146 PG_RETURN_TEXT_P(out);
147 }
148
149
150 PG_FUNCTION_INFO_V1(hstore_exists);
151 Datum
hstore_exists(PG_FUNCTION_ARGS)152 hstore_exists(PG_FUNCTION_ARGS)
153 {
154 HStore *hs = PG_GETARG_HS(0);
155 text *key = PG_GETARG_TEXT_PP(1);
156 int idx = hstoreFindKey(hs, NULL,
157 VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
158
159 PG_RETURN_BOOL(idx >= 0);
160 }
161
162
163 PG_FUNCTION_INFO_V1(hstore_exists_any);
164 Datum
hstore_exists_any(PG_FUNCTION_ARGS)165 hstore_exists_any(PG_FUNCTION_ARGS)
166 {
167 HStore *hs = PG_GETARG_HS(0);
168 ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
169 int nkeys;
170 Pairs *key_pairs = hstoreArrayToPairs(keys, &nkeys);
171 int i;
172 int lowbound = 0;
173 bool res = false;
174
175 /*
176 * we exploit the fact that the pairs list is already sorted into strictly
177 * increasing order to narrow the hstoreFindKey search; each search can
178 * start one entry past the previous "found" entry, or at the lower bound
179 * of the last search.
180 */
181 for (i = 0; i < nkeys; i++)
182 {
183 int idx = hstoreFindKey(hs, &lowbound,
184 key_pairs[i].key, key_pairs[i].keylen);
185
186 if (idx >= 0)
187 {
188 res = true;
189 break;
190 }
191 }
192
193 PG_RETURN_BOOL(res);
194 }
195
196
197 PG_FUNCTION_INFO_V1(hstore_exists_all);
198 Datum
hstore_exists_all(PG_FUNCTION_ARGS)199 hstore_exists_all(PG_FUNCTION_ARGS)
200 {
201 HStore *hs = PG_GETARG_HS(0);
202 ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
203 int nkeys;
204 Pairs *key_pairs = hstoreArrayToPairs(keys, &nkeys);
205 int i;
206 int lowbound = 0;
207 bool res = true;
208
209 /*
210 * we exploit the fact that the pairs list is already sorted into strictly
211 * increasing order to narrow the hstoreFindKey search; each search can
212 * start one entry past the previous "found" entry, or at the lower bound
213 * of the last search.
214 */
215 for (i = 0; i < nkeys; i++)
216 {
217 int idx = hstoreFindKey(hs, &lowbound,
218 key_pairs[i].key, key_pairs[i].keylen);
219
220 if (idx < 0)
221 {
222 res = false;
223 break;
224 }
225 }
226
227 PG_RETURN_BOOL(res);
228 }
229
230
231 PG_FUNCTION_INFO_V1(hstore_defined);
232 Datum
hstore_defined(PG_FUNCTION_ARGS)233 hstore_defined(PG_FUNCTION_ARGS)
234 {
235 HStore *hs = PG_GETARG_HS(0);
236 text *key = PG_GETARG_TEXT_PP(1);
237 HEntry *entries = ARRPTR(hs);
238 int idx = hstoreFindKey(hs, NULL,
239 VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
240 bool res = (idx >= 0 && !HSTORE_VALISNULL(entries, idx));
241
242 PG_RETURN_BOOL(res);
243 }
244
245
246 PG_FUNCTION_INFO_V1(hstore_delete);
247 Datum
hstore_delete(PG_FUNCTION_ARGS)248 hstore_delete(PG_FUNCTION_ARGS)
249 {
250 HStore *hs = PG_GETARG_HS(0);
251 text *key = PG_GETARG_TEXT_PP(1);
252 char *keyptr = VARDATA_ANY(key);
253 int keylen = VARSIZE_ANY_EXHDR(key);
254 HStore *out = palloc(VARSIZE(hs));
255 char *bufs,
256 *bufd,
257 *ptrd;
258 HEntry *es,
259 *ed;
260 int i;
261 int count = HS_COUNT(hs);
262 int outcount = 0;
263
264 SET_VARSIZE(out, VARSIZE(hs));
265 HS_SETCOUNT(out, count); /* temporary! */
266
267 bufs = STRPTR(hs);
268 es = ARRPTR(hs);
269 bufd = ptrd = STRPTR(out);
270 ed = ARRPTR(out);
271
272 for (i = 0; i < count; ++i)
273 {
274 int len = HSTORE_KEYLEN(es, i);
275 char *ptrs = HSTORE_KEY(es, bufs, i);
276
277 if (!(len == keylen && memcmp(ptrs, keyptr, keylen) == 0))
278 {
279 int vallen = HSTORE_VALLEN(es, i);
280
281 HS_COPYITEM(ed, bufd, ptrd, ptrs, len, vallen,
282 HSTORE_VALISNULL(es, i));
283 ++outcount;
284 }
285 }
286
287 HS_FINALIZE(out, outcount, bufd, ptrd);
288
289 PG_RETURN_POINTER(out);
290 }
291
292
293 PG_FUNCTION_INFO_V1(hstore_delete_array);
294 Datum
hstore_delete_array(PG_FUNCTION_ARGS)295 hstore_delete_array(PG_FUNCTION_ARGS)
296 {
297 HStore *hs = PG_GETARG_HS(0);
298 HStore *out = palloc(VARSIZE(hs));
299 int hs_count = HS_COUNT(hs);
300 char *ps,
301 *bufd,
302 *pd;
303 HEntry *es,
304 *ed;
305 int i,
306 j;
307 int outcount = 0;
308 ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1);
309 int nkeys;
310 Pairs *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
311
312 SET_VARSIZE(out, VARSIZE(hs));
313 HS_SETCOUNT(out, hs_count); /* temporary! */
314
315 ps = STRPTR(hs);
316 es = ARRPTR(hs);
317 bufd = pd = STRPTR(out);
318 ed = ARRPTR(out);
319
320 if (nkeys == 0)
321 {
322 /* return a copy of the input, unchanged */
323 memcpy(out, hs, VARSIZE(hs));
324 HS_FIXSIZE(out, hs_count);
325 HS_SETCOUNT(out, hs_count);
326 PG_RETURN_POINTER(out);
327 }
328
329 /*
330 * this is in effect a merge between hs and key_pairs, both of which are
331 * already sorted by (keylen,key); we take keys from hs only
332 */
333
334 for (i = j = 0; i < hs_count;)
335 {
336 int difference;
337
338 if (j >= nkeys)
339 difference = -1;
340 else
341 {
342 int skeylen = HSTORE_KEYLEN(es, i);
343
344 if (skeylen == key_pairs[j].keylen)
345 difference = memcmp(HSTORE_KEY(es, ps, i),
346 key_pairs[j].key,
347 key_pairs[j].keylen);
348 else
349 difference = (skeylen > key_pairs[j].keylen) ? 1 : -1;
350 }
351
352 if (difference > 0)
353 ++j;
354 else if (difference == 0)
355 ++i, ++j;
356 else
357 {
358 HS_COPYITEM(ed, bufd, pd,
359 HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
360 HSTORE_VALLEN(es, i), HSTORE_VALISNULL(es, i));
361 ++outcount;
362 ++i;
363 }
364 }
365
366 HS_FINALIZE(out, outcount, bufd, pd);
367
368 PG_RETURN_POINTER(out);
369 }
370
371
372 PG_FUNCTION_INFO_V1(hstore_delete_hstore);
373 Datum
hstore_delete_hstore(PG_FUNCTION_ARGS)374 hstore_delete_hstore(PG_FUNCTION_ARGS)
375 {
376 HStore *hs = PG_GETARG_HS(0);
377 HStore *hs2 = PG_GETARG_HS(1);
378 HStore *out = palloc(VARSIZE(hs));
379 int hs_count = HS_COUNT(hs);
380 int hs2_count = HS_COUNT(hs2);
381 char *ps,
382 *ps2,
383 *bufd,
384 *pd;
385 HEntry *es,
386 *es2,
387 *ed;
388 int i,
389 j;
390 int outcount = 0;
391
392 SET_VARSIZE(out, VARSIZE(hs));
393 HS_SETCOUNT(out, hs_count); /* temporary! */
394
395 ps = STRPTR(hs);
396 es = ARRPTR(hs);
397 ps2 = STRPTR(hs2);
398 es2 = ARRPTR(hs2);
399 bufd = pd = STRPTR(out);
400 ed = ARRPTR(out);
401
402 if (hs2_count == 0)
403 {
404 /* return a copy of the input, unchanged */
405 memcpy(out, hs, VARSIZE(hs));
406 HS_FIXSIZE(out, hs_count);
407 HS_SETCOUNT(out, hs_count);
408 PG_RETURN_POINTER(out);
409 }
410
411 /*
412 * this is in effect a merge between hs and hs2, both of which are already
413 * sorted by (keylen,key); we take keys from hs only; for equal keys, we
414 * take the value from hs unless the values are equal
415 */
416
417 for (i = j = 0; i < hs_count;)
418 {
419 int difference;
420
421 if (j >= hs2_count)
422 difference = -1;
423 else
424 {
425 int skeylen = HSTORE_KEYLEN(es, i);
426 int s2keylen = HSTORE_KEYLEN(es2, j);
427
428 if (skeylen == s2keylen)
429 difference = memcmp(HSTORE_KEY(es, ps, i),
430 HSTORE_KEY(es2, ps2, j),
431 skeylen);
432 else
433 difference = (skeylen > s2keylen) ? 1 : -1;
434 }
435
436 if (difference > 0)
437 ++j;
438 else if (difference == 0)
439 {
440 int svallen = HSTORE_VALLEN(es, i);
441 int snullval = HSTORE_VALISNULL(es, i);
442
443 if (snullval != HSTORE_VALISNULL(es2, j) ||
444 (!snullval && (svallen != HSTORE_VALLEN(es2, j) ||
445 memcmp(HSTORE_VAL(es, ps, i),
446 HSTORE_VAL(es2, ps2, j),
447 svallen) != 0)))
448 {
449 HS_COPYITEM(ed, bufd, pd,
450 HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
451 svallen, snullval);
452 ++outcount;
453 }
454 ++i, ++j;
455 }
456 else
457 {
458 HS_COPYITEM(ed, bufd, pd,
459 HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
460 HSTORE_VALLEN(es, i), HSTORE_VALISNULL(es, i));
461 ++outcount;
462 ++i;
463 }
464 }
465
466 HS_FINALIZE(out, outcount, bufd, pd);
467
468 PG_RETURN_POINTER(out);
469 }
470
471
472 PG_FUNCTION_INFO_V1(hstore_concat);
473 Datum
hstore_concat(PG_FUNCTION_ARGS)474 hstore_concat(PG_FUNCTION_ARGS)
475 {
476 HStore *s1 = PG_GETARG_HS(0);
477 HStore *s2 = PG_GETARG_HS(1);
478 HStore *out = palloc(VARSIZE(s1) + VARSIZE(s2));
479 char *ps1,
480 *ps2,
481 *bufd,
482 *pd;
483 HEntry *es1,
484 *es2,
485 *ed;
486 int s1idx;
487 int s2idx;
488 int s1count = HS_COUNT(s1);
489 int s2count = HS_COUNT(s2);
490 int outcount = 0;
491
492 SET_VARSIZE(out, VARSIZE(s1) + VARSIZE(s2) - HSHRDSIZE);
493 HS_SETCOUNT(out, s1count + s2count);
494
495 if (s1count == 0)
496 {
497 /* return a copy of the input, unchanged */
498 memcpy(out, s2, VARSIZE(s2));
499 HS_FIXSIZE(out, s2count);
500 HS_SETCOUNT(out, s2count);
501 PG_RETURN_POINTER(out);
502 }
503
504 if (s2count == 0)
505 {
506 /* return a copy of the input, unchanged */
507 memcpy(out, s1, VARSIZE(s1));
508 HS_FIXSIZE(out, s1count);
509 HS_SETCOUNT(out, s1count);
510 PG_RETURN_POINTER(out);
511 }
512
513 ps1 = STRPTR(s1);
514 ps2 = STRPTR(s2);
515 bufd = pd = STRPTR(out);
516 es1 = ARRPTR(s1);
517 es2 = ARRPTR(s2);
518 ed = ARRPTR(out);
519
520 /*
521 * this is in effect a merge between s1 and s2, both of which are already
522 * sorted by (keylen,key); we take s2 for equal keys
523 */
524
525 for (s1idx = s2idx = 0; s1idx < s1count || s2idx < s2count; ++outcount)
526 {
527 int difference;
528
529 if (s1idx >= s1count)
530 difference = 1;
531 else if (s2idx >= s2count)
532 difference = -1;
533 else
534 {
535 int s1keylen = HSTORE_KEYLEN(es1, s1idx);
536 int s2keylen = HSTORE_KEYLEN(es2, s2idx);
537
538 if (s1keylen == s2keylen)
539 difference = memcmp(HSTORE_KEY(es1, ps1, s1idx),
540 HSTORE_KEY(es2, ps2, s2idx),
541 s1keylen);
542 else
543 difference = (s1keylen > s2keylen) ? 1 : -1;
544 }
545
546 if (difference >= 0)
547 {
548 HS_COPYITEM(ed, bufd, pd,
549 HSTORE_KEY(es2, ps2, s2idx), HSTORE_KEYLEN(es2, s2idx),
550 HSTORE_VALLEN(es2, s2idx), HSTORE_VALISNULL(es2, s2idx));
551 ++s2idx;
552 if (difference == 0)
553 ++s1idx;
554 }
555 else
556 {
557 HS_COPYITEM(ed, bufd, pd,
558 HSTORE_KEY(es1, ps1, s1idx), HSTORE_KEYLEN(es1, s1idx),
559 HSTORE_VALLEN(es1, s1idx), HSTORE_VALISNULL(es1, s1idx));
560 ++s1idx;
561 }
562 }
563
564 HS_FINALIZE(out, outcount, bufd, pd);
565
566 PG_RETURN_POINTER(out);
567 }
568
569
570 PG_FUNCTION_INFO_V1(hstore_slice_to_array);
571 Datum
hstore_slice_to_array(PG_FUNCTION_ARGS)572 hstore_slice_to_array(PG_FUNCTION_ARGS)
573 {
574 HStore *hs = PG_GETARG_HS(0);
575 HEntry *entries = ARRPTR(hs);
576 char *ptr = STRPTR(hs);
577 ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1);
578 ArrayType *aout;
579 Datum *key_datums;
580 bool *key_nulls;
581 Datum *out_datums;
582 bool *out_nulls;
583 int key_count;
584 int i;
585
586 deconstruct_array(key_array,
587 TEXTOID, -1, false, 'i',
588 &key_datums, &key_nulls, &key_count);
589
590 if (key_count == 0)
591 {
592 aout = construct_empty_array(TEXTOID);
593 PG_RETURN_POINTER(aout);
594 }
595
596 out_datums = palloc(sizeof(Datum) * key_count);
597 out_nulls = palloc(sizeof(bool) * key_count);
598
599 for (i = 0; i < key_count; ++i)
600 {
601 text *key = (text *) DatumGetPointer(key_datums[i]);
602 int idx;
603
604 if (key_nulls[i])
605 idx = -1;
606 else
607 idx = hstoreFindKey(hs, NULL, VARDATA(key), VARSIZE(key) - VARHDRSZ);
608
609 if (idx < 0 || HSTORE_VALISNULL(entries, idx))
610 {
611 out_nulls[i] = true;
612 out_datums[i] = (Datum) 0;
613 }
614 else
615 {
616 out_datums[i] = PointerGetDatum(
617 cstring_to_text_with_len(HSTORE_VAL(entries, ptr, idx),
618 HSTORE_VALLEN(entries, idx)));
619 out_nulls[i] = false;
620 }
621 }
622
623 aout = construct_md_array(out_datums, out_nulls,
624 ARR_NDIM(key_array),
625 ARR_DIMS(key_array),
626 ARR_LBOUND(key_array),
627 TEXTOID, -1, false, 'i');
628
629 PG_RETURN_POINTER(aout);
630 }
631
632
633 PG_FUNCTION_INFO_V1(hstore_slice_to_hstore);
634 Datum
hstore_slice_to_hstore(PG_FUNCTION_ARGS)635 hstore_slice_to_hstore(PG_FUNCTION_ARGS)
636 {
637 HStore *hs = PG_GETARG_HS(0);
638 HEntry *entries = ARRPTR(hs);
639 char *ptr = STRPTR(hs);
640 ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1);
641 HStore *out;
642 int nkeys;
643 Pairs *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
644 Pairs *out_pairs;
645 int bufsiz;
646 int lastidx = 0;
647 int i;
648 int out_count = 0;
649
650 if (nkeys == 0)
651 {
652 out = hstorePairs(NULL, 0, 0);
653 PG_RETURN_POINTER(out);
654 }
655
656 /* hstoreArrayToPairs() checked overflow */
657 out_pairs = palloc(sizeof(Pairs) * nkeys);
658 bufsiz = 0;
659
660 /*
661 * we exploit the fact that the pairs list is already sorted into strictly
662 * increasing order to narrow the hstoreFindKey search; each search can
663 * start one entry past the previous "found" entry, or at the lower bound
664 * of the last search.
665 */
666
667 for (i = 0; i < nkeys; ++i)
668 {
669 int idx = hstoreFindKey(hs, &lastidx,
670 key_pairs[i].key, key_pairs[i].keylen);
671
672 if (idx >= 0)
673 {
674 out_pairs[out_count].key = key_pairs[i].key;
675 bufsiz += (out_pairs[out_count].keylen = key_pairs[i].keylen);
676 out_pairs[out_count].val = HSTORE_VAL(entries, ptr, idx);
677 bufsiz += (out_pairs[out_count].vallen = HSTORE_VALLEN(entries, idx));
678 out_pairs[out_count].isnull = HSTORE_VALISNULL(entries, idx);
679 out_pairs[out_count].needfree = false;
680 ++out_count;
681 }
682 }
683
684 /*
685 * we don't use uniquePairs here because we know that the pairs list is
686 * already sorted and uniq'ed.
687 */
688
689 out = hstorePairs(out_pairs, out_count, bufsiz);
690
691 PG_RETURN_POINTER(out);
692 }
693
694
695 PG_FUNCTION_INFO_V1(hstore_akeys);
696 Datum
hstore_akeys(PG_FUNCTION_ARGS)697 hstore_akeys(PG_FUNCTION_ARGS)
698 {
699 HStore *hs = PG_GETARG_HS(0);
700 Datum *d;
701 ArrayType *a;
702 HEntry *entries = ARRPTR(hs);
703 char *base = STRPTR(hs);
704 int count = HS_COUNT(hs);
705 int i;
706
707 if (count == 0)
708 {
709 a = construct_empty_array(TEXTOID);
710 PG_RETURN_POINTER(a);
711 }
712
713 d = (Datum *) palloc(sizeof(Datum) * count);
714
715 for (i = 0; i < count; ++i)
716 {
717 text *t = cstring_to_text_with_len(HSTORE_KEY(entries, base, i),
718 HSTORE_KEYLEN(entries, i));
719
720 d[i] = PointerGetDatum(t);
721 }
722
723 a = construct_array(d, count,
724 TEXTOID, -1, false, 'i');
725
726 PG_RETURN_POINTER(a);
727 }
728
729
730 PG_FUNCTION_INFO_V1(hstore_avals);
731 Datum
hstore_avals(PG_FUNCTION_ARGS)732 hstore_avals(PG_FUNCTION_ARGS)
733 {
734 HStore *hs = PG_GETARG_HS(0);
735 Datum *d;
736 bool *nulls;
737 ArrayType *a;
738 HEntry *entries = ARRPTR(hs);
739 char *base = STRPTR(hs);
740 int count = HS_COUNT(hs);
741 int lb = 1;
742 int i;
743
744 if (count == 0)
745 {
746 a = construct_empty_array(TEXTOID);
747 PG_RETURN_POINTER(a);
748 }
749
750 d = (Datum *) palloc(sizeof(Datum) * count);
751 nulls = (bool *) palloc(sizeof(bool) * count);
752
753 for (i = 0; i < count; ++i)
754 {
755 if (HSTORE_VALISNULL(entries, i))
756 {
757 d[i] = (Datum) 0;
758 nulls[i] = true;
759 }
760 else
761 {
762 text *item = cstring_to_text_with_len(HSTORE_VAL(entries, base, i),
763 HSTORE_VALLEN(entries, i));
764
765 d[i] = PointerGetDatum(item);
766 nulls[i] = false;
767 }
768 }
769
770 a = construct_md_array(d, nulls, 1, &count, &lb,
771 TEXTOID, -1, false, 'i');
772
773 PG_RETURN_POINTER(a);
774 }
775
776
777 static ArrayType *
hstore_to_array_internal(HStore * hs,int ndims)778 hstore_to_array_internal(HStore *hs, int ndims)
779 {
780 HEntry *entries = ARRPTR(hs);
781 char *base = STRPTR(hs);
782 int count = HS_COUNT(hs);
783 int out_size[2] = {0, 2};
784 int lb[2] = {1, 1};
785 Datum *out_datums;
786 bool *out_nulls;
787 int i;
788
789 Assert(ndims < 3);
790
791 if (count == 0 || ndims == 0)
792 return construct_empty_array(TEXTOID);
793
794 out_size[0] = count * 2 / ndims;
795 out_datums = palloc(sizeof(Datum) * count * 2);
796 out_nulls = palloc(sizeof(bool) * count * 2);
797
798 for (i = 0; i < count; ++i)
799 {
800 text *key = cstring_to_text_with_len(HSTORE_KEY(entries, base, i),
801 HSTORE_KEYLEN(entries, i));
802
803 out_datums[i * 2] = PointerGetDatum(key);
804 out_nulls[i * 2] = false;
805
806 if (HSTORE_VALISNULL(entries, i))
807 {
808 out_datums[i * 2 + 1] = (Datum) 0;
809 out_nulls[i * 2 + 1] = true;
810 }
811 else
812 {
813 text *item = cstring_to_text_with_len(HSTORE_VAL(entries, base, i),
814 HSTORE_VALLEN(entries, i));
815
816 out_datums[i * 2 + 1] = PointerGetDatum(item);
817 out_nulls[i * 2 + 1] = false;
818 }
819 }
820
821 return construct_md_array(out_datums, out_nulls,
822 ndims, out_size, lb,
823 TEXTOID, -1, false, 'i');
824 }
825
826 PG_FUNCTION_INFO_V1(hstore_to_array);
827 Datum
hstore_to_array(PG_FUNCTION_ARGS)828 hstore_to_array(PG_FUNCTION_ARGS)
829 {
830 HStore *hs = PG_GETARG_HS(0);
831 ArrayType *out = hstore_to_array_internal(hs, 1);
832
833 PG_RETURN_POINTER(out);
834 }
835
836 PG_FUNCTION_INFO_V1(hstore_to_matrix);
837 Datum
hstore_to_matrix(PG_FUNCTION_ARGS)838 hstore_to_matrix(PG_FUNCTION_ARGS)
839 {
840 HStore *hs = PG_GETARG_HS(0);
841 ArrayType *out = hstore_to_array_internal(hs, 2);
842
843 PG_RETURN_POINTER(out);
844 }
845
846 /*
847 * Common initialization function for the various set-returning
848 * funcs. fcinfo is only passed if the function is to return a
849 * composite; it will be used to look up the return tupledesc.
850 * we stash a copy of the hstore in the multi-call context in
851 * case it was originally toasted. (At least I assume that's why;
852 * there was no explanatory comment in the original code. --AG)
853 */
854
855 static void
setup_firstcall(FuncCallContext * funcctx,HStore * hs,FunctionCallInfoData * fcinfo)856 setup_firstcall(FuncCallContext *funcctx, HStore *hs,
857 FunctionCallInfoData *fcinfo)
858 {
859 MemoryContext oldcontext;
860 HStore *st;
861
862 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
863
864 st = (HStore *) palloc(VARSIZE(hs));
865 memcpy(st, hs, VARSIZE(hs));
866
867 funcctx->user_fctx = (void *) st;
868
869 if (fcinfo)
870 {
871 TupleDesc tupdesc;
872
873 /* Build a tuple descriptor for our result type */
874 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
875 elog(ERROR, "return type must be a row type");
876
877 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
878 }
879
880 MemoryContextSwitchTo(oldcontext);
881 }
882
883
884 PG_FUNCTION_INFO_V1(hstore_skeys);
885 Datum
hstore_skeys(PG_FUNCTION_ARGS)886 hstore_skeys(PG_FUNCTION_ARGS)
887 {
888 FuncCallContext *funcctx;
889 HStore *hs;
890 int i;
891
892 if (SRF_IS_FIRSTCALL())
893 {
894 hs = PG_GETARG_HS(0);
895 funcctx = SRF_FIRSTCALL_INIT();
896 setup_firstcall(funcctx, hs, NULL);
897 }
898
899 funcctx = SRF_PERCALL_SETUP();
900 hs = (HStore *) funcctx->user_fctx;
901 i = funcctx->call_cntr;
902
903 if (i < HS_COUNT(hs))
904 {
905 HEntry *entries = ARRPTR(hs);
906 text *item;
907
908 item = cstring_to_text_with_len(HSTORE_KEY(entries, STRPTR(hs), i),
909 HSTORE_KEYLEN(entries, i));
910
911 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
912 }
913
914 SRF_RETURN_DONE(funcctx);
915 }
916
917
918 PG_FUNCTION_INFO_V1(hstore_svals);
919 Datum
hstore_svals(PG_FUNCTION_ARGS)920 hstore_svals(PG_FUNCTION_ARGS)
921 {
922 FuncCallContext *funcctx;
923 HStore *hs;
924 int i;
925
926 if (SRF_IS_FIRSTCALL())
927 {
928 hs = PG_GETARG_HS(0);
929 funcctx = SRF_FIRSTCALL_INIT();
930 setup_firstcall(funcctx, hs, NULL);
931 }
932
933 funcctx = SRF_PERCALL_SETUP();
934 hs = (HStore *) funcctx->user_fctx;
935 i = funcctx->call_cntr;
936
937 if (i < HS_COUNT(hs))
938 {
939 HEntry *entries = ARRPTR(hs);
940
941 if (HSTORE_VALISNULL(entries, i))
942 {
943 ReturnSetInfo *rsi;
944
945 /* ugly ugly ugly. why no macro for this? */
946 (funcctx)->call_cntr++;
947 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
948 rsi->isDone = ExprMultipleResult;
949 PG_RETURN_NULL();
950 }
951 else
952 {
953 text *item;
954
955 item = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), i),
956 HSTORE_VALLEN(entries, i));
957
958 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
959 }
960 }
961
962 SRF_RETURN_DONE(funcctx);
963 }
964
965
966 PG_FUNCTION_INFO_V1(hstore_contains);
967 Datum
hstore_contains(PG_FUNCTION_ARGS)968 hstore_contains(PG_FUNCTION_ARGS)
969 {
970 HStore *val = PG_GETARG_HS(0);
971 HStore *tmpl = PG_GETARG_HS(1);
972 bool res = true;
973 HEntry *te = ARRPTR(tmpl);
974 char *tstr = STRPTR(tmpl);
975 HEntry *ve = ARRPTR(val);
976 char *vstr = STRPTR(val);
977 int tcount = HS_COUNT(tmpl);
978 int lastidx = 0;
979 int i;
980
981 /*
982 * we exploit the fact that keys in "tmpl" are in strictly increasing
983 * order to narrow the hstoreFindKey search; each search can start one
984 * entry past the previous "found" entry, or at the lower bound of the
985 * search
986 */
987
988 for (i = 0; res && i < tcount; ++i)
989 {
990 int idx = hstoreFindKey(val, &lastidx,
991 HSTORE_KEY(te, tstr, i),
992 HSTORE_KEYLEN(te, i));
993
994 if (idx >= 0)
995 {
996 bool nullval = HSTORE_VALISNULL(te, i);
997 int vallen = HSTORE_VALLEN(te, i);
998
999 if (nullval != HSTORE_VALISNULL(ve, idx) ||
1000 (!nullval && (vallen != HSTORE_VALLEN(ve, idx) ||
1001 memcmp(HSTORE_VAL(te, tstr, i),
1002 HSTORE_VAL(ve, vstr, idx),
1003 vallen) != 0)))
1004 res = false;
1005 }
1006 else
1007 res = false;
1008 }
1009
1010 PG_RETURN_BOOL(res);
1011 }
1012
1013
1014 PG_FUNCTION_INFO_V1(hstore_contained);
1015 Datum
hstore_contained(PG_FUNCTION_ARGS)1016 hstore_contained(PG_FUNCTION_ARGS)
1017 {
1018 PG_RETURN_DATUM(DirectFunctionCall2(hstore_contains,
1019 PG_GETARG_DATUM(1),
1020 PG_GETARG_DATUM(0)
1021 ));
1022 }
1023
1024
1025 PG_FUNCTION_INFO_V1(hstore_each);
1026 Datum
hstore_each(PG_FUNCTION_ARGS)1027 hstore_each(PG_FUNCTION_ARGS)
1028 {
1029 FuncCallContext *funcctx;
1030 HStore *hs;
1031 int i;
1032
1033 if (SRF_IS_FIRSTCALL())
1034 {
1035 hs = PG_GETARG_HS(0);
1036 funcctx = SRF_FIRSTCALL_INIT();
1037 setup_firstcall(funcctx, hs, fcinfo);
1038 }
1039
1040 funcctx = SRF_PERCALL_SETUP();
1041 hs = (HStore *) funcctx->user_fctx;
1042 i = funcctx->call_cntr;
1043
1044 if (i < HS_COUNT(hs))
1045 {
1046 HEntry *entries = ARRPTR(hs);
1047 char *ptr = STRPTR(hs);
1048 Datum res,
1049 dvalues[2];
1050 bool nulls[2] = {false, false};
1051 text *item;
1052 HeapTuple tuple;
1053
1054 item = cstring_to_text_with_len(HSTORE_KEY(entries, ptr, i),
1055 HSTORE_KEYLEN(entries, i));
1056 dvalues[0] = PointerGetDatum(item);
1057
1058 if (HSTORE_VALISNULL(entries, i))
1059 {
1060 dvalues[1] = (Datum) 0;
1061 nulls[1] = true;
1062 }
1063 else
1064 {
1065 item = cstring_to_text_with_len(HSTORE_VAL(entries, ptr, i),
1066 HSTORE_VALLEN(entries, i));
1067 dvalues[1] = PointerGetDatum(item);
1068 }
1069
1070 tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
1071 res = HeapTupleGetDatum(tuple);
1072
1073 SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
1074 }
1075
1076 SRF_RETURN_DONE(funcctx);
1077 }
1078
1079
1080 /*
1081 * btree sort order for hstores isn't intended to be useful; we really only
1082 * care about equality versus non-equality. we compare the entire string
1083 * buffer first, then the entry pos array.
1084 */
1085
1086 PG_FUNCTION_INFO_V1(hstore_cmp);
1087 Datum
hstore_cmp(PG_FUNCTION_ARGS)1088 hstore_cmp(PG_FUNCTION_ARGS)
1089 {
1090 HStore *hs1 = PG_GETARG_HS(0);
1091 HStore *hs2 = PG_GETARG_HS(1);
1092 int hcount1 = HS_COUNT(hs1);
1093 int hcount2 = HS_COUNT(hs2);
1094 int res = 0;
1095
1096 if (hcount1 == 0 || hcount2 == 0)
1097 {
1098 /*
1099 * if either operand is empty, and the other is nonempty, the nonempty
1100 * one is larger. If both are empty they are equal.
1101 */
1102 if (hcount1 > 0)
1103 res = 1;
1104 else if (hcount2 > 0)
1105 res = -1;
1106 }
1107 else
1108 {
1109 /* here we know both operands are nonempty */
1110 char *str1 = STRPTR(hs1);
1111 char *str2 = STRPTR(hs2);
1112 HEntry *ent1 = ARRPTR(hs1);
1113 HEntry *ent2 = ARRPTR(hs2);
1114 size_t len1 = HSE_ENDPOS(ent1[2 * hcount1 - 1]);
1115 size_t len2 = HSE_ENDPOS(ent2[2 * hcount2 - 1]);
1116
1117 res = memcmp(str1, str2, Min(len1, len2));
1118
1119 if (res == 0)
1120 {
1121 if (len1 > len2)
1122 res = 1;
1123 else if (len1 < len2)
1124 res = -1;
1125 else if (hcount1 > hcount2)
1126 res = 1;
1127 else if (hcount2 > hcount1)
1128 res = -1;
1129 else
1130 {
1131 int count = hcount1 * 2;
1132 int i;
1133
1134 for (i = 0; i < count; ++i)
1135 if (HSE_ENDPOS(ent1[i]) != HSE_ENDPOS(ent2[i]) ||
1136 HSE_ISNULL(ent1[i]) != HSE_ISNULL(ent2[i]))
1137 break;
1138 if (i < count)
1139 {
1140 if (HSE_ENDPOS(ent1[i]) < HSE_ENDPOS(ent2[i]))
1141 res = -1;
1142 else if (HSE_ENDPOS(ent1[i]) > HSE_ENDPOS(ent2[i]))
1143 res = 1;
1144 else if (HSE_ISNULL(ent1[i]))
1145 res = 1;
1146 else if (HSE_ISNULL(ent2[i]))
1147 res = -1;
1148 }
1149 }
1150 }
1151 else
1152 {
1153 res = (res > 0) ? 1 : -1;
1154 }
1155 }
1156
1157 /*
1158 * this is a btree support function; this is one of the few places where
1159 * memory needs to be explicitly freed.
1160 */
1161 PG_FREE_IF_COPY(hs1, 0);
1162 PG_FREE_IF_COPY(hs2, 1);
1163 PG_RETURN_INT32(res);
1164 }
1165
1166
1167 PG_FUNCTION_INFO_V1(hstore_eq);
1168 Datum
hstore_eq(PG_FUNCTION_ARGS)1169 hstore_eq(PG_FUNCTION_ARGS)
1170 {
1171 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
1172 PG_GETARG_DATUM(0),
1173 PG_GETARG_DATUM(1)));
1174
1175 PG_RETURN_BOOL(res == 0);
1176 }
1177
1178 PG_FUNCTION_INFO_V1(hstore_ne);
1179 Datum
hstore_ne(PG_FUNCTION_ARGS)1180 hstore_ne(PG_FUNCTION_ARGS)
1181 {
1182 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
1183 PG_GETARG_DATUM(0),
1184 PG_GETARG_DATUM(1)));
1185
1186 PG_RETURN_BOOL(res != 0);
1187 }
1188
1189 PG_FUNCTION_INFO_V1(hstore_gt);
1190 Datum
hstore_gt(PG_FUNCTION_ARGS)1191 hstore_gt(PG_FUNCTION_ARGS)
1192 {
1193 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
1194 PG_GETARG_DATUM(0),
1195 PG_GETARG_DATUM(1)));
1196
1197 PG_RETURN_BOOL(res > 0);
1198 }
1199
1200 PG_FUNCTION_INFO_V1(hstore_ge);
1201 Datum
hstore_ge(PG_FUNCTION_ARGS)1202 hstore_ge(PG_FUNCTION_ARGS)
1203 {
1204 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
1205 PG_GETARG_DATUM(0),
1206 PG_GETARG_DATUM(1)));
1207
1208 PG_RETURN_BOOL(res >= 0);
1209 }
1210
1211 PG_FUNCTION_INFO_V1(hstore_lt);
1212 Datum
hstore_lt(PG_FUNCTION_ARGS)1213 hstore_lt(PG_FUNCTION_ARGS)
1214 {
1215 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
1216 PG_GETARG_DATUM(0),
1217 PG_GETARG_DATUM(1)));
1218
1219 PG_RETURN_BOOL(res < 0);
1220 }
1221
1222 PG_FUNCTION_INFO_V1(hstore_le);
1223 Datum
hstore_le(PG_FUNCTION_ARGS)1224 hstore_le(PG_FUNCTION_ARGS)
1225 {
1226 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
1227 PG_GETARG_DATUM(0),
1228 PG_GETARG_DATUM(1)));
1229
1230 PG_RETURN_BOOL(res <= 0);
1231 }
1232
1233
1234 PG_FUNCTION_INFO_V1(hstore_hash);
1235 Datum
hstore_hash(PG_FUNCTION_ARGS)1236 hstore_hash(PG_FUNCTION_ARGS)
1237 {
1238 HStore *hs = PG_GETARG_HS(0);
1239 Datum hval = hash_any((unsigned char *) VARDATA(hs),
1240 VARSIZE(hs) - VARHDRSZ);
1241
1242 /*
1243 * this is the only place in the code that cares whether the overall
1244 * varlena size exactly matches the true data size; this assertion should
1245 * be maintained by all the other code, but we make it explicit here.
1246 */
1247 Assert(VARSIZE(hs) ==
1248 (HS_COUNT(hs) != 0 ?
1249 CALCDATASIZE(HS_COUNT(hs),
1250 HSE_ENDPOS(ARRPTR(hs)[2 * HS_COUNT(hs) - 1])) :
1251 HSHRDSIZE));
1252
1253 PG_FREE_IF_COPY(hs, 0);
1254 PG_RETURN_DATUM(hval);
1255 }
1256