1 /*-------------------------------------------------------------------------
4 * Functions to process JSON data types.
6 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/backend/utils/adt/jsonfuncs.c
12 *-------------------------------------------------------------------------
21 #include "miscadmin.h"
22 #include "access/htup_details.h"
23 #include "catalog/pg_type.h"
24 #include "lib/stringinfo.h"
25 #include "mb/pg_wchar.h"
26 #include "utils/array.h"
27 #include "utils/builtins.h"
28 #include "utils/hsearch.h"
29 #include "utils/json.h"
30 #include "utils/jsonb.h"
31 #include "utils/jsonapi.h"
32 #include "utils/lsyscache.h"
33 #include "utils/memutils.h"
34 #include "utils/typcache.h"
36 /* semantic action functions for json_object_keys */
37 static void okeys_object_field_start(void *state, char *fname, bool isnull);
38 static void okeys_array_start(void *state);
39 static void okeys_scalar(void *state, char *token, JsonTokenType tokentype);
41 /* semantic action functions for json_get* functions */
42 static void get_object_start(void *state);
43 static void get_object_field_start(void *state, char *fname, bool isnull);
44 static void get_object_field_end(void *state, char *fname, bool isnull);
45 static void get_array_start(void *state);
46 static void get_array_element_start(void *state, bool isnull);
47 static void get_array_element_end(void *state, bool isnull);
48 static void get_scalar(void *state, char *token, JsonTokenType tokentype);
50 /* common worker function for json getter functions */
51 static inline Datum get_path_all(FunctionCallInfo fcinfo, bool as_text);
52 static inline text *get_worker(text *json, char *field, int elem_index,
53 char **tpath, int *ipath, int npath,
54 bool normalize_results);
55 static inline Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text);
57 /* semantic action functions for json_array_length */
58 static void alen_object_start(void *state);
59 static void alen_scalar(void *state, char *token, JsonTokenType tokentype);
60 static void alen_array_element_start(void *state, bool isnull);
62 /* common workers for json{b}_each* functions */
63 static inline Datum each_worker(FunctionCallInfo fcinfo, bool as_text);
64 static inline Datum each_worker_jsonb(FunctionCallInfo fcinfo, bool as_text);
66 /* semantic action functions for json_each */
67 static void each_object_field_start(void *state, char *fname, bool isnull);
68 static void each_object_field_end(void *state, char *fname, bool isnull);
69 static void each_array_start(void *state);
70 static void each_scalar(void *state, char *token, JsonTokenType tokentype);
72 /* common workers for json{b}_array_elements_* functions */
73 static inline Datum elements_worker(FunctionCallInfo fcinfo, bool as_text);
74 static inline Datum elements_worker_jsonb(FunctionCallInfo fcinfo, bool as_text);
76 /* semantic action functions for json_array_elements */
77 static void elements_object_start(void *state);
78 static void elements_array_element_start(void *state, bool isnull);
79 static void elements_array_element_end(void *state, bool isnull);
80 static void elements_scalar(void *state, char *token, JsonTokenType tokentype);
82 /* turn a json object into a hash table */
83 static HTAB *get_json_object_as_hash(text *json, char *funcname, bool use_json_as_text);
85 /* common worker for populate_record and to_record */
86 static inline Datum populate_record_worker(FunctionCallInfo fcinfo,
87 bool have_record_arg);
89 /* semantic action functions for get_json_object_as_hash */
90 static void hash_object_field_start(void *state, char *fname, bool isnull);
91 static void hash_object_field_end(void *state, char *fname, bool isnull);
92 static void hash_array_start(void *state);
93 static void hash_scalar(void *state, char *token, JsonTokenType tokentype);
95 /* semantic action functions for populate_recordset */
96 static void populate_recordset_object_field_start(void *state, char *fname, bool isnull);
97 static void populate_recordset_object_field_end(void *state, char *fname, bool isnull);
98 static void populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype);
99 static void populate_recordset_object_start(void *state);
100 static void populate_recordset_object_end(void *state);
101 static void populate_recordset_array_start(void *state);
102 static void populate_recordset_array_element_start(void *state, bool isnull);
104 /* worker function for populate_recordset and to_recordset */
105 static inline Datum populate_recordset_worker(FunctionCallInfo fcinfo,
106 bool have_record_arg);
108 /* Worker that takes care of common setup for us */
109 static JsonbValue *findJsonbValueFromContainerLen(JsonbContainer *container,
114 /* search type classification for json_get* functions */
117 JSON_SEARCH_OBJECT = 1,
122 /* state for json_object_keys */
123 typedef struct OkeysState
132 /* state for json_get* functions */
133 typedef struct GetState
136 JsonSearch search_type;
143 bool normalize_results;
149 int *array_level_index;
150 int *path_level_index;
153 /* state for json_array_length */
154 typedef struct AlenState
160 /* state for json_each */
161 typedef struct EachState
164 Tuplestorestate *tuple_store;
166 MemoryContext tmp_cxt;
168 bool normalize_results;
170 char *normalized_scalar;
173 /* state for json_array_elements */
174 typedef struct ElementsState
177 Tuplestorestate *tuple_store;
179 MemoryContext tmp_cxt;
181 bool normalize_results;
183 char *normalized_scalar;
186 /* state for get_json_object_as_hash */
187 typedef struct JhashState
192 char *save_json_start;
193 bool use_json_as_text;
197 /* used to build the hashtable */
198 typedef struct JsonHashEntry
200 char fname[NAMEDATALEN];
206 /* these two are stolen from hstore / record_out, used in populate_record* */
207 typedef struct ColumnIOData
215 typedef struct RecordIOData
220 ColumnIOData columns[1]; /* VARIABLE LENGTH ARRAY */
223 /* state for populate_recordset */
224 typedef struct PopulateRecordsetState
229 char *save_json_start;
230 bool use_json_as_text;
231 Tuplestorestate *tuple_store;
234 RecordIOData *my_extra;
235 MemoryContext fn_mcxt; /* used to stash IO funcs */
236 } PopulateRecordsetState;
238 /* Turn a jsonb object into a record */
239 static void make_row_from_rec_and_jsonb(Jsonb *element,
240 PopulateRecordsetState *state);
243 * SQL function json_object_keys
245 * Returns the set of keys for the object argument.
247 * This SRF operates in value-per-call mode. It processes the
248 * object during the first call, and the keys are simply stashed
249 * in an array, whose size is expanded as necessary. This is probably
250 * safe enough for a list of keys of a single object, since they are
251 * limited in size to NAMEDATALEN and the number of keys is unlikely to
252 * be so huge that it has major memory implications.
255 jsonb_object_keys(PG_FUNCTION_ARGS)
257 FuncCallContext *funcctx;
261 if (SRF_IS_FIRSTCALL())
263 MemoryContext oldcontext;
264 Jsonb *jb = PG_GETARG_JSONB(0);
265 bool skipNested = false;
270 if (JB_ROOT_IS_SCALAR(jb))
272 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
273 errmsg("cannot call jsonb_object_keys on a scalar")));
274 else if (JB_ROOT_IS_ARRAY(jb))
276 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
277 errmsg("cannot call jsonb_object_keys on an array")));
279 funcctx = SRF_FIRSTCALL_INIT();
280 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
282 state = palloc(sizeof(OkeysState));
284 state->result_size = JB_ROOT_COUNT(jb);
285 state->result_count = 0;
286 state->sent_count = 0;
287 state->result = palloc(state->result_size * sizeof(char *));
289 it = JsonbIteratorInit(&jb->root);
291 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
299 cstr = palloc(v.val.string.len + 1 * sizeof(char));
300 memcpy(cstr, v.val.string.val, v.val.string.len);
301 cstr[v.val.string.len] = '\0';
302 state->result[state->result_count++] = cstr;
307 MemoryContextSwitchTo(oldcontext);
308 funcctx->user_fctx = (void *) state;
312 funcctx = SRF_PERCALL_SETUP();
313 state = (OkeysState *) funcctx->user_fctx;
315 if (state->sent_count < state->result_count)
317 char *nxt = state->result[state->sent_count++];
319 SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(nxt));
322 /* cleanup to reduce or eliminate memory leaks */
323 for (i = 0; i < state->result_count; i++)
324 pfree(state->result[i]);
325 pfree(state->result);
328 SRF_RETURN_DONE(funcctx);
333 json_object_keys(PG_FUNCTION_ARGS)
335 FuncCallContext *funcctx;
339 if (SRF_IS_FIRSTCALL())
341 text *json = PG_GETARG_TEXT_P(0);
342 JsonLexContext *lex = makeJsonLexContext(json, true);
345 MemoryContext oldcontext;
347 funcctx = SRF_FIRSTCALL_INIT();
348 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
350 state = palloc(sizeof(OkeysState));
351 sem = palloc0(sizeof(JsonSemAction));
354 state->result_size = 256;
355 state->result_count = 0;
356 state->sent_count = 0;
357 state->result = palloc(256 * sizeof(char *));
359 sem->semstate = (void *) state;
360 sem->array_start = okeys_array_start;
361 sem->scalar = okeys_scalar;
362 sem->object_field_start = okeys_object_field_start;
363 /* remainder are all NULL, courtesy of palloc0 above */
365 pg_parse_json(lex, sem);
366 /* keys are now in state->result */
368 pfree(lex->strval->data);
373 MemoryContextSwitchTo(oldcontext);
374 funcctx->user_fctx = (void *) state;
378 funcctx = SRF_PERCALL_SETUP();
379 state = (OkeysState *) funcctx->user_fctx;
381 if (state->sent_count < state->result_count)
383 char *nxt = state->result[state->sent_count++];
385 SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(nxt));
388 /* cleanup to reduce or eliminate memory leaks */
389 for (i = 0; i < state->result_count; i++)
390 pfree(state->result[i]);
391 pfree(state->result);
394 SRF_RETURN_DONE(funcctx);
398 okeys_object_field_start(void *state, char *fname, bool isnull)
400 OkeysState *_state = (OkeysState *) state;
402 /* only collecting keys for the top level object */
403 if (_state->lex->lex_level != 1)
406 /* enlarge result array if necessary */
407 if (_state->result_count >= _state->result_size)
409 _state->result_size *= 2;
411 repalloc(_state->result, sizeof(char *) * _state->result_size);
414 /* save a copy of the field name */
415 _state->result[_state->result_count++] = pstrdup(fname);
419 okeys_array_start(void *state)
421 OkeysState *_state = (OkeysState *) state;
423 /* top level must be a json object */
424 if (_state->lex->lex_level == 0)
426 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
427 errmsg("cannot call json_object_keys on an array")));
431 okeys_scalar(void *state, char *token, JsonTokenType tokentype)
433 OkeysState *_state = (OkeysState *) state;
435 /* top level must be a json object */
436 if (_state->lex->lex_level == 0)
438 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
439 errmsg("cannot call json_object_keys on a scalar")));
443 * json and jsonb getter functions
444 * these implement the -> ->> #> and #>> operators
445 * and the json{b?}_extract_path*(json, text, ...) functions
450 json_object_field(PG_FUNCTION_ARGS)
452 text *json = PG_GETARG_TEXT_P(0);
454 text *fname = PG_GETARG_TEXT_P(1);
455 char *fnamestr = text_to_cstring(fname);
457 result = get_worker(json, fnamestr, -1, NULL, NULL, -1, false);
460 PG_RETURN_TEXT_P(result);
466 jsonb_object_field(PG_FUNCTION_ARGS)
468 Jsonb *jb = PG_GETARG_JSONB(0);
469 text *key = PG_GETARG_TEXT_PP(1);
472 if (JB_ROOT_IS_SCALAR(jb))
474 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
475 errmsg("cannot call jsonb_object_field (jsonb -> text operator) on a scalar")));
476 else if (JB_ROOT_IS_ARRAY(jb))
478 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
479 errmsg("cannot call jsonb_object_field (jsonb -> text operator) on an array")));
481 Assert(JB_ROOT_IS_OBJECT(jb));
483 v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT,
484 VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
487 PG_RETURN_JSONB(JsonbValueToJsonb(v));
493 json_object_field_text(PG_FUNCTION_ARGS)
495 text *json = PG_GETARG_TEXT_P(0);
497 text *fname = PG_GETARG_TEXT_P(1);
498 char *fnamestr = text_to_cstring(fname);
500 result = get_worker(json, fnamestr, -1, NULL, NULL, -1, true);
503 PG_RETURN_TEXT_P(result);
509 jsonb_object_field_text(PG_FUNCTION_ARGS)
511 Jsonb *jb = PG_GETARG_JSONB(0);
512 text *key = PG_GETARG_TEXT_PP(1);
515 if (JB_ROOT_IS_SCALAR(jb))
517 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
518 errmsg("cannot call jsonb_object_field_text (jsonb ->> text operator) on a scalar")));
519 else if (JB_ROOT_IS_ARRAY(jb))
521 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
522 errmsg("cannot call jsonb_object_field_text (jsonb ->> text operator) on an array")));
524 Assert(JB_ROOT_IS_OBJECT(jb));
526 v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT,
527 VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
538 result = cstring_to_text(v->val.boolean ? "true" : "false");
541 result = cstring_to_text_with_len(v->val.string.val, v->val.string.len);
544 result = cstring_to_text(DatumGetCString(DirectFunctionCall1(numeric_out,
545 PointerGetDatum(v->val.numeric))));
549 StringInfo jtext = makeStringInfo();
551 (void) JsonbToCString(jtext, v->val.binary.data, -1);
552 result = cstring_to_text_with_len(jtext->data, jtext->len);
556 elog(ERROR, "Wrong jsonb type: %d", v->type);
560 PG_RETURN_TEXT_P(result);
567 json_array_element(PG_FUNCTION_ARGS)
569 text *json = PG_GETARG_TEXT_P(0);
571 int element = PG_GETARG_INT32(1);
573 result = get_worker(json, NULL, element, NULL, NULL, -1, false);
576 PG_RETURN_TEXT_P(result);
582 jsonb_array_element(PG_FUNCTION_ARGS)
584 Jsonb *jb = PG_GETARG_JSONB(0);
585 int element = PG_GETARG_INT32(1);
588 if (JB_ROOT_IS_SCALAR(jb))
590 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
591 errmsg("cannot call jsonb_array_element (jsonb -> int operator) on a scalar")));
592 else if (JB_ROOT_IS_OBJECT(jb))
594 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
595 errmsg("cannot call jsonb_array_element (jsonb -> int operator) on an object")));
597 Assert(JB_ROOT_IS_ARRAY(jb));
599 v = getIthJsonbValueFromContainer(&jb->root, element);
601 PG_RETURN_JSONB(JsonbValueToJsonb(v));
607 json_array_element_text(PG_FUNCTION_ARGS)
609 text *json = PG_GETARG_TEXT_P(0);
611 int element = PG_GETARG_INT32(1);
613 result = get_worker(json, NULL, element, NULL, NULL, -1, true);
616 PG_RETURN_TEXT_P(result);
622 jsonb_array_element_text(PG_FUNCTION_ARGS)
624 Jsonb *jb = PG_GETARG_JSONB(0);
625 int element = PG_GETARG_INT32(1);
628 if (JB_ROOT_IS_SCALAR(jb))
630 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
631 errmsg("cannot call jsonb_array_element_text on a scalar")));
632 else if (JB_ROOT_IS_OBJECT(jb))
634 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
635 errmsg("cannot call jsonb_array_element_text on an object")));
637 Assert(JB_ROOT_IS_ARRAY(jb));
639 v = getIthJsonbValueFromContainer(&jb->root, element);
649 result = cstring_to_text(v->val.boolean ? "true" : "false");
652 result = cstring_to_text_with_len(v->val.string.val, v->val.string.len);
655 result = cstring_to_text(DatumGetCString(DirectFunctionCall1(numeric_out,
656 PointerGetDatum(v->val.numeric))));
660 StringInfo jtext = makeStringInfo();
662 (void) JsonbToCString(jtext, v->val.binary.data, -1);
663 result = cstring_to_text_with_len(jtext->data, jtext->len);
667 elog(ERROR, "Wrong jsonb type: %d", v->type);
671 PG_RETURN_TEXT_P(result);
678 json_extract_path(PG_FUNCTION_ARGS)
680 return get_path_all(fcinfo, false);
684 json_extract_path_text(PG_FUNCTION_ARGS)
686 return get_path_all(fcinfo, true);
690 * common routine for extract_path functions
693 get_path_all(FunctionCallInfo fcinfo, bool as_text)
696 ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
707 json = PG_GETARG_TEXT_P(0);
709 if (array_contains_nulls(path))
711 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
712 errmsg("cannot call function with null path elements")));
715 deconstruct_array(path, TEXTOID, -1, false, 'i',
716 &pathtext, &pathnulls, &npath);
718 tpath = palloc(npath * sizeof(char *));
719 ipath = palloc(npath * sizeof(int));
722 for (i = 0; i < npath; i++)
724 tpath[i] = TextDatumGetCString(pathtext[i]);
725 if (*tpath[i] == '\0')
728 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
729 errmsg("cannot call function with empty path elements")));
732 * we have no idea at this stage what structure the document is so
733 * just convert anything in the path that we can to an integer and set
734 * all the other integers to -1 which will never match.
736 ind = strtol(tpath[i], &endptr, 10);
737 if (*endptr == '\0' && ind <= INT_MAX && ind >= 0)
738 ipath[i] = (int) ind;
744 result = get_worker(json, NULL, -1, tpath, ipath, npath, as_text);
747 PG_RETURN_TEXT_P(result);
749 /* null is NULL, regardless */
756 * common worker for all the json getter functions
759 get_worker(text *json,
765 bool normalize_results)
768 JsonLexContext *lex = makeJsonLexContext(json, true);
771 /* only allowed to use one of these */
772 Assert(elem_index < 0 || (tpath == NULL && ipath == NULL && field == NULL));
773 Assert(tpath == NULL || field == NULL);
775 state = palloc0(sizeof(GetState));
776 sem = palloc0(sizeof(JsonSemAction));
779 /* is it "_as_text" variant? */
780 state->normalize_results = normalize_results;
783 /* single text argument */
784 state->search_type = JSON_SEARCH_OBJECT;
785 state->search_term = field;
787 else if (tpath != NULL)
789 /* path array argument */
790 state->search_type = JSON_SEARCH_PATH;
792 state->npath = npath;
793 state->current_path = palloc(sizeof(char *) * npath);
794 state->pathok = palloc0(sizeof(bool) * npath);
795 state->pathok[0] = true;
796 state->array_level_index = palloc(sizeof(int) * npath);
797 state->path_level_index = ipath;
802 /* single integer argument */
803 state->search_type = JSON_SEARCH_ARRAY;
804 state->search_index = elem_index;
805 state->array_index = -1;
808 sem->semstate = (void *) state;
811 * Not all variants need all the semantic routines. only set the ones
812 * that are actually needed for maximum efficiency.
814 sem->object_start = get_object_start;
815 sem->array_start = get_array_start;
816 sem->scalar = get_scalar;
817 if (field != NULL || tpath != NULL)
819 sem->object_field_start = get_object_field_start;
820 sem->object_field_end = get_object_field_end;
824 sem->array_element_start = get_array_element_start;
825 sem->array_element_end = get_array_element_end;
828 pg_parse_json(lex, sem);
830 return state->tresult;
834 get_object_start(void *state)
836 GetState *_state = (GetState *) state;
838 /* json structure check */
839 if (_state->lex->lex_level == 0 && _state->search_type == JSON_SEARCH_ARRAY)
841 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
842 errmsg("cannot extract array element from a non-array")));
846 get_object_field_start(void *state, char *fname, bool isnull)
848 GetState *_state = (GetState *) state;
849 bool get_next = false;
850 int lex_level = _state->lex->lex_level;
852 if (lex_level == 1 && _state->search_type == JSON_SEARCH_OBJECT &&
853 strcmp(fname, _state->search_term) == 0)
856 _state->tresult = NULL;
857 _state->result_start = NULL;
860 else if (_state->search_type == JSON_SEARCH_PATH &&
861 lex_level <= _state->npath &&
862 _state->pathok[_state->lex->lex_level - 1] &&
863 strcmp(fname, _state->path[lex_level - 1]) == 0)
865 /* path search, path so far is ok, and we have a match */
867 /* this object overrides any previous matching object */
869 _state->tresult = NULL;
870 _state->result_start = NULL;
872 /* if not at end of path just mark path ok */
873 if (lex_level < _state->npath)
874 _state->pathok[lex_level] = true;
876 /* end of path, so we want this value */
877 if (lex_level == _state->npath)
883 if (_state->normalize_results &&
884 _state->lex->token_type == JSON_TOKEN_STRING)
886 /* for as_text variants, tell get_scalar to set it for us */
887 _state->next_scalar = true;
891 /* for non-as_text variants, just note the json starting point */
892 _state->result_start = _state->lex->token_start;
898 get_object_field_end(void *state, char *fname, bool isnull)
900 GetState *_state = (GetState *) state;
901 bool get_last = false;
902 int lex_level = _state->lex->lex_level;
905 /* same tests as in get_object_field_start, mutatis mutandis */
906 if (lex_level == 1 && _state->search_type == JSON_SEARCH_OBJECT &&
907 strcmp(fname, _state->search_term) == 0)
911 else if (_state->search_type == JSON_SEARCH_PATH &&
912 lex_level <= _state->npath &&
913 _state->pathok[lex_level - 1] &&
914 strcmp(fname, _state->path[lex_level - 1]) == 0)
916 /* done with this field so reset pathok */
917 if (lex_level < _state->npath)
918 _state->pathok[lex_level] = false;
920 if (lex_level == _state->npath)
924 /* for as_test variants our work is already done */
925 if (get_last && _state->result_start != NULL)
928 * make a text object from the string from the prevously noted json
929 * start up to the end of the previous token (the lexer is by now
930 * ahead of us on whatever came after what we're interested in).
932 int len = _state->lex->prev_token_terminator - _state->result_start;
934 if (isnull && _state->normalize_results)
935 _state->tresult = (text *) NULL;
937 _state->tresult = cstring_to_text_with_len(_state->result_start, len);
941 * don't need to reset _state->result_start b/c we're only returning one
942 * datum, the conditions should not occur more than once, and this lets us
943 * check cheaply that they don't (see object_field_start() )
948 get_array_start(void *state)
950 GetState *_state = (GetState *) state;
951 int lex_level = _state->lex->lex_level;
953 /* json structure check */
954 if (lex_level == 0 && _state->search_type == JSON_SEARCH_OBJECT)
956 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
957 errmsg("cannot extract field from a non-object")));
960 * initialize array count for this nesting level Note: the lex_level seen
961 * by array_start is one less than that seen by the elements of the array.
963 if (_state->search_type == JSON_SEARCH_PATH &&
964 lex_level < _state->npath)
965 _state->array_level_index[lex_level] = -1;
969 get_array_element_start(void *state, bool isnull)
971 GetState *_state = (GetState *) state;
972 bool get_next = false;
973 int lex_level = _state->lex->lex_level;
975 if (lex_level == 1 && _state->search_type == JSON_SEARCH_ARRAY)
977 /* single integer search */
978 _state->array_index++;
979 if (_state->array_index == _state->search_index)
982 else if (_state->search_type == JSON_SEARCH_PATH &&
983 lex_level <= _state->npath &&
984 _state->pathok[lex_level - 1])
987 * path search, path so far is ok
989 * increment the array counter. no point doing this if we already know
992 * then check if we have a match.
995 if (++_state->array_level_index[lex_level - 1] ==
996 _state->path_level_index[lex_level - 1])
998 if (lex_level == _state->npath)
1000 /* match and at end of path, so get value */
1005 /* not at end of path just mark path ok */
1006 _state->pathok[lex_level] = true;
1012 /* same logic as for objects */
1015 if (_state->normalize_results &&
1016 _state->lex->token_type == JSON_TOKEN_STRING)
1018 _state->next_scalar = true;
1022 _state->result_start = _state->lex->token_start;
1028 get_array_element_end(void *state, bool isnull)
1030 GetState *_state = (GetState *) state;
1031 bool get_last = false;
1032 int lex_level = _state->lex->lex_level;
1034 /* same logic as in get_object_end, modified for arrays */
1036 if (lex_level == 1 && _state->search_type == JSON_SEARCH_ARRAY &&
1037 _state->array_index == _state->search_index)
1041 else if (_state->search_type == JSON_SEARCH_PATH &&
1042 lex_level <= _state->npath &&
1043 _state->pathok[lex_level - 1] &&
1044 _state->array_level_index[lex_level - 1] ==
1045 _state->path_level_index[lex_level - 1])
1047 /* done with this element so reset pathok */
1048 if (lex_level < _state->npath)
1049 _state->pathok[lex_level] = false;
1051 if (lex_level == _state->npath)
1054 if (get_last && _state->result_start != NULL)
1056 int len = _state->lex->prev_token_terminator - _state->result_start;
1058 if (isnull && _state->normalize_results)
1059 _state->tresult = (text *) NULL;
1061 _state->tresult = cstring_to_text_with_len(_state->result_start, len);
1066 get_scalar(void *state, char *token, JsonTokenType tokentype)
1068 GetState *_state = (GetState *) state;
1070 if (_state->lex->lex_level == 0 && _state->search_type != JSON_SEARCH_PATH)
1072 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1073 errmsg("cannot extract element from a scalar")));
1074 if (_state->next_scalar)
1076 /* a de-escaped text value is wanted, so supply it */
1077 _state->tresult = cstring_to_text(token);
1078 /* make sure the next call to get_scalar doesn't overwrite it */
1079 _state->next_scalar = false;
1085 jsonb_extract_path(PG_FUNCTION_ARGS)
1087 return get_jsonb_path_all(fcinfo, false);
1091 jsonb_extract_path_text(PG_FUNCTION_ARGS)
1093 return get_jsonb_path_all(fcinfo, true);
1097 get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
1099 Jsonb *jb = PG_GETARG_JSONB(0);
1100 ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
1106 bool have_object = false,
1108 JsonbValue *jbvp = NULL;
1110 JsonbContainer *container;
1112 if (array_contains_nulls(path))
1114 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1115 errmsg("cannot call function with null path elements")));
1117 deconstruct_array(path, TEXTOID, -1, false, 'i',
1118 &pathtext, &pathnulls, &npath);
1120 if (JB_ROOT_IS_OBJECT(jb))
1122 else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
1125 container = &jb->root;
1127 for (i = 0; i < npath; i++)
1131 jbvp = findJsonbValueFromContainerLen(container,
1133 VARDATA_ANY(pathtext[i]),
1134 VARSIZE_ANY_EXHDR(pathtext[i]));
1136 else if (have_array)
1140 char *indextext = TextDatumGetCString(pathtext[i]);
1143 lindex = strtol(indextext, &endptr, 10);
1144 if (*endptr != '\0' || lindex > INT_MAX || lindex < 0)
1146 index = (uint32) lindex;
1147 jbvp = getIthJsonbValueFromContainer(container, index);
1153 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1154 errmsg("cannot call extract path from a scalar")));
1160 else if (i == npath - 1)
1163 if (jbvp->type == jbvBinary)
1165 JsonbIterator *it = JsonbIteratorInit((JsonbContainer *) jbvp->val.binary.data);
1168 r = JsonbIteratorNext(&it, &tv, true);
1169 container = (JsonbContainer *) jbvp->val.binary.data;
1170 have_object = r == WJB_BEGIN_OBJECT;
1171 have_array = r == WJB_BEGIN_ARRAY;
1175 have_object = jbvp->type == jbvObject;
1176 have_array = jbvp->type == jbvArray;
1182 if (jbvp->type == jbvString)
1183 PG_RETURN_TEXT_P(cstring_to_text_with_len(jbvp->val.string.val, jbvp->val.string.len));
1184 else if (jbvp->type == jbvNull)
1188 res = JsonbValueToJsonb(jbvp);
1192 PG_RETURN_TEXT_P(cstring_to_text(JsonbToCString(NULL,
1198 /* not text mode - just hand back the jsonb */
1199 PG_RETURN_JSONB(res);
1204 * SQL function json_array_length(json) -> int
1207 json_array_length(PG_FUNCTION_ARGS)
1212 JsonLexContext *lex;
1215 json = PG_GETARG_TEXT_P(0);
1216 lex = makeJsonLexContext(json, false);
1217 state = palloc0(sizeof(AlenState));
1218 sem = palloc0(sizeof(JsonSemAction));
1220 /* palloc0 does this for us */
1226 sem->semstate = (void *) state;
1227 sem->object_start = alen_object_start;
1228 sem->scalar = alen_scalar;
1229 sem->array_element_start = alen_array_element_start;
1231 pg_parse_json(lex, sem);
1233 PG_RETURN_INT32(state->count);
1237 jsonb_array_length(PG_FUNCTION_ARGS)
1239 Jsonb *jb = PG_GETARG_JSONB(0);
1241 if (JB_ROOT_IS_SCALAR(jb))
1243 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1244 errmsg("cannot get array length of a scalar")));
1245 else if (!JB_ROOT_IS_ARRAY(jb))
1247 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1248 errmsg("cannot get array length of a non-array")));
1250 PG_RETURN_INT32(JB_ROOT_COUNT(jb));
1254 * These next two check ensure that the json is an array (since it can't be
1255 * a scalar or an object).
1259 alen_object_start(void *state)
1261 AlenState *_state = (AlenState *) state;
1263 /* json structure check */
1264 if (_state->lex->lex_level == 0)
1266 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1267 errmsg("cannot get array length of a non-array")));
1271 alen_scalar(void *state, char *token, JsonTokenType tokentype)
1273 AlenState *_state = (AlenState *) state;
1275 /* json structure check */
1276 if (_state->lex->lex_level == 0)
1278 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1279 errmsg("cannot get array length of a scalar")));
1283 alen_array_element_start(void *state, bool isnull)
1285 AlenState *_state = (AlenState *) state;
1287 /* just count up all the level 1 elements */
1288 if (_state->lex->lex_level == 1)
1293 * SQL function json_each and json_each_text
1295 * decompose a json object into key value pairs.
1297 * Unlike json_object_keys() these SRFs operate in materialize mode,
1298 * stashing results into a Tuplestore object as they go.
1299 * The construction of tuples is done using a temporary memory context
1300 * that is cleared out after each tuple is built.
1303 json_each(PG_FUNCTION_ARGS)
1305 return each_worker(fcinfo, false);
1309 jsonb_each(PG_FUNCTION_ARGS)
1311 return each_worker_jsonb(fcinfo, false);
1315 json_each_text(PG_FUNCTION_ARGS)
1317 return each_worker(fcinfo, true);
1321 jsonb_each_text(PG_FUNCTION_ARGS)
1323 return each_worker_jsonb(fcinfo, true);
1327 each_worker_jsonb(FunctionCallInfo fcinfo, bool as_text)
1329 Jsonb *jb = PG_GETARG_JSONB(0);
1331 Tuplestorestate *tuple_store;
1333 TupleDesc ret_tdesc;
1334 MemoryContext old_cxt,
1336 bool skipNested = false;
1341 if (!JB_ROOT_IS_OBJECT(jb))
1343 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1344 errmsg("cannot call jsonb_each%s on a non-object",
1345 as_text ? "_text" : "")));
1347 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1349 if (!rsi || !IsA(rsi, ReturnSetInfo) ||
1350 (rsi->allowedModes & SFRM_Materialize) == 0 ||
1351 rsi->expectedDesc == NULL)
1353 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1354 errmsg("set-valued function called in context that "
1355 "cannot accept a set")));
1358 rsi->returnMode = SFRM_Materialize;
1360 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1362 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1363 errmsg("function returning record called in context "
1364 "that cannot accept type record")));
1366 old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
1368 ret_tdesc = CreateTupleDescCopy(tupdesc);
1369 BlessTupleDesc(ret_tdesc);
1371 tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
1374 MemoryContextSwitchTo(old_cxt);
1376 tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
1377 "jsonb_each temporary cxt",
1378 ALLOCSET_DEFAULT_MINSIZE,
1379 ALLOCSET_DEFAULT_INITSIZE,
1380 ALLOCSET_DEFAULT_MAXSIZE);
1383 it = JsonbIteratorInit(&jb->root);
1385 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
1394 bool nulls[2] = {false, false};
1396 /* Use the tmp context so we can clean up after each tuple is done */
1397 old_cxt = MemoryContextSwitchTo(tmp_cxt);
1399 key = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
1402 * The next thing the iterator fetches should be the value, no
1403 * matter what shape it is.
1405 r = JsonbIteratorNext(&it, &v, skipNested);
1407 values[0] = PointerGetDatum(key);
1411 if (v.type == jbvNull)
1413 /* a json null is an sql null in text mode */
1415 values[1] = (Datum) NULL;
1421 if (v.type == jbvString)
1423 /* In text mode, scalar strings should be dequoted */
1424 sv = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
1428 /* Turn anything else into a json string */
1429 StringInfo jtext = makeStringInfo();
1430 Jsonb *jb = JsonbValueToJsonb(&v);
1432 (void) JsonbToCString(jtext, &jb->root, 0);
1433 sv = cstring_to_text_with_len(jtext->data, jtext->len);
1436 values[1] = PointerGetDatum(sv);
1441 /* Not in text mode, just return the Jsonb */
1442 Jsonb *val = JsonbValueToJsonb(&v);
1444 values[1] = PointerGetDatum(val);
1447 tuple = heap_form_tuple(ret_tdesc, values, nulls);
1449 tuplestore_puttuple(tuple_store, tuple);
1451 /* clean up and switch back */
1452 MemoryContextSwitchTo(old_cxt);
1453 MemoryContextReset(tmp_cxt);
1457 MemoryContextDelete(tmp_cxt);
1459 rsi->setResult = tuple_store;
1460 rsi->setDesc = ret_tdesc;
1467 each_worker(FunctionCallInfo fcinfo, bool as_text)
1470 JsonLexContext *lex;
1473 MemoryContext old_cxt;
1477 json = PG_GETARG_TEXT_P(0);
1479 lex = makeJsonLexContext(json, true);
1480 state = palloc0(sizeof(EachState));
1481 sem = palloc0(sizeof(JsonSemAction));
1483 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1485 if (!rsi || !IsA(rsi, ReturnSetInfo) ||
1486 (rsi->allowedModes & SFRM_Materialize) == 0 ||
1487 rsi->expectedDesc == NULL)
1489 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1490 errmsg("set-valued function called in context that "
1491 "cannot accept a set")));
1494 rsi->returnMode = SFRM_Materialize;
1496 (void) get_call_result_type(fcinfo, NULL, &tupdesc);
1498 /* make these in a sufficiently long-lived memory context */
1499 old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
1501 state->ret_tdesc = CreateTupleDescCopy(tupdesc);
1502 BlessTupleDesc(state->ret_tdesc);
1503 state->tuple_store =
1504 tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
1507 MemoryContextSwitchTo(old_cxt);
1509 sem->semstate = (void *) state;
1510 sem->array_start = each_array_start;
1511 sem->scalar = each_scalar;
1512 sem->object_field_start = each_object_field_start;
1513 sem->object_field_end = each_object_field_end;
1515 state->normalize_results = as_text;
1516 state->next_scalar = false;
1519 state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
1520 "json_each temporary cxt",
1521 ALLOCSET_DEFAULT_MINSIZE,
1522 ALLOCSET_DEFAULT_INITSIZE,
1523 ALLOCSET_DEFAULT_MAXSIZE);
1525 pg_parse_json(lex, sem);
1527 MemoryContextDelete(state->tmp_cxt);
1529 rsi->setResult = state->tuple_store;
1530 rsi->setDesc = state->ret_tdesc;
1537 each_object_field_start(void *state, char *fname, bool isnull)
1539 EachState *_state = (EachState *) state;
1541 /* save a pointer to where the value starts */
1542 if (_state->lex->lex_level == 1)
1545 * next_scalar will be reset in the object_field_end handler, and
1546 * since we know the value is a scalar there is no danger of it being
1547 * on while recursing down the tree.
1549 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
1550 _state->next_scalar = true;
1552 _state->result_start = _state->lex->token_start;
1557 each_object_field_end(void *state, char *fname, bool isnull)
1559 EachState *_state = (EachState *) state;
1560 MemoryContext old_cxt;
1565 bool nulls[2] = {false, false};
1567 /* skip over nested objects */
1568 if (_state->lex->lex_level != 1)
1571 /* use the tmp context so we can clean up after each tuple is done */
1572 old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
1574 values[0] = CStringGetTextDatum(fname);
1576 if (isnull && _state->normalize_results)
1579 values[1] = (Datum) NULL;
1581 else if (_state->next_scalar)
1583 values[1] = CStringGetTextDatum(_state->normalized_scalar);
1584 _state->next_scalar = false;
1588 len = _state->lex->prev_token_terminator - _state->result_start;
1589 val = cstring_to_text_with_len(_state->result_start, len);
1590 values[1] = PointerGetDatum(val);
1594 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
1596 tuplestore_puttuple(_state->tuple_store, tuple);
1598 /* clean up and switch back */
1599 MemoryContextSwitchTo(old_cxt);
1600 MemoryContextReset(_state->tmp_cxt);
1604 each_array_start(void *state)
1606 EachState *_state = (EachState *) state;
1608 /* json structure check */
1609 if (_state->lex->lex_level == 0)
1611 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1612 errmsg("cannot deconstruct an array as an object")));
1616 each_scalar(void *state, char *token, JsonTokenType tokentype)
1618 EachState *_state = (EachState *) state;
1620 /* json structure check */
1621 if (_state->lex->lex_level == 0)
1623 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1624 errmsg("cannot deconstruct a scalar")));
1626 /* supply de-escaped value if required */
1627 if (_state->next_scalar)
1628 _state->normalized_scalar = token;
1632 * SQL functions json_array_elements and json_array_elements_text
1634 * get the elements from a json array
1636 * a lot of this processing is similar to the json_each* functions
1640 jsonb_array_elements(PG_FUNCTION_ARGS)
1642 return elements_worker_jsonb(fcinfo, false);
1646 jsonb_array_elements_text(PG_FUNCTION_ARGS)
1648 return elements_worker_jsonb(fcinfo, true);
1652 elements_worker_jsonb(FunctionCallInfo fcinfo, bool as_text)
1654 Jsonb *jb = PG_GETARG_JSONB(0);
1656 Tuplestorestate *tuple_store;
1658 TupleDesc ret_tdesc;
1659 MemoryContext old_cxt,
1661 bool skipNested = false;
1666 if (JB_ROOT_IS_SCALAR(jb))
1668 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1669 errmsg("cannot extract elements from a scalar")));
1670 else if (!JB_ROOT_IS_ARRAY(jb))
1672 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1673 errmsg("cannot extract elements from an object")));
1675 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1677 if (!rsi || !IsA(rsi, ReturnSetInfo) ||
1678 (rsi->allowedModes & SFRM_Materialize) == 0 ||
1679 rsi->expectedDesc == NULL)
1681 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1682 errmsg("set-valued function called in context that "
1683 "cannot accept a set")));
1686 rsi->returnMode = SFRM_Materialize;
1688 /* it's a simple type, so don't use get_call_result_type() */
1689 tupdesc = rsi->expectedDesc;
1691 old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
1693 ret_tdesc = CreateTupleDescCopy(tupdesc);
1694 BlessTupleDesc(ret_tdesc);
1696 tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
1699 MemoryContextSwitchTo(old_cxt);
1701 tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
1702 "jsonb_each temporary cxt",
1703 ALLOCSET_DEFAULT_MINSIZE,
1704 ALLOCSET_DEFAULT_INITSIZE,
1705 ALLOCSET_DEFAULT_MAXSIZE);
1708 it = JsonbIteratorInit(&jb->root);
1710 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
1718 bool nulls[1] = {false};
1720 /* use the tmp context so we can clean up after each tuple is done */
1721 old_cxt = MemoryContextSwitchTo(tmp_cxt);
1725 Jsonb *val = JsonbValueToJsonb(&v);
1727 values[0] = PointerGetDatum(val);
1731 if (v.type == jbvNull)
1733 /* a json null is an sql null in text mode */
1735 values[0] = (Datum) NULL;
1741 if (v.type == jbvString)
1743 /* in text mode scalar strings should be dequoted */
1744 sv = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
1748 /* turn anything else into a json string */
1749 StringInfo jtext = makeStringInfo();
1750 Jsonb *jb = JsonbValueToJsonb(&v);
1752 (void) JsonbToCString(jtext, &jb->root, 0);
1753 sv = cstring_to_text_with_len(jtext->data, jtext->len);
1756 values[0] = PointerGetDatum(sv);
1760 tuple = heap_form_tuple(ret_tdesc, values, nulls);
1762 tuplestore_puttuple(tuple_store, tuple);
1764 /* clean up and switch back */
1765 MemoryContextSwitchTo(old_cxt);
1766 MemoryContextReset(tmp_cxt);
1770 MemoryContextDelete(tmp_cxt);
1772 rsi->setResult = tuple_store;
1773 rsi->setDesc = ret_tdesc;
1779 json_array_elements(PG_FUNCTION_ARGS)
1781 return elements_worker(fcinfo, false);
1785 json_array_elements_text(PG_FUNCTION_ARGS)
1787 return elements_worker(fcinfo, true);
1791 elements_worker(FunctionCallInfo fcinfo, bool as_text)
1793 text *json = PG_GETARG_TEXT_P(0);
1795 /* elements only needs escaped strings when as_text */
1796 JsonLexContext *lex = makeJsonLexContext(json, as_text);
1799 MemoryContext old_cxt;
1801 ElementsState *state;
1803 state = palloc0(sizeof(ElementsState));
1804 sem = palloc0(sizeof(JsonSemAction));
1806 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1808 if (!rsi || !IsA(rsi, ReturnSetInfo) ||
1809 (rsi->allowedModes & SFRM_Materialize) == 0 ||
1810 rsi->expectedDesc == NULL)
1812 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1813 errmsg("set-valued function called in context that "
1814 "cannot accept a set")));
1817 rsi->returnMode = SFRM_Materialize;
1819 /* it's a simple type, so don't use get_call_result_type() */
1820 tupdesc = rsi->expectedDesc;
1822 /* make these in a sufficiently long-lived memory context */
1823 old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
1825 state->ret_tdesc = CreateTupleDescCopy(tupdesc);
1826 BlessTupleDesc(state->ret_tdesc);
1827 state->tuple_store =
1828 tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
1831 MemoryContextSwitchTo(old_cxt);
1833 sem->semstate = (void *) state;
1834 sem->object_start = elements_object_start;
1835 sem->scalar = elements_scalar;
1836 sem->array_element_start = elements_array_element_start;
1837 sem->array_element_end = elements_array_element_end;
1839 state->normalize_results = as_text;
1840 state->next_scalar = false;
1843 state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
1844 "json_array_elements temporary cxt",
1845 ALLOCSET_DEFAULT_MINSIZE,
1846 ALLOCSET_DEFAULT_INITSIZE,
1847 ALLOCSET_DEFAULT_MAXSIZE);
1849 pg_parse_json(lex, sem);
1851 MemoryContextDelete(state->tmp_cxt);
1853 rsi->setResult = state->tuple_store;
1854 rsi->setDesc = state->ret_tdesc;
1860 elements_array_element_start(void *state, bool isnull)
1862 ElementsState *_state = (ElementsState *) state;
1864 /* save a pointer to where the value starts */
1865 if (_state->lex->lex_level == 1)
1868 * next_scalar will be reset in the array_element_end handler, and
1869 * since we know the value is a scalar there is no danger of it being
1870 * on while recursing down the tree.
1872 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
1873 _state->next_scalar = true;
1875 _state->result_start = _state->lex->token_start;
1880 elements_array_element_end(void *state, bool isnull)
1882 ElementsState *_state = (ElementsState *) state;
1883 MemoryContext old_cxt;
1888 bool nulls[1] = {false};
1890 /* skip over nested objects */
1891 if (_state->lex->lex_level != 1)
1894 /* use the tmp context so we can clean up after each tuple is done */
1895 old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
1897 if (isnull && _state->normalize_results)
1900 values[0] = (Datum) NULL;
1902 else if (_state->next_scalar)
1904 values[0] = CStringGetTextDatum(_state->normalized_scalar);
1905 _state->next_scalar = false;
1909 len = _state->lex->prev_token_terminator - _state->result_start;
1910 val = cstring_to_text_with_len(_state->result_start, len);
1911 values[0] = PointerGetDatum(val);
1915 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
1917 tuplestore_puttuple(_state->tuple_store, tuple);
1919 /* clean up and switch back */
1920 MemoryContextSwitchTo(old_cxt);
1921 MemoryContextReset(_state->tmp_cxt);
1925 elements_object_start(void *state)
1927 ElementsState *_state = (ElementsState *) state;
1929 /* json structure check */
1930 if (_state->lex->lex_level == 0)
1932 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1933 errmsg("cannot call json_array_elements on a non-array")));
1937 elements_scalar(void *state, char *token, JsonTokenType tokentype)
1939 ElementsState *_state = (ElementsState *) state;
1941 /* json structure check */
1942 if (_state->lex->lex_level == 0)
1944 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1945 errmsg("cannot call json_array_elements on a scalar")));
1947 /* supply de-escaped value if required */
1948 if (_state->next_scalar)
1949 _state->normalized_scalar = token;
1953 * SQL function json_populate_record
1955 * set fields in a record from the argument json
1957 * Code adapted shamelessly from hstore's populate_record
1958 * which is in turn partly adapted from record_out.
1960 * The json is decomposed into a hash table, in which each
1961 * field in the record is then looked up by name. For jsonb
1962 * we fetch the values direct from the object.
1965 jsonb_populate_record(PG_FUNCTION_ARGS)
1967 return populate_record_worker(fcinfo, true);
1971 jsonb_to_record(PG_FUNCTION_ARGS)
1973 return populate_record_worker(fcinfo, false);
1977 json_populate_record(PG_FUNCTION_ARGS)
1979 return populate_record_worker(fcinfo, true);
1983 json_to_record(PG_FUNCTION_ARGS)
1985 return populate_record_worker(fcinfo, false);
1989 populate_record_worker(FunctionCallInfo fcinfo, bool have_record_arg)
1991 int json_arg_num = have_record_arg ? 1 : 0;
1992 Oid jtype = get_fn_expr_argtype(fcinfo->flinfo, json_arg_num);
1995 bool use_json_as_text;
1996 HTAB *json_hash = NULL;
1997 HeapTupleHeader rec = NULL;
1998 Oid tupType = InvalidOid;
1999 int32 tupTypmod = -1;
2001 HeapTupleData tuple;
2003 RecordIOData *my_extra;
2009 Assert(jtype == JSONOID || jtype == JSONBOID);
2011 use_json_as_text = PG_ARGISNULL(json_arg_num + 1) ? false :
2012 PG_GETARG_BOOL(json_arg_num + 1);
2014 if (have_record_arg)
2016 Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
2018 if (!type_is_rowtype(argtype))
2020 (errcode(ERRCODE_DATATYPE_MISMATCH),
2021 errmsg("first argument of json%s_populate_record must be a row type", jtype == JSONBOID ? "b" : "")));
2023 if (PG_ARGISNULL(0))
2025 if (PG_ARGISNULL(1))
2029 * have no tuple to look at, so the only source of type info is
2030 * the argtype. The lookup_rowtype_tupdesc call below will error
2031 * out if we don't have a known composite type oid here.
2038 rec = PG_GETARG_HEAPTUPLEHEADER(0);
2040 if (PG_ARGISNULL(1))
2041 PG_RETURN_POINTER(rec);
2043 /* Extract type info from the tuple itself */
2044 tupType = HeapTupleHeaderGetTypeId(rec);
2045 tupTypmod = HeapTupleHeaderGetTypMod(rec);
2048 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
2051 { /* json{b}_to_record case */
2053 if (PG_ARGISNULL(0))
2056 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2058 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2059 errmsg("function returning record called in context "
2060 "that cannot accept type record"),
2061 errhint("Try calling the function in the FROM clause "
2062 "using a column definition list.")));
2065 if (jtype == JSONOID)
2067 /* just get the text */
2068 json = PG_GETARG_TEXT_P(json_arg_num);
2070 json_hash = get_json_object_as_hash(json, "json_populate_record", use_json_as_text);
2073 * if the input json is empty, we can only skip the rest if we were
2074 * passed in a non-null record, since otherwise there may be issues
2075 * with domain nulls.
2077 if (hash_get_num_entries(json_hash) == 0 && rec)
2079 hash_destroy(json_hash);
2080 PG_RETURN_POINTER(rec);
2085 jb = PG_GETARG_JSONB(json_arg_num);
2087 /* same logic as for json */
2088 if (!have_record_arg && rec)
2089 PG_RETURN_POINTER(rec);
2092 ncolumns = tupdesc->natts;
2096 /* Build a temporary HeapTuple control structure */
2097 tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
2098 ItemPointerSetInvalid(&(tuple.t_self));
2099 tuple.t_tableOid = InvalidOid;
2104 * We arrange to look up the needed I/O info just once per series of
2105 * calls, assuming the record type doesn't change underneath us.
2107 my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
2108 if (my_extra == NULL ||
2109 my_extra->ncolumns != ncolumns)
2111 fcinfo->flinfo->fn_extra =
2112 MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
2113 sizeof(RecordIOData) - sizeof(ColumnIOData)
2114 + ncolumns * sizeof(ColumnIOData));
2115 my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
2116 my_extra->record_type = InvalidOid;
2117 my_extra->record_typmod = 0;
2118 my_extra->ncolumns = ncolumns;
2119 MemSet(my_extra->columns, 0, sizeof(ColumnIOData) * ncolumns);
2122 if (have_record_arg && (my_extra->record_type != tupType ||
2123 my_extra->record_typmod != tupTypmod))
2126 sizeof(RecordIOData) - sizeof(ColumnIOData)
2127 + ncolumns * sizeof(ColumnIOData));
2128 my_extra->record_type = tupType;
2129 my_extra->record_typmod = tupTypmod;
2130 my_extra->ncolumns = ncolumns;
2133 values = (Datum *) palloc(ncolumns * sizeof(Datum));
2134 nulls = (bool *) palloc(ncolumns * sizeof(bool));
2138 /* Break down the tuple into fields */
2139 heap_deform_tuple(&tuple, tupdesc, values, nulls);
2143 for (i = 0; i < ncolumns; ++i)
2145 values[i] = (Datum) 0;
2150 for (i = 0; i < ncolumns; ++i)
2152 ColumnIOData *column_info = &my_extra->columns[i];
2153 Oid column_type = tupdesc->attrs[i]->atttypid;
2154 JsonbValue *v = NULL;
2155 char fname[NAMEDATALEN];
2156 JsonHashEntry *hashentry = NULL;
2158 /* Ignore dropped columns in datatype */
2159 if (tupdesc->attrs[i]->attisdropped)
2165 if (jtype == JSONOID)
2168 memset(fname, 0, NAMEDATALEN);
2169 strncpy(fname, NameStr(tupdesc->attrs[i]->attname), NAMEDATALEN);
2170 hashentry = hash_search(json_hash, fname, HASH_FIND, NULL);
2174 char *key = NameStr(tupdesc->attrs[i]->attname);
2176 v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT, key,
2181 * we can't just skip here if the key wasn't found since we might have
2182 * a domain to deal with. If we were passed in a non-null record
2183 * datum, we assume that the existing values are valid (if they're
2184 * not, then it's not our fault), but if we were passed in a null,
2185 * then every field which we don't populate needs to be run through
2186 * the input function just in case it's a domain type.
2188 if (((jtype == JSONOID && hashentry == NULL) ||
2189 (jtype == JSONBOID && v == NULL)) && rec)
2193 * Prepare to convert the column value from text
2195 if (column_info->column_type != column_type)
2197 getTypeInputInfo(column_type,
2198 &column_info->typiofunc,
2199 &column_info->typioparam);
2200 fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
2201 fcinfo->flinfo->fn_mcxt);
2202 column_info->column_type = column_type;
2204 if ((jtype == JSONOID && (hashentry == NULL || hashentry->isnull)) ||
2205 (jtype == JSONBOID && (v == NULL || v->type == jbvNull)))
2208 * need InputFunctionCall to happen even for nulls, so that domain
2211 values[i] = InputFunctionCall(&column_info->proc, NULL,
2212 column_info->typioparam,
2213 tupdesc->attrs[i]->atttypmod);
2220 if (jtype == JSONOID)
2222 /* already done the hard work in the json case */
2227 if (v->type == jbvString)
2228 s = pnstrdup(v->val.string.val, v->val.string.len);
2229 else if (v->type == jbvBool)
2230 s = pnstrdup((v->val.boolean) ? "t" : "f", 1);
2231 else if (v->type == jbvNumeric)
2232 s = DatumGetCString(DirectFunctionCall1(numeric_out,
2233 PointerGetDatum(v->val.numeric)));
2234 else if (!use_json_as_text)
2236 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2237 errmsg("cannot populate with a nested object unless use_json_as_text is true")));
2238 else if (v->type == jbvBinary)
2239 s = JsonbToCString(NULL, (JsonbContainer *) v->val.binary.data, v->val.binary.len);
2241 elog(ERROR, "invalid jsonb type");
2244 values[i] = InputFunctionCall(&column_info->proc, s,
2245 column_info->typioparam,
2246 tupdesc->attrs[i]->atttypmod);
2251 rettuple = heap_form_tuple(tupdesc, values, nulls);
2253 ReleaseTupleDesc(tupdesc);
2256 hash_destroy(json_hash);
2258 PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
2262 * get_json_object_as_hash
2264 * decompose a json object into a hash table.
2266 * Currently doesn't allow anything but a flat object. Should this
2269 * funcname argument allows caller to pass in its name for use in
2273 get_json_object_as_hash(text *json, char *funcname, bool use_json_as_text)
2278 JsonLexContext *lex = makeJsonLexContext(json, true);
2281 memset(&ctl, 0, sizeof(ctl));
2282 ctl.keysize = NAMEDATALEN;
2283 ctl.entrysize = sizeof(JsonHashEntry);
2284 ctl.hcxt = CurrentMemoryContext;
2285 tab = hash_create("json object hashtable",
2288 HASH_ELEM | HASH_CONTEXT);
2290 state = palloc0(sizeof(JHashState));
2291 sem = palloc0(sizeof(JsonSemAction));
2293 state->function_name = funcname;
2296 state->use_json_as_text = use_json_as_text;
2298 sem->semstate = (void *) state;
2299 sem->array_start = hash_array_start;
2300 sem->scalar = hash_scalar;
2301 sem->object_field_start = hash_object_field_start;
2302 sem->object_field_end = hash_object_field_end;
2304 pg_parse_json(lex, sem);
2310 hash_object_field_start(void *state, char *fname, bool isnull)
2312 JHashState *_state = (JHashState *) state;
2314 if (_state->lex->lex_level > 1)
2317 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
2318 _state->lex->token_type == JSON_TOKEN_OBJECT_START)
2320 if (!_state->use_json_as_text)
2322 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2323 errmsg("cannot call %s on a nested object",
2324 _state->function_name)));
2325 _state->save_json_start = _state->lex->token_start;
2329 /* must be a scalar */
2330 _state->save_json_start = NULL;
2335 hash_object_field_end(void *state, char *fname, bool isnull)
2337 JHashState *_state = (JHashState *) state;
2338 JsonHashEntry *hashentry;
2340 char name[NAMEDATALEN];
2343 * ignore field names >= NAMEDATALEN - they can't match a record field
2344 * ignore nested fields.
2346 if (_state->lex->lex_level > 2 || strlen(fname) >= NAMEDATALEN)
2349 memset(name, 0, NAMEDATALEN);
2350 strncpy(name, fname, NAMEDATALEN);
2352 hashentry = hash_search(_state->hash, name, HASH_ENTER, &found);
2355 * found being true indicates a duplicate. We don't do anything about
2356 * that, a later field with the same name overrides the earlier field.
2359 hashentry->isnull = isnull;
2360 if (_state->save_json_start != NULL)
2362 int len = _state->lex->prev_token_terminator - _state->save_json_start;
2363 char *val = palloc((len + 1) * sizeof(char));
2365 memcpy(val, _state->save_json_start, len);
2367 hashentry->val = val;
2371 /* must have had a scalar instead */
2372 hashentry->val = _state->saved_scalar;
2377 hash_array_start(void *state)
2379 JHashState *_state = (JHashState *) state;
2381 if (_state->lex->lex_level == 0)
2383 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2384 errmsg("cannot call %s on an array", _state->function_name)));
2388 hash_scalar(void *state, char *token, JsonTokenType tokentype)
2390 JHashState *_state = (JHashState *) state;
2392 if (_state->lex->lex_level == 0)
2394 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2395 errmsg("cannot call %s on a scalar", _state->function_name)));
2397 if (_state->lex->lex_level == 1)
2398 _state->saved_scalar = token;
2403 * SQL function json_populate_recordset
2405 * set fields in a set of records from the argument json,
2406 * which must be an array of objects.
2408 * similar to json_populate_record, but the tuple-building code
2409 * is pushed down into the semantic action handlers so it's done
2410 * per object in the array.
2413 jsonb_populate_recordset(PG_FUNCTION_ARGS)
2415 return populate_recordset_worker(fcinfo, true);
2419 jsonb_to_recordset(PG_FUNCTION_ARGS)
2421 return populate_recordset_worker(fcinfo, false);
2425 json_populate_recordset(PG_FUNCTION_ARGS)
2427 return populate_recordset_worker(fcinfo, true);
2431 json_to_recordset(PG_FUNCTION_ARGS)
2433 return populate_recordset_worker(fcinfo, false);
2437 make_row_from_rec_and_jsonb(Jsonb *element, PopulateRecordsetState *state)
2442 RecordIOData *my_extra = state->my_extra;
2443 int ncolumns = my_extra->ncolumns;
2444 TupleDesc tupdesc = state->ret_tdesc;
2445 HeapTupleHeader rec = state->rec;
2448 values = (Datum *) palloc(ncolumns * sizeof(Datum));
2449 nulls = (bool *) palloc(ncolumns * sizeof(bool));
2453 HeapTupleData tuple;
2455 /* Build a temporary HeapTuple control structure */
2456 tuple.t_len = HeapTupleHeaderGetDatumLength(state->rec);
2457 ItemPointerSetInvalid(&(tuple.t_self));
2458 tuple.t_tableOid = InvalidOid;
2459 tuple.t_data = state->rec;
2461 /* Break down the tuple into fields */
2462 heap_deform_tuple(&tuple, tupdesc, values, nulls);
2466 for (i = 0; i < ncolumns; ++i)
2468 values[i] = (Datum) 0;
2473 for (i = 0; i < ncolumns; ++i)
2475 ColumnIOData *column_info = &my_extra->columns[i];
2476 Oid column_type = tupdesc->attrs[i]->atttypid;
2477 JsonbValue *v = NULL;
2480 /* Ignore dropped columns in datatype */
2481 if (tupdesc->attrs[i]->attisdropped)
2487 key = NameStr(tupdesc->attrs[i]->attname);
2489 v = findJsonbValueFromContainerLen(&element->root, JB_FOBJECT,
2493 * We can't just skip here if the key wasn't found since we might have
2494 * a domain to deal with. If we were passed in a non-null record
2495 * datum, we assume that the existing values are valid (if they're
2496 * not, then it's not our fault), but if we were passed in a null,
2497 * then every field which we don't populate needs to be run through
2498 * the input function just in case it's a domain type.
2500 if (v == NULL && rec)
2504 * Prepare to convert the column value from text
2506 if (column_info->column_type != column_type)
2508 getTypeInputInfo(column_type,
2509 &column_info->typiofunc,
2510 &column_info->typioparam);
2511 fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
2513 column_info->column_type = column_type;
2515 if (v == NULL || v->type == jbvNull)
2518 * Need InputFunctionCall to happen even for nulls, so that domain
2521 values[i] = InputFunctionCall(&column_info->proc, NULL,
2522 column_info->typioparam,
2523 tupdesc->attrs[i]->atttypmod);
2530 if (v->type == jbvString)
2531 s = pnstrdup(v->val.string.val, v->val.string.len);
2532 else if (v->type == jbvBool)
2533 s = pnstrdup((v->val.boolean) ? "t" : "f", 1);
2534 else if (v->type == jbvNumeric)
2535 s = DatumGetCString(DirectFunctionCall1(numeric_out,
2536 PointerGetDatum(v->val.numeric)));
2537 else if (!state->use_json_as_text)
2539 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2540 errmsg("cannot populate with a nested object unless use_json_as_text is true")));
2541 else if (v->type == jbvBinary)
2542 s = JsonbToCString(NULL, (JsonbContainer *) v->val.binary.data, v->val.binary.len);
2544 elog(ERROR, "invalid jsonb type");
2546 values[i] = InputFunctionCall(&column_info->proc, s,
2547 column_info->typioparam,
2548 tupdesc->attrs[i]->atttypmod);
2553 rettuple = heap_form_tuple(tupdesc, values, nulls);
2555 tuplestore_puttuple(state->tuple_store, rettuple);
2559 * common worker for json_populate_recordset() and json_to_recordset()
2562 populate_recordset_worker(FunctionCallInfo fcinfo, bool have_record_arg)
2564 int json_arg_num = have_record_arg ? 1 : 0;
2565 Oid jtype = get_fn_expr_argtype(fcinfo->flinfo, json_arg_num);
2566 bool use_json_as_text;
2568 MemoryContext old_cxt;
2571 HeapTupleHeader rec;
2573 RecordIOData *my_extra;
2575 PopulateRecordsetState *state;
2577 use_json_as_text = PG_ARGISNULL(json_arg_num + 1) ? false : PG_GETARG_BOOL(json_arg_num + 1);
2579 if (have_record_arg)
2581 Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
2583 if (!type_is_rowtype(argtype))
2585 (errcode(ERRCODE_DATATYPE_MISMATCH),
2586 errmsg("first argument must be a row type")));
2589 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2591 if (!rsi || !IsA(rsi, ReturnSetInfo) ||
2592 (rsi->allowedModes & SFRM_Materialize) == 0 ||
2593 rsi->expectedDesc == NULL)
2595 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2596 errmsg("set-valued function called in context that "
2597 "cannot accept a set")));
2600 rsi->returnMode = SFRM_Materialize;
2603 * get the tupdesc from the result set info - it must be a record type
2604 * because we already checked that arg1 is a record type, or we're in a
2605 * to_record function which returns a setof record.
2607 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2609 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2610 errmsg("function returning record called in context "
2611 "that cannot accept type record")));
2613 /* if the json is null send back an empty set */
2614 if (PG_ARGISNULL(json_arg_num))
2617 if (!have_record_arg || PG_ARGISNULL(0))
2620 rec = PG_GETARG_HEAPTUPLEHEADER(0);
2622 tupType = tupdesc->tdtypeid;
2623 tupTypmod = tupdesc->tdtypmod;
2624 ncolumns = tupdesc->natts;
2627 * We arrange to look up the needed I/O info just once per series of
2628 * calls, assuming the record type doesn't change underneath us.
2630 my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
2631 if (my_extra == NULL ||
2632 my_extra->ncolumns != ncolumns)
2634 fcinfo->flinfo->fn_extra =
2635 MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
2636 sizeof(RecordIOData) - sizeof(ColumnIOData)
2637 + ncolumns * sizeof(ColumnIOData));
2638 my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
2639 my_extra->record_type = InvalidOid;
2640 my_extra->record_typmod = 0;
2643 if (my_extra->record_type != tupType ||
2644 my_extra->record_typmod != tupTypmod)
2647 sizeof(RecordIOData) - sizeof(ColumnIOData)
2648 + ncolumns * sizeof(ColumnIOData));
2649 my_extra->record_type = tupType;
2650 my_extra->record_typmod = tupTypmod;
2651 my_extra->ncolumns = ncolumns;
2654 state = palloc0(sizeof(PopulateRecordsetState));
2656 /* make these in a sufficiently long-lived memory context */
2657 old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
2658 state->ret_tdesc = CreateTupleDescCopy(tupdesc);;
2659 BlessTupleDesc(state->ret_tdesc);
2660 state->tuple_store = tuplestore_begin_heap(rsi->allowedModes &
2661 SFRM_Materialize_Random,
2663 MemoryContextSwitchTo(old_cxt);
2665 state->my_extra = my_extra;
2667 state->use_json_as_text = use_json_as_text;
2668 state->fn_mcxt = fcinfo->flinfo->fn_mcxt;
2670 if (jtype == JSONOID)
2672 text *json = PG_GETARG_TEXT_P(have_record_arg ? 1 : 0);
2673 JsonLexContext *lex;
2676 sem = palloc0(sizeof(JsonSemAction));
2678 lex = makeJsonLexContext(json, true);
2680 sem->semstate = (void *) state;
2681 sem->array_start = populate_recordset_array_start;
2682 sem->array_element_start = populate_recordset_array_element_start;
2683 sem->scalar = populate_recordset_scalar;
2684 sem->object_field_start = populate_recordset_object_field_start;
2685 sem->object_field_end = populate_recordset_object_field_end;
2686 sem->object_start = populate_recordset_object_start;
2687 sem->object_end = populate_recordset_object_end;
2691 pg_parse_json(lex, sem);
2699 bool skipNested = false;
2702 Assert(jtype == JSONBOID);
2703 jb = PG_GETARG_JSONB(have_record_arg ? 1 : 0);
2705 if (JB_ROOT_IS_SCALAR(jb) || !JB_ROOT_IS_ARRAY(jb))
2707 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2708 errmsg("cannot call jsonb_populate_recordset on non-array")));
2710 it = JsonbIteratorInit(&jb->root);
2712 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
2718 Jsonb *element = JsonbValueToJsonb(&v);
2720 if (!JB_ROOT_IS_OBJECT(element))
2722 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2723 errmsg("jsonb_populate_recordset argument must be an array of objects")));
2724 make_row_from_rec_and_jsonb(element, state);
2729 rsi->setResult = state->tuple_store;
2730 rsi->setDesc = state->ret_tdesc;
2737 populate_recordset_object_start(void *state)
2739 PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
2740 int lex_level = _state->lex->lex_level;
2743 /* Reject object at top level: we must have an array at level 0 */
2746 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2747 errmsg("cannot call json_populate_recordset on an object")));
2749 /* Nested objects, if allowed, require no special processing */
2752 if (!_state->use_json_as_text)
2754 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2755 errmsg("cannot call json_populate_recordset with nested objects")));
2759 /* Object at level 1: set up a new hash table for this object */
2760 memset(&ctl, 0, sizeof(ctl));
2761 ctl.keysize = NAMEDATALEN;
2762 ctl.entrysize = sizeof(JsonHashEntry);
2763 ctl.hcxt = CurrentMemoryContext;
2764 _state->json_hash = hash_create("json object hashtable",
2767 HASH_ELEM | HASH_CONTEXT);
2771 populate_recordset_object_end(void *state)
2773 PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
2774 HTAB *json_hash = _state->json_hash;
2777 char fname[NAMEDATALEN];
2779 RecordIOData *my_extra = _state->my_extra;
2780 int ncolumns = my_extra->ncolumns;
2781 TupleDesc tupdesc = _state->ret_tdesc;
2782 JsonHashEntry *hashentry;
2783 HeapTupleHeader rec = _state->rec;
2786 /* Nested objects require no special processing */
2787 if (_state->lex->lex_level > 1)
2790 /* Otherwise, construct and return a tuple based on this level-1 object */
2791 values = (Datum *) palloc(ncolumns * sizeof(Datum));
2792 nulls = (bool *) palloc(ncolumns * sizeof(bool));
2796 HeapTupleData tuple;
2798 /* Build a temporary HeapTuple control structure */
2799 tuple.t_len = HeapTupleHeaderGetDatumLength(_state->rec);
2800 ItemPointerSetInvalid(&(tuple.t_self));
2801 tuple.t_tableOid = InvalidOid;
2802 tuple.t_data = _state->rec;
2804 /* Break down the tuple into fields */
2805 heap_deform_tuple(&tuple, tupdesc, values, nulls);
2809 for (i = 0; i < ncolumns; ++i)
2811 values[i] = (Datum) 0;
2816 for (i = 0; i < ncolumns; ++i)
2818 ColumnIOData *column_info = &my_extra->columns[i];
2819 Oid column_type = tupdesc->attrs[i]->atttypid;
2822 /* Ignore dropped columns in datatype */
2823 if (tupdesc->attrs[i]->attisdropped)
2829 memset(fname, 0, NAMEDATALEN);
2830 strncpy(fname, NameStr(tupdesc->attrs[i]->attname), NAMEDATALEN);
2831 hashentry = hash_search(json_hash, fname, HASH_FIND, NULL);
2834 * we can't just skip here if the key wasn't found since we might have
2835 * a domain to deal with. If we were passed in a non-null record
2836 * datum, we assume that the existing values are valid (if they're
2837 * not, then it's not our fault), but if we were passed in a null,
2838 * then every field which we don't populate needs to be run through
2839 * the input function just in case it's a domain type.
2841 if (hashentry == NULL && rec)
2845 * Prepare to convert the column value from text
2847 if (column_info->column_type != column_type)
2849 getTypeInputInfo(column_type,
2850 &column_info->typiofunc,
2851 &column_info->typioparam);
2852 fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
2854 column_info->column_type = column_type;
2856 if (hashentry == NULL || hashentry->isnull)
2859 * need InputFunctionCall to happen even for nulls, so that domain
2862 values[i] = InputFunctionCall(&column_info->proc, NULL,
2863 column_info->typioparam,
2864 tupdesc->attrs[i]->atttypmod);
2869 value = hashentry->val;
2871 values[i] = InputFunctionCall(&column_info->proc, value,
2872 column_info->typioparam,
2873 tupdesc->attrs[i]->atttypmod);
2878 rettuple = heap_form_tuple(tupdesc, values, nulls);
2880 tuplestore_puttuple(_state->tuple_store, rettuple);
2882 /* Done with hash for this object */
2883 hash_destroy(json_hash);
2884 _state->json_hash = NULL;
2888 populate_recordset_array_element_start(void *state, bool isnull)
2890 PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
2892 if (_state->lex->lex_level == 1 &&
2893 _state->lex->token_type != JSON_TOKEN_OBJECT_START)
2895 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2896 errmsg("must call json_populate_recordset on an array of objects")));
2900 populate_recordset_array_start(void *state)
2902 PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
2904 if (_state->lex->lex_level != 0 && !_state->use_json_as_text)
2906 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2907 errmsg("cannot call json_populate_recordset with nested arrays")));
2911 populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
2913 PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
2915 if (_state->lex->lex_level == 0)
2917 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2918 errmsg("cannot call json_populate_recordset on a scalar")));
2920 if (_state->lex->lex_level == 2)
2921 _state->saved_scalar = token;
2925 populate_recordset_object_field_start(void *state, char *fname, bool isnull)
2927 PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
2929 if (_state->lex->lex_level > 2)
2932 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
2933 _state->lex->token_type == JSON_TOKEN_OBJECT_START)
2935 if (!_state->use_json_as_text)
2937 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2938 errmsg("cannot call json_populate_recordset on a nested object")));
2939 _state->save_json_start = _state->lex->token_start;
2943 _state->save_json_start = NULL;
2948 populate_recordset_object_field_end(void *state, char *fname, bool isnull)
2950 PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
2951 JsonHashEntry *hashentry;
2953 char name[NAMEDATALEN];
2956 * ignore field names >= NAMEDATALEN - they can't match a record field
2957 * ignore nested fields.
2959 if (_state->lex->lex_level > 2 || strlen(fname) >= NAMEDATALEN)
2962 memset(name, 0, NAMEDATALEN);
2963 strncpy(name, fname, NAMEDATALEN);
2965 hashentry = hash_search(_state->json_hash, name, HASH_ENTER, &found);
2968 * found being true indicates a duplicate. We don't do anything about
2969 * that, a later field with the same name overrides the earlier field.
2972 hashentry->isnull = isnull;
2973 if (_state->save_json_start != NULL)
2975 int len = _state->lex->prev_token_terminator - _state->save_json_start;
2976 char *val = palloc((len + 1) * sizeof(char));
2978 memcpy(val, _state->save_json_start, len);
2980 hashentry->val = val;
2984 /* must have had a scalar instead */
2985 hashentry->val = _state->saved_scalar;
2990 * findJsonbValueFromContainer() wrapper that sets up JsonbValue key string.
2993 findJsonbValueFromContainerLen(JsonbContainer *container, uint32 flags,
2994 char *key, uint32 keylen)
2999 k.val.string.val = key;
3000 k.val.string.len = keylen;
3002 return findJsonbValueFromContainer(container, flags, &k);