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