PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 */
480static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems,
481 bool *path_nulls, int path_len,
482 JsonbParseState **st, int level, JsonbValue *newval,
483 int op_type);
484static void setPathObject(JsonbIterator **it, Datum *path_elems,
485 bool *path_nulls, int path_len, JsonbParseState **st,
486 int level,
487 JsonbValue *newval, uint32 npairs, int op_type);
488static void setPathArray(JsonbIterator **it, Datum *path_elems,
489 bool *path_nulls, int path_len, JsonbParseState **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
596 state = palloc(sizeof(OkeysState));
597
598 state->result_size = JB_ROOT_COUNT(jb);
599 state->result_count = 0;
600 state->sent_count = 0;
601 state->result = palloc(state->result_size * sizeof(char *));
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
747 state = palloc(sizeof(OkeysState));
748 sem = palloc0(sizeof(JsonSemAction));
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(256 * sizeof(char *));
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(npath * sizeof(char *));
1049 ipath = palloc(npath * sizeof(int));
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{
1110 GetState *state = palloc0(sizeof(GetState));
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(sizeof(bool) * npath);
1122 state->array_cur_index = palloc(sizeof(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, 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, Datum *path, int path_len,
1681{
1682 JsonbValue *res;
1683 JsonbParseState *state = NULL;
1684 JsonbIterator *it;
1685 bool *path_nulls = palloc0(path_len * sizeof(bool));
1686
1687 if (newval->type == jbvArray && newval->val.array.rawScalar)
1688 *newval = newval->val.array.elems[0];
1689
1690 it = JsonbIteratorInit(&jb->root);
1691
1692 res = setPath(&it, path, path_nulls, path_len, &state, 0, newval,
1695
1696 pfree(path_nulls);
1697
1699}
1700
1701static void
1703{
1704 JsonbValue null;
1705
1706 null.type = jbvNull;
1707
1708 while (num-- > 0)
1709 pushJsonbValue(ps, WJB_ELEM, &null);
1710}
1711
1712/*
1713 * Prepare a new structure containing nested empty objects and arrays
1714 * corresponding to the specified path, and assign a new value at the end of
1715 * this path. E.g. the path [a][0][b] with the new value 1 will produce the
1716 * structure {a: [{b: 1}]}.
1717 *
1718 * Caller is responsible to make sure such path does not exist yet.
1719 */
1720static void
1721push_path(JsonbParseState **st, int level, Datum *path_elems,
1722 bool *path_nulls, int path_len, JsonbValue *newval)
1723{
1724 /*
1725 * tpath contains expected type of an empty jsonb created at each level
1726 * higher or equal than the current one, either jbvObject or jbvArray.
1727 * Since it contains only information about path slice from level to the
1728 * end, the access index must be normalized by level.
1729 */
1730 enum jbvType *tpath = palloc0((path_len - level) * sizeof(enum jbvType));
1731 JsonbValue newkey;
1732
1733 /*
1734 * Create first part of the chain with beginning tokens. For the current
1735 * level WJB_BEGIN_OBJECT/WJB_BEGIN_ARRAY was already created, so start
1736 * with the next one.
1737 */
1738 for (int i = level + 1; i < path_len; i++)
1739 {
1740 char *c,
1741 *badp;
1742 int lindex;
1743
1744 if (path_nulls[i])
1745 break;
1746
1747 /*
1748 * Try to convert to an integer to find out the expected type, object
1749 * or array.
1750 */
1751 c = TextDatumGetCString(path_elems[i]);
1752 errno = 0;
1753 lindex = strtoint(c, &badp, 10);
1754 if (badp == c || *badp != '\0' || errno != 0)
1755 {
1756 /* text, an object is expected */
1757 newkey.type = jbvString;
1758 newkey.val.string.val = c;
1759 newkey.val.string.len = strlen(c);
1760
1761 (void) pushJsonbValue(st, WJB_BEGIN_OBJECT, NULL);
1762 (void) pushJsonbValue(st, WJB_KEY, &newkey);
1763
1764 tpath[i - level] = jbvObject;
1765 }
1766 else
1767 {
1768 /* integer, an array is expected */
1769 (void) pushJsonbValue(st, WJB_BEGIN_ARRAY, NULL);
1770
1771 push_null_elements(st, lindex);
1772
1773 tpath[i - level] = jbvArray;
1774 }
1775 }
1776
1777 /* Insert an actual value for either an object or array */
1778 if (tpath[(path_len - level) - 1] == jbvArray)
1779 {
1780 (void) pushJsonbValue(st, WJB_ELEM, newval);
1781 }
1782 else
1783 (void) pushJsonbValue(st, WJB_VALUE, newval);
1784
1785 /*
1786 * Close everything up to the last but one level. The last one will be
1787 * closed outside of this function.
1788 */
1789 for (int i = path_len - 1; i > level; i--)
1790 {
1791 if (path_nulls[i])
1792 break;
1793
1794 if (tpath[i - level] == jbvObject)
1795 (void) pushJsonbValue(st, WJB_END_OBJECT, NULL);
1796 else
1797 (void) pushJsonbValue(st, WJB_END_ARRAY, NULL);
1798 }
1799}
1800
1801/*
1802 * Return the text representation of the given JsonbValue.
1803 */
1804static text *
1806{
1807 switch (v->type)
1808 {
1809 case jbvNull:
1810 return NULL;
1811
1812 case jbvBool:
1813 return v->val.boolean ?
1814 cstring_to_text_with_len("true", 4) :
1815 cstring_to_text_with_len("false", 5);
1816
1817 case jbvString:
1818 return cstring_to_text_with_len(v->val.string.val,
1819 v->val.string.len);
1820
1821 case jbvNumeric:
1822 {
1823 Datum cstr;
1824
1826 PointerGetDatum(v->val.numeric));
1827
1828 return cstring_to_text(DatumGetCString(cstr));
1829 }
1830
1831 case jbvBinary:
1832 {
1833 StringInfoData jtext;
1834
1835 initStringInfo(&jtext);
1836 (void) JsonbToCString(&jtext, v->val.binary.data,
1837 v->val.binary.len);
1838
1839 return cstring_to_text_with_len(jtext.data, jtext.len);
1840 }
1841
1842 default:
1843 elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
1844 return NULL;
1845 }
1846}
1847
1848/*
1849 * SQL function json_array_length(json) -> int
1850 */
1851Datum
1853{
1854 text *json = PG_GETARG_TEXT_PP(0);
1856 JsonLexContext lex;
1858
1859 state = palloc0(sizeof(AlenState));
1860 state->lex = makeJsonLexContext(&lex, json, false);
1861 /* palloc0 does this for us */
1862#if 0
1863 state->count = 0;
1864#endif
1865
1866 sem = palloc0(sizeof(JsonSemAction));
1867 sem->semstate = state;
1871
1873
1874 PG_RETURN_INT32(state->count);
1875}
1876
1877Datum
1879{
1880 Jsonb *jb = PG_GETARG_JSONB_P(0);
1881
1882 if (JB_ROOT_IS_SCALAR(jb))
1883 ereport(ERROR,
1884 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1885 errmsg("cannot get array length of a scalar")));
1886 else if (!JB_ROOT_IS_ARRAY(jb))
1887 ereport(ERROR,
1888 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1889 errmsg("cannot get array length of a non-array")));
1890
1892}
1893
1894/*
1895 * These next two checks ensure that the json is an array (since it can't be
1896 * a scalar or an object).
1897 */
1898
1899static JsonParseErrorType
1901{
1902 AlenState *_state = (AlenState *) state;
1903
1904 /* json structure check */
1905 if (_state->lex->lex_level == 0)
1906 ereport(ERROR,
1907 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1908 errmsg("cannot get array length of a non-array")));
1909
1910 return JSON_SUCCESS;
1911}
1912
1913static JsonParseErrorType
1914alen_scalar(void *state, char *token, JsonTokenType tokentype)
1915{
1916 AlenState *_state = (AlenState *) state;
1917
1918 /* json structure check */
1919 if (_state->lex->lex_level == 0)
1920 ereport(ERROR,
1921 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1922 errmsg("cannot get array length of a scalar")));
1923
1924 return JSON_SUCCESS;
1925}
1926
1927static JsonParseErrorType
1929{
1930 AlenState *_state = (AlenState *) state;
1931
1932 /* just count up all the level 1 elements */
1933 if (_state->lex->lex_level == 1)
1934 _state->count++;
1935
1936 return JSON_SUCCESS;
1937}
1938
1939/*
1940 * SQL function json_each and json_each_text
1941 *
1942 * decompose a json object into key value pairs.
1943 *
1944 * Unlike json_object_keys() these SRFs operate in materialize mode,
1945 * stashing results into a Tuplestore object as they go.
1946 * The construction of tuples is done using a temporary memory context
1947 * that is cleared out after each tuple is built.
1948 */
1949Datum
1951{
1952 return each_worker(fcinfo, false);
1953}
1954
1955Datum
1957{
1958 return each_worker_jsonb(fcinfo, "jsonb_each", false);
1959}
1960
1961Datum
1963{
1964 return each_worker(fcinfo, true);
1965}
1966
1967Datum
1969{
1970 return each_worker_jsonb(fcinfo, "jsonb_each_text", true);
1971}
1972
1973static Datum
1974each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
1975{
1976 Jsonb *jb = PG_GETARG_JSONB_P(0);
1977 ReturnSetInfo *rsi;
1978 MemoryContext old_cxt,
1979 tmp_cxt;
1980 bool skipNested = false;
1981 JsonbIterator *it;
1982 JsonbValue v;
1984
1985 if (!JB_ROOT_IS_OBJECT(jb))
1986 ereport(ERROR,
1987 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1988 errmsg("cannot call %s on a non-object",
1989 funcname)));
1990
1991 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1993
1995 "jsonb_each temporary cxt",
1997
1998 it = JsonbIteratorInit(&jb->root);
1999
2000 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
2001 {
2002 skipNested = true;
2003
2004 if (r == WJB_KEY)
2005 {
2006 text *key;
2007 Datum values[2];
2008 bool nulls[2] = {false, false};
2009
2010 /* Use the tmp context so we can clean up after each tuple is done */
2011 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2012
2013 key = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
2014
2015 /*
2016 * The next thing the iterator fetches should be the value, no
2017 * matter what shape it is.
2018 */
2019 r = JsonbIteratorNext(&it, &v, skipNested);
2020 Assert(r != WJB_DONE);
2021
2023
2024 if (as_text)
2025 {
2026 if (v.type == jbvNull)
2027 {
2028 /* a json null is an sql null in text mode */
2029 nulls[1] = true;
2030 values[1] = (Datum) NULL;
2031 }
2032 else
2034 }
2035 else
2036 {
2037 /* Not in text mode, just return the Jsonb */
2039
2041 }
2042
2043 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2044
2045 /* clean up and switch back */
2046 MemoryContextSwitchTo(old_cxt);
2047 MemoryContextReset(tmp_cxt);
2048 }
2049 }
2050
2051 MemoryContextDelete(tmp_cxt);
2052
2054}
2055
2056
2057static Datum
2058each_worker(FunctionCallInfo fcinfo, bool as_text)
2059{
2060 text *json = PG_GETARG_TEXT_PP(0);
2061 JsonLexContext lex;
2063 ReturnSetInfo *rsi;
2065
2066 state = palloc0(sizeof(EachState));
2067 sem = palloc0(sizeof(JsonSemAction));
2068
2069 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2070
2072 state->tuple_store = rsi->setResult;
2073 state->ret_tdesc = rsi->setDesc;
2074
2075 sem->semstate = state;
2080
2081 state->normalize_results = as_text;
2082 state->next_scalar = false;
2083 state->lex = makeJsonLexContext(&lex, json, true);
2085 "json_each temporary cxt",
2087
2089
2090 MemoryContextDelete(state->tmp_cxt);
2091 freeJsonLexContext(&lex);
2092
2094}
2095
2096
2097static JsonParseErrorType
2098each_object_field_start(void *state, char *fname, bool isnull)
2099{
2100 EachState *_state = (EachState *) state;
2101
2102 /* save a pointer to where the value starts */
2103 if (_state->lex->lex_level == 1)
2104 {
2105 /*
2106 * next_scalar will be reset in the object_field_end handler, and
2107 * since we know the value is a scalar there is no danger of it being
2108 * on while recursing down the tree.
2109 */
2110 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2111 _state->next_scalar = true;
2112 else
2113 _state->result_start = _state->lex->token_start;
2114 }
2115
2116 return JSON_SUCCESS;
2117}
2118
2119static JsonParseErrorType
2120each_object_field_end(void *state, char *fname, bool isnull)
2121{
2122 EachState *_state = (EachState *) state;
2123 MemoryContext old_cxt;
2124 int len;
2125 text *val;
2126 HeapTuple tuple;
2127 Datum values[2];
2128 bool nulls[2] = {false, false};
2129
2130 /* skip over nested objects */
2131 if (_state->lex->lex_level != 1)
2132 return JSON_SUCCESS;
2133
2134 /* use the tmp context so we can clean up after each tuple is done */
2135 old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2136
2137 values[0] = CStringGetTextDatum(fname);
2138
2139 if (isnull && _state->normalize_results)
2140 {
2141 nulls[1] = true;
2142 values[1] = (Datum) 0;
2143 }
2144 else if (_state->next_scalar)
2145 {
2147 _state->next_scalar = false;
2148 }
2149 else
2150 {
2151 len = _state->lex->prev_token_terminator - _state->result_start;
2154 }
2155
2156 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2157
2158 tuplestore_puttuple(_state->tuple_store, tuple);
2159
2160 /* clean up and switch back */
2161 MemoryContextSwitchTo(old_cxt);
2162 MemoryContextReset(_state->tmp_cxt);
2163
2164 return JSON_SUCCESS;
2165}
2166
2167static JsonParseErrorType
2169{
2170 EachState *_state = (EachState *) state;
2171
2172 /* json structure check */
2173 if (_state->lex->lex_level == 0)
2174 ereport(ERROR,
2175 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2176 errmsg("cannot deconstruct an array as an object")));
2177
2178 return JSON_SUCCESS;
2179}
2180
2181static JsonParseErrorType
2182each_scalar(void *state, char *token, JsonTokenType tokentype)
2183{
2184 EachState *_state = (EachState *) state;
2185
2186 /* json structure check */
2187 if (_state->lex->lex_level == 0)
2188 ereport(ERROR,
2189 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2190 errmsg("cannot deconstruct a scalar")));
2191
2192 /* supply de-escaped value if required */
2193 if (_state->next_scalar)
2194 _state->normalized_scalar = token;
2195
2196 return JSON_SUCCESS;
2197}
2198
2199/*
2200 * SQL functions json_array_elements and json_array_elements_text
2201 *
2202 * get the elements from a json array
2203 *
2204 * a lot of this processing is similar to the json_each* functions
2205 */
2206
2207Datum
2209{
2210 return elements_worker_jsonb(fcinfo, "jsonb_array_elements", false);
2211}
2212
2213Datum
2215{
2216 return elements_worker_jsonb(fcinfo, "jsonb_array_elements_text", true);
2217}
2218
2219static Datum
2221 bool as_text)
2222{
2223 Jsonb *jb = PG_GETARG_JSONB_P(0);
2224 ReturnSetInfo *rsi;
2225 MemoryContext old_cxt,
2226 tmp_cxt;
2227 bool skipNested = false;
2228 JsonbIterator *it;
2229 JsonbValue v;
2231
2232 if (JB_ROOT_IS_SCALAR(jb))
2233 ereport(ERROR,
2234 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2235 errmsg("cannot extract elements from a scalar")));
2236 else if (!JB_ROOT_IS_ARRAY(jb))
2237 ereport(ERROR,
2238 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2239 errmsg("cannot extract elements from an object")));
2240
2241 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2242
2244
2246 "jsonb_array_elements temporary cxt",
2248
2249 it = JsonbIteratorInit(&jb->root);
2250
2251 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
2252 {
2253 skipNested = true;
2254
2255 if (r == WJB_ELEM)
2256 {
2257 Datum values[1];
2258 bool nulls[1] = {false};
2259
2260 /* use the tmp context so we can clean up after each tuple is done */
2261 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2262
2263 if (as_text)
2264 {
2265 if (v.type == jbvNull)
2266 {
2267 /* a json null is an sql null in text mode */
2268 nulls[0] = true;
2269 values[0] = (Datum) NULL;
2270 }
2271 else
2273 }
2274 else
2275 {
2276 /* Not in text mode, just return the Jsonb */
2278
2280 }
2281
2282 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2283
2284 /* clean up and switch back */
2285 MemoryContextSwitchTo(old_cxt);
2286 MemoryContextReset(tmp_cxt);
2287 }
2288 }
2289
2290 MemoryContextDelete(tmp_cxt);
2291
2293}
2294
2295Datum
2297{
2298 return elements_worker(fcinfo, "json_array_elements", false);
2299}
2300
2301Datum
2303{
2304 return elements_worker(fcinfo, "json_array_elements_text", true);
2305}
2306
2307static Datum
2308elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
2309{
2310 text *json = PG_GETARG_TEXT_PP(0);
2311 JsonLexContext lex;
2313 ReturnSetInfo *rsi;
2315
2316 /* elements only needs escaped strings when as_text */
2317 makeJsonLexContext(&lex, json, as_text);
2318
2319 state = palloc0(sizeof(ElementsState));
2320 sem = palloc0(sizeof(JsonSemAction));
2321
2323 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2324 state->tuple_store = rsi->setResult;
2325 state->ret_tdesc = rsi->setDesc;
2326
2327 sem->semstate = state;
2332
2333 state->function_name = funcname;
2334 state->normalize_results = as_text;
2335 state->next_scalar = false;
2336 state->lex = &lex;
2338 "json_array_elements temporary cxt",
2340
2342
2343 MemoryContextDelete(state->tmp_cxt);
2344 freeJsonLexContext(&lex);
2345
2347}
2348
2349static JsonParseErrorType
2351{
2352 ElementsState *_state = (ElementsState *) state;
2353
2354 /* save a pointer to where the value starts */
2355 if (_state->lex->lex_level == 1)
2356 {
2357 /*
2358 * next_scalar will be reset in the array_element_end handler, and
2359 * since we know the value is a scalar there is no danger of it being
2360 * on while recursing down the tree.
2361 */
2362 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2363 _state->next_scalar = true;
2364 else
2365 _state->result_start = _state->lex->token_start;
2366 }
2367
2368 return JSON_SUCCESS;
2369}
2370
2371static JsonParseErrorType
2373{
2374 ElementsState *_state = (ElementsState *) state;
2375 MemoryContext old_cxt;
2376 int len;
2377 text *val;
2378 HeapTuple tuple;
2379 Datum values[1];
2380 bool nulls[1] = {false};
2381
2382 /* skip over nested objects */
2383 if (_state->lex->lex_level != 1)
2384 return JSON_SUCCESS;
2385
2386 /* use the tmp context so we can clean up after each tuple is done */
2387 old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2388
2389 if (isnull && _state->normalize_results)
2390 {
2391 nulls[0] = true;
2392 values[0] = (Datum) NULL;
2393 }
2394 else if (_state->next_scalar)
2395 {
2397 _state->next_scalar = false;
2398 }
2399 else
2400 {
2401 len = _state->lex->prev_token_terminator - _state->result_start;
2404 }
2405
2406 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2407
2408 tuplestore_puttuple(_state->tuple_store, tuple);
2409
2410 /* clean up and switch back */
2411 MemoryContextSwitchTo(old_cxt);
2412 MemoryContextReset(_state->tmp_cxt);
2413
2414 return JSON_SUCCESS;
2415}
2416
2417static JsonParseErrorType
2419{
2420 ElementsState *_state = (ElementsState *) state;
2421
2422 /* json structure check */
2423 if (_state->lex->lex_level == 0)
2424 ereport(ERROR,
2425 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2426 errmsg("cannot call %s on a non-array",
2427 _state->function_name)));
2428
2429 return JSON_SUCCESS;
2430}
2431
2432static JsonParseErrorType
2434{
2435 ElementsState *_state = (ElementsState *) state;
2436
2437 /* json structure check */
2438 if (_state->lex->lex_level == 0)
2439 ereport(ERROR,
2440 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2441 errmsg("cannot call %s on a scalar",
2442 _state->function_name)));
2443
2444 /* supply de-escaped value if required */
2445 if (_state->next_scalar)
2446 _state->normalized_scalar = token;
2447
2448 return JSON_SUCCESS;
2449}
2450
2451/*
2452 * SQL function json_populate_record
2453 *
2454 * set fields in a record from the argument json
2455 *
2456 * Code adapted shamelessly from hstore's populate_record
2457 * which is in turn partly adapted from record_out.
2458 *
2459 * The json is decomposed into a hash table, in which each
2460 * field in the record is then looked up by name. For jsonb
2461 * we fetch the values direct from the object.
2462 */
2463Datum
2465{
2466 return populate_record_worker(fcinfo, "jsonb_populate_record",
2467 false, true, NULL);
2468}
2469
2470/*
2471 * SQL function that can be used for testing json_populate_record().
2472 *
2473 * Returns false if json_populate_record() encounters an error for the
2474 * provided input JSON object, true otherwise.
2475 */
2476Datum
2478{
2479 ErrorSaveContext escontext = {T_ErrorSaveContext};
2480
2481 (void) populate_record_worker(fcinfo, "jsonb_populate_record",
2482 false, true, (Node *) &escontext);
2483
2484 return BoolGetDatum(!escontext.error_occurred);
2485}
2486
2487Datum
2489{
2490 return populate_record_worker(fcinfo, "jsonb_to_record",
2491 false, false, NULL);
2492}
2493
2494Datum
2496{
2497 return populate_record_worker(fcinfo, "json_populate_record",
2498 true, true, NULL);
2499}
2500
2501Datum
2503{
2504 return populate_record_worker(fcinfo, "json_to_record",
2505 true, false, NULL);
2506}
2507
2508/* helper function for diagnostics */
2509static void
2511{
2512 if (ndim <= 0)
2513 {
2514 if (ctx->colname)
2515 errsave(ctx->escontext,
2516 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2517 errmsg("expected JSON array"),
2518 errhint("See the value of key \"%s\".", ctx->colname)));
2519 else
2520 errsave(ctx->escontext,
2521 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2522 errmsg("expected JSON array")));
2523 return;
2524 }
2525 else
2526 {
2527 StringInfoData indices;
2528 int i;
2529
2530 initStringInfo(&indices);
2531
2532 Assert(ctx->ndims > 0 && ndim < ctx->ndims);
2533
2534 for (i = 0; i < ndim; i++)
2535 appendStringInfo(&indices, "[%d]", ctx->sizes[i]);
2536
2537 if (ctx->colname)
2538 errsave(ctx->escontext,
2539 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2540 errmsg("expected JSON array"),
2541 errhint("See the array element %s of key \"%s\".",
2542 indices.data, ctx->colname)));
2543 else
2544 errsave(ctx->escontext,
2545 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2546 errmsg("expected JSON array"),
2547 errhint("See the array element %s.",
2548 indices.data)));
2549 return;
2550 }
2551}
2552
2553/*
2554 * Validate and set ndims for populating an array with some
2555 * populate_array_*() function.
2556 *
2557 * Returns false if the input (ndims) is erroneous.
2558 */
2559static bool
2561{
2562 int i;
2563
2564 Assert(ctx->ndims <= 0);
2565
2566 if (ndims <= 0)
2567 {
2569 /* Getting here means the error was reported softly. */
2571 return false;
2572 }
2573
2574 ctx->ndims = ndims;
2575 ctx->dims = palloc(sizeof(int) * ndims);
2576 ctx->sizes = palloc0(sizeof(int) * ndims);
2577
2578 for (i = 0; i < ndims; i++)
2579 ctx->dims[i] = -1; /* dimensions are unknown yet */
2580
2581 return true;
2582}
2583
2584/*
2585 * Check the populated subarray dimension
2586 *
2587 * Returns false if the input (ndims) is erroneous.
2588 */
2589static bool
2591{
2592 int dim = ctx->sizes[ndim]; /* current dimension counter */
2593
2594 if (ctx->dims[ndim] == -1)
2595 ctx->dims[ndim] = dim; /* assign dimension if not yet known */
2596 else if (ctx->dims[ndim] != dim)
2597 ereturn(ctx->escontext, false,
2598 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2599 errmsg("malformed JSON array"),
2600 errdetail("Multidimensional arrays must have "
2601 "sub-arrays with matching dimensions.")));
2602
2603 /* reset the current array dimension size counter */
2604 ctx->sizes[ndim] = 0;
2605
2606 /* increment the parent dimension counter if it is a nested sub-array */
2607 if (ndim > 0)
2608 ctx->sizes[ndim - 1]++;
2609
2610 return true;
2611}
2612
2613/*
2614 * Returns true if the array element value was successfully extracted from jsv
2615 * and added to ctx->astate. False if an error occurred when doing so.
2616 */
2617static bool
2619{
2620 Datum element;
2621 bool element_isnull;
2622
2623 /* populate the array element */
2625 ctx->aio->element_type,
2626 ctx->aio->element_typmod,
2627 NULL, ctx->mcxt, PointerGetDatum(NULL),
2628 jsv, &element_isnull, ctx->escontext,
2629 false);
2630 /* Nothing to do on an error. */
2632 return false;
2633
2634 accumArrayResult(ctx->astate, element, element_isnull,
2635 ctx->aio->element_type, ctx->acxt);
2636
2637 Assert(ndim > 0);
2638 ctx->sizes[ndim - 1]++; /* increment current dimension counter */
2639
2640 return true;
2641}
2642
2643/* json object start handler for populate_array_json() */
2644static JsonParseErrorType
2646{
2648 int ndim = state->lex->lex_level;
2649
2650 if (state->ctx->ndims <= 0)
2651 {
2652 if (!populate_array_assign_ndims(state->ctx, ndim))
2654 }
2655 else if (ndim < state->ctx->ndims)
2656 {
2658 /* Getting here means the error was reported softly. */
2659 Assert(SOFT_ERROR_OCCURRED(state->ctx->escontext));
2661 }
2662
2663 return JSON_SUCCESS;
2664}
2665
2666/* json array end handler for populate_array_json() */
2667static JsonParseErrorType
2669{
2671 PopulateArrayContext *ctx = state->ctx;
2672 int ndim = state->lex->lex_level;
2673
2674 if (ctx->ndims <= 0)
2675 {
2676 if (!populate_array_assign_ndims(ctx, ndim + 1))
2678 }
2679
2680 if (ndim < ctx->ndims)
2681 {
2682 /* Report if an error occurred. */
2683 if (!populate_array_check_dimension(ctx, ndim))
2685 }
2686
2687 return JSON_SUCCESS;
2688}
2689
2690/* json array element start handler for populate_array_json() */
2691static JsonParseErrorType
2692populate_array_element_start(void *_state, bool isnull)
2693{
2695 int ndim = state->lex->lex_level;
2696
2697 if (state->ctx->ndims <= 0 || ndim == state->ctx->ndims)
2698 {
2699 /* remember current array element start */
2700 state->element_start = state->lex->token_start;
2701 state->element_type = state->lex->token_type;
2702 state->element_scalar = NULL;
2703 }
2704
2705 return JSON_SUCCESS;
2706}
2707
2708/* json array element end handler for populate_array_json() */
2709static JsonParseErrorType
2710populate_array_element_end(void *_state, bool isnull)
2711{
2713 PopulateArrayContext *ctx = state->ctx;
2714 int ndim = state->lex->lex_level;
2715
2716 Assert(ctx->ndims > 0);
2717
2718 if (ndim == ctx->ndims)
2719 {
2720 JsValue jsv;
2721
2722 jsv.is_json = true;
2723 jsv.val.json.type = state->element_type;
2724
2725 if (isnull)
2726 {
2728 jsv.val.json.str = NULL;
2729 jsv.val.json.len = 0;
2730 }
2731 else if (state->element_scalar)
2732 {
2733 jsv.val.json.str = state->element_scalar;
2734 jsv.val.json.len = -1; /* null-terminated */
2735 }
2736 else
2737 {
2738 jsv.val.json.str = state->element_start;
2739 jsv.val.json.len = (state->lex->prev_token_terminator -
2740 state->element_start) * sizeof(char);
2741 }
2742
2743 /* Report if an error occurred. */
2744 if (!populate_array_element(ctx, ndim, &jsv))
2746 }
2747
2748 return JSON_SUCCESS;
2749}
2750
2751/* json scalar handler for populate_array_json() */
2752static JsonParseErrorType
2753populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
2754{
2756 PopulateArrayContext *ctx = state->ctx;
2757 int ndim = state->lex->lex_level;
2758
2759 if (ctx->ndims <= 0)
2760 {
2761 if (!populate_array_assign_ndims(ctx, ndim))
2763 }
2764 else if (ndim < ctx->ndims)
2765 {
2767 /* Getting here means the error was reported softly. */
2770 }
2771
2772 if (ndim == ctx->ndims)
2773 {
2774 /* remember the scalar element token */
2775 state->element_scalar = token;
2776 /* element_type must already be set in populate_array_element_start() */
2777 Assert(state->element_type == tokentype);
2778 }
2779
2780 return JSON_SUCCESS;
2781}
2782
2783/*
2784 * Parse a json array and populate array
2785 *
2786 * Returns false if an error occurs when parsing.
2787 */
2788static bool
2790{
2793
2794 state.lex = makeJsonLexContextCstringLen(NULL, json, len,
2795 GetDatabaseEncoding(), true);
2796 state.ctx = ctx;
2797
2798 memset(&sem, 0, sizeof(sem));
2799 sem.semstate = &state;
2805
2807 {
2808 /* number of dimensions should be already known */
2809 Assert(ctx->ndims > 0 && ctx->dims);
2810 }
2811
2813
2814 return !SOFT_ERROR_OCCURRED(ctx->escontext);
2815}
2816
2817/*
2818 * populate_array_dim_jsonb() -- Iterate recursively through jsonb sub-array
2819 * elements and accumulate result using given ArrayBuildState.
2820 *
2821 * Returns false if we return partway through because of an error in a
2822 * subroutine.
2823 */
2824static bool
2826 JsonbValue *jbv, /* jsonb sub-array */
2827 int ndim) /* current dimension */
2828{
2829 JsonbContainer *jbc = jbv->val.binary.data;
2830 JsonbIterator *it;
2833 JsValue jsv;
2834
2836
2837 /* Even scalars can end up here thanks to ExecEvalJsonCoercion(). */
2838 if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc) ||
2840 {
2842 /* Getting here means the error was reported softly. */
2844 return false;
2845 }
2846
2847 it = JsonbIteratorInit(jbc);
2848
2849 tok = JsonbIteratorNext(&it, &val, true);
2850 Assert(tok == WJB_BEGIN_ARRAY);
2851
2852 tok = JsonbIteratorNext(&it, &val, true);
2853
2854 /*
2855 * If the number of dimensions is not yet known and we have found end of
2856 * the array, or the first child element is not an array, then assign the
2857 * number of dimensions now.
2858 */
2859 if (ctx->ndims <= 0 &&
2860 (tok == WJB_END_ARRAY ||
2861 (tok == WJB_ELEM &&
2862 (val.type != jbvBinary ||
2863 !JsonContainerIsArray(val.val.binary.data)))))
2864 {
2865 if (!populate_array_assign_ndims(ctx, ndim))
2866 return false;
2867 }
2868
2869 jsv.is_json = false;
2870 jsv.val.jsonb = &val;
2871
2872 /* process all the array elements */
2873 while (tok == WJB_ELEM)
2874 {
2875 /*
2876 * Recurse only if the dimensions of dimensions is still unknown or if
2877 * it is not the innermost dimension.
2878 */
2879 if (ctx->ndims > 0 && ndim >= ctx->ndims)
2880 {
2881 if (!populate_array_element(ctx, ndim, &jsv))
2882 return false;
2883 }
2884 else
2885 {
2886 /* populate child sub-array */
2887 if (!populate_array_dim_jsonb(ctx, &val, ndim + 1))
2888 return false;
2889
2890 /* number of dimensions should be already known */
2891 Assert(ctx->ndims > 0 && ctx->dims);
2892
2893 if (!populate_array_check_dimension(ctx, ndim))
2894 return false;
2895 }
2896
2897 tok = JsonbIteratorNext(&it, &val, true);
2898 }
2899
2900 Assert(tok == WJB_END_ARRAY);
2901
2902 /* free iterator, iterating until WJB_DONE */
2903 tok = JsonbIteratorNext(&it, &val, true);
2904 Assert(tok == WJB_DONE && !it);
2905
2906 return true;
2907}
2908
2909/*
2910 * Recursively populate an array from json/jsonb
2911 *
2912 * *isnull is set to true if an error is reported during parsing.
2913 */
2914static Datum
2916 const char *colname,
2917 MemoryContext mcxt,
2918 JsValue *jsv,
2919 bool *isnull,
2920 Node *escontext)
2921{
2923 Datum result;
2924 int *lbs;
2925 int i;
2926
2927 ctx.aio = aio;
2928 ctx.mcxt = mcxt;
2930 ctx.astate = initArrayResult(aio->element_type, ctx.acxt, true);
2931 ctx.colname = colname;
2932 ctx.ndims = 0; /* unknown yet */
2933 ctx.dims = NULL;
2934 ctx.sizes = NULL;
2935 ctx.escontext = escontext;
2936
2937 if (jsv->is_json)
2938 {
2939 /* Return null if an error was found. */
2940 if (!populate_array_json(&ctx, jsv->val.json.str,
2941 jsv->val.json.len >= 0 ? jsv->val.json.len
2942 : strlen(jsv->val.json.str)))
2943 {
2944 *isnull = true;
2945 return (Datum) 0;
2946 }
2947 }
2948 else
2949 {
2950 /* Return null if an error was found. */
2951 if (!populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1))
2952 {
2953 *isnull = true;
2954 return (Datum) 0;
2955 }
2956 ctx.dims[0] = ctx.sizes[0];
2957 }
2958
2959 Assert(ctx.ndims > 0);
2960
2961 lbs = palloc(sizeof(int) * ctx.ndims);
2962
2963 for (i = 0; i < ctx.ndims; i++)
2964 lbs[i] = 1;
2965
2966 result = makeMdArrayResult(ctx.astate, ctx.ndims, ctx.dims, lbs,
2967 ctx.acxt, true);
2968
2969 pfree(ctx.dims);
2970 pfree(ctx.sizes);
2971 pfree(lbs);
2972
2973 *isnull = false;
2974 return result;
2975}
2976
2977/*
2978 * Returns false if an error occurs, provided escontext points to an
2979 * ErrorSaveContext.
2980 */
2981static bool
2983{
2984 jso->is_json = jsv->is_json;
2985
2986 if (jsv->is_json)
2987 {
2988 /* convert plain-text json into a hash table */
2989 jso->val.json_hash =
2991 jsv->val.json.len >= 0
2992 ? jsv->val.json.len
2993 : strlen(jsv->val.json.str),
2994 "populate_composite",
2995 escontext);
2996 Assert(jso->val.json_hash != NULL || SOFT_ERROR_OCCURRED(escontext));
2997 }
2998 else
2999 {
3000 JsonbValue *jbv = jsv->val.jsonb;
3001
3002 if (jbv->type == jbvBinary &&
3003 JsonContainerIsObject(jbv->val.binary.data))
3004 {
3005 jso->val.jsonb_cont = jbv->val.binary.data;
3006 }
3007 else
3008 {
3009 bool is_scalar;
3010
3011 is_scalar = IsAJsonbScalar(jbv) ||
3012 (jbv->type == jbvBinary &&
3013 JsonContainerIsScalar(jbv->val.binary.data));
3014 errsave(escontext,
3015 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3016 is_scalar
3017 ? errmsg("cannot call %s on a scalar",
3018 "populate_composite")
3019 : errmsg("cannot call %s on an array",
3020 "populate_composite")));
3021 }
3022 }
3023
3024 return !SOFT_ERROR_OCCURRED(escontext);
3025}
3026
3027/* acquire or update cached tuple descriptor for a composite type */
3028static void
3030{
3031 if (!io->tupdesc ||
3032 io->tupdesc->tdtypeid != io->base_typid ||
3033 io->tupdesc->tdtypmod != io->base_typmod)
3034 {
3036 io->base_typmod);
3037 MemoryContext oldcxt;
3038
3039 if (io->tupdesc)
3041
3042 /* copy tuple desc without constraints into cache memory context */
3043 oldcxt = MemoryContextSwitchTo(mcxt);
3044 io->tupdesc = CreateTupleDescCopy(tupdesc);
3045 MemoryContextSwitchTo(oldcxt);
3046
3047 ReleaseTupleDesc(tupdesc);
3048 }
3049}
3050
3051/*
3052 * Recursively populate a composite (row type) value from json/jsonb
3053 *
3054 * Returns null if an error occurs in a subroutine, provided escontext points
3055 * to an ErrorSaveContext.
3056 */
3057static Datum
3059 Oid typid,
3060 const char *colname,
3061 MemoryContext mcxt,
3062 HeapTupleHeader defaultval,
3063 JsValue *jsv,
3064 bool *isnull,
3065 Node *escontext)
3066{
3067 Datum result;
3068
3069 /* acquire/update cached tuple descriptor */
3070 update_cached_tupdesc(io, mcxt);
3071
3072 if (*isnull)
3073 result = (Datum) 0;
3074 else
3075 {
3076 HeapTupleHeader tuple;
3077 JsObject jso;
3078
3079 /* prepare input value */
3080 if (!JsValueToJsObject(jsv, &jso, escontext))
3081 {
3082 *isnull = true;
3083 return (Datum) 0;
3084 }
3085
3086 /* populate resulting record tuple */
3087 tuple = populate_record(io->tupdesc, &io->record_io,
3088 defaultval, mcxt, &jso, escontext);
3089
3090 if (SOFT_ERROR_OCCURRED(escontext))
3091 {
3092 *isnull = true;
3093 return (Datum) 0;
3094 }
3095 result = HeapTupleHeaderGetDatum(tuple);
3096
3097 JsObjectFree(&jso);
3098 }
3099
3100 /*
3101 * If it's domain over composite, check domain constraints. (This should
3102 * probably get refactored so that we can see the TYPECAT value, but for
3103 * now, we can tell by comparing typid to base_typid.)
3104 */
3105 if (typid != io->base_typid && typid != RECORDOID)
3106 {
3107 if (!domain_check_safe(result, *isnull, typid, &io->domain_info, mcxt,
3108 escontext))
3109 {
3110 *isnull = true;
3111 return (Datum) 0;
3112 }
3113 }
3114
3115 return result;
3116}
3117
3118/*
3119 * Populate non-null scalar value from json/jsonb value.
3120 *
3121 * Returns null if an error occurs during the call to type input function,
3122 * provided escontext is valid.
3123 */
3124static Datum
3126 bool *isnull, Node *escontext, bool omit_quotes)
3127{
3128 Datum res;
3129 char *str = NULL;
3130 const char *json = NULL;
3131
3132 if (jsv->is_json)
3133 {
3134 int len = jsv->val.json.len;
3135
3136 json = jsv->val.json.str;
3137 Assert(json);
3138
3139 /* If converting to json/jsonb, make string into valid JSON literal */
3140 if ((typid == JSONOID || typid == JSONBOID) &&
3142 {
3144
3146 if (len >= 0)
3147 escape_json_with_len(&buf, json, len);
3148 else
3149 escape_json(&buf, json);
3150 str = buf.data;
3151 }
3152 else if (len >= 0)
3153 {
3154 /* create a NUL-terminated version */
3155 str = palloc(len + 1);
3156 memcpy(str, json, len);
3157 str[len] = '\0';
3158 }
3159 else
3160 {
3161 /* string is already NUL-terminated */
3162 str = unconstify(char *, json);
3163 }
3164 }
3165 else
3166 {
3167 JsonbValue *jbv = jsv->val.jsonb;
3168
3169 if (jbv->type == jbvString && omit_quotes)
3170 str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3171 else if (typid == JSONBOID)
3172 {
3173 Jsonb *jsonb = JsonbValueToJsonb(jbv); /* directly use jsonb */
3174
3175 return JsonbPGetDatum(jsonb);
3176 }
3177 /* convert jsonb to string for typio call */
3178 else if (typid == JSONOID && jbv->type != jbvBinary)
3179 {
3180 /*
3181 * Convert scalar jsonb (non-scalars are passed here as jbvBinary)
3182 * to json string, preserving quotes around top-level strings.
3183 */
3184 Jsonb *jsonb = JsonbValueToJsonb(jbv);
3185
3186 str = JsonbToCString(NULL, &jsonb->root, VARSIZE(jsonb));
3187 }
3188 else if (jbv->type == jbvString) /* quotes are stripped */
3189 str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3190 else if (jbv->type == jbvBool)
3191 str = pstrdup(jbv->val.boolean ? "true" : "false");
3192 else if (jbv->type == jbvNumeric)
3194 PointerGetDatum(jbv->val.numeric)));
3195 else if (jbv->type == jbvBinary)
3196 str = JsonbToCString(NULL, jbv->val.binary.data,
3197 jbv->val.binary.len);
3198 else
3199 elog(ERROR, "unrecognized jsonb type: %d", (int) jbv->type);
3200 }
3201
3202 if (!InputFunctionCallSafe(&io->typiofunc, str, io->typioparam, typmod,
3203 escontext, &res))
3204 {
3205 res = (Datum) 0;
3206 *isnull = true;
3207 }
3208
3209 /* free temporary buffer */
3210 if (str != json)
3211 pfree(str);
3212
3213 return res;
3214}
3215
3216static Datum
3218 Oid typid,
3219 const char *colname,
3220 MemoryContext mcxt,
3221 JsValue *jsv,
3222 bool *isnull,
3223 Node *escontext,
3224 bool omit_quotes)
3225{
3226 Datum res;
3227
3228 if (*isnull)
3229 res = (Datum) 0;
3230 else
3231 {
3233 io->base_typid, io->base_typmod,
3234 colname, mcxt, PointerGetDatum(NULL),
3235 jsv, isnull, escontext, omit_quotes);
3236 Assert(!*isnull || SOFT_ERROR_OCCURRED(escontext));
3237 }
3238
3239 if (!domain_check_safe(res, *isnull, typid, &io->domain_info, mcxt,
3240 escontext))
3241 {
3242 *isnull = true;
3243 return (Datum) 0;
3244 }
3245
3246 return res;
3247}
3248
3249/* prepare column metadata cache for the given type */
3250static void
3252 Oid typid,
3253 int32 typmod,
3254 MemoryContext mcxt,
3255 bool need_scalar)
3256{
3257 HeapTuple tup;
3259
3260 column->typid = typid;
3261 column->typmod = typmod;
3262
3263 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3264 if (!HeapTupleIsValid(tup))
3265 elog(ERROR, "cache lookup failed for type %u", typid);
3266
3267 type = (Form_pg_type) GETSTRUCT(tup);
3268
3269 if (type->typtype == TYPTYPE_DOMAIN)
3270 {
3271 /*
3272 * We can move directly to the bottom base type; domain_check() will
3273 * take care of checking all constraints for a stack of domains.
3274 */
3275 Oid base_typid;
3276 int32 base_typmod = typmod;
3277
3278 base_typid = getBaseTypeAndTypmod(typid, &base_typmod);
3279 if (get_typtype(base_typid) == TYPTYPE_COMPOSITE)
3280 {
3281 /* domain over composite has its own code path */
3283 column->io.composite.record_io = NULL;
3284 column->io.composite.tupdesc = NULL;
3285 column->io.composite.base_typid = base_typid;
3286 column->io.composite.base_typmod = base_typmod;
3287 column->io.composite.domain_info = NULL;
3288 }
3289 else
3290 {
3291 /* domain over anything else */
3292 column->typcat = TYPECAT_DOMAIN;
3293 column->io.domain.base_typid = base_typid;
3294 column->io.domain.base_typmod = base_typmod;
3295 column->io.domain.base_io =
3296 MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3297 column->io.domain.domain_info = NULL;
3298 }
3299 }
3300 else if (type->typtype == TYPTYPE_COMPOSITE || typid == RECORDOID)
3301 {
3302 column->typcat = TYPECAT_COMPOSITE;
3303 column->io.composite.record_io = NULL;
3304 column->io.composite.tupdesc = NULL;
3305 column->io.composite.base_typid = typid;
3306 column->io.composite.base_typmod = typmod;
3307 column->io.composite.domain_info = NULL;
3308 }
3309 else if (IsTrueArrayType(type))
3310 {
3311 column->typcat = TYPECAT_ARRAY;
3313 sizeof(ColumnIOData));
3314 column->io.array.element_type = type->typelem;
3315 /* array element typemod stored in attribute's typmod */
3316 column->io.array.element_typmod = typmod;
3317 }
3318 else
3319 {
3320 column->typcat = TYPECAT_SCALAR;
3321 need_scalar = true;
3322 }
3323
3324 /* caller can force us to look up scalar_io info even for non-scalars */
3325 if (need_scalar)
3326 {
3327 Oid typioproc;
3328
3329 getTypeInputInfo(typid, &typioproc, &column->scalar_io.typioparam);
3330 fmgr_info_cxt(typioproc, &column->scalar_io.typiofunc, mcxt);
3331 }
3332
3333 ReleaseSysCache(tup);
3334}
3335
3336/*
3337 * Populate and return the value of specified type from a given json/jsonb
3338 * value 'json_val'. 'cache' is caller-specified pointer to save the
3339 * ColumnIOData that will be initialized on the 1st call and then reused
3340 * during any subsequent calls. 'mcxt' gives the memory context to allocate
3341 * the ColumnIOData and any other subsidiary memory in. 'escontext',
3342 * if not NULL, tells that any errors that occur should be handled softly.
3343 */
3344Datum
3345json_populate_type(Datum json_val, Oid json_type,
3346 Oid typid, int32 typmod,
3347 void **cache, MemoryContext mcxt,
3348 bool *isnull, bool omit_quotes,
3349 Node *escontext)
3350{
3351 JsValue jsv = {0};
3352 JsonbValue jbv;
3353
3354 jsv.is_json = json_type == JSONOID;
3355
3356 if (*isnull)
3357 {
3358 if (jsv.is_json)
3359 jsv.val.json.str = NULL;
3360 else
3361 jsv.val.jsonb = NULL;
3362 }
3363 else if (jsv.is_json)
3364 {
3365 text *json = DatumGetTextPP(json_val);
3366
3367 jsv.val.json.str = VARDATA_ANY(json);
3368 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3369 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3370 * populate_composite() */
3371 }
3372 else
3373 {
3374 Jsonb *jsonb = DatumGetJsonbP(json_val);
3375
3376 jsv.val.jsonb = &jbv;
3377
3378 if (omit_quotes)
3379 {
3380 char *str = JsonbUnquote(DatumGetJsonbP(json_val));
3381
3382 /* fill the quote-stripped string */
3383 jbv.type = jbvString;
3384 jbv.val.string.len = strlen(str);
3385 jbv.val.string.val = str;
3386 }
3387 else
3388 {
3389 /* fill binary jsonb value pointing to jb */
3390 jbv.type = jbvBinary;
3391 jbv.val.binary.data = &jsonb->root;
3392 jbv.val.binary.len = VARSIZE(jsonb) - VARHDRSZ;
3393 }
3394 }
3395
3396 if (*cache == NULL)
3397 *cache = MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3398
3399 return populate_record_field(*cache, typid, typmod, NULL, mcxt,
3400 PointerGetDatum(NULL), &jsv, isnull,
3401 escontext, omit_quotes);
3402}
3403
3404/* recursively populate a record field or an array element from a json/jsonb value */
3405static Datum
3407 Oid typid,
3408 int32 typmod,
3409 const char *colname,
3410 MemoryContext mcxt,
3411 Datum defaultval,
3412 JsValue *jsv,
3413 bool *isnull,
3414 Node *escontext,
3415 bool omit_scalar_quotes)
3416{
3417 TypeCat typcat;
3418
3420
3421 /*
3422 * Prepare column metadata cache for the given type. Force lookup of the
3423 * scalar_io data so that the json string hack below will work.
3424 */
3425 if (col->typid != typid || col->typmod != typmod)
3426 prepare_column_cache(col, typid, typmod, mcxt, true);
3427
3428 *isnull = JsValueIsNull(jsv);
3429
3430 typcat = col->typcat;
3431
3432 /* try to convert json string to a non-scalar type through input function */
3433 if (JsValueIsString(jsv) &&
3434 (typcat == TYPECAT_ARRAY ||
3435 typcat == TYPECAT_COMPOSITE ||
3436 typcat == TYPECAT_COMPOSITE_DOMAIN))
3437 typcat = TYPECAT_SCALAR;
3438
3439 /* we must perform domain checks for NULLs, otherwise exit immediately */
3440 if (*isnull &&
3441 typcat != TYPECAT_DOMAIN &&
3442 typcat != TYPECAT_COMPOSITE_DOMAIN)
3443 return (Datum) 0;
3444
3445 switch (typcat)
3446 {
3447 case TYPECAT_SCALAR:
3448 return populate_scalar(&col->scalar_io, typid, typmod, jsv,
3449 isnull, escontext, omit_scalar_quotes);
3450
3451 case TYPECAT_ARRAY:
3452 return populate_array(&col->io.array, colname, mcxt, jsv,
3453 isnull, escontext);
3454
3455 case TYPECAT_COMPOSITE:
3457 return populate_composite(&col->io.composite, typid,
3458 colname, mcxt,
3459 DatumGetPointer(defaultval)
3460 ? DatumGetHeapTupleHeader(defaultval)
3461 : NULL,
3462 jsv, isnull,
3463 escontext);
3464
3465 case TYPECAT_DOMAIN:
3466 return populate_domain(&col->io.domain, typid, colname, mcxt,
3467 jsv, isnull, escontext, omit_scalar_quotes);
3468
3469 default:
3470 elog(ERROR, "unrecognized type category '%c'", typcat);
3471 return (Datum) 0;
3472 }
3473}
3474
3475static RecordIOData *
3477{
3479 MemoryContextAlloc(mcxt,
3480 offsetof(RecordIOData, columns) +
3481 ncolumns * sizeof(ColumnIOData));
3482
3483 data->record_type = InvalidOid;
3484 data->record_typmod = 0;
3485 data->ncolumns = ncolumns;
3486 MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3487
3488 return data;
3489}
3490
3491static bool
3492JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
3493{
3494 jsv->is_json = obj->is_json;
3495
3496 if (jsv->is_json)
3497 {
3498 JsonHashEntry *hashentry = hash_search(obj->val.json_hash, field,
3499 HASH_FIND, NULL);
3500
3501 jsv->val.json.type = hashentry ? hashentry->type : JSON_TOKEN_NULL;
3502 jsv->val.json.str = jsv->val.json.type == JSON_TOKEN_NULL ? NULL :
3503 hashentry->val;
3504 jsv->val.json.len = jsv->val.json.str ? -1 : 0; /* null-terminated */
3505
3506 return hashentry != NULL;
3507 }
3508 else
3509 {
3510 jsv->val.jsonb = !obj->val.jsonb_cont ? NULL :
3511 getKeyJsonValueFromContainer(obj->val.jsonb_cont, field, strlen(field),
3512 NULL);
3513
3514 return jsv->val.jsonb != NULL;
3515 }
3516}
3517
3518/* populate a record tuple from json/jsonb value */
3519static HeapTupleHeader
3521 RecordIOData **record_p,
3522 HeapTupleHeader defaultval,
3523 MemoryContext mcxt,
3524 JsObject *obj,
3525 Node *escontext)
3526{
3527 RecordIOData *record = *record_p;
3528 Datum *values;
3529 bool *nulls;
3530 HeapTuple res;
3531 int ncolumns = tupdesc->natts;
3532 int i;
3533
3534 /*
3535 * if the input json is empty, we can only skip the rest if we were passed
3536 * in a non-null record, since otherwise there may be issues with domain
3537 * nulls.
3538 */
3539 if (defaultval && JsObjectIsEmpty(obj))
3540 return defaultval;
3541
3542 /* (re)allocate metadata cache */
3543 if (record == NULL ||
3544 record->ncolumns != ncolumns)
3545 *record_p = record = allocate_record_info(mcxt, ncolumns);
3546
3547 /* invalidate metadata cache if the record type has changed */
3548 if (record->record_type != tupdesc->tdtypeid ||
3549 record->record_typmod != tupdesc->tdtypmod)
3550 {
3551 MemSet(record, 0, offsetof(RecordIOData, columns) +
3552 ncolumns * sizeof(ColumnIOData));
3553 record->record_type = tupdesc->tdtypeid;
3554 record->record_typmod = tupdesc->tdtypmod;
3555 record->ncolumns = ncolumns;
3556 }
3557
3558 values = (Datum *) palloc(ncolumns * sizeof(Datum));
3559 nulls = (bool *) palloc(ncolumns * sizeof(bool));
3560
3561 if (defaultval)
3562 {
3563 HeapTupleData tuple;
3564
3565 /* Build a temporary HeapTuple control structure */
3566 tuple.t_len = HeapTupleHeaderGetDatumLength(defaultval);
3567 ItemPointerSetInvalid(&(tuple.t_self));
3568 tuple.t_tableOid = InvalidOid;
3569 tuple.t_data = defaultval;
3570
3571 /* Break down the tuple into fields */
3572 heap_deform_tuple(&tuple, tupdesc, values, nulls);
3573 }
3574 else
3575 {
3576 for (i = 0; i < ncolumns; ++i)
3577 {
3578 values[i] = (Datum) 0;
3579 nulls[i] = true;
3580 }
3581 }
3582
3583 for (i = 0; i < ncolumns; ++i)
3584 {
3585 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
3586 char *colname = NameStr(att->attname);
3587 JsValue field = {0};
3588 bool found;
3589
3590 /* Ignore dropped columns in datatype */
3591 if (att->attisdropped)
3592 {
3593 nulls[i] = true;
3594 continue;
3595 }
3596
3597 found = JsObjectGetField(obj, colname, &field);
3598
3599 /*
3600 * we can't just skip here if the key wasn't found since we might have
3601 * a domain to deal with. If we were passed in a non-null record
3602 * datum, we assume that the existing values are valid (if they're
3603 * not, then it's not our fault), but if we were passed in a null,
3604 * then every field which we don't populate needs to be run through
3605 * the input function just in case it's a domain type.
3606 */
3607 if (defaultval && !found)
3608 continue;
3609
3610 values[i] = populate_record_field(&record->columns[i],
3611 att->atttypid,
3612 att->atttypmod,
3613 colname,
3614 mcxt,
3615 nulls[i] ? (Datum) 0 : values[i],
3616 &field,
3617 &nulls[i],
3618 escontext,
3619 false);
3620 }
3621
3622 res = heap_form_tuple(tupdesc, values, nulls);
3623
3624 pfree(values);
3625 pfree(nulls);
3626
3627 return res->t_data;
3628}
3629
3630/*
3631 * Setup for json{b}_populate_record{set}: result type will be same as first
3632 * argument's type --- unless first argument is "null::record", which we can't
3633 * extract type info from; we handle that later.
3634 */
3635static void
3637 const char *funcname,
3638 PopulateRecordCache *cache)
3639{
3640 cache->argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
3641 prepare_column_cache(&cache->c,
3642 cache->argtype, -1,
3643 cache->fn_mcxt, false);
3644 if (cache->c.typcat != TYPECAT_COMPOSITE &&
3646 ereport(ERROR,
3647 (errcode(ERRCODE_DATATYPE_MISMATCH),
3648 /* translator: %s is a function name, eg json_to_record */
3649 errmsg("first argument of %s must be a row type",
3650 funcname)));
3651}
3652
3653/*
3654 * Setup for json{b}_to_record{set}: result type is specified by calling
3655 * query. We'll also use this code for json{b}_populate_record{set},
3656 * if we discover that the first argument is a null of type RECORD.
3657 *
3658 * Here it is syntactically impossible to specify the target type
3659 * as domain-over-composite.
3660 */
3661static void
3663 const char *funcname,
3664 PopulateRecordCache *cache)
3665{
3666 TupleDesc tupdesc;
3667 MemoryContext old_cxt;
3668
3669 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3670 ereport(ERROR,
3671 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3672 /* translator: %s is a function name, eg json_to_record */
3673 errmsg("could not determine row type for result of %s",
3674 funcname),
3675 errhint("Provide a non-null record argument, "
3676 "or call the function in the FROM clause "
3677 "using a column definition list.")));
3678
3679 Assert(tupdesc);
3680 cache->argtype = tupdesc->tdtypeid;
3681
3682 /* If we go through this more than once, avoid memory leak */
3683 if (cache->c.io.composite.tupdesc)
3685
3686 /* Save identified tupdesc */
3687 old_cxt = MemoryContextSwitchTo(cache->fn_mcxt);
3688 cache->c.io.composite.tupdesc = CreateTupleDescCopy(tupdesc);
3689 cache->c.io.composite.base_typid = tupdesc->tdtypeid;
3690 cache->c.io.composite.base_typmod = tupdesc->tdtypmod;
3691 MemoryContextSwitchTo(old_cxt);
3692}
3693
3694/*
3695 * common worker for json{b}_populate_record() and json{b}_to_record()
3696 * is_json and have_record_arg identify the specific function
3697 */
3698static Datum
3700 bool is_json, bool have_record_arg,
3701 Node *escontext)
3702{
3703 int json_arg_num = have_record_arg ? 1 : 0;
3704 JsValue jsv = {0};
3705 HeapTupleHeader rec;
3706 Datum rettuple;
3707 bool isnull;
3708 JsonbValue jbv;
3709 MemoryContext fnmcxt = fcinfo->flinfo->fn_mcxt;
3710 PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
3711
3712 /*
3713 * If first time through, identify input/result record type. Note that
3714 * this stanza looks only at fcinfo context, which can't change during the
3715 * query; so we may not be able to fully resolve a RECORD input type yet.
3716 */
3717 if (!cache)
3718 {
3719 fcinfo->flinfo->fn_extra = cache =
3720 MemoryContextAllocZero(fnmcxt, sizeof(*cache));
3721 cache->fn_mcxt = fnmcxt;
3722
3723 if (have_record_arg)
3725 else
3726 get_record_type_from_query(fcinfo, funcname, cache);
3727 }
3728
3729 /* Collect record arg if we have one */
3730 if (!have_record_arg)
3731 rec = NULL; /* it's json{b}_to_record() */
3732 else if (!PG_ARGISNULL(0))
3733 {
3735
3736 /*
3737 * When declared arg type is RECORD, identify actual record type from
3738 * the tuple itself.
3739 */
3740 if (cache->argtype == RECORDOID)
3741 {
3744 }
3745 }
3746 else
3747 {
3748 rec = NULL;
3749
3750 /*
3751 * When declared arg type is RECORD, identify actual record type from
3752 * calling query, or fail if we can't.
3753 */
3754 if (cache->argtype == RECORDOID)
3755 {
3756 get_record_type_from_query(fcinfo, funcname, cache);
3757 /* This can't change argtype, which is important for next time */
3758 Assert(cache->argtype == RECORDOID);
3759 }
3760 }
3761
3762 /* If no JSON argument, just return the record (if any) unchanged */
3763 if (PG_ARGISNULL(json_arg_num))
3764 {
3765 if (rec)
3766 PG_RETURN_POINTER(rec);
3767 else
3769 }
3770
3771 jsv.is_json = is_json;
3772
3773 if (is_json)
3774 {
3775 text *json = PG_GETARG_TEXT_PP(json_arg_num);
3776
3777 jsv.val.json.str = VARDATA_ANY(json);
3778 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3779 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3780 * populate_composite() */
3781 }
3782 else
3783 {
3784 Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
3785
3786 jsv.val.jsonb = &jbv;
3787
3788 /* fill binary jsonb value pointing to jb */
3789 jbv.type = jbvBinary;
3790 jbv.val.binary.data = &jb->root;
3791 jbv.val.binary.len = VARSIZE(jb) - VARHDRSZ;
3792 }
3793
3794 isnull = false;
3795 rettuple = populate_composite(&cache->c.io.composite, cache->argtype,
3796 NULL, fnmcxt, rec, &jsv, &isnull,
3797 escontext);
3798 Assert(!isnull || SOFT_ERROR_OCCURRED(escontext));
3799
3800 PG_RETURN_DATUM(rettuple);
3801}
3802
3803/*
3804 * get_json_object_as_hash
3805 *
3806 * Decomposes a json object into a hash table.
3807 *
3808 * Returns the hash table if the json is parsed successfully, NULL otherwise.
3809 */
3810static HTAB *
3811get_json_object_as_hash(const char *json, int len, const char *funcname,
3812 Node *escontext)
3813{
3814 HASHCTL ctl;
3815 HTAB *tab;
3818
3819 ctl.keysize = NAMEDATALEN;
3820 ctl.entrysize = sizeof(JsonHashEntry);
3822 tab = hash_create("json object hashtable",
3823 100,
3824 &ctl,
3826
3827 state = palloc0(sizeof(JHashState));
3828 sem = palloc0(sizeof(JsonSemAction));
3829
3830 state->function_name = funcname;
3831 state->hash = tab;
3832 state->lex = makeJsonLexContextCstringLen(NULL, json, len,
3833 GetDatabaseEncoding(), true);
3834
3835 sem->semstate = state;
3840
3841 if (!pg_parse_json_or_errsave(state->lex, sem, escontext))
3842 {
3843 hash_destroy(state->hash);
3844 tab = NULL;
3845 }
3846
3848
3849 return tab;
3850}
3851
3852static JsonParseErrorType
3853hash_object_field_start(void *state, char *fname, bool isnull)
3854{
3855 JHashState *_state = (JHashState *) state;
3856
3857 if (_state->lex->lex_level > 1)
3858 return JSON_SUCCESS;
3859
3860 /* remember token type */
3861 _state->saved_token_type = _state->lex->token_type;
3862
3863 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
3865 {
3866 /* remember start position of the whole text of the subobject */
3867 _state->save_json_start = _state->lex->token_start;
3868 }
3869 else
3870 {
3871 /* must be a scalar */
3872 _state->save_json_start = NULL;
3873 }
3874
3875 return JSON_SUCCESS;
3876}
3877
3878static JsonParseErrorType
3879hash_object_field_end(void *state, char *fname, bool isnull)
3880{
3881 JHashState *_state = (JHashState *) state;
3882 JsonHashEntry *hashentry;
3883 bool found;
3884
3885 /*
3886 * Ignore nested fields.
3887 */
3888 if (_state->lex->lex_level > 1)
3889 return JSON_SUCCESS;
3890
3891 /*
3892 * Ignore field names >= NAMEDATALEN - they can't match a record field.
3893 * (Note: without this test, the hash code would truncate the string at
3894 * NAMEDATALEN-1, and could then match against a similarly-truncated
3895 * record field name. That would be a reasonable behavior, but this code
3896 * has previously insisted on exact equality, so we keep this behavior.)
3897 */
3898 if (strlen(fname) >= NAMEDATALEN)
3899 return JSON_SUCCESS;
3900
3901 hashentry = hash_search(_state->hash, fname, HASH_ENTER, &found);
3902
3903 /*
3904 * found being true indicates a duplicate. We don't do anything about
3905 * that, a later field with the same name overrides the earlier field.
3906 */
3907
3908 hashentry->type = _state->saved_token_type;
3909 Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
3910
3911 if (_state->save_json_start != NULL)
3912 {
3913 int len = _state->lex->prev_token_terminator - _state->save_json_start;
3914 char *val = palloc((len + 1) * sizeof(char));
3915
3916 memcpy(val, _state->save_json_start, len);
3917 val[len] = '\0';
3918 hashentry->val = val;
3919 }
3920 else
3921 {
3922 /* must have had a scalar instead */
3923 hashentry->val = _state->saved_scalar;
3924 }
3925
3926 return JSON_SUCCESS;
3927}
3928
3929static JsonParseErrorType
3931{
3932 JHashState *_state = (JHashState *) state;
3933
3934 if (_state->lex->lex_level == 0)
3935 ereport(ERROR,
3936 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3937 errmsg("cannot call %s on an array", _state->function_name)));
3938
3939 return JSON_SUCCESS;
3940}
3941
3942static JsonParseErrorType
3943hash_scalar(void *state, char *token, JsonTokenType tokentype)
3944{
3945 JHashState *_state = (JHashState *) state;
3946
3947 if (_state->lex->lex_level == 0)
3948 ereport(ERROR,
3949 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3950 errmsg("cannot call %s on a scalar", _state->function_name)));
3951
3952 if (_state->lex->lex_level == 1)
3953 {
3954 _state->saved_scalar = token;
3955 /* saved_token_type must already be set in hash_object_field_start() */
3956 Assert(_state->saved_token_type == tokentype);
3957 }
3958
3959 return JSON_SUCCESS;
3960}
3961
3962
3963/*
3964 * SQL function json_populate_recordset
3965 *
3966 * set fields in a set of records from the argument json,
3967 * which must be an array of objects.
3968 *
3969 * similar to json_populate_record, but the tuple-building code
3970 * is pushed down into the semantic action handlers so it's done
3971 * per object in the array.
3972 */
3973Datum
3975{
3976 return populate_recordset_worker(fcinfo, "jsonb_populate_recordset",
3977 false, true);
3978}
3979
3980Datum
3982{
3983 return populate_recordset_worker(fcinfo, "jsonb_to_recordset",
3984 false, false);
3985}
3986
3987Datum
3989{
3990 return populate_recordset_worker(fcinfo, "json_populate_recordset",
3991 true, true);
3992}
3993
3994Datum
3996{
3997 return populate_recordset_worker(fcinfo, "json_to_recordset",
3998 true, false);
3999}
4000
4001static void
4003{
4004 PopulateRecordCache *cache = state->cache;
4005 HeapTupleHeader tuphead;
4006 HeapTupleData tuple;
4007
4008 /* acquire/update cached tuple descriptor */
4009 update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4010
4011 /* replace record fields from json */
4012 tuphead = populate_record(cache->c.io.composite.tupdesc,
4013 &cache->c.io.composite.record_io,
4014 state->rec,
4015 cache->fn_mcxt,
4016 obj,
4017 NULL);
4018
4019 /* if it's domain over composite, check domain constraints */
4020 if (cache->c.typcat == TYPECAT_COMPOSITE_DOMAIN)
4021 (void) domain_check_safe(HeapTupleHeaderGetDatum(tuphead), false,
4022 cache->argtype,
4023 &cache->c.io.composite.domain_info,
4024 cache->fn_mcxt,
4025 NULL);
4026
4027 /* ok, save into tuplestore */
4028 tuple.t_len = HeapTupleHeaderGetDatumLength(tuphead);
4029 ItemPointerSetInvalid(&(tuple.t_self));
4030 tuple.t_tableOid = InvalidOid;
4031 tuple.t_data = tuphead;
4032
4033 tuplestore_puttuple(state->tuple_store, &tuple);
4034}
4035
4036/*
4037 * common worker for json{b}_populate_recordset() and json{b}_to_recordset()
4038 * is_json and have_record_arg identify the specific function
4039 */
4040static Datum
4042 bool is_json, bool have_record_arg)
4043{
4044 int json_arg_num = have_record_arg ? 1 : 0;
4045 ReturnSetInfo *rsi;
4046 MemoryContext old_cxt;
4047 HeapTupleHeader rec;
4048 PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
4050
4051 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
4052
4053 if (!rsi || !IsA(rsi, ReturnSetInfo))
4054 ereport(ERROR,
4055 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4056 errmsg("set-valued function called in context that cannot accept a set")));
4057
4058 if (!(rsi->allowedModes & SFRM_Materialize))
4059 ereport(ERROR,
4060 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4061 errmsg("materialize mode required, but it is not allowed in this context")));
4062
4064
4065 /*
4066 * If first time through, identify input/result record type. Note that
4067 * this stanza looks only at fcinfo context, which can't change during the
4068 * query; so we may not be able to fully resolve a RECORD input type yet.
4069 */
4070 if (!cache)
4071 {
4072 fcinfo->flinfo->fn_extra = cache =
4073 MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, sizeof(*cache));
4074 cache->fn_mcxt = fcinfo->flinfo->fn_mcxt;
4075
4076 if (have_record_arg)
4078 else
4079 get_record_type_from_query(fcinfo, funcname, cache);
4080 }
4081
4082 /* Collect record arg if we have one */
4083 if (!have_record_arg)
4084 rec = NULL; /* it's json{b}_to_recordset() */
4085 else if (!PG_ARGISNULL(0))
4086 {
4088
4089 /*
4090 * When declared arg type is RECORD, identify actual record type from
4091 * the tuple itself.
4092 */
4093 if (cache->argtype == RECORDOID)
4094 {
4097 }
4098 }
4099 else
4100 {
4101 rec = NULL;
4102
4103 /*
4104 * When declared arg type is RECORD, identify actual record type from
4105 * calling query, or fail if we can't.
4106 */
4107 if (cache->argtype == RECORDOID)
4108 {
4109 get_record_type_from_query(fcinfo, funcname, cache);
4110 /* This can't change argtype, which is important for next time */
4111 Assert(cache->argtype == RECORDOID);
4112 }
4113 }
4114
4115 /* if the json is null send back an empty set */
4116 if (PG_ARGISNULL(json_arg_num))
4118
4119 /*
4120 * Forcibly update the cached tupdesc, to ensure we have the right tupdesc
4121 * to return even if the JSON contains no rows.
4122 */
4123 update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4124
4126
4127 /* make tuplestore in a sufficiently long-lived memory context */
4129 state->tuple_store = tuplestore_begin_heap(rsi->allowedModes &
4131 false, work_mem);
4132 MemoryContextSwitchTo(old_cxt);
4133
4134 state->function_name = funcname;
4135 state->cache = cache;
4136 state->rec = rec;
4137
4138 if (is_json)
4139 {
4140 text *json = PG_GETARG_TEXT_PP(json_arg_num);
4141 JsonLexContext lex;
4143
4144 sem = palloc0(sizeof(JsonSemAction));
4145
4146 makeJsonLexContext(&lex, json, true);
4147
4148 sem->semstate = state;
4156
4157 state->lex = &lex;
4158
4160
4161 freeJsonLexContext(&lex);
4162 state->lex = NULL;
4163 }
4164 else
4165 {
4166 Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
4167 JsonbIterator *it;
4168 JsonbValue v;
4169 bool skipNested = false;
4171
4172 if (JB_ROOT_IS_SCALAR(jb) || !JB_ROOT_IS_ARRAY(jb))
4173 ereport(ERROR,
4174 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4175 errmsg("cannot call %s on a non-array",
4176 funcname)));
4177
4178 it = JsonbIteratorInit(&jb->root);
4179
4180 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4181 {
4182 skipNested = true;
4183
4184 if (r == WJB_ELEM)
4185 {
4186 JsObject obj;
4187
4188 if (v.type != jbvBinary ||
4189 !JsonContainerIsObject(v.val.binary.data))
4190 ereport(ERROR,
4191 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4192 errmsg("argument of %s must be an array of objects",
4193 funcname)));
4194
4195 obj.is_json = false;
4196 obj.val.jsonb_cont = v.val.binary.data;
4197
4199 }
4200 }
4201 }
4202
4203 /*
4204 * Note: we must copy the cached tupdesc because the executor will free
4205 * the passed-back setDesc, but we want to hang onto the cache in case
4206 * we're called again in the same query.
4207 */
4208 rsi->setResult = state->tuple_store;
4210
4212}
4213
4214static JsonParseErrorType
4216{
4218 int lex_level = _state->lex->lex_level;
4219 HASHCTL ctl;
4220
4221 /* Reject object at top level: we must have an array at level 0 */
4222 if (lex_level == 0)
4223 ereport(ERROR,
4224 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4225 errmsg("cannot call %s on an object",
4226 _state->function_name)));
4227
4228 /* Nested objects require no special processing */
4229 if (lex_level > 1)
4230 return JSON_SUCCESS;
4231
4232 /* Object at level 1: set up a new hash table for this object */
4233 ctl.keysize = NAMEDATALEN;
4234 ctl.entrysize = sizeof(JsonHashEntry);
4236 _state->json_hash = hash_create("json object hashtable",
4237 100,
4238 &ctl,
4240
4241 return JSON_SUCCESS;
4242}
4243
4244static JsonParseErrorType
4246{
4248 JsObject obj;
4249
4250 /* Nested objects require no special processing */
4251 if (_state->lex->lex_level > 1)
4252 return JSON_SUCCESS;
4253
4254 obj.is_json = true;
4255 obj.val.json_hash = _state->json_hash;
4256
4257 /* Otherwise, construct and return a tuple based on this level-1 object */
4258 populate_recordset_record(_state, &obj);
4259
4260 /* Done with hash for this object */
4261 hash_destroy(_state->json_hash);
4262 _state->json_hash = NULL;
4263
4264 return JSON_SUCCESS;
4265}
4266
4267static JsonParseErrorType
4269{
4271
4272 if (_state->lex->lex_level == 1 &&
4274 ereport(ERROR,
4275 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4276 errmsg("argument of %s must be an array of objects",
4277 _state->function_name)));
4278
4279 return JSON_SUCCESS;
4280}
4281
4282static JsonParseErrorType
4284{
4285 /* nothing to do */
4286 return JSON_SUCCESS;
4287}
4288
4289static JsonParseErrorType
4291{
4293
4294 if (_state->lex->lex_level == 0)
4295 ereport(ERROR,
4296 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4297 errmsg("cannot call %s on a scalar",
4298 _state->function_name)));
4299
4300 if (_state->lex->lex_level == 2)
4301 _state->saved_scalar = token;
4302
4303 return JSON_SUCCESS;
4304}
4305
4306static JsonParseErrorType
4307populate_recordset_object_field_start(void *state, char *fname, bool isnull)
4308{
4310
4311 if (_state->lex->lex_level > 2)
4312 return JSON_SUCCESS;
4313
4314 _state->saved_token_type = _state->lex->token_type;
4315
4316 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
4318 {
4319 _state->save_json_start = _state->lex->token_start;
4320 }
4321 else
4322 {
4323 _state->save_json_start = NULL;
4324 }
4325
4326 return JSON_SUCCESS;
4327}
4328
4329static JsonParseErrorType
4330populate_recordset_object_field_end(void *state, char *fname, bool isnull)
4331{
4333 JsonHashEntry *hashentry;
4334 bool found;
4335
4336 /*
4337 * Ignore nested fields.
4338 */
4339 if (_state->lex->lex_level > 2)
4340 return JSON_SUCCESS;
4341
4342 /*
4343 * Ignore field names >= NAMEDATALEN - they can't match a record field.
4344 * (Note: without this test, the hash code would truncate the string at
4345 * NAMEDATALEN-1, and could then match against a similarly-truncated
4346 * record field name. That would be a reasonable behavior, but this code
4347 * has previously insisted on exact equality, so we keep this behavior.)
4348 */
4349 if (strlen(fname) >= NAMEDATALEN)
4350 return JSON_SUCCESS;
4351
4352 hashentry = hash_search(_state->json_hash, fname, HASH_ENTER, &found);
4353
4354 /*
4355 * found being true indicates a duplicate. We don't do anything about
4356 * that, a later field with the same name overrides the earlier field.
4357 */
4358
4359 hashentry->type = _state->saved_token_type;
4360 Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
4361
4362 if (_state->save_json_start != NULL)
4363 {
4364 int len = _state->lex->prev_token_terminator - _state->save_json_start;
4365 char *val = palloc((len + 1) * sizeof(char));
4366
4367 memcpy(val, _state->save_json_start, len);
4368 val[len] = '\0';
4369 hashentry->val = val;
4370 }
4371 else
4372 {
4373 /* must have had a scalar instead */
4374 hashentry->val = _state->saved_scalar;
4375 }
4376
4377 return JSON_SUCCESS;
4378}
4379
4380/*
4381 * Semantic actions for json_strip_nulls.
4382 *
4383 * Simply repeat the input on the output unless we encounter
4384 * a null object field. State for this is set when the field
4385 * is started and reset when the scalar action (which must be next)
4386 * is called.
4387 */
4388
4389static JsonParseErrorType
4391{
4392 StripnullState *_state = (StripnullState *) state;
4393
4394 appendStringInfoCharMacro(_state->strval, '{');
4395
4396 return JSON_SUCCESS;
4397}
4398
4399static JsonParseErrorType
4401{
4402 StripnullState *_state = (StripnullState *) state;
4403
4404 appendStringInfoCharMacro(_state->strval, '}');
4405
4406 return JSON_SUCCESS;
4407}
4408
4409static JsonParseErrorType
4411{
4412 StripnullState *_state = (StripnullState *) state;
4413
4414 appendStringInfoCharMacro(_state->strval, '[');
4415
4416 return JSON_SUCCESS;
4417}
4418
4419static JsonParseErrorType
4421{
4422 StripnullState *_state = (StripnullState *) state;
4423
4424 appendStringInfoCharMacro(_state->strval, ']');
4425
4426 return JSON_SUCCESS;
4427}
4428
4429static JsonParseErrorType
4430sn_object_field_start(void *state, char *fname, bool isnull)
4431{
4432 StripnullState *_state = (StripnullState *) state;
4433
4434 if (isnull)
4435 {
4436 /*
4437 * The next thing must be a scalar or isnull couldn't be true, so
4438 * there is no danger of this state being carried down into a nested
4439 * object or array. The flag will be reset in the scalar action.
4440 */
4441 _state->skip_next_null = true;
4442 return JSON_SUCCESS;
4443 }
4444
4445 if (_state->strval->data[_state->strval->len - 1] != '{')
4446 appendStringInfoCharMacro(_state->strval, ',');
4447
4448 /*
4449 * Unfortunately we don't have the quoted and escaped string any more, so
4450 * we have to re-escape it.
4451 */
4452 escape_json(_state->strval, fname);
4453
4454 appendStringInfoCharMacro(_state->strval, ':');
4455
4456 return JSON_SUCCESS;
4457}
4458
4459static JsonParseErrorType
4461{
4462 StripnullState *_state = (StripnullState *) state;
4463
4464 /* If strip_in_arrays is enabled and this is a null, mark it for skipping */
4465 if (isnull && _state->strip_in_arrays)
4466 {
4467 _state->skip_next_null = true;
4468 return JSON_SUCCESS;
4469 }
4470
4471 /* Only add a comma if this is not the first valid element */
4472 if (_state->strval->len > 0 &&
4473 _state->strval->data[_state->strval->len - 1] != '[')
4474 {
4475 appendStringInfoCharMacro(_state->strval, ',');
4476 }
4477
4478 return JSON_SUCCESS;
4479}
4480
4481static JsonParseErrorType
4482sn_scalar(void *state, char *token, JsonTokenType tokentype)
4483{
4484 StripnullState *_state = (StripnullState *) state;
4485
4486 if (_state->skip_next_null)
4487 {
4488 Assert(tokentype == JSON_TOKEN_NULL);
4489 _state->skip_next_null = false;
4490 return JSON_SUCCESS;
4491 }
4492
4493 if (tokentype == JSON_TOKEN_STRING)
4494 escape_json(_state->strval, token);
4495 else
4497
4498 return JSON_SUCCESS;
4499}
4500
4501/*
4502 * SQL function json_strip_nulls(json) -> json
4503 */
4504Datum
4506{
4507 text *json = PG_GETARG_TEXT_PP(0);
4508 bool strip_in_arrays = PG_NARGS() == 2 ? PG_GETARG_BOOL(1) : false;
4510 JsonLexContext lex;
4512
4513 state = palloc0(sizeof(StripnullState));
4514 sem = palloc0(sizeof(JsonSemAction));
4515
4516 state->lex = makeJsonLexContext(&lex, json, true);
4517 state->strval = makeStringInfo();
4518 state->skip_next_null = false;
4519 state->strip_in_arrays = strip_in_arrays;
4520
4521 sem->semstate = state;
4526 sem->scalar = sn_scalar;
4529
4531
4533 state->strval->len));
4534}
4535
4536/*
4537 * SQL function jsonb_strip_nulls(jsonb, bool) -> jsonb
4538 */
4539Datum
4541{
4542 Jsonb *jb = PG_GETARG_JSONB_P(0);
4543 bool strip_in_arrays = false;
4544 JsonbIterator *it;
4545 JsonbParseState *parseState = NULL;
4546 JsonbValue *res = NULL;
4547 JsonbValue v,
4548 k;
4550 bool last_was_key = false;
4551
4552 if (PG_NARGS() == 2)
4553 strip_in_arrays = PG_GETARG_BOOL(1);
4554
4555 if (JB_ROOT_IS_SCALAR(jb))
4557
4558 it = JsonbIteratorInit(&jb->root);
4559
4560 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
4561 {
4562 Assert(!(type == WJB_KEY && last_was_key));
4563
4564 if (type == WJB_KEY)
4565 {
4566 /* stash the key until we know if it has a null value */
4567 k = v;
4568 last_was_key = true;
4569 continue;
4570 }
4571
4572 if (last_was_key)
4573 {
4574 /* if the last element was a key this one can't be */
4575 last_was_key = false;
4576
4577 /* skip this field if value is null */
4578 if (type == WJB_VALUE && v.type == jbvNull)
4579 continue;
4580
4581 /* otherwise, do a delayed push of the key */
4582 (void) pushJsonbValue(&parseState, WJB_KEY, &k);
4583 }
4584
4585 /* if strip_in_arrays is set, also skip null array elements */
4586 if (strip_in_arrays)
4587 if (type == WJB_ELEM && v.type == jbvNull)
4588 continue;
4589
4590 if (type == WJB_VALUE || type == WJB_ELEM)
4591 res = pushJsonbValue(&parseState, type, &v);
4592 else
4593 res = pushJsonbValue(&parseState, type, NULL);
4594 }
4595
4596 Assert(res != NULL);
4597
4599}
4600
4601/*
4602 * SQL function jsonb_pretty (jsonb)
4603 *
4604 * Pretty-printed text for the jsonb
4605 */
4606Datum
4608{
4609 Jsonb *jb = PG_GETARG_JSONB_P(0);
4611
4613
4615}
4616
4617/*
4618 * SQL function jsonb_concat (jsonb, jsonb)
4619 *
4620 * function for || operator
4621 */
4622Datum
4624{
4625 Jsonb *jb1 = PG_GETARG_JSONB_P(0);
4626 Jsonb *jb2 = PG_GETARG_JSONB_P(1);
4627 JsonbParseState *state = NULL;
4628 JsonbValue *res;
4629 JsonbIterator *it1,
4630 *it2;
4631
4632 /*
4633 * If one of the jsonb is empty, just return the other if it's not scalar
4634 * and both are of the same kind. If it's a scalar or they are of
4635 * different kinds we need to perform the concatenation even if one is
4636 * empty.
4637 */
4638 if (JB_ROOT_IS_OBJECT(jb1) == JB_ROOT_IS_OBJECT(jb2))
4639 {
4640 if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
4641 PG_RETURN_JSONB_P(jb2);
4642 else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
4643 PG_RETURN_JSONB_P(jb1);
4644 }
4645
4646 it1 = JsonbIteratorInit(&jb1->root);
4647 it2 = JsonbIteratorInit(&jb2->root);
4648
4649 res = IteratorConcat(&it1, &it2, &state);
4650
4651 Assert(res != NULL);
4652
4654}
4655
4656
4657/*
4658 * SQL function jsonb_delete (jsonb, text)
4659 *
4660 * return a copy of the jsonb with the indicated item
4661 * removed.
4662 */
4663Datum
4665{
4666 Jsonb *in = PG_GETARG_JSONB_P(0);
4668 char *keyptr = VARDATA_ANY(key);
4669 int keylen = VARSIZE_ANY_EXHDR(key);
4670 JsonbParseState *state = NULL;
4671 JsonbIterator *it;
4672 JsonbValue v,
4673 *res = NULL;
4674 bool skipNested = false;
4676
4677 if (JB_ROOT_IS_SCALAR(in))
4678 ereport(ERROR,
4679 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4680 errmsg("cannot delete from scalar")));
4681
4682 if (JB_ROOT_COUNT(in) == 0)
4684
4685 it = JsonbIteratorInit(&in->root);
4686
4687 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4688 {
4689 skipNested = true;
4690
4691 if ((r == WJB_ELEM || r == WJB_KEY) &&
4692 (v.type == jbvString && keylen == v.val.string.len &&
4693 memcmp(keyptr, v.val.string.val, keylen) == 0))
4694 {
4695 /* skip corresponding value as well */
4696 if (r == WJB_KEY)
4697 (void) JsonbIteratorNext(&it, &v, true);
4698
4699 continue;
4700 }
4701
4702 res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4703 }
4704
4705 Assert(res != NULL);
4706
4708}
4709
4710/*
4711 * SQL function jsonb_delete (jsonb, variadic text[])
4712 *
4713 * return a copy of the jsonb with the indicated items
4714 * removed.
4715 */
4716Datum
4718{
4719 Jsonb *in = PG_GETARG_JSONB_P(0);
4721 Datum *keys_elems;
4722 bool *keys_nulls;
4723 int keys_len;
4724 JsonbParseState *state = NULL;
4725 JsonbIterator *it;
4726 JsonbValue v,
4727 *res = NULL;
4728 bool skipNested = false;
4730
4731 if (ARR_NDIM(keys) > 1)
4732 ereport(ERROR,
4733 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4734 errmsg("wrong number of array subscripts")));
4735
4736 if (JB_ROOT_IS_SCALAR(in))
4737 ereport(ERROR,
4738 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4739 errmsg("cannot delete from scalar")));
4740
4741 if (JB_ROOT_COUNT(in) == 0)
4743
4744 deconstruct_array_builtin(keys, TEXTOID, &keys_elems, &keys_nulls, &keys_len);
4745
4746 if (keys_len == 0)
4748
4749 it = JsonbIteratorInit(&in->root);
4750
4751 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4752 {
4753 skipNested = true;
4754
4755 if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString)
4756 {
4757 int i;
4758 bool found = false;
4759
4760 for (i = 0; i < keys_len; i++)
4761 {
4762 char *keyptr;
4763 int keylen;
4764
4765 if (keys_nulls[i])
4766 continue;
4767
4768 /* We rely on the array elements not being toasted */
4769 keyptr = VARDATA_ANY(keys_elems[i]);
4770 keylen = VARSIZE_ANY_EXHDR(keys_elems[i]);
4771 if (keylen == v.val.string.len &&
4772 memcmp(keyptr, v.val.string.val, keylen) == 0)
4773 {
4774 found = true;
4775 break;
4776 }
4777 }
4778 if (found)
4779 {
4780 /* skip corresponding value as well */
4781 if (r == WJB_KEY)
4782 (void) JsonbIteratorNext(&it, &v, true);
4783
4784 continue;
4785 }
4786 }
4787
4788 res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4789 }
4790
4791 Assert(res != NULL);
4792
4794}
4795
4796/*
4797 * SQL function jsonb_delete (jsonb, int)
4798 *
4799 * return a copy of the jsonb with the indicated item
4800 * removed. Negative int means count back from the
4801 * end of the items.
4802 */
4803Datum
4805{
4806 Jsonb *in = PG_GETARG_JSONB_P(0);
4807 int idx = PG_GETARG_INT32(1);
4808 JsonbParseState *state = NULL;
4809 JsonbIterator *it;
4810 uint32 i = 0,
4811 n;
4812 JsonbValue v,
4813 *res = NULL;
4815
4816 if (JB_ROOT_IS_SCALAR(in))
4817 ereport(ERROR,
4818 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4819 errmsg("cannot delete from scalar")));
4820
4821 if (JB_ROOT_IS_OBJECT(in))
4822 ereport(ERROR,
4823 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4824 errmsg("cannot delete from object using integer index")));
4825
4826 if (JB_ROOT_COUNT(in) == 0)
4828
4829 it = JsonbIteratorInit(&in->root);
4830
4831 r = JsonbIteratorNext(&it, &v, false);
4832 Assert(r == WJB_BEGIN_ARRAY);
4833 n = v.val.array.nElems;
4834
4835 if (idx < 0)
4836 {
4837 if (pg_abs_s32(idx) > n)
4838 idx = n;
4839 else
4840 idx = n + idx;
4841 }
4842
4843 if (idx >= n)
4845
4846 pushJsonbValue(&state, r, NULL);
4847
4848 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
4849 {
4850 if (r == WJB_ELEM)
4851 {
4852 if (i++ == idx)
4853 continue;
4854 }
4855
4856 res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4857 }
4858
4859 Assert(res != NULL);
4860
4862}
4863
4864/*
4865 * SQL function jsonb_set(jsonb, text[], jsonb, boolean)
4866 */
4867Datum
4869{
4870 Jsonb *in = PG_GETARG_JSONB_P(0);
4872 Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
4874 bool create = PG_GETARG_BOOL(3);
4875 JsonbValue *res = NULL;
4876 Datum *path_elems;
4877 bool *path_nulls;
4878 int path_len;
4879 JsonbIterator *it;
4880 JsonbParseState *st = NULL;
4881
4882 JsonbToJsonbValue(newjsonb, &newval);
4883
4884 if (ARR_NDIM(path) > 1)
4885 ereport(ERROR,
4886 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4887 errmsg("wrong number of array subscripts")));
4888
4889 if (JB_ROOT_IS_SCALAR(in))
4890 ereport(ERROR,
4891 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4892 errmsg("cannot set path in scalar")));
4893
4894 if (JB_ROOT_COUNT(in) == 0 && !create)
4896
4897 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4898
4899 if (path_len == 0)
4901
4902 it = JsonbIteratorInit(&in->root);
4903
4904 res = setPath(&it, path_elems, path_nulls, path_len, &st,
4905 0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4906
4907 Assert(res != NULL);
4908
4910}
4911
4912
4913/*
4914 * SQL function jsonb_set_lax(jsonb, text[], jsonb, boolean, text)
4915 */
4916Datum
4918{
4919 /* Jsonb *in = PG_GETARG_JSONB_P(0); */
4920 /* ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); */
4921 /* Jsonb *newval = PG_GETARG_JSONB_P(2); */
4922 /* bool create = PG_GETARG_BOOL(3); */
4923 text *handle_null;
4924 char *handle_val;
4925
4926 if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
4928
4929 /* could happen if they pass in an explicit NULL */
4930 if (PG_ARGISNULL(4))
4931 ereport(ERROR,
4932 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4933 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4934
4935 /* if the new value isn't an SQL NULL just call jsonb_set */
4936 if (!PG_ARGISNULL(2))
4937 return jsonb_set(fcinfo);
4938
4939 handle_null = PG_GETARG_TEXT_P(4);
4940 handle_val = text_to_cstring(handle_null);
4941
4942 if (strcmp(handle_val, "raise_exception") == 0)
4943 {
4944 ereport(ERROR,
4945 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4946 errmsg("JSON value must not be null"),
4947 errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
4948 errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed.")));
4949 return (Datum) 0; /* silence stupider compilers */
4950 }
4951 else if (strcmp(handle_val, "use_json_null") == 0)
4952 {
4953 Datum newval;
4954
4956
4957 fcinfo->args[2].value = newval;
4958 fcinfo->args[2].isnull = false;
4959 return jsonb_set(fcinfo);
4960 }
4961 else if (strcmp(handle_val, "delete_key") == 0)
4962 {
4963 return jsonb_delete_path(fcinfo);
4964 }
4965 else if (strcmp(handle_val, "return_target") == 0)
4966 {
4967 Jsonb *in = PG_GETARG_JSONB_P(0);
4968
4970 }
4971 else
4972 {
4973 ereport(ERROR,
4974 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4975 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4976 return (Datum) 0; /* silence stupider compilers */
4977 }
4978}
4979
4980/*
4981 * SQL function jsonb_delete_path(jsonb, text[])
4982 */
4983Datum
4985{
4986 Jsonb *in = PG_GETARG_JSONB_P(0);
4988 JsonbValue *res = NULL;
4989 Datum *path_elems;
4990 bool *path_nulls;
4991 int path_len;
4992 JsonbIterator *it;
4993 JsonbParseState *st = NULL;
4994
4995 if (ARR_NDIM(path) > 1)
4996 ereport(ERROR,
4997 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4998 errmsg("wrong number of array subscripts")));
4999
5000 if (JB_ROOT_IS_SCALAR(in))
5001 ereport(ERROR,
5002 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5003 errmsg("cannot delete path in scalar")));
5004
5005 if (JB_ROOT_COUNT(in) == 0)
5007
5008 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
5009
5010 if (path_len == 0)
5012
5013 it = JsonbIteratorInit(&in->root);
5014
5015 res = setPath(&it, path_elems, path_nulls, path_len, &st,
5016 0, NULL, JB_PATH_DELETE);
5017
5018 Assert(res != NULL);
5019
5021}
5022
5023/*
5024 * SQL function jsonb_insert(jsonb, text[], jsonb, boolean)
5025 */
5026Datum
5028{
5029 Jsonb *in = PG_GETARG_JSONB_P(0);
5031 Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
5033 bool after = PG_GETARG_BOOL(3);
5034 JsonbValue *res = NULL;
5035 Datum *path_elems;
5036 bool *path_nulls;
5037 int path_len;
5038 JsonbIterator *it;
5039 JsonbParseState *st = NULL;
5040
5041 JsonbToJsonbValue(newjsonb, &newval);
5042
5043 if (ARR_NDIM(path) > 1)
5044 ereport(ERROR,
5045 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5046 errmsg("wrong number of array subscripts")));
5047
5048 if (JB_ROOT_IS_SCALAR(in))
5049 ereport(ERROR,
5050 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5051 errmsg("cannot set path in scalar")));
5052
5053 deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
5054
5055 if (path_len == 0)
5057
5058 it = JsonbIteratorInit(&in->root);
5059
5060 res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, &newval,
5062
5063 Assert(res != NULL);
5064
5066}
5067
5068/*
5069 * Iterate over all jsonb objects and merge them into one.
5070 * The logic of this function copied from the same hstore function,
5071 * except the case, when it1 & it2 represents jbvObject.
5072 * In that case we just append the content of it2 to it1 without any
5073 * verifications.
5074 */
5075static JsonbValue *
5078{
5079 JsonbValue v1,
5080 v2,
5081 *res = NULL;
5083 r2,
5084 rk1,
5085 rk2;
5086
5087 rk1 = JsonbIteratorNext(it1, &v1, false);
5088 rk2 = JsonbIteratorNext(it2, &v2, false);
5089
5090 /*
5091 * JsonbIteratorNext reports raw scalars as if they were single-element
5092 * arrays; hence we only need consider "object" and "array" cases here.
5093 */
5094 if (rk1 == WJB_BEGIN_OBJECT && rk2 == WJB_BEGIN_OBJECT)
5095 {
5096 /*
5097 * Both inputs are objects.
5098 *
5099 * Append all the tokens from v1 to res, except last WJB_END_OBJECT
5100 * (because res will not be finished yet).
5101 */
5102 pushJsonbValue(state, rk1, NULL);
5103 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_OBJECT)
5104 pushJsonbValue(state, r1, &v1);
5105
5106 /*
5107 * Append all the tokens from v2 to res, including last WJB_END_OBJECT
5108 * (the concatenation will be completed). Any duplicate keys will
5109 * automatically override the value from the first object.
5110 */
5111 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5112 res = pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
5113 }
5114 else if (rk1 == WJB_BEGIN_ARRAY && rk2 == WJB_BEGIN_ARRAY)
5115 {
5116 /*
5117 * Both inputs are arrays.
5118 */
5119 pushJsonbValue(state, rk1, NULL);
5120
5121 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5122 {
5123 Assert(r1 == WJB_ELEM);
5124 pushJsonbValue(state, r1, &v1);
5125 }
5126
5127 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_END_ARRAY)
5128 {
5129 Assert(r2 == WJB_ELEM);
5131 }
5132
5133 res = pushJsonbValue(state, WJB_END_ARRAY, NULL /* signal to sort */ );
5134 }
5135 else if (rk1 == WJB_BEGIN_OBJECT)
5136 {
5137 /*
5138 * We have object || array.
5139 */
5140 Assert(rk2 == WJB_BEGIN_ARRAY);
5141
5143
5145 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_DONE)
5146 pushJsonbValue(state, r1, r1 != WJB_END_OBJECT ? &v1 : NULL);
5147
5148 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5149 res = pushJsonbValue(state, r2, r2 != WJB_END_ARRAY ? &v2 : NULL);
5150 }
5151 else
5152 {
5153 /*
5154 * We have array || object.
5155 */
5156 Assert(rk1 == WJB_BEGIN_ARRAY);
5157 Assert(rk2 == WJB_BEGIN_OBJECT);
5158
5160
5161 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5162 pushJsonbValue(state, r1, &v1);
5163
5165 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5166 pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
5167
5168 res = pushJsonbValue(state, WJB_END_ARRAY, NULL);
5169 }
5170
5171 return res;
5172}
5173
5174/*
5175 * Do most of the heavy work for jsonb_set/jsonb_insert
5176 *
5177 * If JB_PATH_DELETE bit is set in op_type, the element is to be removed.
5178 *
5179 * If any bit mentioned in JB_PATH_CREATE_OR_INSERT is set in op_type,
5180 * we create the new value if the key or array index does not exist.
5181 *
5182 * Bits JB_PATH_INSERT_BEFORE and JB_PATH_INSERT_AFTER in op_type
5183 * behave as JB_PATH_CREATE if new value is inserted in JsonbObject.
5184 *
5185 * If JB_PATH_FILL_GAPS bit is set, this will change an assignment logic in
5186 * case if target is an array. The assignment index will not be restricted by
5187 * number of elements in the array, and if there are any empty slots between
5188 * last element of the array and a new one they will be filled with nulls. If
5189 * the index is negative, it still will be considered an index from the end
5190 * of the array. Of a part of the path is not present and this part is more
5191 * than just one last element, this flag will instruct to create the whole
5192 * chain of corresponding objects and insert the value.
5193 *
5194 * JB_PATH_CONSISTENT_POSITION for an array indicates that the caller wants to
5195 * keep values with fixed indices. Indices for existing elements could be
5196 * changed (shifted forward) in case if the array is prepended with a new value
5197 * and a negative index out of the range, so this behavior will be prevented
5198 * and return an error.
5199 *
5200 * All path elements before the last must already exist
5201 * whatever bits in op_type are set, or nothing is done.
5202 */
5203static JsonbValue *
5204setPath(JsonbIterator **it, Datum *path_elems,
5205 bool *path_nulls, int path_len,
5206 JsonbParseState **st, int level, JsonbValue *newval, int op_type)
5207{
5208 JsonbValue v;
5210 JsonbValue *res;
5211
5213
5214 if (path_nulls[level])
5215 ereport(ERROR,
5216 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5217 errmsg("path element at position %d is null",
5218 level + 1)));
5219
5220 r = JsonbIteratorNext(it, &v, false);
5221
5222 switch (r)
5223 {
5224 case WJB_BEGIN_ARRAY:
5225
5226 /*
5227 * If instructed complain about attempts to replace within a raw
5228 * scalar value. This happens even when current level is equal to
5229 * path_len, because the last path key should also correspond to
5230 * an object or an array, not raw scalar.
5231 */
5232 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) &&
5233 v.val.array.rawScalar)
5234 ereport(ERROR,
5235 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5236 errmsg("cannot replace existing key"),
5237 errdetail("The path assumes key is a composite object, "
5238 "but it is a scalar value.")));
5239
5240 (void) pushJsonbValue(st, r, NULL);
5241 setPathArray(it, path_elems, path_nulls, path_len, st, level,
5242 newval, v.val.array.nElems, op_type);
5243 r = JsonbIteratorNext(it, &v, false);
5244 Assert(r == WJB_END_ARRAY);
5245 res = pushJsonbValue(st, r, NULL);
5246 break;
5247 case WJB_BEGIN_OBJECT:
5248 (void) pushJsonbValue(st, r, NULL);
5249 setPathObject(it, path_elems, path_nulls, path_len, st, level,
5250 newval, v.val.object.nPairs, op_type);
5251 r = JsonbIteratorNext(it, &v, true);
5252 Assert(r == WJB_END_OBJECT);
5253 res = pushJsonbValue(st, r, NULL);
5254 break;
5255 case WJB_ELEM:
5256 case WJB_VALUE:
5257
5258 /*
5259 * If instructed complain about attempts to replace within a
5260 * scalar value. This happens even when current level is equal to
5261 * path_len, because the last path key should also correspond to
5262 * an object or an array, not an element or value.
5263 */
5264 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1))
5265 ereport(ERROR,
5266 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5267 errmsg("cannot replace existing key"),
5268 errdetail("The path assumes key is a composite object, "
5269 "but it is a scalar value.")));
5270
5271 res = pushJsonbValue(st, r, &v);
5272 break;
5273 default:
5274 elog(ERROR, "unrecognized iterator result: %d", (int) r);
5275 res = NULL; /* keep compiler quiet */
5276 break;
5277 }
5278
5279 return res;
5280}
5281
5282/*
5283 * Object walker for setPath
5284 */
5285static void
5286setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
5287 int path_len, JsonbParseState **st, int level,
5288 JsonbValue *newval, uint32 npairs, int op_type)
5289{
5290 text *pathelem = NULL;
5291 int i;
5292 JsonbValue k,
5293 v;
5294 bool done = false;
5295
5296 if (level >= path_len || path_nulls[level])
5297 done = true;
5298 else
5299 {
5300 /* The path Datum could be toasted, in which case we must detoast it */
5301 pathelem = DatumGetTextPP(path_elems[level]);
5302 }
5303
5304 /* empty object is a special case for create */
5305 if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
5306 (level == path_len - 1))
5307 {
5308 JsonbValue newkey;
5309
5310 newkey.type = jbvString;
5311 newkey.val.string.val = VARDATA_ANY(pathelem);
5312 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5313
5314 (void) pushJsonbValue(st, WJB_KEY, &newkey);
5315 (void) pushJsonbValue(st, WJB_VALUE, newval);
5316 }
5317
5318 for (i = 0; i < npairs; i++)
5319 {
5320 JsonbIteratorToken r = JsonbIteratorNext(it, &k, true);
5321
5322 Assert(r == WJB_KEY);
5323
5324 if (!done &&
5325 k.val.string.len == VARSIZE_ANY_EXHDR(pathelem) &&
5326 memcmp(k.val.string.val, VARDATA_ANY(pathelem),
5327 k.val.string.len) == 0)
5328 {
5329 done = true;
5330
5331 if (level == path_len - 1)
5332 {
5333 /*
5334 * called from jsonb_insert(), it forbids redefining an
5335 * existing value
5336 */
5338 ereport(ERROR,
5339 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5340 errmsg("cannot replace existing key"),
5341 errhint("Try using the function jsonb_set "
5342 "to replace key value.")));
5343
5344 r = JsonbIteratorNext(it, &v, true); /* skip value */
5345 if (!(op_type & JB_PATH_DELETE))
5346 {
5347 (void) pushJsonbValue(st, WJB_KEY, &k);
5348 (void) pushJsonbValue(st, WJB_VALUE, newval);
5349 }
5350 }
5351 else
5352 {
5353 (void) pushJsonbValue(st, r, &k);
5354 setPath(it, path_elems, path_nulls, path_len,
5355 st, level + 1, newval, op_type);
5356 }
5357 }
5358 else
5359 {
5360 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done &&
5361 level == path_len - 1 && i == npairs - 1)
5362 {
5363 JsonbValue newkey;
5364
5365 newkey.type = jbvString;
5366 newkey.val.string.val = VARDATA_ANY(pathelem);
5367 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5368
5369 (void) pushJsonbValue(st, WJB_KEY, &newkey);
5370 (void) pushJsonbValue(st, WJB_VALUE, newval);
5371 }
5372
5373 (void) pushJsonbValue(st, r, &k);
5374 r = JsonbIteratorNext(it, &v, false);
5375 (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5376 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5377 {
5378 int walking_level = 1;
5379
5380 while (walking_level != 0)
5381 {
5382 r = JsonbIteratorNext(it, &v, false);
5383
5384 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5385 ++walking_level;
5386 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5387 --walking_level;
5388
5389 (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5390 }
5391 }
5392 }
5393 }
5394
5395 /*--
5396 * If we got here there are only few possibilities:
5397 * - no target path was found, and an open object with some keys/values was
5398 * pushed into the state
5399 * - an object is empty, only WJB_BEGIN_OBJECT is pushed
5400 *
5401 * In both cases if instructed to create the path when not present,
5402 * generate the whole chain of empty objects and insert the new value
5403 * there.
5404 */
5405 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5406 {
5407 JsonbValue newkey;
5408
5409 newkey.type = jbvString;
5410 newkey.val.string.val = VARDATA_ANY(pathelem);
5411 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5412
5413 (void) pushJsonbValue(st, WJB_KEY, &newkey);
5414 (void) push_path(st, level, path_elems, path_nulls,
5415 path_len, newval);
5416
5417 /* Result is closed with WJB_END_OBJECT outside of this function */
5418 }
5419}
5420
5421/*
5422 * Array walker for setPath
5423 */
5424static void
5425setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
5426 int path_len, JsonbParseState **st, int level,
5427 JsonbValue *newval, uint32 nelems, int op_type)
5428{
5429 JsonbValue v;
5430 int idx,
5431 i;
5432 bool done = false;
5433
5434 /* pick correct index */
5435 if (level < path_len && !path_nulls[level])
5436 {
5437 char *c = TextDatumGetCString(path_elems[level]);
5438 char *badp;
5439
5440 errno = 0;
5441 idx = strtoint(c, &badp, 10);
5442 if (badp == c || *badp != '\0' || errno != 0)
5443 ereport(ERROR,
5444 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
5445 errmsg("path element at position %d is not an integer: \"%s\"",
5446 level + 1, c)));
5447 }
5448 else
5449 idx = nelems;
5450
5451 if (idx < 0)
5452 {
5453 if (pg_abs_s32(idx) > nelems)
5454 {
5455 /*
5456 * If asked to keep elements position consistent, it's not allowed
5457 * to prepend the array.
5458 */
5459 if (op_type & JB_PATH_CONSISTENT_POSITION)
5460 ereport(ERROR,
5461 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5462 errmsg("path element at position %d is out of range: %d",
5463 level + 1, idx)));
5464 else
5465 idx = PG_INT32_MIN;
5466 }
5467 else
5468 idx = nelems + idx;
5469 }
5470
5471 /*
5472 * Filling the gaps means there are no limits on the positive index are
5473 * imposed, we can set any element. Otherwise limit the index by nelems.
5474 */
5475 if (!(op_type & JB_PATH_FILL_GAPS))
5476 {
5477 if (idx > 0 && idx > nelems)
5478 idx = nelems;
5479 }
5480
5481 /*
5482 * if we're creating, and idx == INT_MIN, we prepend the new value to the
5483 * array also if the array is empty - in which case we don't really care
5484 * what the idx value is
5485 */
5486 if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) &&
5487 (op_type & JB_PATH_CREATE_OR_INSERT))
5488 {
5489 Assert(newval != NULL);
5490
5491 if (op_type & JB_PATH_FILL_GAPS && nelems == 0 && idx > 0)
5493
5494 (void) pushJsonbValue(st, WJB_ELEM, newval);
5495
5496 done = true;
5497 }
5498
5499 /* iterate over the array elements */
5500 for (i = 0; i < nelems; i++)
5501 {
5503
5504 if (i == idx && level < path_len)
5505 {
5506 done = true;
5507
5508 if (level == path_len - 1)
5509 {
5510 r = JsonbIteratorNext(it, &v, true); /* skip */
5511
5512 if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_CREATE))
5513 (void) pushJsonbValue(st, WJB_ELEM, newval);
5514
5515 /*
5516 * We should keep current value only in case of
5517 * JB_PATH_INSERT_BEFORE or JB_PATH_INSERT_AFTER because
5518 * otherwise it should be deleted or replaced
5519 */
5521 (void) pushJsonbValue(st, r, &v);
5522
5523 if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE))
5524 (void) pushJsonbValue(st, WJB_ELEM, newval);
5525 }
5526 else
5527 (void) setPath(it, path_elems, path_nulls, path_len,
5528 st, level + 1, newval, op_type);
5529 }
5530 else
5531 {
5532 r = JsonbIteratorNext(it, &v, false);
5533
5534 (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5535
5536 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5537 {
5538 int walking_level = 1;
5539
5540 while (walking_level != 0)
5541 {
5542 r = JsonbIteratorNext(it, &v, false);
5543
5544 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5545 ++walking_level;
5546 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5547 --walking_level;
5548
5549 (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5550 }
5551 }
5552 }
5553 }
5554
5555 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1)
5556 {
5557 /*
5558 * If asked to fill the gaps, idx could be bigger than nelems, so
5559 * prepend the new element with nulls if that's the case.
5560 */
5561 if (op_type & JB_PATH_FILL_GAPS && idx > nelems)
5562 push_null_elements(st, idx - nelems);
5563
5564 (void) pushJsonbValue(st, WJB_ELEM, newval);
5565 done = true;
5566 }
5567
5568 /*--
5569 * If we got here there are only few possibilities:
5570 * - no target path was found, and an open array with some keys/values was
5571 * pushed into the state
5572 * - an array is empty, only WJB_BEGIN_ARRAY is pushed
5573 *
5574 * In both cases if instructed to create the path when not present,
5575 * generate the whole chain of empty objects and insert the new value
5576 * there.
5577 */
5578 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5579 {
5580 if (idx > 0)
5581 push_null_elements(st, idx - nelems);
5582
5583 (void) push_path(st, level, path_elems, path_nulls,
5584 path_len, newval);
5585
5586 /* Result is closed with WJB_END_OBJECT outside of this function */
5587 }
5588}
5589
5590/*
5591 * Parse information about what elements of a jsonb document we want to iterate
5592 * in functions iterate_json(b)_values. This information is presented in jsonb
5593 * format, so that it can be easily extended in the future.
5594 */
5595uint32
5597{
5598 JsonbIterator *it;
5599 JsonbValue v;
5601 uint32 flags = 0;
5602
5603 it = JsonbIteratorInit(&jb->root);
5604
5605 type = JsonbIteratorNext(&it, &v, false);
5606
5607 /*
5608 * We iterate over array (scalar internally is represented as array, so,
5609 * we will accept it too) to check all its elements. Flag names are
5610 * chosen the same as jsonb_typeof uses.
5611 */
5612 if (type != WJB_BEGIN_ARRAY)
5613 ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5614 errmsg("wrong flag type, only arrays and scalars are allowed")));
5615
5616 while ((type = JsonbIteratorNext(&it, &v, false)) == WJB_ELEM)
5617 {
5618 if (v.type != jbvString)
5619 ereport(ERROR,
5620 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5621 errmsg("flag array element is not a string"),
5622 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5623
5624 if (v.val.string.len == 3 &&
5625 pg_strncasecmp(v.val.string.val, "all", 3) == 0)
5626 flags |= jtiAll;
5627 else if (v.val.string.len == 3 &&
5628 pg_strncasecmp(v.val.string.val, "key", 3) == 0)
5629 flags |= jtiKey;
5630 else if (v.val.string.len == 6 &&
5631 pg_strncasecmp(v.val.string.val, "string", 6) == 0)
5632 flags |= jtiString;
5633 else if (v.val.string.len == 7 &&
5634 pg_strncasecmp(v.val.string.val, "numeric", 7) == 0)
5635 flags |= jtiNumeric;
5636 else if (v.val.string.len == 7 &&
5637 pg_strncasecmp(v.val.string.val, "boolean", 7) == 0)
5638 flags |= jtiBool;
5639 else
5640 ereport(ERROR,
5641 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5642 errmsg("wrong flag in flag array: \"%s\"",
5643 pnstrdup(v.val.string.val, v.val.string.len)),
5644 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5645 }
5646
5647 /* expect end of array now */
5648 if (type != WJB_END_ARRAY)
5649 elog(ERROR, "unexpected end of flag array");
5650
5651 /* get final WJB_DONE and free iterator */
5652 type = JsonbIteratorNext(&it, &v, false);
5653 if (type != WJB_DONE)
5654 elog(ERROR, "unexpected end of flag array");
5655
5656 return flags;
5657}
5658
5659/*
5660 * Iterate over jsonb values or elements, specified by flags, and pass them
5661 * together with an iteration state to a specified JsonIterateStringValuesAction.
5662 */
5663void
5666{
5667 JsonbIterator *it;
5668 JsonbValue v;
5670
5671 it = JsonbIteratorInit(&jb->root);
5672
5673 /*
5674 * Just recursively iterating over jsonb and call callback on all
5675 * corresponding elements
5676 */
5677 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5678 {
5679 if (type == WJB_KEY)
5680 {
5681 if (flags & jtiKey)
5682 action(state, v.val.string.val, v.val.string.len);
5683
5684 continue;
5685 }
5686 else if (!(type == WJB_VALUE || type == WJB_ELEM))
5687 {
5688 /* do not call callback for composite JsonbValue */
5689 continue;
5690 }
5691
5692 /* JsonbValue is a value of object or element of array */
5693 switch (v.type)
5694 {
5695 case jbvString:
5696 if (flags & jtiString)
5697 action(state, v.val.string.val, v.val.string.len);
5698 break;
5699 case jbvNumeric:
5700 if (flags & jtiNumeric)
5701 {
5702 char *val;
5703
5705 NumericGetDatum(v.val.numeric)));
5706
5707 action(state, val, strlen(val));
5708 pfree(val);
5709 }
5710 break;
5711 case jbvBool:
5712 if (flags & jtiBool)
5713 {
5714 if (v.val.boolean)
5715 action(state, "true", 4);
5716 else
5717 action(state, "false", 5);
5718 }
5719 break;
5720 default:
5721 /* do not call callback for composite JsonbValue */
5722 break;
5723 }
5724 }
5725}
5726
5727/*
5728 * Iterate over json values and elements, specified by flags, and pass them
5729 * together with an iteration state to a specified JsonIterateStringValuesAction.
5730 */
5731void
5732iterate_json_values(text *json, uint32 flags, void *action_state,
5734{
5735 JsonLexContext lex;
5738
5739 state->lex = makeJsonLexContext(&lex, json, true);
5740 state->action = action;
5741 state->action_state = action_state;
5742 state->flags = flags;
5743
5744 sem->semstate = state;
5747
5749 freeJsonLexContext(&lex);
5750}
5751
5752/*
5753 * An auxiliary function for iterate_json_values to invoke a specified
5754 * JsonIterateStringValuesAction for specified values.
5755 */
5756static JsonParseErrorType
5758{
5760
5761 switch (tokentype)
5762 {
5763 case JSON_TOKEN_STRING:
5764 if (_state->flags & jtiString)
5765 _state->action(_state->action_state, token, strlen(token));
5766 break;
5767 case JSON_TOKEN_NUMBER:
5768 if (_state->flags & jtiNumeric)
5769 _state->action(_state->action_state, token, strlen(token));
5770 break;
5771 case JSON_TOKEN_TRUE:
5772 case JSON_TOKEN_FALSE:
5773 if (_state->flags & jtiBool)
5774 _state->action(_state->action_state, token, strlen(token));
5775 break;
5776 default:
5777 /* do not call callback for any other token */
5778 break;
5779 }
5780
5781 return JSON_SUCCESS;
5782}
5783
5784static JsonParseErrorType
5785iterate_values_object_field_start(void *state, char *fname, bool isnull)
5786{
5788
5789 if (_state->flags & jtiKey)
5790 {
5791 char *val = pstrdup(fname);
5792
5793 _state->action(_state->action_state, val, strlen(val));
5794 }
5795
5796 return JSON_SUCCESS;
5797}
5798
5799/*
5800 * Iterate over a jsonb, and apply a specified JsonTransformStringValuesAction
5801 * to every string value or element. Any necessary context for a
5802 * JsonTransformStringValuesAction can be passed in the action_state variable.
5803 * Function returns a copy of an original jsonb object with transformed values.
5804 */
5805Jsonb *
5806transform_jsonb_string_values(Jsonb *jsonb, void *action_state,
5807 JsonTransformStringValuesAction transform_action)
5808{
5809 JsonbIterator *it;
5810 JsonbValue v,
5811 *res = NULL;
5813 JsonbParseState *st = NULL;
5814 text *out;
5815 bool is_scalar = false;
5816
5817 it = JsonbIteratorInit(&jsonb->root);
5818 is_scalar = it->isScalar;
5819
5820 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5821 {
5822 if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
5823 {
5824 out = transform_action(action_state, v.val.string.val, v.val.string.len);
5825 /* out is probably not toasted, but let's be sure */
5826 out = pg_detoast_datum_packed(out);
5827 v.val.string.val = VARDATA_ANY(out);
5828 v.val.string.len = VARSIZE_ANY_EXHDR(out);
5829 res = pushJsonbValue(&st, type, type < WJB_BEGIN_ARRAY ? &v : NULL);
5830 }
5831 else
5832 {
5833 res = pushJsonbValue(&st, type, (type == WJB_KEY ||
5834 type == WJB_VALUE ||
5835 type == WJB_ELEM) ? &v : NULL);
5836 }
5837 }
5838
5839 if (res->type == jbvArray)
5840 res->val.array.rawScalar = is_scalar;
5841
5842 return JsonbValueToJsonb(res);
5843}
5844
5845/*
5846 * Iterate over a json, and apply a specified JsonTransformStringValuesAction
5847 * to every string value or element. Any necessary context for a
5848 * JsonTransformStringValuesAction can be passed in the action_state variable.
5849 * Function returns a StringInfo, which is a copy of an original json with
5850 * transformed values.
5851 */
5852text *
5853transform_json_string_values(text *json, void *action_state,
5854 JsonTransformStringValuesAction transform_action)
5855{
5856 JsonLexContext lex;
5859
5860 state->lex = makeJsonLexContext(&lex, json, true);
5861 state->strval = makeStringInfo();
5862 state->action = transform_action;
5863 state->action_state = action_state;
5864
5865 sem->semstate = state;
5873
5875 freeJsonLexContext(&lex);
5876
5877 return cstring_to_text_with_len(state->strval->data, state->strval->len);
5878}
5879
5880/*
5881 * Set of auxiliary functions for transform_json_string_values to invoke a
5882 * specified JsonTransformStringValuesAction for all values and left everything
5883 * else untouched.
5884 */
5885static JsonParseErrorType
5887{
5889
5890 appendStringInfoCharMacro(_state->strval, '{');
5891
5892 return JSON_SUCCESS;
5893}
5894
5895static JsonParseErrorType
5897{
5899
5900 appendStringInfoCharMacro(_state->strval, '}');
5901
5902 return JSON_SUCCESS;
5903}
5904
5905static JsonParseErrorType
5907{
5909
5910 appendStringInfoCharMacro(_state->strval, '[');
5911
5912 return JSON_SUCCESS;
5913}
5914
5915static JsonParseErrorType
5917{
5919
5920 appendStringInfoCharMacro(_state->strval, ']');
5921
5922 return JSON_SUCCESS;
5923}
5924
5925static JsonParseErrorType
5927{
5929
5930 if (_state->strval->data[_state->strval->len - 1] != '{')
5931 appendStringInfoCharMacro(_state->strval, ',');
5932
5933 /*
5934 * Unfortunately we don't have the quoted and escaped string any more, so
5935 * we have to re-escape it.
5936 */
5937 escape_json(_state->strval, fname);
5938 appendStringInfoCharMacro(_state->strval, ':');
5939
5940 return JSON_SUCCESS;
5941}
5942
5943static JsonParseErrorType
5945{
5947
5948 if (_state->strval->data[_state->strval->len - 1] != '[')
5949 appendStringInfoCharMacro(_state->strval, ',');
5950
5951 return JSON_SUCCESS;
5952}
5953
5954static JsonParseErrorType
5956{
5958
5959 if (tokentype == JSON_TOKEN_STRING)
5960 {
5961 text *out = _state->action(_state->action_state, token, strlen(token));
5962
5963 escape_json_text(_state->strval, out);
5964 }
5965 else
5967
5968 return JSON_SUCCESS;
5969}
5970
5972json_get_first_token(text *json, bool throw_error)
5973{
5974 JsonLexContext lex;
5975 JsonParseErrorType result;
5976
5977 makeJsonLexContext(&lex, json, false);
5978
5979 /* Lex exactly one token from the input and check its type. */
5980 result = json_lex(&lex);
5981
5982 if (result == JSON_SUCCESS)
5983 return lex.token_type;
5984
5985 if (throw_error)
5986 json_errsave_error(result, &lex, NULL);
5987
5988 return JSON_TOKEN_INVALID; /* invalid json */
5989}
5990
5991/*
5992 * Determine how we want to print values of a given type in datum_to_json(b).
5993 *
5994 * Given the datatype OID, return its JsonTypeCategory, as well as the type's
5995 * output function OID. If the returned category is JSONTYPE_CAST, we return
5996 * the OID of the type->JSON cast function instead.
5997 */
5998void
5999json_categorize_type(Oid typoid, bool is_jsonb,
6000 JsonTypeCategory *tcategory, Oid *outfuncoid)
6001{
6002 bool typisvarlena;
6003
6004 /* Look through any domain */
6005 typoid = getBaseType(typoid);
6006
6007 *outfuncoid = InvalidOid;
6008
6009 switch (typoid)
6010 {
6011 case BOOLOID:
6012 *outfuncoid = F_BOOLOUT;
6013 *tcategory = JSONTYPE_BOOL;
6014 break;
6015
6016 case INT2OID:
6017 case INT4OID:
6018 case INT8OID:
6019 case FLOAT4OID:
6020 case FLOAT8OID:
6021 case NUMERICOID:
6022 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6023 *tcategory = JSONTYPE_NUMERIC;
6024 break;
6025
6026 case DATEOID:
6027 *outfuncoid = F_DATE_OUT;
6028 *tcategory = JSONTYPE_DATE;
6029 break;
6030
6031 case TIMESTAMPOID:
6032 *outfuncoid = F_TIMESTAMP_OUT;
6033 *tcategory = JSONTYPE_TIMESTAMP;
6034 break;
6035
6036 case TIMESTAMPTZOID:
6037 *outfuncoid = F_TIMESTAMPTZ_OUT;
6038 *tcategory = JSONTYPE_TIMESTAMPTZ;
6039 break;
6040
6041 case JSONOID:
6042 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6043 *tcategory = JSONTYPE_JSON;
6044 break;
6045
6046 case JSONBOID:
6047 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6048 *tcategory = is_jsonb ? JSONTYPE_JSONB : JSONTYPE_JSON;
6049 break;
6050
6051 default:
6052 /* Check for arrays and composites */
6053 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
6054 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
6055 {
6056 *outfuncoid = F_ARRAY_OUT;
6057 *tcategory = JSONTYPE_ARRAY;
6058 }
6059 else if (type_is_rowtype(typoid)) /* includes RECORDOID */
6060 {
6061 *outfuncoid = F_RECORD_OUT;
6062 *tcategory = JSONTYPE_COMPOSITE;
6063 }
6064 else
6065 {
6066 /*
6067 * It's probably the general case. But let's look for a cast
6068 * to json (note: not to jsonb even if is_jsonb is true), if
6069 * it's not built-in.
6070 */
6071 *tcategory = JSONTYPE_OTHER;
6072 if (typoid >= FirstNormalObjectId)
6073 {
6074 Oid castfunc;
6075 CoercionPathType ctype;
6076
6077 ctype = find_coercion_pathway(JSONOID, typoid,
6079 &castfunc);
6080 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
6081 {
6082 *outfuncoid = castfunc;
6083 *tcategory = JSONTYPE_CAST;
6084 }
6085 else
6086 {
6087 /* non builtin type with no cast */
6088 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6089 }
6090 }
6091 else
6092 {
6093 /* any other builtin type */
6094 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6095 }
6096 }
6097 break;
6098 }
6099}
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
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3767
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5350
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5452
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3697
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5293
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:816
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:717
#define unconstify(underlying_type, expr)
Definition: c.h:1216
#define IS_HIGHBIT_SET(ch)
Definition: c.h:1126
#define VARHDRSZ
Definition: c.h:663
#define FLEXIBLE_ARRAY_MEMBER
Definition: c.h:434
int32_t int32
Definition: c.h:498
uint32_t uint32
Definition: c.h:502
#define PG_INT32_MIN
Definition: c.h:559
#define MemSet(start, val, len)
Definition: c.h:991
#define OidIsValid(objectId)
Definition: c.h:746
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:955
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1231
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int errhint(const char *fmt,...)
Definition: elog.c:1318
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereturn(context, dummy_value,...)
Definition: elog.h:278
#define errsave(context,...)
Definition: elog.h:262
#define errcontext
Definition: elog.h:197
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:149
Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
Definition: execTuples.c:2413
@ SFRM_Materialize_Random
Definition: execnodes.h:337
@ SFRM_Materialize
Definition: execnodes.h:336
struct varlena * pg_detoast_datum_packed(struct varlena *datum)
Definition: fmgr.c:1864
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, fmNodePtr escontext, Datum *result)
Definition: fmgr.c:1585
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1910
#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:132
#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:1736
void escape_json_with_len(StringInfo buf, const char *str, int len)
Definition: json.c:1631
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1602
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:2401
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:2229
Datum jsonb_in(PG_FUNCTION_ARGS)
Definition: jsonb.c:73
char * JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len)
Definition: jsonb.c:473
char * JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
Definition: jsonb.c:482
jbvType
Definition: jsonb.h:226
@ jbvObject
Definition: jsonb.h:234
@ jbvNumeric
Definition: jsonb.h:230
@ jbvBool
Definition: jsonb.h:231
@ jbvArray
Definition: jsonb.h:233
@ jbvBinary
Definition: jsonb.h:236
@ jbvNull
Definition: jsonb.h:228
@ jbvString
Definition: jsonb.h:229
#define JsonContainerIsScalar(jc)
Definition: jsonb.h:207
#define JsonContainerIsArray(jc)
Definition: jsonb.h:209
#define JsonContainerSize(jc)
Definition: jsonb.h:206
#define JB_ROOT_IS_OBJECT(jbp_)
Definition: jsonb.h:221
static Datum JsonbPGetDatum(const Jsonb *p)
Definition: jsonb.h:386
#define IsAJsonbScalar(jsonbval)
Definition: jsonb.h:297
#define PG_RETURN_JSONB_P(x)
Definition: jsonb.h:393
#define JB_ROOT_IS_ARRAY(jbp_)
Definition: jsonb.h:222
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:391
#define JsonContainerIsObject(jc)
Definition: jsonb.h:208
static Jsonb * DatumGetJsonbP(Datum d)
Definition: jsonb.h:374
#define JB_ROOT_IS_SCALAR(jbp_)
Definition: jsonb.h:220
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:219
JsonbValue * getKeyJsonValueFromContainer(JsonbContainer *container, const char *keyVal, int keyLen, JsonbValue *res)
Definition: jsonb_util.c:405
JsonbValue * pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition: jsonb_util.c:573
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition: jsonb_util.c:824
void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val)
Definition: jsonb_util.c:72
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition: jsonb_util.c:860
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition: jsonb_util.c:475
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition: jsonb_util.c:92
Datum jsonb_populate_recordset(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:3974
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:2308
static JsonParseErrorType hash_array_start(void *state)
Definition: jsonfuncs.c:3930
Datum jsonb_object_keys(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:568
static JsonParseErrorType populate_recordset_array_start(void *state)
Definition: jsonfuncs.c:4283
static JsonParseErrorType transform_string_values_array_start(void *state)
Definition: jsonfuncs.c:5906
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:2418
static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5926
Datum jsonb_array_elements(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2208
static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:5785
struct PopulateArrayContext PopulateArrayContext
static JsonbValue * IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, JsonbParseState **state)
Definition: jsonfuncs.c:5076
Datum json_each_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1962
Datum json_populate_recordset(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:3988
static JsonParseErrorType populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2753
text * transform_json_string_values(text *json, void *action_state, JsonTransformStringValuesAction transform_action)
Definition: jsonfuncs.c:5853
Datum jsonb_delete(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4664
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:3345
Datum jsonb_delete_array(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4717
static JsonbValue * setPath(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, int op_type)
Definition: jsonfuncs.c:5204
Datum jsonb_pretty(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4607
struct DomainIOData DomainIOData
static JsonParseErrorType transform_string_values_array_end(void *state)
Definition: jsonfuncs.c:5916
static JsonParseErrorType populate_recordset_object_start(void *state)
Definition: jsonfuncs.c:4215
static RecordIOData * allocate_record_info(MemoryContext mcxt, int ncolumns)
Definition: jsonfuncs.c:3476
static JsonParseErrorType iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5757
static text * JsonbValueAsText(JsonbValue *v)
Definition: jsonfuncs.c:1805
Datum jsonb_insert(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:5027
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:4307
static JsonParseErrorType populate_recordset_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4330
static JsonParseErrorType populate_array_object_start(void *_state)
Definition: jsonfuncs.c:2645
#define JsObjectIsEmpty(jso)
Definition: jsonfuncs.c:329
static void get_record_type_from_argument(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition: jsonfuncs.c:3636
Datum json_array_element(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:922
Datum jsonb_delete_idx(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4804
#define JB_PATH_DELETE
Definition: jsonfuncs.c:45
struct GetState GetState
static JsonParseErrorType sn_object_end(void *state)
Definition: jsonfuncs.c:4400
#define JB_PATH_CREATE_OR_INSERT
Definition: jsonfuncs.c:49
Datum jsonb_populate_record_valid(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2477
Datum json_array_elements_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2302
#define JB_PATH_CREATE
Definition: jsonfuncs.c:44
struct EachState EachState
static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:3943
static JsonParseErrorType sn_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:4460
static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg, Node *escontext)
Definition: jsonfuncs.c:3699
static HTAB * get_json_object_as_hash(const char *json, int len, const char *funcname, Node *escontext)
Definition: jsonfuncs.c:3811
static bool populate_array_json(PopulateArrayContext *ctx, const char *json, int len)
Definition: jsonfuncs.c:2789
struct StripnullState StripnullState
static void setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 nelems, int op_type)
Definition: jsonfuncs.c:5425
struct IterateJsonStringValuesState IterateJsonStringValuesState
#define JsValueIsString(jsv)
Definition: jsonfuncs.c:325
static JsonParseErrorType populate_recordset_object_end(void *state)
Definition: jsonfuncs.c:4245
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:3406
Datum jsonb_delete_path(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4984
struct JsValue JsValue
struct CompositeIOData CompositeIOData
static JsonParseErrorType each_object_field_end(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:2120
Datum jsonb_object_field_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:900
static Datum each_worker(FunctionCallInfo fcinfo, bool as_text)
Definition: jsonfuncs.c:2058
static JsonParseErrorType get_array_start(void *state)
Definition: jsonfuncs.c:1295
static JsonParseErrorType each_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2182
static int report_json_context(JsonLexContext *lex)
Definition: jsonfuncs.c:677
Datum json_strip_nulls(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4505
static void push_path(JsonbParseState **st, int level, Datum *path_elems, bool *path_nulls, int path_len, JsonbValue *newval)
Definition: jsonfuncs.c:1721
struct JsonHashEntry JsonHashEntry
Datum jsonb_set_element(Jsonb *jb, Datum *path, int path_len, JsonbValue *newval)
Definition: jsonfuncs.c:1679
Datum json_array_elements(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2296
Datum jsonb_concat(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4623
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:5596
Datum jsonb_extract_path_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1494
Datum json_each(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1950
static JsonParseErrorType alen_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:1914
static JsonParseErrorType sn_object_start(void *state)
Definition: jsonfuncs.c:4390
static JsonParseErrorType sn_array_start(void *state)
Definition: jsonfuncs.c:4410
static bool populate_array_check_dimension(PopulateArrayContext *ctx, int ndim)
Definition: jsonfuncs.c:2590
Datum jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
Definition: jsonfuncs.c:1531
static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition: jsonfuncs.c:1974
static JsonParseErrorType sn_array_end(void *state)
Definition: jsonfuncs.c:4420
Datum json_to_recordset(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:3995
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:2560
JsonTokenType json_get_first_token(text *json, bool throw_error)
Definition: jsonfuncs.c:5972
Datum jsonb_set(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4868
#define JsValueIsNull(jsv)
Definition: jsonfuncs.c:320
static void update_cached_tupdesc(CompositeIOData *io, MemoryContext mcxt)
Definition: jsonfuncs.c:3029
struct ColumnIOData ColumnIOData
Definition: jsonfuncs.c:162
void iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state, JsonIterateStringValuesAction action)
Definition: jsonfuncs.c:5664
static JsonParseErrorType populate_array_element_end(void *_state, bool isnull)
Definition: jsonfuncs.c:2710
Datum jsonb_set_lax(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4917
static JsonParseErrorType elements_array_element_end(void *state, bool isnull)
Definition: jsonfuncs.c:2372
static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:4430
Datum jsonb_each_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1968
static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:2433
struct ScalarIOData ScalarIOData
static JsonParseErrorType each_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:2098
Datum jsonb_strip_nulls(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:4540
struct OkeysState OkeysState
struct PopulateArrayState PopulateArrayState
struct PopulateRecordCache PopulateRecordCache
Datum jsonb_extract_path(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1488
static void push_null_elements(JsonbParseState **ps, int num)
Definition: jsonfuncs.c:1702
void json_categorize_type(Oid typoid, bool is_jsonb, JsonTypeCategory *tcategory, Oid *outfuncoid)
Definition: jsonfuncs.c:5999
static Datum populate_array(ArrayIOData *aio, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext)
Definition: jsonfuncs.c:2915
static JsonParseErrorType okeys_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:786
Datum json_array_length(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1852
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:1878
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:2220
void iterate_json_values(text *json, uint32 flags, void *action_state, JsonIterateStringValuesAction action)
Definition: jsonfuncs.c:5732
Datum jsonb_populate_record(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2464
Datum json_extract_path(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1009
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:2350
static void get_record_type_from_query(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition: jsonfuncs.c:3662
Datum json_populate_record(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2495
static JsonParseErrorType populate_recordset_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:4268
#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:5806
static JsonParseErrorType transform_string_values_object_end(void *state)
Definition: jsonfuncs.c:5896
static bool JsValueToJsObject(JsValue *jsv, JsObject *jso, Node *escontext)
Definition: jsonfuncs.c:2982
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:2510
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:3058
Datum jsonb_to_record(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2488
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:4290
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:4041
static HeapTupleHeader populate_record(TupleDesc tupdesc, RecordIOData **record_p, HeapTupleHeader defaultval, MemoryContext mcxt, JsObject *obj, Node *escontext)
Definition: jsonfuncs.c:3520
static JsonParseErrorType alen_object_start(void *state)
Definition: jsonfuncs.c:1900
static bool JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
Definition: jsonfuncs.c:3492
static bool populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv)
Definition: jsonfuncs.c:2618
static JsonParseErrorType populate_array_element_start(void *_state, bool isnull)
Definition: jsonfuncs.c:2692
static JsonParseErrorType populate_array_array_end(void *_state)
Definition: jsonfuncs.c:2668
static void prepare_column_cache(ColumnIOData *column, Oid typid, int32 typmod, MemoryContext mcxt, bool need_scalar)
Definition: jsonfuncs.c:3251
static JsonParseErrorType get_array_end(void *state)
Definition: jsonfuncs.c:1335
Datum jsonb_to_recordset(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:3981
static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:4482
#define JB_PATH_INSERT_AFTER
Definition: jsonfuncs.c:48
Datum jsonb_each(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:1956
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:3879
#define JB_PATH_REPLACE
Definition: jsonfuncs.c:46
static void populate_recordset_record(PopulateRecordsetState *state, JsObject *obj)
Definition: jsonfuncs.c:4002
#define JsObjectFree(jso)
Definition: jsonfuncs.c:335
struct PopulateRecordsetState PopulateRecordsetState
static JsonParseErrorType transform_string_values_object_start(void *state)
Definition: jsonfuncs.c:5886
static JsonParseErrorType transform_string_values_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:5944
static JsonParseErrorType alen_array_element_start(void *state, bool isnull)
Definition: jsonfuncs.c:1928
static Datum populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv, bool *isnull, Node *escontext, bool omit_quotes)
Definition: jsonfuncs.c:3125
static bool populate_array_dim_jsonb(PopulateArrayContext *ctx, JsonbValue *jbv, int ndim)
Definition: jsonfuncs.c:2825
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:2502
static JsonParseErrorType each_array_start(void *state)
Definition: jsonfuncs.c:2168
Datum json_array_element_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:965
static void setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 npairs, int op_type)
Definition: jsonfuncs.c:5286
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:3217
static JsonParseErrorType transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: jsonfuncs.c:5955
static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull)
Definition: jsonfuncs.c:3853
Datum jsonb_array_elements_text(PG_FUNCTION_ARGS)
Definition: jsonfuncs.c:2214
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:2899
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2795
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:3047
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:3014
char get_typtype(Oid typid)
Definition: lsyscache.c:2769
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2678
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2661
int GetDatabaseEncoding(void)
Definition: mbutils.c:1261
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1023
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1256
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:414
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1290
char * pstrdup(const char *in)
Definition: mcxt.c:2322
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:2167
void pfree(void *pointer)
Definition: mcxt.c:2147
void * palloc0(Size size)
Definition: mcxt.c:1970
void * palloc(Size size)
Definition: mcxt.c:1940
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:2333
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:485
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:180
#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:73
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
Definition: pg_test_fsync.c:72
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:69
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static char * DatumGetCString(Datum X)
Definition: postgres.h:340
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
char * c
@ COERCION_EXPLICIT
Definition: primnodes.h:734
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 *pg_restrict str, char **pg_restrict endptr, int base)
Definition: string.c:50
StringInfo makeStringInfo(void)
Definition: stringinfo.c:72
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
union ColumnIOData::@24 io
CompositeIOData composite
Definition: jsonfuncs.c:221
TypeCat typcat
Definition: jsonfuncs.c:215
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:275
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
fmNodePtr resultinfo
Definition: fmgr.h:89
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:220
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::@27 val
const char * str
Definition: jsonfuncs.c:300
JsonbValue * jsonb
Definition: jsonfuncs.c:305
struct JsValue::@25::@26 json
int len
Definition: jsonfuncs.c:301
union JsValue::@25 val
JsonTokenType type
Definition: jsonfuncs.c:302
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
bool isScalar
Definition: jsonb.h:347
enum jbvType type
Definition: jsonb.h:255
char * val
Definition: jsonb.h:264
Definition: jsonb.h:213
JsonbContainer root
Definition: jsonb.h:215
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:355
ExprContext * econtext
Definition: execnodes.h:351
TupleDesc setDesc
Definition: execnodes.h:359
Tuplestorestate * setResult
Definition: execnodes.h:358
int allowedModes
Definition: execnodes.h:353
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:658
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
static JsonSemAction sem
#define FirstNormalObjectId
Definition: transam.h:197
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:495
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:245
#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:1922
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE(PTR)
Definition: varatt.h:279
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:204
text * cstring_to_text(const char *s)
Definition: varlena.c:192
char * text_to_cstring(const text *t)
Definition: varlena.c:225
const char * type