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