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