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