1 /*
2  * contrib/hstore/hstore_io.c
3  */
4 #include "postgres.h"
5 
6 #include <ctype.h>
7 
8 #include "access/htup_details.h"
9 #include "catalog/pg_type.h"
10 #include "common/jsonapi.h"
11 #include "funcapi.h"
12 #include "hstore.h"
13 #include "lib/stringinfo.h"
14 #include "libpq/pqformat.h"
15 #include "utils/builtins.h"
16 #include "utils/json.h"
17 #include "utils/jsonb.h"
18 #include "utils/lsyscache.h"
19 #include "utils/memutils.h"
20 #include "utils/typcache.h"
21 
22 PG_MODULE_MAGIC;
23 
24 /* old names for C functions */
25 HSTORE_POLLUTE(hstore_from_text, tconvert);
26 
27 
28 typedef struct
29 {
30 	char	   *begin;
31 	char	   *ptr;
32 	char	   *cur;
33 	char	   *word;
34 	int			wordlen;
35 
36 	Pairs	   *pairs;
37 	int			pcur;
38 	int			plen;
39 } HSParser;
40 
41 #define RESIZEPRSBUF \
42 do { \
43 		if ( state->cur - state->word + 1 >= state->wordlen ) \
44 		{ \
45 				int32 clen = state->cur - state->word; \
46 				state->wordlen *= 2; \
47 				state->word = (char*)repalloc( (void*)state->word, state->wordlen ); \
48 				state->cur = state->word + clen; \
49 		} \
50 } while (0)
51 
52 
53 #define GV_WAITVAL 0
54 #define GV_INVAL 1
55 #define GV_INESCVAL 2
56 #define GV_WAITESCIN 3
57 #define GV_WAITESCESCIN 4
58 
59 static bool
get_val(HSParser * state,bool ignoreeq,bool * escaped)60 get_val(HSParser *state, bool ignoreeq, bool *escaped)
61 {
62 	int			st = GV_WAITVAL;
63 
64 	state->wordlen = 32;
65 	state->cur = state->word = palloc(state->wordlen);
66 	*escaped = false;
67 
68 	while (1)
69 	{
70 		if (st == GV_WAITVAL)
71 		{
72 			if (*(state->ptr) == '"')
73 			{
74 				*escaped = true;
75 				st = GV_INESCVAL;
76 			}
77 			else if (*(state->ptr) == '\0')
78 			{
79 				return false;
80 			}
81 			else if (*(state->ptr) == '=' && !ignoreeq)
82 			{
83 				elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
84 			}
85 			else if (*(state->ptr) == '\\')
86 			{
87 				st = GV_WAITESCIN;
88 			}
89 			else if (!isspace((unsigned char) *(state->ptr)))
90 			{
91 				*(state->cur) = *(state->ptr);
92 				state->cur++;
93 				st = GV_INVAL;
94 			}
95 		}
96 		else if (st == GV_INVAL)
97 		{
98 			if (*(state->ptr) == '\\')
99 			{
100 				st = GV_WAITESCIN;
101 			}
102 			else if (*(state->ptr) == '=' && !ignoreeq)
103 			{
104 				state->ptr--;
105 				return true;
106 			}
107 			else if (*(state->ptr) == ',' && ignoreeq)
108 			{
109 				state->ptr--;
110 				return true;
111 			}
112 			else if (isspace((unsigned char) *(state->ptr)))
113 			{
114 				return true;
115 			}
116 			else if (*(state->ptr) == '\0')
117 			{
118 				state->ptr--;
119 				return true;
120 			}
121 			else
122 			{
123 				RESIZEPRSBUF;
124 				*(state->cur) = *(state->ptr);
125 				state->cur++;
126 			}
127 		}
128 		else if (st == GV_INESCVAL)
129 		{
130 			if (*(state->ptr) == '\\')
131 			{
132 				st = GV_WAITESCESCIN;
133 			}
134 			else if (*(state->ptr) == '"')
135 			{
136 				return true;
137 			}
138 			else if (*(state->ptr) == '\0')
139 			{
140 				elog(ERROR, "Unexpected end of string");
141 			}
142 			else
143 			{
144 				RESIZEPRSBUF;
145 				*(state->cur) = *(state->ptr);
146 				state->cur++;
147 			}
148 		}
149 		else if (st == GV_WAITESCIN)
150 		{
151 			if (*(state->ptr) == '\0')
152 				elog(ERROR, "Unexpected end of string");
153 			RESIZEPRSBUF;
154 			*(state->cur) = *(state->ptr);
155 			state->cur++;
156 			st = GV_INVAL;
157 		}
158 		else if (st == GV_WAITESCESCIN)
159 		{
160 			if (*(state->ptr) == '\0')
161 				elog(ERROR, "Unexpected end of string");
162 			RESIZEPRSBUF;
163 			*(state->cur) = *(state->ptr);
164 			state->cur++;
165 			st = GV_INESCVAL;
166 		}
167 		else
168 			elog(ERROR, "Unknown state %d at position line %d in file '%s'", st, __LINE__, __FILE__);
169 
170 		state->ptr++;
171 	}
172 }
173 
174 #define WKEY	0
175 #define WVAL	1
176 #define WEQ 2
177 #define WGT 3
178 #define WDEL	4
179 
180 
181 static void
parse_hstore(HSParser * state)182 parse_hstore(HSParser *state)
183 {
184 	int			st = WKEY;
185 	bool		escaped = false;
186 
187 	state->plen = 16;
188 	state->pairs = (Pairs *) palloc(sizeof(Pairs) * state->plen);
189 	state->pcur = 0;
190 	state->ptr = state->begin;
191 	state->word = NULL;
192 
193 	while (1)
194 	{
195 		if (st == WKEY)
196 		{
197 			if (!get_val(state, false, &escaped))
198 				return;
199 			if (state->pcur >= state->plen)
200 			{
201 				state->plen *= 2;
202 				state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen);
203 			}
204 			state->pairs[state->pcur].key = state->word;
205 			state->pairs[state->pcur].keylen = hstoreCheckKeyLen(state->cur - state->word);
206 			state->pairs[state->pcur].val = NULL;
207 			state->word = NULL;
208 			st = WEQ;
209 		}
210 		else if (st == WEQ)
211 		{
212 			if (*(state->ptr) == '=')
213 			{
214 				st = WGT;
215 			}
216 			else if (*(state->ptr) == '\0')
217 			{
218 				elog(ERROR, "Unexpected end of string");
219 			}
220 			else if (!isspace((unsigned char) *(state->ptr)))
221 			{
222 				elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
223 			}
224 		}
225 		else if (st == WGT)
226 		{
227 			if (*(state->ptr) == '>')
228 			{
229 				st = WVAL;
230 			}
231 			else if (*(state->ptr) == '\0')
232 			{
233 				elog(ERROR, "Unexpected end of string");
234 			}
235 			else
236 			{
237 				elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
238 			}
239 		}
240 		else if (st == WVAL)
241 		{
242 			if (!get_val(state, true, &escaped))
243 				elog(ERROR, "Unexpected end of string");
244 			state->pairs[state->pcur].val = state->word;
245 			state->pairs[state->pcur].vallen = hstoreCheckValLen(state->cur - state->word);
246 			state->pairs[state->pcur].isnull = false;
247 			state->pairs[state->pcur].needfree = true;
248 			if (state->cur - state->word == 4 && !escaped)
249 			{
250 				state->word[4] = '\0';
251 				if (0 == pg_strcasecmp(state->word, "null"))
252 					state->pairs[state->pcur].isnull = true;
253 			}
254 			state->word = NULL;
255 			state->pcur++;
256 			st = WDEL;
257 		}
258 		else if (st == WDEL)
259 		{
260 			if (*(state->ptr) == ',')
261 			{
262 				st = WKEY;
263 			}
264 			else if (*(state->ptr) == '\0')
265 			{
266 				return;
267 			}
268 			else if (!isspace((unsigned char) *(state->ptr)))
269 			{
270 				elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int32) (state->ptr - state->begin));
271 			}
272 		}
273 		else
274 			elog(ERROR, "Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__);
275 
276 		state->ptr++;
277 	}
278 }
279 
280 static int
comparePairs(const void * a,const void * b)281 comparePairs(const void *a, const void *b)
282 {
283 	const Pairs *pa = a;
284 	const Pairs *pb = b;
285 
286 	if (pa->keylen == pb->keylen)
287 	{
288 		int			res = memcmp(pa->key, pb->key, pa->keylen);
289 
290 		if (res)
291 			return res;
292 
293 		/* guarantee that needfree will be later */
294 		if (pb->needfree == pa->needfree)
295 			return 0;
296 		else if (pa->needfree)
297 			return 1;
298 		else
299 			return -1;
300 	}
301 	return (pa->keylen > pb->keylen) ? 1 : -1;
302 }
303 
304 /*
305  * this code still respects pairs.needfree, even though in general
306  * it should never be called in a context where anything needs freeing.
307  * we keep it because (a) those calls are in a rare code path anyway,
308  * and (b) who knows whether they might be needed by some caller.
309  */
310 int
hstoreUniquePairs(Pairs * a,int32 l,int32 * buflen)311 hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen)
312 {
313 	Pairs	   *ptr,
314 			   *res;
315 
316 	*buflen = 0;
317 	if (l < 2)
318 	{
319 		if (l == 1)
320 			*buflen = a->keylen + ((a->isnull) ? 0 : a->vallen);
321 		return l;
322 	}
323 
324 	qsort((void *) a, l, sizeof(Pairs), comparePairs);
325 
326 	/*
327 	 * We can't use qunique here because we have some clean-up code to run on
328 	 * removed elements.
329 	 */
330 	ptr = a + 1;
331 	res = a;
332 	while (ptr - a < l)
333 	{
334 		if (ptr->keylen == res->keylen &&
335 			memcmp(ptr->key, res->key, res->keylen) == 0)
336 		{
337 			if (ptr->needfree)
338 			{
339 				pfree(ptr->key);
340 				pfree(ptr->val);
341 			}
342 		}
343 		else
344 		{
345 			*buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
346 			res++;
347 			if (res != ptr)
348 				memcpy(res, ptr, sizeof(Pairs));
349 		}
350 
351 		ptr++;
352 	}
353 
354 	*buflen += res->keylen + ((res->isnull) ? 0 : res->vallen);
355 	return res + 1 - a;
356 }
357 
358 size_t
hstoreCheckKeyLen(size_t len)359 hstoreCheckKeyLen(size_t len)
360 {
361 	if (len > HSTORE_MAX_KEY_LEN)
362 		ereport(ERROR,
363 				(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
364 				 errmsg("string too long for hstore key")));
365 	return len;
366 }
367 
368 size_t
hstoreCheckValLen(size_t len)369 hstoreCheckValLen(size_t len)
370 {
371 	if (len > HSTORE_MAX_VALUE_LEN)
372 		ereport(ERROR,
373 				(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
374 				 errmsg("string too long for hstore value")));
375 	return len;
376 }
377 
378 
379 HStore *
hstorePairs(Pairs * pairs,int32 pcount,int32 buflen)380 hstorePairs(Pairs *pairs, int32 pcount, int32 buflen)
381 {
382 	HStore	   *out;
383 	HEntry	   *entry;
384 	char	   *ptr;
385 	char	   *buf;
386 	int32		len;
387 	int32		i;
388 
389 	len = CALCDATASIZE(pcount, buflen);
390 	out = palloc(len);
391 	SET_VARSIZE(out, len);
392 	HS_SETCOUNT(out, pcount);
393 
394 	if (pcount == 0)
395 		return out;
396 
397 	entry = ARRPTR(out);
398 	buf = ptr = STRPTR(out);
399 
400 	for (i = 0; i < pcount; i++)
401 		HS_ADDITEM(entry, buf, ptr, pairs[i]);
402 
403 	HS_FINALIZE(out, pcount, buf, ptr);
404 
405 	return out;
406 }
407 
408 
409 PG_FUNCTION_INFO_V1(hstore_in);
410 Datum
hstore_in(PG_FUNCTION_ARGS)411 hstore_in(PG_FUNCTION_ARGS)
412 {
413 	HSParser	state;
414 	int32		buflen;
415 	HStore	   *out;
416 
417 	state.begin = PG_GETARG_CSTRING(0);
418 
419 	parse_hstore(&state);
420 
421 	state.pcur = hstoreUniquePairs(state.pairs, state.pcur, &buflen);
422 
423 	out = hstorePairs(state.pairs, state.pcur, buflen);
424 
425 	PG_RETURN_POINTER(out);
426 }
427 
428 
429 PG_FUNCTION_INFO_V1(hstore_recv);
430 Datum
hstore_recv(PG_FUNCTION_ARGS)431 hstore_recv(PG_FUNCTION_ARGS)
432 {
433 	int32		buflen;
434 	HStore	   *out;
435 	Pairs	   *pairs;
436 	int32		i;
437 	int32		pcount;
438 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
439 
440 	pcount = pq_getmsgint(buf, 4);
441 
442 	if (pcount == 0)
443 	{
444 		out = hstorePairs(NULL, 0, 0);
445 		PG_RETURN_POINTER(out);
446 	}
447 
448 	if (pcount < 0 || pcount > MaxAllocSize / sizeof(Pairs))
449 		ereport(ERROR,
450 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
451 				 errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
452 						pcount, (int) (MaxAllocSize / sizeof(Pairs)))));
453 	pairs = palloc(pcount * sizeof(Pairs));
454 
455 	for (i = 0; i < pcount; ++i)
456 	{
457 		int			rawlen = pq_getmsgint(buf, 4);
458 		int			len;
459 
460 		if (rawlen < 0)
461 			ereport(ERROR,
462 					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
463 					 errmsg("null value not allowed for hstore key")));
464 
465 		pairs[i].key = pq_getmsgtext(buf, rawlen, &len);
466 		pairs[i].keylen = hstoreCheckKeyLen(len);
467 		pairs[i].needfree = true;
468 
469 		rawlen = pq_getmsgint(buf, 4);
470 		if (rawlen < 0)
471 		{
472 			pairs[i].val = NULL;
473 			pairs[i].vallen = 0;
474 			pairs[i].isnull = true;
475 		}
476 		else
477 		{
478 			pairs[i].val = pq_getmsgtext(buf, rawlen, &len);
479 			pairs[i].vallen = hstoreCheckValLen(len);
480 			pairs[i].isnull = false;
481 		}
482 	}
483 
484 	pcount = hstoreUniquePairs(pairs, pcount, &buflen);
485 
486 	out = hstorePairs(pairs, pcount, buflen);
487 
488 	PG_RETURN_POINTER(out);
489 }
490 
491 
492 PG_FUNCTION_INFO_V1(hstore_from_text);
493 Datum
hstore_from_text(PG_FUNCTION_ARGS)494 hstore_from_text(PG_FUNCTION_ARGS)
495 {
496 	text	   *key;
497 	text	   *val = NULL;
498 	Pairs		p;
499 	HStore	   *out;
500 
501 	if (PG_ARGISNULL(0))
502 		PG_RETURN_NULL();
503 
504 	p.needfree = false;
505 	key = PG_GETARG_TEXT_PP(0);
506 	p.key = VARDATA_ANY(key);
507 	p.keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key));
508 
509 	if (PG_ARGISNULL(1))
510 	{
511 		p.vallen = 0;
512 		p.isnull = true;
513 	}
514 	else
515 	{
516 		val = PG_GETARG_TEXT_PP(1);
517 		p.val = VARDATA_ANY(val);
518 		p.vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(val));
519 		p.isnull = false;
520 	}
521 
522 	out = hstorePairs(&p, 1, p.keylen + p.vallen);
523 
524 	PG_RETURN_POINTER(out);
525 }
526 
527 
528 PG_FUNCTION_INFO_V1(hstore_from_arrays);
529 Datum
hstore_from_arrays(PG_FUNCTION_ARGS)530 hstore_from_arrays(PG_FUNCTION_ARGS)
531 {
532 	int32		buflen;
533 	HStore	   *out;
534 	Pairs	   *pairs;
535 	Datum	   *key_datums;
536 	bool	   *key_nulls;
537 	int			key_count;
538 	Datum	   *value_datums;
539 	bool	   *value_nulls;
540 	int			value_count;
541 	ArrayType  *key_array;
542 	ArrayType  *value_array;
543 	int			i;
544 
545 	if (PG_ARGISNULL(0))
546 		PG_RETURN_NULL();
547 
548 	key_array = PG_GETARG_ARRAYTYPE_P(0);
549 
550 	Assert(ARR_ELEMTYPE(key_array) == TEXTOID);
551 
552 	/*
553 	 * must check >1 rather than != 1 because empty arrays have 0 dimensions,
554 	 * not 1
555 	 */
556 
557 	if (ARR_NDIM(key_array) > 1)
558 		ereport(ERROR,
559 				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
560 				 errmsg("wrong number of array subscripts")));
561 
562 	deconstruct_array(key_array,
563 					  TEXTOID, -1, false, TYPALIGN_INT,
564 					  &key_datums, &key_nulls, &key_count);
565 
566 	/* see discussion in hstoreArrayToPairs() */
567 	if (key_count > MaxAllocSize / sizeof(Pairs))
568 		ereport(ERROR,
569 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
570 				 errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
571 						key_count, (int) (MaxAllocSize / sizeof(Pairs)))));
572 
573 	/* value_array might be NULL */
574 
575 	if (PG_ARGISNULL(1))
576 	{
577 		value_array = NULL;
578 		value_count = key_count;
579 		value_datums = NULL;
580 		value_nulls = NULL;
581 	}
582 	else
583 	{
584 		value_array = PG_GETARG_ARRAYTYPE_P(1);
585 
586 		Assert(ARR_ELEMTYPE(value_array) == TEXTOID);
587 
588 		if (ARR_NDIM(value_array) > 1)
589 			ereport(ERROR,
590 					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
591 					 errmsg("wrong number of array subscripts")));
592 
593 		if ((ARR_NDIM(key_array) > 0 || ARR_NDIM(value_array) > 0) &&
594 			(ARR_NDIM(key_array) != ARR_NDIM(value_array) ||
595 			 ARR_DIMS(key_array)[0] != ARR_DIMS(value_array)[0] ||
596 			 ARR_LBOUND(key_array)[0] != ARR_LBOUND(value_array)[0]))
597 			ereport(ERROR,
598 					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
599 					 errmsg("arrays must have same bounds")));
600 
601 		deconstruct_array(value_array,
602 						  TEXTOID, -1, false, TYPALIGN_INT,
603 						  &value_datums, &value_nulls, &value_count);
604 
605 		Assert(key_count == value_count);
606 	}
607 
608 	pairs = palloc(key_count * sizeof(Pairs));
609 
610 	for (i = 0; i < key_count; ++i)
611 	{
612 		if (key_nulls[i])
613 			ereport(ERROR,
614 					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
615 					 errmsg("null value not allowed for hstore key")));
616 
617 		if (!value_nulls || value_nulls[i])
618 		{
619 			pairs[i].key = VARDATA(key_datums[i]);
620 			pairs[i].val = NULL;
621 			pairs[i].keylen =
622 				hstoreCheckKeyLen(VARSIZE(key_datums[i]) - VARHDRSZ);
623 			pairs[i].vallen = 4;
624 			pairs[i].isnull = true;
625 			pairs[i].needfree = false;
626 		}
627 		else
628 		{
629 			pairs[i].key = VARDATA(key_datums[i]);
630 			pairs[i].val = VARDATA(value_datums[i]);
631 			pairs[i].keylen =
632 				hstoreCheckKeyLen(VARSIZE(key_datums[i]) - VARHDRSZ);
633 			pairs[i].vallen =
634 				hstoreCheckValLen(VARSIZE(value_datums[i]) - VARHDRSZ);
635 			pairs[i].isnull = false;
636 			pairs[i].needfree = false;
637 		}
638 	}
639 
640 	key_count = hstoreUniquePairs(pairs, key_count, &buflen);
641 
642 	out = hstorePairs(pairs, key_count, buflen);
643 
644 	PG_RETURN_POINTER(out);
645 }
646 
647 
648 PG_FUNCTION_INFO_V1(hstore_from_array);
649 Datum
hstore_from_array(PG_FUNCTION_ARGS)650 hstore_from_array(PG_FUNCTION_ARGS)
651 {
652 	ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
653 	int			ndims = ARR_NDIM(in_array);
654 	int			count;
655 	int32		buflen;
656 	HStore	   *out;
657 	Pairs	   *pairs;
658 	Datum	   *in_datums;
659 	bool	   *in_nulls;
660 	int			in_count;
661 	int			i;
662 
663 	Assert(ARR_ELEMTYPE(in_array) == TEXTOID);
664 
665 	switch (ndims)
666 	{
667 		case 0:
668 			out = hstorePairs(NULL, 0, 0);
669 			PG_RETURN_POINTER(out);
670 
671 		case 1:
672 			if ((ARR_DIMS(in_array)[0]) % 2)
673 				ereport(ERROR,
674 						(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
675 						 errmsg("array must have even number of elements")));
676 			break;
677 
678 		case 2:
679 			if ((ARR_DIMS(in_array)[1]) != 2)
680 				ereport(ERROR,
681 						(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
682 						 errmsg("array must have two columns")));
683 			break;
684 
685 		default:
686 			ereport(ERROR,
687 					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
688 					 errmsg("wrong number of array subscripts")));
689 	}
690 
691 	deconstruct_array(in_array,
692 					  TEXTOID, -1, false, TYPALIGN_INT,
693 					  &in_datums, &in_nulls, &in_count);
694 
695 	count = in_count / 2;
696 
697 	/* see discussion in hstoreArrayToPairs() */
698 	if (count > MaxAllocSize / sizeof(Pairs))
699 		ereport(ERROR,
700 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
701 				 errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
702 						count, (int) (MaxAllocSize / sizeof(Pairs)))));
703 
704 	pairs = palloc(count * sizeof(Pairs));
705 
706 	for (i = 0; i < count; ++i)
707 	{
708 		if (in_nulls[i * 2])
709 			ereport(ERROR,
710 					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
711 					 errmsg("null value not allowed for hstore key")));
712 
713 		if (in_nulls[i * 2 + 1])
714 		{
715 			pairs[i].key = VARDATA(in_datums[i * 2]);
716 			pairs[i].val = NULL;
717 			pairs[i].keylen =
718 				hstoreCheckKeyLen(VARSIZE(in_datums[i * 2]) - VARHDRSZ);
719 			pairs[i].vallen = 4;
720 			pairs[i].isnull = true;
721 			pairs[i].needfree = false;
722 		}
723 		else
724 		{
725 			pairs[i].key = VARDATA(in_datums[i * 2]);
726 			pairs[i].val = VARDATA(in_datums[i * 2 + 1]);
727 			pairs[i].keylen =
728 				hstoreCheckKeyLen(VARSIZE(in_datums[i * 2]) - VARHDRSZ);
729 			pairs[i].vallen =
730 				hstoreCheckValLen(VARSIZE(in_datums[i * 2 + 1]) - VARHDRSZ);
731 			pairs[i].isnull = false;
732 			pairs[i].needfree = false;
733 		}
734 	}
735 
736 	count = hstoreUniquePairs(pairs, count, &buflen);
737 
738 	out = hstorePairs(pairs, count, buflen);
739 
740 	PG_RETURN_POINTER(out);
741 }
742 
743 /* most of hstore_from_record is shamelessly swiped from record_out */
744 
745 /*
746  * structure to cache metadata needed for record I/O
747  */
748 typedef struct ColumnIOData
749 {
750 	Oid			column_type;
751 	Oid			typiofunc;
752 	Oid			typioparam;
753 	FmgrInfo	proc;
754 } ColumnIOData;
755 
756 typedef struct RecordIOData
757 {
758 	Oid			record_type;
759 	int32		record_typmod;
760 	/* this field is used only if target type is domain over composite: */
761 	void	   *domain_info;	/* opaque cache for domain checks */
762 	int			ncolumns;
763 	ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER];
764 } RecordIOData;
765 
766 PG_FUNCTION_INFO_V1(hstore_from_record);
767 Datum
hstore_from_record(PG_FUNCTION_ARGS)768 hstore_from_record(PG_FUNCTION_ARGS)
769 {
770 	HeapTupleHeader rec;
771 	int32		buflen;
772 	HStore	   *out;
773 	Pairs	   *pairs;
774 	Oid			tupType;
775 	int32		tupTypmod;
776 	TupleDesc	tupdesc;
777 	HeapTupleData tuple;
778 	RecordIOData *my_extra;
779 	int			ncolumns;
780 	int			i,
781 				j;
782 	Datum	   *values;
783 	bool	   *nulls;
784 
785 	if (PG_ARGISNULL(0))
786 	{
787 		Oid			argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
788 
789 		/*
790 		 * We have no tuple to look at, so the only source of type info is the
791 		 * argtype --- which might be domain over composite, but we don't care
792 		 * here, since we have no need to be concerned about domain
793 		 * constraints.  The lookup_rowtype_tupdesc_domain call below will
794 		 * error out if we don't have a known composite type oid here.
795 		 */
796 		tupType = argtype;
797 		tupTypmod = -1;
798 
799 		rec = NULL;
800 	}
801 	else
802 	{
803 		rec = PG_GETARG_HEAPTUPLEHEADER(0);
804 
805 		/*
806 		 * Extract type info from the tuple itself -- this will work even for
807 		 * anonymous record types.
808 		 */
809 		tupType = HeapTupleHeaderGetTypeId(rec);
810 		tupTypmod = HeapTupleHeaderGetTypMod(rec);
811 	}
812 
813 	tupdesc = lookup_rowtype_tupdesc_domain(tupType, tupTypmod, false);
814 	ncolumns = tupdesc->natts;
815 
816 	/*
817 	 * We arrange to look up the needed I/O info just once per series of
818 	 * calls, assuming the record type doesn't change underneath us.
819 	 */
820 	my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
821 	if (my_extra == NULL ||
822 		my_extra->ncolumns != ncolumns)
823 	{
824 		fcinfo->flinfo->fn_extra =
825 			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
826 							   offsetof(RecordIOData, columns) +
827 							   ncolumns * sizeof(ColumnIOData));
828 		my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
829 		my_extra->record_type = InvalidOid;
830 		my_extra->record_typmod = 0;
831 	}
832 
833 	if (my_extra->record_type != tupType ||
834 		my_extra->record_typmod != tupTypmod)
835 	{
836 		MemSet(my_extra, 0,
837 			   offsetof(RecordIOData, columns) +
838 			   ncolumns * sizeof(ColumnIOData));
839 		my_extra->record_type = tupType;
840 		my_extra->record_typmod = tupTypmod;
841 		my_extra->ncolumns = ncolumns;
842 	}
843 
844 	Assert(ncolumns <= MaxTupleAttributeNumber);	/* thus, no overflow */
845 	pairs = palloc(ncolumns * sizeof(Pairs));
846 
847 	if (rec)
848 	{
849 		/* Build a temporary HeapTuple control structure */
850 		tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
851 		ItemPointerSetInvalid(&(tuple.t_self));
852 		tuple.t_tableOid = InvalidOid;
853 		tuple.t_data = rec;
854 
855 		values = (Datum *) palloc(ncolumns * sizeof(Datum));
856 		nulls = (bool *) palloc(ncolumns * sizeof(bool));
857 
858 		/* Break down the tuple into fields */
859 		heap_deform_tuple(&tuple, tupdesc, values, nulls);
860 	}
861 	else
862 	{
863 		values = NULL;
864 		nulls = NULL;
865 	}
866 
867 	for (i = 0, j = 0; i < ncolumns; ++i)
868 	{
869 		ColumnIOData *column_info = &my_extra->columns[i];
870 		Form_pg_attribute att = TupleDescAttr(tupdesc, i);
871 		Oid			column_type = att->atttypid;
872 		char	   *value;
873 
874 		/* Ignore dropped columns in datatype */
875 		if (att->attisdropped)
876 			continue;
877 
878 		pairs[j].key = NameStr(att->attname);
879 		pairs[j].keylen = hstoreCheckKeyLen(strlen(NameStr(att->attname)));
880 
881 		if (!nulls || nulls[i])
882 		{
883 			pairs[j].val = NULL;
884 			pairs[j].vallen = 4;
885 			pairs[j].isnull = true;
886 			pairs[j].needfree = false;
887 			++j;
888 			continue;
889 		}
890 
891 		/*
892 		 * Convert the column value to text
893 		 */
894 		if (column_info->column_type != column_type)
895 		{
896 			bool		typIsVarlena;
897 
898 			getTypeOutputInfo(column_type,
899 							  &column_info->typiofunc,
900 							  &typIsVarlena);
901 			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
902 						  fcinfo->flinfo->fn_mcxt);
903 			column_info->column_type = column_type;
904 		}
905 
906 		value = OutputFunctionCall(&column_info->proc, values[i]);
907 
908 		pairs[j].val = value;
909 		pairs[j].vallen = hstoreCheckValLen(strlen(value));
910 		pairs[j].isnull = false;
911 		pairs[j].needfree = false;
912 		++j;
913 	}
914 
915 	ncolumns = hstoreUniquePairs(pairs, j, &buflen);
916 
917 	out = hstorePairs(pairs, ncolumns, buflen);
918 
919 	ReleaseTupleDesc(tupdesc);
920 
921 	PG_RETURN_POINTER(out);
922 }
923 
924 
925 PG_FUNCTION_INFO_V1(hstore_populate_record);
926 Datum
hstore_populate_record(PG_FUNCTION_ARGS)927 hstore_populate_record(PG_FUNCTION_ARGS)
928 {
929 	Oid			argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
930 	HStore	   *hs;
931 	HEntry	   *entries;
932 	char	   *ptr;
933 	HeapTupleHeader rec;
934 	Oid			tupType;
935 	int32		tupTypmod;
936 	TupleDesc	tupdesc;
937 	HeapTupleData tuple;
938 	HeapTuple	rettuple;
939 	RecordIOData *my_extra;
940 	int			ncolumns;
941 	int			i;
942 	Datum	   *values;
943 	bool	   *nulls;
944 
945 	if (!type_is_rowtype(argtype))
946 		ereport(ERROR,
947 				(errcode(ERRCODE_DATATYPE_MISMATCH),
948 				 errmsg("first argument must be a rowtype")));
949 
950 	if (PG_ARGISNULL(0))
951 	{
952 		if (PG_ARGISNULL(1))
953 			PG_RETURN_NULL();
954 
955 		rec = NULL;
956 
957 		/*
958 		 * We have no tuple to look at, so the only source of type info is the
959 		 * argtype.  The lookup_rowtype_tupdesc_domain call below will error
960 		 * out if we don't have a known composite type oid here.
961 		 */
962 		tupType = argtype;
963 		tupTypmod = -1;
964 	}
965 	else
966 	{
967 		rec = PG_GETARG_HEAPTUPLEHEADER(0);
968 
969 		if (PG_ARGISNULL(1))
970 			PG_RETURN_POINTER(rec);
971 
972 		/*
973 		 * Extract type info from the tuple itself -- this will work even for
974 		 * anonymous record types.
975 		 */
976 		tupType = HeapTupleHeaderGetTypeId(rec);
977 		tupTypmod = HeapTupleHeaderGetTypMod(rec);
978 	}
979 
980 	hs = PG_GETARG_HSTORE_P(1);
981 	entries = ARRPTR(hs);
982 	ptr = STRPTR(hs);
983 
984 	/*
985 	 * if the input hstore is empty, we can only skip the rest if we were
986 	 * passed in a non-null record, since otherwise there may be issues with
987 	 * domain nulls.
988 	 */
989 
990 	if (HS_COUNT(hs) == 0 && rec)
991 		PG_RETURN_POINTER(rec);
992 
993 	/*
994 	 * Lookup the input record's tupdesc.  For the moment, we don't worry
995 	 * about whether it is a domain over composite.
996 	 */
997 	tupdesc = lookup_rowtype_tupdesc_domain(tupType, tupTypmod, false);
998 	ncolumns = tupdesc->natts;
999 
1000 	if (rec)
1001 	{
1002 		/* Build a temporary HeapTuple control structure */
1003 		tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
1004 		ItemPointerSetInvalid(&(tuple.t_self));
1005 		tuple.t_tableOid = InvalidOid;
1006 		tuple.t_data = rec;
1007 	}
1008 
1009 	/*
1010 	 * We arrange to look up the needed I/O info just once per series of
1011 	 * calls, assuming the record type doesn't change underneath us.
1012 	 */
1013 	my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
1014 	if (my_extra == NULL ||
1015 		my_extra->ncolumns != ncolumns)
1016 	{
1017 		fcinfo->flinfo->fn_extra =
1018 			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1019 							   offsetof(RecordIOData, columns) +
1020 							   ncolumns * sizeof(ColumnIOData));
1021 		my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
1022 		my_extra->record_type = InvalidOid;
1023 		my_extra->record_typmod = 0;
1024 		my_extra->domain_info = NULL;
1025 	}
1026 
1027 	if (my_extra->record_type != tupType ||
1028 		my_extra->record_typmod != tupTypmod)
1029 	{
1030 		MemSet(my_extra, 0,
1031 			   offsetof(RecordIOData, columns) +
1032 			   ncolumns * sizeof(ColumnIOData));
1033 		my_extra->record_type = tupType;
1034 		my_extra->record_typmod = tupTypmod;
1035 		my_extra->ncolumns = ncolumns;
1036 	}
1037 
1038 	values = (Datum *) palloc(ncolumns * sizeof(Datum));
1039 	nulls = (bool *) palloc(ncolumns * sizeof(bool));
1040 
1041 	if (rec)
1042 	{
1043 		/* Break down the tuple into fields */
1044 		heap_deform_tuple(&tuple, tupdesc, values, nulls);
1045 	}
1046 	else
1047 	{
1048 		for (i = 0; i < ncolumns; ++i)
1049 		{
1050 			values[i] = (Datum) 0;
1051 			nulls[i] = true;
1052 		}
1053 	}
1054 
1055 	for (i = 0; i < ncolumns; ++i)
1056 	{
1057 		ColumnIOData *column_info = &my_extra->columns[i];
1058 		Form_pg_attribute att = TupleDescAttr(tupdesc, i);
1059 		Oid			column_type = att->atttypid;
1060 		char	   *value;
1061 		int			idx;
1062 		int			vallen;
1063 
1064 		/* Ignore dropped columns in datatype */
1065 		if (att->attisdropped)
1066 		{
1067 			nulls[i] = true;
1068 			continue;
1069 		}
1070 
1071 		idx = hstoreFindKey(hs, 0,
1072 							NameStr(att->attname),
1073 							strlen(NameStr(att->attname)));
1074 
1075 		/*
1076 		 * we can't just skip here if the key wasn't found since we might have
1077 		 * a domain to deal with. If we were passed in a non-null record
1078 		 * datum, we assume that the existing values are valid (if they're
1079 		 * not, then it's not our fault), but if we were passed in a null,
1080 		 * then every field which we don't populate needs to be run through
1081 		 * the input function just in case it's a domain type.
1082 		 */
1083 		if (idx < 0 && rec)
1084 			continue;
1085 
1086 		/*
1087 		 * Prepare to convert the column value from text
1088 		 */
1089 		if (column_info->column_type != column_type)
1090 		{
1091 			getTypeInputInfo(column_type,
1092 							 &column_info->typiofunc,
1093 							 &column_info->typioparam);
1094 			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
1095 						  fcinfo->flinfo->fn_mcxt);
1096 			column_info->column_type = column_type;
1097 		}
1098 
1099 		if (idx < 0 || HSTORE_VALISNULL(entries, idx))
1100 		{
1101 			/*
1102 			 * need InputFunctionCall to happen even for nulls, so that domain
1103 			 * checks are done
1104 			 */
1105 			values[i] = InputFunctionCall(&column_info->proc, NULL,
1106 										  column_info->typioparam,
1107 										  att->atttypmod);
1108 			nulls[i] = true;
1109 		}
1110 		else
1111 		{
1112 			vallen = HSTORE_VALLEN(entries, idx);
1113 			value = palloc(1 + vallen);
1114 			memcpy(value, HSTORE_VAL(entries, ptr, idx), vallen);
1115 			value[vallen] = 0;
1116 
1117 			values[i] = InputFunctionCall(&column_info->proc, value,
1118 										  column_info->typioparam,
1119 										  att->atttypmod);
1120 			nulls[i] = false;
1121 		}
1122 	}
1123 
1124 	rettuple = heap_form_tuple(tupdesc, values, nulls);
1125 
1126 	/*
1127 	 * If the target type is domain over composite, all we know at this point
1128 	 * is that we've made a valid value of the base composite type.  Must
1129 	 * check domain constraints before deciding we're done.
1130 	 */
1131 	if (argtype != tupdesc->tdtypeid)
1132 		domain_check(HeapTupleGetDatum(rettuple), false,
1133 					 argtype,
1134 					 &my_extra->domain_info,
1135 					 fcinfo->flinfo->fn_mcxt);
1136 
1137 	ReleaseTupleDesc(tupdesc);
1138 
1139 	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
1140 }
1141 
1142 
1143 static char *
cpw(char * dst,char * src,int len)1144 cpw(char *dst, char *src, int len)
1145 {
1146 	char	   *ptr = src;
1147 
1148 	while (ptr - src < len)
1149 	{
1150 		if (*ptr == '"' || *ptr == '\\')
1151 			*dst++ = '\\';
1152 		*dst++ = *ptr++;
1153 	}
1154 	return dst;
1155 }
1156 
1157 PG_FUNCTION_INFO_V1(hstore_out);
1158 Datum
hstore_out(PG_FUNCTION_ARGS)1159 hstore_out(PG_FUNCTION_ARGS)
1160 {
1161 	HStore	   *in = PG_GETARG_HSTORE_P(0);
1162 	int			buflen,
1163 				i;
1164 	int			count = HS_COUNT(in);
1165 	char	   *out,
1166 			   *ptr;
1167 	char	   *base = STRPTR(in);
1168 	HEntry	   *entries = ARRPTR(in);
1169 
1170 	if (count == 0)
1171 		PG_RETURN_CSTRING(pstrdup(""));
1172 
1173 	buflen = 0;
1174 
1175 	/*
1176 	 * this loop overestimates due to pessimistic assumptions about escaping,
1177 	 * so very large hstore values can't be output. this could be fixed, but
1178 	 * many other data types probably have the same issue. This replaced code
1179 	 * that used the original varlena size for calculations, which was wrong
1180 	 * in some subtle ways.
1181 	 */
1182 
1183 	for (i = 0; i < count; i++)
1184 	{
1185 		/* include "" and => and comma-space */
1186 		buflen += 6 + 2 * HSTORE_KEYLEN(entries, i);
1187 		/* include "" only if nonnull */
1188 		buflen += 2 + (HSTORE_VALISNULL(entries, i)
1189 					   ? 2
1190 					   : 2 * HSTORE_VALLEN(entries, i));
1191 	}
1192 
1193 	out = ptr = palloc(buflen);
1194 
1195 	for (i = 0; i < count; i++)
1196 	{
1197 		*ptr++ = '"';
1198 		ptr = cpw(ptr, HSTORE_KEY(entries, base, i), HSTORE_KEYLEN(entries, i));
1199 		*ptr++ = '"';
1200 		*ptr++ = '=';
1201 		*ptr++ = '>';
1202 		if (HSTORE_VALISNULL(entries, i))
1203 		{
1204 			*ptr++ = 'N';
1205 			*ptr++ = 'U';
1206 			*ptr++ = 'L';
1207 			*ptr++ = 'L';
1208 		}
1209 		else
1210 		{
1211 			*ptr++ = '"';
1212 			ptr = cpw(ptr, HSTORE_VAL(entries, base, i), HSTORE_VALLEN(entries, i));
1213 			*ptr++ = '"';
1214 		}
1215 
1216 		if (i + 1 != count)
1217 		{
1218 			*ptr++ = ',';
1219 			*ptr++ = ' ';
1220 		}
1221 	}
1222 	*ptr = '\0';
1223 
1224 	PG_RETURN_CSTRING(out);
1225 }
1226 
1227 
1228 PG_FUNCTION_INFO_V1(hstore_send);
1229 Datum
hstore_send(PG_FUNCTION_ARGS)1230 hstore_send(PG_FUNCTION_ARGS)
1231 {
1232 	HStore	   *in = PG_GETARG_HSTORE_P(0);
1233 	int			i;
1234 	int			count = HS_COUNT(in);
1235 	char	   *base = STRPTR(in);
1236 	HEntry	   *entries = ARRPTR(in);
1237 	StringInfoData buf;
1238 
1239 	pq_begintypsend(&buf);
1240 
1241 	pq_sendint32(&buf, count);
1242 
1243 	for (i = 0; i < count; i++)
1244 	{
1245 		int32		keylen = HSTORE_KEYLEN(entries, i);
1246 
1247 		pq_sendint32(&buf, keylen);
1248 		pq_sendtext(&buf, HSTORE_KEY(entries, base, i), keylen);
1249 		if (HSTORE_VALISNULL(entries, i))
1250 		{
1251 			pq_sendint32(&buf, -1);
1252 		}
1253 		else
1254 		{
1255 			int32		vallen = HSTORE_VALLEN(entries, i);
1256 
1257 			pq_sendint32(&buf, vallen);
1258 			pq_sendtext(&buf, HSTORE_VAL(entries, base, i), vallen);
1259 		}
1260 	}
1261 
1262 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1263 }
1264 
1265 
1266 /*
1267  * hstore_to_json_loose
1268  *
1269  * This is a heuristic conversion to json which treats
1270  * 't' and 'f' as booleans and strings that look like numbers as numbers,
1271  * as long as they don't start with a leading zero followed by another digit
1272  * (think zip codes or phone numbers starting with 0).
1273  */
1274 PG_FUNCTION_INFO_V1(hstore_to_json_loose);
1275 Datum
hstore_to_json_loose(PG_FUNCTION_ARGS)1276 hstore_to_json_loose(PG_FUNCTION_ARGS)
1277 {
1278 	HStore	   *in = PG_GETARG_HSTORE_P(0);
1279 	int			i;
1280 	int			count = HS_COUNT(in);
1281 	char	   *base = STRPTR(in);
1282 	HEntry	   *entries = ARRPTR(in);
1283 	StringInfoData tmp,
1284 				dst;
1285 
1286 	if (count == 0)
1287 		PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
1288 
1289 	initStringInfo(&tmp);
1290 	initStringInfo(&dst);
1291 
1292 	appendStringInfoChar(&dst, '{');
1293 
1294 	for (i = 0; i < count; i++)
1295 	{
1296 		resetStringInfo(&tmp);
1297 		appendBinaryStringInfo(&tmp, HSTORE_KEY(entries, base, i),
1298 							   HSTORE_KEYLEN(entries, i));
1299 		escape_json(&dst, tmp.data);
1300 		appendStringInfoString(&dst, ": ");
1301 		if (HSTORE_VALISNULL(entries, i))
1302 			appendStringInfoString(&dst, "null");
1303 		/* guess that values of 't' or 'f' are booleans */
1304 		else if (HSTORE_VALLEN(entries, i) == 1 &&
1305 				 *(HSTORE_VAL(entries, base, i)) == 't')
1306 			appendStringInfoString(&dst, "true");
1307 		else if (HSTORE_VALLEN(entries, i) == 1 &&
1308 				 *(HSTORE_VAL(entries, base, i)) == 'f')
1309 			appendStringInfoString(&dst, "false");
1310 		else
1311 		{
1312 			resetStringInfo(&tmp);
1313 			appendBinaryStringInfo(&tmp, HSTORE_VAL(entries, base, i),
1314 								   HSTORE_VALLEN(entries, i));
1315 			if (IsValidJsonNumber(tmp.data, tmp.len))
1316 				appendBinaryStringInfo(&dst, tmp.data, tmp.len);
1317 			else
1318 				escape_json(&dst, tmp.data);
1319 		}
1320 
1321 		if (i + 1 != count)
1322 			appendStringInfoString(&dst, ", ");
1323 	}
1324 	appendStringInfoChar(&dst, '}');
1325 
1326 	PG_RETURN_TEXT_P(cstring_to_text(dst.data));
1327 }
1328 
1329 PG_FUNCTION_INFO_V1(hstore_to_json);
1330 Datum
hstore_to_json(PG_FUNCTION_ARGS)1331 hstore_to_json(PG_FUNCTION_ARGS)
1332 {
1333 	HStore	   *in = PG_GETARG_HSTORE_P(0);
1334 	int			i;
1335 	int			count = HS_COUNT(in);
1336 	char	   *base = STRPTR(in);
1337 	HEntry	   *entries = ARRPTR(in);
1338 	StringInfoData tmp,
1339 				dst;
1340 
1341 	if (count == 0)
1342 		PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
1343 
1344 	initStringInfo(&tmp);
1345 	initStringInfo(&dst);
1346 
1347 	appendStringInfoChar(&dst, '{');
1348 
1349 	for (i = 0; i < count; i++)
1350 	{
1351 		resetStringInfo(&tmp);
1352 		appendBinaryStringInfo(&tmp, HSTORE_KEY(entries, base, i),
1353 							   HSTORE_KEYLEN(entries, i));
1354 		escape_json(&dst, tmp.data);
1355 		appendStringInfoString(&dst, ": ");
1356 		if (HSTORE_VALISNULL(entries, i))
1357 			appendStringInfoString(&dst, "null");
1358 		else
1359 		{
1360 			resetStringInfo(&tmp);
1361 			appendBinaryStringInfo(&tmp, HSTORE_VAL(entries, base, i),
1362 								   HSTORE_VALLEN(entries, i));
1363 			escape_json(&dst, tmp.data);
1364 		}
1365 
1366 		if (i + 1 != count)
1367 			appendStringInfoString(&dst, ", ");
1368 	}
1369 	appendStringInfoChar(&dst, '}');
1370 
1371 	PG_RETURN_TEXT_P(cstring_to_text(dst.data));
1372 }
1373 
1374 PG_FUNCTION_INFO_V1(hstore_to_jsonb);
1375 Datum
hstore_to_jsonb(PG_FUNCTION_ARGS)1376 hstore_to_jsonb(PG_FUNCTION_ARGS)
1377 {
1378 	HStore	   *in = PG_GETARG_HSTORE_P(0);
1379 	int			i;
1380 	int			count = HS_COUNT(in);
1381 	char	   *base = STRPTR(in);
1382 	HEntry	   *entries = ARRPTR(in);
1383 	JsonbParseState *state = NULL;
1384 	JsonbValue *res;
1385 
1386 	(void) pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
1387 
1388 	for (i = 0; i < count; i++)
1389 	{
1390 		JsonbValue	key,
1391 					val;
1392 
1393 		key.type = jbvString;
1394 		key.val.string.len = HSTORE_KEYLEN(entries, i);
1395 		key.val.string.val = HSTORE_KEY(entries, base, i);
1396 
1397 		(void) pushJsonbValue(&state, WJB_KEY, &key);
1398 
1399 		if (HSTORE_VALISNULL(entries, i))
1400 		{
1401 			val.type = jbvNull;
1402 		}
1403 		else
1404 		{
1405 			val.type = jbvString;
1406 			val.val.string.len = HSTORE_VALLEN(entries, i);
1407 			val.val.string.val = HSTORE_VAL(entries, base, i);
1408 		}
1409 		(void) pushJsonbValue(&state, WJB_VALUE, &val);
1410 	}
1411 
1412 	res = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
1413 
1414 	PG_RETURN_POINTER(JsonbValueToJsonb(res));
1415 }
1416 
1417 PG_FUNCTION_INFO_V1(hstore_to_jsonb_loose);
1418 Datum
hstore_to_jsonb_loose(PG_FUNCTION_ARGS)1419 hstore_to_jsonb_loose(PG_FUNCTION_ARGS)
1420 {
1421 	HStore	   *in = PG_GETARG_HSTORE_P(0);
1422 	int			i;
1423 	int			count = HS_COUNT(in);
1424 	char	   *base = STRPTR(in);
1425 	HEntry	   *entries = ARRPTR(in);
1426 	JsonbParseState *state = NULL;
1427 	JsonbValue *res;
1428 	StringInfoData tmp;
1429 
1430 	initStringInfo(&tmp);
1431 
1432 	(void) pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
1433 
1434 	for (i = 0; i < count; i++)
1435 	{
1436 		JsonbValue	key,
1437 					val;
1438 
1439 		key.type = jbvString;
1440 		key.val.string.len = HSTORE_KEYLEN(entries, i);
1441 		key.val.string.val = HSTORE_KEY(entries, base, i);
1442 
1443 		(void) pushJsonbValue(&state, WJB_KEY, &key);
1444 
1445 		if (HSTORE_VALISNULL(entries, i))
1446 		{
1447 			val.type = jbvNull;
1448 		}
1449 		/* guess that values of 't' or 'f' are booleans */
1450 		else if (HSTORE_VALLEN(entries, i) == 1 &&
1451 				 *(HSTORE_VAL(entries, base, i)) == 't')
1452 		{
1453 			val.type = jbvBool;
1454 			val.val.boolean = true;
1455 		}
1456 		else if (HSTORE_VALLEN(entries, i) == 1 &&
1457 				 *(HSTORE_VAL(entries, base, i)) == 'f')
1458 		{
1459 			val.type = jbvBool;
1460 			val.val.boolean = false;
1461 		}
1462 		else
1463 		{
1464 			resetStringInfo(&tmp);
1465 			appendBinaryStringInfo(&tmp, HSTORE_VAL(entries, base, i),
1466 								   HSTORE_VALLEN(entries, i));
1467 			if (IsValidJsonNumber(tmp.data, tmp.len))
1468 			{
1469 				Datum		numd;
1470 
1471 				val.type = jbvNumeric;
1472 				numd = DirectFunctionCall3(numeric_in,
1473 										   CStringGetDatum(tmp.data),
1474 										   ObjectIdGetDatum(InvalidOid),
1475 										   Int32GetDatum(-1));
1476 				val.val.numeric = DatumGetNumeric(numd);
1477 			}
1478 			else
1479 			{
1480 				val.type = jbvString;
1481 				val.val.string.len = HSTORE_VALLEN(entries, i);
1482 				val.val.string.val = HSTORE_VAL(entries, base, i);
1483 			}
1484 		}
1485 		(void) pushJsonbValue(&state, WJB_VALUE, &val);
1486 	}
1487 
1488 	res = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
1489 
1490 	PG_RETURN_POINTER(JsonbValueToJsonb(res));
1491 }
1492