2 * contrib/hstore/hstore_op.c
6 #include "access/hash.h"
7 #include "access/htup_details.h"
8 #include "catalog/pg_type.h"
10 #include "utils/builtins.h"
11 #include "utils/memutils.h"
12 #include "utils/pg_crc.h"
16 #ifndef SRF_RETURN_NEXT_NULL
17 #define SRF_RETURN_NEXT_NULL(_funcctx) \
20 (_funcctx)->call_cntr++; \
21 rsi = (ReturnSetInfo *) fcinfo->resultinfo; \
22 rsi->isDone = ExprMultipleResult; \
27 /* old names for C functions */
28 HSTORE_POLLUTE(hstore_fetchval, fetchval);
29 HSTORE_POLLUTE(hstore_exists, exists);
30 HSTORE_POLLUTE(hstore_defined, defined);
31 HSTORE_POLLUTE(hstore_delete, delete);
32 HSTORE_POLLUTE(hstore_concat, hs_concat);
33 HSTORE_POLLUTE(hstore_contains, hs_contains);
34 HSTORE_POLLUTE(hstore_contained, hs_contained);
35 HSTORE_POLLUTE(hstore_akeys, akeys);
36 HSTORE_POLLUTE(hstore_avals, avals);
37 HSTORE_POLLUTE(hstore_skeys, skeys);
38 HSTORE_POLLUTE(hstore_svals, svals);
39 HSTORE_POLLUTE(hstore_each, each);
42 arrayToHStoreSortedArray(ArrayType *a)
50 bool hasNonUniq = false;
53 TEXTOID, -1, false, 'i',
54 &key_datums, &key_nulls, &key_count);
60 * A text array uses at least eight bytes per element, so any overflow in
61 * "key_count * sizeof(Pairs)" is small enough for palloc() to catch.
62 * However, credible improvements to the array format could invalidate
63 * that assumption. Therefore, use an explicit check rather than relying
64 * on palloc() to complain.
66 if (key_count > MaxAllocSize / sizeof(HStorePair))
68 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
69 errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
70 key_count, (int) (MaxAllocSize / sizeof(HStorePair)))));
72 v = palloc(sizeof(*v));
74 v->array.scalar = false;
76 v->array.elems = palloc(sizeof(*v->hash.pairs) * key_count);
78 for (i = 0, j = 0; i < key_count; i++)
82 v->array.elems[j].type = hsvString;
83 v->array.elems[j].string.val = VARDATA(key_datums[i]);
84 v->array.elems[j].string.len = VARSIZE(key_datums[i]) - VARHDRSZ;
90 if (v->array.nelems > 1)
91 qsort_arg(v->array.elems, v->array.nelems, sizeof(*v->array.elems),
92 compareHStoreStringValue, &hasNonUniq);
96 HStoreValue *ptr = v->array.elems + 1,
97 *res = v->array.elems;
99 while (ptr - v->array.elems < v->array.nelems)
101 if (!(ptr->string.len == res->string.len &&
102 memcmp(ptr->string.val, res->string.val, ptr->string.len) == 0))
111 v->array.nelems = res + 1 - v->array.elems;
118 findInHStoreSortedArray(HStoreValue *a, uint32 *lowbound,
119 char *key, uint32 keylen)
121 HStoreValue *stopLow = a->array.elems + ((lowbound) ? *lowbound : 0),
122 *stopHigh = a->array.elems + a->array.nelems,
125 while (stopLow < stopHigh)
129 stopMiddle = stopLow + (stopHigh - stopLow) / 2;
131 if (keylen == stopMiddle->string.len)
132 diff = memcmp(stopMiddle->string.val, key, keylen);
134 diff = (stopMiddle->string.len > keylen) ? 1 : -1;
139 *lowbound = (stopMiddle - a->array.elems) + 1;
144 stopLow = stopMiddle + 1;
148 stopHigh = stopMiddle;
153 *lowbound = (stopLow - a->array.elems) + 1;
158 PG_FUNCTION_INFO_V1(hstore_fetchval);
159 Datum hstore_fetchval(PG_FUNCTION_ARGS);
161 hstore_fetchval(PG_FUNCTION_ARGS)
163 HStore *hs = PG_GETARG_HS(0);
164 text *key = PG_GETARG_TEXT_PP(1);
165 HStoreValue *v = NULL;
169 v = findUncompressedHStoreValue(VARDATA(hs),
170 HS_FLAG_HSTORE | HS_FLAG_ARRAY,
173 VARSIZE_ANY_EXHDR(key));
175 if ((out = HStoreValueToText(v)) == NULL)
178 PG_RETURN_TEXT_P(out);
181 PG_FUNCTION_INFO_V1(hstore_fetchval_numeric);
182 Datum hstore_fetchval_numeric(PG_FUNCTION_ARGS);
184 hstore_fetchval_numeric(PG_FUNCTION_ARGS)
186 HStore *hs = PG_GETARG_HS(0);
187 text *key = PG_GETARG_TEXT_PP(1);
188 HStoreValue *v = NULL;
191 v = findUncompressedHStoreValue(VARDATA(hs),
192 HS_FLAG_HSTORE | HS_FLAG_ARRAY,
195 VARSIZE_ANY_EXHDR(key));
197 if (v && v->type == hsvNumeric)
199 Numeric out = palloc(VARSIZE_ANY(v->numeric));
201 memcpy(out, v->numeric, VARSIZE_ANY(v->numeric));
202 PG_RETURN_NUMERIC(out);
208 PG_FUNCTION_INFO_V1(hstore_fetchval_boolean);
209 Datum hstore_fetchval_boolean(PG_FUNCTION_ARGS);
211 hstore_fetchval_boolean(PG_FUNCTION_ARGS)
213 HStore *hs = PG_GETARG_HS(0);
214 text *key = PG_GETARG_TEXT_PP(1);
215 HStoreValue *v = NULL;
218 v = findUncompressedHStoreValue(VARDATA(hs),
219 HS_FLAG_HSTORE | HS_FLAG_ARRAY,
222 VARSIZE_ANY_EXHDR(key));
224 if (v && v->type == hsvBool)
225 PG_RETURN_BOOL(v->boolean);
230 PG_FUNCTION_INFO_V1(hstore_fetchval_n);
231 Datum hstore_fetchval_n(PG_FUNCTION_ARGS);
233 hstore_fetchval_n(PG_FUNCTION_ARGS)
235 HStore *hs = PG_GETARG_HS(0);
236 int i = PG_GETARG_INT32(1);
237 HStoreValue *v = NULL;
241 v = getHStoreValue(VARDATA(hs), HS_FLAG_HSTORE | HS_FLAG_ARRAY, i);
243 if ((out = HStoreValueToText(v)) == NULL)
246 PG_RETURN_TEXT_P(out);
249 PG_FUNCTION_INFO_V1(hstore_fetchval_n_numeric);
250 Datum hstore_fetchval_n_numeric(PG_FUNCTION_ARGS);
252 hstore_fetchval_n_numeric(PG_FUNCTION_ARGS)
254 HStore *hs = PG_GETARG_HS(0);
255 int i = PG_GETARG_INT32(1);
256 HStoreValue *v = NULL;
259 v = getHStoreValue(VARDATA(hs), HS_FLAG_HSTORE | HS_FLAG_ARRAY, i);
261 if (v && v->type == hsvNumeric)
263 Numeric out = palloc(VARSIZE_ANY(v->numeric));
265 memcpy(out, v->numeric, VARSIZE_ANY(v->numeric));
266 PG_RETURN_NUMERIC(out);
272 PG_FUNCTION_INFO_V1(hstore_fetchval_n_boolean);
273 Datum hstore_fetchval_n_boolean(PG_FUNCTION_ARGS);
275 hstore_fetchval_n_boolean(PG_FUNCTION_ARGS)
277 HStore *hs = PG_GETARG_HS(0);
278 int i = PG_GETARG_INT32(1);
279 HStoreValue *v = NULL;
282 v = getHStoreValue(VARDATA(hs), HS_FLAG_HSTORE | HS_FLAG_ARRAY, i);
284 if (v && v->type == hsvBool)
285 PG_RETURN_BOOL(v->boolean);
291 h_atoi(char *c, int l, int *acc)
293 bool negative = false;
298 while(isspace(*p) && p - c < l)
335 hstoreDeepFetch(HStore *in, ArrayType *path)
337 HStoreValue *v = NULL;
338 static HStoreValue init /* could be returned */;
343 Assert(ARR_ELEMTYPE(path) == TEXTOID);
345 if (ARR_NDIM(path) > 1)
347 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
348 errmsg("wrong number of array subscripts")));
350 if (HS_ROOT_COUNT(in) == 0)
353 deconstruct_array(path, TEXTOID, -1, false, 'i',
354 &path_elems, &path_nulls, &path_len);
356 init.type = hsvBinary;
357 init.size = VARSIZE(in);
358 init.binary.data = VARDATA(in);
359 init.binary.len = VARSIZE_ANY_EXHDR(in);
366 for(i=0; v != NULL && i<path_len; i++)
370 if (v->type != hsvBinary || path_nulls[i])
373 header = *(uint32*)v->binary.data;
375 if (header & HS_FLAG_HSTORE)
377 v = findUncompressedHStoreValue(v->binary.data, HS_FLAG_HSTORE,
379 VARDATA_ANY(path_elems[i]),
380 VARSIZE_ANY_EXHDR(path_elems[i]));
382 else if (header & HS_FLAG_ARRAY)
386 if (h_atoi(VARDATA_ANY(path_elems[i]),
387 VARSIZE_ANY_EXHDR(path_elems[i]), &ith) == false)
392 if (-ith > (int)(header & HS_COUNT_MASK))
395 ith = ((int)(header & HS_COUNT_MASK)) + ith;
399 if (ith >= (int)(header & HS_COUNT_MASK))
403 v = getHStoreValue(v->binary.data, HS_FLAG_ARRAY, ith);
407 elog(PANIC,"wrong header type: %08x", header);
414 PG_FUNCTION_INFO_V1(hstore_fetchval_path);
415 Datum hstore_fetchval_path(PG_FUNCTION_ARGS);
417 hstore_fetchval_path(PG_FUNCTION_ARGS)
419 HStore *hs = PG_GETARG_HS(0);
420 ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
423 if ((out = HStoreValueToText(hstoreDeepFetch(hs, path))) == NULL)
426 PG_RETURN_TEXT_P(out);
429 PG_FUNCTION_INFO_V1(hstore_fetchval_path_numeric);
430 Datum hstore_fetchval_path_numeric(PG_FUNCTION_ARGS);
432 hstore_fetchval_path_numeric(PG_FUNCTION_ARGS)
434 HStore *hs = PG_GETARG_HS(0);
435 ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
436 HStoreValue *v = NULL;
439 v = hstoreDeepFetch(hs, path);
441 if (v && v->type == hsvNumeric)
443 Numeric out = palloc(VARSIZE_ANY(v->numeric));
445 memcpy(out, v->numeric, VARSIZE_ANY(v->numeric));
446 PG_RETURN_NUMERIC(out);
452 PG_FUNCTION_INFO_V1(hstore_fetchval_path_boolean);
453 Datum hstore_fetchval_path_boolean(PG_FUNCTION_ARGS);
455 hstore_fetchval_path_boolean(PG_FUNCTION_ARGS)
457 HStore *hs = PG_GETARG_HS(0);
458 ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
459 HStoreValue *v = NULL;
462 v = hstoreDeepFetch(hs, path);
464 if (v && v->type == hsvBool)
465 PG_RETURN_BOOL(v->boolean);
471 HStoreValueToHStore(HStoreValue *v)
475 if (v == NULL || v->type == hsvNull)
479 else if (v->type == hsvString || v->type == hsvBool ||
480 v->type == hsvNumeric)
482 ToHStoreState *state = NULL;
485 HStoreValue scalarArray;
487 scalarArray.type = hsvArray;
488 scalarArray.array.scalar = true;
489 scalarArray.array.nelems = 1;
491 pushHStoreValue(&state, WHS_BEGIN_ARRAY, &scalarArray);
492 pushHStoreValue(&state, WHS_ELEM, v);
493 res = pushHStoreValue(&state, WHS_END_ARRAY, NULL);
495 out = palloc(VARHDRSZ + res->size);
496 SET_VARSIZE(out, VARHDRSZ + res->size);
497 r = compressHStore(res, VARDATA(out));
498 Assert(r <= res->size);
499 SET_VARSIZE(out, r + VARHDRSZ);
503 out = palloc(VARHDRSZ + v->size);
505 Assert(v->type == hsvBinary);
506 SET_VARSIZE(out, VARHDRSZ + v->binary.len);
507 memcpy(VARDATA(out), v->binary.data, v->binary.len);
513 PG_FUNCTION_INFO_V1(hstore_fetchval_hstore);
514 Datum hstore_fetchval_hstore(PG_FUNCTION_ARGS);
516 hstore_fetchval_hstore(PG_FUNCTION_ARGS)
518 HStore *hs = PG_GETARG_HS(0);
519 text *key = PG_GETARG_TEXT_PP(1);
520 HStoreValue *v = NULL;
524 v = findUncompressedHStoreValue(VARDATA(hs),
525 HS_FLAG_HSTORE | HS_FLAG_ARRAY,
528 VARSIZE_ANY_EXHDR(key));
531 if ((out = HStoreValueToHStore(v)) == NULL)
534 PG_RETURN_POINTER(out);
537 PG_FUNCTION_INFO_V1(hstore_fetchval_n_hstore);
538 Datum hstore_fetchval_n_hstore(PG_FUNCTION_ARGS);
540 hstore_fetchval_n_hstore(PG_FUNCTION_ARGS)
542 HStore *hs = PG_GETARG_HS(0);
543 int i = PG_GETARG_INT32(1);
544 HStoreValue *v = NULL;
548 v = getHStoreValue(VARDATA(hs), HS_FLAG_HSTORE | HS_FLAG_ARRAY, i);
550 if ((out = HStoreValueToHStore(v)) == NULL)
553 PG_RETURN_POINTER(out);
556 PG_FUNCTION_INFO_V1(hstore_fetchval_path_hstore);
557 Datum hstore_fetchval_path_hstore(PG_FUNCTION_ARGS);
559 hstore_fetchval_path_hstore(PG_FUNCTION_ARGS)
561 HStore *hs = PG_GETARG_HS(0);
562 ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
565 if ((out = HStoreValueToHStore(hstoreDeepFetch(hs, path))) == NULL)
568 PG_RETURN_POINTER(out);
571 PG_FUNCTION_INFO_V1(hstore_exists);
572 Datum hstore_exists(PG_FUNCTION_ARGS);
574 hstore_exists(PG_FUNCTION_ARGS)
576 HStore *hs = PG_GETARG_HS(0);
577 text *key = PG_GETARG_TEXT_PP(1);
578 HStoreValue *v = NULL;
581 v = findUncompressedHStoreValue(VARDATA(hs),
582 HS_FLAG_HSTORE | HS_FLAG_ARRAY,
585 VARSIZE_ANY_EXHDR(key));
587 PG_RETURN_BOOL(v != NULL);
591 PG_FUNCTION_INFO_V1(hstore_exists_idx);
592 Datum hstore_exists_idx(PG_FUNCTION_ARGS);
594 hstore_exists_idx(PG_FUNCTION_ARGS)
596 HStore *hs = PG_GETARG_HS(0);
597 int ith = PG_GETARG_INT32(1);
598 HStoreValue *v = NULL;
601 v = getHStoreValue(VARDATA(hs), HS_FLAG_HSTORE | HS_FLAG_ARRAY, ith);
603 PG_RETURN_BOOL(v != NULL);
606 PG_FUNCTION_INFO_V1(hstore_exists_path);
607 Datum hstore_exists_path(PG_FUNCTION_ARGS);
609 hstore_exists_path(PG_FUNCTION_ARGS)
611 HStore *hs = PG_GETARG_HS(0);
612 ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
614 PG_RETURN_BOOL(hstoreDeepFetch(hs, path) != NULL);
619 PG_FUNCTION_INFO_V1(hstore_exists_any);
620 Datum hstore_exists_any(PG_FUNCTION_ARGS);
622 hstore_exists_any(PG_FUNCTION_ARGS)
624 HStore *hs = PG_GETARG_HS(0);
625 ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
626 HStoreValue *v = arrayToHStoreSortedArray(keys);
628 uint32 *plowbound = NULL, lowbound = 0;
631 if (HS_ISEMPTY(hs) || v == NULL || v->hash.npairs == 0)
632 PG_RETURN_BOOL(false);
634 if (HS_ROOT_IS_HASH(hs))
635 plowbound = &lowbound;
637 * we exploit the fact that the pairs list is already sorted into strictly
638 * increasing order to narrow the findUncompressedHStoreValue search; each search can
639 * start one entry past the previous "found" entry, or at the lower bound
640 * of the last search.
642 for (i = 0; i < v->array.nelems; i++)
644 if (findUncompressedHStoreValueByValue(VARDATA(hs), HS_FLAG_HSTORE | HS_FLAG_ARRAY, plowbound,
645 v->array.elems + i) != NULL)
656 PG_FUNCTION_INFO_V1(hstore_exists_all);
657 Datum hstore_exists_all(PG_FUNCTION_ARGS);
659 hstore_exists_all(PG_FUNCTION_ARGS)
661 HStore *hs = PG_GETARG_HS(0);
662 ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
663 HStoreValue *v = arrayToHStoreSortedArray(keys);
665 uint32 *plowbound = NULL, lowbound = 0;
668 if (HS_ISEMPTY(hs) || v == NULL || v->array.nelems == 0)
671 if (v == NULL || v->array.nelems == 0)
672 PG_RETURN_BOOL(true); /* compatibility */
674 PG_RETURN_BOOL(false);
677 if (HS_ROOT_IS_HASH(hs))
678 plowbound = &lowbound;
680 * we exploit the fact that the pairs list is already sorted into strictly
681 * increasing order to narrow the findUncompressedHStoreValue search;
682 * each search can start one entry past the previous "found" entry,
683 * or at the lower bound of the last search.
685 for (i = 0; i < v->array.nelems; i++)
687 if (findUncompressedHStoreValueByValue(VARDATA(hs),
688 HS_FLAG_HSTORE | HS_FLAG_ARRAY,
690 v->array.elems + i) == NULL)
701 PG_FUNCTION_INFO_V1(hstore_defined);
702 Datum hstore_defined(PG_FUNCTION_ARGS);
704 hstore_defined(PG_FUNCTION_ARGS)
706 HStore *hs = PG_GETARG_HS(0);
707 text *key = PG_GETARG_TEXT_PP(1);
708 HStoreValue *v = NULL;
711 v = findUncompressedHStoreValue(VARDATA(hs),
712 HS_FLAG_HSTORE | HS_FLAG_ARRAY,
715 VARSIZE_ANY_EXHDR(key));
717 PG_RETURN_BOOL(!(v == NULL || v->type == hsvNull));
721 PG_FUNCTION_INFO_V1(hstore_delete);
722 Datum hstore_delete(PG_FUNCTION_ARGS);
724 hstore_delete(PG_FUNCTION_ARGS)
726 HStore *in = PG_GETARG_HS(0);
727 text *key = PG_GETARG_TEXT_PP(1);
728 char *keyptr = VARDATA_ANY(key);
729 int keylen = VARSIZE_ANY_EXHDR(key);
730 HStore *out = palloc(VARSIZE(in));
731 ToHStoreState *toState = NULL;
734 HStoreValue v, *res = NULL;
735 bool skipNested = false;
737 SET_VARSIZE(out, VARSIZE(in));
740 PG_RETURN_POINTER(out);
742 it = HStoreIteratorInit(VARDATA(in));
744 while((r = HStoreIteratorGet(&it, &v, skipNested)) != 0)
748 if ((r == WHS_ELEM || r == WHS_KEY) &&
749 (v.type == hsvString && keylen == v.string.len &&
750 memcmp(keyptr, v.string.val, keylen) == 0))
753 /* skip corresponding value */
754 HStoreIteratorGet(&it, &v, true);
759 res = pushHStoreValue(&toState, r, &v);
762 if (res == NULL || (res->type == hsvArray && res->array.nelems == 0) ||
763 (res->type == hsvHash && res->hash.npairs == 0) )
765 SET_VARSIZE(out, VARHDRSZ);
769 r = compressHStore(res, VARDATA(out));
770 SET_VARSIZE(out, r + VARHDRSZ);
773 PG_RETURN_POINTER(out);
776 PG_FUNCTION_INFO_V1(hstore_delete_array);
777 Datum hstore_delete_array(PG_FUNCTION_ARGS);
779 hstore_delete_array(PG_FUNCTION_ARGS)
781 HStore *in = PG_GETARG_HS(0);
782 HStore *out = palloc(VARSIZE(in));
783 HStoreValue *a = arrayToHStoreSortedArray(PG_GETARG_ARRAYTYPE_P(1));
785 ToHStoreState *toState = NULL;
787 HStoreValue v, *res = NULL;
788 bool skipNested = false;
792 if (HS_ISEMPTY(in) || a == NULL || a->array.nelems == 0)
794 memcpy(out, in, VARSIZE(in));
795 PG_RETURN_POINTER(out);
798 it = HStoreIteratorInit(VARDATA(in));
800 while((r = HStoreIteratorGet(&it, &v, skipNested)) != 0)
803 if (skipNested == false)
805 Assert(v.type == hsvArray || v.type == hsvHash);
806 isHash = (v.type == hsvArray) ? false : true;
810 if ((r == WHS_ELEM || r == WHS_KEY) && v.type == hsvString &&
818 diff = compareHStoreStringValue(&v, a->array.elems + i,
823 } while(diff > 0 && i < a->array.nelems);
827 diff = (findInHStoreSortedArray(a, NULL,
829 v.string.len) == NULL) ? 1 : 0;
835 /* skip corresponding value */
836 HStoreIteratorGet(&it, &v, true);
842 res = pushHStoreValue(&toState, r, &v);
845 if (res == NULL || (res->type == hsvArray && res->array.nelems == 0) ||
846 (res->type == hsvHash && res->hash.npairs == 0) )
848 SET_VARSIZE(out, VARHDRSZ);
852 r = compressHStore(res, VARDATA(out));
853 SET_VARSIZE(out, r + VARHDRSZ);
856 PG_RETURN_POINTER(out);
860 PG_FUNCTION_INFO_V1(hstore_delete_hstore);
861 Datum hstore_delete_hstore(PG_FUNCTION_ARGS);
863 hstore_delete_hstore(PG_FUNCTION_ARGS)
865 HStore *hs1 = PG_GETARG_HS(0);
866 HStore *hs2 = PG_GETARG_HS(1);
867 HStore *out = palloc(VARSIZE(hs1));
868 HStoreIterator *it1, *it2;
869 ToHStoreState *toState = NULL;
871 HStoreValue v1, v2, *res = NULL;
872 bool isHash1, isHash2;
874 if (HS_ISEMPTY(hs1) || HS_ISEMPTY(hs2))
876 memcpy(out, hs1, VARSIZE(hs1));
877 PG_RETURN_POINTER(out);
880 it1 = HStoreIteratorInit(VARDATA(hs1));
881 r1 = HStoreIteratorGet(&it1, &v1, false);
882 isHash1 = (v1.type == hsvArray) ? false : true;
884 it2 = HStoreIteratorInit(VARDATA(hs2));
885 r2 = HStoreIteratorGet(&it2, &v2, false);
886 isHash2 = (v2.type == hsvArray) ? false : true;
888 res = pushHStoreValue(&toState, r1, &v1);
890 if (isHash1 == true && isHash2 == true)
895 while((r1 = HStoreIteratorGet(&it1, &v1, true)) != 0)
897 if (r1 == WHS_KEY && fin2 == false)
905 (r2 = HStoreIteratorGet(&it2, &v2, true)) != 0)
910 diff = compareHStoreStringValue(&v1, &v2, NULL);
912 if (diff > 0 && keyIsDef)
928 r1 = HStoreIteratorGet(&it1, &vk, true);
929 r2 = HStoreIteratorGet(&it2, &v2, true);
931 Assert(r1 == WHS_VALUE && r2 == WHS_VALUE);
933 if (compareHStoreValue(&vk, &v2) != 0)
935 res = pushHStoreValue(&toState, WHS_KEY, &v1);
936 res = pushHStoreValue(&toState, WHS_VALUE, &vk);
947 res = pushHStoreValue(&toState, r1, &v1);
952 while((r1 = HStoreIteratorGet(&it1, &v1, true)) != 0)
955 if (r1 == WHS_ELEM || r1 == WHS_KEY)
959 it2 = HStoreIteratorInit(VARDATA(hs2));
961 r2 = HStoreIteratorGet(&it2, &v2, false);
963 while(diff && (r2 = HStoreIteratorGet(&it2, &v2, true)) != 0)
965 if (r2 == WHS_KEY || r2 == WHS_VALUE || r2 == WHS_ELEM)
966 diff = compareHStoreValue(&v1, &v2);
972 HStoreIteratorGet(&it1, &v1, true);
977 res = pushHStoreValue(&toState, r1, &v1);
981 if (res == NULL || (res->type == hsvArray && res->array.nelems == 0) ||
982 (res->type == hsvHash && res->hash.npairs == 0) )
984 SET_VARSIZE(out, VARHDRSZ);
988 int r = compressHStore(res, VARDATA(out));
989 SET_VARSIZE(out, r + VARHDRSZ);
992 PG_RETURN_POINTER(out);
996 deletePathDo(HStoreIterator **it, Datum *path_elems,
997 bool *path_nulls, int path_len,
998 ToHStoreState **st, int level)
1000 HStoreValue v, *res = NULL;
1003 r = HStoreIteratorGet(it, &v, false);
1005 if (r == WHS_BEGIN_ARRAY)
1008 uint32 n = v.array.nelems;
1011 if (level >= path_len || path_nulls[level] ||
1012 h_atoi(VARDATA_ANY(path_elems[level]),
1013 VARSIZE_ANY_EXHDR(path_elems[level]), &skipIdx) == false)
1017 else if (skipIdx < 0)
1022 skipIdx = n + skipIdx;
1028 if (skipIdx == 0 && n == 1)
1030 r = HStoreIteratorGet(it, &v, true);
1031 Assert(r == WHS_ELEM);
1032 r = HStoreIteratorGet(it, &v, true);
1033 Assert(r == WHS_END_ARRAY);
1037 pushHStoreValue(st, r, &v);
1039 for(i=0; i<skipIdx; i++) {
1040 r = HStoreIteratorGet(it, &v, true);
1041 Assert(r == WHS_ELEM);
1042 res = pushHStoreValue(st, r, &v);
1045 if (level >= path_len || skipIdx == n) {
1046 r = HStoreIteratorGet(it, &v, true);
1047 Assert(r == WHS_END_ARRAY);
1048 res = pushHStoreValue(st, r, &v);
1052 if (level == path_len - 1)
1054 /* last level in path, skip all elem */
1055 r = HStoreIteratorGet(it, &v, true);
1056 Assert(r == WHS_ELEM);
1060 res = deletePathDo(it, path_elems, path_nulls, path_len, st,
1064 for(i = skipIdx + 1; i<n; i++) {
1065 r = HStoreIteratorGet(it, &v, true);
1066 Assert(r == WHS_ELEM);
1067 res = pushHStoreValue(st, r, &v);
1070 r = HStoreIteratorGet(it, &v, true);
1071 Assert(r == WHS_END_ARRAY);
1072 res = pushHStoreValue(st, r, &v);
1074 else if (r == WHS_BEGIN_HASH)
1077 uint32 n = v.hash.npairs;
1081 if (n == 1 && level == path_len - 1)
1083 r = HStoreIteratorGet(it, &k, false);
1084 Assert(r == WHS_KEY);
1086 if ( path_nulls[level] == false &&
1087 k.string.len == VARSIZE_ANY_EXHDR(path_elems[level]) &&
1088 memcmp(k.string.val, VARDATA_ANY(path_elems[level]),
1091 r = HStoreIteratorGet(it, &v, true);
1092 Assert(r == WHS_VALUE);
1093 r = HStoreIteratorGet(it, &v, true);
1094 Assert(r == WHS_END_HASH);
1098 pushHStoreValue(st, WHS_BEGIN_HASH, &v);
1099 pushHStoreValue(st, WHS_KEY, &k);
1100 r = HStoreIteratorGet(it, &v, true);
1101 Assert(r == WHS_VALUE);
1102 pushHStoreValue(st, r, &v);
1103 r = HStoreIteratorGet(it, &v, true);
1104 Assert(r == WHS_END_HASH);
1105 return pushHStoreValue(st, r, &v);
1108 pushHStoreValue(st, WHS_BEGIN_HASH, &v);
1110 if (level >= path_len || path_nulls[level])
1115 r = HStoreIteratorGet(it, &k, false);
1116 Assert(r == WHS_KEY);
1118 if (done == false &&
1119 k.string.len == VARSIZE_ANY_EXHDR(path_elems[level]) &&
1120 memcmp(k.string.val, VARDATA_ANY(path_elems[level]),
1125 if (level == path_len - 1)
1127 r = HStoreIteratorGet(it, &v, true);
1128 Assert(r == WHS_VALUE);
1132 pushHStoreValue(st, r, &k);
1133 res = deletePathDo(it, path_elems, path_nulls, path_len,
1138 pushHStoreValue(st, WHS_VALUE, &v);
1145 pushHStoreValue(st, r, &k);
1146 r = HStoreIteratorGet(it, &v, true);
1147 Assert(r == WHS_VALUE);
1148 pushHStoreValue(st, r, &v);
1151 r = HStoreIteratorGet(it, &v, true);
1152 Assert(r == WHS_END_HASH);
1153 res = pushHStoreValue(st, r, &v);
1155 else if (r == WHS_ELEM || r == WHS_VALUE) /* just a string or null */
1157 pushHStoreValue(st, r, &v);
1158 res = (void*)0x01; /* dummy value */
1162 elog(PANIC, "impossible state");
1169 PG_FUNCTION_INFO_V1(hstore_delete_path);
1170 Datum hstore_delete_path(PG_FUNCTION_ARGS);
1172 hstore_delete_path(PG_FUNCTION_ARGS)
1174 HStore *in = PG_GETARG_HS(0);
1175 HStore *out = palloc(VARSIZE(in));
1176 ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
1177 HStoreValue *res = NULL;
1182 ToHStoreState *st = NULL;
1184 Assert(ARR_ELEMTYPE(path) == TEXTOID);
1186 if (ARR_NDIM(path) > 1)
1188 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1189 errmsg("wrong number of array subscripts")));
1191 if (HS_ROOT_COUNT(in) == 0)
1193 memcpy(out, in, VARSIZE(in));
1194 PG_RETURN_POINTER(out);
1197 deconstruct_array(path, TEXTOID, -1, false, 'i',
1198 &path_elems, &path_nulls, &path_len);
1202 memcpy(out, in, VARSIZE(in));
1203 PG_RETURN_POINTER(out);
1206 it = HStoreIteratorInit(VARDATA(in));
1208 res = deletePathDo(&it, path_elems, path_nulls, path_len, &st, 0);
1212 SET_VARSIZE(out, VARHDRSZ);
1218 sz = compressHStore(res, VARDATA(out));
1219 SET_VARSIZE(out, sz + VARHDRSZ);
1222 PG_RETURN_POINTER(out);
1225 PG_FUNCTION_INFO_V1(hstore_delete_idx);
1226 Datum hstore_delete_idx(PG_FUNCTION_ARGS);
1228 hstore_delete_idx(PG_FUNCTION_ARGS)
1230 HStore *in = PG_GETARG_HS(0);
1231 int idx = PG_GETARG_INT32(1);
1232 HStore *out = palloc(VARSIZE(in));
1233 ToHStoreState *toState = NULL;
1236 HStoreValue v, *res = NULL;
1240 memcpy(out, in, VARSIZE(in));
1241 PG_RETURN_POINTER(out);
1244 it = HStoreIteratorInit(VARDATA(in));
1246 r = HStoreIteratorGet(&it, &v, false);
1247 if (r == WHS_BEGIN_ARRAY)
1262 memcpy(out, in, VARSIZE(in));
1263 PG_RETURN_POINTER(out);
1266 pushHStoreValue(&toState, r, &v);
1268 while((r = HStoreIteratorGet(&it, &v, true)) != 0)
1270 if (r == WHS_ELEM || r == WHS_KEY)
1275 HStoreIteratorGet(&it, &v, true); /* skip value */
1280 res = pushHStoreValue(&toState, r, &v);
1283 if (res == NULL || (res->type == hsvArray && res->array.nelems == 0) ||
1284 (res->type == hsvHash && res->hash.npairs == 0) )
1286 SET_VARSIZE(out, VARHDRSZ);
1290 r = compressHStore(res, VARDATA(out));
1291 SET_VARSIZE(out, r + VARHDRSZ);
1294 PG_RETURN_POINTER(out);
1298 convertScalarToString(HStoreValue *v)
1302 elog(ERROR, "key in hstore type could not be a NULL");
1305 v->type = hsvString;
1306 v->string.val = pnstrdup((v->boolean) ? "t" : "f", 1);
1308 v->size = sizeof(HEntry) + v->string.len;
1311 v->type = hsvString;
1312 v->string.val = DatumGetCString(
1313 DirectFunctionCall1(numeric_out,
1314 PointerGetDatum(v->numeric)));
1315 v->string.len = strlen(v->string.val);
1316 v->size = sizeof(HEntry) + v->string.len;
1321 elog(PANIC,"Could not convert to string");
1325 static HStoreValue *
1326 IteratorConcat(HStoreIterator **it1, HStoreIterator **it2,
1327 ToHStoreState **toState)
1329 uint32 r1, r2, rk1, rk2;
1330 HStoreValue v1, v2, *res = NULL;
1332 r1 = rk1 = HStoreIteratorGet(it1, &v1, false);
1333 r2 = rk2 = HStoreIteratorGet(it2, &v2, false);
1335 if (rk1 == WHS_BEGIN_HASH && rk2 == WHS_BEGIN_HASH)
1340 res = pushHStoreValue(toState, r1, &v1);
1344 r1 = HStoreIteratorGet(it1, &v1, true);
1346 Assert(r1 == WHS_KEY || r1 == WHS_VALUE || r1 == WHS_END_HASH);
1348 if (r1 == WHS_KEY && fin2 == false)
1355 while(keyIsDef || (r2 = HStoreIteratorGet(it2, &v2, true)) != 0)
1360 diff = compareHStoreStringValue(&v1, &v2, NULL);
1367 pushHStoreValue(toState, r2, &v2);
1368 r2 = HStoreIteratorGet(it2, &v2, true);
1369 Assert(r2 == WHS_VALUE);
1370 pushHStoreValue(toState, r2, &v2);
1386 pushHStoreValue(toState, r1, &v1);
1388 r1 = HStoreIteratorGet(it1, &v1, true); /* ignore */
1389 r2 = HStoreIteratorGet(it2, &v2, true); /* new val */
1391 Assert(r1 == WHS_VALUE && r2 == WHS_VALUE);
1392 pushHStoreValue(toState, r2, &v2);
1401 else if (r1 == WHS_END_HASH)
1409 (r2 = HStoreIteratorGet(it2, &v2, true)) != 0)
1414 pushHStoreValue(toState, r2, &v2);
1415 r2 = HStoreIteratorGet(it2, &v2, true);
1416 Assert(r2 == WHS_VALUE);
1417 pushHStoreValue(toState, r2, &v2);
1422 res = pushHStoreValue(toState, r1, &v1);
1426 res = pushHStoreValue(toState, r1, &v1);
1429 else if ((rk1 == WHS_BEGIN_HASH || rk1 == WHS_BEGIN_ARRAY) &&
1430 (rk2 == WHS_BEGIN_HASH || rk2 == WHS_BEGIN_ARRAY))
1432 if (rk1 == WHS_BEGIN_HASH && rk2 == WHS_BEGIN_ARRAY &&
1433 v2.array.nelems % 2 != 0)
1434 elog(ERROR, "hstore's array must have even number of elements");
1436 res = pushHStoreValue(toState, r1, &v1);
1440 r1 = HStoreIteratorGet(it1, &v1, true);
1441 if (r1 == WHS_END_HASH || r1 == WHS_END_ARRAY)
1443 Assert(r1 == WHS_KEY || r1 == WHS_VALUE || r1 == WHS_ELEM);
1444 pushHStoreValue(toState, r1, &v1);
1447 while((r2 = HStoreIteratorGet(it2, &v2, true)) != 0)
1449 if (!(r2 == WHS_END_HASH || r2 == WHS_END_ARRAY))
1451 if (rk1 == WHS_BEGIN_HASH)
1453 convertScalarToString(&v2);
1454 pushHStoreValue(toState, WHS_KEY, &v2);
1455 r2 = HStoreIteratorGet(it2, &v2, true);
1456 Assert(r2 == WHS_ELEM);
1457 pushHStoreValue(toState, WHS_VALUE, &v2);
1461 pushHStoreValue(toState, WHS_ELEM, &v2);
1466 res = pushHStoreValue(toState,
1467 (rk1 == WHS_BEGIN_HASH) ? WHS_END_HASH : WHS_END_ARRAY,
1468 NULL/* signal to sort */);
1470 else if ((rk1 & (WHS_VALUE | WHS_ELEM)) != 0)
1472 if (v2.type == hsvArray && v2.array.scalar)
1474 Assert(v2.array.nelems == 1);
1475 r2 = HStoreIteratorGet(it2, &v2, false);
1476 pushHStoreValue(toState, r1, &v2);
1480 res = pushHStoreValue(toState, r2, &v2);
1481 while((r2 = HStoreIteratorGet(it2, &v2, true)) != 0)
1482 res = pushHStoreValue(toState, r2, &v2);
1487 elog(ERROR, "invalid concatnation of hstores");
1493 PG_FUNCTION_INFO_V1(hstore_concat);
1494 Datum hstore_concat(PG_FUNCTION_ARGS);
1496 hstore_concat(PG_FUNCTION_ARGS)
1498 HStore *hs1 = PG_GETARG_HS(0);
1499 HStore *hs2 = PG_GETARG_HS(1);
1500 HStore *out = palloc(VARSIZE(hs1) + VARSIZE(hs2));
1501 ToHStoreState *toState = NULL;
1503 HStoreIterator *it1, *it2;
1505 if (HS_ISEMPTY(hs1))
1507 memcpy(out, hs2, VARSIZE(hs2));
1508 PG_RETURN_POINTER(out);
1510 else if (HS_ISEMPTY(hs2))
1512 memcpy(out, hs1, VARSIZE(hs1));
1513 PG_RETURN_POINTER(out);
1516 it1 = HStoreIteratorInit(VARDATA(hs1));
1517 it2 = HStoreIteratorInit(VARDATA(hs2));
1519 res = IteratorConcat(&it1, &it2, &toState);
1521 if (res == NULL || (res->type == hsvArray && res->array.nelems == 0) ||
1522 (res->type == hsvHash && res->hash.npairs == 0) )
1524 SET_VARSIZE(out, VARHDRSZ);
1530 if (res->type == hsvArray && res->array.nelems > 1)
1531 res->array.scalar = false;
1533 r = compressHStore(res, VARDATA(out));
1534 SET_VARSIZE(out, r + VARHDRSZ);
1537 PG_RETURN_POINTER(out);
1541 PG_FUNCTION_INFO_V1(hstore_slice_to_array);
1542 Datum hstore_slice_to_array(PG_FUNCTION_ARGS);
1544 hstore_slice_to_array(PG_FUNCTION_ARGS)
1546 HStore *hs = PG_GETARG_HS(0);
1547 ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1);
1556 deconstruct_array(key_array,
1557 TEXTOID, -1, false, 'i',
1558 &key_datums, &key_nulls, &key_count);
1560 if (key_count == 0 || HS_ISEMPTY(hs))
1562 aout = construct_empty_array(TEXTOID);
1563 PG_RETURN_POINTER(aout);
1566 out_datums = palloc(sizeof(Datum) * key_count);
1567 out_nulls = palloc(sizeof(bool) * key_count);
1569 for (i = 0; i < key_count; ++i)
1571 text *key = (text *) DatumGetPointer(key_datums[i]);
1572 HStoreValue *v = NULL;
1574 if (key_nulls[i] == false)
1575 v = findUncompressedHStoreValue(VARDATA(hs),
1576 HS_FLAG_HSTORE | HS_FLAG_ARRAY,
1579 VARSIZE(key) - VARHDRSZ);
1581 out_datums[i] = PointerGetDatum(HStoreValueToText(v));
1582 out_nulls[i] = (DatumGetPointer(out_datums[i]) == NULL) ? true : false;
1585 aout = construct_md_array(out_datums, out_nulls,
1586 ARR_NDIM(key_array),
1587 ARR_DIMS(key_array),
1588 ARR_LBOUND(key_array),
1589 TEXTOID, -1, false, 'i');
1591 PG_RETURN_POINTER(aout);
1595 PG_FUNCTION_INFO_V1(hstore_slice_to_hstore);
1596 Datum hstore_slice_to_hstore(PG_FUNCTION_ARGS);
1598 hstore_slice_to_hstore(PG_FUNCTION_ARGS)
1600 HStore *hs = PG_GETARG_HS(0);
1601 HStoreValue *a = arrayToHStoreSortedArray(PG_GETARG_ARRAYTYPE_P(1));
1602 uint32 lowbound = 0,
1604 HStoreValue *res = NULL;
1605 ToHStoreState *state = NULL;
1609 out = palloc(VARSIZE(hs));
1611 if (a == NULL || a->array.nelems == 0 || HS_ISEMPTY(hs))
1613 memcpy(out, hs, VARSIZE(hs));
1614 PG_RETURN_POINTER(out);
1617 if (HS_ROOT_IS_HASH(hs))
1619 plowbound = &lowbound;
1620 pushHStoreValue(&state, WHS_BEGIN_HASH, NULL);
1625 pushHStoreValue(&state, WHS_BEGIN_ARRAY, NULL);
1628 for (i = 0; i < a->array.nelems; ++i)
1630 HStoreValue *v = findUncompressedHStoreValueByValue(VARDATA(hs),
1631 HS_FLAG_HSTORE | HS_FLAG_ARRAY,
1633 a->array.elems + i);
1639 pushHStoreValue(&state, WHS_KEY, a->array.elems + i);
1640 pushHStoreValue(&state, WHS_VALUE, v);
1644 pushHStoreValue(&state, WHS_ELEM, v);
1650 res = pushHStoreValue(&state, WHS_END_HASH, a /* any non-null value */);
1652 res = pushHStoreValue(&state, WHS_END_ARRAY, NULL);
1655 if (res == NULL || (res->type == hsvArray && res->array.nelems == 0) ||
1656 (res->type == hsvHash && res->hash.npairs == 0) )
1658 SET_VARSIZE(out, VARHDRSZ);
1662 int r = compressHStore(res, VARDATA(out));
1663 SET_VARSIZE(out, r + VARHDRSZ);
1666 PG_RETURN_POINTER(out);
1670 replacePathDo(HStoreIterator **it, Datum *path_elems,
1671 bool *path_nulls, int path_len,
1672 ToHStoreState **st, int level, HStoreValue *newval)
1674 HStoreValue v, *res = NULL;
1677 r = HStoreIteratorGet(it, &v, false);
1679 if (r == WHS_BEGIN_ARRAY)
1682 uint32 n = v.array.nelems;
1685 if (level >= path_len || path_nulls[level] ||
1686 h_atoi(VARDATA_ANY(path_elems[level]),
1687 VARSIZE_ANY_EXHDR(path_elems[level]), &idx) == false)
1702 pushHStoreValue(st, r, &v);
1706 if (i == idx && level < path_len)
1708 if (level == path_len - 1)
1710 r = HStoreIteratorGet(it, &v, true); /* skip */
1711 Assert(r == WHS_ELEM);
1712 res = pushHStoreValue(st, r, newval);
1716 res = replacePathDo(it, path_elems, path_nulls, path_len,
1717 st, level + 1, newval);
1722 r = HStoreIteratorGet(it, &v, true);
1723 Assert(r == WHS_ELEM);
1724 res = pushHStoreValue(st, r, &v);
1728 r = HStoreIteratorGet(it, &v, true);
1729 Assert(r == WHS_END_ARRAY);
1730 res = pushHStoreValue(st, r, &v);
1732 else if (r == WHS_BEGIN_HASH)
1735 uint32 n = v.hash.npairs;
1739 pushHStoreValue(st, WHS_BEGIN_HASH, &v);
1741 if (level >= path_len || path_nulls[level])
1746 r = HStoreIteratorGet(it, &k, false);
1747 Assert(r == WHS_KEY);
1748 res = pushHStoreValue(st, r, &k);
1750 if (done == false &&
1751 k.string.len == VARSIZE_ANY_EXHDR(path_elems[level]) &&
1752 memcmp(k.string.val, VARDATA_ANY(path_elems[level]),
1755 if (level == path_len - 1)
1757 r = HStoreIteratorGet(it, &v, true); /* skip */
1758 Assert(r == WHS_VALUE);
1759 res = pushHStoreValue(st, r, newval);
1763 res = replacePathDo(it, path_elems, path_nulls, path_len,
1764 st, level + 1, newval);
1769 r = HStoreIteratorGet(it, &v, true);
1770 Assert(r == WHS_VALUE);
1771 res = pushHStoreValue(st, r, &v);
1775 r = HStoreIteratorGet(it, &v, true);
1776 Assert(r == WHS_END_HASH);
1777 res = pushHStoreValue(st, r, &v);
1779 else if (r == WHS_ELEM || r == WHS_VALUE)
1781 pushHStoreValue(st, r, &v);
1782 res = (void*)0x01; /* dummy value */
1786 elog(PANIC, "impossible state");
1792 PG_FUNCTION_INFO_V1(hstore_replace);
1793 Datum hstore_replace(PG_FUNCTION_ARGS);
1795 hstore_replace(PG_FUNCTION_ARGS)
1797 HStore *in = PG_GETARG_HS(0);
1798 ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
1799 HStore *newval = PG_GETARG_HS(2);
1800 HStore *out = palloc(VARSIZE(in) + VARSIZE(newval));
1801 HStoreValue *res = NULL;
1807 ToHStoreState *st = NULL;
1809 Assert(ARR_ELEMTYPE(path) == TEXTOID);
1811 if (ARR_NDIM(path) > 1)
1813 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1814 errmsg("wrong number of array subscripts")));
1816 if (HS_ROOT_COUNT(in) == 0)
1818 memcpy(out, in, VARSIZE(in));
1819 PG_RETURN_POINTER(out);
1822 deconstruct_array(path, TEXTOID, -1, false, 'i',
1823 &path_elems, &path_nulls, &path_len);
1827 memcpy(out, in, VARSIZE(in));
1828 PG_RETURN_POINTER(out);
1831 if (HS_ROOT_COUNT(newval) == 0)
1833 value.type = hsvNull;
1834 value.size = sizeof(HEntry);
1838 value.type = hsvBinary;
1839 value.binary.data = VARDATA(newval);
1840 value.binary.len = VARSIZE_ANY_EXHDR(newval);
1841 value.size = value.binary.len + sizeof(HEntry);
1844 it = HStoreIteratorInit(VARDATA(in));
1846 res = replacePathDo(&it, path_elems, path_nulls, path_len, &st, 0, &value);
1850 SET_VARSIZE(out, VARHDRSZ);
1856 sz = compressHStore(res, VARDATA(out));
1857 SET_VARSIZE(out, sz + VARHDRSZ);
1860 PG_RETURN_POINTER(out);
1864 concatPathDo(HStoreIterator **it, Datum *path_elems,
1865 bool *path_nulls, int path_len,
1866 ToHStoreState **st, int level, HStoreIterator *toConcat)
1868 HStoreValue v, *res = NULL;
1871 r = HStoreIteratorGet(it, &v, false);
1873 if (r == WHS_BEGIN_ARRAY)
1876 uint32 n = v.array.nelems;
1879 if (level >= path_len || path_nulls[level] ||
1880 h_atoi(VARDATA_ANY(path_elems[level]),
1881 VARSIZE_ANY_EXHDR(path_elems[level]), &idx) == false)
1896 pushHStoreValue(st, r, &v);
1900 if (i == idx && level < path_len)
1902 if (level == path_len - 1)
1903 res = IteratorConcat(it, &toConcat, st);
1905 res = concatPathDo(it, path_elems, path_nulls, path_len,
1906 st, level + 1, toConcat);
1910 r = HStoreIteratorGet(it, &v, true);
1911 Assert(r == WHS_ELEM);
1912 res = pushHStoreValue(st, r, &v);
1916 r = HStoreIteratorGet(it, &v, true);
1917 Assert(r == WHS_END_ARRAY);
1918 res = pushHStoreValue(st, r, &v);
1920 else if (r == WHS_BEGIN_HASH)
1923 uint32 n = v.hash.npairs;
1927 pushHStoreValue(st, WHS_BEGIN_HASH, &v);
1929 if (level >= path_len || path_nulls[level])
1934 r = HStoreIteratorGet(it, &k, false);
1935 Assert(r == WHS_KEY);
1936 res = pushHStoreValue(st, r, &k);
1938 if (done == false && level < path_len &&
1939 k.string.len == VARSIZE_ANY_EXHDR(path_elems[level]) &&
1940 memcmp(k.string.val, VARDATA_ANY(path_elems[level]),
1943 if (level == path_len - 1)
1944 res = IteratorConcat(it, &toConcat, st);
1946 res = concatPathDo(it, path_elems, path_nulls, path_len,
1947 st, level + 1, toConcat);
1951 r = HStoreIteratorGet(it, &v, true);
1952 Assert(r == WHS_VALUE);
1953 res = pushHStoreValue(st, r, &v);
1957 r = HStoreIteratorGet(it, &v, true);
1958 Assert(r == WHS_END_HASH);
1959 res = pushHStoreValue(st, r, &v);
1961 else if (r == WHS_ELEM || r == WHS_VALUE)
1963 pushHStoreValue(st, r, &v);
1964 res = (void*)0x01; /* dummy value */
1968 elog(PANIC, "impossible state");
1974 PG_FUNCTION_INFO_V1(hstore_deep_concat);
1975 Datum hstore_deep_concat(PG_FUNCTION_ARGS);
1977 hstore_deep_concat(PG_FUNCTION_ARGS)
1979 HStore *in = PG_GETARG_HS(0);
1980 ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
1981 HStore *newval = PG_GETARG_HS(2);
1982 HStore *out = palloc(VARSIZE(in) + VARSIZE(newval));
1983 HStoreValue *res = NULL;
1987 HStoreIterator *it1, *it2;
1988 ToHStoreState *st = NULL;
1990 Assert(ARR_ELEMTYPE(path) == TEXTOID);
1992 if (ARR_NDIM(path) > 1)
1994 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1995 errmsg("wrong number of array subscripts")));
1997 if (HS_ROOT_COUNT(in) == 0 || HS_ROOT_COUNT(newval) == 0)
1999 memcpy(out, in, VARSIZE(in));
2000 PG_RETURN_POINTER(out);
2003 deconstruct_array(path, TEXTOID, -1, false, 'i',
2004 &path_elems, &path_nulls, &path_len);
2006 it1 = HStoreIteratorInit(VARDATA(in));
2007 it2 = HStoreIteratorInit(VARDATA(newval));
2010 res = IteratorConcat(&it1, &it2, &st);
2012 res = concatPathDo(&it1, path_elems, path_nulls, path_len, &st, 0, it2);
2016 SET_VARSIZE(out, VARHDRSZ);
2022 if (res->type == hsvArray && res->array.nelems > 1)
2023 res->array.scalar = false;
2025 sz = compressHStore(res, VARDATA(out));
2026 SET_VARSIZE(out, sz + VARHDRSZ);
2029 PG_RETURN_POINTER(out);
2032 PG_FUNCTION_INFO_V1(hstore_akeys);
2033 Datum hstore_akeys(PG_FUNCTION_ARGS);
2035 hstore_akeys(PG_FUNCTION_ARGS)
2037 HStore *hs = PG_GETARG_HS(0);
2043 bool skipNested = false;
2047 a = construct_empty_array(TEXTOID);
2048 PG_RETURN_POINTER(a);
2051 d = (Datum *) palloc(sizeof(Datum) * HS_ROOT_COUNT(hs));
2053 it = HStoreIteratorInit(VARDATA(hs));
2055 while((r = HStoreIteratorGet(&it, &v, skipNested)) != 0)
2059 if ((r == WHS_ELEM && v.type != hsvNull) || r == WHS_KEY)
2060 d[i++] = PointerGetDatum(HStoreValueToText(&v));
2063 a = construct_array(d, i,
2064 TEXTOID, -1, false, 'i');
2066 PG_RETURN_POINTER(a);
2070 PG_FUNCTION_INFO_V1(hstore_avals);
2071 Datum hstore_avals(PG_FUNCTION_ARGS);
2073 hstore_avals(PG_FUNCTION_ARGS)
2075 HStore *hs = PG_GETARG_HS(0);
2081 bool skipNested = false;
2087 a = construct_empty_array(TEXTOID);
2088 PG_RETURN_POINTER(a);
2091 d = (Datum *) palloc(sizeof(Datum) * HS_ROOT_COUNT(hs));
2092 nulls = (bool *) palloc(sizeof(bool) * HS_ROOT_COUNT(hs));
2094 it = HStoreIteratorInit(VARDATA(hs));
2096 while((r = HStoreIteratorGet(&it, &v, skipNested)) != 0)
2100 if (r == WHS_ELEM || r == WHS_VALUE)
2102 d[i] = PointerGetDatum(HStoreValueToText(&v));
2103 nulls[i] = (DatumGetPointer(d[i]) == NULL) ? true : false;
2108 a = construct_md_array(d, nulls, 1, &i, &lb,
2109 TEXTOID, -1, false, 'i');
2111 PG_RETURN_POINTER(a);
2116 hstore_to_array_internal(HStore *hs, int ndims)
2118 int count = HS_ROOT_COUNT(hs);
2119 int out_size[2] = {0, 2};
2123 bool isHash = HS_ROOT_IS_HASH(hs) ? true : false;
2127 bool skipNested = false;
2131 if (count == 0 || ndims == 0)
2132 return construct_empty_array(TEXTOID);
2134 if (isHash == false && ndims == 2 && count % 2 != 0)
2135 elog(ERROR, "hstore's array should have even number of elements");
2137 out_size[0] = count * (isHash ? 2 : 1) / ndims;
2138 out_datums = palloc(sizeof(Datum) * count * 2);
2139 out_nulls = palloc(sizeof(bool) * count * 2);
2141 it = HStoreIteratorInit(VARDATA(hs));
2143 while((r = HStoreIteratorGet(&it, &v, skipNested)) != 0)
2150 out_datums[i] = PointerGetDatum(HStoreValueToText(&v));
2151 out_nulls[i] = (DatumGetPointer(out_datums[i]) == NULL) ? true : false;
2155 out_datums[i * 2] = PointerGetDatum(HStoreValueToText(&v));
2156 out_nulls[i * 2] = (DatumGetPointer(out_datums[i * 2]) == NULL) ? true : false;
2159 out_datums[i * 2 + 1] = PointerGetDatum(HStoreValueToText(&v));
2160 out_nulls[i * 2 + 1] = (DatumGetPointer(out_datums[i * 2 + 1]) == NULL) ? true : false;
2168 return construct_md_array(out_datums, out_nulls,
2169 ndims, out_size, lb,
2170 TEXTOID, -1, false, 'i');
2173 PG_FUNCTION_INFO_V1(hstore_to_array);
2174 Datum hstore_to_array(PG_FUNCTION_ARGS);
2176 hstore_to_array(PG_FUNCTION_ARGS)
2178 HStore *hs = PG_GETARG_HS(0);
2179 ArrayType *out = hstore_to_array_internal(hs, 1);
2181 PG_RETURN_POINTER(out);
2184 PG_FUNCTION_INFO_V1(hstore_to_matrix);
2185 Datum hstore_to_matrix(PG_FUNCTION_ARGS);
2187 hstore_to_matrix(PG_FUNCTION_ARGS)
2189 HStore *hs = PG_GETARG_HS(0);
2190 ArrayType *out = hstore_to_array_internal(hs, 2);
2192 PG_RETURN_POINTER(out);
2196 * Common initialization function for the various set-returning
2197 * funcs. fcinfo is only passed if the function is to return a
2198 * composite; it will be used to look up the return tupledesc.
2199 * we stash a copy of the hstore in the multi-call context in
2200 * case it was originally toasted. (At least I assume that's why;
2201 * there was no explanatory comment in the original code. --AG)
2204 typedef struct SetReturningState
2224 } SetReturningState;
2226 static SetReturningState*
2227 setup_firstcall(FuncCallContext *funcctx, HStore *hs, ArrayType *path,
2228 FunctionCallInfoData *fcinfo)
2230 MemoryContext oldcontext;
2231 SetReturningState *st;
2233 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2235 st = palloc(sizeof(*st));
2237 st->ctx = funcctx->multi_call_memory_ctx;
2239 st->hs = (HStore *) palloc(VARSIZE(hs));
2240 memcpy(st->hs, hs, VARSIZE(hs));
2241 if (HS_ISEMPTY(hs) || path)
2244 st->it = HStoreIteratorInit(VARDATA(st->hs));
2246 funcctx->user_fctx = (void *) st;
2252 /* Build a tuple descriptor for our result type */
2253 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2254 elog(ERROR, "return type must be a row type");
2256 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
2259 st->path_len = st->level = 0;
2266 Assert(ARR_ELEMTYPE(path) == TEXTOID);
2267 if (ARR_NDIM(path) > 1)
2269 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2270 errmsg("wrong number of array subscripts")));
2272 deconstruct_array(path, TEXTOID, -1, false, 'i',
2273 &path_elems, &path_nulls, &st->path_len);
2275 st->init.type = hsvBinary;
2276 st->init.size = VARSIZE(st->hs);
2277 st->init.binary.data = VARDATA(st->hs);
2278 st->init.binary.len = VARSIZE_ANY_EXHDR(st->hs);
2280 if (st->path_len > 0)
2282 st->path = palloc(sizeof(*st->path) * st->path_len);
2283 st->path[0].v = st->init;
2286 for(i=0; i<st->path_len; i++)
2288 st->path[i].varStr = path_elems[i];
2292 st->path[i].varKind = pathAny;
2293 else if (h_atoi(VARDATA_ANY(path_elems[i]),
2294 VARSIZE_ANY_EXHDR(path_elems[i]),
2295 &st->path[i].varInt))
2296 st->path[i].varKind = pathInt;
2298 st->path[i].varKind = pathStr;
2302 MemoryContextSwitchTo(oldcontext);
2308 HStoreIteratorGetCtx(SetReturningState *st, HStoreValue *v, bool skipNested)
2311 MemoryContext oldctx;
2313 oldctx = MemoryContextSwitchTo(st->ctx);
2314 r = HStoreIteratorGet(&st->it, v, skipNested);
2315 MemoryContextSwitchTo(oldctx);
2320 PG_FUNCTION_INFO_V1(hstore_skeys);
2321 Datum hstore_skeys(PG_FUNCTION_ARGS);
2323 hstore_skeys(PG_FUNCTION_ARGS)
2325 FuncCallContext *funcctx;
2326 SetReturningState *st;
2330 if (SRF_IS_FIRSTCALL())
2332 funcctx = SRF_FIRSTCALL_INIT();
2333 st = setup_firstcall(funcctx, PG_GETARG_HS(0), NULL, NULL);
2336 funcctx = SRF_PERCALL_SETUP();
2337 st = (SetReturningState *) funcctx->user_fctx;
2339 while(st->it && (r = HStoreIteratorGetCtx(st, &v, true)) != 0)
2341 if (r == WHS_KEY || r == WHS_ELEM)
2343 text *item = HStoreValueToText(&v);
2346 SRF_RETURN_NEXT_NULL(funcctx);
2348 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
2352 SRF_RETURN_DONE(funcctx);
2355 PG_FUNCTION_INFO_V1(hstore_svals);
2356 Datum hstore_svals(PG_FUNCTION_ARGS);
2358 hstore_svals(PG_FUNCTION_ARGS)
2360 FuncCallContext *funcctx;
2361 SetReturningState *st;
2365 if (SRF_IS_FIRSTCALL())
2367 funcctx = SRF_FIRSTCALL_INIT();
2368 st = setup_firstcall(funcctx, PG_GETARG_HS(0), NULL, NULL);
2371 funcctx = SRF_PERCALL_SETUP();
2372 st = (SetReturningState *) funcctx->user_fctx;
2374 while(st->it && (r = HStoreIteratorGetCtx(st, &v, true)) != 0)
2376 if (r == WHS_VALUE || r == WHS_ELEM)
2378 text *item = HStoreValueToText(&v);
2381 SRF_RETURN_NEXT_NULL(funcctx);
2383 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
2387 SRF_RETURN_DONE(funcctx);
2390 PG_FUNCTION_INFO_V1(hstore_hvals);
2391 Datum hstore_hvals(PG_FUNCTION_ARGS);
2393 hstore_hvals(PG_FUNCTION_ARGS)
2395 FuncCallContext *funcctx;
2396 SetReturningState *st;
2400 if (SRF_IS_FIRSTCALL())
2402 funcctx = SRF_FIRSTCALL_INIT();
2403 st = setup_firstcall(funcctx, PG_GETARG_HS(0), NULL, NULL);
2406 funcctx = SRF_PERCALL_SETUP();
2407 st = (SetReturningState *) funcctx->user_fctx;
2409 while(st->it && (r = HStoreIteratorGetCtx(st, &v, true)) != 0)
2411 if (r == WHS_VALUE || r == WHS_ELEM)
2413 HStore *item = HStoreValueToHStore(&v);
2416 SRF_RETURN_NEXT_NULL(funcctx);
2418 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
2422 SRF_RETURN_DONE(funcctx);
2426 getNextValsPath(SetReturningState *st)
2428 HStoreValue *v = NULL;
2430 if (st->path_len == 0)
2442 while(st->level >= 0)
2447 if (st->path[st->level].v.type != hsvBinary)
2453 header = *(uint32*)st->path[st->level].v.binary.data;
2455 if (header & HS_FLAG_HSTORE)
2457 if (st->path[st->level].varKind == pathAny)
2459 v = getHStoreValue(st->path[st->level].v.binary.data,
2461 st->path[st->level].i++);
2465 v = findUncompressedHStoreValue(st->path[st->level].v.binary.data,
2466 HS_FLAG_HSTORE, NULL,
2467 VARDATA_ANY(st->path[st->level].varStr),
2468 VARSIZE_ANY_EXHDR(st->path[st->level].varStr));
2471 else if (header & HS_FLAG_ARRAY)
2473 if (st->path[st->level].varKind == pathAny)
2475 v = getHStoreValue(st->path[st->level].v.binary.data,
2476 HS_FLAG_ARRAY, st->path[st->level].i++);
2478 else if (st->path[st->level].varKind == pathInt)
2480 int ith = st->path[st->level].varInt;
2484 if (-ith > (int)(header & HS_COUNT_MASK))
2491 ith = ((int)(header & HS_COUNT_MASK)) + ith;
2496 if (ith >= (int)(header & HS_COUNT_MASK))
2503 v = getHStoreValue(st->path[st->level].v.binary.data,
2504 HS_FLAG_ARRAY, ith);
2514 elog(PANIC, "impossible state");
2521 else if (st->level == st->path_len - 1)
2523 if (st->path[st->level].varKind != pathAny)
2525 st->path[st->level].v.type = hsvNull;
2532 if (st->path[st->level].varKind != pathAny)
2533 st->path[st->level].v.type = hsvNull;
2535 st->path[st->level].v = *v;
2536 st->path[st->level].i = 0;
2543 PG_FUNCTION_INFO_V1(hstore_svals_path);
2544 Datum hstore_svals_path(PG_FUNCTION_ARGS);
2546 hstore_svals_path(PG_FUNCTION_ARGS)
2548 FuncCallContext *funcctx;
2549 SetReturningState *st;
2552 if (SRF_IS_FIRSTCALL())
2554 funcctx = SRF_FIRSTCALL_INIT();
2555 st = setup_firstcall(funcctx, PG_GETARG_HS(0), PG_GETARG_ARRAYTYPE_P(1), NULL);
2558 funcctx = SRF_PERCALL_SETUP();
2559 st = (SetReturningState *) funcctx->user_fctx;
2561 if ((v = getNextValsPath(st)) != NULL)
2563 text *item = HStoreValueToText(v);
2566 SRF_RETURN_NEXT_NULL(funcctx);
2568 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
2571 SRF_RETURN_DONE(funcctx);
2574 PG_FUNCTION_INFO_V1(hstore_hvals_path);
2575 Datum hstore_hvals_path(PG_FUNCTION_ARGS);
2577 hstore_hvals_path(PG_FUNCTION_ARGS)
2579 FuncCallContext *funcctx;
2580 SetReturningState *st;
2583 if (SRF_IS_FIRSTCALL())
2585 funcctx = SRF_FIRSTCALL_INIT();
2586 st = setup_firstcall(funcctx, PG_GETARG_HS(0),
2587 PG_GETARG_ARRAYTYPE_P(1), NULL);
2590 funcctx = SRF_PERCALL_SETUP();
2591 st = (SetReturningState *) funcctx->user_fctx;
2593 if ((v = getNextValsPath(st)) != NULL)
2595 HStore *item = HStoreValueToHStore(v);
2598 SRF_RETURN_NEXT_NULL(funcctx);
2600 SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
2603 SRF_RETURN_DONE(funcctx);
2606 PG_FUNCTION_INFO_V1(hstore_each);
2607 Datum hstore_each(PG_FUNCTION_ARGS);
2609 hstore_each(PG_FUNCTION_ARGS)
2611 FuncCallContext *funcctx;
2612 SetReturningState *st;
2616 if (SRF_IS_FIRSTCALL())
2618 funcctx = SRF_FIRSTCALL_INIT();
2619 st = setup_firstcall(funcctx, PG_GETARG_HS(0), NULL, fcinfo);
2622 funcctx = SRF_PERCALL_SETUP();
2623 st = (SetReturningState *) funcctx->user_fctx;
2625 while(st->it && (r = HStoreIteratorGetCtx(st, &v, true)) != 0)
2628 dvalues[2] = {0, 0};
2629 bool nulls[2] = {false, false};
2637 item = HStoreValueToText(&v);
2641 dvalues[1] = PointerGetDatum(item);
2643 else if (r == WHS_KEY)
2645 item = HStoreValueToText(&v);
2646 dvalues[0] = PointerGetDatum(item);
2648 r = HStoreIteratorGetCtx(st, &v, true);
2649 Assert(r == WHS_VALUE);
2650 item = HStoreValueToText(&v);
2654 dvalues[1] = PointerGetDatum(item);
2661 tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
2662 res = HeapTupleGetDatum(tuple);
2664 SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
2667 SRF_RETURN_DONE(funcctx);
2670 PG_FUNCTION_INFO_V1(hstore_each_hstore);
2671 Datum hstore_each_hstore(PG_FUNCTION_ARGS);
2673 hstore_each_hstore(PG_FUNCTION_ARGS)
2675 FuncCallContext *funcctx;
2676 SetReturningState *st;
2680 if (SRF_IS_FIRSTCALL())
2682 funcctx = SRF_FIRSTCALL_INIT();
2683 st = setup_firstcall(funcctx, PG_GETARG_HS(0), NULL, fcinfo);
2686 funcctx = SRF_PERCALL_SETUP();
2687 st = (SetReturningState *) funcctx->user_fctx;
2689 while(st->it && (r = HStoreIteratorGetCtx(st, &v, true)) != 0)
2692 dvalues[2] = {0, 0};
2693 bool nulls[2] = {false, false};
2702 hitem = HStoreValueToHStore(&v);
2706 dvalues[1] = PointerGetDatum(hitem);
2708 else if (r == WHS_KEY)
2710 item = HStoreValueToText(&v);
2711 dvalues[0] = PointerGetDatum(item);
2713 r = HStoreIteratorGetCtx(st, &v, true);
2714 Assert(r == WHS_VALUE);
2715 hitem = HStoreValueToHStore(&v);
2719 dvalues[1] = PointerGetDatum(hitem);
2726 tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
2727 res = HeapTupleGetDatum(tuple);
2729 SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
2732 SRF_RETURN_DONE(funcctx);
2736 deepContains(HStoreIterator **it1, HStoreIterator **it2)
2742 r1 = HStoreIteratorGet(it1, &v1, false);
2743 r2 = HStoreIteratorGet(it2, &v2, false);
2749 else if (r1 == WHS_BEGIN_HASH)
2751 uint32 lowbound = 0;
2755 r2 = HStoreIteratorGet(it2, &v2, false);
2756 if (r2 == WHS_END_HASH)
2759 Assert(r2 == WHS_KEY);
2761 v = findUncompressedHStoreValueByValue((*it1)->buffer,
2771 r2 = HStoreIteratorGet(it2, &v2, true);
2772 Assert(r2 == WHS_VALUE);
2774 if (v->type != v2.type)
2779 else if (v->type == hsvString || v->type == hsvNull ||
2780 v->type == hsvBool || v->type == hsvNumeric)
2782 if (compareHStoreValue(v, &v2) != 0)
2790 HStoreIterator *it1a, *it2a;
2792 Assert(v2.type == hsvBinary);
2793 Assert(v->type == hsvBinary);
2795 it1a = HStoreIteratorInit(v->binary.data);
2796 it2a = HStoreIteratorInit(v2.binary.data);
2798 if ((res = deepContains(&it1a, &it2a)) == false)
2803 else if (r1 == WHS_BEGIN_ARRAY)
2806 HStoreValue *av = NULL;
2807 uint32 nelems = v1.array.nelems;
2810 r2 = HStoreIteratorGet(it2, &v2, true);
2811 if (r2 == WHS_END_ARRAY)
2814 Assert(r2 == WHS_ELEM);
2816 if (v2.type == hsvString || v2.type == hsvNull ||
2817 v2.type == hsvBool || v2.type == hsvNumeric)
2819 v = findUncompressedHStoreValueByValue((*it1)->buffer,
2820 HS_FLAG_ARRAY, NULL,
2836 av = palloc(sizeof(*av) * nelems);
2838 for(i=0; i<nelems; i++)
2840 r2 = HStoreIteratorGet(it1, &v1, true);
2841 Assert(r2 == WHS_ELEM);
2843 if (v1.type == hsvBinary)
2857 for(i = 0; res == false && i<nelems; i++)
2859 HStoreIterator *it1a, *it2a;
2861 it1a = HStoreIteratorInit(av[i].binary.data);
2862 it2a = HStoreIteratorInit(v2.binary.data);
2864 res = deepContains(&it1a, &it2a);
2874 elog(PANIC, "impossible state");
2880 PG_FUNCTION_INFO_V1(hstore_contains);
2881 Datum hstore_contains(PG_FUNCTION_ARGS);
2883 hstore_contains(PG_FUNCTION_ARGS)
2885 HStore *val = PG_GETARG_HS(0);
2886 HStore *tmpl = PG_GETARG_HS(1);
2888 HStoreIterator *it1, *it2;
2890 if (HS_ROOT_COUNT(val) < HS_ROOT_COUNT(tmpl) ||
2891 HS_ROOT_IS_HASH(val) != HS_ROOT_IS_HASH(tmpl))
2892 PG_RETURN_BOOL(false);
2894 it1 = HStoreIteratorInit(VARDATA(val));
2895 it2 = HStoreIteratorInit(VARDATA(tmpl));
2896 res = deepContains(&it1, &it2);
2898 PG_RETURN_BOOL(res);
2902 PG_FUNCTION_INFO_V1(hstore_contained);
2903 Datum hstore_contained(PG_FUNCTION_ARGS);
2905 hstore_contained(PG_FUNCTION_ARGS)
2907 PG_RETURN_DATUM(DirectFunctionCall2(hstore_contains,
2914 * btree sort order for hstores isn't intended to be useful; we really only
2915 * care about equality versus non-equality. we compare the entire string
2916 * buffer first, then the entry pos array.
2919 PG_FUNCTION_INFO_V1(hstore_cmp);
2920 Datum hstore_cmp(PG_FUNCTION_ARGS);
2922 hstore_cmp(PG_FUNCTION_ARGS)
2924 HStore *hs1 = PG_GETARG_HS(0);
2925 HStore *hs2 = PG_GETARG_HS(1);
2928 if (HS_ISEMPTY(hs1) || HS_ISEMPTY(hs2))
2930 if (HS_ISEMPTY(hs1))
2932 if (HS_ISEMPTY(hs2))
2944 res = compareHStoreBinaryValue(VARDATA(hs1), VARDATA(hs2));
2948 * this is a btree support function; this is one of the few places where
2949 * memory needs to be explicitly freed.
2951 PG_FREE_IF_COPY(hs1, 0);
2952 PG_FREE_IF_COPY(hs2, 1);
2953 PG_RETURN_INT32(res);
2957 PG_FUNCTION_INFO_V1(hstore_eq);
2958 Datum hstore_eq(PG_FUNCTION_ARGS);
2960 hstore_eq(PG_FUNCTION_ARGS)
2962 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
2964 PG_GETARG_DATUM(1)));
2966 PG_RETURN_BOOL(res == 0);
2969 PG_FUNCTION_INFO_V1(hstore_ne);
2970 Datum hstore_ne(PG_FUNCTION_ARGS);
2972 hstore_ne(PG_FUNCTION_ARGS)
2974 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
2976 PG_GETARG_DATUM(1)));
2978 PG_RETURN_BOOL(res != 0);
2981 PG_FUNCTION_INFO_V1(hstore_gt);
2982 Datum hstore_gt(PG_FUNCTION_ARGS);
2984 hstore_gt(PG_FUNCTION_ARGS)
2986 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
2988 PG_GETARG_DATUM(1)));
2990 PG_RETURN_BOOL(res > 0);
2993 PG_FUNCTION_INFO_V1(hstore_ge);
2994 Datum hstore_ge(PG_FUNCTION_ARGS);
2996 hstore_ge(PG_FUNCTION_ARGS)
2998 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
3000 PG_GETARG_DATUM(1)));
3002 PG_RETURN_BOOL(res >= 0);
3005 PG_FUNCTION_INFO_V1(hstore_lt);
3006 Datum hstore_lt(PG_FUNCTION_ARGS);
3008 hstore_lt(PG_FUNCTION_ARGS)
3010 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
3012 PG_GETARG_DATUM(1)));
3014 PG_RETURN_BOOL(res < 0);
3017 PG_FUNCTION_INFO_V1(hstore_le);
3018 Datum hstore_le(PG_FUNCTION_ARGS);
3020 hstore_le(PG_FUNCTION_ARGS)
3022 int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
3024 PG_GETARG_DATUM(1)));
3026 PG_RETURN_BOOL(res <= 0);
3030 PG_FUNCTION_INFO_V1(hstore_hash);
3031 Datum hstore_hash(PG_FUNCTION_ARGS);
3033 hstore_hash(PG_FUNCTION_ARGS)
3035 HStore *hs = PG_GETARG_HS(0);
3041 if (HS_ROOT_COUNT(hs) == 0)
3042 PG_RETURN_INT32(0x1EEE);
3044 it = HStoreIteratorInit(VARDATA(hs));
3047 while((r = HStoreIteratorGet(&it, &v, false)) != 0)
3051 case WHS_BEGIN_ARRAY:
3052 COMP_CRC32(crc, "ab", 3);
3053 COMP_CRC32(crc, &v.array.nelems, sizeof(v.array.nelems));
3054 COMP_CRC32(crc, &v.array.scalar, sizeof(v.array.scalar));
3056 case WHS_BEGIN_HASH:
3057 COMP_CRC32(crc, "hb", 3);
3058 COMP_CRC32(crc, &v.hash.npairs, sizeof(v.hash.npairs));
3061 COMP_CRC32(crc, "k", 2);
3067 COMP_CRC32(crc, v.string.val, v.string.len);
3070 COMP_CRC32(crc, "N", 2);
3073 COMP_CRC32(crc, &v.boolean, sizeof(v.boolean));
3076 crc ^= DatumGetInt32(DirectFunctionCall1(hash_numeric,
3077 NumericGetDatum(v.numeric)));
3080 elog(ERROR, "unexpected state of hstore iterator");
3085 COMP_CRC32(crc, "ae", 3);
3088 COMP_CRC32(crc, "he", 3);
3091 elog(ERROR, "unexpected state of hstore iterator");
3097 PG_FREE_IF_COPY(hs, 0);
3098 PG_RETURN_INT32(crc);
3101 PG_FUNCTION_INFO_V1(hstore_typeof);
3102 Datum hstore_typeof(PG_FUNCTION_ARGS);
3104 hstore_typeof(PG_FUNCTION_ARGS)
3106 HStore *hs = PG_GETARG_HS(0);
3114 it = HStoreIteratorInit(VARDATA(hs));
3115 r = HStoreIteratorGet(&it, &v, false);
3119 case WHS_BEGIN_ARRAY:
3122 Assert(v.array.nelems == 1);
3123 r = HStoreIteratorGet(&it, &v, false);
3124 Assert(r == WHS_ELEM);
3129 PG_RETURN_TEXT_P(cstring_to_text("null"));
3131 PG_RETURN_TEXT_P(cstring_to_text("bool"));
3133 PG_RETURN_TEXT_P(cstring_to_text("numeric"));
3135 PG_RETURN_TEXT_P(cstring_to_text("string"));
3137 elog(ERROR, "bogus hstore");
3142 PG_RETURN_TEXT_P(cstring_to_text("array"));
3144 case WHS_BEGIN_HASH:
3145 PG_RETURN_TEXT_P(cstring_to_text("hash"));
3149 elog(ERROR, "bogus hstore");