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