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