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