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