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