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