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