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 0 : hstoreFindKey(HStore *hs, int *lowbound, char *key, int keylen)
37 : {
38 0 : HEntry *entries = ARRPTR(hs);
39 0 : int stopLow = lowbound ? *lowbound : 0;
40 0 : int stopHigh = HS_COUNT(hs);
41 0 : int stopMiddle;
42 0 : char *base = STRPTR(hs);
43 :
44 0 : while (stopLow < stopHigh)
45 : {
46 0 : int difference;
47 :
48 0 : stopMiddle = stopLow + (stopHigh - stopLow) / 2;
49 :
50 0 : if (HSTORE_KEYLEN(entries, stopMiddle) == keylen)
51 0 : difference = memcmp(HSTORE_KEY(entries, base, stopMiddle), key, keylen);
52 : else
53 0 : difference = (HSTORE_KEYLEN(entries, stopMiddle) > keylen) ? 1 : -1;
54 :
55 0 : if (difference == 0)
56 : {
57 0 : if (lowbound)
58 0 : *lowbound = stopMiddle + 1;
59 0 : return stopMiddle;
60 : }
61 0 : else if (difference < 0)
62 0 : stopLow = stopMiddle + 1;
63 : else
64 0 : stopHigh = stopMiddle;
65 0 : }
66 :
67 0 : if (lowbound)
68 0 : *lowbound = stopLow;
69 0 : return -1;
70 0 : }
71 :
72 : Pairs *
73 0 : hstoreArrayToPairs(ArrayType *a, int *npairs)
74 : {
75 0 : Datum *key_datums;
76 0 : bool *key_nulls;
77 0 : int key_count;
78 0 : Pairs *key_pairs;
79 0 : int bufsiz;
80 0 : int i,
81 : j;
82 :
83 0 : deconstruct_array_builtin(a, TEXTOID, &key_datums, &key_nulls, &key_count);
84 :
85 0 : if (key_count == 0)
86 : {
87 0 : *npairs = 0;
88 0 : 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 0 : 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 0 : key_pairs = palloc(sizeof(Pairs) * key_count);
105 :
106 0 : for (i = 0, j = 0; i < key_count; i++)
107 : {
108 0 : if (!key_nulls[i])
109 : {
110 0 : key_pairs[j].key = VARDATA(DatumGetPointer(key_datums[i]));
111 0 : key_pairs[j].keylen = VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ;
112 0 : key_pairs[j].val = NULL;
113 0 : key_pairs[j].vallen = 0;
114 0 : key_pairs[j].needfree = 0;
115 0 : key_pairs[j].isnull = 1;
116 0 : j++;
117 0 : }
118 0 : }
119 :
120 0 : *npairs = hstoreUniquePairs(key_pairs, j, &bufsiz);
121 :
122 0 : return key_pairs;
123 0 : }
124 :
125 :
126 0 : PG_FUNCTION_INFO_V1(hstore_fetchval);
127 : Datum
128 0 : hstore_fetchval(PG_FUNCTION_ARGS)
129 : {
130 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
131 0 : text *key = PG_GETARG_TEXT_PP(1);
132 0 : HEntry *entries = ARRPTR(hs);
133 0 : text *out;
134 0 : int idx = hstoreFindKey(hs, NULL,
135 0 : VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
136 :
137 0 : if (idx < 0 || HSTORE_VALISNULL(entries, idx))
138 0 : PG_RETURN_NULL();
139 :
140 0 : out = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), idx),
141 0 : HSTORE_VALLEN(entries, idx));
142 :
143 0 : PG_RETURN_TEXT_P(out);
144 0 : }
145 :
146 :
147 0 : PG_FUNCTION_INFO_V1(hstore_exists);
148 : Datum
149 0 : hstore_exists(PG_FUNCTION_ARGS)
150 : {
151 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
152 0 : text *key = PG_GETARG_TEXT_PP(1);
153 0 : int idx = hstoreFindKey(hs, NULL,
154 0 : VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
155 :
156 0 : PG_RETURN_BOOL(idx >= 0);
157 0 : }
158 :
159 :
160 0 : PG_FUNCTION_INFO_V1(hstore_exists_any);
161 : Datum
162 0 : hstore_exists_any(PG_FUNCTION_ARGS)
163 : {
164 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
165 0 : ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
166 0 : int nkeys;
167 0 : Pairs *key_pairs = hstoreArrayToPairs(keys, &nkeys);
168 0 : int i;
169 0 : int lowbound = 0;
170 0 : 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 0 : for (i = 0; i < nkeys; i++)
179 : {
180 0 : int idx = hstoreFindKey(hs, &lowbound,
181 0 : key_pairs[i].key, key_pairs[i].keylen);
182 :
183 0 : if (idx >= 0)
184 : {
185 0 : res = true;
186 0 : break;
187 : }
188 0 : }
189 :
190 0 : PG_RETURN_BOOL(res);
191 0 : }
192 :
193 :
194 0 : PG_FUNCTION_INFO_V1(hstore_exists_all);
195 : Datum
196 0 : hstore_exists_all(PG_FUNCTION_ARGS)
197 : {
198 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
199 0 : ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
200 0 : int nkeys;
201 0 : Pairs *key_pairs = hstoreArrayToPairs(keys, &nkeys);
202 0 : int i;
203 0 : int lowbound = 0;
204 0 : 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 0 : for (i = 0; i < nkeys; i++)
213 : {
214 0 : int idx = hstoreFindKey(hs, &lowbound,
215 0 : key_pairs[i].key, key_pairs[i].keylen);
216 :
217 0 : if (idx < 0)
218 : {
219 0 : res = false;
220 0 : break;
221 : }
222 0 : }
223 :
224 0 : PG_RETURN_BOOL(res);
225 0 : }
226 :
227 :
228 0 : PG_FUNCTION_INFO_V1(hstore_defined);
229 : Datum
230 0 : hstore_defined(PG_FUNCTION_ARGS)
231 : {
232 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
233 0 : text *key = PG_GETARG_TEXT_PP(1);
234 0 : HEntry *entries = ARRPTR(hs);
235 0 : int idx = hstoreFindKey(hs, NULL,
236 0 : VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
237 0 : bool res = (idx >= 0 && !HSTORE_VALISNULL(entries, idx));
238 :
239 0 : PG_RETURN_BOOL(res);
240 0 : }
241 :
242 :
243 0 : PG_FUNCTION_INFO_V1(hstore_delete);
244 : Datum
245 0 : hstore_delete(PG_FUNCTION_ARGS)
246 : {
247 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
248 0 : text *key = PG_GETARG_TEXT_PP(1);
249 0 : char *keyptr = VARDATA_ANY(key);
250 0 : int keylen = VARSIZE_ANY_EXHDR(key);
251 0 : HStore *out = palloc(VARSIZE(hs));
252 0 : char *bufs,
253 : *bufd,
254 : *ptrd;
255 0 : HEntry *es,
256 : *ed;
257 0 : int i;
258 0 : int count = HS_COUNT(hs);
259 0 : int outcount = 0;
260 :
261 0 : SET_VARSIZE(out, VARSIZE(hs));
262 0 : HS_SETCOUNT(out, count); /* temporary! */
263 :
264 0 : bufs = STRPTR(hs);
265 0 : es = ARRPTR(hs);
266 0 : bufd = ptrd = STRPTR(out);
267 0 : ed = ARRPTR(out);
268 :
269 0 : for (i = 0; i < count; ++i)
270 : {
271 0 : int len = HSTORE_KEYLEN(es, i);
272 0 : char *ptrs = HSTORE_KEY(es, bufs, i);
273 :
274 0 : if (!(len == keylen && memcmp(ptrs, keyptr, keylen) == 0))
275 : {
276 0 : int vallen = HSTORE_VALLEN(es, i);
277 :
278 0 : HS_COPYITEM(ed, bufd, ptrd, ptrs, len, vallen,
279 : HSTORE_VALISNULL(es, i));
280 0 : ++outcount;
281 0 : }
282 0 : }
283 :
284 0 : HS_FINALIZE(out, outcount, bufd, ptrd);
285 :
286 0 : PG_RETURN_POINTER(out);
287 0 : }
288 :
289 :
290 0 : PG_FUNCTION_INFO_V1(hstore_delete_array);
291 : Datum
292 0 : hstore_delete_array(PG_FUNCTION_ARGS)
293 : {
294 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
295 0 : HStore *out = palloc(VARSIZE(hs));
296 0 : int hs_count = HS_COUNT(hs);
297 0 : char *ps,
298 : *bufd,
299 : *pd;
300 0 : HEntry *es,
301 : *ed;
302 0 : int i,
303 : j;
304 0 : int outcount = 0;
305 0 : ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1);
306 0 : int nkeys;
307 0 : Pairs *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
308 :
309 0 : SET_VARSIZE(out, VARSIZE(hs));
310 0 : HS_SETCOUNT(out, hs_count); /* temporary! */
311 :
312 0 : ps = STRPTR(hs);
313 0 : es = ARRPTR(hs);
314 0 : bufd = pd = STRPTR(out);
315 0 : ed = ARRPTR(out);
316 :
317 0 : if (nkeys == 0)
318 : {
319 : /* return a copy of the input, unchanged */
320 0 : memcpy(out, hs, VARSIZE(hs));
321 0 : HS_FIXSIZE(out, hs_count);
322 0 : HS_SETCOUNT(out, hs_count);
323 0 : 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 0 : for (i = j = 0; i < hs_count;)
332 : {
333 0 : int difference;
334 :
335 0 : if (j >= nkeys)
336 0 : difference = -1;
337 : else
338 : {
339 0 : int skeylen = HSTORE_KEYLEN(es, i);
340 :
341 0 : if (skeylen == key_pairs[j].keylen)
342 0 : difference = memcmp(HSTORE_KEY(es, ps, i),
343 0 : key_pairs[j].key,
344 0 : key_pairs[j].keylen);
345 : else
346 0 : difference = (skeylen > key_pairs[j].keylen) ? 1 : -1;
347 0 : }
348 :
349 0 : if (difference > 0)
350 0 : ++j;
351 0 : else if (difference == 0)
352 0 : ++i, ++j;
353 : else
354 : {
355 0 : 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 0 : ++outcount;
359 0 : ++i;
360 : }
361 0 : }
362 :
363 0 : HS_FINALIZE(out, outcount, bufd, pd);
364 :
365 0 : PG_RETURN_POINTER(out);
366 0 : }
367 :
368 :
369 0 : PG_FUNCTION_INFO_V1(hstore_delete_hstore);
370 : Datum
371 0 : hstore_delete_hstore(PG_FUNCTION_ARGS)
372 : {
373 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
374 0 : HStore *hs2 = PG_GETARG_HSTORE_P(1);
375 0 : HStore *out = palloc(VARSIZE(hs));
376 0 : int hs_count = HS_COUNT(hs);
377 0 : int hs2_count = HS_COUNT(hs2);
378 0 : char *ps,
379 : *ps2,
380 : *bufd,
381 : *pd;
382 0 : HEntry *es,
383 : *es2,
384 : *ed;
385 0 : int i,
386 : j;
387 0 : int outcount = 0;
388 :
389 0 : SET_VARSIZE(out, VARSIZE(hs));
390 0 : HS_SETCOUNT(out, hs_count); /* temporary! */
391 :
392 0 : ps = STRPTR(hs);
393 0 : es = ARRPTR(hs);
394 0 : ps2 = STRPTR(hs2);
395 0 : es2 = ARRPTR(hs2);
396 0 : bufd = pd = STRPTR(out);
397 0 : ed = ARRPTR(out);
398 :
399 0 : if (hs2_count == 0)
400 : {
401 : /* return a copy of the input, unchanged */
402 0 : memcpy(out, hs, VARSIZE(hs));
403 0 : HS_FIXSIZE(out, hs_count);
404 0 : HS_SETCOUNT(out, hs_count);
405 0 : 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 0 : for (i = j = 0; i < hs_count;)
415 : {
416 0 : int difference;
417 :
418 0 : if (j >= hs2_count)
419 0 : difference = -1;
420 : else
421 : {
422 0 : int skeylen = HSTORE_KEYLEN(es, i);
423 0 : int s2keylen = HSTORE_KEYLEN(es2, j);
424 :
425 0 : if (skeylen == s2keylen)
426 0 : difference = memcmp(HSTORE_KEY(es, ps, i),
427 0 : HSTORE_KEY(es2, ps2, j),
428 0 : skeylen);
429 : else
430 0 : difference = (skeylen > s2keylen) ? 1 : -1;
431 0 : }
432 :
433 0 : if (difference > 0)
434 0 : ++j;
435 0 : else if (difference == 0)
436 : {
437 0 : int svallen = HSTORE_VALLEN(es, i);
438 0 : int snullval = HSTORE_VALISNULL(es, i);
439 :
440 0 : if (snullval != HSTORE_VALISNULL(es2, j) ||
441 0 : (!snullval && (svallen != HSTORE_VALLEN(es2, j) ||
442 0 : memcmp(HSTORE_VAL(es, ps, i),
443 0 : HSTORE_VAL(es2, ps2, j),
444 0 : svallen) != 0)))
445 : {
446 0 : HS_COPYITEM(ed, bufd, pd,
447 : HSTORE_KEY(es, ps, i), HSTORE_KEYLEN(es, i),
448 : svallen, snullval);
449 0 : ++outcount;
450 0 : }
451 0 : ++i, ++j;
452 0 : }
453 : else
454 : {
455 0 : 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 0 : ++outcount;
459 0 : ++i;
460 : }
461 0 : }
462 :
463 0 : HS_FINALIZE(out, outcount, bufd, pd);
464 :
465 0 : PG_RETURN_POINTER(out);
466 0 : }
467 :
468 :
469 0 : PG_FUNCTION_INFO_V1(hstore_concat);
470 : Datum
471 0 : hstore_concat(PG_FUNCTION_ARGS)
472 : {
473 0 : HStore *s1 = PG_GETARG_HSTORE_P(0);
474 0 : HStore *s2 = PG_GETARG_HSTORE_P(1);
475 0 : HStore *out = palloc(VARSIZE(s1) + VARSIZE(s2));
476 0 : char *ps1,
477 : *ps2,
478 : *bufd,
479 : *pd;
480 0 : HEntry *es1,
481 : *es2,
482 : *ed;
483 0 : int s1idx;
484 0 : int s2idx;
485 0 : int s1count = HS_COUNT(s1);
486 0 : int s2count = HS_COUNT(s2);
487 0 : int outcount = 0;
488 :
489 0 : SET_VARSIZE(out, VARSIZE(s1) + VARSIZE(s2) - HSHRDSIZE);
490 0 : HS_SETCOUNT(out, s1count + s2count);
491 :
492 0 : if (s1count == 0)
493 : {
494 : /* return a copy of the input, unchanged */
495 0 : memcpy(out, s2, VARSIZE(s2));
496 0 : HS_FIXSIZE(out, s2count);
497 0 : HS_SETCOUNT(out, s2count);
498 0 : PG_RETURN_POINTER(out);
499 : }
500 :
501 0 : if (s2count == 0)
502 : {
503 : /* return a copy of the input, unchanged */
504 0 : memcpy(out, s1, VARSIZE(s1));
505 0 : HS_FIXSIZE(out, s1count);
506 0 : HS_SETCOUNT(out, s1count);
507 0 : PG_RETURN_POINTER(out);
508 : }
509 :
510 0 : ps1 = STRPTR(s1);
511 0 : ps2 = STRPTR(s2);
512 0 : bufd = pd = STRPTR(out);
513 0 : es1 = ARRPTR(s1);
514 0 : es2 = ARRPTR(s2);
515 0 : 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 0 : for (s1idx = s2idx = 0; s1idx < s1count || s2idx < s2count; ++outcount)
523 : {
524 0 : int difference;
525 :
526 0 : if (s1idx >= s1count)
527 0 : difference = 1;
528 0 : else if (s2idx >= s2count)
529 0 : difference = -1;
530 : else
531 : {
532 0 : int s1keylen = HSTORE_KEYLEN(es1, s1idx);
533 0 : int s2keylen = HSTORE_KEYLEN(es2, s2idx);
534 :
535 0 : if (s1keylen == s2keylen)
536 0 : difference = memcmp(HSTORE_KEY(es1, ps1, s1idx),
537 0 : HSTORE_KEY(es2, ps2, s2idx),
538 0 : s1keylen);
539 : else
540 0 : difference = (s1keylen > s2keylen) ? 1 : -1;
541 0 : }
542 :
543 0 : if (difference >= 0)
544 : {
545 0 : 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 0 : ++s2idx;
549 0 : if (difference == 0)
550 0 : ++s1idx;
551 0 : }
552 : else
553 : {
554 0 : 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 0 : ++s1idx;
558 : }
559 0 : }
560 :
561 0 : HS_FINALIZE(out, outcount, bufd, pd);
562 :
563 0 : PG_RETURN_POINTER(out);
564 0 : }
565 :
566 :
567 0 : PG_FUNCTION_INFO_V1(hstore_slice_to_array);
568 : Datum
569 0 : hstore_slice_to_array(PG_FUNCTION_ARGS)
570 : {
571 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
572 0 : HEntry *entries = ARRPTR(hs);
573 0 : char *ptr = STRPTR(hs);
574 0 : ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1);
575 0 : ArrayType *aout;
576 0 : Datum *key_datums;
577 0 : bool *key_nulls;
578 0 : Datum *out_datums;
579 0 : bool *out_nulls;
580 0 : int key_count;
581 0 : int i;
582 :
583 0 : deconstruct_array_builtin(key_array, TEXTOID, &key_datums, &key_nulls, &key_count);
584 :
585 0 : if (key_count == 0)
586 : {
587 0 : aout = construct_empty_array(TEXTOID);
588 0 : PG_RETURN_POINTER(aout);
589 : }
590 :
591 0 : out_datums = palloc(sizeof(Datum) * key_count);
592 0 : out_nulls = palloc(sizeof(bool) * key_count);
593 :
594 0 : for (i = 0; i < key_count; ++i)
595 : {
596 0 : text *key = (text *) DatumGetPointer(key_datums[i]);
597 0 : int idx;
598 :
599 0 : if (key_nulls[i])
600 0 : idx = -1;
601 : else
602 0 : idx = hstoreFindKey(hs, NULL, VARDATA(key), VARSIZE(key) - VARHDRSZ);
603 :
604 0 : if (idx < 0 || HSTORE_VALISNULL(entries, idx))
605 : {
606 0 : out_nulls[i] = true;
607 0 : out_datums[i] = (Datum) 0;
608 0 : }
609 : else
610 : {
611 0 : out_datums[i] =
612 0 : PointerGetDatum(cstring_to_text_with_len(HSTORE_VAL(entries, ptr, idx),
613 0 : HSTORE_VALLEN(entries, idx)));
614 0 : out_nulls[i] = false;
615 : }
616 0 : }
617 :
618 0 : aout = construct_md_array(out_datums, out_nulls,
619 0 : ARR_NDIM(key_array),
620 0 : ARR_DIMS(key_array),
621 0 : ARR_LBOUND(key_array),
622 : TEXTOID, -1, false, TYPALIGN_INT);
623 :
624 0 : PG_RETURN_POINTER(aout);
625 0 : }
626 :
627 :
628 0 : PG_FUNCTION_INFO_V1(hstore_slice_to_hstore);
629 : Datum
630 0 : hstore_slice_to_hstore(PG_FUNCTION_ARGS)
631 : {
632 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
633 0 : HEntry *entries = ARRPTR(hs);
634 0 : char *ptr = STRPTR(hs);
635 0 : ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1);
636 0 : HStore *out;
637 0 : int nkeys;
638 0 : Pairs *key_pairs = hstoreArrayToPairs(key_array, &nkeys);
639 0 : Pairs *out_pairs;
640 0 : int bufsiz;
641 0 : int lastidx = 0;
642 0 : int i;
643 0 : int out_count = 0;
644 :
645 0 : if (nkeys == 0)
646 : {
647 0 : out = hstorePairs(NULL, 0, 0);
648 0 : PG_RETURN_POINTER(out);
649 : }
650 :
651 : /* hstoreArrayToPairs() checked overflow */
652 0 : out_pairs = palloc(sizeof(Pairs) * nkeys);
653 0 : 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 0 : for (i = 0; i < nkeys; ++i)
663 : {
664 0 : int idx = hstoreFindKey(hs, &lastidx,
665 0 : key_pairs[i].key, key_pairs[i].keylen);
666 :
667 0 : if (idx >= 0)
668 : {
669 0 : out_pairs[out_count].key = key_pairs[i].key;
670 0 : bufsiz += (out_pairs[out_count].keylen = key_pairs[i].keylen);
671 0 : out_pairs[out_count].val = HSTORE_VAL(entries, ptr, idx);
672 0 : bufsiz += (out_pairs[out_count].vallen = HSTORE_VALLEN(entries, idx));
673 0 : out_pairs[out_count].isnull = HSTORE_VALISNULL(entries, idx);
674 0 : out_pairs[out_count].needfree = false;
675 0 : ++out_count;
676 0 : }
677 0 : }
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 0 : out = hstorePairs(out_pairs, out_count, bufsiz);
685 :
686 0 : PG_RETURN_POINTER(out);
687 0 : }
688 :
689 :
690 0 : PG_FUNCTION_INFO_V1(hstore_akeys);
691 : Datum
692 0 : hstore_akeys(PG_FUNCTION_ARGS)
693 : {
694 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
695 0 : Datum *d;
696 0 : ArrayType *a;
697 0 : HEntry *entries = ARRPTR(hs);
698 0 : char *base = STRPTR(hs);
699 0 : int count = HS_COUNT(hs);
700 0 : int i;
701 :
702 0 : if (count == 0)
703 : {
704 0 : a = construct_empty_array(TEXTOID);
705 0 : PG_RETURN_POINTER(a);
706 : }
707 :
708 0 : d = (Datum *) palloc(sizeof(Datum) * count);
709 :
710 0 : for (i = 0; i < count; ++i)
711 : {
712 0 : text *t = cstring_to_text_with_len(HSTORE_KEY(entries, base, i),
713 0 : HSTORE_KEYLEN(entries, i));
714 :
715 0 : d[i] = PointerGetDatum(t);
716 0 : }
717 :
718 0 : a = construct_array_builtin(d, count, TEXTOID);
719 :
720 0 : PG_RETURN_POINTER(a);
721 0 : }
722 :
723 :
724 0 : PG_FUNCTION_INFO_V1(hstore_avals);
725 : Datum
726 0 : hstore_avals(PG_FUNCTION_ARGS)
727 : {
728 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
729 0 : Datum *d;
730 0 : bool *nulls;
731 0 : ArrayType *a;
732 0 : HEntry *entries = ARRPTR(hs);
733 0 : char *base = STRPTR(hs);
734 0 : int count = HS_COUNT(hs);
735 0 : int lb = 1;
736 0 : int i;
737 :
738 0 : if (count == 0)
739 : {
740 0 : a = construct_empty_array(TEXTOID);
741 0 : PG_RETURN_POINTER(a);
742 : }
743 :
744 0 : d = (Datum *) palloc(sizeof(Datum) * count);
745 0 : nulls = (bool *) palloc(sizeof(bool) * count);
746 :
747 0 : for (i = 0; i < count; ++i)
748 : {
749 0 : if (HSTORE_VALISNULL(entries, i))
750 : {
751 0 : d[i] = (Datum) 0;
752 0 : nulls[i] = true;
753 0 : }
754 : else
755 : {
756 0 : text *item = cstring_to_text_with_len(HSTORE_VAL(entries, base, i),
757 0 : HSTORE_VALLEN(entries, i));
758 :
759 0 : d[i] = PointerGetDatum(item);
760 0 : nulls[i] = false;
761 0 : }
762 0 : }
763 :
764 0 : a = construct_md_array(d, nulls, 1, &count, &lb,
765 : TEXTOID, -1, false, TYPALIGN_INT);
766 :
767 0 : PG_RETURN_POINTER(a);
768 0 : }
769 :
770 :
771 : static ArrayType *
772 0 : hstore_to_array_internal(HStore *hs, int ndims)
773 : {
774 0 : HEntry *entries = ARRPTR(hs);
775 0 : char *base = STRPTR(hs);
776 0 : int count = HS_COUNT(hs);
777 0 : int out_size[2] = {0, 2};
778 0 : int lb[2] = {1, 1};
779 0 : Datum *out_datums;
780 0 : bool *out_nulls;
781 0 : int i;
782 :
783 0 : Assert(ndims < 3);
784 :
785 0 : if (count == 0 || ndims == 0)
786 0 : return construct_empty_array(TEXTOID);
787 :
788 0 : out_size[0] = count * 2 / ndims;
789 0 : out_datums = palloc(sizeof(Datum) * count * 2);
790 0 : out_nulls = palloc(sizeof(bool) * count * 2);
791 :
792 0 : for (i = 0; i < count; ++i)
793 : {
794 0 : text *key = cstring_to_text_with_len(HSTORE_KEY(entries, base, i),
795 0 : HSTORE_KEYLEN(entries, i));
796 :
797 0 : out_datums[i * 2] = PointerGetDatum(key);
798 0 : out_nulls[i * 2] = false;
799 :
800 0 : if (HSTORE_VALISNULL(entries, i))
801 : {
802 0 : out_datums[i * 2 + 1] = (Datum) 0;
803 0 : out_nulls[i * 2 + 1] = true;
804 0 : }
805 : else
806 : {
807 0 : text *item = cstring_to_text_with_len(HSTORE_VAL(entries, base, i),
808 0 : HSTORE_VALLEN(entries, i));
809 :
810 0 : out_datums[i * 2 + 1] = PointerGetDatum(item);
811 0 : out_nulls[i * 2 + 1] = false;
812 0 : }
813 0 : }
814 :
815 0 : return construct_md_array(out_datums, out_nulls,
816 0 : ndims, out_size, lb,
817 : TEXTOID, -1, false, TYPALIGN_INT);
818 0 : }
819 :
820 0 : PG_FUNCTION_INFO_V1(hstore_to_array);
821 : Datum
822 0 : hstore_to_array(PG_FUNCTION_ARGS)
823 : {
824 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
825 0 : ArrayType *out = hstore_to_array_internal(hs, 1);
826 :
827 0 : PG_RETURN_POINTER(out);
828 0 : }
829 :
830 0 : PG_FUNCTION_INFO_V1(hstore_to_matrix);
831 : Datum
832 0 : hstore_to_matrix(PG_FUNCTION_ARGS)
833 : {
834 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
835 0 : ArrayType *out = hstore_to_array_internal(hs, 2);
836 :
837 0 : PG_RETURN_POINTER(out);
838 0 : }
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 0 : setup_firstcall(FuncCallContext *funcctx, HStore *hs,
851 : FunctionCallInfo fcinfo)
852 : {
853 0 : MemoryContext oldcontext;
854 0 : HStore *st;
855 :
856 0 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
857 :
858 0 : st = (HStore *) palloc(VARSIZE(hs));
859 0 : memcpy(st, hs, VARSIZE(hs));
860 :
861 0 : funcctx->user_fctx = st;
862 :
863 0 : if (fcinfo)
864 : {
865 0 : TupleDesc tupdesc;
866 :
867 : /* Build a tuple descriptor for our result type */
868 0 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
869 0 : elog(ERROR, "return type must be a row type");
870 :
871 0 : funcctx->tuple_desc = BlessTupleDesc(tupdesc);
872 0 : }
873 :
874 0 : MemoryContextSwitchTo(oldcontext);
875 0 : }
876 :
877 :
878 0 : PG_FUNCTION_INFO_V1(hstore_skeys);
879 : Datum
880 0 : hstore_skeys(PG_FUNCTION_ARGS)
881 : {
882 0 : FuncCallContext *funcctx;
883 0 : HStore *hs;
884 0 : int i;
885 :
886 0 : if (SRF_IS_FIRSTCALL())
887 : {
888 0 : hs = PG_GETARG_HSTORE_P(0);
889 0 : funcctx = SRF_FIRSTCALL_INIT();
890 0 : setup_firstcall(funcctx, hs, NULL);
891 0 : }
892 :
893 0 : funcctx = SRF_PERCALL_SETUP();
894 0 : hs = (HStore *) funcctx->user_fctx;
895 0 : i = funcctx->call_cntr;
896 :
897 0 : if (i < HS_COUNT(hs))
898 : {
899 0 : HEntry *entries = ARRPTR(hs);
900 0 : text *item;
901 :
902 0 : item = cstring_to_text_with_len(HSTORE_KEY(entries, STRPTR(hs), i),
903 0 : HSTORE_KEYLEN(entries, i));
904 :
905 0 : SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
906 0 : }
907 :
908 0 : SRF_RETURN_DONE(funcctx);
909 0 : }
910 :
911 :
912 0 : PG_FUNCTION_INFO_V1(hstore_svals);
913 : Datum
914 0 : hstore_svals(PG_FUNCTION_ARGS)
915 : {
916 0 : FuncCallContext *funcctx;
917 0 : HStore *hs;
918 0 : int i;
919 :
920 0 : if (SRF_IS_FIRSTCALL())
921 : {
922 0 : hs = PG_GETARG_HSTORE_P(0);
923 0 : funcctx = SRF_FIRSTCALL_INIT();
924 0 : setup_firstcall(funcctx, hs, NULL);
925 0 : }
926 :
927 0 : funcctx = SRF_PERCALL_SETUP();
928 0 : hs = (HStore *) funcctx->user_fctx;
929 0 : i = funcctx->call_cntr;
930 :
931 0 : if (i < HS_COUNT(hs))
932 : {
933 0 : HEntry *entries = ARRPTR(hs);
934 :
935 0 : if (HSTORE_VALISNULL(entries, i))
936 : {
937 0 : ReturnSetInfo *rsi;
938 :
939 : /* ugly ugly ugly. why no macro for this? */
940 0 : (funcctx)->call_cntr++;
941 0 : rsi = (ReturnSetInfo *) fcinfo->resultinfo;
942 0 : rsi->isDone = ExprMultipleResult;
943 0 : PG_RETURN_NULL();
944 0 : }
945 : else
946 : {
947 0 : text *item;
948 :
949 0 : item = cstring_to_text_with_len(HSTORE_VAL(entries, STRPTR(hs), i),
950 0 : HSTORE_VALLEN(entries, i));
951 :
952 0 : SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
953 0 : }
954 0 : }
955 :
956 0 : SRF_RETURN_DONE(funcctx);
957 0 : }
958 :
959 :
960 0 : PG_FUNCTION_INFO_V1(hstore_contains);
961 : Datum
962 0 : hstore_contains(PG_FUNCTION_ARGS)
963 : {
964 0 : HStore *val = PG_GETARG_HSTORE_P(0);
965 0 : HStore *tmpl = PG_GETARG_HSTORE_P(1);
966 0 : bool res = true;
967 0 : HEntry *te = ARRPTR(tmpl);
968 0 : char *tstr = STRPTR(tmpl);
969 0 : HEntry *ve = ARRPTR(val);
970 0 : char *vstr = STRPTR(val);
971 0 : int tcount = HS_COUNT(tmpl);
972 0 : int lastidx = 0;
973 0 : 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 0 : for (i = 0; res && i < tcount; ++i)
983 : {
984 0 : int idx = hstoreFindKey(val, &lastidx,
985 0 : HSTORE_KEY(te, tstr, i),
986 0 : HSTORE_KEYLEN(te, i));
987 :
988 0 : if (idx >= 0)
989 : {
990 0 : bool nullval = HSTORE_VALISNULL(te, i);
991 0 : int vallen = HSTORE_VALLEN(te, i);
992 :
993 0 : if (nullval != HSTORE_VALISNULL(ve, idx) ||
994 0 : (!nullval && (vallen != HSTORE_VALLEN(ve, idx) ||
995 0 : memcmp(HSTORE_VAL(te, tstr, i),
996 0 : HSTORE_VAL(ve, vstr, idx),
997 0 : vallen) != 0)))
998 0 : res = false;
999 0 : }
1000 : else
1001 0 : res = false;
1002 0 : }
1003 :
1004 0 : PG_RETURN_BOOL(res);
1005 0 : }
1006 :
1007 :
1008 0 : 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 0 : PG_FUNCTION_INFO_V1(hstore_each);
1020 : Datum
1021 0 : hstore_each(PG_FUNCTION_ARGS)
1022 : {
1023 0 : FuncCallContext *funcctx;
1024 0 : HStore *hs;
1025 0 : int i;
1026 :
1027 0 : if (SRF_IS_FIRSTCALL())
1028 : {
1029 0 : hs = PG_GETARG_HSTORE_P(0);
1030 0 : funcctx = SRF_FIRSTCALL_INIT();
1031 0 : setup_firstcall(funcctx, hs, fcinfo);
1032 0 : }
1033 :
1034 0 : funcctx = SRF_PERCALL_SETUP();
1035 0 : hs = (HStore *) funcctx->user_fctx;
1036 0 : i = funcctx->call_cntr;
1037 :
1038 0 : if (i < HS_COUNT(hs))
1039 : {
1040 0 : HEntry *entries = ARRPTR(hs);
1041 0 : char *ptr = STRPTR(hs);
1042 0 : Datum res,
1043 : dvalues[2];
1044 0 : bool nulls[2] = {false, false};
1045 0 : text *item;
1046 0 : HeapTuple tuple;
1047 :
1048 0 : item = cstring_to_text_with_len(HSTORE_KEY(entries, ptr, i),
1049 0 : HSTORE_KEYLEN(entries, i));
1050 0 : dvalues[0] = PointerGetDatum(item);
1051 :
1052 0 : if (HSTORE_VALISNULL(entries, i))
1053 : {
1054 0 : dvalues[1] = (Datum) 0;
1055 0 : nulls[1] = true;
1056 0 : }
1057 : else
1058 : {
1059 0 : item = cstring_to_text_with_len(HSTORE_VAL(entries, ptr, i),
1060 0 : HSTORE_VALLEN(entries, i));
1061 0 : dvalues[1] = PointerGetDatum(item);
1062 : }
1063 :
1064 0 : tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
1065 0 : res = HeapTupleGetDatum(tuple);
1066 :
1067 0 : SRF_RETURN_NEXT(funcctx, res);
1068 0 : }
1069 :
1070 0 : SRF_RETURN_DONE(funcctx);
1071 0 : }
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 0 : PG_FUNCTION_INFO_V1(hstore_cmp);
1081 : Datum
1082 0 : hstore_cmp(PG_FUNCTION_ARGS)
1083 : {
1084 0 : HStore *hs1 = PG_GETARG_HSTORE_P(0);
1085 0 : HStore *hs2 = PG_GETARG_HSTORE_P(1);
1086 0 : int hcount1 = HS_COUNT(hs1);
1087 0 : int hcount2 = HS_COUNT(hs2);
1088 0 : int res = 0;
1089 :
1090 0 : 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 0 : if (hcount1 > 0)
1097 0 : res = 1;
1098 0 : else if (hcount2 > 0)
1099 0 : res = -1;
1100 0 : }
1101 : else
1102 : {
1103 : /* here we know both operands are nonempty */
1104 0 : char *str1 = STRPTR(hs1);
1105 0 : char *str2 = STRPTR(hs2);
1106 0 : HEntry *ent1 = ARRPTR(hs1);
1107 0 : HEntry *ent2 = ARRPTR(hs2);
1108 0 : size_t len1 = HSE_ENDPOS(ent1[2 * hcount1 - 1]);
1109 0 : size_t len2 = HSE_ENDPOS(ent2[2 * hcount2 - 1]);
1110 :
1111 0 : res = memcmp(str1, str2, Min(len1, len2));
1112 :
1113 0 : if (res == 0)
1114 : {
1115 0 : if (len1 > len2)
1116 0 : res = 1;
1117 0 : else if (len1 < len2)
1118 0 : res = -1;
1119 0 : else if (hcount1 > hcount2)
1120 0 : res = 1;
1121 0 : else if (hcount2 > hcount1)
1122 0 : res = -1;
1123 : else
1124 : {
1125 0 : int count = hcount1 * 2;
1126 0 : int i;
1127 :
1128 0 : for (i = 0; i < count; ++i)
1129 0 : if (HSE_ENDPOS(ent1[i]) != HSE_ENDPOS(ent2[i]) ||
1130 0 : HSE_ISNULL(ent1[i]) != HSE_ISNULL(ent2[i]))
1131 0 : break;
1132 0 : 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 0 : }
1143 0 : }
1144 0 : }
1145 : else
1146 : {
1147 0 : res = (res > 0) ? 1 : -1;
1148 : }
1149 0 : }
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 0 : PG_FREE_IF_COPY(hs1, 0);
1156 0 : PG_FREE_IF_COPY(hs2, 1);
1157 0 : PG_RETURN_INT32(res);
1158 0 : }
1159 :
1160 :
1161 0 : PG_FUNCTION_INFO_V1(hstore_eq);
1162 : Datum
1163 0 : hstore_eq(PG_FUNCTION_ARGS)
1164 : {
1165 0 : int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
1166 : PG_GETARG_DATUM(0),
1167 : PG_GETARG_DATUM(1)));
1168 :
1169 0 : PG_RETURN_BOOL(res == 0);
1170 0 : }
1171 :
1172 0 : 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 0 : }
1182 :
1183 0 : PG_FUNCTION_INFO_V1(hstore_gt);
1184 : Datum
1185 0 : hstore_gt(PG_FUNCTION_ARGS)
1186 : {
1187 0 : int res = DatumGetInt32(DirectFunctionCall2(hstore_cmp,
1188 : PG_GETARG_DATUM(0),
1189 : PG_GETARG_DATUM(1)));
1190 :
1191 0 : PG_RETURN_BOOL(res > 0);
1192 0 : }
1193 :
1194 0 : 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 0 : }
1204 :
1205 0 : 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 0 : }
1215 :
1216 0 : 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 0 : }
1226 :
1227 :
1228 0 : PG_FUNCTION_INFO_V1(hstore_hash);
1229 : Datum
1230 0 : hstore_hash(PG_FUNCTION_ARGS)
1231 : {
1232 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
1233 0 : Datum hval = hash_any((unsigned char *) VARDATA(hs),
1234 0 : 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 0 : 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 0 : PG_FREE_IF_COPY(hs, 0);
1249 0 : PG_RETURN_DATUM(hval);
1250 0 : }
1251 :
1252 0 : PG_FUNCTION_INFO_V1(hstore_hash_extended);
1253 : Datum
1254 0 : hstore_hash_extended(PG_FUNCTION_ARGS)
1255 : {
1256 0 : HStore *hs = PG_GETARG_HSTORE_P(0);
1257 0 : uint64 seed = PG_GETARG_INT64(1);
1258 0 : Datum hval;
1259 :
1260 0 : hval = hash_any_extended((unsigned char *) VARDATA(hs),
1261 0 : VARSIZE(hs) - VARHDRSZ,
1262 0 : seed);
1263 :
1264 : /* See comment in hstore_hash */
1265 0 : 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 0 : PG_FREE_IF_COPY(hs, 0);
1272 0 : PG_RETURN_DATUM(hval);
1273 0 : }
|