PostgreSQL Source Code git master
jsonfuncs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * jsonfuncs.c
4 * Functions to process JSON data types.
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/backend/utils/adt/jsonfuncs.c
11 *
12 *-------------------------------------------------------------------------
13 */
14
15#include "postgres.h"
16
17#include <limits.h>
18
19#include "access/htup_details.h"
20#include "catalog/pg_type.h"
21#include "common/int.h"
22#include "common/jsonapi.h"
23#include "common/string.h"
24#include "fmgr.h"
25#include "funcapi.h"
26#include "lib/stringinfo.h"
27#include "mb/pg_wchar.h"
28#include "miscadmin.h"
29#include "nodes/miscnodes.h"
30#include "parser/parse_coerce.h"
31#include "utils/array.h"
32#include "utils/builtins.h"
33#include "utils/fmgroids.h"
34#include "utils/hsearch.h"
35#include "utils/json.h"
36#include "utils/jsonb.h"
37#include "utils/jsonfuncs.h"
38#include "utils/lsyscache.h"
39#include "utils/memutils.h"
40#include "utils/syscache.h"
41#include "utils/typcache.h"
42
43/* Operations available for setPath */
44#define JB_PATH_CREATE 0x0001
45#define JB_PATH_DELETE 0x0002
46#define JB_PATH_REPLACE 0x0004
47#define JB_PATH_INSERT_BEFORE 0x0008
48#define JB_PATH_INSERT_AFTER 0x0010
49#define JB_PATH_CREATE_OR_INSERT \
50 (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE)
51#define JB_PATH_FILL_GAPS 0x0020
52#define JB_PATH_CONSISTENT_POSITION 0x0040
53
54/* state for json_object_keys */
55typedef struct OkeysState
56{
58 char **result;
63
64/* state for iterate_json_values function */
66{
68 JsonIterateStringValuesAction action; /* an action that will be applied
69 * to each json value */
70 void *action_state; /* any necessary context for iteration */
71 uint32 flags; /* what kind of elements from a json we want
72 * to iterate */
74
75/* state for transform_json_string_values function */
77{
79 StringInfo strval; /* resulting json */
80 JsonTransformStringValuesAction action; /* an action that will be applied
81 * to each json value */
82 void *action_state; /* any necessary context for transformation */
84
85/* state for json_get* functions */
86typedef struct GetState
87{
90 const char *result_start;
93 int npath; /* length of each path-related array */
94 char **path_names; /* field name(s) being sought */
95 int *path_indexes; /* array index(es) being sought */
96 bool *pathok; /* is path matched to current depth? */
97 int *array_cur_index; /* current element index at each path
98 * level */
100
101/* state for json_array_length */
102typedef struct AlenState
103{
105 int count;
107
108/* state for json_each */
109typedef struct EachState
110{
115 const char *result_start;
120
121/* state for json_array_elements */
122typedef struct ElementsState
123{
125 const char *function_name;
129 const char *result_start;
134
135/* state for get_json_object_as_hash */
136typedef struct JHashState
137{
139 const char *function_name;
142 const char *save_json_start;
145
146/* hashtable element */
147typedef struct JsonHashEntry
148{
149 char fname[NAMEDATALEN]; /* hash key (MUST BE FIRST) */
150 char *val;
153
154/* structure to cache type I/O metadata needed for populate_scalar() */
155typedef struct ScalarIOData
156{
160
161/* these two structures are used recursively */
164
165/* structure to cache metadata needed for populate_array() */
166typedef struct ArrayIOData
167{
168 ColumnIOData *element_info; /* metadata cache */
169 Oid element_type; /* array element type id */
170 int32 element_typmod; /* array element type modifier */
172
173/* structure to cache metadata needed for populate_composite() */
174typedef struct CompositeIOData
175{
176 /*
177 * We use pointer to a RecordIOData here because variable-length struct
178 * RecordIOData can't be used directly in ColumnIOData.io union
179 */
180 RecordIOData *record_io; /* metadata cache for populate_record() */
181 TupleDesc tupdesc; /* cached tuple descriptor */
182 /* these fields differ from target type only if domain over composite: */
183 Oid base_typid; /* base type id */
184 int32 base_typmod; /* base type modifier */
185 /* this field is used only if target type is domain over composite: */
186 void *domain_info; /* opaque cache for domain checks */
188
189/* structure to cache metadata needed for populate_domain() */
190typedef struct DomainIOData
191{
192 ColumnIOData *base_io; /* metadata cache */
193 Oid base_typid; /* base type id */
194 int32 base_typmod; /* base type modifier */
195 void *domain_info; /* opaque cache for domain checks */
197
198/* enumeration type categories */
199typedef enum TypeCat
200{
207
208/* these two are stolen from hstore / record_out, used in populate_record* */
209
210/* structure to cache record metadata needed for populate_record_field() */
211struct ColumnIOData
212{
213 Oid typid; /* column type id */
214 int32 typmod; /* column type modifier */
215 TypeCat typcat; /* column type category */
216 ScalarIOData scalar_io; /* metadata cache for direct conversion
217 * through input function */
218 union
219 {
223 } io; /* metadata cache for various column type
224 * categories */
225};
226
227/* structure to cache record metadata needed for populate_record() */
228struct RecordIOData
229{
232 int ncolumns;
234};
235
236/* per-query cache for populate_record_worker and populate_recordset_worker */
238{
239 Oid argtype; /* declared type of the record argument */
240 ColumnIOData c; /* metadata cache for populate_composite() */
241 MemoryContext fn_mcxt; /* where this is stored */
243
244/* per-call state for populate_recordset */
246{
248 const char *function_name;
251 const char *save_json_start;
257
258/* common data for populate_array_json() and populate_array_dim_jsonb() */
260{
261 ArrayBuildState *astate; /* array build state */
262 ArrayIOData *aio; /* metadata cache */
263 MemoryContext acxt; /* array build memory context */
264 MemoryContext mcxt; /* cache memory context */
265 const char *colname; /* for diagnostics only */
266 int *dims; /* dimensions */
267 int *sizes; /* current dimension counters */
268 int ndims; /* number of dimensions */
269 Node *escontext; /* For soft-error handling */
271
272/* state for populate_array_json() */
273typedef struct PopulateArrayState
274{
275 JsonLexContext *lex; /* json lexer */
276 PopulateArrayContext *ctx; /* context */
277 const char *element_start; /* start of the current array element */
278 char *element_scalar; /* current array element token if it is a
279 * scalar */
280 JsonTokenType element_type; /* current array element type */
282
283/* state for json_strip_nulls */
284typedef struct StripnullState
285{
291
292/* structure for generalized json/jsonb value passing */
293typedef struct JsValue
294{
295 bool is_json; /* json/jsonb */
296 union
297 {
298 struct
299 {
300 const char *str; /* json string */
301 int len; /* json string length or -1 if null-terminated */
302 JsonTokenType type; /* json type */
303 } json; /* json value */
304
305 JsonbValue *jsonb; /* jsonb value */
308
309typedef struct JsObject
310{
311 bool is_json; /* json/jsonb */
312 union
313 {
318
319/* useful macros for testing JsValue properties */
320#define JsValueIsNull(jsv) \
321 ((jsv)->is_json ? \
322 (!(jsv)->val.json.str || (jsv)->val.json.type == JSON_TOKEN_NULL) : \
323 (!(jsv)->val.jsonb || (jsv)->val.jsonb->type == jbvNull))
324
325#define JsValueIsString(jsv) \
326 ((jsv)->is_json ? (jsv)->val.json.type == JSON_TOKEN_STRING \
327 : ((jsv)->val.jsonb && (jsv)->val.jsonb->type == jbvString))
328
329#define JsObjectIsEmpty(jso) \
330 ((jso)->is_json \
331 ? hash_get_num_entries((jso)->val.json_hash) == 0 \
332 : ((jso)->val.jsonb_cont == NULL || \
333 JsonContainerSize((jso)->val.jsonb_cont) == 0))
334
335#define JsObjectFree(jso) \
336 do { \
337 if ((jso)->is_json) \
338 hash_destroy((jso)->val.json_hash); \
339 } while (0)
340
341static int report_json_context(JsonLexContext *lex);
342
343/* semantic action functions for json_object_keys */
344static JsonParseErrorType okeys_object_field_start(void *state, char *fname, bool isnull);
346static JsonParseErrorType okeys_scalar(void *state, char *token, JsonTokenType tokentype);
347
348/* semantic action functions for json_get* functions */
351static JsonParseErrorType get_object_field_start(void *state, char *fname, bool isnull);
352static JsonParseErrorType get_object_field_end(void *state, char *fname, bool isnull);
355static JsonParseErrorType get_array_element_start(void *state, bool isnull);
356static JsonParseErrorType get_array_element_end(void *state, bool isnull);
357static JsonParseErrorType get_scalar(void *state, char *token, JsonTokenType tokentype);
358
359/* common worker function for json getter functions */
360static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text);
361static text *get_worker(text *json, char **tpath, int *ipath, int npath,
362 bool normalize_results);
363static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text);
365
366/* semantic action functions for json_array_length */
368static JsonParseErrorType alen_scalar(void *state, char *token, JsonTokenType tokentype);
369static JsonParseErrorType alen_array_element_start(void *state, bool isnull);
370
371/* common workers for json{b}_each* functions */
372static Datum each_worker(FunctionCallInfo fcinfo, bool as_text);
373static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
374 bool as_text);
375
376/* semantic action functions for json_each */
377static JsonParseErrorType each_object_field_start(void *state, char *fname, bool isnull);
378static JsonParseErrorType each_object_field_end(void *state, char *fname, bool isnull);
380static JsonParseErrorType each_scalar(void *state, char *token, JsonTokenType tokentype);
381
382/* common workers for json{b}_array_elements_* functions */
383static Datum elements_worker(FunctionCallInfo fcinfo, const char *funcname,
384 bool as_text);
385static Datum elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
386 bool as_text);
387
388/* semantic action functions for json_array_elements */
390static JsonParseErrorType elements_array_element_start(void *state, bool isnull);
391static JsonParseErrorType elements_array_element_end(void *state, bool isnull);
392static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype);
393
394/* turn a json object into a hash table */
395static HTAB *get_json_object_as_hash(const char *json, int len, const char *funcname,
396 Node *escontext);
397
398/* semantic actions for populate_array_json */
401static JsonParseErrorType populate_array_element_start(void *_state, bool isnull);
402static JsonParseErrorType populate_array_element_end(void *_state, bool isnull);
403static JsonParseErrorType populate_array_scalar(void *_state, char *token, JsonTokenType tokentype);
404
405/* semantic action functions for get_json_object_as_hash */
406static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull);
407static JsonParseErrorType hash_object_field_end(void *state, char *fname, bool isnull);
409static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype);
410
411/* semantic action functions for populate_recordset */
412static JsonParseErrorType populate_recordset_object_field_start(void *state, char *fname, bool isnull);
413static JsonParseErrorType populate_recordset_object_field_end(void *state, char *fname, bool isnull);
419
420/* semantic action functions for json_strip_nulls */
425static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull);
426static JsonParseErrorType sn_array_element_start(void *state, bool isnull);
427static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype);
428
429/* worker functions for populate_record, to_record, populate_recordset and to_recordset */
431 bool is_json, bool have_record_arg);
432static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
433 bool is_json, bool have_record_arg,
434 Node *escontext);
435
436/* helper functions for populate_record[set] */
437static HeapTupleHeader populate_record(TupleDesc tupdesc, RecordIOData **record_p,
438 HeapTupleHeader defaultval, MemoryContext mcxt,
439 JsObject *obj, Node *escontext);
441 const char *funcname,
442 PopulateRecordCache *cache);
444 const char *funcname,
445 PopulateRecordCache *cache);
446static bool JsValueToJsObject(JsValue *jsv, JsObject *jso, Node *escontext);
448 const char *colname, MemoryContext mcxt,
449 HeapTupleHeader defaultval, JsValue *jsv, bool *isnull,
450 Node *escontext);
451static Datum populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv,
452 bool *isnull, Node *escontext, bool omit_quotes);
453static void prepare_column_cache(ColumnIOData *column, Oid typid, int32 typmod,
454 MemoryContext mcxt, bool need_scalar);
455static Datum populate_record_field(ColumnIOData *col, Oid typid, int32 typmod,
456 const char *colname, MemoryContext mcxt, Datum defaultval,
457 JsValue *jsv, bool *isnull, Node *escontext,
458 bool omit_scalar_quotes);
459static RecordIOData *allocate_record_info(MemoryContext mcxt, int ncolumns);
460static bool JsObjectGetField(JsObject *obj, char *field, JsValue *jsv);
462static bool populate_array_json(PopulateArrayContext *ctx, const char *json, int len);
464 int ndim);
466static bool populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims);
467static bool populate_array_check_dimension(PopulateArrayContext *ctx, int ndim);
468static bool populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv);
469static Datum populate_array(ArrayIOData *aio, const char *colname,
470 MemoryContext mcxt, JsValue *jsv,
471 bool *isnull,
472 Node *escontext);
473static Datum populate_domain(DomainIOData *io, Oid typid, const char *colname,
474 MemoryContext mcxt, JsValue *jsv, bool *isnull,
475 Node *escontext, bool omit_quotes);
476
477/* functions supporting jsonb_delete, jsonb_set and jsonb_concat */
478static void IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
480static void setPath(JsonbIterator **it, const Datum *path_elems,
481 const bool *path_nulls, int path_len,
482 JsonbInState *st, int level, JsonbValue *newval,
483 int op_type);
484static void setPathObject(JsonbIterator **it, const Datum *path_elems,
485 const bool *path_nulls, int path_len, JsonbInState *st,
486 int level,
487 JsonbValue *newval, uint32 npairs, int op_type);
488static void setPathArray(JsonbIterator **it, const Datum *path_elems,
489 const bool *path_nulls, int path_len, JsonbInState *st,
490 int level,
491 JsonbValue *newval, uint32 nelems, int op_type);
492
493/* function supporting iterate_json_values */
495static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull);
496
497/* functions supporting transform_json_string_values */
502static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull);
505
506
507/*
508 * pg_parse_json_or_errsave
509 *
510 * This function is like pg_parse_json, except that it does not return a
511 * JsonParseErrorType. Instead, in case of any failure, this function will
512 * save error data into *escontext if that's an ErrorSaveContext, otherwise
513 * ereport(ERROR).
514 *
515 * Returns a boolean indicating success or failure (failure will only be
516 * returned when escontext is an ErrorSaveContext).
517 */
518bool
520 Node *escontext)
521{
522 JsonParseErrorType result;
523
524 result = pg_parse_json(lex, sem);
525 if (result != JSON_SUCCESS)
526 {
527 json_errsave_error(result, lex, escontext);
528 return false;
529 }
530 return true;
531}
532
533/*
534 * makeJsonLexContext
535 *
536 * This is like makeJsonLexContextCstringLen, but it accepts a text value
537 * directly.
538 */
540makeJsonLexContext(JsonLexContext *lex, text *json, bool need_escapes)
541{
542 /*
543 * Most callers pass a detoasted datum, but it's not clear that they all
544 * do. pg_detoast_datum_packed() is cheap insurance.
545 */
546 json = pg_detoast_datum_packed(json);
547
549 VARDATA_ANY(json),
550 VARSIZE_ANY_EXHDR(json),
552 need_escapes);
553}
554
555/*
556 * SQL function json_object_keys
557 *
558 * Returns the set of keys for the object argument.
559 *
560 * This SRF operates in value-per-call mode. It processes the
561 * object during the first call, and the keys are simply stashed
562 * in an array, whose size is expanded as necessary. This is probably
563 * safe enough for a list of keys of a single object, since they are
564 * limited in size to NAMEDATALEN and the number of keys is unlikely to
565 * be so huge that it has major memory implications.
566 */
567Datum
569{
570 FuncCallContext *funcctx;
572
573 if (SRF_IS_FIRSTCALL())
574 {
575 MemoryContext oldcontext;
576 Jsonb *jb = PG_GETARG_JSONB_P(0);
577 bool skipNested = false;
578 JsonbIterator *it;
579 JsonbValue v;
581
582 if (JB_ROOT_IS_SCALAR(jb))
584 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
585 errmsg("cannot call %s on a scalar",
586 "jsonb_object_keys")));
587 else if (JB_ROOT_IS_ARRAY(jb))
589 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
590 errmsg("cannot call %s on an array",
591 "jsonb_object_keys")));
592
593 funcctx = SRF_FIRSTCALL_INIT();
594 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
595
597
598 state->result_size = JB_ROOT_COUNT(jb);
599 state->result_count = 0;
600 state->sent_count = 0;
601 state->result = palloc_array(char *, state->result_size);
602
603 it = JsonbIteratorInit(&jb->root);
604
605 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
606 {
607 skipNested = true;
608
609 if (r == WJB_KEY)
610 {
611 char *cstr;
612
613 cstr = palloc(v.val.string.len + 1 * sizeof(char));
614 memcpy(cstr, v.val.string.val, v.val.string.len);
615 cstr[v.val.string.len] = '\0';
616 state->result[state->result_count++] = cstr;
617 }
618 }
619
620 MemoryContextSwitchTo(oldcontext);
621 funcctx->user_fctx = state;
622 }
623
624 funcctx = SRF_PERCALL_SETUP();
625 state = (OkeysState *) funcctx->user_fctx;
626
627 if (state->sent_count < state->result_count)
628 {
629 char *nxt = state->result[state->sent_count++];
630
632 }
633
634 SRF_RETURN_DONE(funcctx);
635}
636
637/*
638 * Report a JSON error.
639 */
640void
642 Node *escontext)
643{
647 errsave(escontext,
648 (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
649 errmsg("unsupported Unicode escape sequence"),
651 report_json_context(lex)));
652 else if (error == JSON_SEM_ACTION_FAILED)
653 {
654 /* semantic action function had better have reported something */
655 if (!SOFT_ERROR_OCCURRED(escontext))
656 elog(ERROR, "JSON semantic action function did not provide error information");
657 }
658 else
659 errsave(escontext,
660 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
661 errmsg("invalid input syntax for type %s", "json"),
663 report_json_context(lex)));
664}
665
666/*
667 * Report a CONTEXT line for bogus JSON input.
668 *
669 * lex->token_terminator must be set to identify the spot where we detected
670 * the error. Note that lex->token_start might be NULL, in case we recognized
671 * error at EOF.
672 *
673 * The return value isn't meaningful, but we make it non-void so that this
674 * can be invoked inside ereport().
675 */
676static int
678{
679 const char *context_start;
680 const char *context_end;
681 const char *line_start;
682 char *ctxt;
683 int ctxtlen;
684 const char *prefix;
685 const char *suffix;
686
687 /* Choose boundaries for the part of the input we will display */
688 line_start = lex->line_start;
689 context_start = line_start;
690 context_end = lex->token_terminator;
691 Assert(context_end >= context_start);
692
693 /* Advance until we are close enough to context_end */
694 while (context_end - context_start >= 50)
695 {
696 /* Advance to next multibyte character */
697 if (IS_HIGHBIT_SET(*context_start))
698 context_start += pg_mblen(context_start);
699 else
700 context_start++;
701 }
702
703 /*
704 * We add "..." to indicate that the excerpt doesn't start at the
705 * beginning of the line ... but if we're within 3 characters of the
706 * beginning of the line, we might as well just show the whole line.
707 */
708 if (context_start - line_start <= 3)
709 context_start = line_start;
710
711 /* Get a null-terminated copy of the data to present */
712 ctxtlen = context_end - context_start;
713 ctxt = palloc(ctxtlen + 1);
714 memcpy(ctxt, context_start, ctxtlen);
715 ctxt[ctxtlen] = '\0';
716
717 /*
718 * Show the context, prefixing "..." if not starting at start of line, and
719 * suffixing "..." if not ending at end of line.
720 */
721 prefix = (context_start > line_start) ? "..." : "";
722 suffix = (lex->token_type != JSON_TOKEN_END &&
723 context_end - lex->input < lex->input_length &&
724 *context_end != '\n' && *context_end != '\r') ? "..." : "";
725
726 return errcontext("JSON data, line %d: %s%s%s",
727 lex->line_number, prefix, ctxt, suffix);
728}
729
730
731Datum
733{
734 FuncCallContext *funcctx;
736
737 if (SRF_IS_FIRSTCALL())
738 {
739 text *json = PG_GETARG_TEXT_PP(0);
740 JsonLexContext lex;
742 MemoryContext oldcontext;
743
744 funcctx = SRF_FIRSTCALL_INIT();
745 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
746
749
750 state->lex = makeJsonLexContext(&lex, json, true);
751 state->result_size = 256;
752 state->result_count = 0;
753 state->sent_count = 0;
754 state->result = palloc_array(char *, 256);
755
756 sem->semstate = state;
760 /* remainder are all NULL, courtesy of palloc0 above */
761
763 /* keys are now in state->result */
764
765 freeJsonLexContext(&lex);
766 pfree(sem);
767
768 MemoryContextSwitchTo(oldcontext);
769 funcctx->user_fctx = state;
770 }
771
772 funcctx = SRF_PERCALL_SETUP();
773 state = (OkeysState *) funcctx->user_fctx;
774
775 if (state->sent_count < state->result_count)
776 {
777 char *nxt = state->result[state->sent_count++];
778
780 }
781
782 SRF_RETURN_DONE(funcctx);
783}
784
786okeys_object_field_start(void *state, char *fname, bool isnull)
787{
788 OkeysState *_state = (OkeysState *) state;
789
790 /* only collecting keys for the top level object */
791 if (_state->lex->lex_level != 1)
792 return JSON_SUCCESS;
793
794 /* enlarge result array if necessary */
795 if (_state->result_count >= _state->result_size)
796 {
797 _state->result_size *= 2;
798 _state->result = (char **)
799 repalloc(_state->result, sizeof(char *) * _state->result_size);
800 }
801
802 /* save a copy of the field name */
803 _state->result[_state->result_count++] = pstrdup(fname);
804
805 return JSON_SUCCESS;
806}
807
810{
811 OkeysState *_state = (OkeysState *) state;
812
813 /* top level must be a json object */
814 if (_state->lex->lex_level == 0)
816 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
817 errmsg("cannot call %s on an array",
818 "json_object_keys")));
819
820 return JSON_SUCCESS;
821}
822
824okeys_scalar(void *state, char *token, JsonTokenType tokentype)
825{
826 OkeysState *_state = (OkeysState *) state;
827
828 /* top level must be a json object */
829 if (_state->lex->lex_level == 0)
831 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
832 errmsg("cannot call %s on a scalar",
833 "json_object_keys")));
834
835 return JSON_SUCCESS;
836}
837
838/*
839 * json and jsonb getter functions
840 * these implement the -> ->> #> and #>> operators
841 * and the json{b?}_extract_path*(json, text, ...) functions
842 */
843
844
845Datum
847{
848 text *json = PG_GETARG_TEXT_PP(0);
849 text *fname = PG_GETARG_TEXT_PP(1);
850 char *fnamestr = text_to_cstring(fname);
851 text *result;
852
853 result = get_worker(json, &fnamestr, NULL, 1, false);
854
855 if (result != NULL)
856 PG_RETURN_TEXT_P(result);
857 else
859}
860
861Datum
863{
864 Jsonb *jb = PG_GETARG_JSONB_P(0);
866 JsonbValue *v;
867 JsonbValue vbuf;
868
869 if (!JB_ROOT_IS_OBJECT(jb))
871
875 &vbuf);
876
877 if (v != NULL)
879
881}
882
883Datum
885{
886 text *json = PG_GETARG_TEXT_PP(0);
887 text *fname = PG_GETARG_TEXT_PP(1);
888 char *fnamestr = text_to_cstring(fname);
889 text *result;
890
891 result = get_worker(json, &fnamestr, NULL, 1, true);
892
893 if (result != NULL)
894 PG_RETURN_TEXT_P(result);
895 else
897}
898
899Datum
901{
902 Jsonb *jb = PG_GETARG_JSONB_P(0);
904 JsonbValue *v;
905 JsonbValue vbuf;
906
907 if (!JB_ROOT_IS_OBJECT(jb))
909
913 &vbuf);
914
915 if (v != NULL && v->type != jbvNull)
917
919}
920
921Datum
923{
924 text *json = PG_GETARG_TEXT_PP(0);
925 int element = PG_GETARG_INT32(1);
926 text *result;
927
928 result = get_worker(json, NULL, &element, 1, false);
929
930 if (result != NULL)
931 PG_RETURN_TEXT_P(result);
932 else
934}
935
936Datum
938{
939 Jsonb *jb = PG_GETARG_JSONB_P(0);
940 int element = PG_GETARG_INT32(1);
941 JsonbValue *v;
942
943 if (!JB_ROOT_IS_ARRAY(jb))
945
946 /* Handle negative subscript */
947 if (element < 0)
948 {
949 uint32 nelements = JB_ROOT_COUNT(jb);
950
951 if (pg_abs_s32(element) > nelements)
953 else
954 element += nelements;
955 }
956
958 if (v != NULL)
960
962}
963
964Datum
966{
967 text *json = PG_GETARG_TEXT_PP(0);
968 int element = PG_GETARG_INT32(1);
969 text *result;
970
971 result = get_worker(json, NULL, &element, 1, true);
972
973 if (result != NULL)
974 PG_RETURN_TEXT_P(result);
975 else
977}
978
979Datum
981{
982 Jsonb *jb = PG_GETARG_JSONB_P(0);
983 int element = PG_GETARG_INT32(1);
984 JsonbValue *v;
985
986 if (!JB_ROOT_IS_ARRAY(jb))
988
989 /* Handle negative subscript */
990 if (element < 0)
991 {
992 uint32 nelements = JB_ROOT_COUNT(jb);
993
994 if (pg_abs_s32(element) > nelements)
996 else
997 element += nelements;
998 }
999
1001
1002 if (v != NULL && v->type != jbvNull)
1004
1006}
1007
1008Datum
1010{
1011 return get_path_all(fcinfo, false);
1012}
1013
1014Datum
1016{
1017 return get_path_all(fcinfo, true);
1018}
1019
1020/*
1021 * common routine for extract_path functions
1022 */
1023static Datum
1024get_path_all(FunctionCallInfo fcinfo, bool as_text)
1025{
1026 text *json = PG_GETARG_TEXT_PP(0);
1028 text *result;
1029 Datum *pathtext;
1030 bool *pathnulls;
1031 int npath;
1032 char **tpath;
1033 int *ipath;
1034 int i;
1035
1036 /*
1037 * If the array contains any null elements, return NULL, on the grounds
1038 * that you'd have gotten NULL if any RHS value were NULL in a nested
1039 * series of applications of the -> operator. (Note: because we also
1040 * return NULL for error cases such as no-such-field, this is true
1041 * regardless of the contents of the rest of the array.)
1042 */
1043 if (array_contains_nulls(path))
1045
1046 deconstruct_array_builtin(path, TEXTOID, &pathtext, &pathnulls, &npath);
1047
1048 tpath = palloc_array(char *, npath);
1049 ipath = palloc_array(int, npath);
1050
1051 for (i = 0; i < npath; i++)
1052 {
1053 Assert(!pathnulls[i]);
1054 tpath[i] = TextDatumGetCString(pathtext[i]);
1055
1056 /*
1057 * we have no idea at this stage what structure the document is so
1058 * just convert anything in the path that we can to an integer and set
1059 * all the other integers to INT_MIN which will never match.
1060 */
1061 if (*tpath[i] != '\0')
1062 {
1063 int ind;
1064 char *endptr;
1065
1066 errno = 0;
1067 ind = strtoint(tpath[i], &endptr, 10);
1068 if (endptr == tpath[i] || *endptr != '\0' || errno != 0)
1069 ipath[i] = INT_MIN;
1070 else
1071 ipath[i] = ind;
1072 }
1073 else
1074 ipath[i] = INT_MIN;
1075 }
1076
1077 result = get_worker(json, tpath, ipath, npath, as_text);
1078
1079 if (result != NULL)
1080 PG_RETURN_TEXT_P(result);
1081 else
1083}
1084
1085/*
1086 * get_worker
1087 *
1088 * common worker for all the json getter functions
1089 *
1090 * json: JSON object (in text form)
1091 * tpath[]: field name(s) to extract
1092 * ipath[]: array index(es) (zero-based) to extract, accepts negatives
1093 * npath: length of tpath[] and/or ipath[]
1094 * normalize_results: true to de-escape string and null scalars
1095 *
1096 * tpath can be NULL, or any one tpath[] entry can be NULL, if an object
1097 * field is not to be matched at that nesting level. Similarly, ipath can
1098 * be NULL, or any one ipath[] entry can be INT_MIN if an array element is
1099 * not to be matched at that nesting level (a json datum should never be
1100 * large enough to have -INT_MIN elements due to MaxAllocSize restriction).
1101 */
1102static text *
1104 char **tpath,
1105 int *ipath,
1106 int npath,
1107 bool normalize_results)
1108{
1111
1112 Assert(npath >= 0);
1113
1114 state->lex = makeJsonLexContext(NULL, json, true);
1115
1116 /* is it "_as_text" variant? */
1117 state->normalize_results = normalize_results;
1118 state->npath = npath;
1119 state->path_names = tpath;
1120 state->path_indexes = ipath;
1121 state->pathok = palloc0_array(bool, npath);
1122 state->array_cur_index = palloc_array(int, npath);
1123
1124 if (npath > 0)
1125 state->pathok[0] = true;
1126
1127 sem->semstate = state;
1128
1129 /*
1130 * Not all variants need all the semantic routines. Only set the ones that
1131 * are actually needed for maximum efficiency.
1132 */
1134 if (npath == 0)
1135 {
1140 }
1141 if (tpath != NULL)
1142 {
1145 }
1146 if (ipath != NULL)
1147 {
1151 }
1152
1155
1156 return state->tresult;
1157}
1158
1159static JsonParseErrorType
1161{
1162 GetState *_state = (GetState *) state;
1163 int lex_level = _state->lex->lex_level;
1164
1165 if (lex_level == 0 && _state->npath == 0)
1166 {
1167 /*
1168 * Special case: we should match the entire object. We only need this
1169 * at outermost level because at nested levels the match will have
1170 * been started by the outer field or array element callback.
1171 */
1172 _state->result_start = _state->lex->token_start;
1173 }
1174
1175 return JSON_SUCCESS;
1176}
1177
1178static JsonParseErrorType
1180{
1181 GetState *_state = (GetState *) state;
1182 int lex_level = _state->lex->lex_level;
1183
1184 if (lex_level == 0 && _state->npath == 0)
1185 {
1186 /* Special case: return the entire object */
1187 const char *start = _state->result_start;
1188 int len = _state->lex->prev_token_terminator - start;
1189
1191 }
1192
1193 return JSON_SUCCESS;
1194}
1195
1196static JsonParseErrorType
1197get_object_field_start(void *state, char *fname, bool isnull)
1198{
1199 GetState *_state = (GetState *) state;
1200 bool get_next = false;
1201 int lex_level = _state->lex->lex_level;
1202
1203 if (lex_level <= _state->npath &&
1204 _state->pathok[lex_level - 1] &&
1205 _state->path_names != NULL &&
1206 _state->path_names[lex_level - 1] != NULL &&
1207 strcmp(fname, _state->path_names[lex_level - 1]) == 0)
1208 {
1209 if (lex_level < _state->npath)
1210 {
1211 /* if not at end of path just mark path ok */
1212 _state->pathok[lex_level] = true;
1213 }
1214 else
1215 {
1216 /* end of path, so we want this value */
1217 get_next = true;
1218 }
1219 }
1220
1221 if (get_next)
1222 {
1223 /* this object overrides any previous matching object */
1224 _state->tresult = NULL;
1225 _state->result_start = NULL;
1226
1227 if (_state->normalize_results &&
1228 _state->lex->token_type == JSON_TOKEN_STRING)
1229 {
1230 /* for as_text variants, tell get_scalar to set it for us */
1231 _state->next_scalar = true;
1232 }
1233 else
1234 {
1235 /* for non-as_text variants, just note the json starting point */
1236 _state->result_start = _state->lex->token_start;
1237 }
1238 }
1239
1240 return JSON_SUCCESS;
1241}
1242
1243static JsonParseErrorType
1244get_object_field_end(void *state, char *fname, bool isnull)
1245{
1246 GetState *_state = (GetState *) state;
1247 bool get_last = false;
1248 int lex_level = _state->lex->lex_level;
1249
1250 /* same tests as in get_object_field_start */
1251 if (lex_level <= _state->npath &&
1252 _state->pathok[lex_level - 1] &&
1253 _state->path_names != NULL &&
1254 _state->path_names[lex_level - 1] != NULL &&
1255 strcmp(fname, _state->path_names[lex_level - 1]) == 0)
1256 {
1257 if (lex_level < _state->npath)
1258 {
1259 /* done with this field so reset pathok */
1260 _state->pathok[lex_level] = false;
1261 }
1262 else
1263 {
1264 /* end of path, so we want this value */
1265 get_last = true;
1266 }
1267 }
1268
1269 /* for as_text scalar case, our work is already done */
1270 if (get_last && _state->result_start != NULL)
1271 {
1272 /*
1273 * make a text object from the string from the previously noted json
1274 * start up to the end of the previous token (the lexer is by now
1275 * ahead of us on whatever came after what we're interested in).
1276 */
1277 if (isnull && _state->normalize_results)
1278 _state->tresult = (text *) NULL;
1279 else
1280 {
1281 const char *start = _state->result_start;
1282 int len = _state->lex->prev_token_terminator - start;
1283
1285 }
1286
1287 /* this should be unnecessary but let's do it for cleanliness: */
1288 _state->result_start = NULL;
1289 }
1290
1291 return JSON_SUCCESS;
1292}
1293
1294static JsonParseErrorType
1296{
1297 GetState *_state = (GetState *) state;
1298 int lex_level = _state->lex->lex_level;
1299
1300 if (lex_level < _state->npath)
1301 {
1302 /* Initialize counting of elements in this array */
1303 _state->array_cur_index[lex_level] = -1;
1304
1305 /* INT_MIN value is reserved to represent invalid subscript */
1306 if (_state->path_indexes[lex_level] < 0 &&
1307 _state->path_indexes[lex_level] != INT_MIN)
1308 {
1309 /* Negative subscript -- convert to positive-wise subscript */
1311 int nelements;
1312
1313 error = json_count_array_elements(_state->lex, &nelements);
1314 if (error != JSON_SUCCESS)
1315 json_errsave_error(error, _state->lex, NULL);
1316
1317 if (-_state->path_indexes[lex_level] <= nelements)
1318 _state->path_indexes[lex_level] += nelements;
1319 }
1320 }
1321 else if (lex_level == 0 && _state->npath == 0)
1322 {
1323 /*
1324 * Special case: we should match the entire array. We only need this
1325 * at the outermost level because at nested levels the match will have
1326 * been started by the outer field or array element callback.
1327 */
1328 _state->result_start = _state->lex->token_start;
1329 }
1330
1331 return JSON_SUCCESS;
1332}
1333
1334static JsonParseErrorType
1336{
1337 GetState *_state = (GetState *) state;
1338 int lex_level = _state->lex->lex_level;
1339
1340 if (lex_level == 0 && _state->npath == 0)
1341 {
1342 /* Special case: return the entire array */
1343 const char *start = _state->result_start;
1344 int len = _state->lex->prev_token_terminator - start;
1345
1347 }
1348
1349 return JSON_SUCCESS;
1350}
1351
1352static JsonParseErrorType
1354{
1355 GetState *_state = (GetState *) state;
1356 bool get_next = false;
1357 int lex_level = _state->lex->lex_level;
1358
1359 /* Update array element counter */
1360 if (lex_level <= _state->npath)
1361 _state->array_cur_index[lex_level - 1]++;
1362
1363 if (lex_level <= _state->npath &&
1364 _state->pathok[lex_level - 1] &&
1365 _state->path_indexes != NULL &&
1366 _state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
1367 {
1368 if (lex_level < _state->npath)
1369 {
1370 /* if not at end of path just mark path ok */
1371 _state->pathok[lex_level] = true;
1372 }
1373 else
1374 {
1375 /* end of path, so we want this value */
1376 get_next = true;
1377 }
1378 }
1379
1380 /* same logic as for objects */
1381 if (get_next)
1382 {
1383 _state->tresult = NULL;
1384 _state->result_start = NULL;
1385
1386 if (_state->normalize_results &&
1387 _state->lex->token_type == JSON_TOKEN_STRING)
1388 {
1389 _state->next_scalar = true;
1390 }
1391 else
1392 {
1393 _state->result_start = _state->lex->token_start;
1394 }
1395 }
1396
1397 return JSON_SUCCESS;
1398}
1399
1400static JsonParseErrorType
1401get_array_element_end(void *state, bool isnull)
1402{
1403 GetState *_state = (GetState *) state;
1404 bool get_last = false;
1405 int lex_level = _state->lex->lex_level;
1406
1407 /* same tests as in get_array_element_start */
1408 if (lex_level <= _state->npath &&
1409 _state->pathok[lex_level - 1] &&
1410 _state->path_indexes != NULL &&
1411 _state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
1412 {
1413 if (lex_level < _state->npath)
1414 {
1415 /* done with this element so reset pathok */
1416 _state->pathok[lex_level] = false;
1417 }
1418 else
1419 {
1420 /* end of path, so we want this value */
1421 get_last = true;
1422 }
1423 }
1424
1425 /* same logic as for objects */
1426 if (get_last && _state->result_start != NULL)
1427 {
1428 if (isnull && _state->normalize_results)
1429 _state->tresult = (text *) NULL;
1430 else
1431 {
1432 const char *start = _state->result_start;
1433 int len = _state->lex->prev_token_terminator - start;
1434
1436 }
1437
1438 _state->result_start = NULL;
1439 }
1440
1441 return JSON_SUCCESS;
1442}
1443
1444static JsonParseErrorType
1445get_scalar(void *state, char *token, JsonTokenType tokentype)
1446{
1447 GetState *_state = (GetState *) state;
1448 int lex_level = _state->lex->lex_level;
1449
1450 /* Check for whole-object match */
1451 if (lex_level == 0 && _state->npath == 0)
1452 {
1453 if (_state->normalize_results && tokentype == JSON_TOKEN_STRING)
1454 {
1455 /* we want the de-escaped string */
1456 _state->next_scalar = true;
1457 }
1458 else if (_state->normalize_results && tokentype == JSON_TOKEN_NULL)
1459 {
1460 _state->tresult = (text *) NULL;
1461 }
1462 else
1463 {
1464 /*
1465 * This is a bit hokey: we will suppress whitespace after the
1466 * scalar token, but not whitespace before it. Probably not worth
1467 * doing our own space-skipping to avoid that.
1468 */
1469 const char *start = _state->lex->input;
1470 int len = _state->lex->prev_token_terminator - start;
1471
1473 }
1474 }
1475
1476 if (_state->next_scalar)
1477 {
1478 /* a de-escaped text value is wanted, so supply it */
1479 _state->tresult = cstring_to_text(token);
1480 /* make sure the next call to get_scalar doesn't overwrite it */
1481 _state->next_scalar = false;
1482 }
1483
1484 return JSON_SUCCESS;
1485}
1486
1487Datum
1489{
1490 return get_jsonb_path_all(fcinfo, false);
1491}
1492
1493Datum
1495{
1496 return get_jsonb_path_all(fcinfo, true);
1497}
1498
1499static Datum
1501{
1502 Jsonb *jb = PG_GETARG_JSONB_P(0);
1504 Datum *pathtext;
1505 bool *pathnulls;
1506 bool isnull;
1507 int npath;
1508 Datum res;
1509
1510 /*
1511 * If the array contains any null elements, return NULL, on the grounds
1512 * that you'd have gotten NULL if any RHS value were NULL in a nested
1513 * series of applications of the -> operator. (Note: because we also
1514 * return NULL for error cases such as no-such-field, this is true
1515 * regardless of the contents of the rest of the array.)
1516 */
1517 if (array_contains_nulls(path))
1519
1520 deconstruct_array_builtin(path, TEXTOID, &pathtext, &pathnulls, &npath);
1521
1522 res = jsonb_get_element(jb, pathtext, npath, &isnull, as_text);
1523
1524 if (isnull)
1526 else
1527 PG_RETURN_DATUM(res);
1528}
1529
1530Datum
1531jsonb_get_element(Jsonb *jb, const Datum *path, int npath, bool *isnull, bool as_text)
1532{
1533 JsonbContainer *container = &jb->root;
1534 JsonbValue *jbvp = NULL;
1535 int i;
1536 bool have_object = false,
1537 have_array = false;
1538
1539 *isnull = false;
1540
1541 /* Identify whether we have object, array, or scalar at top-level */
1542 if (JB_ROOT_IS_OBJECT(jb))
1543 have_object = true;
1544 else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
1545 have_array = true;
1546 else
1547 {
1549 /* Extract the scalar value, if it is what we'll return */
1550 if (npath <= 0)
1551 jbvp = getIthJsonbValueFromContainer(container, 0);
1552 }
1553
1554 /*
1555 * If the array is empty, return the entire LHS object, on the grounds
1556 * that we should do zero field or element extractions. For the
1557 * non-scalar case we can just hand back the object without much work. For
1558 * the scalar case, fall through and deal with the value below the loop.
1559 * (This inconsistency arises because there's no easy way to generate a
1560 * JsonbValue directly for root-level containers.)
1561 */
1562 if (npath <= 0 && jbvp == NULL)
1563 {
1564 if (as_text)
1565 {
1567 container,
1568 VARSIZE(jb))));
1569 }
1570 else
1571 {
1572 /* not text mode - just hand back the jsonb */
1574 }
1575 }
1576
1577 for (i = 0; i < npath; i++)
1578 {
1579 if (have_object)
1580 {
1581 text *subscr = DatumGetTextPP(path[i]);
1582
1583 jbvp = getKeyJsonValueFromContainer(container,
1584 VARDATA_ANY(subscr),
1585 VARSIZE_ANY_EXHDR(subscr),
1586 NULL);
1587 }
1588 else if (have_array)
1589 {
1590 int lindex;
1591 uint32 index;
1592 char *indextext = TextDatumGetCString(path[i]);
1593 char *endptr;
1594
1595 errno = 0;
1596 lindex = strtoint(indextext, &endptr, 10);
1597 if (endptr == indextext || *endptr != '\0' || errno != 0)
1598 {
1599 *isnull = true;
1600 return PointerGetDatum(NULL);
1601 }
1602
1603 if (lindex >= 0)
1604 {
1605 index = (uint32) lindex;
1606 }
1607 else
1608 {
1609 /* Handle negative subscript */
1610 uint32 nelements;
1611
1612 /* Container must be array, but make sure */
1613 if (!JsonContainerIsArray(container))
1614 elog(ERROR, "not a jsonb array");
1615
1616 nelements = JsonContainerSize(container);
1617
1618 if (lindex == INT_MIN || -lindex > nelements)
1619 {
1620 *isnull = true;
1621 return PointerGetDatum(NULL);
1622 }
1623 else
1624 index = nelements + lindex;
1625 }
1626
1627 jbvp = getIthJsonbValueFromContainer(container, index);
1628 }
1629 else
1630 {
1631 /* scalar, extraction yields a null */
1632 *isnull = true;
1633 return PointerGetDatum(NULL);
1634 }
1635
1636 if (jbvp == NULL)
1637 {
1638 *isnull = true;
1639 return PointerGetDatum(NULL);
1640 }
1641 else if (i == npath - 1)
1642 break;
1643
1644 if (jbvp->type == jbvBinary)
1645 {
1646 container = jbvp->val.binary.data;
1647 have_object = JsonContainerIsObject(container);
1648 have_array = JsonContainerIsArray(container);
1649 Assert(!JsonContainerIsScalar(container));
1650 }
1651 else
1652 {
1653 Assert(IsAJsonbScalar(jbvp));
1654 have_object = false;
1655 have_array = false;
1656 }
1657 }
1658
1659 if (as_text)
1660 {
1661 if (jbvp->type == jbvNull)
1662 {
1663 *isnull = true;
1664 return PointerGetDatum(NULL);
1665 }
1666
1667 return PointerGetDatum(JsonbValueAsText(jbvp));
1668 }
1669 else
1670 {
1671 Jsonb *res = JsonbValueToJsonb(jbvp);
1672
1673 /* not text mode - just hand back the jsonb */
1674 PG_RETURN_JSONB_P(res);
1675 }
1676}
1677
1678Datum
1679jsonb_set_element(Jsonb *jb, const Datum *path, int path_len,
1681{
1682 JsonbInState state = {0};
1683 JsonbIterator *it;
1684 bool *path_nulls = palloc0_array(bool, path_len);
1685
1686 if (newval->type == jbvArray && newval->val.array.rawScalar)
1687 *newval = newval->val.array.elems[0];
1688
1689 it = JsonbIteratorInit(&jb->root);
1690
1691 setPath(&it, path, path_nulls, path_len, &state, 0, newval,
1694
1695 pfree(path_nulls);
1696
1698}
1699
1700static void
1702{
1703 JsonbValue null;
1704
1705 null.type = jbvNull;
1706
1707 while (num-- > 0)
1708 pushJsonbValue(ps, WJB_ELEM, &null);
1709}
1710
1711/*
1712 * Prepare a new structure containing nested empty objects and arrays
1713 * corresponding to the specified path, and assign a new value at the end of
1714 * this path. E.g. the path [a][0][b] with the new value 1 will produce the
1715 * structure {a: [{b: 1}]}.
1716 *
1717 * Caller is responsible to make sure such path does not exist yet.
1718 */
1719static void
1720push_path(JsonbInState *st, int level, const Datum *path_elems,
1721 const bool *path_nulls, int path_len, JsonbValue *newval)
1722{
1723 /*
1724 * tpath contains expected type of an empty jsonb created at each level
1725 * higher or equal to the current one, either jbvObject or jbvArray. Since
1726 * it contains only information about path slice from level to the end,
1727 * the access index must be normalized by level.
1728 */
1729 enum jbvType *tpath = palloc0_array(enum jbvType, path_len - level);
1730 JsonbValue newkey;
1731
1732 /*
1733 * Create first part of the chain with beginning tokens. For the current
1734 * level WJB_BEGIN_OBJECT/WJB_BEGIN_ARRAY was already created, so start
1735 * with the next one.
1736 */
1737 for (int i = level + 1; i < path_len; i++)
1738 {
1739 char *c,
1740 *badp;
1741 int lindex;
1742
1743 if (path_nulls[i])
1744 break;
1745
1746 /*
1747 * Try to convert to an integer to find out the expected type, object
1748 * or array.
1749 */
1750 c = TextDatumGetCString(path_elems[i]);
1751 errno = 0;
1752 lindex = strtoint(c, &badp, 10);
1753 if (badp == c || *badp != '\0' || errno != 0)
1754 {
1755 /* text, an object is expected */
1756 newkey.type = jbvString;
1757 newkey.val.string.val = c;
1758 newkey.val.string.len = strlen(c);
1759
1761 pushJsonbValue(st, WJB_KEY, &newkey);
1762
1763 tpath[i - level] = jbvObject;
1764 }
1765 else
1766 {
1767 /* integer, an array is expected */
1769
1770 push_null_elements(st, lindex);
1771
1772 tpath[i - level] = jbvArray;
1773 }
1774 }
1775
1776 /* Insert an actual value for either an object or array */
1777 if (tpath[(path_len - level) - 1] == jbvArray)
1779 else
1781
1782 /*
1783 * Close everything up to the last but one level. The last one will be
1784 * closed outside of this function.
1785 */
1786 for (int i = path_len - 1; i > level; i--)
1787 {
1788 if (path_nulls[i])
1789 break;
1790
1791 if (tpath[i - level] == jbvObject)
1792 pushJsonbValue(st, WJB_END_OBJECT, NULL);
1793 else
1794 pushJsonbValue(st, WJB_END_ARRAY, NULL);
1795 }
1796}
1797
1798/*
1799 * Return the text representation of the given JsonbValue.
1800 */
1801static text *
1803{
1804 switch (v->type)
1805 {
1806 case jbvNull:
1807 return NULL;
1808
1809 case jbvBool:
1810 return v->val.boolean ?
1811 cstring_to_text_with_len("true", 4) :
1812 cstring_to_text_with_len("false", 5);
1813
1814 case jbvString:
1815 return cstring_to_text_with_len(v->val.string.val,
1816 v->val.string.len);
1817
1818 case jbvNumeric:
1819 {
1820 Datum cstr;
1821
1823 PointerGetDatum(v->val.numeric));
1824
1825 return cstring_to_text(DatumGetCString(cstr));
1826 }
1827
1828 case jbvBinary:
1829 {
1830 StringInfoData jtext;
1831
1832 initStringInfo(&jtext);
1833 (void) JsonbToCString(&jtext, v->val.binary.data,
1834 v->val.binary.len);
1835
1836 return cstring_to_text_with_len(jtext.data, jtext.len);
1837 }
1838
1839 default:
1840 elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
1841 return NULL;
1842 }
1843}
1844
1845/*
1846 * SQL function json_array_length(json) -> int
1847 */
1848Datum
1850{
1851 text *json = PG_GETARG_TEXT_PP(0);
1853 JsonLexContext lex;
1855
1857 state->lex = makeJsonLexContext(&lex, json, false);
1858 /* palloc0 does this for us */
1859#if 0
1860 state->count = 0;
1861#endif
1862
1864 sem->semstate = state;
1868
1870
1871 PG_RETURN_INT32(state->count);
1872}
1873
1874Datum
1876{
1877 Jsonb *jb = PG_GETARG_JSONB_P(0);
1878
1879 if (JB_ROOT_IS_SCALAR(jb))
1880 ereport(ERROR,
1881 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1882 errmsg("cannot get array length of a scalar")));
1883 else if (!JB_ROOT_IS_ARRAY(jb))
1884 ereport(ERROR,
1885 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1886 errmsg("cannot get array length of a non-array")));
1887
1889}
1890
1891/*
1892 * These next two checks ensure that the json is an array (since it can't be
1893 * a scalar or an object).
1894 */
1895
1896static JsonParseErrorType
1898{
1899 AlenState *_state = (AlenState *) state;
1900
1901 /* json structure check */
1902 if (_state->lex->lex_level == 0)
1903 ereport(ERROR,
1904 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1905 errmsg("cannot get array length of a non-array")));
1906
1907 return JSON_SUCCESS;
1908}
1909
1910static JsonParseErrorType
1911alen_scalar(void *state, char *token, JsonTokenType tokentype)
1912{
1913 AlenState *_state = (AlenState *) state;
1914
1915 /* json structure check */
1916 if (_state->lex->lex_level == 0)
1917 ereport(ERROR,
1918 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1919 errmsg("cannot get array length of a scalar")));
1920
1921 return JSON_SUCCESS;
1922}
1923
1924static JsonParseErrorType
1926{
1927 AlenState *_state = (AlenState *) state;
1928
1929 /* just count up all the level 1 elements */
1930 if (_state->lex->lex_level == 1)
1931 _state->count++;
1932
1933 return JSON_SUCCESS;
1934}
1935
1936/*
1937 * SQL function json_each and json_each_text
1938 *
1939 * decompose a json object into key value pairs.
1940 *
1941 * Unlike json_object_keys() these SRFs operate in materialize mode,
1942 * stashing results into a Tuplestore object as they go.
1943 * The construction of tuples is done using a temporary memory context
1944 * that is cleared out after each tuple is built.
1945 */
1946Datum
1948{
1949 return each_worker(fcinfo, false);
1950}
1951
1952Datum
1954{
1955 return each_worker_jsonb(fcinfo, "jsonb_each", false);
1956}
1957
1958Datum
1960{
1961 return each_worker(fcinfo, true);
1962}
1963
1964Datum
1966{
1967 return each_worker_jsonb(fcinfo, "jsonb_each_text", true);
1968}
1969
1970static Datum
1971each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
1972{
1973 Jsonb *jb = PG_GETARG_JSONB_P(0);
1974 ReturnSetInfo *rsi;
1975 MemoryContext old_cxt,
1976 tmp_cxt;
1977 bool skipNested = false;
1978 JsonbIterator *it;
1979 JsonbValue v;
1981
1982 if (!JB_ROOT_IS_OBJECT(jb))
1983 ereport(ERROR,
1984 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1985 errmsg("cannot call %s on a non-object",
1986 funcname)));
1987
1988 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1990
1992 "jsonb_each temporary cxt",
1994
1995 it = JsonbIteratorInit(&jb->root);
1996
1997 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
1998 {
1999 skipNested = true;
2000
2001 if (r == WJB_KEY)
2002 {
2003 text *key;
2004 Datum values[2];
2005 bool nulls[2] = {false, false};
2006
2007 /* Use the tmp context so we can clean up after each tuple is done */
2008 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2009
2010 key = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
2011
2012 /*
2013 * The next thing the iterator fetches should be the value, no
2014 * matter what shape it is.
2015 */
2016 r = JsonbIteratorNext(&it, &v, skipNested);
2017 Assert(r != WJB_DONE);
2018
2020
2021 if (as_text)
2022 {
2023 if (v.type == jbvNull)
2024 {
2025 /* a json null is an sql null in text mode */
2026 nulls[1] = true;
2027 values[1] = (Datum) 0;
2028 }
2029 else
2031 }
2032 else
2033 {
2034 /* Not in text mode, just return the Jsonb */
2036
2038 }
2039
2040 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2041
2042 /* clean up and switch back */
2043 MemoryContextSwitchTo(old_cxt);
2044 MemoryContextReset(tmp_cxt);
2045 }
2046 }
2047
2048 MemoryContextDelete(tmp_cxt);
2049
2051}
2052
2053
2054static Datum
2055each_worker(FunctionCallInfo fcinfo, bool as_text)
2056{
2057 text *json = PG_GETARG_TEXT_PP(0);
2058 JsonLexContext lex;
2060 ReturnSetInfo *rsi;
2062
2065
2066 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2067
2069 state->tuple_store = rsi->setResult;
2070 state->ret_tdesc = rsi->setDesc;
2071
2072 sem->semstate = state;
2077
2078 state->normalize_results = as_text;
2079 state->next_scalar = false;
2080 state->lex = makeJsonLexContext(&lex, json, true);
2082 "json_each temporary cxt",
2084
2086
2087 MemoryContextDelete(state->tmp_cxt);
2088 freeJsonLexContext(&lex);
2089
2091}
2092
2093
2094static JsonParseErrorType
2095each_object_field_start(void *state, char *fname, bool isnull)
2096{
2097 EachState *_state = (EachState *) state;
2098
2099 /* save a pointer to where the value starts */
2100 if (_state->lex->lex_level == 1)
2101 {
2102 /*
2103 * next_scalar will be reset in the object_field_end handler, and
2104 * since we know the value is a scalar there is no danger of it being
2105 * on while recursing down the tree.
2106 */
2107 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2108 _state->next_scalar = true;
2109 else
2110 _state->result_start = _state->lex->token_start;
2111 }
2112
2113 return JSON_SUCCESS;
2114}
2115
2116static JsonParseErrorType
2117each_object_field_end(void *state, char *fname, bool isnull)
2118{
2119 EachState *_state = (EachState *) state;
2120 MemoryContext old_cxt;
2121 int len;
2122 text *val;
2123 HeapTuple tuple;
2124 Datum values[2];
2125 bool nulls[2] = {false, false};
2126
2127 /* skip over nested objects */
2128 if (_state->lex->lex_level != 1)
2129 return JSON_SUCCESS;
2130
2131 /* use the tmp context so we can clean up after each tuple is done */
2132 old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2133
2134 values[0] = CStringGetTextDatum(fname);
2135
2136 if (isnull && _state->normalize_results)
2137 {
2138 nulls[1] = true;
2139 values[1] = (Datum) 0;
2140 }
2141 else if (_state->next_scalar)
2142 {
2144 _state->next_scalar = false;
2145 }
2146 else
2147 {
2148 len = _state->lex->prev_token_terminator - _state->result_start;
2151 }
2152
2153 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2154
2155 tuplestore_puttuple(_state->tuple_store, tuple);
2156
2157 /* clean up and switch back */
2158 MemoryContextSwitchTo(old_cxt);
2159 MemoryContextReset(_state->tmp_cxt);
2160
2161 return JSON_SUCCESS;
2162}
2163
2164static JsonParseErrorType
2166{
2167 EachState *_state = (EachState *) state;
2168
2169 /* json structure check */
2170 if (_state->lex->lex_level == 0)
2171 ereport(ERROR,
2172 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2173 errmsg("cannot deconstruct an array as an object")));
2174
2175 return JSON_SUCCESS;
2176}
2177
2178static JsonParseErrorType
2179each_scalar(void *state, char *token, JsonTokenType tokentype)
2180{
2181 EachState *_state = (EachState *) state;
2182
2183 /* json structure check */
2184 if (_state->lex->lex_level == 0)
2185 ereport(ERROR,
2186 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2187 errmsg("cannot deconstruct a scalar")));
2188
2189 /* supply de-escaped value if required */
2190 if (_state->next_scalar)
2191 _state->normalized_scalar = token;
2192
2193 return JSON_SUCCESS;
2194}
2195
2196/*
2197 * SQL functions json_array_elements and json_array_elements_text
2198 *
2199 * get the elements from a json array
2200 *
2201 * a lot of this processing is similar to the json_each* functions
2202 */
2203
2204Datum
2206{
2207 return elements_worker_jsonb(fcinfo, "jsonb_array_elements", false);
2208}
2209
2210Datum
2212{
2213 return elements_worker_jsonb(fcinfo, "jsonb_array_elements_text", true);
2214}
2215
2216static Datum
2218 bool as_text)
2219{
2220 Jsonb *jb = PG_GETARG_JSONB_P(0);
2221 ReturnSetInfo *rsi;
2222 MemoryContext old_cxt,
2223 tmp_cxt;
2224 bool skipNested = false;
2225 JsonbIterator *it;
2226 JsonbValue v;
2228
2229 if (JB_ROOT_IS_SCALAR(jb))
2230 ereport(ERROR,
2231 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2232 errmsg("cannot extract elements from a scalar")));
2233 else if (!JB_ROOT_IS_ARRAY(jb))
2234 ereport(ERROR,
2235 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2236 errmsg("cannot extract elements from an object")));
2237
2238 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2239
2241
2243 "jsonb_array_elements temporary cxt",
2245
2246 it = JsonbIteratorInit(&jb->root);
2247
2248 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
2249 {
2250 skipNested = true;
2251
2252 if (r == WJB_ELEM)
2253 {
2254 Datum values[1];
2255 bool nulls[1] = {false};
2256
2257 /* use the tmp context so we can clean up after each tuple is done */
2258 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2259
2260 if (as_text)
2261 {
2262 if (v.type == jbvNull)
2263 {
2264 /* a json null is an sql null in text mode */
2265 nulls[0] = true;
2266 values[0] = (Datum) 0;
2267 }
2268 else
2270 }
2271 else
2272 {
2273 /* Not in text mode, just return the Jsonb */
2275
2277 }
2278
2279 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2280
2281 /* clean up and switch back */
2282 MemoryContextSwitchTo(old_cxt);
2283 MemoryContextReset(tmp_cxt);
2284 }
2285 }
2286
2287 MemoryContextDelete(tmp_cxt);
2288
2290}
2291
2292Datum
2294{
2295 return elements_worker(fcinfo, "json_array_elements", false);
2296}
2297
2298Datum
2300{
2301 return elements_worker(fcinfo, "json_array_elements_text", true);
2302}
2303
2304static Datum
2305elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
2306{
2307 text *json = PG_GETARG_TEXT_PP(0);
2308 JsonLexContext lex;
2310 ReturnSetInfo *rsi;
2312
2313 /* elements only needs escaped strings when as_text */
2314 makeJsonLexContext(&lex, json, as_text);
2315
2318
2320 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2321 state->tuple_store = rsi->setResult;
2322 state->ret_tdesc = rsi->setDesc;
2323
2324 sem->semstate = state;
2329
2330 state->function_name = funcname;
2331 state->normalize_results = as_text;
2332 state->next_scalar = false;
2333 state->lex = &lex;
2335 "json_array_elements temporary cxt",
2337
2339
2340 MemoryContextDelete(state->tmp_cxt);
2341 freeJsonLexContext(&lex);
2342
2344}
2345
2346static JsonParseErrorType
2348{
2349 ElementsState *_state = (ElementsState *) state;
2350
2351 /* save a pointer to where the value starts */
2352 if (_state->lex->lex_level == 1)
2353 {
2354 /*
2355 * next_scalar will be reset in the array_element_end handler, and
2356 * since we know the value is a scalar there is no danger of it being
2357 * on while recursing down the tree.
2358 */
2359 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2360 _state->next_scalar = true;
2361 else
2362 _state->result_start = _state->lex->token_start;
2363 }
2364
2365 return JSON_SUCCESS;
2366}
2367
2368static JsonParseErrorType
2370{
2371 ElementsState *_state = (ElementsState *) state;
2372 MemoryContext old_cxt;
2373 int len;
2374 text *val;
2375 HeapTuple tuple;
2376 Datum values[1];
2377 bool nulls[1] = {false};
2378
2379 /* skip over nested objects */
2380 if (_state->lex->lex_level != 1)
2381 return JSON_SUCCESS;
2382
2383 /* use the tmp context so we can clean up after each tuple is done */
2384 old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2385
2386 if (isnull && _state->normalize_results)
2387 {
2388 nulls[0] = true;
2389 values[0] = (Datum) 0;
2390 }
2391 else if (_state->next_scalar)
2392 {
2394 _state->next_scalar = false;
2395 }
2396 else
2397 {
2398 len = _state->lex->prev_token_terminator - _state->result_start;
2401 }
2402
2403 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2404
2405 tuplestore_puttuple(_state->tuple_store, tuple);
2406
2407 /* clean up and switch back */
2408 MemoryContextSwitchTo(old_cxt);
2409 MemoryContextReset(_state->tmp_cxt);
2410
2411 return JSON_SUCCESS;
2412}
2413
2414static JsonParseErrorType
2416{
2417 ElementsState *_state = (ElementsState *) state;
2418
2419 /* json structure check */
2420 if (_state->lex->lex_level == 0)
2421 ereport(ERROR,
2422 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2423 errmsg("cannot call %s on a non-array",
2424 _state->function_name)));
2425
2426 return JSON_SUCCESS;
2427}
2428
2429static JsonParseErrorType
2431{
2432 ElementsState *_state = (ElementsState *) state;
2433
2434 /* json structure check */
2435 if (_state->lex->lex_level == 0)
2436 ereport(ERROR,
2437 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2438 errmsg("cannot call %s on a scalar",
2439 _state->function_name)));
2440
2441 /* supply de-escaped value if required */
2442 if (_state->next_scalar)
2443 _state->normalized_scalar = token;
2444
2445 return JSON_SUCCESS;
2446}
2447
2448/*
2449 * SQL function json_populate_record
2450 *
2451 * set fields in a record from the argument json
2452 *
2453 * Code adapted shamelessly from hstore's populate_record
2454 * which is in turn partly adapted from record_out.
2455 *
2456 * The json is decomposed into a hash table, in which each
2457 * field in the record is then looked up by name. For jsonb
2458 * we fetch the values direct from the object.
2459 */
2460Datum
2462{
2463 return populate_record_worker(fcinfo, "jsonb_populate_record",
2464 false, true, NULL);
2465}
2466
2467/*
2468 * SQL function that can be used for testing json_populate_record().
2469 *
2470 * Returns false if json_populate_record() encounters an error for the
2471 * provided input JSON object, true otherwise.
2472 */
2473Datum
2475{
2476 ErrorSaveContext escontext = {T_ErrorSaveContext};
2477
2478 (void) populate_record_worker(fcinfo, "jsonb_populate_record",
2479 false, true, (Node *) &escontext);
2480
2481 return BoolGetDatum(!escontext.error_occurred);
2482}
2483
2484Datum
2486{
2487 return populate_record_worker(fcinfo, "jsonb_to_record",
2488 false, false, NULL);
2489}
2490
2491Datum
2493{
2494 return populate_record_worker(fcinfo, "json_populate_record",
2495 true, true, NULL);
2496}
2497
2498Datum
2500{
2501 return populate_record_worker(fcinfo, "json_to_record",
2502 true, false, NULL);
2503}
2504
2505/* helper function for diagnostics */
2506static void
2508{
2509 if (ndim <= 0)
2510 {
2511 if (ctx->colname)
2512 errsave(ctx->escontext,
2513 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2514 errmsg("expected JSON array"),
2515 errhint("See the value of key \"%s\".", ctx->colname)));
2516 else
2517 errsave(ctx->escontext,
2518 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2519 errmsg("expected JSON array")));
2520 return;
2521 }
2522 else
2523 {
2524 StringInfoData indices;
2525 int i;
2526
2527 initStringInfo(&indices);
2528
2529 Assert(ctx->ndims > 0 && ndim < ctx->ndims);
2530
2531 for (i = 0; i < ndim; i++)
2532 appendStringInfo(&indices, "[%d]", ctx->sizes[i]);
2533
2534 if (ctx->colname)
2535 errsave(ctx->escontext,
2536 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2537 errmsg("expected JSON array"),
2538 errhint("See the array element %s of key \"%s\".",
2539 indices.data, ctx->colname)));
2540 else
2541 errsave(ctx->escontext,
2542 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2543 errmsg("expected JSON array"),
2544 errhint("See the array element %s.",
2545 indices.data)));
2546 return;
2547 }
2548}
2549
2550/*
2551 * Validate and set ndims for populating an array with some
2552 * populate_array_*() function.
2553 *
2554 * Returns false if the input (ndims) is erroneous.
2555 */
2556static bool
2558{
2559 int i;
2560
2561 Assert(ctx->ndims <= 0);
2562
2563 if (ndims <= 0)
2564 {
2566 /* Getting here means the error was reported softly. */
2568 return false;
2569 }
2570
2571 ctx->ndims = ndims;
2572 ctx->dims = palloc_array(int, ndims);
2573 ctx->sizes = palloc0_array(int, ndims);
2574
2575 for (i = 0; i < ndims; i++)
2576 ctx->dims[i] = -1; /* dimensions are unknown yet */
2577
2578 return true;
2579}
2580
2581/*
2582 * Check the populated subarray dimension
2583 *
2584 * Returns false if the input (ndims) is erroneous.
2585 */
2586static bool
2588{
2589 int dim = ctx->sizes[ndim]; /* current dimension counter */
2590
2591 if (ctx->dims[ndim] == -1)
2592 ctx->dims[ndim] = dim; /* assign dimension if not yet known */
2593 else if (ctx->dims[ndim] != dim)
2594 ereturn(ctx->escontext, false,
2595 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2596 errmsg("malformed JSON array"),
2597 errdetail("Multidimensional arrays must have "
2598 "sub-arrays with matching dimensions.")));
2599
2600 /* reset the current array dimension size counter */
2601 ctx->sizes[ndim] = 0;
2602
2603 /* increment the parent dimension counter if it is a nested sub-array */
2604 if (ndim > 0)
2605 ctx->sizes[ndim - 1]++;
2606
2607 return true;
2608}
2609
2610/*
2611 * Returns true if the array element value was successfully extracted from jsv
2612 * and added to ctx->astate. False if an error occurred when doing so.
2613 */
2614static bool
2616{
2617 Datum element;
2618 bool element_isnull;
2619
2620 /* populate the array element */
2622 ctx->aio->element_type,
2623 ctx->aio->element_typmod,
2624 NULL, ctx->mcxt, PointerGetDatum(NULL),
2625 jsv, &element_isnull, ctx->escontext,
2626 false);
2627 /* Nothing to do on an error. */
2629 return false;
2630
2631 accumArrayResult(ctx->astate, element, element_isnull,
2632 ctx->aio->element_type, ctx->acxt);
2633
2634 Assert(ndim > 0);
2635 ctx->sizes[ndim - 1]++; /* increment current dimension counter */
2636
2637 return true;
2638}
2639
2640/* json object start handler for populate_array_json() */
2641static JsonParseErrorType
2643{
2645 int ndim = state->lex->lex_level;
2646
2647 if (state->ctx->ndims <= 0)
2648 {
2649 if (!populate_array_assign_ndims(state->ctx, ndim))
2651 }
2652 else if (ndim < state->ctx->ndims)
2653 {
2655 /* Getting here means the error was reported softly. */
2656 Assert(SOFT_ERROR_OCCURRED(state->ctx->escontext));
2658 }
2659
2660 return JSON_SUCCESS;
2661}
2662
2663/* json array end handler for populate_array_json() */
2664static JsonParseErrorType
2666{
2668 PopulateArrayContext *ctx = state->ctx;
2669 int ndim = state->lex->lex_level;
2670
2671 if (ctx->ndims <= 0)
2672 {
2673 if (!populate_array_assign_ndims(ctx, ndim + 1))
2675 }
2676
2677 if (ndim < ctx->ndims)
2678 {
2679 /* Report if an error occurred. */
2680 if (!populate_array_check_dimension(ctx, ndim))
2682 }
2683
2684 return JSON_SUCCESS;
2685}
2686
2687/* json array element start handler for populate_array_json() */
2688static JsonParseErrorType
2689populate_array_element_start(void *_state, bool isnull)
2690{
2692 int ndim = state->lex->lex_level;
2693
2694 if (state->ctx->ndims <= 0 || ndim == state->ctx->ndims)
2695 {
2696 /* remember current array element start */
2697 state->element_start = state->lex->token_start;
2698 state->element_type = state->lex->token_type;
2699 state->element_scalar = NULL;
2700 }
2701
2702 return JSON_SUCCESS;
2703}
2704
2705/* json array element end handler for populate_array_json() */
2706static JsonParseErrorType
2707populate_array_element_end(void *_state, bool isnull)
2708{
2710 PopulateArrayContext *ctx = state->ctx;
2711 int ndim = state->lex->lex_level;
2712
2713 Assert(ctx->ndims > 0);
2714
2715 if (ndim == ctx->ndims)
2716 {
2717 JsValue jsv;
2718
2719 jsv.is_json = true;
2720 jsv.val.json.type = state->element_type;
2721
2722 if (isnull)
2723 {
2725 jsv.val.json.str = NULL;
2726 jsv.val.json.len = 0;
2727 }
2728 else if (state->element_scalar)
2729 {
2730 jsv.val.json.str = state->element_scalar;
2731 jsv.val.json.len = -1; /* null-terminated */
2732 }
2733 else
2734 {
2735 jsv.val.json.str = state->element_start;
2736 jsv.val.json.len = (state->lex->prev_token_terminator -
2737 state->element_start) * sizeof(char);
2738 }
2739
2740 /* Report if an error occurred. */
2741 if (!populate_array_element(ctx, ndim, &jsv))
2743 }
2744
2745 return JSON_SUCCESS;
2746}
2747
2748/* json scalar handler for populate_array_json() */
2749static JsonParseErrorType
2750populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
2751{
2753 PopulateArrayContext *ctx = state->ctx;
2754 int ndim = state->lex->lex_level;
2755
2756 if (ctx->ndims <= 0)
2757 {
2758 if (!populate_array_assign_ndims(ctx, ndim))
2760 }
2761 else if (ndim < ctx->ndims)
2762 {
2764 /* Getting here means the error was reported softly. */
2767 }
2768
2769 if (ndim == ctx->ndims)
2770 {
2771 /* remember the scalar element token */
2772 state->element_scalar = token;
2773 /* element_type must already be set in populate_array_element_start() */
2774 Assert(state->element_type == tokentype);
2775 }
2776
2777 return JSON_SUCCESS;
2778}
2779
2780/*
2781 * Parse a json array and populate array
2782 *
2783 * Returns false if an error occurs when parsing.
2784 */
2785static bool
2787{
2790
2791 state.lex = makeJsonLexContextCstringLen(NULL, json, len,
2792 GetDatabaseEncoding(), true);
2793 state.ctx = ctx;
2794
2795 memset(&sem, 0, sizeof(sem));
2796 sem.semstate = &state;
2802
2804 {
2805 /* number of dimensions should be already known */
2806 Assert(ctx->ndims > 0 && ctx->dims);
2807 }
2808
2810
2811 return !SOFT_ERROR_OCCURRED(ctx->escontext);
2812}
2813
2814/*
2815 * populate_array_dim_jsonb() -- Iterate recursively through jsonb sub-array
2816 * elements and accumulate result using given ArrayBuildState.
2817 *
2818 * Returns false if we return partway through because of an error in a
2819 * subroutine.
2820 */
2821static bool
2823 JsonbValue *jbv, /* jsonb sub-array */
2824 int ndim) /* current dimension */
2825{
2826 JsonbContainer *jbc = jbv->val.binary.data;
2827 JsonbIterator *it;
2830 JsValue jsv;
2831
2833
2834 /* Even scalars can end up here thanks to ExecEvalJsonCoercion(). */
2835 if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc) ||
2837 {
2839 /* Getting here means the error was reported softly. */
2841 return false;
2842 }
2843
2844 it = JsonbIteratorInit(jbc);
2845
2846 tok = JsonbIteratorNext(&it, &val, true);
2847 Assert(tok == WJB_BEGIN_ARRAY);
2848
2849 tok = JsonbIteratorNext(&it, &val, true);
2850
2851 /*
2852 * If the number of dimensions is not yet known and we have found end of
2853 * the array, or the first child element is not an array, then assign the
2854 * number of dimensions now.
2855 */
2856 if (ctx->ndims <= 0 &&
2857 (tok == WJB_END_ARRAY ||
2858 (tok == WJB_ELEM &&
2859 (val.type != jbvBinary ||
2860 !JsonContainerIsArray(val.val.binary.data)))))
2861 {
2862 if (!populate_array_assign_ndims(ctx, ndim))
2863 return false;
2864 }
2865
2866 jsv.is_json = false;
2867 jsv.val.jsonb = &val;
2868
2869 /* process all the array elements */
2870 while (tok == WJB_ELEM)
2871 {
2872 /*
2873 * Recurse only if the dimensions of dimensions is still unknown or if
2874 * it is not the innermost dimension.
2875 */
2876 if (ctx->ndims > 0 && ndim >= ctx->ndims)
2877 {
2878 if (!populate_array_element(ctx, ndim, &jsv))
2879 return false;
2880 }
2881 else
2882 {
2883 /* populate child sub-array */
2884 if (!populate_array_dim_jsonb(ctx, &val, ndim + 1))
2885 return false;
2886
2887 /* number of dimensions should be already known */
2888 Assert(ctx->ndims > 0 && ctx->dims);
2889
2890 if (!populate_array_check_dimension(ctx, ndim))
2891 return false;
2892 }
2893
2894 tok = JsonbIteratorNext(&it, &val, true);
2895 }
2896
2897 Assert(tok == WJB_END_ARRAY);
2898
2899 /* free iterator, iterating until WJB_DONE */
2900 tok = JsonbIteratorNext(&it, &val, true);
2901 Assert(tok == WJB_DONE && !it);
2902
2903 return true;
2904}
2905
2906/*
2907 * Recursively populate an array from json/jsonb
2908 *
2909 * *isnull is set to true if an error is reported during parsing.
2910 */
2911static Datum
2913 const char *colname,
2914 MemoryContext mcxt,
2915 JsValue *jsv,
2916 bool *isnull,
2917 Node *escontext)
2918{
2920 Datum result;
2921 int *lbs;
2922 int i;
2923
2924 ctx.aio = aio;
2925 ctx.mcxt = mcxt;
2927 ctx.astate = initArrayResult(aio->element_type, ctx.acxt, true);
2928 ctx.colname = colname;
2929 ctx.ndims = 0; /* unknown yet */
2930 ctx.dims = NULL;
2931 ctx.sizes = NULL;
2932 ctx.escontext = escontext;
2933
2934 if (jsv->is_json)
2935 {
2936 /* Return null if an error was found. */
2937 if (!populate_array_json(&ctx, jsv->val.json.str,
2938 jsv->val.json.len >= 0 ? jsv->val.json.len
2939 : strlen(jsv->val.json.str)))
2940 {
2941 *isnull = true;
2942 return (Datum) 0;
2943 }
2944 }
2945 else
2946 {
2947 /* Return null if an error was found. */
2948 if (!populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1))
2949 {
2950 *isnull = true;
2951 return (Datum) 0;
2952 }
2953 ctx.dims[0] = ctx.sizes[0];
2954 }
2955
2956 Assert(ctx.ndims > 0);
2957
2958 lbs = palloc_array(int, ctx.ndims);
2959
2960 for (i = 0; i < ctx.ndims; i++)
2961 lbs[i] = 1;
2962
2963 result = makeMdArrayResult(ctx.astate, ctx.ndims, ctx.dims, lbs,
2964 ctx.acxt, true);
2965
2966 pfree(ctx.dims);
2967 pfree(ctx.sizes);
2968 pfree(lbs);
2969
2970 *isnull = false;
2971 return result;
2972}
2973
2974/*
2975 * Returns false if an error occurs, provided escontext points to an
2976 * ErrorSaveContext.
2977 */
2978static bool
2980{
2981 jso->is_json = jsv->is_json;
2982
2983 if (jsv->is_json)
2984 {
2985 /* convert plain-text json into a hash table */
2986 jso->val.json_hash =
2988 jsv->val.json.len >= 0
2989 ? jsv->val.json.len
2990 : strlen(jsv->val.json.str),
2991 "populate_composite",
2992 escontext);
2993 Assert(jso->val.json_hash != NULL || SOFT_ERROR_OCCURRED(escontext));
2994 }
2995 else
2996 {
2997 JsonbValue *jbv = jsv->val.jsonb;
2998
2999 if (jbv->type == jbvBinary &&
3000 JsonContainerIsObject(jbv->val.binary.data))
3001 {
3002 jso->val.jsonb_cont = jbv->val.binary.data;
3003 }
3004 else
3005 {
3006 bool is_scalar;
3007
3008 is_scalar = IsAJsonbScalar(jbv) ||
3009 (jbv->type == jbvBinary &&
3010 JsonContainerIsScalar(jbv->val.binary.data));
3011 errsave(escontext,
3012 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3013 is_scalar
3014 ? errmsg("cannot call %s on a scalar",
3015 "populate_composite")
3016 : errmsg("cannot call %s on an array",
3017 "populate_composite")));
3018 }
3019 }
3020
3021 return !SOFT_ERROR_OCCURRED(escontext);
3022}
3023
3024/* acquire or update cached tuple descriptor for a composite type */
3025static void
3027{
3028 if (!io->tupdesc ||
3029 io->tupdesc->tdtypeid != io->base_typid ||
3030 io->tupdesc->tdtypmod != io->base_typmod)
3031 {
3033 io->base_typmod);
3034 MemoryContext oldcxt;
3035
3036 if (io->tupdesc)
3038
3039 /* copy tuple desc without constraints into cache memory context */
3040 oldcxt = MemoryContextSwitchTo(mcxt);
3041 io->tupdesc = CreateTupleDescCopy(tupdesc);
3042 MemoryContextSwitchTo(oldcxt);
3043
3044 ReleaseTupleDesc(tupdesc);
3045 }
3046}
3047
3048/*
3049 * Recursively populate a composite (row type) value from json/jsonb
3050 *
3051 * Returns null if an error occurs in a subroutine, provided escontext points
3052 * to an ErrorSaveContext.
3053 */
3054static Datum
3056 Oid typid,
3057 const char *colname,
3058 MemoryContext mcxt,
3059 HeapTupleHeader defaultval,
3060 JsValue *jsv,
3061 bool *isnull,
3062 Node *escontext)
3063{
3064 Datum result;
3065
3066 /* acquire/update cached tuple descriptor */
3067 update_cached_tupdesc(io, mcxt);
3068
3069 if (*isnull)
3070 result = (Datum) 0;
3071 else
3072 {
3073 HeapTupleHeader tuple;
3074 JsObject jso;
3075
3076 /* prepare input value */
3077 if (!JsValueToJsObject(jsv, &jso, escontext))
3078 {
3079 *isnull = true;
3080 return (Datum) 0;
3081 }
3082
3083 /* populate resulting record tuple */
3084 tuple = populate_record(io->tupdesc, &io->record_io,
3085 defaultval, mcxt, &jso, escontext);
3086
3087 if (SOFT_ERROR_OCCURRED(escontext))
3088 {
3089 *isnull = true;
3090 return (Datum) 0;
3091 }
3092 result = HeapTupleHeaderGetDatum(tuple);
3093
3094 JsObjectFree(&jso);
3095 }
3096
3097 /*
3098 * If it's domain over composite, check domain constraints. (This should
3099 * probably get refactored so that we can see the TYPECAT value, but for
3100 * now, we can tell by comparing typid to base_typid.)
3101 */
3102 if (typid != io->base_typid && typid != RECORDOID)
3103 {
3104 if (!domain_check_safe(result, *isnull, typid, &io->domain_info, mcxt,
3105 escontext))
3106 {
3107 *isnull = true;
3108 return (Datum) 0;
3109 }
3110 }
3111
3112 return result;
3113}
3114
3115/*
3116 * Populate non-null scalar value from json/jsonb value.
3117 *
3118 * Returns null if an error occurs during the call to type input function,
3119 * provided escontext is valid.
3120 */
3121static Datum
3123 bool *isnull, Node *escontext, bool omit_quotes)
3124{
3125 Datum res;
3126 char *str = NULL;
3127 const char *json = NULL;
3128
3129 if (jsv->is_json)
3130 {
3131 int len = jsv->val.json.len;
3132
3133 json = jsv->val.json.str;
3134 Assert(json);
3135
3136 /* If converting to json/jsonb, make string into valid JSON literal */
3137 if ((typid == JSONOID || typid == JSONBOID) &&
3139 {
3141
3143 if (len >= 0)
3144 escape_json_with_len(&buf, json, len);
3145 else
3146 escape_json(&buf, json);
3147 str = buf.data;
3148 }
3149 else if (len >= 0)
3150 {
3151 /* create a NUL-terminated version */
3152 str = palloc(len + 1);
3153 memcpy(str, json, len);
3154 str[len] = '\0';
3155 }
3156 else
3157 {
3158 /* string is already NUL-terminated */
3159 str = unconstify(char *, json);
3160 }
3161 }
3162 else
3163 {
3164 JsonbValue *jbv = jsv->val.jsonb;
3165
3166 if (jbv->type == jbvString && omit_quotes)
3167 str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3168 else if (typid == JSONBOID)
3169 {
3170 Jsonb *jsonb = JsonbValueToJsonb(jbv); /* directly use jsonb */
3171
3172 return JsonbPGetDatum(jsonb);
3173 }
3174 /* convert jsonb to string for typio call */
3175 else if (typid == JSONOID && jbv->type != jbvBinary)
3176 {
3177 /*
3178 * Convert scalar jsonb (non-scalars are passed here as jbvBinary)
3179 * to json string, preserving quotes around top-level strings.
3180 */
3181 Jsonb *jsonb = JsonbValueToJsonb(jbv);
3182
3183 str = JsonbToCString(NULL, &jsonb->root, VARSIZE(jsonb));
3184 }
3185 else if (jbv->type == jbvString) /* quotes are stripped */
3186 str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3187 else if (jbv->type == jbvBool)
3188 str = pstrdup(jbv->val.boolean ? "true" : "false");
3189 else if (jbv->type == jbvNumeric)
3191 PointerGetDatum(jbv->val.numeric)));
3192 else if (jbv->type == jbvBinary)
3193 str = JsonbToCString(NULL, jbv->val.binary.data,
3194 jbv->val.binary.len);
3195 else
3196 elog(ERROR, "unrecognized jsonb type: %d", (int) jbv->type);
3197 }
3198
3199 if (!InputFunctionCallSafe(&io->typiofunc, str, io->typioparam, typmod,
3200 escontext, &res))
3201 {
3202 res = (Datum) 0;
3203 *isnull = true;
3204 }
3205
3206 /* free temporary buffer */
3207 if (str != json)
3208 pfree(str);
3209
3210 return res;
3211}
3212
3213static Datum
3215 Oid typid,
3216 const char *colname,
3217 MemoryContext mcxt,
3218 JsValue *jsv,
3219 bool *isnull,
3220 Node *escontext,
3221 bool omit_quotes)
3222{
3223 Datum res;
3224
3225 if (*isnull)
3226 res = (Datum) 0;
3227 else
3228 {
3230 io->base_typid, io->base_typmod,
3231 colname, mcxt, PointerGetDatum(NULL),
3232 jsv, isnull, escontext, omit_quotes);
3233 Assert(!*isnull || SOFT_ERROR_OCCURRED(escontext));
3234 }
3235
3236 if (!domain_check_safe(res, *isnull, typid, &io->domain_info, mcxt,
3237 escontext))
3238 {
3239 *isnull = true;
3240 return (Datum) 0;
3241 }
3242
3243 return res;
3244}
3245
3246/* prepare column metadata cache for the given type */
3247static void
3249 Oid typid,
3250 int32 typmod,
3251 MemoryContext mcxt,
3252 bool need_scalar)
3253{
3254 HeapTuple tup;
3256
3257 column->typid = typid;
3258 column->typmod = typmod;
3259
3260 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3261 if (!HeapTupleIsValid(tup))
3262 elog(ERROR, "cache lookup failed for type %u", typid);
3263
3264 type = (Form_pg_type) GETSTRUCT(tup);
3265
3266 if (type->typtype == TYPTYPE_DOMAIN)
3267 {
3268 /*
3269 * We can move directly to the bottom base type; domain_check() will
3270 * take care of checking all constraints for a stack of domains.
3271 */
3272 Oid base_typid;
3273 int32 base_typmod = typmod;
3274
3275 base_typid = getBaseTypeAndTypmod(typid, &base_typmod);
3276 if (get_typtype(base_typid) == TYPTYPE_COMPOSITE)
3277 {
3278 /* domain over composite has its own code path */
3280 column->io.composite.record_io = NULL;
3281 column->io.composite.tupdesc = NULL;
3282 column->io.composite.base_typid = base_typid;
3283 column->io.composite.base_typmod = base_typmod;
3284 column->io.composite.domain_info = NULL;
3285 }
3286 else
3287 {
3288 /* domain over anything else */
3289 column->typcat = TYPECAT_DOMAIN;
3290 column->io.domain.base_typid = base_typid;
3291 column->io.domain.base_typmod = base_typmod;
3292 column->io.domain.base_io =
3293 MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3294 column->io.domain.domain_info = NULL;
3295 }
3296 }
3297 else if (type->typtype == TYPTYPE_COMPOSITE || typid == RECORDOID)
3298 {
3299 column->typcat = TYPECAT_COMPOSITE;
3300 column->io.composite.record_io = NULL;
3301 column->io.composite.tupdesc = NULL;
3302 column->io.composite.base_typid = typid;
3303 column->io.composite.base_typmod = typmod;
3304 column->io.composite.domain_info = NULL;
3305 }
3306 else if (IsTrueArrayType(type))
3307 {
3308 column->typcat = TYPECAT_ARRAY;
3310 sizeof(ColumnIOData));
3311 column->io.array.element_type = type->typelem;
3312 /* array element typemod stored in attribute's typmod */
3313 column->io.array.element_typmod = typmod;
3314 }
3315 else
3316 {
3317 column->typcat = TYPECAT_SCALAR;
3318 need_scalar = true;
3319 }
3320
3321 /* caller can force us to look up scalar_io info even for non-scalars */
3322 if (need_scalar)
3323 {
3324 Oid typioproc;
3325
3326 getTypeInputInfo(typid, &typioproc, &column->scalar_io.typioparam);
3327 fmgr_info_cxt(typioproc, &column->scalar_io.typiofunc, mcxt);
3328 }
3329
3330 ReleaseSysCache(tup);
3331}
3332
3333/*
3334 * Populate and return the value of specified type from a given json/jsonb
3335 * value 'json_val'. 'cache' is caller-specified pointer to save the
3336 * ColumnIOData that will be initialized on the 1st call and then reused
3337 * during any subsequent calls. 'mcxt' gives the memory context to allocate
3338 * the ColumnIOData and any other subsidiary memory in. 'escontext',
3339 * if not NULL, tells that any errors that occur should be handled softly.
3340 */
3341Datum
3342json_populate_type(Datum json_val, Oid json_type,
3343 Oid typid, int32 typmod,
3344 void **cache, MemoryContext mcxt,
3345 bool *isnull, bool omit_quotes,
3346 Node *escontext)
3347{
3348 JsValue jsv = {0};
3349 JsonbValue jbv;
3350
3351 jsv.is_json = json_type == JSONOID;
3352
3353 if (*isnull)
3354 {
3355 if (jsv.is_json)
3356 jsv.val.json.str = NULL;
3357 else
3358 jsv.val.jsonb = NULL;
3359 }
3360 else if (jsv.is_json)
3361 {
3362 text *json = DatumGetTextPP(json_val);
3363
3364 jsv.val.json.str = VARDATA_ANY(json);
3365 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3366 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3367 * populate_composite() */
3368 }
3369 else
3370 {
3371 Jsonb *jsonb = DatumGetJsonbP(json_val);
3372
3373 jsv.val.jsonb = &jbv;
3374
3375 if (omit_quotes)
3376 {
3377 char *str = JsonbUnquote(DatumGetJsonbP(json_val));
3378
3379 /* fill the quote-stripped string */
3380 jbv.type = jbvString;
3381 jbv.val.string.len = strlen(str);
3382 jbv.val.string.val = str;
3383 }
3384 else
3385 {
3386 /* fill binary jsonb value pointing to jb */
3387 jbv.type = jbvBinary;
3388 jbv.val.binary.data = &jsonb->root;
3389 jbv.val.binary.len = VARSIZE(jsonb) - VARHDRSZ;
3390 }
3391 }
3392
3393 if (*cache == NULL)
3394 *cache = MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3395
3396 return populate_record_field(*cache, typid, typmod, NULL, mcxt,
3397 PointerGetDatum(NULL), &jsv, isnull,
3398 escontext, omit_quotes);
3399}
3400
3401/* recursively populate a record field or an array element from a json/jsonb value */
3402static Datum
3404 Oid typid,
3405 int32 typmod,
3406 const char *colname,
3407 MemoryContext mcxt,
3408 Datum defaultval,
3409 JsValue *jsv,
3410 bool *isnull,
3411 Node *escontext,
3412 bool omit_scalar_quotes)
3413{
3414 TypeCat typcat;
3415
3417
3418 /*
3419 * Prepare column metadata cache for the given type. Force lookup of the
3420 * scalar_io data so that the json string hack below will work.
3421 */
3422 if (col->typid != typid || col->typmod != typmod)
3423 prepare_column_cache(col, typid, typmod, mcxt, true);
3424
3425 *isnull = JsValueIsNull(jsv);
3426
3427 typcat = col->typcat;
3428
3429 /* try to convert json string to a non-scalar type through input function */
3430 if (JsValueIsString(jsv) &&
3431 (typcat == TYPECAT_ARRAY ||
3432 typcat == TYPECAT_COMPOSITE ||
3433 typcat == TYPECAT_COMPOSITE_DOMAIN))
3434 typcat = TYPECAT_SCALAR;
3435
3436 /* we must perform domain checks for NULLs, otherwise exit immediately */
3437 if (*isnull &&
3438 typcat != TYPECAT_DOMAIN &&
3439 typcat != TYPECAT_COMPOSITE_DOMAIN)
3440 return (Datum) 0;
3441
3442 switch (typcat)
3443 {
3444 case TYPECAT_SCALAR:
3445 return populate_scalar(&col->scalar_io, typid, typmod, jsv,
3446 isnull, escontext, omit_scalar_quotes);
3447
3448 case TYPECAT_ARRAY:
3449 return populate_array(&col->io.array, colname, mcxt, jsv,
3450 isnull, escontext);
3451
3452 case TYPECAT_COMPOSITE:
3454 return populate_composite(&col->io.composite, typid,
3455 colname, mcxt,
3456 DatumGetPointer(defaultval)
3457 ? DatumGetHeapTupleHeader(defaultval)
3458 : NULL,
3459 jsv, isnull,
3460 escontext);
3461
3462 case TYPECAT_DOMAIN:
3463 return populate_domain(&col->io.domain, typid, colname, mcxt,
3464 jsv, isnull, escontext, omit_scalar_quotes);
3465
3466 default:
3467 elog(ERROR, "unrecognized type category '%c'", typcat);
3468 return (Datum) 0;
3469 }
3470}
3471
3472static RecordIOData *
3474{
3476 MemoryContextAlloc(mcxt,
3477 offsetof(RecordIOData, columns) +
3478 ncolumns * sizeof(ColumnIOData));
3479
3480 data->record_type = InvalidOid;
3481 data->record_typmod = 0;
3482 data->ncolumns = ncolumns;
3483 MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3484
3485 return data;
3486}
3487
3488static bool
3489JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
3490{
3491 jsv->is_json = obj->is_json;
3492
3493 if (jsv->is_json)
3494 {
3495 JsonHashEntry *hashentry = hash_search(obj->val.json_hash, field,
3496 HASH_FIND, NULL);
3497
3498 jsv->val.json.type = hashentry ? hashentry->type : JSON_TOKEN_NULL;
3499 jsv->val.json.str = jsv->val.json.type == JSON_TOKEN_NULL ? NULL :
3500 hashentry->val;
3501 jsv->val.json.len = jsv->val.json.str ? -1 : 0; /* null-terminated */
3502
3503 return hashentry != NULL;
3504 }
3505 else
3506 {
3507 jsv->val.jsonb = !obj->val.jsonb_cont ? NULL :
3508 getKeyJsonValueFromContainer(obj->val.jsonb_cont, field, strlen(field),
3509 NULL);
3510
3511 return jsv->val.jsonb != NULL;
3512 }
3513}
3514
3515/* populate a record tuple from json/jsonb value */
3516static HeapTupleHeader
3518 RecordIOData **record_p,
3519 HeapTupleHeader defaultval,
3520 MemoryContext mcxt,
3521 JsObject *obj,
3522 Node *escontext)
3523{
3524 RecordIOData *record = *record_p;
3525 Datum *values;
3526 bool *nulls;
3527 HeapTuple res;
3528 int ncolumns = tupdesc->natts;
3529 int i;
3530
3531 /*
3532 * if the input json is empty, we can only skip the rest if we were passed
3533 * in a non-null record, since otherwise there may be issues with domain
3534 * nulls.
3535 */
3536 if (defaultval && JsObjectIsEmpty(obj))
3537 return defaultval;
3538
3539 /* (re)allocate metadata cache */
3540 if (record == NULL ||
3541 record->ncolumns != ncolumns)
3542 *record_p = record = allocate_record_info(mcxt, ncolumns);
3543
3544 /* invalidate metadata cache if the record type has changed */
3545 if (record->record_type != tupdesc->tdtypeid ||
3546 record->record_typmod != tupdesc->tdtypmod)
3547 {
3548 MemSet(record, 0, offsetof(RecordIOData, columns) +
3549 ncolumns * sizeof(ColumnIOData));
3550 record->record_type = tupdesc->tdtypeid;
3551 record->record_typmod = tupdesc->tdtypmod;
3552 record->ncolumns = ncolumns;
3553 }
3554
3555 values = (Datum *) palloc(ncolumns * sizeof(Datum));
3556 nulls = (bool *) palloc(ncolumns * sizeof(bool));
3557
3558 if (defaultval)
3559 {
3560 HeapTupleData tuple;
3561
3562 /* Build a temporary HeapTuple control structure */
3563 tuple.t_len = HeapTupleHeaderGetDatumLength(defaultval);
3564 ItemPointerSetInvalid(&(tuple.t_self));
3565 tuple.t_tableOid = InvalidOid;
3566 tuple.t_data = defaultval;
3567
3568 /* Break down the tuple into fields */
3569 heap_deform_tuple(&tuple, tupdesc, values, nulls);
3570 }
3571 else
3572 {
3573 for (i = 0; i < ncolumns; ++i)
3574 {
3575 values[i] = (Datum) 0;
3576 nulls[i] = true;
3577 }
3578 }
3579
3580 for (i = 0; i < ncolumns; ++i)
3581 {
3582 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
3583 char *colname = NameStr(att->attname);
3584 JsValue field = {0};
3585 bool found;
3586
3587 /* Ignore dropped columns in datatype */
3588 if (att->attisdropped)
3589 {
3590 nulls[i] = true;
3591 continue;
3592 }
3593
3594 found = JsObjectGetField(obj, colname, &field);
3595
3596 /*
3597 * we can't just skip here if the key wasn't found since we might have
3598 * a domain to deal with. If we were passed in a non-null record
3599 * datum, we assume that the existing values are valid (if they're
3600 * not, then it's not our fault), but if we were passed in a null,
3601 * then every field which we don't populate needs to be run through
3602 * the input function just in case it's a domain type.
3603 */
3604 if (defaultval && !found)
3605 continue;
3606
3607 values[i] = populate_record_field(&record->columns[i],
3608 att->atttypid,
3609 att->atttypmod,
3610 colname,
3611 mcxt,
3612 nulls[i] ? (Datum) 0 : values[i],
3613 &field,
3614 &nulls[i],
3615 escontext,
3616 false);
3617 }
3618
3619 res = heap_form_tuple(tupdesc, values, nulls);
3620
3621 pfree(values);
3622 pfree(nulls);
3623
3624 return res->t_data;
3625}
3626
3627/*
3628 * Setup for json{b}_populate_record{set}: result type will be same as first
3629 * argument's type --- unless first argument is "null::record", which we can't
3630 * extract type info from; we handle that later.
3631 */
3632static void
3634 const char *funcname,
3635 PopulateRecordCache *cache)
3636{
3637 cache->argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
3638 prepare_column_cache(&cache->c,
3639 cache->argtype, -1,
3640 cache->fn_mcxt, false);
3641 if (cache->c.typcat != TYPECAT_COMPOSITE &&
3643 ereport(ERROR,
3644 (errcode(ERRCODE_DATATYPE_MISMATCH),
3645 /* translator: %s is a function name, eg json_to_record */
3646 errmsg("first argument of %s must be a row type",
3647 funcname)));
3648}
3649
3650/*
3651 * Setup for json{b}_to_record{set}: result type is specified by calling
3652 * query. We'll also use this code for json{b}_populate_record{set},
3653 * if we discover that the first argument is a null of type RECORD.
3654 *
3655 * Here it is syntactically impossible to specify the target type
3656 * as domain-over-composite.
3657 */
3658static void
3660 const char *funcname,
3661 PopulateRecordCache *cache)
3662{
3663 TupleDesc tupdesc;
3664 MemoryContext old_cxt;
3665
3666 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3667 ereport(ERROR,
3668 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3669 /* translator: %s is a function name, eg json_to_record */
3670 errmsg("could not determine row type for result of %s",
3671 funcname),
3672 errhint("Provide a non-null record argument, "
3673 "or call the function in the FROM clause "
3674 "using a column definition list.")));
3675
3676 Assert(tupdesc);
3677 cache->argtype = tupdesc->tdtypeid;
3678
3679 /* If we go through this more than once, avoid memory leak */
3680 if (cache->c.io.composite.tupdesc)
3682
3683 /* Save identified tupdesc */
3684 old_cxt = MemoryContextSwitchTo(cache->fn_mcxt);
3685 cache->c.io.composite.tupdesc = CreateTupleDescCopy(tupdesc);
3686 cache->c.io.composite.base_typid = tupdesc->tdtypeid;
3687 cache->c.io.composite.base_typmod = tupdesc->tdtypmod;
3688 MemoryContextSwitchTo(old_cxt);
3689}
3690
3691/*
3692 * common worker for json{b}_populate_record() and json{b}_to_record()
3693 * is_json and have_record_arg identify the specific function
3694 */
3695static Datum
3697 bool is_json, bool have_record_arg,
3698 Node *escontext)
3699{
3700 int json_arg_num = have_record_arg ? 1 : 0;
3701 JsValue jsv = {0};
3702 HeapTupleHeader rec;
3703 Datum rettuple;
3704 bool isnull;
3705 JsonbValue jbv;
3706 MemoryContext fnmcxt = fcinfo->flinfo->fn_mcxt;
3707 PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
3708
3709 /*
3710 * If first time through, identify input/result record type. Note that
3711 * this stanza looks only at fcinfo context, which can't change during the
3712 * query; so we may not be able to fully resolve a RECORD input type yet.
3713 */
3714 if (!cache)
3715 {
3716 fcinfo->flinfo->fn_extra = cache =
3717 MemoryContextAllocZero(fnmcxt, sizeof(*cache));
3718 cache->fn_mcxt = fnmcxt;
3719
3720 if (have_record_arg)
3722 else
3723 get_record_type_from_query(fcinfo, funcname, cache);
3724 }
3725
3726 /* Collect record arg if we have one */
3727 if (!have_record_arg)
3728 rec = NULL; /* it's json{b}_to_record() */
3729 else if (!PG_ARGISNULL(0))
3730 {
3732
3733 /*
3734 * When declared arg type is RECORD, identify actual record type from
3735 * the tuple itself.
3736 */
3737 if (cache->argtype == RECORDOID)
3738 {
3741 }
3742 }
3743 else
3744 {
3745 rec = NULL;
3746
3747 /*
3748 * When declared arg type is RECORD, identify actual record type from
3749 * calling query, or fail if we can't.
3750 */
3751 if (cache->argtype == RECORDOID)
3752 {
3753 get_record_type_from_query(fcinfo, funcname, cache);
3754 /* This can't change argtype, which is important for next time */
3755 Assert(cache->argtype == RECORDOID);
3756 }
3757 }
3758
3759 /* If no JSON argument, just return the record (if any) unchanged */
3760 if (PG_ARGISNULL(json_arg_num))
3761 {
3762 if (rec)
3763 PG_RETURN_POINTER(rec);
3764 else
3766 }
3767
3768 jsv.is_json = is_json;
3769
3770 if (is_json)
3771 {
3772 text *json = PG_GETARG_TEXT_PP(json_arg_num);
3773
3774 jsv.val.json.str = VARDATA_ANY(json);
3775 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3776 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3777 * populate_composite() */
3778 }
3779 else
3780 {
3781 Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
3782
3783 jsv.val.jsonb = &jbv;
3784
3785 /* fill binary jsonb value pointing to jb */
3786 jbv.type = jbvBinary;
3787 jbv.val.binary.data = &jb->root;
3788 jbv.val.binary.len = VARSIZE(jb) - VARHDRSZ;
3789 }
3790
3791 isnull = false;
3792 rettuple = populate_composite(&cache->c.io.composite, cache->argtype,
3793 NULL, fnmcxt, rec, &jsv, &isnull,
3794 escontext);
3795 Assert(!isnull || SOFT_ERROR_OCCURRED(escontext));
3796
3797 PG_RETURN_DATUM(rettuple);
3798}
3799
3800/*
3801 * get_json_object_as_hash
3802 *
3803 * Decomposes a json object into a hash table.
3804 *
3805 * Returns the hash table if the json is parsed successfully, NULL otherwise.
3806 */
3807static HTAB *
3808get_json_object_as_hash(const char *json, int len, const char *funcname,
3809 Node *escontext)
3810{
3811 HASHCTL ctl;
3812 HTAB *tab;
3815
3816 ctl.keysize = NAMEDATALEN;
3817 ctl.entrysize = sizeof(JsonHashEntry);
3819 tab = hash_create("json object hashtable",
3820 100,
3821 &ctl,
3823
3826
3827 state->function_name = funcname;
3828 state->hash = tab;
3829 state->lex = makeJsonLexContextCstringLen(NULL, json, len,
3830 GetDatabaseEncoding(), true);
3831
3832 sem->semstate = state;
3837
3838 if (!pg_parse_json_or_errsave(state->lex, sem, escontext))
3839 {
3840 hash_destroy(state->hash);
3841 tab = NULL;
3842 }
3843
3845
3846 return tab;
3847}
3848
3849static JsonParseErrorType
3850hash_object_field_start(void *state, char *fname, bool isnull)
3851{
3852 JHashState *_state = (JHashState *) state;
3853
3854 if (_state->lex->lex_level > 1)
3855 return JSON_SUCCESS;
3856
3857 /* remember token type */
3858 _state->saved_token_type = _state->lex->token_type;
3859
3860 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
3862 {
3863 /* remember start position of the whole text of the subobject */
3864 _state->save_json_start = _state->lex->token_start;
3865 }
3866 else
3867 {
3868 /* must be a scalar */
3869 _state->save_json_start = NULL;
3870 }
3871
3872 return JSON_SUCCESS;
3873}
3874
3875static JsonParseErrorType
3876hash_object_field_end(void *state, char *fname, bool isnull)
3877{
3878 JHashState *_state = (JHashState *) state;
3879 JsonHashEntry *hashentry;
3880 bool found;
3881
3882 /*
3883 * Ignore nested fields.
3884 */
3885 if (_state->lex->lex_level > 1)
3886 return JSON_SUCCESS;
3887
3888 /*
3889 * Ignore field names >= NAMEDATALEN - they can't match a record field.
3890 * (Note: without this test, the hash code would truncate the string at
3891 * NAMEDATALEN-1, and could then match against a similarly-truncated
3892 * record field name. That would be a reasonable behavior, but this code
3893 * has previously insisted on exact equality, so we keep this behavior.)
3894 */
3895 if (strlen(fname) >= NAMEDATALEN)
3896 return JSON_SUCCESS;
3897
3898 hashentry = hash_search(_state->hash, fname, HASH_ENTER, &found);
3899
3900 /*
3901 * found being true indicates a duplicate. We don't do anything about
3902 * that, a later field with the same name overrides the earlier field.
3903 */
3904
3905 hashentry->type = _state->saved_token_type;
3906 Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
3907
3908 if (_state->save_json_start != NULL)
3909 {
3910 int len = _state->lex->prev_token_terminator - _state->save_json_start;
3911 char *val = palloc((len + 1) * sizeof(char));
3912
3913 memcpy(val, _state->save_json_start, len);
3914 val[len] = '\0';
3915 hashentry->val = val;
3916 }
3917 else
3918 {
3919 /* must have had a scalar instead */
3920 hashentry->val = _state->saved_scalar;
3921 }
3922
3923 return JSON_SUCCESS;
3924}
3925
3926static JsonParseErrorType
3928{
3929 JHashState *_state = (JHashState *) state;
3930
3931 if (_state->lex->lex_level == 0)
3932 ereport(ERROR,
3933 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3934 errmsg("cannot call %s on an array", _state->function_name)));
3935
3936 return JSON_SUCCESS;
3937}
3938
3939static JsonParseErrorType
3940hash_scalar(void *state, char *token, JsonTokenType tokentype)
3941{
3942 JHashState *_state = (JHashState *) state;
3943
3944 if (_state->lex->lex_level == 0)
3945 ereport(ERROR,
3946 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3947 errmsg("cannot call %s on a scalar", _state->function_name)));
3948
3949 if (_state->lex->lex_level == 1)
3950 {
3951 _state->saved_scalar = token;
3952 /* saved_token_type must already be set in hash_object_field_start() */
3953 Assert(_state->saved_token_type == tokentype);
3954 }
3955
3956 return JSON_SUCCESS;
3957}
3958
3959
3960/*
3961 * SQL function json_populate_recordset
3962 *
3963 * set fields in a set of records from the argument json,
3964 * which must be an array of objects.
3965 *
3966 * similar to json_populate_record, but the tuple-building code
3967 * is pushed down into the semantic action handlers so it's done
3968 * per object in the array.
3969 */
3970Datum
3972{
3973 return populate_recordset_worker(fcinfo, "jsonb_populate_recordset",
3974 false, true);
3975}
3976
3977Datum
3979{
3980 return populate_recordset_worker(fcinfo, "jsonb_to_recordset",
3981 false, false);
3982}
3983
3984Datum
3986{
3987 return populate_recordset_worker(fcinfo, "json_populate_recordset",
3988 true, true);
3989}
3990
3991Datum
3993{
3994 return populate_recordset_worker(fcinfo, "json_to_recordset",
3995 true, false);
3996}
3997
3998static void
4000{
4001 PopulateRecordCache *cache = state->cache;
4002 HeapTupleHeader tuphead;
4003 HeapTupleData tuple;
4004
4005 /* acquire/update cached tuple descriptor */
4006 update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4007
4008 /* replace record fields from json */
4009 tuphead = populate_record(cache->c.io.composite.tupdesc,
4010 &cache->c.io.composite.record_io,
4011 state->rec,
4012 cache->fn_mcxt,
4013 obj,
4014 NULL);
4015
4016 /* if it's domain over composite, check domain constraints */
4017 if (cache->c.typcat == TYPECAT_COMPOSITE_DOMAIN)
4018 (void) domain_check_safe(HeapTupleHeaderGetDatum(tuphead), false,
4019 cache->argtype,
4020 &cache->c.io.composite.domain_info,
4021 cache->fn_mcxt,
4022 NULL);
4023
4024 /* ok, save into tuplestore */
4025 tuple.t_len = HeapTupleHeaderGetDatumLength(tuphead);
4026 ItemPointerSetInvalid(&(tuple.t_self));
4027 tuple.t_tableOid = InvalidOid;
4028 tuple.t_data = tuphead;
4029
4030 tuplestore_puttuple(state->tuple_store, &tuple);
4031}
4032
4033/*
4034 * common worker for json{b}_populate_recordset() and json{b}_to_recordset()
4035 * is_json and have_record_arg identify the specific function
4036 */
4037static Datum
4039 bool is_json, bool have_record_arg)
4040{
4041 int json_arg_num = have_record_arg ? 1 : 0;
4042 ReturnSetInfo *rsi;
4043 MemoryContext old_cxt;
4044 HeapTupleHeader rec;
4045 PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
4047
4048 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
4049
4050 if (!rsi || !IsA(rsi, ReturnSetInfo))
4051 ereport(ERROR,
4052 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4053 errmsg("set-valued function called in context that cannot accept a set")));
4054
4055 if (!(rsi->allowedModes & SFRM_Materialize))
4056 ereport(ERROR,
4057 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4058 errmsg("materialize mode required, but it is not allowed in this context")));
4059
4061
4062 /*
4063 * If first time through, identify input/result record type. Note that
4064 * this stanza looks only at fcinfo context, which can't change during the
4065 * query; so we may not be able to fully resolve a RECORD input type yet.
4066 */
4067 if (!cache)
4068 {
4069 fcinfo->flinfo->fn_extra = cache =
4070 MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, sizeof(*cache));
4071 cache->fn_mcxt = fcinfo->flinfo->fn_mcxt;
4072
4073 if (have_record_arg)
4075 else
4076 get_record_type_from_query(fcinfo, funcname, cache);
4077 }
4078
4079 /* Collect record arg if we have one */
4080 if (!have_record_arg)
4081 rec = NULL; /* it's json{b}_to_recordset() */
4082 else if (!PG_ARGISNULL(0))
4083 {
4085
4086 /*
4087 * When declared arg type is RECORD, identify actual record type from
4088 * the tuple itself.
4089 */
4090 if (cache->argtype == RECORDOID)
4091 {
4094 }
4095 }
4096 else
4097 {
4098 rec = NULL;
4099
4100 /*
4101 * When declared arg type is RECORD, identify actual record type from
4102 * calling query, or fail if we can't.
4103 */
4104 if (cache->argtype == RECORDOID)
4105 {
4106 get_record_type_from_query(fcinfo, funcname, cache);
4107 /* This can't change argtype, which is important for next time */
4108 Assert(cache->argtype == RECORDOID);
4109 }
4110 }
4111
4112 /* if the json is null send back an empty set */
4113 if (PG_ARGISNULL(json_arg_num))
4115
4116 /*
4117 * Forcibly update the cached tupdesc, to ensure we have the right tupdesc
4118 * to return even if the JSON contains no rows.
4119 */
4120 update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4121
4123
4124 /* make tuplestore in a sufficiently long-lived memory context */
4126 state->tuple_store = tuplestore_begin_heap(rsi->allowedModes &
4128 false, work_mem);
4129 MemoryContextSwitchTo(old_cxt);
4130
4131 state->function_name = funcname;
4132 state->cache = cache;
4133 state->rec = rec;
4134
4135 if (is_json)
4136 {
4137 text *json = PG_GETARG_TEXT_PP(json_arg_num);
4138 JsonLexContext lex;
4140
4142
4143 makeJsonLexContext(&lex, json, true);
4144
4145 sem->semstate = state;
4153
4154 state->lex = &lex;
4155
4157
4158 freeJsonLexContext(&lex);
4159 state->lex = NULL;
4160 }
4161 else
4162 {
4163 Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
4164 JsonbIterator *it;
4165 JsonbValue v;
4166 bool skipNested = false;
4168
4169 if (JB_ROOT_IS_SCALAR(jb) || !JB_ROOT_IS_ARRAY(jb))
4170 ereport(ERROR,
4171 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4172 errmsg("cannot call %s on a non-array",
4173 funcname)));
4174
4175 it = JsonbIteratorInit(&jb->root);
4176
4177 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4178 {
4179 skipNested = true;
4180
4181 if (r == WJB_ELEM)
4182 {
4183 JsObject obj;
4184
4185 if (v.type != jbvBinary ||
4186 !JsonContainerIsObject(v.val.binary.data))
4187 ereport(ERROR,
4188 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4189 errmsg("argument of %s must be an array of objects",
4190 funcname)));
4191
4192 obj.is_json = false;
4193 obj.val.jsonb_cont = v.val.binary.data;
4194
4196 }
4197 }
4198 }
4199
4200 /*
4201 * Note: we must copy the cached tupdesc because the executor will free
4202 * the passed-back setDesc, but we want to hang onto the cache in case
4203 * we're called again in the same query.
4204 */
4205 rsi->setResult = state->tuple_store;
4207
4209}
4210
4211static JsonParseErrorType
4213{
4215 int lex_level = _state->lex->lex_level;
4216 HASHCTL ctl;
4217
4218 /* Reject object at top level: we must have an array at level 0 */
4219 if (lex_level == 0)
4220 ereport(ERROR,
4221 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4222 errmsg("cannot call %s on an object",
4223 _state->function_name)));
4224
4225 /* Nested objects require no special processing */
4226 if (lex_level > 1)
4227 return JSON_SUCCESS;
4228
4229 /* Object at level 1: set up a new hash table for this object */
4230 ctl.keysize = NAMEDATALEN;
4231 ctl.entrysize = sizeof(JsonHashEntry);
4233 _state->json_hash = hash_create("json object hashtable",
4234 100,
4235 &ctl,
4237
4238 return JSON_SUCCESS;
4239}
4240
4241static JsonParseErrorType
4243{
4245 JsObject obj;
4246
4247 /* Nested objects require no special processing */
4248 if (_state->lex->lex_level > 1)
4249 return JSON_SUCCESS;
4250
4251 obj.is_json = true;
4252 obj.val.json_hash = _state->json_hash;
4253
4254 /* Otherwise, construct and return a tuple based on this level-1 object */
4255 populate_recordset_record(_state, &obj);
4256
4257 /* Done with hash for this object */
4258 hash_destroy(_state->json_hash);
4259 _state->json_hash = NULL;
4260
4261 return JSON_SUCCESS;
4262}
4263
4264static JsonParseErrorType
4266{
4268
4269 if (_state->lex->lex_level == 1 &&
4271 ereport(ERROR,
4272 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4273 errmsg("argument of %s must be an array of objects",
4274 _state->function_name)));
4275
4276 return JSON_SUCCESS;
4277}
4278
4279static JsonParseErrorType
4281{
4282 /* nothing to do */
4283 return JSON_SUCCESS;
4284}
4285
4286static JsonParseErrorType
4288{
4290
4291 if (_state->lex->lex_level == 0)
4292 ereport(ERROR,
4293 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4294 errmsg("cannot call %s on a scalar",
4295 _state->function_name)));
4296
4297 if (_state->lex->lex_level == 2)
4298 _state->saved_scalar = token;
4299
4300 return JSON_SUCCESS;
4301}
4302
4303static JsonParseErrorType
4304populate_recordset_object_field_start(void *state, char *fname, bool isnull)
4305{
4307
4308 if (_state->lex->lex_level > 2)
4309 return JSON_SUCCESS;
4310
4311 _state->saved_token_type = _state->lex->token_type;
4312
4313 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
4315 {
4316 _state->save_json_start = _state->lex->token_start;
4317 }
4318 else
4319 {
4320 _state->save_json_start = NULL;
4321 }
4322
4323 return JSON_SUCCESS;
4324}
4325
4326static JsonParseErrorType
4327populate_recordset_object_field_end(void *state, char *fname, bool isnull)
4328{
4330 JsonHashEntry *hashentry;
4331 bool found;
4332
4333 /*
4334 * Ignore nested fields.
4335 */
4336 if (_state->lex->lex_level > 2)
4337 return JSON_SUCCESS;
4338
4339 /*
4340 * Ignore field names >= NAMEDATALEN - they can't match a record field.
4341 * (Note: without this test, the hash code would truncate the string at
4342 * NAMEDATALEN-1, and could then match against a similarly-truncated
4343 * record field name. That would be a reasonable behavior, but this code
4344 * has previously insisted on exact equality, so we keep this behavior.)
4345 */
4346 if (strlen(fname) >= NAMEDATALEN)
4347 return JSON_SUCCESS;
4348
4349 hashentry = hash_search(_state->json_hash, fname, HASH_ENTER, &found);
4350
4351 /*
4352 * found being true indicates a duplicate. We don't do anything about
4353 * that, a later field with the same name overrides the earlier field.
4354 */
4355
4356 hashentry->type = _state->saved_token_type;
4357 Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
4358
4359 if (_state->save_json_start != NULL)
4360 {
4361 int len = _state->lex->prev_token_terminator - _state->save_json_start;
4362 char *val = palloc((len + 1) * sizeof(char));
4363
4364 memcpy(val, _state->save_json_start, len);
4365 val[len] = '\0';
4366 hashentry->val = val;
4367 }
4368 else
4369 {
4370 /* must have had a scalar instead */
4371 hashentry->val = _state->saved_scalar;
4372 }
4373
4374 return JSON_SUCCESS;
4375}
4376
4377/*
4378 * Semantic actions for json_strip_nulls.
4379 *
4380 * Simply repeat the input on the output unless we encounter
4381 * a null object field. State for this is set when the field
4382 * is started and reset when the scalar action (which must be next)
4383 * is called.
4384 */
4385
4386static JsonParseErrorType
4388{
4389 StripnullState *_state = (StripnullState *) state;
4390
4391 appendStringInfoCharMacro(_state->strval, '{');
4392
4393 return JSON_SUCCESS;
4394}
4395
4396static JsonParseErrorType
4398{
4399 StripnullState *_state = (StripnullState *) state;
4400
4401 appendStringInfoCharMacro(_state->strval, '}');
4402
4403 return JSON_SUCCESS;
4404}
4405
4406static JsonParseErrorType
4408{
4409 StripnullState *_state = (StripnullState *) state;
4410
4411 appendStringInfoCharMacro(_state->strval, '[');
4412
4413 return JSON_SUCCESS;
4414}
4415
4416static JsonParseErrorType
4418{
4419 StripnullState *_state = (StripnullState *) state;
4420
4421 appendStringInfoCharMacro(_state->strval, ']');
4422
4423 return JSON_SUCCESS;
4424}
4425
4426static JsonParseErrorType
4427sn_object_field_start(void *state, char *fname, bool isnull)
4428{
4429 StripnullState *_state = (StripnullState *) state;
4430
4431 if (isnull)
4432 {
4433 /*
4434 * The next thing must be a scalar or isnull couldn't be true, so
4435 * there is no danger of this state being carried down into a nested
4436 * object or array. The flag will be reset in the scalar action.
4437 */
4438 _state->skip_next_null = true;
4439 return JSON_SUCCESS;
4440 }
4441
4442 if (_state->strval->data[_state->strval->len - 1] != '{')
4443 appendStringInfoCharMacro(_state->strval, ',');
4444
4445 /*
4446 * Unfortunately we don't have the quoted and escaped string any more, so
4447 * we have to re-escape it.
4448 */
4449 escape_json(_state->strval, fname);
4450
4451 appendStringInfoCharMacro(_state->strval, ':');
4452
4453 return JSON_SUCCESS;
4454}
4455
4456static JsonParseErrorType
4458{
4459 StripnullState *_state = (StripnullState *) state;
4460
4461 /* If strip_in_arrays is enabled and this is a null, mark it for skipping */
4462 if (isnull && _state->strip_in_arrays)
4463 {
4464 _state->skip_next_null = true;
4465 return JSON_SUCCESS;
4466 }
4467
4468 /* Only add a comma if this is not the first valid element */
4469 if (_state->strval->len > 0 &&
4470 _state->strval->data[_state->strval->len - 1] != '[')
4471 {
4472 appendStringInfoCharMacro(_state->strval, ',');
4473 }
4474
4475 return JSON_SUCCESS;
4476}
4477
4478static JsonParseErrorType
4479sn_scalar(void *state, char *token, JsonTokenType tokentype)
4480{
4481 StripnullState *_state = (StripnullState *) state;
4482
4483 if (_state->skip_next_null)
4484 {
4485 Assert(tokentype == JSON_TOKEN_NULL);
4486 _state->skip_next_null = false;
4487 return JSON_SUCCESS;
4488 }
4489
4490 if (tokentype == JSON_TOKEN_STRING)
4491 escape_json(_state->strval, token);
4492 else
4494
4495 return JSON_SUCCESS;
4496}
4497
4498/*
4499 * SQL function json_strip_nulls(json) -> json
4500 */
4501Datum
4503{
4504 text *json = PG_GETARG_TEXT_PP(0);
4505 bool strip_in_arrays = PG_NARGS() == 2 ? PG_GETARG_BOOL(1) : false;
4507 StringInfoData strbuf;
4508 JsonLexContext lex;
4510
4513 initStringInfo(&strbuf);
4514
4515 state->lex = makeJsonLexContext(&lex, json, true);
4516 state->strval = &strbuf;
4517 state->skip_next_null = false;
4518 state->strip_in_arrays = strip_in_arrays;
4519
4520 sem->semstate = state;
4525 sem->scalar = sn_scalar;
4528
4530
4532 state->strval->len));
4533}
4534
4535/*
4536 * SQL function jsonb_strip_nulls(jsonb, bool) -> jsonb
4537 */
4538Datum
4540{
4541 Jsonb *jb = PG_GETARG_JSONB_P(0);
4542 bool strip_in_arrays = false;
4543 JsonbIterator *it;
4544 JsonbInState parseState = {0};
4545 JsonbValue v,
4546 k;
4548 bool last_was_key = false;
4549
4550 if (PG_NARGS() == 2)
4551 strip_in_arrays = PG_GETARG_BOOL(1);
4552
4553 if (JB_ROOT_IS_SCALAR(jb))
4555
4556 it = JsonbIteratorInit(&jb->root);
4557
4558 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
4559 {
4560 Assert(!(type == WJB_KEY && last_was_key));
4561
4562 if (type == WJB_KEY)
4563 {
4564 /* stash the key until we know if it has a null value */
4565 k = v;
4566 last_was_key = true;
4567 continue;
4568 }
4569
4570 if (last_was_key)
4571 {
4572 /* if the last element was a key this one can't be */
4573 last_was_key = false;
4574
4575 /* skip this field if value is null */
4576 if (type == WJB_VALUE && v.type == jbvNull)
4577 continue;
4578
4579 /* otherwise, do a delayed push of the key */
4580 pushJsonbValue(&parseState, WJB_KEY, &k);
4581 }
4582
4583 /* if strip_in_arrays is set, also skip null array elements */
4584 if (strip_in_arrays)
4585 if (type == WJB_ELEM && v.type == jbvNull)
4586 continue;
4587
4588 if (type == WJB_VALUE || type == WJB_ELEM)
4589 pushJsonbValue(&parseState, type, &v);
4590 else
4591 pushJsonbValue(&parseState, type, NULL);
4592 }
4593
4595}
4596
4597/*
4598 * SQL function jsonb_pretty (jsonb)
4599 *
4600 * Pretty-printed text for the jsonb
4601 */
4602Datum
4604{
4605 Jsonb *jb = PG_GETARG_JSONB_P(0);
4607
4609 JsonbToCStringIndent(&str, &jb->root, VARSIZE(jb));
4610
4612}
4613
4614/*
4615 * SQL function jsonb_concat (jsonb, jsonb)
4616 *
4617 * function for || operator
4618 */
4619Datum
4621{
4622 Jsonb *jb1 = PG_GETARG_JSONB_P(0);
4623 Jsonb *jb2 = PG_GETARG_JSONB_P(1);
4624 JsonbInState state = {0};
4625 JsonbIterator *it1,
4626 *it2;
4627
4628 /*
4629 * If one of the jsonb is empty, just return the other if it's not scalar
4630 * and both are of the same kind. If it's a scalar or they are of
4631 * different kinds we need to perform the concatenation even if one is
4632 * empty.
4633 */
4634 if (JB_ROOT_IS_OBJECT(jb1) == JB_ROOT_IS_OBJECT(jb2))
4635 {
4636 if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
4637 PG_RETURN_JSONB_P(jb2);
4638 else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
4639 PG_RETURN_JSONB_P(jb1);
4640 }
4641
4642 it1 = JsonbIteratorInit(&jb1->root);
4643 it2 = JsonbIteratorInit(&jb2->root);
4644
4645 IteratorConcat(&it1, &it2, &state);
4646
4648}
4649
4650
4651/*
4652 * SQL function jsonb_delete (jsonb, text)
4653 *
4654 * return a copy of the jsonb with the indicated item
4655 * removed.
4656 */
4657Datum
4659{
4660 Jsonb *in = PG_GETARG_JSONB_P(0);
4662 char *keyptr = VARDATA_ANY(key);
4663 int keylen = VARSIZE_ANY_EXHDR(key);
4664 JsonbInState pstate = {0};
4665 JsonbIterator *it;
4666 JsonbValue v;
4667 bool skipNested = false;
4669
4670 if (JB_ROOT_IS_SCALAR(in))
4671 ereport(ERROR,
4672 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4673 errmsg("cannot delete from scalar")));
4674
4675 if (JB_ROOT_COUNT(in) == 0)
4677
4678 it = JsonbIteratorInit(&in->root);
4679
4680 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4681 {
4682 skipNested = true;
4683
4684 if ((r == WJB_ELEM || r == WJB_KEY) &&
4685 (v.type == jbvString && keylen == v.val.string.len &&
4686 memcmp(keyptr, v.val.string.val, keylen) == 0))
4687 {
4688 /* skip corresponding value as well */
4689 if (r == WJB_KEY)
4690 (void) JsonbIteratorNext(&it, &v, true);
4691
4692 continue;
4693 }
4694
4695 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4696 }
4697
4699}
4700
4701/*
4702 * SQL function jsonb_delete (jsonb, variadic text[])
4703 *
4704 * return a copy of the jsonb with the indicated items
4705 * removed.
4706 */
4707Datum
4709{
4710 Jsonb *in = PG_GETARG_JSONB_P(0);
4712 Datum *keys_elems;
4713 bool *keys_nulls;
4714 int keys_len;
4715 JsonbInState pstate = {0};
4716 JsonbIterator *it;
4717 JsonbValue v;
4718 bool skipNested = false;
4720
4721 if (ARR_NDIM(keys) > 1)
4722 ereport(ERROR,
4723 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4724 errmsg("wrong number of array subscripts")));
4725
4726 if (JB_ROOT_IS_SCALAR(in))
4727 ereport(ERROR,
4728 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4729 errmsg("cannot delete from scalar")));
4730
4731 if (JB_ROOT_COUNT(in) == 0)
4733
4734 deconstruct_array_builtin(keys, TEXTOID, &keys_elems, &keys_nulls, &keys_len);
4735
4736 if (keys_len == 0)
4738
4739 it = JsonbIteratorInit(&in->root);
4740
4741 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4742 {
4743 skipNested = true;
4744
4745 if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString)
4746 {
4747 int i;
4748 bool found = false;
4749
4750 for (i = 0; i < keys_len; i++)
4751 {
4752 char *keyptr;
4753 int keylen;
4754
4755 if (keys_nulls[i])
4756 continue;
4757
4758 /* We rely on the array elements not being toasted */
4759 keyptr = VARDATA_ANY(DatumGetPointer(keys_elems[i]));
4760 keylen = VARSIZE_ANY_EXHDR(DatumGetPointer(keys_elems[i]));
4761 if (keylen == v.val.string.len &&
4762 memcmp(keyptr, v.val.string.val, keylen) == 0)
4763 {
4764 found = true;
4765 break;
4766 }
4767 }
4768 if (found)
4769 {
4770 /* skip corresponding value as well */
4771 if (r == WJB_KEY)
4772 (void) JsonbIteratorNext(&it, &v, true);
4773
4774 continue;
4775 }
4776 }
4777
4778 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4779 }
4780
4782}
4783
4784/*
4785 * SQL function jsonb_delete (jsonb, int)
4786 *
4787 * return a copy of the jsonb with the indicated item
4788 * removed. Negative int means count back from the
4789 * end of the items.
4790 */
4791Datum
4793{
4794 Jsonb *in = PG_GETARG_JSONB_P(0);
4795 int idx = PG_GETARG_INT32(1);
4796 JsonbInState pstate = {0};
4797 JsonbIterator *it;
4798 uint32 i = 0,
4799 n;
4800 JsonbValue v;
4802
4803 if (JB_ROOT_IS_SCALAR(in))
4804 ereport(ERROR,
4805 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4806 errmsg("cannot delete from scalar")));
4807
4808 if (JB_ROOT_IS_OBJECT(in))
4809 ereport(ERROR,
4810 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4811 errmsg("cannot delete from object using integer index")));
4812
4813 if (JB_ROOT_COUNT(in) == 0)
4815
4816 it = JsonbIteratorInit(&in->root);
4817
4818 r = JsonbIteratorNext(&it, &v, false);
4819 Assert(r == WJB_BEGIN_ARRAY);
4820 n = v.val.array.nElems;
4821
4822 if (idx < 0)
4823 {
4824 if (pg_abs_s32(idx) > n)
4825 idx = n;
4826 else
4827 idx = n + idx;
4828 }
4829
4830 if (idx >= n)
4832
4833 pushJsonbValue(&pstate, r, NULL);
4834
4835 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
4836 {
4837 if (r == WJB_ELEM)
4838 {
4839 if (i++ == idx)
4840 continue;
4841 }
4842
4843 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4844 }
4845
4847}
4848
4849/*
4850 * SQL function jsonb_set(jsonb, text[], jsonb, boolean)
4851 */
4852Datum
4854{
4855 Jsonb *in = PG_GETARG_JSONB_P(0);
4857 Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
4859 bool create = PG_GETARG_BOOL(3);
4860 Datum *path_elems;
4861 bool *path_nulls;
4862 int path_len;
4863 JsonbIterator *it;
4864 JsonbInState st = {0};
4865
4866 JsonbToJsonbValue(newjsonb, &newval);
4867
4868 if (ARR_NDIM(path) > 1)
4869 ereport(ERROR,
4870 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4871 errmsg("wrong number of array subscripts")));
4872
4873 if (JB_ROOT_IS_SCALAR(in))
4874 ereport(ERROR,
4875 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4876 errmsg("cannot set path in scalar")));
4877
4878 if (JB_ROOT_COUNT(in) == 0 && !create)
4880
4881 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4882
4883 if (path_len == 0)
4885
4886 it = JsonbIteratorInit(&in->root);
4887
4888 setPath(&it, path_elems, path_nulls, path_len, &st,
4889 0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4890
4892}
4893
4894
4895/*
4896 * SQL function jsonb_set_lax(jsonb, text[], jsonb, boolean, text)
4897 */
4898Datum
4900{
4901 /* Jsonb *in = PG_GETARG_JSONB_P(0); */
4902 /* ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); */
4903 /* Jsonb *newval = PG_GETARG_JSONB_P(2); */
4904 /* bool create = PG_GETARG_BOOL(3); */
4905 text *handle_null;
4906 char *handle_val;
4907
4908 if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
4910
4911 /* could happen if they pass in an explicit NULL */
4912 if (PG_ARGISNULL(4))
4913 ereport(ERROR,
4914 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4915 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4916
4917 /* if the new value isn't an SQL NULL just call jsonb_set */
4918 if (!PG_ARGISNULL(2))
4919 return jsonb_set(fcinfo);
4920
4921 handle_null = PG_GETARG_TEXT_P(4);
4922 handle_val = text_to_cstring(handle_null);
4923
4924 if (strcmp(handle_val, "raise_exception") == 0)
4925 {
4926 ereport(ERROR,
4927 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4928 errmsg("JSON value must not be null"),
4929 errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
4930 errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed.")));
4931 return (Datum) 0; /* silence stupider compilers */
4932 }
4933 else if (strcmp(handle_val, "use_json_null") == 0)
4934 {
4935 Datum newval;
4936
4938
4939 fcinfo->args[2].value = newval;
4940 fcinfo->args[2].isnull = false;
4941 return jsonb_set(fcinfo);
4942 }
4943 else if (strcmp(handle_val, "delete_key") == 0)
4944 {
4945 return jsonb_delete_path(fcinfo);
4946 }
4947 else if (strcmp(handle_val, "return_target") == 0)
4948 {
4949 Jsonb *in = PG_GETARG_JSONB_P(0);
4950
4952 }
4953 else
4954 {
4955 ereport(ERROR,
4956 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4957 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4958 return (Datum) 0; /* silence stupider compilers */
4959 }
4960}
4961
4962/*
4963 * SQL function jsonb_delete_path(jsonb, text[])
4964 */
4965Datum
4967{
4968 Jsonb *in = PG_GETARG_JSONB_P(0);
4970 Datum *path_elems;
4971 bool *path_nulls;
4972 int path_len;
4973 JsonbIterator *it;
4974 JsonbInState st = {0};
4975
4976 if (ARR_NDIM(path) > 1)
4977 ereport(ERROR,
4978 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4979 errmsg("wrong number of array subscripts")));
4980
4981 if (JB_ROOT_IS_SCALAR(in))
4982 ereport(ERROR,
4983 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4984 errmsg("cannot delete path in scalar")));
4985
4986 if (JB_ROOT_COUNT(in) == 0)
4988
4989 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4990
4991 if (path_len == 0)
4993
4994 it = JsonbIteratorInit(&in->root);
4995
4996 setPath(&it, path_elems, path_nulls, path_len, &st,
4997 0, NULL, JB_PATH_DELETE);
4998
5000}
5001
5002/*
5003 * SQL function jsonb_insert(jsonb, text[], jsonb, boolean)
5004 */
5005Datum
5007{
5008 Jsonb *in = PG_GETARG_JSONB_P(0);
5010 Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
5012 bool after = PG_GETARG_BOOL(3);
5013 Datum *path_elems;
5014 bool *path_nulls;
5015 int path_len;
5016 JsonbIterator *it;
5017 JsonbInState st = {0};
5018
5019 JsonbToJsonbValue(newjsonb, &newval);
5020
5021 if (ARR_NDIM(path) > 1)
5022 ereport(ERROR,
5023 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5024 errmsg("wrong number of array subscripts")));
5025
5026 if (JB_ROOT_IS_SCALAR(in))
5027 ereport(ERROR,
5028 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5029 errmsg("cannot set path in scalar")));
5030
5031 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
5032
5033 if (path_len == 0)
5035
5036 it = JsonbIteratorInit(&in->root);
5037
5038 setPath(&it, path_elems, path_nulls, path_len, &st, 0, &newval,
5040
5042}
5043
5044/*
5045 * Iterate over all jsonb objects and merge them into one.
5046 * The logic of this function copied from the same hstore function,
5047 * except the case, when it1 & it2 represents jbvObject.
5048 * In that case we just append the content of it2 to it1 without any
5049 * verifications.
5050 */
5051static void
5054{
5055 JsonbValue v1,
5056 v2;
5058 r2,
5059 rk1,
5060 rk2;
5061
5062 rk1 = JsonbIteratorNext(it1, &v1, false);
5063 rk2 = JsonbIteratorNext(it2, &v2, false);
5064
5065 /*
5066 * JsonbIteratorNext reports raw scalars as if they were single-element
5067 * arrays; hence we only need consider "object" and "array" cases here.
5068 */
5069 if (rk1 == WJB_BEGIN_OBJECT && rk2 == WJB_BEGIN_OBJECT)
5070 {
5071 /*
5072 * Both inputs are objects.
5073 *
5074 * Append all the tokens from v1 to res, except last WJB_END_OBJECT
5075 * (because res will not be finished yet).
5076 */
5077 pushJsonbValue(state, rk1, NULL);
5078 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_OBJECT)
5079 pushJsonbValue(state, r1, &v1);
5080
5081 /*
5082 * Append all the tokens from v2 to res, including last WJB_END_OBJECT
5083 * (the concatenation will be completed). Any duplicate keys will
5084 * automatically override the value from the first object.
5085 */
5086 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5087 pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
5088 }
5089 else if (rk1 == WJB_BEGIN_ARRAY && rk2 == WJB_BEGIN_ARRAY)
5090 {
5091 /*
5092 * Both inputs are arrays.
5093 */
5094 pushJsonbValue(state, rk1, NULL);
5095
5096 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5097 {
5098 Assert(r1 == WJB_ELEM);
5099 pushJsonbValue(state, r1, &v1);
5100 }
5101
5102 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_END_ARRAY)
5103 {
5104 Assert(r2 == WJB_ELEM);
5106 }
5107
5108 pushJsonbValue(state, WJB_END_ARRAY, NULL /* signal to sort */ );
5109 }
5110 else if (rk1 == WJB_BEGIN_OBJECT)
5111 {
5112 /*
5113 * We have object || array.
5114 */
5115 Assert(rk2 == WJB_BEGIN_ARRAY);
5116
5118
5120 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_DONE)
5121 pushJsonbValue(state, r1, r1 != WJB_END_OBJECT ? &v1 : NULL);
5122
5123 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5124 pushJsonbValue(state, r2, r2 != WJB_END_ARRAY ? &v2 : NULL);
5125 }
5126 else
5127 {
5128 /*
5129 * We have array || object.
5130 */
5131 Assert(rk1 == WJB_BEGIN_ARRAY);
5132 Assert(rk2 == WJB_BEGIN_OBJECT);
5133
5135
5136 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5137 pushJsonbValue(state, r1, &v1);
5138
5140 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5141 pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
5142
5144 }
5145}
5146
5147/*
5148 * Do most of the heavy work for jsonb_set/jsonb_insert
5149 *
5150 * If JB_PATH_DELETE bit is set in op_type, the element is to be removed.
5151 *
5152 * If any bit mentioned in JB_PATH_CREATE_OR_INSERT is set in op_type,
5153 * we create the new value if the key or array index does not exist.
5154 *
5155 * Bits JB_PATH_INSERT_BEFORE and JB_PATH_INSERT_AFTER in op_type
5156 * behave as JB_PATH_CREATE if new value is inserted in JsonbObject.
5157 *
5158 * If JB_PATH_FILL_GAPS bit is set, this will change an assignment logic in
5159 * case if target is an array. The assignment index will not be restricted by
5160 * number of elements in the array, and if there are any empty slots between
5161 * last element of the array and a new one they will be filled with nulls. If
5162 * the index is negative, it still will be considered an index from the end
5163 * of the array. Of a part of the path is not present and this part is more
5164 * than just one last element, this flag will instruct to create the whole
5165 * chain of corresponding objects and insert the value.
5166 *
5167 * JB_PATH_CONSISTENT_POSITION for an array indicates that the caller wants to
5168 * keep values with fixed indices. Indices for existing elements could be
5169 * changed (shifted forward) in case if the array is prepended with a new value
5170 * and a negative index out of the range, so this behavior will be prevented
5171 * and return an error.
5172 *
5173 * All path elements before the last must already exist
5174 * whatever bits in op_type are set, or nothing is done.
5175 */
5176static void
5177setPath(JsonbIterator **it, const Datum *path_elems,
5178 const bool *path_nulls, int path_len,
5179 JsonbInState *st, int level, JsonbValue *newval, int op_type)
5180{
5181 JsonbValue v;
5183
5185
5186 if (path_nulls[level])
5187 ereport(ERROR,
5188 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5189 errmsg("path element at position %d is null",
5190 level + 1)));
5191
5192 r = JsonbIteratorNext(it, &v, false);
5193
5194 switch (r)
5195 {
5196 case WJB_BEGIN_ARRAY:
5197
5198 /*
5199 * If instructed complain about attempts to replace within a raw
5200 * scalar value. This happens even when current level is equal to
5201 * path_len, because the last path key should also correspond to
5202 * an object or an array, not raw scalar.
5203 */
5204 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) &&
5205 v.val.array.rawScalar)
5206 ereport(ERROR,
5207 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5208 errmsg("cannot replace existing key"),
5209 errdetail("The path assumes key is a composite object, "
5210 "but it is a scalar value.")));
5211
5212 pushJsonbValue(st, r, NULL);
5213 setPathArray(it, path_elems, path_nulls, path_len, st, level,
5214 newval, v.val.array.nElems, op_type);
5215 r = JsonbIteratorNext(it, &v, false);
5216 Assert(r == WJB_END_ARRAY);
5217 pushJsonbValue(st, r, NULL);
5218 break;
5219 case WJB_BEGIN_OBJECT:
5220 pushJsonbValue(st, r, NULL);
5221 setPathObject(it, path_elems, path_nulls, path_len, st, level,
5222 newval, v.val.object.nPairs, op_type);
5223 r = JsonbIteratorNext(it, &v, true);
5224 Assert(r == WJB_END_OBJECT);
5225 pushJsonbValue(st, r, NULL);
5226 break;
5227 case WJB_ELEM:
5228 case WJB_VALUE:
5229
5230 /*
5231 * If instructed complain about attempts to replace within a
5232 * scalar value. This happens even when current level is equal to
5233 * path_len, because the last path key should also correspond to
5234 * an object or an array, not an element or value.
5235 */
5236 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1))
5237 ereport(ERROR,
5238 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5239 errmsg("cannot replace existing key"),
5240 errdetail("The path assumes key is a composite object, "
5241 "but it is a scalar value.")));
5242
5243 pushJsonbValue(st, r, &v);
5244 break;
5245 default:
5246 elog(ERROR, "unrecognized iterator result: %d", (int) r);
5247 break;
5248 }
5249}
5250
5251/*
5252 * Object walker for setPath
5253 */
5254static void
5255setPathObject(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls,
5256 int path_len, JsonbInState *st, int level,
5257 JsonbValue *newval, uint32 npairs, int op_type)
5258{
5259 text *pathelem = NULL;
5260 int i;
5261 JsonbValue k,
5262 v;
5263 bool done = false;
5264
5265 if (level >= path_len || path_nulls[level])
5266 done = true;
5267 else
5268 {
5269 /* The path Datum could be toasted, in which case we must detoast it */
5270 pathelem = DatumGetTextPP(path_elems[level]);
5271 }
5272
5273 /* empty object is a special case for create */
5274 if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
5275 (level == path_len - 1))
5276 {
5277 JsonbValue newkey;
5278
5279 newkey.type = jbvString;
5280 newkey.val.string.val = VARDATA_ANY(pathelem);
5281 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5282
5283 pushJsonbValue(st, WJB_KEY, &newkey);
5285 }
5286
5287 for (i = 0; i < npairs; i++)
5288 {
5289 JsonbIteratorToken r = JsonbIteratorNext(it, &k, true);
5290
5291 Assert(r == WJB_KEY);
5292
5293 if (!done &&
5294 k.val.string.len == VARSIZE_ANY_EXHDR(pathelem) &&
5295 memcmp(k.val.string.val, VARDATA_ANY(pathelem),
5296 k.val.string.len) == 0)
5297 {
5298 done = true;
5299
5300 if (level == path_len - 1)
5301 {
5302 /*
5303 * called from jsonb_insert(), it forbids redefining an
5304 * existing value
5305 */
5307 ereport(ERROR,
5308 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5309 errmsg("cannot replace existing key"),
5310 errhint("Try using the function jsonb_set "
5311 "to replace key value.")));
5312
5313 r = JsonbIteratorNext(it, &v, true); /* skip value */
5314 if (!(op_type & JB_PATH_DELETE))
5315 {
5316 pushJsonbValue(st, WJB_KEY, &k);
5318 }
5319 }
5320 else
5321 {
5322 pushJsonbValue(st, r, &k);
5323 setPath(it, path_elems, path_nulls, path_len,
5324 st, level + 1, newval, op_type);
5325 }
5326 }
5327 else
5328 {
5329 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done &&
5330 level == path_len - 1 && i == npairs - 1)
5331 {
5332 JsonbValue newkey;
5333
5334 newkey.type = jbvString;
5335 newkey.val.string.val = VARDATA_ANY(pathelem);
5336 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5337
5338 pushJsonbValue(st, WJB_KEY, &newkey);
5340 }
5341
5342 pushJsonbValue(st, r, &k);
5343 r = JsonbIteratorNext(it, &v, false);
5344 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5345 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5346 {
5347 int walking_level = 1;
5348
5349 while (walking_level != 0)
5350 {
5351 r = JsonbIteratorNext(it, &v, false);
5352
5353 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5354 ++walking_level;
5355 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5356 --walking_level;
5357
5358 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5359 }
5360 }
5361 }
5362 }
5363
5364 /*--
5365 * If we got here there are only few possibilities:
5366 * - no target path was found, and an open object with some keys/values was
5367 * pushed into the state
5368 * - an object is empty, only WJB_BEGIN_OBJECT is pushed
5369 *
5370 * In both cases if instructed to create the path when not present,
5371 * generate the whole chain of empty objects and insert the new value
5372 * there.
5373 */
5374 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5375 {
5376 JsonbValue newkey;
5377
5378 newkey.type = jbvString;
5379 newkey.val.string.val = VARDATA_ANY(pathelem);
5380 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5381
5382 pushJsonbValue(st, WJB_KEY, &newkey);
5383 push_path(st, level, path_elems, path_nulls, path_len, newval);
5384
5385 /* Result is closed with WJB_END_OBJECT outside of this function */
5386 }
5387}
5388
5389/*
5390 * Array walker for setPath
5391 */
5392static void
5393setPathArray(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls,
5394 int path_len, JsonbInState *st, int level,
5395 JsonbValue *newval, uint32 nelems, int op_type)
5396{
5397 JsonbValue v;
5398 int idx,
5399 i;
5400 bool done = false;
5401
5402 /* pick correct index */
5403 if (level < path_len && !path_nulls[level])
5404 {
5405 char *c = TextDatumGetCString(path_elems[level]);
5406 char *badp;
5407
5408 errno = 0;
5409 idx = strtoint(c, &badp, 10);
5410 if (badp == c || *badp != '\0' || errno != 0)
5411 ereport(ERROR,
5412 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
5413 errmsg("path element at position %d is not an integer: \"%s\"",
5414 level + 1, c)));
5415 }
5416 else
5417 idx = nelems;
5418
5419 if (idx < 0)
5420 {
5421 if (pg_abs_s32(idx) > nelems)
5422 {
5423 /*
5424 * If asked to keep elements position consistent, it's not allowed
5425 * to prepend the array.
5426 */
5427 if (op_type & JB_PATH_CONSISTENT_POSITION)
5428 ereport(ERROR,
5429 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5430 errmsg("path element at position %d is out of range: %d",
5431 level + 1, idx)));
5432 else
5433 idx = PG_INT32_MIN;
5434 }
5435 else
5436 idx = nelems + idx;
5437 }
5438
5439 /*
5440 * Filling the gaps means there are no limits on the positive index are
5441 * imposed, we can set any element. Otherwise limit the index by nelems.
5442 */
5443 if (!(op_type & JB_PATH_FILL_GAPS))
5444 {
5445 if (idx > 0 && idx > nelems)
5446 idx = nelems;
5447 }
5448
5449 /*
5450 * if we're creating, and idx == INT_MIN, we prepend the new value to the
5451 * array also if the array is empty - in which case we don't really care
5452 * what the idx value is
5453 */
5454 if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) &&
5455 (op_type & JB_PATH_CREATE_OR_INSERT))
5456 {
5457 Assert(newval != NULL);
5458
5459 if (op_type & JB_PATH_FILL_GAPS && nelems == 0 && idx > 0)
5461
5463
5464 done = true;
5465 }
5466
5467 /* iterate over the array elements */
5468 for (i = 0; i < nelems; i++)
5469 {
5471
5472 if (i == idx && level < path_len)
5473 {
5474 done = true;
5475
5476 if (level == path_len - 1)
5477 {
5478 r = JsonbIteratorNext(it, &v, true); /* skip */
5479
5480 if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_CREATE))
5482
5483 /*
5484 * We should keep current value only in case of
5485 * JB_PATH_INSERT_BEFORE or JB_PATH_INSERT_AFTER because
5486 * otherwise it should be deleted or replaced
5487 */
5489 pushJsonbValue(st, r, &v);
5490
5491 if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE))
5493 }
5494 else
5495 setPath(it, path_elems, path_nulls, path_len,
5496 st, level + 1, newval, op_type);
5497 }
5498 else
5499 {
5500 r = JsonbIteratorNext(it, &v, false);
5501
5502 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5503
5504 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5505 {
5506 int walking_level = 1;
5507
5508 while (walking_level != 0)
5509 {
5510 r = JsonbIteratorNext(it, &v, false);
5511
5512 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5513 ++walking_level;
5514 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5515 --walking_level;
5516
5517 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5518 }
5519 }
5520 }
5521 }
5522
5523 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1)
5524 {
5525 /*
5526 * If asked to fill the gaps, idx could be bigger than nelems, so
5527 * prepend the new element with nulls if that's the case.
5528 */
5529 if (op_type & JB_PATH_FILL_GAPS && idx > nelems)
5530 push_null_elements(st, idx - nelems);
5531
5533 done = true;
5534 }
5535
5536 /*--
5537 * If we got here there are only few possibilities:
5538 * - no target path was found, and an open array with some keys/values was
5539 * pushed into the state
5540 * - an array is empty, only WJB_BEGIN_ARRAY is pushed
5541 *
5542 * In both cases if instructed to create the path when not present,
5543 * generate the whole chain of empty objects and insert the new value
5544 * there.
5545 */
5546 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5547 {
5548 if (idx > 0)
5549 push_null_elements(st, idx - nelems);
5550
5551 push_path(st, level, path_elems, path_nulls, path_len, newval);
5552
5553 /* Result is closed with WJB_END_OBJECT outside of this function */
5554 }
5555}
5556
5557/*
5558 * Parse information about what elements of a jsonb document we want to iterate
5559 * in functions iterate_json(b)_values. This information is presented in jsonb
5560 * format, so that it can be easily extended in the future.
5561 */
5562uint32
5564{
5565 JsonbIterator *it;
5566 JsonbValue v;
5568 uint32 flags = 0;
5569
5570 it = JsonbIteratorInit(&jb->root);
5571
5572 type = JsonbIteratorNext(&it, &v, false);
5573
5574 /*
5575 * We iterate over array (scalar internally is represented as array, so,
5576 * we will accept it too) to check all its elements. Flag names are
5577 * chosen the same as jsonb_typeof uses.
5578 */
5579 if (type != WJB_BEGIN_ARRAY)
5580 ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5581 errmsg("wrong flag type, only arrays and scalars are allowed")));
5582
5583 while ((type = JsonbIteratorNext(&it, &v, false)) == WJB_ELEM)
5584 {
5585 if (v.type != jbvString)
5586 ereport(ERROR,
5587 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5588 errmsg("flag array element is not a string"),
5589 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5590
5591 if (v.val.string.len == 3 &&
5592 pg_strncasecmp(v.val.string.val, "all", 3) == 0)
5593 flags |= jtiAll;
5594 else if (v.val.string.len == 3 &&
5595 pg_strncasecmp(v.val.string.val, "key", 3) == 0)
5596 flags |= jtiKey;
5597 else if (v.val.string.len == 6 &&
5598 pg_strncasecmp(v.val.string.val, "string", 6) == 0)
5599 flags |= jtiString;
5600 else if (v.val.string.len == 7 &&
5601 pg_strncasecmp(v.val.string.val, "numeric", 7) == 0)
5602 flags |= jtiNumeric;
5603 else if (v.val.string.len == 7 &&
5604 pg_strncasecmp(v.val.string.val, "boolean", 7) == 0)
5605 flags |= jtiBool;
5606 else
5607 ereport(ERROR,
5608 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5609 errmsg("wrong flag in flag array: \"%s\"",
5610 pnstrdup(v.val.string.val, v.val.string.len)),
5611 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5612 }
5613
5614 /* expect end of array now */
5615 if (type != WJB_END_ARRAY)
5616 elog(ERROR, "unexpected end of flag array");
5617
5618 /* get final WJB_DONE and free iterator */
5619 type = JsonbIteratorNext(&it, &v, false);
5620 if (type != WJB_DONE)
5621 elog(ERROR, "unexpected end of flag array");
5622
5623 return flags;
5624}
5625
5626/*
5627 * Iterate over jsonb values or elements, specified by flags, and pass them
5628 * together with an iteration state to a specified JsonIterateStringValuesAction.
5629 */
5630void
5633{
5634 JsonbIterator *it;
5635 JsonbValue v;
5637
5638 it = JsonbIteratorInit(&jb->root);
5639
5640 /*
5641 * Just recursively iterating over jsonb and call callback on all
5642 * corresponding elements
5643 */
5644 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5645 {
5646 if (type == WJB_KEY)
5647 {
5648 if (flags & jtiKey)
5649 action(state, v.val.string.val, v.val.string.len);
5650
5651 continue;
5652 }
5653 else if (!(type == WJB_VALUE || type == WJB_ELEM))
5654 {
5655 /* do not call callback for composite JsonbValue */
5656 continue;
5657 }
5658
5659 /* JsonbValue is a value of object or element of array */
5660 switch (v.type)
5661 {
5662 case jbvString:
5663 if (flags & jtiString)
5664 action(state, v.val.string.val, v.val.string.len);
5665 break;
5666 case jbvNumeric:
5667 if (flags & jtiNumeric)
5668 {
5669 char *val;
5670
5672 NumericGetDatum(v.val.numeric)));
5673
5674 action(state, val, strlen(val));
5675 pfree(val);
5676 }
5677 break;
5678 case jbvBool:
5679 if (flags & jtiBool)
5680 {
5681 if (v.val.boolean)
5682 action(state, "true", 4);
5683 else
5684 action(state, "false", 5);
5685 }
5686 break;
5687 default:
5688 /* do not call callback for composite JsonbValue */
5689 break;
5690 }
5691 }
5692}
5693
5694/*
5695 * Iterate over json values and elements, specified by flags, and pass them
5696 * together with an iteration state to a specified JsonIterateStringValuesAction.
5697 */
5698void
5699iterate_json_values(text *json, uint32 flags, void *action_state,
5701{
5702 JsonLexContext lex;
5705
5706 state->lex = makeJsonLexContext(&lex, json, true);
5707 state->action = action;
5708 state->action_state = action_state;
5709 state->flags = flags;
5710
5711 sem->semstate = state;
5714
5716 freeJsonLexContext(&lex);
5717}
5718
5719/*
5720 * An auxiliary function for iterate_json_values to invoke a specified
5721 * JsonIterateStringValuesAction for specified values.
5722 */
5723static JsonParseErrorType
5725{
5727
5728 switch (tokentype)
5729 {
5730 case JSON_TOKEN_STRING:
5731 if (_state->flags & jtiString)
5732 _state->action(_state->action_state, token, strlen(token));
5733 break;
5734 case JSON_TOKEN_NUMBER:
5735 if (_state->flags & jtiNumeric)
5736 _state->action(_state->action_state, token, strlen(token));
5737 break;
5738 case JSON_TOKEN_TRUE:
5739 case JSON_TOKEN_FALSE:
5740 if (_state->flags & jtiBool)
5741 _state->action(_state->action_state, token, strlen(token));
5742 break;
5743 default:
5744 /* do not call callback for any other token */
5745 break;
5746 }
5747
5748 return JSON_SUCCESS;
5749}
5750
5751static JsonParseErrorType
5752iterate_values_object_field_start(void *state, char *fname, bool isnull)
5753{
5755
5756 if (_state->flags & jtiKey)
5757 {
5758 char *val = pstrdup(fname);
5759
5760 _state->action(_state->action_state, val, strlen(val));
5761 }
5762
5763 return JSON_SUCCESS;
5764}
5765
5766/*
5767 * Iterate over a jsonb, and apply a specified JsonTransformStringValuesAction
5768 * to every string value or element. Any necessary context for a
5769 * JsonTransformStringValuesAction can be passed in the action_state variable.
5770 * Function returns a copy of an original jsonb object with transformed values.
5771 */
5772Jsonb *
5773transform_jsonb_string_values(Jsonb *jsonb, void *action_state,
5774 JsonTransformStringValuesAction transform_action)
5775{
5776 JsonbIterator *it;
5777 JsonbValue v;
5779 JsonbInState st = {0};
5780 text *out;
5781 bool is_scalar = false;
5782
5783 it = JsonbIteratorInit(&jsonb->root);
5784 is_scalar = it->isScalar;
5785
5786 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5787 {
5788 if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
5789 {
5790 out = transform_action(action_state, v.val.string.val, v.val.string.len);
5791 /* out is probably not toasted, but let's be sure */
5792 out = pg_detoast_datum_packed(out);
5793 v.val.string.val = VARDATA_ANY(out);
5794 v.val.string.len = VARSIZE_ANY_EXHDR(out);
5795 pushJsonbValue(&st, type, type < WJB_BEGIN_ARRAY ? &v : NULL);
5796 }
5797 else
5798 {
5799 pushJsonbValue(&st, type, (type == WJB_KEY ||
5800 type == WJB_VALUE ||
5801 type == WJB_ELEM) ? &v : NULL);
5802 }
5803 }
5804
5805 if (st.result->type == jbvArray)
5806 st.result->val.array.rawScalar = is_scalar;
5807
5808 return JsonbValueToJsonb(st.result);
5809}
5810
5811/*
5812 * Iterate over a json, and apply a specified JsonTransformStringValuesAction
5813 * to every string value or element. Any necessary context for a
5814 * JsonTransformStringValuesAction can be passed in the action_state variable.
5815 * Function returns a Text Datum, which is a copy of an original json with
5816 * transformed values.
5817 */
5818text *
5819transform_json_string_values(text *json, void *action_state,
5820 JsonTransformStringValuesAction transform_action)
5821{
5822 JsonLexContext lex;
5825 StringInfoData strbuf;
5826
5827 initStringInfo(&strbuf);
5828
5829 state->lex = makeJsonLexContext(&lex, json, true);
5830 state->strval = &strbuf;
5831 state->action = transform_action;
5832 state->action_state = action_state;
5833
5834 sem->semstate = state;
5842
5844 freeJsonLexContext(&lex);
5845
5846 return cstring_to_text_with_len(state->strval->data, state->strval->len);
5847}
5848
5849/*
5850 * Set of auxiliary functions for transform_json_string_values to invoke a
5851 * specified JsonTransformStringValuesAction for all values and left everything
5852 * else untouched.
5853 */
5854static JsonParseErrorType
5856{
5858
5859 appendStringInfoCharMacro(_state->strval, '{');
5860
5861 return JSON_SUCCESS;
5862}
5863
5864static JsonParseErrorType
5866{
5868
5869 appendStringInfoCharMacro(_state->strval, '}');
5870
5871 return JSON_SUCCESS;
5872}
5873
5874static JsonParseErrorType
5876{
5878
5879 appendStringInfoCharMacro(_state->strval, '[');
5880
5881 return JSON_SUCCESS;
5882}
5883
5884static JsonParseErrorType
5886{
5888
5889 appendStringInfoCharMacro(_state->strval, ']');
5890
5891 return JSON_SUCCESS;
5892}
5893
5894static JsonParseErrorType
5896{
5898
5899 if (_state->strval->data[_state->strval->len - 1] != '{')
5900 appendStringInfoCharMacro(_state->strval, ',');
5901
5902 /*
5903 * Unfortunately we don't have the quoted and escaped string any more, so
5904 * we have to re-escape it.
5905 */
5906 escape_json(_state->strval, fname);
5907 appendStringInfoCharMacro(_state->strval, ':');
5908
5909 return JSON_SUCCESS;
5910}
5911
5912static JsonParseErrorType
5914{
5916
5917 if (_state->strval->data[_state->strval->len - 1] != '[')
5918 appendStringInfoCharMacro(_state->strval, ',');
5919
5920 return JSON_SUCCESS;
5921}
5922
5923static JsonParseErrorType
5925{
5927
5928 if (tokentype == JSON_TOKEN_STRING)
5929 {
5930 text *out = _state->action(_state->action_state, token, strlen(token));
5931
5932 escape_json_text(_state->strval, out);
5933 }
5934 else
5936
5937 return JSON_SUCCESS;
5938}
5939
5941json_get_first_token(text *json, bool throw_error)
5942{
5943 JsonLexContext lex;
5944 JsonParseErrorType result;
5945
5946 makeJsonLexContext(&lex, json, false);
5947
5948 /* Lex exactly one token from the input and check its type. */
5949 result = json_lex(&lex);
5950
5951 if (result == JSON_SUCCESS)
5952 return lex.token_type;
5953
5954 if (throw_error)
5955 json_errsave_error(result, &lex, NULL);
5956
5957 return JSON_TOKEN_INVALID; /* invalid json */
5958}
5959
5960/*
5961 * Determine how we want to print values of a given type in datum_to_json(b).
5962 *
5963 * Given the datatype OID, return its JsonTypeCategory, as well as the type's
5964 * output function OID. If the returned category is JSONTYPE_CAST, we return
5965 * the OID of the type->JSON cast function instead.
5966 */
5967void
5968json_categorize_type(Oid typoid, bool is_jsonb,
5969 JsonTypeCategory *tcategory, Oid *outfuncoid)
5970{
5971 bool typisvarlena;
5972
5973 /* Look through any domain */
5974 typoid = getBaseType(typoid);
5975
5976 *outfuncoid = InvalidOid;
5977
5978 switch (typoid)
5979 {
5980 case BOOLOID:
5981 *outfuncoid = F_BOOLOUT;
5982 *tcategory = JSONTYPE_BOOL;
5983 break;
5984
5985 case INT2OID:
5986 case INT4OID:
5987 case INT8OID:
5988 case FLOAT4OID:
5989 case FLOAT8OID:
5990 case NUMERICOID:
5991 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
5992 *tcategory = JSONTYPE_NUMERIC;
5993 break;
5994
5995 case DATEOID:
5996 *outfuncoid = F_DATE_OUT;
5997 *tcategory = JSONTYPE_DATE;
5998 break;
5999
6000 case TIMESTAMPOID:
6001 *outfuncoid = F_TIMESTAMP_OUT;
6002 *tcategory = JSONTYPE_TIMESTAMP;
6003 break;
6004
6005 case TIMESTAMPTZOID:
6006 *outfuncoid = F_TIMESTAMPTZ_OUT;
6007 *tcategory = JSONTYPE_TIMESTAMPTZ;
6008 break;
6009
6010 case JSONOID:
6011 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6012 *tcategory = JSONTYPE_JSON;
6013 break;
6014
6015 case JSONBOID:
6016 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6017 *tcategory = is_jsonb ? JSONTYPE_JSONB : JSONTYPE_JSON;
6018 break;
6019
6020 default:
6021 /* Check for arrays and composites */
6022 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
6023 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
6024 {
6025 *outfuncoid = F_ARRAY_OUT;
6026 *tcategory = JSONTYPE_ARRAY;
6027 }
6028 else if (type_is_rowtype(typoid)) /* includes RECORDOID */
6029 {
6030 *outfuncoid = F_RECORD_OUT;
6031 *tcategory = JSONTYPE_COMPOSITE;
6032 }
6033 else
6034 {
6035 /*
6036 * It's probably the general case. But let's look for a cast
6037 * to json (note: not to jsonb even if is_jsonb is true), if
6038 * it's not built-in.
6039 */
6040 *tcategory = JSONTYPE_OTHER;
6041 if (typoid >= FirstNormalObjectId)
6042 {
6043 Oid castfunc;
6044 CoercionPathType ctype;
6045
6046 ctype = find_coercion_pathway(JSONOID, typoid,
6048 &castfunc);
6049 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
6050 {
6051 *outfuncoid = castfunc;
6052 *tcategory = JSONTYPE_CAST;
6053 }
6054 else
6055 {
6056 /* non builtin type with no cast */
6057 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6058 }
6059 }
6060 else
6061 {
6062 /* any other builtin type */
6063 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6064 }
6065 }
6066 break;
6067 }
6068}
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:262
#define ARR_NDIM(a)
Definition: array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5351
bool array_contains_nulls(const ArrayType *array)
Definition: arrayfuncs.c:3768
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5453
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5294
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3698
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:799
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:765
#define unconstify(underlying_type, expr)
Definition: c.h:1243
#define IS_HIGHBIT_SET(ch)
Definition: c.h:1153
#define VARHDRSZ
Definition: c.h:711
#define FLEXIBLE_ARRAY_MEMBER
Definition: c.h:486
int32_t int32
Definition: c.h:548
uint32_t uint32
Definition: c.h:552
#define PG_INT32_MIN
Definition: c.h:607
#define MemSet(start, val, len)
Definition: c.h:1032
#define OidIsValid(objectId)
Definition: c.h:788
bool domain_check_safe(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt, Node *escontext)
Definition: domains.c:355
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:358
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1243
int errdetail(const char *fmt,...)
Definition: elog.c:1216
int errhint(const char *fmt,...)
Definition: elog.c:1330
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ereturn(context, dummy_value,...)
Definition: elog.h:278
#define errsave(context,...)
Definition: elog.h:262
#define errcontext
Definition: elog.h:198
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
Definition: execTuples.c:2413
@ SFRM_Materialize_Random
Definition: execnodes.h:342
@ SFRM_Materialize
Definition: execnodes.h:341
#define palloc_object(type)
Definition: fe_memutils.h:74
#define palloc_array(type, count)
Definition: fe_memutils.h:76
#define palloc0_array(type, count)
Definition: fe_memutils.h:77
#define palloc0_object(type)
Definition: fe_memutils.h:75
struct varlena * pg_detoast_datum_packed(struct varlena *datum)
Definition: fmgr.c:1829
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:138
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition: fmgr.c:1585
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1875
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define DatumGetTextPP(X)
Definition: fmgr.h:292
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_HEAPTUPLEHEADER(n)
Definition: fmgr.h:312
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_GETARG_TEXT_P(n)
Definition: fmgr.h:336
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
#define MAT_SRF_BLESS
Definition: funcapi.h:297
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
#define MAT_SRF_USE_EXPECTED_DESC
Definition: funcapi.h:296
int work_mem
Definition: globals.c:131
#define newval
Assert(PointerIsAligned(start, uint64))
return str start
const char * str
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1346
#define HASH_STRINGS
Definition: hsearch.h:96
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static int32 HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
Definition: htup_details.h:516
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
Definition: htup_details.h:492
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
Definition: htup_details.h:504
#define funcname
Definition: indent_codes.h:69
#define token
Definition: indent_globs.h:126
struct parser_state ps
long val
Definition: informix.c:689
static uint32 pg_abs_s32(int32 a)
Definition: int.h:221
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
void escape_json_text(StringInfo buf, const text *txt)
Definition: json.c:1738
void escape_json_with_len(StringInfo buf, const char *str, int len)
Definition: json.c:1633
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1604
JsonParseErrorType pg_parse_json(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:744
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
Definition: jsonapi.c:392
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:1588
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
Definition: jsonapi.c:2404
JsonParseErrorType json_count_array_elements(JsonLexContext *lex, int *elements)
Definition: jsonapi.c:803
void freeJsonLexContext(JsonLexContext *lex)
Definition: jsonapi.c:687
JsonParseErrorType
Definition: jsonapi.h:35
@ JSON_SEM_ACTION_FAILED
Definition: jsonapi.h:59
@ JSON_UNICODE_CODE_POINT_ZERO
Definition: jsonapi.h:53
@ JSON_SUCCESS
Definition: jsonapi.h:36
@ JSON_UNICODE_UNTRANSLATABLE
Definition: jsonapi.h:56
@ JSON_UNICODE_HIGH_ESCAPE
Definition: jsonapi.h:55
JsonTokenType
Definition: jsonapi.h:18
@ JSON_TOKEN_INVALID
Definition: jsonapi.h:19
@ JSON_TOKEN_FALSE
Definition: jsonapi.h:29
@ JSON_TOKEN_END
Definition: jsonapi.h:31
@ JSON_TOKEN_TRUE
Definition: jsonapi.h:28
@ JSON_TOKEN_NULL
Definition: jsonapi.h:30
@ JSON_TOKEN_OBJECT_START
Definition: jsonapi.h:22
@ JSON_TOKEN_NUMBER
Definition: jsonapi.h:21
@ JSON_TOKEN_STRING
Definition: jsonapi.h:20
@ JSON_TOKEN_ARRAY_START
Definition: jsonapi.h:24
char * JsonbUnquote(Jsonb *jb)
Definition: jsonb.c:2039
Datum jsonb_in(PG_FUNCTION_ARGS)
Definition: jsonb.c:65
char * JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len)
Definition: jsonb.c:466
char * JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
Definition: jsonb.c:475
jbvType
Definition: jsonb.h:228
@ jbvObject
Definition: jsonb.h:236
@ jbvNumeric
Definition: jsonb.h:232
@ jbvBool
Definition: jsonb.h:233
@ jbvArray
Definition: jsonb.h:235
@ jbvBinary
Definition: jsonb.h:238
@ jbvNull
Definition: jsonb.h:230
@ jbvString
Definition: jsonb.h:231
#define JsonContainerIsScalar(jc)
Definition: jsonb.h:209
#define JsonContainerIsArray(jc)
Definition: jsonb.h:211
#define JsonContainerSize(jc)
Definition: jsonb.h:208
#define JB_ROOT_IS_OBJECT(jbp_)
Definition: jsonb.h:223
static Datum JsonbPGetDatum(const Jsonb *p)
Definition: jsonb.h:413
#define IsAJsonbScalar(jsonbval)
Definition: jsonb.h:299
#define PG_RETURN_JSONB_P(x)
Definition: jsonb.h:420
#define JB_ROOT_IS_ARRAY(jbp_)
Definition: jsonb.h:224
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:418
#define JsonContainerIsObject(jc)
Definition: jsonb.h:210
static Jsonb * DatumGetJsonbP(Datum d)
Definition: jsonb.h:401
#define JB_ROOT_IS_SCALAR(jbp_)
Definition: jsonb.h:222
JsonbIteratorToken
Definition: jsonb.h:21
@ WJB_KEY
Definition: jsonb.h:23
@ WJB_DONE
Definition: jsonb.h:22
@ WJB_END_ARRAY
Definition: jsonb.h:27
@ WJB_VALUE
Definition: jsonb.h:24
@ WJB_END_OBJECT
Definition: jsonb.h:29
@ WJB_ELEM
Definition: jsonb.h:25
@ WJB_BEGIN_OBJECT
Definition: jsonb.h:28
@ WJB_BEGIN_ARRAY
Definition: jsonb.h:26
#define JB_ROOT_COUNT(jbp_)
Definition: jsonb.h:221
void pushJsonbValue(JsonbInState *pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition: jsonb_util.c:583
JsonbValue * getKeyJsonValueFromContainer(JsonbContainer *container, const char *keyVal, int keyLen, JsonbValue *res)
Definition: jsonb_util.c:402
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition: jsonb_util.c:935
void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val)
Definition: jsonb_util.c:76
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition: jsonb_util.c:973
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition: jsonb_util.c:472
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition: jsonb_util.c:96
Datum jsonb_populate_recordset(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:3971
JsonLexContext * makeJsonLexContext(JsonLexContext *lex, text *json, bool need_escapes)
Definition: jsonfuncs.c:540
static JsonParseErrorType get_array_element_end(void *state, bool isnull)
Definition: jsonfuncs.c:1401
static Datum elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition: jsonfuncs.c:2305
static JsonParseErrorType hash_array_start(void *state)
Definition: jsonfuncs.c:3927
Datum jsonb_object_keys(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:568
static JsonParseErrorType populate_recordset_array_start(void *state)
Definition: jsonfuncs.c:4280
static JsonParseErrorType transform_string_values_array_start(void *state)
Definition: jsonfuncs.c:5875
static JsonParseErrorType get_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:1197
static JsonParseErrorType elements_object_start(void *state)
Definition: jsonfuncs.c:2415
static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5895
Datum jsonb_array_elements(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2205
static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5752
struct PopulateArrayContext PopulateArrayContext
static void IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, JsonbInState *state)
Definition: jsonfuncs.c:5052
Datum json_each_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1959
static void push_path(JsonbInState *st, int level, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbValue *newval)
Definition: jsonfuncs.c:1720
Datum json_populate_recordset(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:3985
static JsonParseErrorType populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2750
text * transform_json_string_values(text *json, void *action_state, JsonTransformStringValuesAction transform_action)
Definition: jsonfuncs.c:5819
Datum jsonb_delete(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4658
struct TransformJsonStringValuesState TransformJsonStringValuesState
Datum json_populate_type(Datum json_val, Oid json_type, Oid typid, int32 typmod, void **cache, MemoryContext mcxt, bool *isnull, bool omit_quotes, Node *escontext)
Definition: jsonfuncs.c:3342
Datum jsonb_delete_array(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4708
Datum jsonb_pretty(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4603
static void setPathArray(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, uint32 nelems, int op_type)
Definition: jsonfuncs.c:5393
struct DomainIOData DomainIOData
static JsonParseErrorType transform_string_values_array_end(void *state)
Definition: jsonfuncs.c:5885
static JsonParseErrorType populate_recordset_object_start(void *state)
Definition: jsonfuncs.c:4212
static RecordIOData * allocate_record_info(MemoryContext mcxt, int ncolumns)
Definition: jsonfuncs.c:3473
static JsonParseErrorType iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5724
static text * JsonbValueAsText(JsonbValue *v)
Definition: jsonfuncs.c:1802
Datum jsonb_insert(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:5006
static JsonParseErrorType get_object_start(void *state)
Definition: jsonfuncs.c:1160
static JsonParseErrorType populate_recordset_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4304
static JsonParseErrorType populate_recordset_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4327
static JsonParseErrorType populate_array_object_start(void *_state)
Definition: jsonfuncs.c:2642
#define JsObjectIsEmpty(jso)
Definition: jsonfuncs.c:329
static void get_record_type_from_argument(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition: jsonfuncs.c:3633
Datum json_array_element(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:922
Datum jsonb_delete_idx(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4792
#define JB_PATH_DELETE
Definition: jsonfuncs.c:45
struct GetState GetState
static JsonParseErrorType sn_object_end(void *state)
Definition: jsonfuncs.c:4397
#define JB_PATH_CREATE_OR_INSERT
Definition: jsonfuncs.c:49
Datum jsonb_populate_record_valid(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2474
Datum json_array_elements_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2299
#define JB_PATH_CREATE
Definition: jsonfuncs.c:44
struct EachState EachState
static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:3940
static JsonParseErrorType sn_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:4457
static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg, Node *escontext)
Definition: jsonfuncs.c:3696
static HTAB * get_json_object_as_hash(const char *json, int len, const char *funcname, Node *escontext)
Definition: jsonfuncs.c:3808
static bool populate_array_json(PopulateArrayContext *ctx, const char *json, int len)
Definition: jsonfuncs.c:2786
struct StripnullState StripnullState
struct IterateJsonStringValuesState IterateJsonStringValuesState
#define JsValueIsString(jsv)
Definition: jsonfuncs.c:325
static JsonParseErrorType populate_recordset_object_end(void *state)
Definition: jsonfuncs.c:4242
static Datum populate_record_field(ColumnIOData *col, Oid typid, int32 typmod, const char *colname, MemoryContext mcxt, Datum defaultval, JsValue *jsv, bool *isnull, Node *escontext, bool omit_scalar_quotes)
Definition: jsonfuncs.c:3403
Datum jsonb_delete_path(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4966
struct JsValue JsValue
struct CompositeIOData CompositeIOData
static JsonParseErrorType each_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:2117
Datum jsonb_object_field_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:900
static Datum each_worker(FunctionCallInfo fcinfo, bool as_text)
Definition: jsonfuncs.c:2055
static JsonParseErrorType get_array_start(void *state)
Definition: jsonfuncs.c:1295
static JsonParseErrorType each_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2179
static int report_json_context(JsonLexContext *lex)
Definition: jsonfuncs.c:677
Datum json_strip_nulls(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4502
struct JsonHashEntry JsonHashEntry
Datum json_array_elements(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2293
Datum jsonb_concat(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4620
struct ArrayIOData ArrayIOData
static JsonParseErrorType okeys_array_start(void *state)
Definition: jsonfuncs.c:809
Datum json_object_field_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:884
uint32 parse_jsonb_index_flags(Jsonb *jb)
Definition: jsonfuncs.c:5563
Datum jsonb_extract_path_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1494
Datum json_each(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1947
static JsonParseErrorType alen_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:1911
Datum jsonb_set_element(Jsonb *jb, const Datum *path, int path_len, JsonbValue *newval)
Definition: jsonfuncs.c:1679
static JsonParseErrorType sn_object_start(void *state)
Definition: jsonfuncs.c:4387
static JsonParseErrorType sn_array_start(void *state)
Definition: jsonfuncs.c:4407
static bool populate_array_check_dimension(PopulateArrayContext *ctx, int ndim)
Definition: jsonfuncs.c:2587
static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition: jsonfuncs.c:1971
static JsonParseErrorType sn_array_end(void *state)
Definition: jsonfuncs.c:4417
static void setPathObject(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, uint32 npairs, int op_type)
Definition: jsonfuncs.c:5255
Datum json_to_recordset(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:3992
static JsonParseErrorType get_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:1445
#define JB_PATH_CONSISTENT_POSITION
Definition: jsonfuncs.c:52
static bool populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims)
Definition: jsonfuncs.c:2557
JsonTokenType json_get_first_token(text *json, bool throw_error)
Definition: jsonfuncs.c:5941
Datum jsonb_set(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4853
#define JsValueIsNull(jsv)
Definition: jsonfuncs.c:320
static void update_cached_tupdesc(CompositeIOData *io, MemoryContext mcxt)
Definition: jsonfuncs.c:3026
struct ColumnIOData ColumnIOData
Definition: jsonfuncs.c:162
void iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state, JsonIterateStringValuesAction action)
Definition: jsonfuncs.c:5631
static JsonParseErrorType populate_array_element_end(void *_state, bool isnull)
Definition: jsonfuncs.c:2707
Datum jsonb_set_lax(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4899
static JsonParseErrorType elements_array_element_end(void *state, bool isnull)
Definition: jsonfuncs.c:2369
static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4427
Datum jsonb_each_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1965
static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2430
struct ScalarIOData ScalarIOData
static JsonParseErrorType each_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:2095
Datum jsonb_strip_nulls(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4539
struct OkeysState OkeysState
struct PopulateArrayState PopulateArrayState
struct PopulateRecordCache PopulateRecordCache
Datum jsonb_extract_path(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1488
void json_categorize_type(Oid typoid, bool is_jsonb, JsonTypeCategory *tcategory, Oid *outfuncoid)
Definition: jsonfuncs.c:5968
static Datum populate_array(ArrayIOData *aio, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext)
Definition: jsonfuncs.c:2912
static JsonParseErrorType okeys_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:786
Datum jsonb_get_element(Jsonb *jb, const Datum *path, int npath, bool *isnull, bool as_text)
Definition: jsonfuncs.c:1531
Datum json_array_length(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1849
struct JHashState JHashState
void json_errsave_error(JsonParseErrorType error, JsonLexContext *lex, Node *escontext)
Definition: jsonfuncs.c:641
struct ElementsState ElementsState
Datum jsonb_array_length(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1875
Datum jsonb_object_field(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:862
static Datum elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition: jsonfuncs.c:2217
void iterate_json_values(text *json, uint32 flags, void *action_state, JsonIterateStringValuesAction action)
Definition: jsonfuncs.c:5699
Datum jsonb_populate_record(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2461
Datum json_extract_path(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1009
static void push_null_elements(JsonbInState *ps, int num)
Definition: jsonfuncs.c:1701
Datum json_extract_path_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1015
static JsonParseErrorType elements_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:2347
static void get_record_type_from_query(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition: jsonfuncs.c:3659
Datum json_populate_record(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2492
static JsonParseErrorType populate_recordset_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:4265
#define JB_PATH_FILL_GAPS
Definition: jsonfuncs.c:51
Jsonb * transform_jsonb_string_values(Jsonb *jsonb, void *action_state, JsonTransformStringValuesAction transform_action)
Definition: jsonfuncs.c:5773
static JsonParseErrorType transform_string_values_object_end(void *state)
Definition: jsonfuncs.c:5865
static bool JsValueToJsObject(JsValue *jsv, JsObject *jso, Node *escontext)
Definition: jsonfuncs.c:2979
Datum json_object_field(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:846
static JsonParseErrorType okeys_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:824
static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
Definition: jsonfuncs.c:1500
static void populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim)
Definition: jsonfuncs.c:2507
static JsonParseErrorType get_object_end(void *state)
Definition: jsonfuncs.c:1179
static Datum populate_composite(CompositeIOData *io, Oid typid, const char *colname, MemoryContext mcxt, HeapTupleHeader defaultval, JsValue *jsv, bool *isnull, Node *escontext)
Definition: jsonfuncs.c:3055
Datum jsonb_to_record(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2485
Datum jsonb_array_element(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:937
Datum json_object_keys(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:732
struct AlenState AlenState
#define JB_PATH_INSERT_BEFORE
Definition: jsonfuncs.c:47
static JsonParseErrorType populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:4287
static JsonParseErrorType get_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:1244
bool pg_parse_json_or_errsave(JsonLexContext *lex, const JsonSemAction *sem, Node *escontext)
Definition: jsonfuncs.c:519
static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text)
Definition: jsonfuncs.c:1024
static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg)
Definition: jsonfuncs.c:4038
static HeapTupleHeader populate_record(TupleDesc tupdesc, RecordIOData **record_p, HeapTupleHeader defaultval, MemoryContext mcxt, JsObject *obj, Node *escontext)
Definition: jsonfuncs.c:3517
static void setPath(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, int op_type)
Definition: jsonfuncs.c:5177
static JsonParseErrorType alen_object_start(void *state)
Definition: jsonfuncs.c:1897
static bool JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
Definition: jsonfuncs.c:3489
static bool populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv)
Definition: jsonfuncs.c:2615
static JsonParseErrorType populate_array_element_start(void *_state, bool isnull)
Definition: jsonfuncs.c:2689
static JsonParseErrorType populate_array_array_end(void *_state)
Definition: jsonfuncs.c:2665
static void prepare_column_cache(ColumnIOData *column, Oid typid, int32 typmod, MemoryContext mcxt, bool need_scalar)
Definition: jsonfuncs.c:3248
static JsonParseErrorType get_array_end(void *state)
Definition: jsonfuncs.c:1335
Datum jsonb_to_recordset(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:3978
static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:4479
#define JB_PATH_INSERT_AFTER
Definition: jsonfuncs.c:48
Datum jsonb_each(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1953
static JsonParseErrorType get_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:1353
static JsonParseErrorType hash_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:3876
#define JB_PATH_REPLACE
Definition: jsonfuncs.c:46
static void populate_recordset_record(PopulateRecordsetState *state, JsObject *obj)
Definition: jsonfuncs.c:3999
#define JsObjectFree(jso)
Definition: jsonfuncs.c:335
struct PopulateRecordsetState PopulateRecordsetState
static JsonParseErrorType transform_string_values_object_start(void *state)
Definition: jsonfuncs.c:5855
static JsonParseErrorType transform_string_values_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:5913
static JsonParseErrorType alen_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:1925
static Datum populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv, bool *isnull, Node *escontext, bool omit_quotes)
Definition: jsonfuncs.c:3122
static bool populate_array_dim_jsonb(PopulateArrayContext *ctx, JsonbValue *jbv, int ndim)
Definition: jsonfuncs.c:2822
Datum jsonb_array_element_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:980
TypeCat
Definition: jsonfuncs.c:200
@ TYPECAT_COMPOSITE
Definition: jsonfuncs.c:203
@ TYPECAT_SCALAR
Definition: jsonfuncs.c:201
@ TYPECAT_COMPOSITE_DOMAIN
Definition: jsonfuncs.c:204
@ TYPECAT_DOMAIN
Definition: jsonfuncs.c:205
@ TYPECAT_ARRAY
Definition: jsonfuncs.c:202
Datum json_to_record(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2499
static JsonParseErrorType each_array_start(void *state)
Definition: jsonfuncs.c:2165
Datum json_array_element_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:965
static Datum populate_domain(DomainIOData *io, Oid typid, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext, bool omit_quotes)
Definition: jsonfuncs.c:3214
static JsonParseErrorType transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5924
static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:3850
Datum jsonb_array_elements_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2211
static text * get_worker(text *json, char **tpath, int *ipath, int npath, bool normalize_results)
Definition: jsonfuncs.c:1103
struct JsObject JsObject
#define pg_parse_json_or_ereport(lex, sem)
Definition: jsonfuncs.h:47
@ jtiKey
Definition: jsonfuncs.h:27
@ jtiAll
Definition: jsonfuncs.h:31
@ jtiNumeric
Definition: jsonfuncs.h:29
@ jtiBool
Definition: jsonfuncs.h:30
@ jtiString
Definition: jsonfuncs.h:28
text *(* JsonTransformStringValuesAction)(void *state, char *elem_value, int elem_len)
Definition: jsonfuncs.h:38
void(* JsonIterateStringValuesAction)(void *state, char *elem_value, int elem_len)
Definition: jsonfuncs.h:35
JsonTypeCategory
Definition: jsonfuncs.h:69
@ JSONTYPE_JSON
Definition: jsonfuncs.h:76
@ JSONTYPE_TIMESTAMP
Definition: jsonfuncs.h:74
@ JSONTYPE_NUMERIC
Definition: jsonfuncs.h:72
@ JSONTYPE_DATE
Definition: jsonfuncs.h:73
@ JSONTYPE_BOOL
Definition: jsonfuncs.h:71
@ JSONTYPE_OTHER
Definition: jsonfuncs.h:81
@ JSONTYPE_CAST
Definition: jsonfuncs.h:80
@ JSONTYPE_COMPOSITE
Definition: jsonfuncs.h:79
@ JSONTYPE_ARRAY
Definition: jsonfuncs.h:78
@ JSONTYPE_TIMESTAMPTZ
Definition: jsonfuncs.h:75
@ JSONTYPE_JSONB
Definition: jsonfuncs.h:77
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2924
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2820
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:3072
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:3039
char get_typtype(Oid typid)
Definition: lsyscache.c:2794
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2703
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2686
int GetDatabaseEncoding(void)
Definition: mbutils.c:1264
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1026
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1229
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1263
char * pstrdup(const char *in)
Definition: mcxt.c:1759
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1610
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc(Size size)
Definition: mcxt.c:1365
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1770
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:469
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define SOFT_ERROR_OCCURRED(escontext)
Definition: miscnodes.h:53
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:76
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, Oid *funcid)
CoercionPathType
Definition: parse_coerce.h:25
@ COERCION_PATH_FUNC
Definition: parse_coerce.h:27
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
#define NAMEDATALEN
const void size_t len
const void * data
static char buf[DEFAULT_XLOG_SEG_SIZE]
Definition: pg_test_fsync.c:71
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:65
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
static Datum BoolGetDatum(bool X)
Definition: postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
static char * DatumGetCString(Datum X)
Definition: postgres.h:345
uint64_t Datum
Definition: postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
char * c
@ COERCION_EXPLICIT
Definition: primnodes.h:749
tree ctl
Definition: radixtree.h:1838
static chr element(struct vars *v, const chr *startp, const chr *endp)
Definition: regc_locale.c:376
static void error(void)
Definition: sql-dyntest.c:147
void check_stack_depth(void)
Definition: stack_depth.c:95
int strtoint(const char *restrict str, char **restrict endptr, int base)
Definition: string.c:50
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:231
int count
Definition: jsonfuncs.c:105
JsonLexContext * lex
Definition: jsonfuncs.c:104
int32 element_typmod
Definition: jsonfuncs.c:170
ColumnIOData * element_info
Definition: jsonfuncs.c:168
Oid element_type
Definition: jsonfuncs.c:169
CompositeIOData composite
Definition: jsonfuncs.c:221
TypeCat typcat
Definition: jsonfuncs.c:215
union ColumnIOData::@26 io
int32 typmod
Definition: jsonfuncs.c:214
ScalarIOData scalar_io
Definition: jsonfuncs.c:216
ArrayIOData array
Definition: jsonfuncs.c:220
DomainIOData domain
Definition: jsonfuncs.c:222
int32 base_typmod
Definition: jsonfuncs.c:184
RecordIOData * record_io
Definition: jsonfuncs.c:180
void * domain_info
Definition: jsonfuncs.c:186
TupleDesc tupdesc
Definition: jsonfuncs.c:181
void * domain_info
Definition: jsonfuncs.c:195
int32 base_typmod
Definition: jsonfuncs.c:194
Oid base_typid
Definition: jsonfuncs.c:193
ColumnIOData * base_io
Definition: jsonfuncs.c:192
bool normalize_results
Definition: jsonfuncs.c:116
TupleDesc ret_tdesc
Definition: jsonfuncs.c:113
char * normalized_scalar
Definition: jsonfuncs.c:118
JsonLexContext * lex
Definition: jsonfuncs.c:111
const char * result_start
Definition: jsonfuncs.c:115
Tuplestorestate * tuple_store
Definition: jsonfuncs.c:112
MemoryContext tmp_cxt
Definition: jsonfuncs.c:114
bool next_scalar
Definition: jsonfuncs.c:117
bool next_scalar
Definition: jsonfuncs.c:131
TupleDesc ret_tdesc
Definition: jsonfuncs.c:127
Tuplestorestate * tuple_store
Definition: jsonfuncs.c:126
bool normalize_results
Definition: jsonfuncs.c:130
MemoryContext tmp_cxt
Definition: jsonfuncs.c:128
JsonLexContext * lex
Definition: jsonfuncs.c:124
const char * function_name
Definition: jsonfuncs.c:125
const char * result_start
Definition: jsonfuncs.c:129
char * normalized_scalar
Definition: jsonfuncs.c:132
bool error_occurred
Definition: miscnodes.h:47
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:280
Definition: fmgr.h:57
void * fn_extra
Definition: fmgr.h:64
MemoryContext fn_mcxt
Definition: fmgr.h:65
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
FmgrInfo * flinfo
Definition: fmgr.h:87
bool next_scalar
Definition: jsonfuncs.c:92
int * path_indexes
Definition: jsonfuncs.c:95
char ** path_names
Definition: jsonfuncs.c:94
bool * pathok
Definition: jsonfuncs.c:96
const char * result_start
Definition: jsonfuncs.c:90
int * array_cur_index
Definition: jsonfuncs.c:97
text * tresult
Definition: jsonfuncs.c:89
JsonLexContext * lex
Definition: jsonfuncs.c:88
bool normalize_results
Definition: jsonfuncs.c:91
int npath
Definition: jsonfuncs.c:93
Definition: dynahash.c:222
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
JsonIterateStringValuesAction action
Definition: jsonfuncs.c:68
JsonLexContext * lex
Definition: jsonfuncs.c:67
char * saved_scalar
Definition: jsonfuncs.c:141
const char * save_json_start
Definition: jsonfuncs.c:142
const char * function_name
Definition: jsonfuncs.c:139
JsonTokenType saved_token_type
Definition: jsonfuncs.c:143
JsonLexContext * lex
Definition: jsonfuncs.c:138
HTAB * hash
Definition: jsonfuncs.c:140
bool is_json
Definition: jsonfuncs.c:311
JsonbContainer * jsonb_cont
Definition: jsonfuncs.c:315
HTAB * json_hash
Definition: jsonfuncs.c:314
union JsObject::@29 val
const char * str
Definition: jsonfuncs.c:300
union JsValue::@27 val
JsonbValue * jsonb
Definition: jsonfuncs.c:305
int len
Definition: jsonfuncs.c:301
JsonTokenType type
Definition: jsonfuncs.c:302
struct JsValue::@27::@28 json
bool is_json
Definition: jsonfuncs.c:295
char * val
Definition: jsonfuncs.c:150
char fname[NAMEDATALEN]
Definition: jsonfuncs.c:149
JsonTokenType type
Definition: jsonfuncs.c:151
const char * prev_token_terminator
Definition: jsonapi.h:107
const char * input
Definition: jsonapi.h:102
const char * token_start
Definition: jsonapi.h:105
size_t input_length
Definition: jsonapi.h:103
const char * line_start
Definition: jsonapi.h:113
int line_number
Definition: jsonapi.h:112
JsonTokenType token_type
Definition: jsonapi.h:109
const char * token_terminator
Definition: jsonapi.h:106
json_struct_action array_end
Definition: jsonapi.h:157
json_struct_action object_start
Definition: jsonapi.h:154
json_ofield_action object_field_start
Definition: jsonapi.h:158
json_aelem_action array_element_start
Definition: jsonapi.h:160
json_scalar_action scalar
Definition: jsonapi.h:162
void * semstate
Definition: jsonapi.h:153
json_aelem_action array_element_end
Definition: jsonapi.h:161
json_struct_action array_start
Definition: jsonapi.h:156
json_struct_action object_end
Definition: jsonapi.h:155
json_ofield_action object_field_end
Definition: jsonapi.h:159
JsonbValue * result
Definition: jsonb.h:333
bool isScalar
Definition: jsonb.h:374
enum jbvType type
Definition: jsonb.h:257
char * val
Definition: jsonb.h:266
Definition: jsonb.h:215
JsonbContainer root
Definition: jsonb.h:217
Definition: nodes.h:135
int result_size
Definition: jsonfuncs.c:59
char ** result
Definition: jsonfuncs.c:58
int result_count
Definition: jsonfuncs.c:60
int sent_count
Definition: jsonfuncs.c:61
JsonLexContext * lex
Definition: jsonfuncs.c:57
ArrayBuildState * astate
Definition: jsonfuncs.c:261
MemoryContext mcxt
Definition: jsonfuncs.c:264
ArrayIOData * aio
Definition: jsonfuncs.c:262
MemoryContext acxt
Definition: jsonfuncs.c:263
const char * colname
Definition: jsonfuncs.c:265
JsonTokenType element_type
Definition: jsonfuncs.c:280
JsonLexContext * lex
Definition: jsonfuncs.c:275
PopulateArrayContext * ctx
Definition: jsonfuncs.c:276
const char * element_start
Definition: jsonfuncs.c:277
char * element_scalar
Definition: jsonfuncs.c:278
ColumnIOData c
Definition: jsonfuncs.c:240
MemoryContext fn_mcxt
Definition: jsonfuncs.c:241
JsonLexContext * lex
Definition: jsonfuncs.c:247
HeapTupleHeader rec
Definition: jsonfuncs.c:254
const char * save_json_start
Definition: jsonfuncs.c:251
const char * function_name
Definition: jsonfuncs.c:248
Tuplestorestate * tuple_store
Definition: jsonfuncs.c:253
PopulateRecordCache * cache
Definition: jsonfuncs.c:255
JsonTokenType saved_token_type
Definition: jsonfuncs.c:252
ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER]
Definition: hstore_io.c:829
Oid record_type
Definition: hstore_io.c:824
int32 record_typmod
Definition: hstore_io.c:825
SetFunctionReturnMode returnMode
Definition: execnodes.h:360
ExprContext * econtext
Definition: execnodes.h:356
TupleDesc setDesc
Definition: execnodes.h:364
Tuplestorestate * setResult
Definition: execnodes.h:363
int allowedModes
Definition: execnodes.h:358
Oid typioparam
Definition: jsonfuncs.c:157
FmgrInfo typiofunc
Definition: jsonfuncs.c:158
bool skip_next_null
Definition: jsonfuncs.c:288
bool strip_in_arrays
Definition: jsonfuncs.c:289
JsonLexContext * lex
Definition: jsonfuncs.c:286
StringInfo strval
Definition: jsonfuncs.c:287
JsonTransformStringValuesAction action
Definition: jsonfuncs.c:80
int32 tdtypmod
Definition: tupdesc.h:139
Oid tdtypeid
Definition: tupdesc.h:138
Definition: type.h:96
Definition: regguts.h:323
Definition: c.h:706
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220
static JsonSemAction sem
#define FirstNormalObjectId
Definition: transam.h:197
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:502
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:252
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:219
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:330
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:764
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1921
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition: varatt.h:472
static Size VARSIZE(const void *PTR)
Definition: varatt.h:298
static char * VARDATA_ANY(const void *PTR)
Definition: varatt.h:486
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:193
text * cstring_to_text(const char *s)
Definition: varlena.c:181
char * text_to_cstring(const text *t)
Definition: varlena.c:214
const char * type