PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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 */
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 */
107
108/* state for json_each */
120
121/* state for json_array_elements */
134
135/* state for get_json_object_as_hash */
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() */
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 */
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 */
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 */
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);
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 */
402static JsonParseErrorType populate_array_element_end(void *_state, bool isnull);
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] */
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,
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 void setPath(JsonbIterator **it, const Datum *path_elems,
481 const bool *path_nulls, int path_len,
482 JsonbInState *st, int level, JsonbValue *newval,
483 int op_type);
484static void setPathObject(JsonbIterator **it, const Datum *path_elems,
485 const bool *path_nulls, int path_len, JsonbInState *st,
486 int level,
488static void setPathArray(JsonbIterator **it, const Datum *path_elems,
489 const bool *path_nulls, int path_len, JsonbInState *st,
490 int level,
491 JsonbValue *newval, uint32 nelems, int op_type);
492
493/* function supporting iterate_json_values */
495static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull);
496
497/* functions supporting transform_json_string_values */
502static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull);
505
506
507/*
508 * pg_parse_json_or_errsave
509 *
510 * This function is like pg_parse_json, except that it does not return a
511 * JsonParseErrorType. Instead, in case of any failure, this function will
512 * save error data into *escontext if that's an ErrorSaveContext, otherwise
513 * ereport(ERROR).
514 *
515 * Returns a boolean indicating success or failure (failure will only be
516 * returned when escontext is an ErrorSaveContext).
517 */
518bool
520 Node *escontext)
521{
522 JsonParseErrorType result;
523
524 result = pg_parse_json(lex, sem);
525 if (result != JSON_SUCCESS)
526 {
527 json_errsave_error(result, lex, escontext);
528 return false;
529 }
530 return true;
531}
532
533/*
534 * makeJsonLexContext
535 *
536 * This is like makeJsonLexContextCstringLen, but it accepts a text value
537 * directly.
538 */
540makeJsonLexContext(JsonLexContext *lex, text *json, bool need_escapes)
541{
542 /*
543 * Most callers pass a detoasted datum, but it's not clear that they all
544 * do. pg_detoast_datum_packed() is cheap insurance.
545 */
546 json = pg_detoast_datum_packed(json);
547
549 VARDATA_ANY(json),
550 VARSIZE_ANY_EXHDR(json),
552 need_escapes);
553}
554
555/*
556 * SQL function json_object_keys
557 *
558 * Returns the set of keys for the object argument.
559 *
560 * This SRF operates in value-per-call mode. It processes the
561 * object during the first call, and the keys are simply stashed
562 * in an array, whose size is expanded as necessary. This is probably
563 * safe enough for a list of keys of a single object, since they are
564 * limited in size to NAMEDATALEN and the number of keys is unlikely to
565 * be so huge that it has major memory implications.
566 */
567Datum
569{
572
573 if (SRF_IS_FIRSTCALL())
574 {
575 MemoryContext oldcontext;
577 bool skipNested = false;
579 JsonbValue v;
581
585 errmsg("cannot call %s on a scalar",
586 "jsonb_object_keys")));
587 else if (JB_ROOT_IS_ARRAY(jb))
590 errmsg("cannot call %s on an array",
591 "jsonb_object_keys")));
592
594 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
595
597
598 state->result_size = JB_ROOT_COUNT(jb);
599 state->result_count = 0;
600 state->sent_count = 0;
601 state->result = palloc_array(char *, state->result_size);
602
603 it = JsonbIteratorInit(&jb->root);
604
605 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
606 {
607 skipNested = true;
608
609 if (r == WJB_KEY)
610 {
611 char *cstr;
612
613 cstr = palloc(v.val.string.len + 1 * sizeof(char));
614 memcpy(cstr, v.val.string.val, v.val.string.len);
615 cstr[v.val.string.len] = '\0';
616 state->result[state->result_count++] = cstr;
617 }
618 }
619
620 MemoryContextSwitchTo(oldcontext);
621 funcctx->user_fctx = state;
622 }
623
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
635}
636
637/*
638 * Report a JSON error.
639 */
640void
642 Node *escontext)
643{
647 errsave(escontext,
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,
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;
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 */
699 else
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 */
713 ctxt = palloc(ctxtlen + 1);
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{
736
737 if (SRF_IS_FIRSTCALL())
738 {
739 text *json = PG_GETARG_TEXT_PP(0);
740 JsonLexContext lex;
742 MemoryContext oldcontext;
743
745 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
746
749
750 state->lex = makeJsonLexContext(&lex, json, true);
751 state->result_size = 256;
752 state->result_count = 0;
753 state->sent_count = 0;
754 state->result = palloc_array(char *, 256);
755
756 sem->semstate = state;
760 /* remainder are all NULL, courtesy of palloc0 above */
761
763 /* keys are now in state->result */
764
765 freeJsonLexContext(&lex);
766 pfree(sem);
767
768 MemoryContextSwitchTo(oldcontext);
769 funcctx->user_fctx = state;
770 }
771
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
783}
784
786okeys_object_field_start(void *state, char *fname, bool isnull)
787{
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{
812
813 /* top level must be a json object */
814 if (_state->lex->lex_level == 0)
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{
827
828 /* top level must be a json object */
829 if (_state->lex->lex_level == 0)
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{
865 text *key = PG_GETARG_TEXT_PP(1);
866 JsonbValue *v;
868
869 if (!JB_ROOT_IS_OBJECT(jb))
871
873 VARDATA_ANY(key),
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{
903 text *key = PG_GETARG_TEXT_PP(1);
904 JsonbValue *v;
906
907 if (!JB_ROOT_IS_OBJECT(jb))
909
911 VARDATA_ANY(key),
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{
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{
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
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
1047
1048 tpath = palloc_array(char *, npath);
1049 ipath = palloc_array(int, npath);
1050
1051 for (i = 0; i < npath; i++)
1052 {
1053 Assert(!pathnulls[i]);
1055
1056 /*
1057 * we have no idea at this stage what structure the document is so
1058 * just convert anything in the path that we can to an integer and set
1059 * all the other integers to INT_MIN which will never match.
1060 */
1061 if (*tpath[i] != '\0')
1062 {
1063 int ind;
1064 char *endptr;
1065
1066 errno = 0;
1067 ind = strtoint(tpath[i], &endptr, 10);
1068 if (endptr == tpath[i] || *endptr != '\0' || errno != 0)
1069 ipath[i] = INT_MIN;
1070 else
1071 ipath[i] = ind;
1072 }
1073 else
1074 ipath[i] = INT_MIN;
1075 }
1076
1077 result = get_worker(json, tpath, ipath, npath, as_text);
1078
1079 if (result != NULL)
1080 PG_RETURN_TEXT_P(result);
1081 else
1083}
1084
1085/*
1086 * get_worker
1087 *
1088 * common worker for all the json getter functions
1089 *
1090 * json: JSON object (in text form)
1091 * tpath[]: field name(s) to extract
1092 * ipath[]: array index(es) (zero-based) to extract, accepts negatives
1093 * npath: length of tpath[] and/or ipath[]
1094 * normalize_results: true to de-escape string and null scalars
1095 *
1096 * tpath can be NULL, or any one tpath[] entry can be NULL, if an object
1097 * field is not to be matched at that nesting level. Similarly, ipath can
1098 * be NULL, or any one ipath[] entry can be INT_MIN if an array element is
1099 * not to be matched at that nesting level (a json datum should never be
1100 * large enough to have -INT_MIN elements due to MaxAllocSize restriction).
1101 */
1102static text *
1104 char **tpath,
1105 int *ipath,
1106 int npath,
1107 bool normalize_results)
1108{
1111
1112 Assert(npath >= 0);
1113
1114 state->lex = makeJsonLexContext(NULL, json, true);
1115
1116 /* is it "_as_text" variant? */
1117 state->normalize_results = normalize_results;
1118 state->npath = npath;
1119 state->path_names = tpath;
1120 state->path_indexes = ipath;
1121 state->pathok = palloc0_array(bool, npath);
1122 state->array_cur_index = palloc_array(int, npath);
1123
1124 if (npath > 0)
1125 state->pathok[0] = true;
1126
1127 sem->semstate = state;
1128
1129 /*
1130 * Not all variants need all the semantic routines. Only set the ones that
1131 * are actually needed for maximum efficiency.
1132 */
1134 if (npath == 0)
1135 {
1140 }
1141 if (tpath != NULL)
1142 {
1145 }
1146 if (ipath != NULL)
1147 {
1151 }
1152
1155
1156 return state->tresult;
1157}
1158
1159static JsonParseErrorType
1161{
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{
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{
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{
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{
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)
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{
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{
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{
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{
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{
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
1521
1522 res = jsonb_get_element(jb, pathtext, npath, &isnull, as_text);
1523
1524 if (isnull)
1526 else
1527 PG_RETURN_DATUM(res);
1528}
1529
1530Datum
1531jsonb_get_element(Jsonb *jb, const Datum *path, int npath, bool *isnull, bool as_text)
1532{
1533 JsonbContainer *container = &jb->root;
1534 JsonbValue *jbvp = NULL;
1535 int i;
1536 bool have_object = false,
1537 have_array = false;
1538
1539 *isnull = false;
1540
1541 /* Identify whether we have object, array, or scalar at top-level */
1542 if (JB_ROOT_IS_OBJECT(jb))
1543 have_object = true;
1544 else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
1545 have_array = true;
1546 else
1547 {
1549 /* Extract the scalar value, if it is what we'll return */
1550 if (npath <= 0)
1551 jbvp = getIthJsonbValueFromContainer(container, 0);
1552 }
1553
1554 /*
1555 * If the array is empty, return the entire LHS object, on the grounds
1556 * that we should do zero field or element extractions. For the
1557 * non-scalar case we can just hand back the object without much work. For
1558 * the scalar case, fall through and deal with the value below the loop.
1559 * (This inconsistency arises because there's no easy way to generate a
1560 * JsonbValue directly for root-level containers.)
1561 */
1562 if (npath <= 0 && jbvp == NULL)
1563 {
1564 if (as_text)
1565 {
1567 container,
1568 VARSIZE(jb))));
1569 }
1570 else
1571 {
1572 /* not text mode - just hand back the jsonb */
1574 }
1575 }
1576
1577 for (i = 0; i < npath; i++)
1578 {
1579 if (have_object)
1580 {
1581 text *subscr = DatumGetTextPP(path[i]);
1582
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
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;
1648 have_array = JsonContainerIsArray(container);
1649 Assert(!JsonContainerIsScalar(container));
1650 }
1651 else
1652 {
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
1668 }
1669 else
1670 {
1672
1673 /* not text mode - just hand back the jsonb */
1674 PG_RETURN_JSONB_P(res);
1675 }
1676}
1677
1678Datum
1681{
1682 JsonbInState state = {0};
1684 bool *path_nulls = palloc0_array(bool, path_len);
1685
1686 if (newval->type == jbvArray && newval->val.array.rawScalar)
1687 *newval = newval->val.array.elems[0];
1688
1689 it = JsonbIteratorInit(&jb->root);
1690
1691 setPath(&it, path, path_nulls, path_len, &state, 0, newval,
1694
1696
1698}
1699
1700static void
1702{
1704
1705 null.type = jbvNull;
1706
1707 while (num-- > 0)
1709}
1710
1711/*
1712 * Prepare a new structure containing nested empty objects and arrays
1713 * corresponding to the specified path, and assign a new value at the end of
1714 * this path. E.g. the path [a][0][b] with the new value 1 will produce the
1715 * structure {a: [{b: 1}]}.
1716 *
1717 * Caller is responsible to make sure such path does not exist yet.
1718 */
1719static void
1721 const bool *path_nulls, int path_len, JsonbValue *newval)
1722{
1723 /*
1724 * tpath contains expected type of an empty jsonb created at each level
1725 * higher or equal to the current one, either jbvObject or jbvArray. Since
1726 * it contains only information about path slice from level to the end,
1727 * the access index must be normalized by level.
1728 */
1729 enum jbvType *tpath = palloc0_array(enum jbvType, path_len - level);
1731
1732 /*
1733 * Create first part of the chain with beginning tokens. For the current
1734 * level WJB_BEGIN_OBJECT/WJB_BEGIN_ARRAY was already created, so start
1735 * with the next one.
1736 */
1737 for (int i = level + 1; i < path_len; i++)
1738 {
1739 char *c,
1740 *badp;
1741 int lindex;
1742
1743 if (path_nulls[i])
1744 break;
1745
1746 /*
1747 * Try to convert to an integer to find out the expected type, object
1748 * or array.
1749 */
1751 errno = 0;
1752 lindex = strtoint(c, &badp, 10);
1753 if (badp == c || *badp != '\0' || errno != 0)
1754 {
1755 /* text, an object is expected */
1756 newkey.type = jbvString;
1757 newkey.val.string.val = c;
1758 newkey.val.string.len = strlen(c);
1759
1762
1763 tpath[i - level] = jbvObject;
1764 }
1765 else
1766 {
1767 /* integer, an array is expected */
1769
1771
1772 tpath[i - level] = jbvArray;
1773 }
1774 }
1775
1776 /* Insert an actual value for either an object or array */
1777 if (tpath[(path_len - level) - 1] == jbvArray)
1779 else
1781
1782 /*
1783 * Close everything up to the last but one level. The last one will be
1784 * closed outside of this function.
1785 */
1786 for (int i = path_len - 1; i > level; i--)
1787 {
1788 if (path_nulls[i])
1789 break;
1790
1791 if (tpath[i - level] == jbvObject)
1793 else
1795 }
1796}
1797
1798/*
1799 * Return the text representation of the given JsonbValue.
1800 */
1801static text *
1803{
1804 switch (v->type)
1805 {
1806 case jbvNull:
1807 return NULL;
1808
1809 case jbvBool:
1810 return v->val.boolean ?
1811 cstring_to_text_with_len("true", 4) :
1812 cstring_to_text_with_len("false", 5);
1813
1814 case jbvString:
1815 return cstring_to_text_with_len(v->val.string.val,
1816 v->val.string.len);
1817
1818 case jbvNumeric:
1819 {
1820 Datum cstr;
1821
1823 PointerGetDatum(v->val.numeric));
1824
1826 }
1827
1828 case jbvBinary:
1829 {
1831
1833 (void) JsonbToCString(&jtext, v->val.binary.data,
1834 v->val.binary.len);
1835
1836 return cstring_to_text_with_len(jtext.data, jtext.len);
1837 }
1838
1839 default:
1840 elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
1841 return NULL;
1842 }
1843}
1844
1845/*
1846 * SQL function json_array_length(json) -> int
1847 */
1848Datum
1850{
1851 text *json = PG_GETARG_TEXT_PP(0);
1853 JsonLexContext lex;
1855
1857 state->lex = makeJsonLexContext(&lex, json, false);
1858 /* palloc0 does this for us */
1859#if 0
1860 state->count = 0;
1861#endif
1862
1864 sem->semstate = state;
1868
1870
1871 PG_RETURN_INT32(state->count);
1872}
1873
1874Datum
1876{
1878
1879 if (JB_ROOT_IS_SCALAR(jb))
1880 ereport(ERROR,
1882 errmsg("cannot get array length of a scalar")));
1883 else if (!JB_ROOT_IS_ARRAY(jb))
1884 ereport(ERROR,
1886 errmsg("cannot get array length of a non-array")));
1887
1889}
1890
1891/*
1892 * These next two checks ensure that the json is an array (since it can't be
1893 * a scalar or an object).
1894 */
1895
1896static JsonParseErrorType
1898{
1900
1901 /* json structure check */
1902 if (_state->lex->lex_level == 0)
1903 ereport(ERROR,
1905 errmsg("cannot get array length of a non-array")));
1906
1907 return JSON_SUCCESS;
1908}
1909
1910static JsonParseErrorType
1911alen_scalar(void *state, char *token, JsonTokenType tokentype)
1912{
1914
1915 /* json structure check */
1916 if (_state->lex->lex_level == 0)
1917 ereport(ERROR,
1919 errmsg("cannot get array length of a scalar")));
1920
1921 return JSON_SUCCESS;
1922}
1923
1924static JsonParseErrorType
1926{
1928
1929 /* just count up all the level 1 elements */
1930 if (_state->lex->lex_level == 1)
1931 _state->count++;
1932
1933 return JSON_SUCCESS;
1934}
1935
1936/*
1937 * SQL function json_each and json_each_text
1938 *
1939 * decompose a json object into key value pairs.
1940 *
1941 * Unlike json_object_keys() these SRFs operate in materialize mode,
1942 * stashing results into a Tuplestore object as they go.
1943 * The construction of tuples is done using a temporary memory context
1944 * that is cleared out after each tuple is built.
1945 */
1946Datum
1948{
1949 return each_worker(fcinfo, false);
1950}
1951
1952Datum
1954{
1955 return each_worker_jsonb(fcinfo, "jsonb_each", false);
1956}
1957
1958Datum
1960{
1961 return each_worker(fcinfo, true);
1962}
1963
1964Datum
1966{
1967 return each_worker_jsonb(fcinfo, "jsonb_each_text", true);
1968}
1969
1970static Datum
1972{
1974 ReturnSetInfo *rsi;
1976 tmp_cxt;
1977 bool skipNested = false;
1979 JsonbValue v;
1981
1982 if (!JB_ROOT_IS_OBJECT(jb))
1983 ereport(ERROR,
1985 errmsg("cannot call %s on a non-object",
1986 funcname)));
1987
1988 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1990
1992 "jsonb_each temporary cxt",
1994
1995 it = JsonbIteratorInit(&jb->root);
1996
1997 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
1998 {
1999 skipNested = true;
2000
2001 if (r == WJB_KEY)
2002 {
2003 text *key;
2004 Datum values[2];
2005 bool nulls[2] = {false, false};
2006
2007 /* Use the tmp context so we can clean up after each tuple is done */
2008 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2009
2010 key = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
2011
2012 /*
2013 * The next thing the iterator fetches should be the value, no
2014 * matter what shape it is.
2015 */
2016 r = JsonbIteratorNext(&it, &v, skipNested);
2017 Assert(r != WJB_DONE);
2018
2019 values[0] = PointerGetDatum(key);
2020
2021 if (as_text)
2022 {
2023 if (v.type == jbvNull)
2024 {
2025 /* a json null is an sql null in text mode */
2026 nulls[1] = true;
2027 values[1] = (Datum) 0;
2028 }
2029 else
2031 }
2032 else
2033 {
2034 /* Not in text mode, just return the Jsonb */
2036
2038 }
2039
2040 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2041
2042 /* clean up and switch back */
2044 MemoryContextReset(tmp_cxt);
2045 }
2046 }
2047
2048 MemoryContextDelete(tmp_cxt);
2049
2051}
2052
2053
2054static Datum
2056{
2057 text *json = PG_GETARG_TEXT_PP(0);
2058 JsonLexContext lex;
2060 ReturnSetInfo *rsi;
2062
2065
2066 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2067
2069 state->tuple_store = rsi->setResult;
2070 state->ret_tdesc = rsi->setDesc;
2071
2072 sem->semstate = state;
2077
2078 state->normalize_results = as_text;
2079 state->next_scalar = false;
2080 state->lex = makeJsonLexContext(&lex, json, true);
2082 "json_each temporary cxt",
2084
2086
2087 MemoryContextDelete(state->tmp_cxt);
2088 freeJsonLexContext(&lex);
2089
2091}
2092
2093
2094static JsonParseErrorType
2095each_object_field_start(void *state, char *fname, bool isnull)
2096{
2098
2099 /* save a pointer to where the value starts */
2100 if (_state->lex->lex_level == 1)
2101 {
2102 /*
2103 * next_scalar will be reset in the object_field_end handler, and
2104 * since we know the value is a scalar there is no danger of it being
2105 * on while recursing down the tree.
2106 */
2107 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2108 _state->next_scalar = true;
2109 else
2110 _state->result_start = _state->lex->token_start;
2111 }
2112
2113 return JSON_SUCCESS;
2114}
2115
2116static JsonParseErrorType
2117each_object_field_end(void *state, char *fname, bool isnull)
2118{
2121 int len;
2122 text *val;
2123 HeapTuple tuple;
2124 Datum values[2];
2125 bool nulls[2] = {false, false};
2126
2127 /* skip over nested objects */
2128 if (_state->lex->lex_level != 1)
2129 return JSON_SUCCESS;
2130
2131 /* use the tmp context so we can clean up after each tuple is done */
2133
2134 values[0] = CStringGetTextDatum(fname);
2135
2136 if (isnull && _state->normalize_results)
2137 {
2138 nulls[1] = true;
2139 values[1] = (Datum) 0;
2140 }
2141 else if (_state->next_scalar)
2142 {
2143 values[1] = CStringGetTextDatum(_state->normalized_scalar);
2144 _state->next_scalar = false;
2145 }
2146 else
2147 {
2148 len = _state->lex->prev_token_terminator - _state->result_start;
2149 val = cstring_to_text_with_len(_state->result_start, len);
2151 }
2152
2153 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2154
2155 tuplestore_puttuple(_state->tuple_store, tuple);
2156
2157 /* clean up and switch back */
2159 MemoryContextReset(_state->tmp_cxt);
2160
2161 return JSON_SUCCESS;
2162}
2163
2164static JsonParseErrorType
2166{
2168
2169 /* json structure check */
2170 if (_state->lex->lex_level == 0)
2171 ereport(ERROR,
2173 errmsg("cannot deconstruct an array as an object")));
2174
2175 return JSON_SUCCESS;
2176}
2177
2178static JsonParseErrorType
2179each_scalar(void *state, char *token, JsonTokenType tokentype)
2180{
2182
2183 /* json structure check */
2184 if (_state->lex->lex_level == 0)
2185 ereport(ERROR,
2187 errmsg("cannot deconstruct a scalar")));
2188
2189 /* supply de-escaped value if required */
2190 if (_state->next_scalar)
2191 _state->normalized_scalar = token;
2192
2193 return JSON_SUCCESS;
2194}
2195
2196/*
2197 * SQL functions json_array_elements and json_array_elements_text
2198 *
2199 * get the elements from a json array
2200 *
2201 * a lot of this processing is similar to the json_each* functions
2202 */
2203
2204Datum
2206{
2207 return elements_worker_jsonb(fcinfo, "jsonb_array_elements", false);
2208}
2209
2210Datum
2212{
2213 return elements_worker_jsonb(fcinfo, "jsonb_array_elements_text", true);
2214}
2215
2216static Datum
2218 bool as_text)
2219{
2221 ReturnSetInfo *rsi;
2223 tmp_cxt;
2224 bool skipNested = false;
2226 JsonbValue v;
2228
2229 if (JB_ROOT_IS_SCALAR(jb))
2230 ereport(ERROR,
2232 errmsg("cannot extract elements from a scalar")));
2233 else if (!JB_ROOT_IS_ARRAY(jb))
2234 ereport(ERROR,
2236 errmsg("cannot extract elements from an object")));
2237
2238 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2239
2241
2243 "jsonb_array_elements temporary cxt",
2245
2246 it = JsonbIteratorInit(&jb->root);
2247
2248 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
2249 {
2250 skipNested = true;
2251
2252 if (r == WJB_ELEM)
2253 {
2254 Datum values[1];
2255 bool nulls[1] = {false};
2256
2257 /* use the tmp context so we can clean up after each tuple is done */
2258 old_cxt = MemoryContextSwitchTo(tmp_cxt);
2259
2260 if (as_text)
2261 {
2262 if (v.type == jbvNull)
2263 {
2264 /* a json null is an sql null in text mode */
2265 nulls[0] = true;
2266 values[0] = (Datum) 0;
2267 }
2268 else
2270 }
2271 else
2272 {
2273 /* Not in text mode, just return the Jsonb */
2275
2277 }
2278
2279 tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2280
2281 /* clean up and switch back */
2283 MemoryContextReset(tmp_cxt);
2284 }
2285 }
2286
2287 MemoryContextDelete(tmp_cxt);
2288
2290}
2291
2292Datum
2294{
2295 return elements_worker(fcinfo, "json_array_elements", false);
2296}
2297
2298Datum
2300{
2301 return elements_worker(fcinfo, "json_array_elements_text", true);
2302}
2303
2304static Datum
2306{
2307 text *json = PG_GETARG_TEXT_PP(0);
2308 JsonLexContext lex;
2310 ReturnSetInfo *rsi;
2312
2313 /* elements only needs escaped strings when as_text */
2314 makeJsonLexContext(&lex, json, as_text);
2315
2318
2320 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2321 state->tuple_store = rsi->setResult;
2322 state->ret_tdesc = rsi->setDesc;
2323
2324 sem->semstate = state;
2329
2330 state->function_name = funcname;
2331 state->normalize_results = as_text;
2332 state->next_scalar = false;
2333 state->lex = &lex;
2335 "json_array_elements temporary cxt",
2337
2339
2340 MemoryContextDelete(state->tmp_cxt);
2341 freeJsonLexContext(&lex);
2342
2344}
2345
2346static JsonParseErrorType
2348{
2350
2351 /* save a pointer to where the value starts */
2352 if (_state->lex->lex_level == 1)
2353 {
2354 /*
2355 * next_scalar will be reset in the array_element_end handler, and
2356 * since we know the value is a scalar there is no danger of it being
2357 * on while recursing down the tree.
2358 */
2359 if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2360 _state->next_scalar = true;
2361 else
2362 _state->result_start = _state->lex->token_start;
2363 }
2364
2365 return JSON_SUCCESS;
2366}
2367
2368static JsonParseErrorType
2370{
2373 int len;
2374 text *val;
2375 HeapTuple tuple;
2376 Datum values[1];
2377 bool nulls[1] = {false};
2378
2379 /* skip over nested objects */
2380 if (_state->lex->lex_level != 1)
2381 return JSON_SUCCESS;
2382
2383 /* use the tmp context so we can clean up after each tuple is done */
2385
2386 if (isnull && _state->normalize_results)
2387 {
2388 nulls[0] = true;
2389 values[0] = (Datum) 0;
2390 }
2391 else if (_state->next_scalar)
2392 {
2393 values[0] = CStringGetTextDatum(_state->normalized_scalar);
2394 _state->next_scalar = false;
2395 }
2396 else
2397 {
2398 len = _state->lex->prev_token_terminator - _state->result_start;
2399 val = cstring_to_text_with_len(_state->result_start, len);
2401 }
2402
2403 tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2404
2405 tuplestore_puttuple(_state->tuple_store, tuple);
2406
2407 /* clean up and switch back */
2409 MemoryContextReset(_state->tmp_cxt);
2410
2411 return JSON_SUCCESS;
2412}
2413
2414static JsonParseErrorType
2416{
2418
2419 /* json structure check */
2420 if (_state->lex->lex_level == 0)
2421 ereport(ERROR,
2423 errmsg("cannot call %s on a non-array",
2424 _state->function_name)));
2425
2426 return JSON_SUCCESS;
2427}
2428
2429static JsonParseErrorType
2431{
2433
2434 /* json structure check */
2435 if (_state->lex->lex_level == 0)
2436 ereport(ERROR,
2438 errmsg("cannot call %s on a scalar",
2439 _state->function_name)));
2440
2441 /* supply de-escaped value if required */
2442 if (_state->next_scalar)
2443 _state->normalized_scalar = token;
2444
2445 return JSON_SUCCESS;
2446}
2447
2448/*
2449 * SQL function json_populate_record
2450 *
2451 * set fields in a record from the argument json
2452 *
2453 * Code adapted shamelessly from hstore's populate_record
2454 * which is in turn partly adapted from record_out.
2455 *
2456 * The json is decomposed into a hash table, in which each
2457 * field in the record is then looked up by name. For jsonb
2458 * we fetch the values direct from the object.
2459 */
2460Datum
2462{
2463 return populate_record_worker(fcinfo, "jsonb_populate_record",
2464 false, true, NULL);
2465}
2466
2467/*
2468 * SQL function that can be used for testing json_populate_record().
2469 *
2470 * Returns false if json_populate_record() encounters an error for the
2471 * provided input JSON object, true otherwise.
2472 */
2473Datum
2475{
2477
2478 (void) populate_record_worker(fcinfo, "jsonb_populate_record",
2479 false, true, (Node *) &escontext);
2480
2481 return BoolGetDatum(!escontext.error_occurred);
2482}
2483
2484Datum
2486{
2487 return populate_record_worker(fcinfo, "jsonb_to_record",
2488 false, false, NULL);
2489}
2490
2491Datum
2493{
2494 return populate_record_worker(fcinfo, "json_populate_record",
2495 true, true, NULL);
2496}
2497
2498Datum
2500{
2501 return populate_record_worker(fcinfo, "json_to_record",
2502 true, false, NULL);
2503}
2504
2505/* helper function for diagnostics */
2506static void
2508{
2509 if (ndim <= 0)
2510 {
2511 if (ctx->colname)
2512 errsave(ctx->escontext,
2514 errmsg("expected JSON array"),
2515 errhint("See the value of key \"%s\".", ctx->colname)));
2516 else
2517 errsave(ctx->escontext,
2519 errmsg("expected JSON array")));
2520 return;
2521 }
2522 else
2523 {
2524 StringInfoData indices;
2525 int i;
2526
2527 initStringInfo(&indices);
2528
2529 Assert(ctx->ndims > 0 && ndim < ctx->ndims);
2530
2531 for (i = 0; i < ndim; i++)
2532 appendStringInfo(&indices, "[%d]", ctx->sizes[i]);
2533
2534 if (ctx->colname)
2535 errsave(ctx->escontext,
2537 errmsg("expected JSON array"),
2538 errhint("See the array element %s of key \"%s\".",
2539 indices.data, ctx->colname)));
2540 else
2541 errsave(ctx->escontext,
2543 errmsg("expected JSON array"),
2544 errhint("See the array element %s.",
2545 indices.data)));
2546 return;
2547 }
2548}
2549
2550/*
2551 * Validate and set ndims for populating an array with some
2552 * populate_array_*() function.
2553 *
2554 * Returns false if the input (ndims) is erroneous.
2555 */
2556static bool
2558{
2559 int i;
2560
2561 Assert(ctx->ndims <= 0);
2562
2563 if (ndims <= 0)
2564 {
2566 /* Getting here means the error was reported softly. */
2568 return false;
2569 }
2570
2571 ctx->ndims = ndims;
2572 ctx->dims = palloc_array(int, ndims);
2573 ctx->sizes = palloc0_array(int, ndims);
2574
2575 for (i = 0; i < ndims; i++)
2576 ctx->dims[i] = -1; /* dimensions are unknown yet */
2577
2578 return true;
2579}
2580
2581/*
2582 * Check the populated subarray dimension
2583 *
2584 * Returns false if the input (ndims) is erroneous.
2585 */
2586static bool
2588{
2589 int dim = ctx->sizes[ndim]; /* current dimension counter */
2590
2591 if (ctx->dims[ndim] == -1)
2592 ctx->dims[ndim] = dim; /* assign dimension if not yet known */
2593 else if (ctx->dims[ndim] != dim)
2594 ereturn(ctx->escontext, false,
2596 errmsg("malformed JSON array"),
2597 errdetail("Multidimensional arrays must have "
2598 "sub-arrays with matching dimensions.")));
2599
2600 /* reset the current array dimension size counter */
2601 ctx->sizes[ndim] = 0;
2602
2603 /* increment the parent dimension counter if it is a nested sub-array */
2604 if (ndim > 0)
2605 ctx->sizes[ndim - 1]++;
2606
2607 return true;
2608}
2609
2610/*
2611 * Returns true if the array element value was successfully extracted from jsv
2612 * and added to ctx->astate. False if an error occurred when doing so.
2613 */
2614static bool
2616{
2617 Datum element;
2618 bool element_isnull;
2619
2620 /* populate the array element */
2622 ctx->aio->element_type,
2623 ctx->aio->element_typmod,
2624 NULL, ctx->mcxt, PointerGetDatum(NULL),
2626 false);
2627 /* Nothing to do on an error. */
2629 return false;
2630
2632 ctx->aio->element_type, ctx->acxt);
2633
2634 Assert(ndim > 0);
2635 ctx->sizes[ndim - 1]++; /* increment current dimension counter */
2636
2637 return true;
2638}
2639
2640/* json object start handler for populate_array_json() */
2641static JsonParseErrorType
2643{
2645 int ndim = state->lex->lex_level;
2646
2647 if (state->ctx->ndims <= 0)
2648 {
2649 if (!populate_array_assign_ndims(state->ctx, ndim))
2651 }
2652 else if (ndim < state->ctx->ndims)
2653 {
2655 /* Getting here means the error was reported softly. */
2656 Assert(SOFT_ERROR_OCCURRED(state->ctx->escontext));
2658 }
2659
2660 return JSON_SUCCESS;
2661}
2662
2663/* json array end handler for populate_array_json() */
2664static JsonParseErrorType
2666{
2668 PopulateArrayContext *ctx = state->ctx;
2669 int ndim = state->lex->lex_level;
2670
2671 if (ctx->ndims <= 0)
2672 {
2673 if (!populate_array_assign_ndims(ctx, ndim + 1))
2675 }
2676
2677 if (ndim < ctx->ndims)
2678 {
2679 /* Report if an error occurred. */
2680 if (!populate_array_check_dimension(ctx, ndim))
2682 }
2683
2684 return JSON_SUCCESS;
2685}
2686
2687/* json array element start handler for populate_array_json() */
2688static JsonParseErrorType
2690{
2692 int ndim = state->lex->lex_level;
2693
2694 if (state->ctx->ndims <= 0 || ndim == state->ctx->ndims)
2695 {
2696 /* remember current array element start */
2697 state->element_start = state->lex->token_start;
2698 state->element_type = state->lex->token_type;
2699 state->element_scalar = NULL;
2700 }
2701
2702 return JSON_SUCCESS;
2703}
2704
2705/* json array element end handler for populate_array_json() */
2706static JsonParseErrorType
2708{
2710 PopulateArrayContext *ctx = state->ctx;
2711 int ndim = state->lex->lex_level;
2712
2713 Assert(ctx->ndims > 0);
2714
2715 if (ndim == ctx->ndims)
2716 {
2717 JsValue jsv;
2718
2719 jsv.is_json = true;
2720 jsv.val.json.type = state->element_type;
2721
2722 if (isnull)
2723 {
2724 Assert(jsv.val.json.type == JSON_TOKEN_NULL);
2725 jsv.val.json.str = NULL;
2726 jsv.val.json.len = 0;
2727 }
2728 else if (state->element_scalar)
2729 {
2730 jsv.val.json.str = state->element_scalar;
2731 jsv.val.json.len = -1; /* null-terminated */
2732 }
2733 else
2734 {
2735 jsv.val.json.str = state->element_start;
2736 jsv.val.json.len = (state->lex->prev_token_terminator -
2737 state->element_start) * sizeof(char);
2738 }
2739
2740 /* Report if an error occurred. */
2741 if (!populate_array_element(ctx, ndim, &jsv))
2743 }
2744
2745 return JSON_SUCCESS;
2746}
2747
2748/* json scalar handler for populate_array_json() */
2749static JsonParseErrorType
2751{
2753 PopulateArrayContext *ctx = state->ctx;
2754 int ndim = state->lex->lex_level;
2755
2756 if (ctx->ndims <= 0)
2757 {
2758 if (!populate_array_assign_ndims(ctx, ndim))
2760 }
2761 else if (ndim < ctx->ndims)
2762 {
2764 /* Getting here means the error was reported softly. */
2767 }
2768
2769 if (ndim == ctx->ndims)
2770 {
2771 /* remember the scalar element token */
2772 state->element_scalar = token;
2773 /* element_type must already be set in populate_array_element_start() */
2774 Assert(state->element_type == tokentype);
2775 }
2776
2777 return JSON_SUCCESS;
2778}
2779
2780/*
2781 * Parse a json array and populate array
2782 *
2783 * Returns false if an error occurs when parsing.
2784 */
2785static bool
2787{
2790
2792 GetDatabaseEncoding(), true);
2793 state.ctx = ctx;
2794
2795 memset(&sem, 0, sizeof(sem));
2796 sem.semstate = &state;
2802
2804 {
2805 /* number of dimensions should be already known */
2806 Assert(ctx->ndims > 0 && ctx->dims);
2807 }
2808
2810
2811 return !SOFT_ERROR_OCCURRED(ctx->escontext);
2812}
2813
2814/*
2815 * populate_array_dim_jsonb() -- Iterate recursively through jsonb sub-array
2816 * elements and accumulate result using given ArrayBuildState.
2817 *
2818 * Returns false if we return partway through because of an error in a
2819 * subroutine.
2820 */
2821static bool
2823 JsonbValue *jbv, /* jsonb sub-array */
2824 int ndim) /* current dimension */
2825{
2826 JsonbContainer *jbc = jbv->val.binary.data;
2830 JsValue jsv;
2831
2833
2834 /* Even scalars can end up here thanks to ExecEvalJsonCoercion(). */
2835 if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc) ||
2837 {
2839 /* Getting here means the error was reported softly. */
2841 return false;
2842 }
2843
2844 it = JsonbIteratorInit(jbc);
2845
2846 tok = JsonbIteratorNext(&it, &val, true);
2848
2849 tok = JsonbIteratorNext(&it, &val, true);
2850
2851 /*
2852 * If the number of dimensions is not yet known and we have found end of
2853 * the array, or the first child element is not an array, then assign the
2854 * number of dimensions now.
2855 */
2856 if (ctx->ndims <= 0 &&
2857 (tok == WJB_END_ARRAY ||
2858 (tok == WJB_ELEM &&
2859 (val.type != jbvBinary ||
2860 !JsonContainerIsArray(val.val.binary.data)))))
2861 {
2862 if (!populate_array_assign_ndims(ctx, ndim))
2863 return false;
2864 }
2865
2866 jsv.is_json = false;
2867 jsv.val.jsonb = &val;
2868
2869 /* process all the array elements */
2870 while (tok == WJB_ELEM)
2871 {
2872 /*
2873 * Recurse only if the dimensions of dimensions is still unknown or if
2874 * it is not the innermost dimension.
2875 */
2876 if (ctx->ndims > 0 && ndim >= ctx->ndims)
2877 {
2878 if (!populate_array_element(ctx, ndim, &jsv))
2879 return false;
2880 }
2881 else
2882 {
2883 /* populate child sub-array */
2884 if (!populate_array_dim_jsonb(ctx, &val, ndim + 1))
2885 return false;
2886
2887 /* number of dimensions should be already known */
2888 Assert(ctx->ndims > 0 && ctx->dims);
2889
2890 if (!populate_array_check_dimension(ctx, ndim))
2891 return false;
2892 }
2893
2894 tok = JsonbIteratorNext(&it, &val, true);
2895 }
2896
2898
2899 /* free iterator, iterating until WJB_DONE */
2900 tok = JsonbIteratorNext(&it, &val, true);
2901 Assert(tok == WJB_DONE && !it);
2902
2903 return true;
2904}
2905
2906/*
2907 * Recursively populate an array from json/jsonb
2908 *
2909 * *isnull is set to true if an error is reported during parsing.
2910 */
2911static Datum
2913 const char *colname,
2914 MemoryContext mcxt,
2915 JsValue *jsv,
2916 bool *isnull,
2917 Node *escontext)
2918{
2920 Datum result;
2921 int *lbs;
2922 int i;
2923
2924 ctx.aio = aio;
2925 ctx.mcxt = mcxt;
2927 ctx.astate = initArrayResult(aio->element_type, ctx.acxt, true);
2928 ctx.colname = colname;
2929 ctx.ndims = 0; /* unknown yet */
2930 ctx.dims = NULL;
2931 ctx.sizes = NULL;
2932 ctx.escontext = escontext;
2933
2934 if (jsv->is_json)
2935 {
2936 /* Return null if an error was found. */
2937 if (!populate_array_json(&ctx, jsv->val.json.str,
2938 jsv->val.json.len >= 0 ? jsv->val.json.len
2939 : strlen(jsv->val.json.str)))
2940 {
2941 *isnull = true;
2942 return (Datum) 0;
2943 }
2944 }
2945 else
2946 {
2947 /* Return null if an error was found. */
2948 if (!populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1))
2949 {
2950 *isnull = true;
2951 return (Datum) 0;
2952 }
2953 ctx.dims[0] = ctx.sizes[0];
2954 }
2955
2956 Assert(ctx.ndims > 0);
2957
2958 lbs = palloc_array(int, ctx.ndims);
2959
2960 for (i = 0; i < ctx.ndims; i++)
2961 lbs[i] = 1;
2962
2963 result = makeMdArrayResult(ctx.astate, ctx.ndims, ctx.dims, lbs,
2964 ctx.acxt, true);
2965
2966 pfree(ctx.dims);
2967 pfree(ctx.sizes);
2968 pfree(lbs);
2969
2970 *isnull = false;
2971 return result;
2972}
2973
2974/*
2975 * Returns false if an error occurs, provided escontext points to an
2976 * ErrorSaveContext.
2977 */
2978static bool
2980{
2981 jso->is_json = jsv->is_json;
2982
2983 if (jsv->is_json)
2984 {
2985 /* convert plain-text json into a hash table */
2986 jso->val.json_hash =
2987 get_json_object_as_hash(jsv->val.json.str,
2988 jsv->val.json.len >= 0
2989 ? jsv->val.json.len
2990 : strlen(jsv->val.json.str),
2991 "populate_composite",
2992 escontext);
2993 Assert(jso->val.json_hash != NULL || SOFT_ERROR_OCCURRED(escontext));
2994 }
2995 else
2996 {
2997 JsonbValue *jbv = jsv->val.jsonb;
2998
2999 if (jbv->type == jbvBinary &&
3000 JsonContainerIsObject(jbv->val.binary.data))
3001 {
3002 jso->val.jsonb_cont = jbv->val.binary.data;
3003 }
3004 else
3005 {
3006 bool is_scalar;
3007
3009 (jbv->type == jbvBinary &&
3010 JsonContainerIsScalar(jbv->val.binary.data));
3011 errsave(escontext,
3013 is_scalar
3014 ? errmsg("cannot call %s on a scalar",
3015 "populate_composite")
3016 : errmsg("cannot call %s on an array",
3017 "populate_composite")));
3018 }
3019 }
3020
3021 return !SOFT_ERROR_OCCURRED(escontext);
3022}
3023
3024/* acquire or update cached tuple descriptor for a composite type */
3025static void
3027{
3028 if (!io->tupdesc ||
3029 io->tupdesc->tdtypeid != io->base_typid ||
3030 io->tupdesc->tdtypmod != io->base_typmod)
3031 {
3033 io->base_typmod);
3035
3036 if (io->tupdesc)
3038
3039 /* copy tuple desc without constraints into cache memory context */
3041 io->tupdesc = CreateTupleDescCopy(tupdesc);
3043
3044 ReleaseTupleDesc(tupdesc);
3045 }
3046}
3047
3048/*
3049 * Recursively populate a composite (row type) value from json/jsonb
3050 *
3051 * Returns null if an error occurs in a subroutine, provided escontext points
3052 * to an ErrorSaveContext.
3053 */
3054static Datum
3056 Oid typid,
3057 const char *colname,
3058 MemoryContext mcxt,
3060 JsValue *jsv,
3061 bool *isnull,
3062 Node *escontext)
3063{
3064 Datum result;
3065
3066 /* acquire/update cached tuple descriptor */
3067 update_cached_tupdesc(io, mcxt);
3068
3069 if (*isnull)
3070 result = (Datum) 0;
3071 else
3072 {
3073 HeapTupleHeader tuple;
3074 JsObject jso;
3075
3076 /* prepare input value */
3077 if (!JsValueToJsObject(jsv, &jso, escontext))
3078 {
3079 *isnull = true;
3080 return (Datum) 0;
3081 }
3082
3083 /* populate resulting record tuple */
3084 tuple = populate_record(io->tupdesc, &io->record_io,
3085 defaultval, mcxt, &jso, escontext);
3086
3087 if (SOFT_ERROR_OCCURRED(escontext))
3088 {
3089 *isnull = true;
3090 return (Datum) 0;
3091 }
3092 result = HeapTupleHeaderGetDatum(tuple);
3093
3094 JsObjectFree(&jso);
3095 }
3096
3097 /*
3098 * If it's domain over composite, check domain constraints. (This should
3099 * probably get refactored so that we can see the TYPECAT value, but for
3100 * now, we can tell by comparing typid to base_typid.)
3101 */
3102 if (typid != io->base_typid && typid != RECORDOID)
3103 {
3104 if (!domain_check_safe(result, *isnull, typid, &io->domain_info, mcxt,
3105 escontext))
3106 {
3107 *isnull = true;
3108 return (Datum) 0;
3109 }
3110 }
3111
3112 return result;
3113}
3114
3115/*
3116 * Populate non-null scalar value from json/jsonb value.
3117 *
3118 * Returns null if an error occurs during the call to type input function,
3119 * provided escontext is valid.
3120 */
3121static Datum
3123 bool *isnull, Node *escontext, bool omit_quotes)
3124{
3125 Datum res;
3126 char *str = NULL;
3127 const char *json = NULL;
3128
3129 if (jsv->is_json)
3130 {
3131 int len = jsv->val.json.len;
3132
3133 json = jsv->val.json.str;
3134 Assert(json);
3135
3136 /* If converting to json/jsonb, make string into valid JSON literal */
3137 if ((typid == JSONOID || typid == JSONBOID) &&
3138 jsv->val.json.type == JSON_TOKEN_STRING)
3139 {
3141
3143 if (len >= 0)
3144 escape_json_with_len(&buf, json, len);
3145 else
3146 escape_json(&buf, json);
3147 str = buf.data;
3148 }
3149 else if (len >= 0)
3150 {
3151 /* create a NUL-terminated version */
3152 str = palloc(len + 1);
3153 memcpy(str, json, len);
3154 str[len] = '\0';
3155 }
3156 else
3157 {
3158 /* string is already NUL-terminated */
3159 str = unconstify(char *, json);
3160 }
3161 }
3162 else
3163 {
3164 JsonbValue *jbv = jsv->val.jsonb;
3165
3166 if (jbv->type == jbvString && omit_quotes)
3167 str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3168 else if (typid == JSONBOID)
3169 {
3170 Jsonb *jsonb = JsonbValueToJsonb(jbv); /* directly use jsonb */
3171
3172 return JsonbPGetDatum(jsonb);
3173 }
3174 /* convert jsonb to string for typio call */
3175 else if (typid == JSONOID && jbv->type != jbvBinary)
3176 {
3177 /*
3178 * Convert scalar jsonb (non-scalars are passed here as jbvBinary)
3179 * to json string, preserving quotes around top-level strings.
3180 */
3181 Jsonb *jsonb = JsonbValueToJsonb(jbv);
3182
3183 str = JsonbToCString(NULL, &jsonb->root, VARSIZE(jsonb));
3184 }
3185 else if (jbv->type == jbvString) /* quotes are stripped */
3186 str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3187 else if (jbv->type == jbvBool)
3188 str = pstrdup(jbv->val.boolean ? "true" : "false");
3189 else if (jbv->type == jbvNumeric)
3191 PointerGetDatum(jbv->val.numeric)));
3192 else if (jbv->type == jbvBinary)
3193 str = JsonbToCString(NULL, jbv->val.binary.data,
3194 jbv->val.binary.len);
3195 else
3196 elog(ERROR, "unrecognized jsonb type: %d", (int) jbv->type);
3197 }
3198
3199 if (!InputFunctionCallSafe(&io->typiofunc, str, io->typioparam, typmod,
3200 escontext, &res))
3201 {
3202 res = (Datum) 0;
3203 *isnull = true;
3204 }
3205
3206 /* free temporary buffer */
3207 if (str != json)
3208 pfree(str);
3209
3210 return res;
3211}
3212
3213static Datum
3215 Oid typid,
3216 const char *colname,
3217 MemoryContext mcxt,
3218 JsValue *jsv,
3219 bool *isnull,
3220 Node *escontext,
3221 bool omit_quotes)
3222{
3223 Datum res;
3224
3225 if (*isnull)
3226 res = (Datum) 0;
3227 else
3228 {
3230 io->base_typid, io->base_typmod,
3231 colname, mcxt, PointerGetDatum(NULL),
3232 jsv, isnull, escontext, omit_quotes);
3233 Assert(!*isnull || SOFT_ERROR_OCCURRED(escontext));
3234 }
3235
3236 if (!domain_check_safe(res, *isnull, typid, &io->domain_info, mcxt,
3237 escontext))
3238 {
3239 *isnull = true;
3240 return (Datum) 0;
3241 }
3242
3243 return res;
3244}
3245
3246/* prepare column metadata cache for the given type */
3247static void
3249 Oid typid,
3250 int32 typmod,
3251 MemoryContext mcxt,
3252 bool need_scalar)
3253{
3254 HeapTuple tup;
3256
3257 column->typid = typid;
3258 column->typmod = typmod;
3259
3261 if (!HeapTupleIsValid(tup))
3262 elog(ERROR, "cache lookup failed for type %u", typid);
3263
3265
3266 if (type->typtype == TYPTYPE_DOMAIN)
3267 {
3268 /*
3269 * We can move directly to the bottom base type; domain_check() will
3270 * take care of checking all constraints for a stack of domains.
3271 */
3272 Oid base_typid;
3273 int32 base_typmod = typmod;
3274
3275 base_typid = getBaseTypeAndTypmod(typid, &base_typmod);
3276 if (get_typtype(base_typid) == TYPTYPE_COMPOSITE)
3277 {
3278 /* domain over composite has its own code path */
3280 column->io.composite.record_io = NULL;
3281 column->io.composite.tupdesc = NULL;
3282 column->io.composite.base_typid = base_typid;
3283 column->io.composite.base_typmod = base_typmod;
3284 column->io.composite.domain_info = NULL;
3285 }
3286 else
3287 {
3288 /* domain over anything else */
3289 column->typcat = TYPECAT_DOMAIN;
3290 column->io.domain.base_typid = base_typid;
3291 column->io.domain.base_typmod = base_typmod;
3292 column->io.domain.base_io =
3293 MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3294 column->io.domain.domain_info = NULL;
3295 }
3296 }
3297 else if (type->typtype == TYPTYPE_COMPOSITE || typid == RECORDOID)
3298 {
3299 column->typcat = TYPECAT_COMPOSITE;
3300 column->io.composite.record_io = NULL;
3301 column->io.composite.tupdesc = NULL;
3302 column->io.composite.base_typid = typid;
3303 column->io.composite.base_typmod = typmod;
3304 column->io.composite.domain_info = NULL;
3305 }
3306 else if (IsTrueArrayType(type))
3307 {
3308 column->typcat = TYPECAT_ARRAY;
3309 column->io.array.element_info = MemoryContextAllocZero(mcxt,
3310 sizeof(ColumnIOData));
3311 column->io.array.element_type = type->typelem;
3312 /* array element typemod stored in attribute's typmod */
3313 column->io.array.element_typmod = typmod;
3314 }
3315 else
3316 {
3317 column->typcat = TYPECAT_SCALAR;
3318 need_scalar = true;
3319 }
3320
3321 /* caller can force us to look up scalar_io info even for non-scalars */
3322 if (need_scalar)
3323 {
3324 Oid typioproc;
3325
3326 getTypeInputInfo(typid, &typioproc, &column->scalar_io.typioparam);
3327 fmgr_info_cxt(typioproc, &column->scalar_io.typiofunc, mcxt);
3328 }
3329
3331}
3332
3333/*
3334 * Populate and return the value of specified type from a given json/jsonb
3335 * value 'json_val'. 'cache' is caller-specified pointer to save the
3336 * ColumnIOData that will be initialized on the 1st call and then reused
3337 * during any subsequent calls. 'mcxt' gives the memory context to allocate
3338 * the ColumnIOData and any other subsidiary memory in. 'escontext',
3339 * if not NULL, tells that any errors that occur should be handled softly.
3340 */
3341Datum
3343 Oid typid, int32 typmod,
3344 void **cache, MemoryContext mcxt,
3345 bool *isnull, bool omit_quotes,
3346 Node *escontext)
3347{
3348 JsValue jsv = {0};
3350
3351 jsv.is_json = json_type == JSONOID;
3352
3353 if (*isnull)
3354 {
3355 if (jsv.is_json)
3356 jsv.val.json.str = NULL;
3357 else
3358 jsv.val.jsonb = NULL;
3359 }
3360 else if (jsv.is_json)
3361 {
3362 text *json = DatumGetTextPP(json_val);
3363
3364 jsv.val.json.str = VARDATA_ANY(json);
3365 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3366 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3367 * populate_composite() */
3368 }
3369 else
3370 {
3371 Jsonb *jsonb = DatumGetJsonbP(json_val);
3372
3373 jsv.val.jsonb = &jbv;
3374
3375 if (omit_quotes)
3376 {
3378
3379 /* fill the quote-stripped string */
3380 jbv.type = jbvString;
3381 jbv.val.string.len = strlen(str);
3382 jbv.val.string.val = str;
3383 }
3384 else
3385 {
3386 /* fill binary jsonb value pointing to jb */
3387 jbv.type = jbvBinary;
3388 jbv.val.binary.data = &jsonb->root;
3389 jbv.val.binary.len = VARSIZE(jsonb) - VARHDRSZ;
3390 }
3391 }
3392
3393 if (*cache == NULL)
3394 *cache = MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3395
3396 return populate_record_field(*cache, typid, typmod, NULL, mcxt,
3397 PointerGetDatum(NULL), &jsv, isnull,
3398 escontext, omit_quotes);
3399}
3400
3401/* recursively populate a record field or an array element from a json/jsonb value */
3402static Datum
3404 Oid typid,
3405 int32 typmod,
3406 const char *colname,
3407 MemoryContext mcxt,
3409 JsValue *jsv,
3410 bool *isnull,
3411 Node *escontext,
3412 bool omit_scalar_quotes)
3413{
3414 TypeCat typcat;
3415
3417
3418 /*
3419 * Prepare column metadata cache for the given type. Force lookup of the
3420 * scalar_io data so that the json string hack below will work.
3421 */
3422 if (col->typid != typid || col->typmod != typmod)
3423 prepare_column_cache(col, typid, typmod, mcxt, true);
3424
3425 *isnull = JsValueIsNull(jsv);
3426
3427 typcat = col->typcat;
3428
3429 /* try to convert json string to a non-scalar type through input function */
3430 if (JsValueIsString(jsv) &&
3431 (typcat == TYPECAT_ARRAY ||
3432 typcat == TYPECAT_COMPOSITE ||
3433 typcat == TYPECAT_COMPOSITE_DOMAIN))
3434 typcat = TYPECAT_SCALAR;
3435
3436 /* we must perform domain checks for NULLs, otherwise exit immediately */
3437 if (*isnull &&
3438 typcat != TYPECAT_DOMAIN &&
3439 typcat != TYPECAT_COMPOSITE_DOMAIN)
3440 return (Datum) 0;
3441
3442 switch (typcat)
3443 {
3444 case TYPECAT_SCALAR:
3445 return populate_scalar(&col->scalar_io, typid, typmod, jsv,
3446 isnull, escontext, omit_scalar_quotes);
3447
3448 case TYPECAT_ARRAY:
3449 return populate_array(&col->io.array, colname, mcxt, jsv,
3450 isnull, escontext);
3451
3452 case TYPECAT_COMPOSITE:
3454 return populate_composite(&col->io.composite, typid,
3455 colname, mcxt,
3458 : NULL,
3459 jsv, isnull,
3460 escontext);
3461
3462 case TYPECAT_DOMAIN:
3463 return populate_domain(&col->io.domain, typid, colname, mcxt,
3464 jsv, isnull, escontext, omit_scalar_quotes);
3465
3466 default:
3467 elog(ERROR, "unrecognized type category '%c'", typcat);
3468 return (Datum) 0;
3469 }
3470}
3471
3472static RecordIOData *
3474{
3476 MemoryContextAlloc(mcxt,
3477 offsetof(RecordIOData, columns) +
3478 ncolumns * sizeof(ColumnIOData));
3479
3481 data->record_typmod = 0;
3482 data->ncolumns = ncolumns;
3483 MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3484
3485 return data;
3486}
3487
3488static bool
3490{
3491 jsv->is_json = obj->is_json;
3492
3493 if (jsv->is_json)
3494 {
3496 HASH_FIND, NULL);
3497
3498 jsv->val.json.type = hashentry ? hashentry->type : JSON_TOKEN_NULL;
3499 jsv->val.json.str = jsv->val.json.type == JSON_TOKEN_NULL ? NULL :
3500 hashentry->val;
3501 jsv->val.json.len = jsv->val.json.str ? -1 : 0; /* null-terminated */
3502
3503 return hashentry != NULL;
3504 }
3505 else
3506 {
3507 jsv->val.jsonb = !obj->val.jsonb_cont ? NULL :
3509 NULL);
3510
3511 return jsv->val.jsonb != NULL;
3512 }
3513}
3514
3515/* populate a record tuple from json/jsonb value */
3516static HeapTupleHeader
3520 MemoryContext mcxt,
3521 JsObject *obj,
3522 Node *escontext)
3523{
3524 RecordIOData *record = *record_p;
3525 Datum *values;
3526 bool *nulls;
3527 HeapTuple res;
3528 int ncolumns = tupdesc->natts;
3529 int i;
3530
3531 /*
3532 * if the input json is empty, we can only skip the rest if we were passed
3533 * in a non-null record, since otherwise there may be issues with domain
3534 * nulls.
3535 */
3536 if (defaultval && JsObjectIsEmpty(obj))
3537 return defaultval;
3538
3539 /* (re)allocate metadata cache */
3540 if (record == NULL ||
3541 record->ncolumns != ncolumns)
3542 *record_p = record = allocate_record_info(mcxt, ncolumns);
3543
3544 /* invalidate metadata cache if the record type has changed */
3545 if (record->record_type != tupdesc->tdtypeid ||
3546 record->record_typmod != tupdesc->tdtypmod)
3547 {
3548 MemSet(record, 0, offsetof(RecordIOData, columns) +
3549 ncolumns * sizeof(ColumnIOData));
3550 record->record_type = tupdesc->tdtypeid;
3551 record->record_typmod = tupdesc->tdtypmod;
3552 record->ncolumns = ncolumns;
3553 }
3554
3555 values = (Datum *) palloc(ncolumns * sizeof(Datum));
3556 nulls = (bool *) palloc(ncolumns * sizeof(bool));
3557
3558 if (defaultval)
3559 {
3560 HeapTupleData tuple;
3561
3562 /* Build a temporary HeapTuple control structure */
3564 ItemPointerSetInvalid(&(tuple.t_self));
3565 tuple.t_tableOid = InvalidOid;
3566 tuple.t_data = defaultval;
3567
3568 /* Break down the tuple into fields */
3569 heap_deform_tuple(&tuple, tupdesc, values, nulls);
3570 }
3571 else
3572 {
3573 for (i = 0; i < ncolumns; ++i)
3574 {
3575 values[i] = (Datum) 0;
3576 nulls[i] = true;
3577 }
3578 }
3579
3580 for (i = 0; i < ncolumns; ++i)
3581 {
3583 char *colname = NameStr(att->attname);
3584 JsValue field = {0};
3585 bool found;
3586
3587 /* Ignore dropped columns in datatype */
3588 if (att->attisdropped)
3589 {
3590 nulls[i] = true;
3591 continue;
3592 }
3593
3594 found = JsObjectGetField(obj, colname, &field);
3595
3596 /*
3597 * we can't just skip here if the key wasn't found since we might have
3598 * a domain to deal with. If we were passed in a non-null record
3599 * datum, we assume that the existing values are valid (if they're
3600 * not, then it's not our fault), but if we were passed in a null,
3601 * then every field which we don't populate needs to be run through
3602 * the input function just in case it's a domain type.
3603 */
3604 if (defaultval && !found)
3605 continue;
3606
3607 values[i] = populate_record_field(&record->columns[i],
3608 att->atttypid,
3609 att->atttypmod,
3610 colname,
3611 mcxt,
3612 nulls[i] ? (Datum) 0 : values[i],
3613 &field,
3614 &nulls[i],
3615 escontext,
3616 false);
3617 }
3618
3619 res = heap_form_tuple(tupdesc, values, nulls);
3620
3621 pfree(values);
3622 pfree(nulls);
3623
3624 return res->t_data;
3625}
3626
3627/*
3628 * Setup for json{b}_populate_record{set}: result type will be same as first
3629 * argument's type --- unless first argument is "null::record", which we can't
3630 * extract type info from; we handle that later.
3631 */
3632static void
3634 const char *funcname,
3635 PopulateRecordCache *cache)
3636{
3637 cache->argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
3638 prepare_column_cache(&cache->c,
3639 cache->argtype, -1,
3640 cache->fn_mcxt, false);
3641 if (cache->c.typcat != TYPECAT_COMPOSITE &&
3643 ereport(ERROR,
3645 /* translator: %s is a function name, eg json_to_record */
3646 errmsg("first argument of %s must be a row type",
3647 funcname)));
3648}
3649
3650/*
3651 * Setup for json{b}_to_record{set}: result type is specified by calling
3652 * query. We'll also use this code for json{b}_populate_record{set},
3653 * if we discover that the first argument is a null of type RECORD.
3654 *
3655 * Here it is syntactically impossible to specify the target type
3656 * as domain-over-composite.
3657 */
3658static void
3660 const char *funcname,
3661 PopulateRecordCache *cache)
3662{
3663 TupleDesc tupdesc;
3665
3666 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3667 ereport(ERROR,
3669 /* translator: %s is a function name, eg json_to_record */
3670 errmsg("could not determine row type for result of %s",
3671 funcname),
3672 errhint("Provide a non-null record argument, "
3673 "or call the function in the FROM clause "
3674 "using a column definition list.")));
3675
3676 Assert(tupdesc);
3677 cache->argtype = tupdesc->tdtypeid;
3678
3679 /* If we go through this more than once, avoid memory leak */
3680 if (cache->c.io.composite.tupdesc)
3682
3683 /* Save identified tupdesc */
3685 cache->c.io.composite.tupdesc = CreateTupleDescCopy(tupdesc);
3686 cache->c.io.composite.base_typid = tupdesc->tdtypeid;
3687 cache->c.io.composite.base_typmod = tupdesc->tdtypmod;
3689}
3690
3691/*
3692 * common worker for json{b}_populate_record() and json{b}_to_record()
3693 * is_json and have_record_arg identify the specific function
3694 */
3695static Datum
3697 bool is_json, bool have_record_arg,
3698 Node *escontext)
3699{
3700 int json_arg_num = have_record_arg ? 1 : 0;
3701 JsValue jsv = {0};
3702 HeapTupleHeader rec;
3704 bool isnull;
3707 PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
3708
3709 /*
3710 * If first time through, identify input/result record type. Note that
3711 * this stanza looks only at fcinfo context, which can't change during the
3712 * query; so we may not be able to fully resolve a RECORD input type yet.
3713 */
3714 if (!cache)
3715 {
3716 fcinfo->flinfo->fn_extra = cache =
3717 MemoryContextAllocZero(fnmcxt, sizeof(*cache));
3718 cache->fn_mcxt = fnmcxt;
3719
3720 if (have_record_arg)
3722 else
3723 get_record_type_from_query(fcinfo, funcname, cache);
3724 }
3725
3726 /* Collect record arg if we have one */
3727 if (!have_record_arg)
3728 rec = NULL; /* it's json{b}_to_record() */
3729 else if (!PG_ARGISNULL(0))
3730 {
3732
3733 /*
3734 * When declared arg type is RECORD, identify actual record type from
3735 * the tuple itself.
3736 */
3737 if (cache->argtype == RECORDOID)
3738 {
3741 }
3742 }
3743 else
3744 {
3745 rec = NULL;
3746
3747 /*
3748 * When declared arg type is RECORD, identify actual record type from
3749 * calling query, or fail if we can't.
3750 */
3751 if (cache->argtype == RECORDOID)
3752 {
3753 get_record_type_from_query(fcinfo, funcname, cache);
3754 /* This can't change argtype, which is important for next time */
3755 Assert(cache->argtype == RECORDOID);
3756 }
3757 }
3758
3759 /* If no JSON argument, just return the record (if any) unchanged */
3761 {
3762 if (rec)
3763 PG_RETURN_POINTER(rec);
3764 else
3766 }
3767
3768 jsv.is_json = is_json;
3769
3770 if (is_json)
3771 {
3773
3774 jsv.val.json.str = VARDATA_ANY(json);
3775 jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3776 jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3777 * populate_composite() */
3778 }
3779 else
3780 {
3782
3783 jsv.val.jsonb = &jbv;
3784
3785 /* fill binary jsonb value pointing to jb */
3786 jbv.type = jbvBinary;
3787 jbv.val.binary.data = &jb->root;
3788 jbv.val.binary.len = VARSIZE(jb) - VARHDRSZ;
3789 }
3790
3791 isnull = false;
3792 rettuple = populate_composite(&cache->c.io.composite, cache->argtype,
3793 NULL, fnmcxt, rec, &jsv, &isnull,
3794 escontext);
3795 Assert(!isnull || SOFT_ERROR_OCCURRED(escontext));
3796
3798}
3799
3800/*
3801 * get_json_object_as_hash
3802 *
3803 * Decomposes a json object into a hash table.
3804 *
3805 * Returns the hash table if the json is parsed successfully, NULL otherwise.
3806 */
3807static HTAB *
3808get_json_object_as_hash(const char *json, int len, const char *funcname,
3809 Node *escontext)
3810{
3811 HASHCTL ctl;
3812 HTAB *tab;
3815
3816 ctl.keysize = NAMEDATALEN;
3817 ctl.entrysize = sizeof(JsonHashEntry);
3819 tab = hash_create("json object hashtable",
3820 100,
3821 &ctl,
3823
3826
3827 state->function_name = funcname;
3828 state->hash = tab;
3830 GetDatabaseEncoding(), true);
3831
3832 sem->semstate = state;
3837
3838 if (!pg_parse_json_or_errsave(state->lex, sem, escontext))
3839 {
3840 hash_destroy(state->hash);
3841 tab = NULL;
3842 }
3843
3845
3846 return tab;
3847}
3848
3849static JsonParseErrorType
3850hash_object_field_start(void *state, char *fname, bool isnull)
3851{
3853
3854 if (_state->lex->lex_level > 1)
3855 return JSON_SUCCESS;
3856
3857 /* remember token type */
3858 _state->saved_token_type = _state->lex->token_type;
3859
3860 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
3861 _state->lex->token_type == JSON_TOKEN_OBJECT_START)
3862 {
3863 /* remember start position of the whole text of the subobject */
3864 _state->save_json_start = _state->lex->token_start;
3865 }
3866 else
3867 {
3868 /* must be a scalar */
3869 _state->save_json_start = NULL;
3870 }
3871
3872 return JSON_SUCCESS;
3873}
3874
3875static JsonParseErrorType
3876hash_object_field_end(void *state, char *fname, bool isnull)
3877{
3880 bool found;
3881
3882 /*
3883 * Ignore nested fields.
3884 */
3885 if (_state->lex->lex_level > 1)
3886 return JSON_SUCCESS;
3887
3888 /*
3889 * Ignore field names >= NAMEDATALEN - they can't match a record field.
3890 * (Note: without this test, the hash code would truncate the string at
3891 * NAMEDATALEN-1, and could then match against a similarly-truncated
3892 * record field name. That would be a reasonable behavior, but this code
3893 * has previously insisted on exact equality, so we keep this behavior.)
3894 */
3895 if (strlen(fname) >= NAMEDATALEN)
3896 return JSON_SUCCESS;
3897
3898 hashentry = hash_search(_state->hash, fname, HASH_ENTER, &found);
3899
3900 /*
3901 * found being true indicates a duplicate. We don't do anything about
3902 * that, a later field with the same name overrides the earlier field.
3903 */
3904
3905 hashentry->type = _state->saved_token_type;
3906 Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
3907
3908 if (_state->save_json_start != NULL)
3909 {
3910 int len = _state->lex->prev_token_terminator - _state->save_json_start;
3911 char *val = palloc((len + 1) * sizeof(char));
3912
3913 memcpy(val, _state->save_json_start, len);
3914 val[len] = '\0';
3915 hashentry->val = val;
3916 }
3917 else
3918 {
3919 /* must have had a scalar instead */
3920 hashentry->val = _state->saved_scalar;
3921 }
3922
3923 return JSON_SUCCESS;
3924}
3925
3926static JsonParseErrorType
3928{
3930
3931 if (_state->lex->lex_level == 0)
3932 ereport(ERROR,
3934 errmsg("cannot call %s on an array", _state->function_name)));
3935
3936 return JSON_SUCCESS;
3937}
3938
3939static JsonParseErrorType
3940hash_scalar(void *state, char *token, JsonTokenType tokentype)
3941{
3943
3944 if (_state->lex->lex_level == 0)
3945 ereport(ERROR,
3947 errmsg("cannot call %s on a scalar", _state->function_name)));
3948
3949 if (_state->lex->lex_level == 1)
3950 {
3951 _state->saved_scalar = token;
3952 /* saved_token_type must already be set in hash_object_field_start() */
3953 Assert(_state->saved_token_type == tokentype);
3954 }
3955
3956 return JSON_SUCCESS;
3957}
3958
3959
3960/*
3961 * SQL function json_populate_recordset
3962 *
3963 * set fields in a set of records from the argument json,
3964 * which must be an array of objects.
3965 *
3966 * similar to json_populate_record, but the tuple-building code
3967 * is pushed down into the semantic action handlers so it's done
3968 * per object in the array.
3969 */
3970Datum
3972{
3973 return populate_recordset_worker(fcinfo, "jsonb_populate_recordset",
3974 false, true);
3975}
3976
3977Datum
3979{
3980 return populate_recordset_worker(fcinfo, "jsonb_to_recordset",
3981 false, false);
3982}
3983
3984Datum
3986{
3987 return populate_recordset_worker(fcinfo, "json_populate_recordset",
3988 true, true);
3989}
3990
3991Datum
3993{
3994 return populate_recordset_worker(fcinfo, "json_to_recordset",
3995 true, false);
3996}
3997
3998static void
4000{
4001 PopulateRecordCache *cache = state->cache;
4003 HeapTupleData tuple;
4004
4005 /* acquire/update cached tuple descriptor */
4006 update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4007
4008 /* replace record fields from json */
4010 &cache->c.io.composite.record_io,
4011 state->rec,
4012 cache->fn_mcxt,
4013 obj,
4014 NULL);
4015
4016 /* if it's domain over composite, check domain constraints */
4017 if (cache->c.typcat == TYPECAT_COMPOSITE_DOMAIN)
4019 cache->argtype,
4020 &cache->c.io.composite.domain_info,
4021 cache->fn_mcxt,
4022 NULL);
4023
4024 /* ok, save into tuplestore */
4026 ItemPointerSetInvalid(&(tuple.t_self));
4027 tuple.t_tableOid = InvalidOid;
4028 tuple.t_data = tuphead;
4029
4030 tuplestore_puttuple(state->tuple_store, &tuple);
4031}
4032
4033/*
4034 * common worker for json{b}_populate_recordset() and json{b}_to_recordset()
4035 * is_json and have_record_arg identify the specific function
4036 */
4037static Datum
4039 bool is_json, bool have_record_arg)
4040{
4041 int json_arg_num = have_record_arg ? 1 : 0;
4042 ReturnSetInfo *rsi;
4044 HeapTupleHeader rec;
4045 PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
4047
4048 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
4049
4050 if (!rsi || !IsA(rsi, ReturnSetInfo))
4051 ereport(ERROR,
4053 errmsg("set-valued function called in context that cannot accept a set")));
4054
4055 if (!(rsi->allowedModes & SFRM_Materialize))
4056 ereport(ERROR,
4058 errmsg("materialize mode required, but it is not allowed in this context")));
4059
4061
4062 /*
4063 * If first time through, identify input/result record type. Note that
4064 * this stanza looks only at fcinfo context, which can't change during the
4065 * query; so we may not be able to fully resolve a RECORD input type yet.
4066 */
4067 if (!cache)
4068 {
4069 fcinfo->flinfo->fn_extra = cache =
4070 MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, sizeof(*cache));
4071 cache->fn_mcxt = fcinfo->flinfo->fn_mcxt;
4072
4073 if (have_record_arg)
4075 else
4076 get_record_type_from_query(fcinfo, funcname, cache);
4077 }
4078
4079 /* Collect record arg if we have one */
4080 if (!have_record_arg)
4081 rec = NULL; /* it's json{b}_to_recordset() */
4082 else if (!PG_ARGISNULL(0))
4083 {
4085
4086 /*
4087 * When declared arg type is RECORD, identify actual record type from
4088 * the tuple itself.
4089 */
4090 if (cache->argtype == RECORDOID)
4091 {
4094 }
4095 }
4096 else
4097 {
4098 rec = NULL;
4099
4100 /*
4101 * When declared arg type is RECORD, identify actual record type from
4102 * calling query, or fail if we can't.
4103 */
4104 if (cache->argtype == RECORDOID)
4105 {
4106 get_record_type_from_query(fcinfo, funcname, cache);
4107 /* This can't change argtype, which is important for next time */
4108 Assert(cache->argtype == RECORDOID);
4109 }
4110 }
4111
4112 /* if the json is null send back an empty set */
4115
4116 /*
4117 * Forcibly update the cached tupdesc, to ensure we have the right tupdesc
4118 * to return even if the JSON contains no rows.
4119 */
4120 update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
4121
4123
4124 /* make tuplestore in a sufficiently long-lived memory context */
4126 state->tuple_store = tuplestore_begin_heap(rsi->allowedModes &
4128 false, work_mem);
4130
4131 state->function_name = funcname;
4132 state->cache = cache;
4133 state->rec = rec;
4134
4135 if (is_json)
4136 {
4138 JsonLexContext lex;
4140
4142
4143 makeJsonLexContext(&lex, json, true);
4144
4145 sem->semstate = state;
4153
4154 state->lex = &lex;
4155
4157
4158 freeJsonLexContext(&lex);
4159 state->lex = NULL;
4160 }
4161 else
4162 {
4165 JsonbValue v;
4166 bool skipNested = false;
4168
4170 ereport(ERROR,
4172 errmsg("cannot call %s on a non-array",
4173 funcname)));
4174
4175 it = JsonbIteratorInit(&jb->root);
4176
4177 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4178 {
4179 skipNested = true;
4180
4181 if (r == WJB_ELEM)
4182 {
4183 JsObject obj;
4184
4185 if (v.type != jbvBinary ||
4186 !JsonContainerIsObject(v.val.binary.data))
4187 ereport(ERROR,
4189 errmsg("argument of %s must be an array of objects",
4190 funcname)));
4191
4192 obj.is_json = false;
4193 obj.val.jsonb_cont = v.val.binary.data;
4194
4196 }
4197 }
4198 }
4199
4200 /*
4201 * Note: we must copy the cached tupdesc because the executor will free
4202 * the passed-back setDesc, but we want to hang onto the cache in case
4203 * we're called again in the same query.
4204 */
4205 rsi->setResult = state->tuple_store;
4207
4209}
4210
4211static JsonParseErrorType
4213{
4215 int lex_level = _state->lex->lex_level;
4216 HASHCTL ctl;
4217
4218 /* Reject object at top level: we must have an array at level 0 */
4219 if (lex_level == 0)
4220 ereport(ERROR,
4222 errmsg("cannot call %s on an object",
4223 _state->function_name)));
4224
4225 /* Nested objects require no special processing */
4226 if (lex_level > 1)
4227 return JSON_SUCCESS;
4228
4229 /* Object at level 1: set up a new hash table for this object */
4230 ctl.keysize = NAMEDATALEN;
4231 ctl.entrysize = sizeof(JsonHashEntry);
4233 _state->json_hash = hash_create("json object hashtable",
4234 100,
4235 &ctl,
4237
4238 return JSON_SUCCESS;
4239}
4240
4241static JsonParseErrorType
4243{
4245 JsObject obj;
4246
4247 /* Nested objects require no special processing */
4248 if (_state->lex->lex_level > 1)
4249 return JSON_SUCCESS;
4250
4251 obj.is_json = true;
4252 obj.val.json_hash = _state->json_hash;
4253
4254 /* Otherwise, construct and return a tuple based on this level-1 object */
4256
4257 /* Done with hash for this object */
4258 hash_destroy(_state->json_hash);
4259 _state->json_hash = NULL;
4260
4261 return JSON_SUCCESS;
4262}
4263
4264static JsonParseErrorType
4266{
4268
4269 if (_state->lex->lex_level == 1 &&
4270 _state->lex->token_type != JSON_TOKEN_OBJECT_START)
4271 ereport(ERROR,
4273 errmsg("argument of %s must be an array of objects",
4274 _state->function_name)));
4275
4276 return JSON_SUCCESS;
4277}
4278
4279static JsonParseErrorType
4281{
4282 /* nothing to do */
4283 return JSON_SUCCESS;
4284}
4285
4286static JsonParseErrorType
4288{
4290
4291 if (_state->lex->lex_level == 0)
4292 ereport(ERROR,
4294 errmsg("cannot call %s on a scalar",
4295 _state->function_name)));
4296
4297 if (_state->lex->lex_level == 2)
4298 _state->saved_scalar = token;
4299
4300 return JSON_SUCCESS;
4301}
4302
4303static JsonParseErrorType
4304populate_recordset_object_field_start(void *state, char *fname, bool isnull)
4305{
4307
4308 if (_state->lex->lex_level > 2)
4309 return JSON_SUCCESS;
4310
4311 _state->saved_token_type = _state->lex->token_type;
4312
4313 if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
4314 _state->lex->token_type == JSON_TOKEN_OBJECT_START)
4315 {
4316 _state->save_json_start = _state->lex->token_start;
4317 }
4318 else
4319 {
4320 _state->save_json_start = NULL;
4321 }
4322
4323 return JSON_SUCCESS;
4324}
4325
4326static JsonParseErrorType
4327populate_recordset_object_field_end(void *state, char *fname, bool isnull)
4328{
4331 bool found;
4332
4333 /*
4334 * Ignore nested fields.
4335 */
4336 if (_state->lex->lex_level > 2)
4337 return JSON_SUCCESS;
4338
4339 /*
4340 * Ignore field names >= NAMEDATALEN - they can't match a record field.
4341 * (Note: without this test, the hash code would truncate the string at
4342 * NAMEDATALEN-1, and could then match against a similarly-truncated
4343 * record field name. That would be a reasonable behavior, but this code
4344 * has previously insisted on exact equality, so we keep this behavior.)
4345 */
4346 if (strlen(fname) >= NAMEDATALEN)
4347 return JSON_SUCCESS;
4348
4349 hashentry = hash_search(_state->json_hash, fname, HASH_ENTER, &found);
4350
4351 /*
4352 * found being true indicates a duplicate. We don't do anything about
4353 * that, a later field with the same name overrides the earlier field.
4354 */
4355
4356 hashentry->type = _state->saved_token_type;
4357 Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
4358
4359 if (_state->save_json_start != NULL)
4360 {
4361 int len = _state->lex->prev_token_terminator - _state->save_json_start;
4362 char *val = palloc((len + 1) * sizeof(char));
4363
4364 memcpy(val, _state->save_json_start, len);
4365 val[len] = '\0';
4366 hashentry->val = val;
4367 }
4368 else
4369 {
4370 /* must have had a scalar instead */
4371 hashentry->val = _state->saved_scalar;
4372 }
4373
4374 return JSON_SUCCESS;
4375}
4376
4377/*
4378 * Semantic actions for json_strip_nulls.
4379 *
4380 * Simply repeat the input on the output unless we encounter
4381 * a null object field. State for this is set when the field
4382 * is started and reset when the scalar action (which must be next)
4383 * is called.
4384 */
4385
4386static JsonParseErrorType
4388{
4390
4391 appendStringInfoCharMacro(_state->strval, '{');
4392
4393 return JSON_SUCCESS;
4394}
4395
4396static JsonParseErrorType
4398{
4400
4401 appendStringInfoCharMacro(_state->strval, '}');
4402
4403 return JSON_SUCCESS;
4404}
4405
4406static JsonParseErrorType
4408{
4410
4411 appendStringInfoCharMacro(_state->strval, '[');
4412
4413 return JSON_SUCCESS;
4414}
4415
4416static JsonParseErrorType
4418{
4420
4421 appendStringInfoCharMacro(_state->strval, ']');
4422
4423 return JSON_SUCCESS;
4424}
4425
4426static JsonParseErrorType
4427sn_object_field_start(void *state, char *fname, bool isnull)
4428{
4430
4431 if (isnull)
4432 {
4433 /*
4434 * The next thing must be a scalar or isnull couldn't be true, so
4435 * there is no danger of this state being carried down into a nested
4436 * object or array. The flag will be reset in the scalar action.
4437 */
4438 _state->skip_next_null = true;
4439 return JSON_SUCCESS;
4440 }
4441
4442 if (_state->strval->data[_state->strval->len - 1] != '{')
4443 appendStringInfoCharMacro(_state->strval, ',');
4444
4445 /*
4446 * Unfortunately we don't have the quoted and escaped string any more, so
4447 * we have to re-escape it.
4448 */
4449 escape_json(_state->strval, fname);
4450
4451 appendStringInfoCharMacro(_state->strval, ':');
4452
4453 return JSON_SUCCESS;
4454}
4455
4456static JsonParseErrorType
4458{
4460
4461 /* If strip_in_arrays is enabled and this is a null, mark it for skipping */
4462 if (isnull && _state->strip_in_arrays)
4463 {
4464 _state->skip_next_null = true;
4465 return JSON_SUCCESS;
4466 }
4467
4468 /* Only add a comma if this is not the first valid element */
4469 if (_state->strval->len > 0 &&
4470 _state->strval->data[_state->strval->len - 1] != '[')
4471 {
4472 appendStringInfoCharMacro(_state->strval, ',');
4473 }
4474
4475 return JSON_SUCCESS;
4476}
4477
4478static JsonParseErrorType
4479sn_scalar(void *state, char *token, JsonTokenType tokentype)
4480{
4482
4483 if (_state->skip_next_null)
4484 {
4485 Assert(tokentype == JSON_TOKEN_NULL);
4486 _state->skip_next_null = false;
4487 return JSON_SUCCESS;
4488 }
4489
4490 if (tokentype == JSON_TOKEN_STRING)
4491 escape_json(_state->strval, token);
4492 else
4494
4495 return JSON_SUCCESS;
4496}
4497
4498/*
4499 * SQL function json_strip_nulls(json) -> json
4500 */
4501Datum
4503{
4504 text *json = PG_GETARG_TEXT_PP(0);
4505 bool strip_in_arrays = PG_NARGS() == 2 ? PG_GETARG_BOOL(1) : false;
4508 JsonLexContext lex;
4510
4514
4515 state->lex = makeJsonLexContext(&lex, json, true);
4516 state->strval = &strbuf;
4517 state->skip_next_null = false;
4518 state->strip_in_arrays = strip_in_arrays;
4519
4520 sem->semstate = state;
4525 sem->scalar = sn_scalar;
4528
4530
4532 state->strval->len));
4533}
4534
4535/*
4536 * SQL function jsonb_strip_nulls(jsonb, bool) -> jsonb
4537 */
4538Datum
4540{
4542 bool strip_in_arrays = false;
4544 JsonbInState parseState = {0};
4545 JsonbValue v,
4546 k;
4548 bool last_was_key = false;
4549
4550 if (PG_NARGS() == 2)
4551 strip_in_arrays = PG_GETARG_BOOL(1);
4552
4553 if (JB_ROOT_IS_SCALAR(jb))
4555
4556 it = JsonbIteratorInit(&jb->root);
4557
4558 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
4559 {
4560 Assert(!(type == WJB_KEY && last_was_key));
4561
4562 if (type == WJB_KEY)
4563 {
4564 /* stash the key until we know if it has a null value */
4565 k = v;
4566 last_was_key = true;
4567 continue;
4568 }
4569
4570 if (last_was_key)
4571 {
4572 /* if the last element was a key this one can't be */
4573 last_was_key = false;
4574
4575 /* skip this field if value is null */
4576 if (type == WJB_VALUE && v.type == jbvNull)
4577 continue;
4578
4579 /* otherwise, do a delayed push of the key */
4580 pushJsonbValue(&parseState, WJB_KEY, &k);
4581 }
4582
4583 /* if strip_in_arrays is set, also skip null array elements */
4584 if (strip_in_arrays)
4585 if (type == WJB_ELEM && v.type == jbvNull)
4586 continue;
4587
4588 if (type == WJB_VALUE || type == WJB_ELEM)
4589 pushJsonbValue(&parseState, type, &v);
4590 else
4591 pushJsonbValue(&parseState, type, NULL);
4592 }
4593
4595}
4596
4597/*
4598 * SQL function jsonb_pretty (jsonb)
4599 *
4600 * Pretty-printed text for the jsonb
4601 */
4602Datum
4613
4614/*
4615 * SQL function jsonb_concat (jsonb, jsonb)
4616 *
4617 * function for || operator
4618 */
4619Datum
4621{
4624 JsonbInState state = {0};
4626 *it2;
4627
4628 /*
4629 * If one of the jsonb is empty, just return the other if it's not scalar
4630 * and both are of the same kind. If it's a scalar or they are of
4631 * different kinds we need to perform the concatenation even if one is
4632 * empty.
4633 */
4635 {
4636 if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
4638 else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
4640 }
4641
4642 it1 = JsonbIteratorInit(&jb1->root);
4643 it2 = JsonbIteratorInit(&jb2->root);
4644
4646
4648}
4649
4650
4651/*
4652 * SQL function jsonb_delete (jsonb, text)
4653 *
4654 * return a copy of the jsonb with the indicated item
4655 * removed.
4656 */
4657Datum
4659{
4660 Jsonb *in = PG_GETARG_JSONB_P(0);
4661 text *key = PG_GETARG_TEXT_PP(1);
4662 char *keyptr = VARDATA_ANY(key);
4663 int keylen = VARSIZE_ANY_EXHDR(key);
4664 JsonbInState pstate = {0};
4666 JsonbValue v;
4667 bool skipNested = false;
4669
4670 if (JB_ROOT_IS_SCALAR(in))
4671 ereport(ERROR,
4673 errmsg("cannot delete from scalar")));
4674
4675 if (JB_ROOT_COUNT(in) == 0)
4677
4678 it = JsonbIteratorInit(&in->root);
4679
4680 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4681 {
4682 skipNested = true;
4683
4684 if ((r == WJB_ELEM || r == WJB_KEY) &&
4685 (v.type == jbvString && keylen == v.val.string.len &&
4686 memcmp(keyptr, v.val.string.val, keylen) == 0))
4687 {
4688 /* skip corresponding value as well */
4689 if (r == WJB_KEY)
4690 (void) JsonbIteratorNext(&it, &v, true);
4691
4692 continue;
4693 }
4694
4695 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4696 }
4697
4699}
4700
4701/*
4702 * SQL function jsonb_delete (jsonb, variadic text[])
4703 *
4704 * return a copy of the jsonb with the indicated items
4705 * removed.
4706 */
4707Datum
4709{
4710 Jsonb *in = PG_GETARG_JSONB_P(0);
4713 bool *keys_nulls;
4714 int keys_len;
4715 JsonbInState pstate = {0};
4717 JsonbValue v;
4718 bool skipNested = false;
4720
4721 if (ARR_NDIM(keys) > 1)
4722 ereport(ERROR,
4724 errmsg("wrong number of array subscripts")));
4725
4726 if (JB_ROOT_IS_SCALAR(in))
4727 ereport(ERROR,
4729 errmsg("cannot delete from scalar")));
4730
4731 if (JB_ROOT_COUNT(in) == 0)
4733
4735
4736 if (keys_len == 0)
4738
4739 it = JsonbIteratorInit(&in->root);
4740
4741 while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4742 {
4743 skipNested = true;
4744
4745 if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString)
4746 {
4747 int i;
4748 bool found = false;
4749
4750 for (i = 0; i < keys_len; i++)
4751 {
4752 char *keyptr;
4753 int keylen;
4754
4755 if (keys_nulls[i])
4756 continue;
4757
4758 /* We rely on the array elements not being toasted */
4761 if (keylen == v.val.string.len &&
4762 memcmp(keyptr, v.val.string.val, keylen) == 0)
4763 {
4764 found = true;
4765 break;
4766 }
4767 }
4768 if (found)
4769 {
4770 /* skip corresponding value as well */
4771 if (r == WJB_KEY)
4772 (void) JsonbIteratorNext(&it, &v, true);
4773
4774 continue;
4775 }
4776 }
4777
4778 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4779 }
4780
4782}
4783
4784/*
4785 * SQL function jsonb_delete (jsonb, int)
4786 *
4787 * return a copy of the jsonb with the indicated item
4788 * removed. Negative int means count back from the
4789 * end of the items.
4790 */
4791Datum
4793{
4794 Jsonb *in = PG_GETARG_JSONB_P(0);
4795 int idx = PG_GETARG_INT32(1);
4796 JsonbInState pstate = {0};
4798 uint32 i = 0,
4799 n;
4800 JsonbValue v;
4802
4803 if (JB_ROOT_IS_SCALAR(in))
4804 ereport(ERROR,
4806 errmsg("cannot delete from scalar")));
4807
4808 if (JB_ROOT_IS_OBJECT(in))
4809 ereport(ERROR,
4811 errmsg("cannot delete from object using integer index")));
4812
4813 if (JB_ROOT_COUNT(in) == 0)
4815
4816 it = JsonbIteratorInit(&in->root);
4817
4818 r = JsonbIteratorNext(&it, &v, false);
4819 Assert(r == WJB_BEGIN_ARRAY);
4820 n = v.val.array.nElems;
4821
4822 if (idx < 0)
4823 {
4824 if (pg_abs_s32(idx) > n)
4825 idx = n;
4826 else
4827 idx = n + idx;
4828 }
4829
4830 if (idx >= n)
4832
4833 pushJsonbValue(&pstate, r, NULL);
4834
4835 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
4836 {
4837 if (r == WJB_ELEM)
4838 {
4839 if (i++ == idx)
4840 continue;
4841 }
4842
4843 pushJsonbValue(&pstate, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4844 }
4845
4847}
4848
4849/*
4850 * SQL function jsonb_set(jsonb, text[], jsonb, boolean)
4851 */
4852Datum
4854{
4855 Jsonb *in = PG_GETARG_JSONB_P(0);
4859 bool create = PG_GETARG_BOOL(3);
4861 bool *path_nulls;
4862 int path_len;
4864 JsonbInState st = {0};
4865
4867
4868 if (ARR_NDIM(path) > 1)
4869 ereport(ERROR,
4871 errmsg("wrong number of array subscripts")));
4872
4873 if (JB_ROOT_IS_SCALAR(in))
4874 ereport(ERROR,
4876 errmsg("cannot set path in scalar")));
4877
4878 if (JB_ROOT_COUNT(in) == 0 && !create)
4880
4882
4883 if (path_len == 0)
4885
4886 it = JsonbIteratorInit(&in->root);
4887
4889 0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4890
4892}
4893
4894
4895/*
4896 * SQL function jsonb_set_lax(jsonb, text[], jsonb, boolean, text)
4897 */
4898Datum
4900{
4902 char *handle_val;
4903
4904 if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
4906
4907 /* could happen if they pass in an explicit NULL */
4908 if (PG_ARGISNULL(4))
4909 ereport(ERROR,
4911 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4912
4913 /* if the new value isn't an SQL NULL just call jsonb_set */
4914 if (!PG_ARGISNULL(2))
4915 return jsonb_set(fcinfo);
4916
4919
4920 if (strcmp(handle_val, "raise_exception") == 0)
4921 {
4922 ereport(ERROR,
4924 errmsg("JSON value must not be null"),
4925 errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
4926 errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed.")));
4927 return (Datum) 0; /* silence stupider compilers */
4928 }
4929 else if (strcmp(handle_val, "use_json_null") == 0)
4930 {
4931 Datum newval;
4932
4934
4935 fcinfo->args[2].value = newval;
4936 fcinfo->args[2].isnull = false;
4937 return jsonb_set(fcinfo);
4938 }
4939 else if (strcmp(handle_val, "delete_key") == 0)
4940 {
4941 return jsonb_delete_path(fcinfo);
4942 }
4943 else if (strcmp(handle_val, "return_target") == 0)
4944 {
4945 Jsonb *in = PG_GETARG_JSONB_P(0);
4946
4948 }
4949 else
4950 {
4951 ereport(ERROR,
4953 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
4954 return (Datum) 0; /* silence stupider compilers */
4955 }
4956}
4957
4958/*
4959 * SQL function jsonb_delete_path(jsonb, text[])
4960 */
4961Datum
4963{
4964 Jsonb *in = PG_GETARG_JSONB_P(0);
4967 bool *path_nulls;
4968 int path_len;
4970 JsonbInState st = {0};
4971
4972 if (ARR_NDIM(path) > 1)
4973 ereport(ERROR,
4975 errmsg("wrong number of array subscripts")));
4976
4977 if (JB_ROOT_IS_SCALAR(in))
4978 ereport(ERROR,
4980 errmsg("cannot delete path in scalar")));
4981
4982 if (JB_ROOT_COUNT(in) == 0)
4984
4986
4987 if (path_len == 0)
4989
4990 it = JsonbIteratorInit(&in->root);
4991
4993 0, NULL, JB_PATH_DELETE);
4994
4996}
4997
4998/*
4999 * SQL function jsonb_insert(jsonb, text[], jsonb, boolean)
5000 */
5001Datum
5003{
5004 Jsonb *in = PG_GETARG_JSONB_P(0);
5008 bool after = PG_GETARG_BOOL(3);
5010 bool *path_nulls;
5011 int path_len;
5013 JsonbInState st = {0};
5014
5016
5017 if (ARR_NDIM(path) > 1)
5018 ereport(ERROR,
5020 errmsg("wrong number of array subscripts")));
5021
5022 if (JB_ROOT_IS_SCALAR(in))
5023 ereport(ERROR,
5025 errmsg("cannot set path in scalar")));
5026
5028
5029 if (path_len == 0)
5031
5032 it = JsonbIteratorInit(&in->root);
5033
5036
5038}
5039
5040/*
5041 * Iterate over all jsonb objects and merge them into one.
5042 * The logic of this function copied from the same hstore function,
5043 * except the case, when it1 & it2 represents jbvObject.
5044 * In that case we just append the content of it2 to it1 without any
5045 * verifications.
5046 */
5047static void
5050{
5051 JsonbValue v1,
5052 v2;
5054 r2,
5055 rk1,
5056 rk2;
5057
5058 rk1 = JsonbIteratorNext(it1, &v1, false);
5059 rk2 = JsonbIteratorNext(it2, &v2, false);
5060
5061 /*
5062 * JsonbIteratorNext reports raw scalars as if they were single-element
5063 * arrays; hence we only need consider "object" and "array" cases here.
5064 */
5066 {
5067 /*
5068 * Both inputs are objects.
5069 *
5070 * Append all the tokens from v1 to res, except last WJB_END_OBJECT
5071 * (because res will not be finished yet).
5072 */
5074 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_OBJECT)
5076
5077 /*
5078 * Append all the tokens from v2 to res, including last WJB_END_OBJECT
5079 * (the concatenation will be completed). Any duplicate keys will
5080 * automatically override the value from the first object.
5081 */
5082 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5084 }
5085 else if (rk1 == WJB_BEGIN_ARRAY && rk2 == WJB_BEGIN_ARRAY)
5086 {
5087 /*
5088 * Both inputs are arrays.
5089 */
5091
5092 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5093 {
5094 Assert(r1 == WJB_ELEM);
5096 }
5097
5098 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_END_ARRAY)
5099 {
5100 Assert(r2 == WJB_ELEM);
5102 }
5103
5104 pushJsonbValue(state, WJB_END_ARRAY, NULL /* signal to sort */ );
5105 }
5106 else if (rk1 == WJB_BEGIN_OBJECT)
5107 {
5108 /*
5109 * We have object || array.
5110 */
5112
5114
5116 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_DONE)
5118
5119 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5121 }
5122 else
5123 {
5124 /*
5125 * We have array || object.
5126 */
5129
5131
5132 while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
5134
5136 while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
5138
5140 }
5141}
5142
5143/*
5144 * Do most of the heavy work for jsonb_set/jsonb_insert
5145 *
5146 * If JB_PATH_DELETE bit is set in op_type, the element is to be removed.
5147 *
5148 * If any bit mentioned in JB_PATH_CREATE_OR_INSERT is set in op_type,
5149 * we create the new value if the key or array index does not exist.
5150 *
5151 * Bits JB_PATH_INSERT_BEFORE and JB_PATH_INSERT_AFTER in op_type
5152 * behave as JB_PATH_CREATE if new value is inserted in JsonbObject.
5153 *
5154 * If JB_PATH_FILL_GAPS bit is set, this will change an assignment logic in
5155 * case if target is an array. The assignment index will not be restricted by
5156 * number of elements in the array, and if there are any empty slots between
5157 * last element of the array and a new one they will be filled with nulls. If
5158 * the index is negative, it still will be considered an index from the end
5159 * of the array. Of a part of the path is not present and this part is more
5160 * than just one last element, this flag will instruct to create the whole
5161 * chain of corresponding objects and insert the value.
5162 *
5163 * JB_PATH_CONSISTENT_POSITION for an array indicates that the caller wants to
5164 * keep values with fixed indices. Indices for existing elements could be
5165 * changed (shifted forward) in case if the array is prepended with a new value
5166 * and a negative index out of the range, so this behavior will be prevented
5167 * and return an error.
5168 *
5169 * All path elements before the last must already exist
5170 * whatever bits in op_type are set, or nothing is done.
5171 */
5172static void
5174 const bool *path_nulls, int path_len,
5175 JsonbInState *st, int level, JsonbValue *newval, int op_type)
5176{
5177 JsonbValue v;
5179
5181
5182 if (path_nulls[level])
5183 ereport(ERROR,
5185 errmsg("path element at position %d is null",
5186 level + 1)));
5187
5188 r = JsonbIteratorNext(it, &v, false);
5189
5190 switch (r)
5191 {
5192 case WJB_BEGIN_ARRAY:
5193
5194 /*
5195 * If instructed complain about attempts to replace within a raw
5196 * scalar value. This happens even when current level is equal to
5197 * path_len, because the last path key should also correspond to
5198 * an object or an array, not raw scalar.
5199 */
5200 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) &&
5201 v.val.array.rawScalar)
5202 ereport(ERROR,
5204 errmsg("cannot replace existing key"),
5205 errdetail("The path assumes key is a composite object, "
5206 "but it is a scalar value.")));
5207
5208 pushJsonbValue(st, r, NULL);
5210 newval, v.val.array.nElems, op_type);
5211 r = JsonbIteratorNext(it, &v, false);
5212 Assert(r == WJB_END_ARRAY);
5213 pushJsonbValue(st, r, NULL);
5214 break;
5215 case WJB_BEGIN_OBJECT:
5216 pushJsonbValue(st, r, NULL);
5218 newval, v.val.object.nPairs, op_type);
5219 r = JsonbIteratorNext(it, &v, true);
5220 Assert(r == WJB_END_OBJECT);
5221 pushJsonbValue(st, r, NULL);
5222 break;
5223 case WJB_ELEM:
5224 case WJB_VALUE:
5225
5226 /*
5227 * If instructed complain about attempts to replace within a
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 an element or value.
5231 */
5232 if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1))
5233 ereport(ERROR,
5235 errmsg("cannot replace existing key"),
5236 errdetail("The path assumes key is a composite object, "
5237 "but it is a scalar value.")));
5238
5239 pushJsonbValue(st, r, &v);
5240 break;
5241 default:
5242 elog(ERROR, "unrecognized iterator result: %d", (int) r);
5243 break;
5244 }
5245}
5246
5247/*
5248 * Object walker for setPath
5249 */
5250static void
5252 int path_len, JsonbInState *st, int level,
5254{
5255 text *pathelem = NULL;
5256 int i;
5257 JsonbValue k,
5258 v;
5259 bool done = false;
5260
5261 if (level >= path_len || path_nulls[level])
5262 done = true;
5263 else
5264 {
5265 /* The path Datum could be toasted, in which case we must detoast it */
5267 }
5268
5269 /* empty object is a special case for create */
5270 if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
5271 (level == path_len - 1))
5272 {
5274
5276 newkey.val.string.val = VARDATA_ANY(pathelem);
5277 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5278
5281 }
5282
5283 for (i = 0; i < npairs; i++)
5284 {
5286
5287 Assert(r == WJB_KEY);
5288
5289 if (!done &&
5290 k.val.string.len == VARSIZE_ANY_EXHDR(pathelem) &&
5291 memcmp(k.val.string.val, VARDATA_ANY(pathelem),
5292 k.val.string.len) == 0)
5293 {
5294 done = true;
5295
5296 if (level == path_len - 1)
5297 {
5298 /*
5299 * called from jsonb_insert(), it forbids redefining an
5300 * existing value
5301 */
5303 ereport(ERROR,
5305 errmsg("cannot replace existing key"),
5306 errhint("Try using the function jsonb_set "
5307 "to replace key value.")));
5308
5309 r = JsonbIteratorNext(it, &v, true); /* skip value */
5310 if (!(op_type & JB_PATH_DELETE))
5311 {
5312 pushJsonbValue(st, WJB_KEY, &k);
5314 }
5315 }
5316 else
5317 {
5318 pushJsonbValue(st, r, &k);
5320 st, level + 1, newval, op_type);
5321 }
5322 }
5323 else
5324 {
5325 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done &&
5326 level == path_len - 1 && i == npairs - 1)
5327 {
5329
5331 newkey.val.string.val = VARDATA_ANY(pathelem);
5332 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5333
5336 }
5337
5338 pushJsonbValue(st, r, &k);
5339 r = JsonbIteratorNext(it, &v, false);
5340 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5341 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5342 {
5343 int walking_level = 1;
5344
5345 while (walking_level != 0)
5346 {
5347 r = JsonbIteratorNext(it, &v, false);
5348
5349 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5350 ++walking_level;
5351 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5352 --walking_level;
5353
5354 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5355 }
5356 }
5357 }
5358 }
5359
5360 /*--
5361 * If we got here there are only few possibilities:
5362 * - no target path was found, and an open object with some keys/values was
5363 * pushed into the state
5364 * - an object is empty, only WJB_BEGIN_OBJECT is pushed
5365 *
5366 * In both cases if instructed to create the path when not present,
5367 * generate the whole chain of empty objects and insert the new value
5368 * there.
5369 */
5370 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5371 {
5373
5375 newkey.val.string.val = VARDATA_ANY(pathelem);
5376 newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5377
5380
5381 /* Result is closed with WJB_END_OBJECT outside of this function */
5382 }
5383}
5384
5385/*
5386 * Array walker for setPath
5387 */
5388static void
5390 int path_len, JsonbInState *st, int level,
5391 JsonbValue *newval, uint32 nelems, int op_type)
5392{
5393 JsonbValue v;
5394 int idx,
5395 i;
5396 bool done = false;
5397
5398 /* pick correct index */
5399 if (level < path_len && !path_nulls[level])
5400 {
5401 char *c = TextDatumGetCString(path_elems[level]);
5402 char *badp;
5403
5404 errno = 0;
5405 idx = strtoint(c, &badp, 10);
5406 if (badp == c || *badp != '\0' || errno != 0)
5407 ereport(ERROR,
5409 errmsg("path element at position %d is not an integer: \"%s\"",
5410 level + 1, c)));
5411 }
5412 else
5413 idx = nelems;
5414
5415 if (idx < 0)
5416 {
5417 if (pg_abs_s32(idx) > nelems)
5418 {
5419 /*
5420 * If asked to keep elements position consistent, it's not allowed
5421 * to prepend the array.
5422 */
5424 ereport(ERROR,
5426 errmsg("path element at position %d is out of range: %d",
5427 level + 1, idx)));
5428 else
5429 idx = PG_INT32_MIN;
5430 }
5431 else
5432 idx = nelems + idx;
5433 }
5434
5435 /*
5436 * Filling the gaps means there are no limits on the positive index are
5437 * imposed, we can set any element. Otherwise limit the index by nelems.
5438 */
5439 if (!(op_type & JB_PATH_FILL_GAPS))
5440 {
5441 if (idx > 0 && idx > nelems)
5442 idx = nelems;
5443 }
5444
5445 /*
5446 * if we're creating, and idx == INT_MIN, we prepend the new value to the
5447 * array also if the array is empty - in which case we don't really care
5448 * what the idx value is
5449 */
5450 if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) &&
5452 {
5453 Assert(newval != NULL);
5454
5455 if (op_type & JB_PATH_FILL_GAPS && nelems == 0 && idx > 0)
5457
5459
5460 done = true;
5461 }
5462
5463 /* iterate over the array elements */
5464 for (i = 0; i < nelems; i++)
5465 {
5467
5468 if (i == idx && level < path_len)
5469 {
5470 done = true;
5471
5472 if (level == path_len - 1)
5473 {
5474 r = JsonbIteratorNext(it, &v, true); /* skip */
5475
5478
5479 /*
5480 * We should keep current value only in case of
5481 * JB_PATH_INSERT_BEFORE or JB_PATH_INSERT_AFTER because
5482 * otherwise it should be deleted or replaced
5483 */
5485 pushJsonbValue(st, r, &v);
5486
5489 }
5490 else
5492 st, level + 1, newval, op_type);
5493 }
5494 else
5495 {
5496 r = JsonbIteratorNext(it, &v, false);
5497
5498 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5499
5500 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5501 {
5502 int walking_level = 1;
5503
5504 while (walking_level != 0)
5505 {
5506 r = JsonbIteratorNext(it, &v, false);
5507
5508 if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5509 ++walking_level;
5510 if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5511 --walking_level;
5512
5513 pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5514 }
5515 }
5516 }
5517 }
5518
5519 if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1)
5520 {
5521 /*
5522 * If asked to fill the gaps, idx could be bigger than nelems, so
5523 * prepend the new element with nulls if that's the case.
5524 */
5525 if (op_type & JB_PATH_FILL_GAPS && idx > nelems)
5526 push_null_elements(st, idx - nelems);
5527
5529 done = true;
5530 }
5531
5532 /*--
5533 * If we got here there are only few possibilities:
5534 * - no target path was found, and an open array with some keys/values was
5535 * pushed into the state
5536 * - an array is empty, only WJB_BEGIN_ARRAY is pushed
5537 *
5538 * In both cases if instructed to create the path when not present,
5539 * generate the whole chain of empty objects and insert the new value
5540 * there.
5541 */
5542 if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5543 {
5544 if (idx > 0)
5545 push_null_elements(st, idx - nelems);
5546
5548
5549 /* Result is closed with WJB_END_OBJECT outside of this function */
5550 }
5551}
5552
5553/*
5554 * Parse information about what elements of a jsonb document we want to iterate
5555 * in functions iterate_json(b)_values. This information is presented in jsonb
5556 * format, so that it can be easily extended in the future.
5557 */
5558uint32
5560{
5562 JsonbValue v;
5564 uint32 flags = 0;
5565
5566 it = JsonbIteratorInit(&jb->root);
5567
5568 type = JsonbIteratorNext(&it, &v, false);
5569
5570 /*
5571 * We iterate over array (scalar internally is represented as array, so,
5572 * we will accept it too) to check all its elements. Flag names are
5573 * chosen the same as jsonb_typeof uses.
5574 */
5575 if (type != WJB_BEGIN_ARRAY)
5577 errmsg("wrong flag type, only arrays and scalars are allowed")));
5578
5579 while ((type = JsonbIteratorNext(&it, &v, false)) == WJB_ELEM)
5580 {
5581 if (v.type != jbvString)
5582 ereport(ERROR,
5584 errmsg("flag array element is not a string"),
5585 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5586
5587 if (v.val.string.len == 3 &&
5588 pg_strncasecmp(v.val.string.val, "all", 3) == 0)
5589 flags |= jtiAll;
5590 else if (v.val.string.len == 3 &&
5591 pg_strncasecmp(v.val.string.val, "key", 3) == 0)
5592 flags |= jtiKey;
5593 else if (v.val.string.len == 6 &&
5594 pg_strncasecmp(v.val.string.val, "string", 6) == 0)
5595 flags |= jtiString;
5596 else if (v.val.string.len == 7 &&
5597 pg_strncasecmp(v.val.string.val, "numeric", 7) == 0)
5598 flags |= jtiNumeric;
5599 else if (v.val.string.len == 7 &&
5600 pg_strncasecmp(v.val.string.val, "boolean", 7) == 0)
5601 flags |= jtiBool;
5602 else
5603 ereport(ERROR,
5605 errmsg("wrong flag in flag array: \"%s\"",
5606 pnstrdup(v.val.string.val, v.val.string.len)),
5607 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
5608 }
5609
5610 /* expect end of array now */
5611 if (type != WJB_END_ARRAY)
5612 elog(ERROR, "unexpected end of flag array");
5613
5614 /* get final WJB_DONE and free iterator */
5615 type = JsonbIteratorNext(&it, &v, false);
5616 if (type != WJB_DONE)
5617 elog(ERROR, "unexpected end of flag array");
5618
5619 return flags;
5620}
5621
5622/*
5623 * Iterate over jsonb values or elements, specified by flags, and pass them
5624 * together with an iteration state to a specified JsonIterateStringValuesAction.
5625 */
5626void
5629{
5631 JsonbValue v;
5633
5634 it = JsonbIteratorInit(&jb->root);
5635
5636 /*
5637 * Just recursively iterating over jsonb and call callback on all
5638 * corresponding elements
5639 */
5640 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5641 {
5642 if (type == WJB_KEY)
5643 {
5644 if (flags & jtiKey)
5645 action(state, v.val.string.val, v.val.string.len);
5646
5647 continue;
5648 }
5649 else if (!(type == WJB_VALUE || type == WJB_ELEM))
5650 {
5651 /* do not call callback for composite JsonbValue */
5652 continue;
5653 }
5654
5655 /* JsonbValue is a value of object or element of array */
5656 switch (v.type)
5657 {
5658 case jbvString:
5659 if (flags & jtiString)
5660 action(state, v.val.string.val, v.val.string.len);
5661 break;
5662 case jbvNumeric:
5663 if (flags & jtiNumeric)
5664 {
5665 char *val;
5666
5668 NumericGetDatum(v.val.numeric)));
5669
5670 action(state, val, strlen(val));
5671 pfree(val);
5672 }
5673 break;
5674 case jbvBool:
5675 if (flags & jtiBool)
5676 {
5677 if (v.val.boolean)
5678 action(state, "true", 4);
5679 else
5680 action(state, "false", 5);
5681 }
5682 break;
5683 default:
5684 /* do not call callback for composite JsonbValue */
5685 break;
5686 }
5687 }
5688}
5689
5690/*
5691 * Iterate over json values and elements, specified by flags, and pass them
5692 * together with an iteration state to a specified JsonIterateStringValuesAction.
5693 */
5694void
5695iterate_json_values(text *json, uint32 flags, void *action_state,
5697{
5698 JsonLexContext lex;
5701
5702 state->lex = makeJsonLexContext(&lex, json, true);
5703 state->action = action;
5704 state->action_state = action_state;
5705 state->flags = flags;
5706
5707 sem->semstate = state;
5710
5712 freeJsonLexContext(&lex);
5713}
5714
5715/*
5716 * An auxiliary function for iterate_json_values to invoke a specified
5717 * JsonIterateStringValuesAction for specified values.
5718 */
5719static JsonParseErrorType
5721{
5723
5724 switch (tokentype)
5725 {
5726 case JSON_TOKEN_STRING:
5727 if (_state->flags & jtiString)
5728 _state->action(_state->action_state, token, strlen(token));
5729 break;
5730 case JSON_TOKEN_NUMBER:
5731 if (_state->flags & jtiNumeric)
5732 _state->action(_state->action_state, token, strlen(token));
5733 break;
5734 case JSON_TOKEN_TRUE:
5735 case JSON_TOKEN_FALSE:
5736 if (_state->flags & jtiBool)
5737 _state->action(_state->action_state, token, strlen(token));
5738 break;
5739 default:
5740 /* do not call callback for any other token */
5741 break;
5742 }
5743
5744 return JSON_SUCCESS;
5745}
5746
5747static JsonParseErrorType
5748iterate_values_object_field_start(void *state, char *fname, bool isnull)
5749{
5751
5752 if (_state->flags & jtiKey)
5753 {
5754 char *val = pstrdup(fname);
5755
5756 _state->action(_state->action_state, val, strlen(val));
5757 }
5758
5759 return JSON_SUCCESS;
5760}
5761
5762/*
5763 * Iterate over a jsonb, and apply a specified JsonTransformStringValuesAction
5764 * to every string value or element. Any necessary context for a
5765 * JsonTransformStringValuesAction can be passed in the action_state variable.
5766 * Function returns a copy of an original jsonb object with transformed values.
5767 */
5768Jsonb *
5769transform_jsonb_string_values(Jsonb *jsonb, void *action_state,
5771{
5773 JsonbValue v;
5775 JsonbInState st = {0};
5776 text *out;
5777 bool is_scalar = false;
5778
5779 it = JsonbIteratorInit(&jsonb->root);
5780 is_scalar = it->isScalar;
5781
5782 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5783 {
5784 if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
5785 {
5786 out = transform_action(action_state, v.val.string.val, v.val.string.len);
5787 /* out is probably not toasted, but let's be sure */
5788 out = pg_detoast_datum_packed(out);
5789 v.val.string.val = VARDATA_ANY(out);
5790 v.val.string.len = VARSIZE_ANY_EXHDR(out);
5792 }
5793 else
5794 {
5795 pushJsonbValue(&st, type, (type == WJB_KEY ||
5796 type == WJB_VALUE ||
5797 type == WJB_ELEM) ? &v : NULL);
5798 }
5799 }
5800
5801 if (st.result->type == jbvArray)
5802 st.result->val.array.rawScalar = is_scalar;
5803
5804 return JsonbValueToJsonb(st.result);
5805}
5806
5807/*
5808 * Iterate over a json, and apply a specified JsonTransformStringValuesAction
5809 * to every string value or element. Any necessary context for a
5810 * JsonTransformStringValuesAction can be passed in the action_state variable.
5811 * Function returns a Text Datum, which is a copy of an original json with
5812 * transformed values.
5813 */
5814text *
5844
5845/*
5846 * Set of auxiliary functions for transform_json_string_values to invoke a
5847 * specified JsonTransformStringValuesAction for all values and left everything
5848 * else untouched.
5849 */
5850static JsonParseErrorType
5859
5860static JsonParseErrorType
5869
5870static JsonParseErrorType
5879
5880static JsonParseErrorType
5889
5890static JsonParseErrorType
5892{
5894
5895 if (_state->strval->data[_state->strval->len - 1] != '{')
5896 appendStringInfoCharMacro(_state->strval, ',');
5897
5898 /*
5899 * Unfortunately we don't have the quoted and escaped string any more, so
5900 * we have to re-escape it.
5901 */
5902 escape_json(_state->strval, fname);
5903 appendStringInfoCharMacro(_state->strval, ':');
5904
5905 return JSON_SUCCESS;
5906}
5907
5908static JsonParseErrorType
5910{
5912
5913 if (_state->strval->data[_state->strval->len - 1] != '[')
5914 appendStringInfoCharMacro(_state->strval, ',');
5915
5916 return JSON_SUCCESS;
5917}
5918
5919static JsonParseErrorType
5921{
5923
5924 if (tokentype == JSON_TOKEN_STRING)
5925 {
5926 text *out = _state->action(_state->action_state, token, strlen(token));
5927
5928 escape_json_text(_state->strval, out);
5929 }
5930 else
5932
5933 return JSON_SUCCESS;
5934}
5935
5938{
5939 JsonLexContext lex;
5940 JsonParseErrorType result;
5941
5942 makeJsonLexContext(&lex, json, false);
5943
5944 /* Lex exactly one token from the input and check its type. */
5945 result = json_lex(&lex);
5946
5947 if (result == JSON_SUCCESS)
5948 return lex.token_type;
5949
5950 if (throw_error)
5951 json_errsave_error(result, &lex, NULL);
5952
5953 return JSON_TOKEN_INVALID; /* invalid json */
5954}
5955
5956/*
5957 * Determine how we want to print values of a given type in datum_to_json(b).
5958 *
5959 * Given the datatype OID, return its JsonTypeCategory, as well as the type's
5960 * output function OID. If the returned category is JSONTYPE_CAST, we return
5961 * the OID of the type->JSON cast function instead.
5962 */
5963void
5966{
5967 bool typisvarlena;
5968
5969 /* Look through any domain */
5970 typoid = getBaseType(typoid);
5971
5973
5974 switch (typoid)
5975 {
5976 case BOOLOID:
5979 break;
5980
5981 case INT2OID:
5982 case INT4OID:
5983 case INT8OID:
5984 case FLOAT4OID:
5985 case FLOAT8OID:
5986 case NUMERICOID:
5987 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
5989 break;
5990
5991 case DATEOID:
5994 break;
5995
5996 case TIMESTAMPOID:
5999 break;
6000
6001 case TIMESTAMPTZOID:
6004 break;
6005
6006 case JSONOID:
6007 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6009 break;
6010
6011 case JSONBOID:
6012 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6014 break;
6015
6016 default:
6017 /* Check for arrays and composites */
6018 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
6019 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
6020 {
6023 }
6024 else if (type_is_rowtype(typoid)) /* includes RECORDOID */
6025 {
6028 }
6029 else
6030 {
6031 /*
6032 * It's probably the general case. But let's look for a cast
6033 * to json (note: not to jsonb even if is_jsonb is true), if
6034 * it's not built-in.
6035 */
6037 if (typoid >= FirstNormalObjectId)
6038 {
6039 Oid castfunc;
6040 CoercionPathType ctype;
6041
6042 ctype = find_coercion_pathway(JSONOID, typoid,
6044 &castfunc);
6045 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
6046 {
6047 *outfuncoid = castfunc;
6049 }
6050 else
6051 {
6052 /* non builtin type with no cast */
6053 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6054 }
6055 }
6056 else
6057 {
6058 /* any other builtin type */
6059 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
6060 }
6061 }
6062 break;
6063 }
6064}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
#define ARR_NDIM(a)
Definition array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition array.h:263
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
bool array_contains_nulls(const ArrayType *array)
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Datum numeric_out(PG_FUNCTION_ARGS)
Definition numeric.c:799
static Datum values[MAXATTR]
Definition bootstrap.c:155
#define CStringGetTextDatum(s)
Definition builtins.h:97
#define TextDatumGetCString(d)
Definition builtins.h:98
#define NameStr(name)
Definition c.h:765
#define unconstify(underlying_type, expr)
Definition c.h:1234
#define IS_HIGHBIT_SET(ch)
Definition c.h:1144
#define VARHDRSZ
Definition c.h:711
#define Assert(condition)
Definition c.h:873
#define FLEXIBLE_ARRAY_MEMBER
Definition c.h:480
int32_t int32
Definition c.h:542
uint32_t uint32
Definition c.h:546
#define PG_INT32_MIN
Definition c.h:602
#define MemSet(start, val, len)
Definition c.h:1013
#define OidIsValid(objectId)
Definition c.h:788
bool domain_check_safe(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt, Node *escontext)
Definition domains.c:355
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
void hash_destroy(HTAB *hashp)
Definition dynahash.c:865
int errdetail_internal(const char *fmt,...)
Definition elog.c:1243
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errhint(const char *fmt,...)
Definition elog.c:1330
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ereturn(context, dummy_value,...)
Definition elog.h:278
#define errsave(context,...)
Definition elog.h:262
#define errcontext
Definition elog.h:198
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
@ SFRM_Materialize_Random
Definition execnodes.h:344
@ SFRM_Materialize
Definition execnodes.h:343
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#define palloc0_object(type)
Definition fe_memutils.h:75
struct varlena * pg_detoast_datum_packed(struct varlena *datum)
Definition fmgr.c:1829
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition fmgr.c:138
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition fmgr.c:1585
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition fmgr.c:1875
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define DatumGetHeapTupleHeader(X)
Definition fmgr.h:296
#define DatumGetTextPP(X)
Definition fmgr.h:293
#define PG_ARGISNULL(n)
Definition fmgr.h:209
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:684
#define PG_NARGS()
Definition fmgr.h:203
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_GETARG_HEAPTUPLEHEADER(n)
Definition fmgr.h:313
#define PG_RETURN_TEXT_P(x)
Definition fmgr.h:374
#define PG_RETURN_INT32(x)
Definition fmgr.h:355
#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:354
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_GETARG_TEXT_P(n)
Definition fmgr.h:337
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition funcapi.c:76
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition funcapi.h:149
#define MAT_SRF_BLESS
Definition funcapi.h:297
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition funcapi.h:328
#define MAT_SRF_USE_EXPECTED_DESC
Definition funcapi.h:296
int work_mem
Definition globals.c:131
#define newval
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)
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
static void * GETSTRUCT(const HeapTupleData *tuple)
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
#define funcname
#define token
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
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition itemptr.h:184
void escape_json_text(StringInfo buf, const text *txt)
Definition json.c:1738
void escape_json_with_len(StringInfo buf, const char *str, int len)
Definition json.c:1633
void escape_json(StringInfo buf, const char *str)
Definition json.c:1604
JsonParseErrorType pg_parse_json(JsonLexContext *lex, const JsonSemAction *sem)
Definition jsonapi.c:744
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
Definition jsonapi.c:392
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition jsonapi.c:1588
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
Definition jsonapi.c:2404
JsonParseErrorType json_count_array_elements(JsonLexContext *lex, int *elements)
Definition jsonapi.c:803
void freeJsonLexContext(JsonLexContext *lex)
Definition jsonapi.c:687
JsonParseErrorType
Definition jsonapi.h:35
@ JSON_SEM_ACTION_FAILED
Definition jsonapi.h:59
@ JSON_UNICODE_CODE_POINT_ZERO
Definition jsonapi.h:53
@ JSON_SUCCESS
Definition jsonapi.h:36
@ JSON_UNICODE_UNTRANSLATABLE
Definition jsonapi.h:56
@ JSON_UNICODE_HIGH_ESCAPE
Definition jsonapi.h:55
JsonTokenType
Definition jsonapi.h:18
@ JSON_TOKEN_INVALID
Definition jsonapi.h:19
@ JSON_TOKEN_FALSE
Definition jsonapi.h:29
@ JSON_TOKEN_END
Definition jsonapi.h:31
@ JSON_TOKEN_TRUE
Definition jsonapi.h:28
@ JSON_TOKEN_NULL
Definition jsonapi.h:30
@ JSON_TOKEN_OBJECT_START
Definition jsonapi.h:22
@ JSON_TOKEN_NUMBER
Definition jsonapi.h:21
@ JSON_TOKEN_STRING
Definition jsonapi.h:20
@ JSON_TOKEN_ARRAY_START
Definition jsonapi.h:24
char * JsonbUnquote(Jsonb *jb)
Definition jsonb.c:2042
Datum jsonb_in(PG_FUNCTION_ARGS)
Definition jsonb.c:65
char * JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len)
Definition jsonb.c:466
char * JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
Definition jsonb.c:475
jbvType
Definition jsonb.h:228
@ jbvObject
Definition jsonb.h:236
@ jbvNumeric
Definition jsonb.h:232
@ jbvBool
Definition jsonb.h:233
@ jbvArray
Definition jsonb.h:235
@ jbvBinary
Definition jsonb.h:238
@ jbvNull
Definition jsonb.h:230
@ jbvString
Definition jsonb.h:231
#define JsonContainerIsScalar(jc)
Definition jsonb.h:209
#define JsonContainerIsArray(jc)
Definition jsonb.h:211
#define JsonContainerSize(jc)
Definition jsonb.h:208
#define JB_ROOT_IS_OBJECT(jbp_)
Definition jsonb.h:223
static Datum JsonbPGetDatum(const Jsonb *p)
Definition jsonb.h:413
#define IsAJsonbScalar(jsonbval)
Definition jsonb.h:299
#define PG_RETURN_JSONB_P(x)
Definition jsonb.h:420
#define JB_ROOT_IS_ARRAY(jbp_)
Definition jsonb.h:224
#define PG_GETARG_JSONB_P(x)
Definition jsonb.h:418
#define JsonContainerIsObject(jc)
Definition jsonb.h:210
static Jsonb * DatumGetJsonbP(Datum d)
Definition jsonb.h:401
#define JB_ROOT_IS_SCALAR(jbp_)
Definition jsonb.h:222
JsonbIteratorToken
Definition jsonb.h:21
@ WJB_KEY
Definition jsonb.h:23
@ WJB_DONE
Definition jsonb.h:22
@ WJB_END_ARRAY
Definition jsonb.h:27
@ WJB_VALUE
Definition jsonb.h:24
@ WJB_END_OBJECT
Definition jsonb.h:29
@ WJB_ELEM
Definition jsonb.h:25
@ WJB_BEGIN_OBJECT
Definition jsonb.h:28
@ WJB_BEGIN_ARRAY
Definition jsonb.h:26
#define JB_ROOT_COUNT(jbp_)
Definition jsonb.h:221
void pushJsonbValue(JsonbInState *pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition jsonb_util.c:583
JsonbValue * getKeyJsonValueFromContainer(JsonbContainer *container, const char *keyVal, int keyLen, JsonbValue *res)
Definition jsonb_util.c:402
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition jsonb_util.c:935
void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val)
Definition jsonb_util.c:76
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition jsonb_util.c:973
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition jsonb_util.c:472
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition jsonb_util.c:96
Datum jsonb_populate_recordset(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:3971
JsonLexContext * makeJsonLexContext(JsonLexContext *lex, text *json, bool need_escapes)
Definition jsonfuncs.c:540
static JsonParseErrorType get_array_element_end(void *state, bool isnull)
Definition jsonfuncs.c:1401
static Datum elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition jsonfuncs.c:2305
static JsonParseErrorType hash_array_start(void *state)
Definition jsonfuncs.c:3927
Datum jsonb_object_keys(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:568
static JsonParseErrorType populate_recordset_array_start(void *state)
Definition jsonfuncs.c:4280
static JsonParseErrorType transform_string_values_array_start(void *state)
Definition jsonfuncs.c:5871
static JsonParseErrorType get_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:1197
static JsonParseErrorType elements_object_start(void *state)
Definition jsonfuncs.c:2415
static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:5891
Datum jsonb_array_elements(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2205
static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:5748
static void IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, JsonbInState *state)
Definition jsonfuncs.c:5048
Datum json_each_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1959
static void push_path(JsonbInState *st, int level, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbValue *newval)
Definition jsonfuncs.c:1720
Datum json_populate_recordset(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:3985
static JsonParseErrorType populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:2750
text * transform_json_string_values(text *json, void *action_state, JsonTransformStringValuesAction transform_action)
Definition jsonfuncs.c:5815
Datum jsonb_delete(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4658
Datum json_populate_type(Datum json_val, Oid json_type, Oid typid, int32 typmod, void **cache, MemoryContext mcxt, bool *isnull, bool omit_quotes, Node *escontext)
Definition jsonfuncs.c:3342
Datum jsonb_delete_array(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4708
Datum jsonb_pretty(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4603
static void setPathArray(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, uint32 nelems, int op_type)
Definition jsonfuncs.c:5389
static JsonParseErrorType transform_string_values_array_end(void *state)
Definition jsonfuncs.c:5881
static JsonParseErrorType populate_recordset_object_start(void *state)
Definition jsonfuncs.c:4212
static RecordIOData * allocate_record_info(MemoryContext mcxt, int ncolumns)
Definition jsonfuncs.c:3473
static JsonParseErrorType iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:5720
static text * JsonbValueAsText(JsonbValue *v)
Definition jsonfuncs.c:1802
Datum jsonb_insert(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:5002
static JsonParseErrorType get_object_start(void *state)
Definition jsonfuncs.c:1160
static JsonParseErrorType populate_recordset_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:4304
static JsonParseErrorType populate_recordset_object_field_end(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:4327
static JsonParseErrorType populate_array_object_start(void *_state)
Definition jsonfuncs.c:2642
#define JsObjectIsEmpty(jso)
Definition jsonfuncs.c:329
static void get_record_type_from_argument(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition jsonfuncs.c:3633
Datum json_array_element(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:922
Datum jsonb_delete_idx(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4792
#define JB_PATH_DELETE
Definition jsonfuncs.c:45
static JsonParseErrorType sn_object_end(void *state)
Definition jsonfuncs.c:4397
#define JB_PATH_CREATE_OR_INSERT
Definition jsonfuncs.c:49
Datum jsonb_populate_record_valid(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2474
Datum json_array_elements_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2299
#define JB_PATH_CREATE
Definition jsonfuncs.c:44
static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:3940
static JsonParseErrorType sn_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:4457
static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg, Node *escontext)
Definition jsonfuncs.c:3696
static HTAB * get_json_object_as_hash(const char *json, int len, const char *funcname, Node *escontext)
Definition jsonfuncs.c:3808
static bool populate_array_json(PopulateArrayContext *ctx, const char *json, int len)
Definition jsonfuncs.c:2786
#define JsValueIsString(jsv)
Definition jsonfuncs.c:325
static JsonParseErrorType populate_recordset_object_end(void *state)
Definition jsonfuncs.c:4242
static Datum populate_record_field(ColumnIOData *col, Oid typid, int32 typmod, const char *colname, MemoryContext mcxt, Datum defaultval, JsValue *jsv, bool *isnull, Node *escontext, bool omit_scalar_quotes)
Definition jsonfuncs.c:3403
Datum jsonb_delete_path(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4962
static JsonParseErrorType each_object_field_end(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:2117
Datum jsonb_object_field_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:900
static Datum each_worker(FunctionCallInfo fcinfo, bool as_text)
Definition jsonfuncs.c:2055
static JsonParseErrorType get_array_start(void *state)
Definition jsonfuncs.c:1295
static JsonParseErrorType each_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:2179
static int report_json_context(JsonLexContext *lex)
Definition jsonfuncs.c:677
Datum json_strip_nulls(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4502
Datum json_array_elements(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2293
Datum jsonb_concat(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4620
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:5559
Datum jsonb_extract_path_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1494
Datum json_each(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1947
static JsonParseErrorType alen_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:1911
Datum jsonb_set_element(Jsonb *jb, const Datum *path, int path_len, JsonbValue *newval)
Definition jsonfuncs.c:1679
static JsonParseErrorType sn_object_start(void *state)
Definition jsonfuncs.c:4387
static JsonParseErrorType sn_array_start(void *state)
Definition jsonfuncs.c:4407
static bool populate_array_check_dimension(PopulateArrayContext *ctx, int ndim)
Definition jsonfuncs.c:2587
static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition jsonfuncs.c:1971
static JsonParseErrorType sn_array_end(void *state)
Definition jsonfuncs.c:4417
static void setPathObject(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, uint32 npairs, int op_type)
Definition jsonfuncs.c:5251
Datum json_to_recordset(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:3992
static JsonParseErrorType get_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:1445
#define JB_PATH_CONSISTENT_POSITION
Definition jsonfuncs.c:52
static bool populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims)
Definition jsonfuncs.c:2557
JsonTokenType json_get_first_token(text *json, bool throw_error)
Definition jsonfuncs.c:5937
Datum jsonb_set(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4853
#define JsValueIsNull(jsv)
Definition jsonfuncs.c:320
static void update_cached_tupdesc(CompositeIOData *io, MemoryContext mcxt)
Definition jsonfuncs.c:3026
struct ColumnIOData ColumnIOData
Definition jsonfuncs.c:162
void iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state, JsonIterateStringValuesAction action)
Definition jsonfuncs.c:5627
static JsonParseErrorType populate_array_element_end(void *_state, bool isnull)
Definition jsonfuncs.c:2707
Datum jsonb_set_lax(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4899
static JsonParseErrorType elements_array_element_end(void *state, bool isnull)
Definition jsonfuncs.c:2369
static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:4427
Datum jsonb_each_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1965
static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:2430
static JsonParseErrorType each_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:2095
Datum jsonb_strip_nulls(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:4539
Datum jsonb_extract_path(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1488
void json_categorize_type(Oid typoid, bool is_jsonb, JsonTypeCategory *tcategory, Oid *outfuncoid)
Definition jsonfuncs.c:5964
static Datum populate_array(ArrayIOData *aio, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext)
Definition jsonfuncs.c:2912
static JsonParseErrorType okeys_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:786
Datum jsonb_get_element(Jsonb *jb, const Datum *path, int npath, bool *isnull, bool as_text)
Definition jsonfuncs.c:1531
Datum json_array_length(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1849
void json_errsave_error(JsonParseErrorType error, JsonLexContext *lex, Node *escontext)
Definition jsonfuncs.c:641
Datum jsonb_array_length(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1875
Datum jsonb_object_field(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:862
static Datum elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
Definition jsonfuncs.c:2217
void iterate_json_values(text *json, uint32 flags, void *action_state, JsonIterateStringValuesAction action)
Definition jsonfuncs.c:5695
Datum jsonb_populate_record(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2461
Datum json_extract_path(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1009
static void push_null_elements(JsonbInState *ps, int num)
Definition jsonfuncs.c:1701
Datum json_extract_path_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1015
static JsonParseErrorType elements_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:2347
static void get_record_type_from_query(FunctionCallInfo fcinfo, const char *funcname, PopulateRecordCache *cache)
Definition jsonfuncs.c:3659
Datum json_populate_record(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2492
static JsonParseErrorType populate_recordset_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:4265
#define JB_PATH_FILL_GAPS
Definition jsonfuncs.c:51
Jsonb * transform_jsonb_string_values(Jsonb *jsonb, void *action_state, JsonTransformStringValuesAction transform_action)
Definition jsonfuncs.c:5769
static JsonParseErrorType transform_string_values_object_end(void *state)
Definition jsonfuncs.c:5861
static bool JsValueToJsObject(JsValue *jsv, JsObject *jso, Node *escontext)
Definition jsonfuncs.c:2979
Datum json_object_field(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:846
static JsonParseErrorType okeys_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:824
static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
Definition jsonfuncs.c:1500
static void populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim)
Definition jsonfuncs.c:2507
static JsonParseErrorType get_object_end(void *state)
Definition jsonfuncs.c:1179
static Datum populate_composite(CompositeIOData *io, Oid typid, const char *colname, MemoryContext mcxt, HeapTupleHeader defaultval, JsValue *jsv, bool *isnull, Node *escontext)
Definition jsonfuncs.c:3055
Datum jsonb_to_record(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2485
Datum jsonb_array_element(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:937
Datum json_object_keys(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:732
#define JB_PATH_INSERT_BEFORE
Definition jsonfuncs.c:47
static JsonParseErrorType populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:4287
static JsonParseErrorType get_object_field_end(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:1244
bool pg_parse_json_or_errsave(JsonLexContext *lex, const JsonSemAction *sem, Node *escontext)
Definition jsonfuncs.c:519
static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text)
Definition jsonfuncs.c:1024
static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, bool is_json, bool have_record_arg)
Definition jsonfuncs.c:4038
static HeapTupleHeader populate_record(TupleDesc tupdesc, RecordIOData **record_p, HeapTupleHeader defaultval, MemoryContext mcxt, JsObject *obj, Node *escontext)
Definition jsonfuncs.c:3517
static void setPath(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbInState *st, int level, JsonbValue *newval, int op_type)
Definition jsonfuncs.c:5173
static JsonParseErrorType alen_object_start(void *state)
Definition jsonfuncs.c:1897
static bool JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
Definition jsonfuncs.c:3489
static bool populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv)
Definition jsonfuncs.c:2615
static JsonParseErrorType populate_array_element_start(void *_state, bool isnull)
Definition jsonfuncs.c:2689
static JsonParseErrorType populate_array_array_end(void *_state)
Definition jsonfuncs.c:2665
static void prepare_column_cache(ColumnIOData *column, Oid typid, int32 typmod, MemoryContext mcxt, bool need_scalar)
Definition jsonfuncs.c:3248
static JsonParseErrorType get_array_end(void *state)
Definition jsonfuncs.c:1335
Datum jsonb_to_recordset(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:3978
static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:4479
#define JB_PATH_INSERT_AFTER
Definition jsonfuncs.c:48
Datum jsonb_each(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:1953
static JsonParseErrorType get_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:1353
static JsonParseErrorType hash_object_field_end(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:3876
#define JB_PATH_REPLACE
Definition jsonfuncs.c:46
static void populate_recordset_record(PopulateRecordsetState *state, JsObject *obj)
Definition jsonfuncs.c:3999
#define JsObjectFree(jso)
Definition jsonfuncs.c:335
static JsonParseErrorType transform_string_values_object_start(void *state)
Definition jsonfuncs.c:5851
static JsonParseErrorType transform_string_values_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:5909
static JsonParseErrorType alen_array_element_start(void *state, bool isnull)
Definition jsonfuncs.c:1925
static Datum populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv, bool *isnull, Node *escontext, bool omit_quotes)
Definition jsonfuncs.c:3122
static bool populate_array_dim_jsonb(PopulateArrayContext *ctx, JsonbValue *jbv, int ndim)
Definition jsonfuncs.c:2822
Datum jsonb_array_element_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:980
TypeCat
Definition jsonfuncs.c:200
@ TYPECAT_COMPOSITE
Definition jsonfuncs.c:203
@ TYPECAT_SCALAR
Definition jsonfuncs.c:201
@ TYPECAT_COMPOSITE_DOMAIN
Definition jsonfuncs.c:204
@ TYPECAT_DOMAIN
Definition jsonfuncs.c:205
@ TYPECAT_ARRAY
Definition jsonfuncs.c:202
Datum json_to_record(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2499
static JsonParseErrorType each_array_start(void *state)
Definition jsonfuncs.c:2165
Datum json_array_element_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:965
static Datum populate_domain(DomainIOData *io, Oid typid, const char *colname, MemoryContext mcxt, JsValue *jsv, bool *isnull, Node *escontext, bool omit_quotes)
Definition jsonfuncs.c:3214
static JsonParseErrorType transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype)
Definition jsonfuncs.c:5920
static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull)
Definition jsonfuncs.c:3850
Datum jsonb_array_elements_text(PG_FUNCTION_ARGS)
Definition jsonfuncs.c:2211
static text * get_worker(text *json, char **tpath, int *ipath, int npath, bool normalize_results)
Definition jsonfuncs.c:1103
#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:2909
bool type_is_rowtype(Oid typid)
Definition lsyscache.c:2805
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition lsyscache.c:3057
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition lsyscache.c:3024
char get_typtype(Oid typid)
Definition lsyscache.c:2779
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition lsyscache.c:2688
Oid getBaseType(Oid typid)
Definition lsyscache.c:2671
int GetDatabaseEncoding(void)
Definition mbutils.c:1264
int pg_mblen(const char *mbstr)
Definition mbutils.c:1026
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
char * pstrdup(const char *in)
Definition mcxt.c:1781
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
char * pnstrdup(const char *in, Size len)
Definition mcxt.c:1792
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define SOFT_ERROR_OCCURRED(escontext)
Definition miscnodes.h:53
#define IsA(nodeptr, _type_)
Definition nodes.h:164
static Datum NumericGetDatum(Numeric X)
Definition numeric.h:76
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, Oid *funcid)
CoercionPathType
@ COERCION_PATH_FUNC
FormData_pg_attribute * Form_pg_attribute
#define NAMEDATALEN
const void size_t len
const void * data
static char buf[DEFAULT_XLOG_SEG_SIZE]
FormData_pg_type * Form_pg_type
Definition pg_type.h:261
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
static char * DatumGetCString(Datum X)
Definition postgres.h:365
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342
static Datum CStringGetDatum(const char *X)
Definition postgres.h:380
#define InvalidOid
unsigned int Oid
char * c
static int fb(int x)
@ COERCION_EXPLICIT
Definition primnodes.h:749
tree ctl
Definition radixtree.h:1838
static chr element(struct vars *v, const chr *startp, const chr *endp)
static void error(void)
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
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
JsonLexContext * lex
Definition jsonfuncs.c:104
int32 element_typmod
Definition jsonfuncs.c:170
ColumnIOData * element_info
Definition jsonfuncs.c:168
Oid element_type
Definition jsonfuncs.c:169
CompositeIOData composite
Definition jsonfuncs.c:221
TypeCat typcat
Definition jsonfuncs.c:215
union ColumnIOData::@26 io
ScalarIOData scalar_io
Definition jsonfuncs.c:216
ArrayIOData array
Definition jsonfuncs.c:220
DomainIOData domain
Definition jsonfuncs.c:222
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
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
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
MemoryContext ecxt_per_query_memory
Definition execnodes.h:282
void * fn_extra
Definition fmgr.h:64
MemoryContext fn_mcxt
Definition fmgr.h:65
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
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
char * saved_scalar
Definition jsonfuncs.c:141
const char * save_json_start
Definition jsonfuncs.c:142
const char * function_name
Definition jsonfuncs.c:139
JsonTokenType saved_token_type
Definition jsonfuncs.c:143
JsonLexContext * lex
Definition jsonfuncs.c:138
HTAB * hash
Definition jsonfuncs.c:140
bool is_json
Definition jsonfuncs.c:311
JsonbContainer * jsonb_cont
Definition jsonfuncs.c:315
HTAB * json_hash
Definition jsonfuncs.c:314
union JsObject::@29 val
const char * str
Definition jsonfuncs.c:300
union JsValue::@27 val
JsonbValue * jsonb
Definition jsonfuncs.c:305
int len
Definition jsonfuncs.c:301
JsonTokenType type
Definition jsonfuncs.c:302
struct JsValue::@27::@28 json
bool is_json
Definition jsonfuncs.c:295
char fname[NAMEDATALEN]
Definition jsonfuncs.c:149
JsonTokenType type
Definition jsonfuncs.c:151
const char * input
Definition jsonapi.h:102
size_t input_length
Definition jsonapi.h:103
const char * line_start
Definition jsonapi.h:113
JsonTokenType token_type
Definition jsonapi.h:109
const char * token_terminator
Definition jsonapi.h:106
json_struct_action array_end
Definition jsonapi.h:157
json_struct_action object_start
Definition jsonapi.h:154
json_ofield_action object_field_start
Definition jsonapi.h:158
json_aelem_action array_element_start
Definition jsonapi.h:160
json_scalar_action scalar
Definition jsonapi.h:162
void * semstate
Definition jsonapi.h:153
json_aelem_action array_element_end
Definition jsonapi.h:161
json_struct_action array_start
Definition jsonapi.h:156
json_struct_action object_end
Definition jsonapi.h:155
json_ofield_action object_field_end
Definition jsonapi.h:159
JsonbValue * result
Definition jsonb.h:333
enum jbvType type
Definition jsonb.h:257
char * val
Definition jsonb.h:266
Definition jsonb.h:215
JsonbContainer root
Definition jsonb.h:217
Definition nodes.h:135
int result_size
Definition jsonfuncs.c:59
char ** result
Definition jsonfuncs.c:58
int result_count
Definition jsonfuncs.c:60
int sent_count
Definition jsonfuncs.c:61
JsonLexContext * lex
Definition jsonfuncs.c:57
ArrayBuildState * astate
Definition jsonfuncs.c:261
MemoryContext mcxt
Definition jsonfuncs.c:264
ArrayIOData * aio
Definition jsonfuncs.c:262
MemoryContext acxt
Definition jsonfuncs.c:263
const char * colname
Definition jsonfuncs.c:265
JsonTokenType element_type
Definition jsonfuncs.c:280
JsonLexContext * lex
Definition jsonfuncs.c:275
PopulateArrayContext * ctx
Definition jsonfuncs.c:276
const char * element_start
Definition jsonfuncs.c:277
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
int32 record_typmod
Definition hstore_io.c:825
SetFunctionReturnMode returnMode
Definition execnodes.h:362
ExprContext * econtext
Definition execnodes.h:358
TupleDesc setDesc
Definition execnodes.h:366
Tuplestorestate * setResult
Definition execnodes.h:365
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
Definition type.h:96
Definition c.h:706
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220
static JsonSemAction sem
#define FirstNormalObjectId
Definition transam.h:197
void FreeTupleDesc(TupleDesc tupdesc)
Definition tupdesc.c:502
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition tupdesc.c:252
#define ReleaseTupleDesc(tupdesc)
Definition tupdesc.h:219
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:160
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition tuplestore.c:330
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition tuplestore.c:784
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition tuplestore.c:764
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition typcache.c:1921
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static Size VARSIZE(const void *PTR)
Definition varatt.h:298
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486
text * cstring_to_text_with_len(const char *s, int len)
Definition varlena.c:193
text * cstring_to_text(const char *s)
Definition varlena.c:181
char * text_to_cstring(const text *t)
Definition varlena.c:214
const char * type