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