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