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