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