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