TLA 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 GNC 16488 : pg_parse_json_or_errsave(JsonLexContext *lex, JsonSemAction *sem,
508 : Node *escontext)
509 : {
510 : JsonParseErrorType result;
511 :
512 GIC 16488 : result = pg_parse_json(lex, sem);
513 16392 : if (result != JSON_SUCCESS)
514 : {
515 GNC 228 : json_errsave_error(result, lex, escontext);
516 15 : return false;
517 : }
518 16164 : return true;
519 : }
520 :
521 : /*
522 : * makeJsonLexContext
523 ECB : *
524 : * This is like makeJsonLexContextCstringLen, but it accepts a text value
525 : * directly.
526 : */
527 : JsonLexContext *
528 GIC 5280 : makeJsonLexContext(text *json, bool need_escapes)
529 ECB : {
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 GIC 5280 : json = pg_detoast_datum_packed(json);
535 :
536 10560 : return makeJsonLexContextCstringLen(VARDATA_ANY(json),
537 5280 : VARSIZE_ANY_EXHDR(json),
538 : GetDatabaseEncoding(),
539 ECB : 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 GIC 27 : jsonb_object_keys(PG_FUNCTION_ARGS)
556 : {
557 : FuncCallContext *funcctx;
558 : OkeysState *state;
559 :
560 27 : if (SRF_IS_FIRSTCALL())
561 : {
562 : MemoryContext oldcontext;
563 9 : Jsonb *jb = PG_GETARG_JSONB_P(0);
564 9 : bool skipNested = false;
565 : JsonbIterator *it;
566 ECB : JsonbValue v;
567 : JsonbIteratorToken r;
568 :
569 GIC 9 : if (JB_ROOT_IS_SCALAR(jb))
570 3 : ereport(ERROR,
571 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
572 : errmsg("cannot call %s on a scalar",
573 : "jsonb_object_keys")));
574 CBC 6 : else if (JB_ROOT_IS_ARRAY(jb))
575 3 : ereport(ERROR,
576 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
577 : errmsg("cannot call %s on an array",
578 : "jsonb_object_keys")));
579 :
580 3 : funcctx = SRF_FIRSTCALL_INIT();
581 3 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
582 :
583 GIC 3 : state = palloc(sizeof(OkeysState));
584 :
585 CBC 3 : state->result_size = JB_ROOT_COUNT(jb);
586 3 : state->result_count = 0;
587 GIC 3 : state->sent_count = 0;
588 3 : state->result = palloc(state->result_size * sizeof(char *));
589 :
590 3 : it = JsonbIteratorInit(&jb->root);
591 ECB :
592 CBC 45 : while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
593 : {
594 42 : skipNested = true;
595 :
596 42 : if (r == WJB_KEY)
597 ECB : {
598 : char *cstr;
599 :
600 GIC 18 : cstr = palloc(v.val.string.len + 1 * sizeof(char));
601 CBC 18 : memcpy(cstr, v.val.string.val, v.val.string.len);
602 GIC 18 : cstr[v.val.string.len] = '\0';
603 CBC 18 : state->result[state->result_count++] = cstr;
604 : }
605 ECB : }
606 :
607 CBC 3 : MemoryContextSwitchTo(oldcontext);
608 GIC 3 : funcctx->user_fctx = (void *) state;
609 : }
610 :
611 CBC 21 : funcctx = SRF_PERCALL_SETUP();
612 21 : state = (OkeysState *) funcctx->user_fctx;
613 ECB :
614 CBC 21 : if (state->sent_count < state->result_count)
615 : {
616 GIC 18 : char *nxt = state->result[state->sent_count++];
617 :
618 CBC 18 : SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(nxt));
619 ECB : }
620 :
621 GIC 3 : SRF_RETURN_DONE(funcctx);
622 ECB : }
623 :
624 : /*
625 : * Report a JSON error.
626 : */
627 : void
628 GNC 228 : json_errsave_error(JsonParseErrorType error, JsonLexContext *lex,
629 : Node *escontext)
630 ECB : {
631 GIC 228 : if (error == JSON_UNICODE_HIGH_ESCAPE ||
632 GNC 228 : error == JSON_UNICODE_UNTRANSLATABLE ||
633 : error == JSON_UNICODE_CODE_POINT_ZERO)
634 12 : 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 216 : else if (error == JSON_SEM_ACTION_FAILED)
640 : {
641 : /* semantic action function had better have reported something */
642 3 : if (!SOFT_ERROR_OCCURRED(escontext))
643 UNC 0 : elog(ERROR, "JSON semantic action function did not provide error information");
644 : }
645 : else
646 GNC 213 : errsave(escontext,
647 ECB : (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 CBC 15 : }
652 :
653 ECB : /*
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 EUB : */
663 : static int
664 GIC 219 : report_json_context(JsonLexContext *lex)
665 ECB : {
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 GIC 219 : line_start = lex->line_start;
676 219 : context_start = line_start;
677 219 : context_end = lex->token_terminator;
678 219 : Assert(context_end >= context_start);
679 :
680 : /* Advance until we are close enough to context_end */
681 285 : while (context_end - context_start >= 50)
682 : {
683 ECB : /* Advance to next multibyte character */
684 GIC 66 : if (IS_HIGHBIT_SET(*context_start))
685 UIC 0 : context_start += pg_mblen(context_start);
686 : else
687 GIC 66 : 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 ECB : */
695 CBC 219 : if (context_start - line_start <= 3)
696 213 : context_start = line_start;
697 ECB :
698 : /* Get a null-terminated copy of the data to present */
699 GIC 219 : ctxtlen = context_end - context_start;
700 CBC 219 : ctxt = palloc(ctxtlen + 1);
701 GIC 219 : memcpy(ctxt, context_start, ctxtlen);
702 219 : ctxt[ctxtlen] = '\0';
703 ECB :
704 EUB : /*
705 : * Show the context, prefixing "..." if not starting at start of line, and
706 ECB : * suffixing "..." if not ending at end of line.
707 : */
708 GIC 219 : prefix = (context_start > line_start) ? "..." : "";
709 627 : suffix = (lex->token_type != JSON_TOKEN_END &&
710 189 : context_end - lex->input < lex->input_length &&
711 408 : *context_end != '\n' && *context_end != '\r') ? "..." : "";
712 :
713 219 : return errcontext("JSON data, line %d: %s%s%s",
714 ECB : lex->line_number, prefix, ctxt, suffix);
715 : }
716 :
717 :
718 : Datum
719 CBC 930 : json_object_keys(PG_FUNCTION_ARGS)
720 ECB : {
721 : FuncCallContext *funcctx;
722 : OkeysState *state;
723 :
724 GIC 930 : if (SRF_IS_FIRSTCALL())
725 : {
726 12 : text *json = PG_GETARG_TEXT_PP(0);
727 CBC 12 : JsonLexContext *lex = makeJsonLexContext(json, true);
728 ECB : JsonSemAction *sem;
729 : MemoryContext oldcontext;
730 :
731 GIC 12 : funcctx = SRF_FIRSTCALL_INIT();
732 CBC 12 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
733 :
734 GIC 12 : state = palloc(sizeof(OkeysState));
735 12 : sem = palloc0(sizeof(JsonSemAction));
736 :
737 12 : state->lex = lex;
738 CBC 12 : state->result_size = 256;
739 GIC 12 : state->result_count = 0;
740 12 : state->sent_count = 0;
741 12 : state->result = palloc(256 * sizeof(char *));
742 :
743 CBC 12 : sem->semstate = (void *) state;
744 GIC 12 : sem->array_start = okeys_array_start;
745 CBC 12 : sem->scalar = okeys_scalar;
746 12 : sem->object_field_start = okeys_object_field_start;
747 : /* remainder are all NULL, courtesy of palloc0 above */
748 :
749 GIC 12 : pg_parse_json_or_ereport(lex, sem);
750 ECB : /* keys are now in state->result */
751 :
752 GIC 6 : pfree(lex->strval->data);
753 CBC 6 : pfree(lex->strval);
754 6 : pfree(lex);
755 GIC 6 : pfree(sem);
756 ECB :
757 CBC 6 : MemoryContextSwitchTo(oldcontext);
758 6 : funcctx->user_fctx = (void *) state;
759 ECB : }
760 :
761 GIC 924 : funcctx = SRF_PERCALL_SETUP();
762 CBC 924 : state = (OkeysState *) funcctx->user_fctx;
763 ECB :
764 CBC 924 : if (state->sent_count < state->result_count)
765 ECB : {
766 GIC 918 : char *nxt = state->result[state->sent_count++];
767 :
768 CBC 918 : SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(nxt));
769 : }
770 :
771 6 : SRF_RETURN_DONE(funcctx);
772 ECB : }
773 :
774 : static JsonParseErrorType
775 GIC 921 : okeys_object_field_start(void *state, char *fname, bool isnull)
776 ECB : {
777 CBC 921 : OkeysState *_state = (OkeysState *) state;
778 :
779 : /* only collecting keys for the top level object */
780 921 : if (_state->lex->lex_level != 1)
781 GNC 3 : return JSON_SUCCESS;
782 :
783 ECB : /* enlarge result array if necessary */
784 GIC 918 : if (_state->result_count >= _state->result_size)
785 ECB : {
786 GIC 3 : _state->result_size *= 2;
787 CBC 3 : _state->result = (char **)
788 GIC 3 : repalloc(_state->result, sizeof(char *) * _state->result_size);
789 : }
790 ECB :
791 : /* save a copy of the field name */
792 GIC 918 : _state->result[_state->result_count++] = pstrdup(fname);
793 :
794 GNC 918 : return JSON_SUCCESS;
795 : }
796 ECB :
797 : static JsonParseErrorType
798 CBC 6 : okeys_array_start(void *state)
799 : {
800 GIC 6 : OkeysState *_state = (OkeysState *) state;
801 ECB :
802 : /* top level must be a json object */
803 GIC 6 : if (_state->lex->lex_level == 0)
804 3 : ereport(ERROR,
805 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
806 : errmsg("cannot call %s on an array",
807 : "json_object_keys")));
808 :
809 GNC 3 : return JSON_SUCCESS;
810 ECB : }
811 :
812 : static JsonParseErrorType
813 GIC 927 : okeys_scalar(void *state, char *token, JsonTokenType tokentype)
814 : {
815 CBC 927 : OkeysState *_state = (OkeysState *) state;
816 :
817 ECB : /* top level must be a json object */
818 GIC 927 : if (_state->lex->lex_level == 0)
819 3 : ereport(ERROR,
820 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
821 ECB : errmsg("cannot call %s on a scalar",
822 : "json_object_keys")));
823 :
824 GNC 924 : return JSON_SUCCESS;
825 ECB : }
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 GIC 490 : json_object_field(PG_FUNCTION_ARGS)
836 : {
837 490 : text *json = PG_GETARG_TEXT_PP(0);
838 CBC 490 : text *fname = PG_GETARG_TEXT_PP(1);
839 GIC 490 : char *fnamestr = text_to_cstring(fname);
840 ECB : text *result;
841 :
842 GIC 490 : result = get_worker(json, &fnamestr, NULL, 1, false);
843 ECB :
844 CBC 478 : if (result != NULL)
845 GIC 391 : PG_RETURN_TEXT_P(result);
846 : else
847 87 : PG_RETURN_NULL();
848 : }
849 ECB :
850 : Datum
851 GIC 12345 : jsonb_object_field(PG_FUNCTION_ARGS)
852 : {
853 12345 : Jsonb *jb = PG_GETARG_JSONB_P(0);
854 12345 : text *key = PG_GETARG_TEXT_PP(1);
855 : JsonbValue *v;
856 : JsonbValue vbuf;
857 :
858 12345 : if (!JB_ROOT_IS_OBJECT(jb))
859 12 : PG_RETURN_NULL();
860 ECB :
861 GIC 24666 : v = getKeyJsonValueFromContainer(&jb->root,
862 CBC 12333 : VARDATA_ANY(key),
863 12333 : VARSIZE_ANY_EXHDR(key),
864 ECB : &vbuf);
865 :
866 GIC 12333 : if (v != NULL)
867 CBC 216 : PG_RETURN_JSONB_P(JsonbValueToJsonb(v));
868 :
869 12117 : PG_RETURN_NULL();
870 ECB : }
871 :
872 : Datum
873 GIC 462 : json_object_field_text(PG_FUNCTION_ARGS)
874 : {
875 462 : text *json = PG_GETARG_TEXT_PP(0);
876 CBC 462 : text *fname = PG_GETARG_TEXT_PP(1);
877 GIC 462 : char *fnamestr = text_to_cstring(fname);
878 ECB : text *result;
879 :
880 GIC 462 : result = get_worker(json, &fnamestr, NULL, 1, true);
881 :
882 459 : if (result != NULL)
883 CBC 441 : PG_RETURN_TEXT_P(result);
884 ECB : else
885 GIC 18 : PG_RETURN_NULL();
886 ECB : }
887 :
888 : Datum
889 GIC 99 : jsonb_object_field_text(PG_FUNCTION_ARGS)
890 : {
891 CBC 99 : Jsonb *jb = PG_GETARG_JSONB_P(0);
892 99 : text *key = PG_GETARG_TEXT_PP(1);
893 : JsonbValue *v;
894 ECB : JsonbValue vbuf;
895 :
896 GIC 99 : if (!JB_ROOT_IS_OBJECT(jb))
897 12 : PG_RETURN_NULL();
898 ECB :
899 GIC 174 : v = getKeyJsonValueFromContainer(&jb->root,
900 CBC 87 : VARDATA_ANY(key),
901 87 : VARSIZE_ANY_EXHDR(key),
902 ECB : &vbuf);
903 :
904 GIC 87 : if (v != NULL && v->type != jbvNull)
905 CBC 72 : PG_RETURN_TEXT_P(JsonbValueAsText(v));
906 :
907 15 : PG_RETURN_NULL();
908 ECB : }
909 :
910 : Datum
911 GIC 140 : json_array_element(PG_FUNCTION_ARGS)
912 : {
913 140 : text *json = PG_GETARG_TEXT_PP(0);
914 CBC 140 : int element = PG_GETARG_INT32(1);
915 : text *result;
916 ECB :
917 CBC 140 : result = get_worker(json, NULL, &element, 1, false);
918 :
919 GIC 140 : if (result != NULL)
920 122 : PG_RETURN_TEXT_P(result);
921 ECB : else
922 CBC 18 : PG_RETURN_NULL();
923 : }
924 ECB :
925 : Datum
926 CBC 159 : jsonb_array_element(PG_FUNCTION_ARGS)
927 : {
928 GIC 159 : Jsonb *jb = PG_GETARG_JSONB_P(0);
929 CBC 159 : int element = PG_GETARG_INT32(1);
930 ECB : JsonbValue *v;
931 :
932 CBC 159 : if (!JB_ROOT_IS_ARRAY(jb))
933 GIC 9 : PG_RETURN_NULL();
934 :
935 : /* Handle negative subscript */
936 CBC 150 : if (element < 0)
937 : {
938 9 : uint32 nelements = JB_ROOT_COUNT(jb);
939 ECB :
940 GIC 9 : if (-element > nelements)
941 3 : PG_RETURN_NULL();
942 ECB : else
943 GIC 6 : element += nelements;
944 ECB : }
945 :
946 GIC 147 : v = getIthJsonbValueFromContainer(&jb->root, element);
947 CBC 147 : if (v != NULL)
948 GIC 132 : PG_RETURN_JSONB_P(JsonbValueToJsonb(v));
949 :
950 15 : PG_RETURN_NULL();
951 ECB : }
952 :
953 : Datum
954 CBC 24 : json_array_element_text(PG_FUNCTION_ARGS)
955 : {
956 GIC 24 : text *json = PG_GETARG_TEXT_PP(0);
957 CBC 24 : int element = PG_GETARG_INT32(1);
958 ECB : text *result;
959 :
960 GIC 24 : result = get_worker(json, NULL, &element, 1, true);
961 ECB :
962 GIC 24 : if (result != NULL)
963 CBC 12 : PG_RETURN_TEXT_P(result);
964 : else
965 12 : PG_RETURN_NULL();
966 ECB : }
967 :
968 : Datum
969 GIC 30 : jsonb_array_element_text(PG_FUNCTION_ARGS)
970 : {
971 CBC 30 : Jsonb *jb = PG_GETARG_JSONB_P(0);
972 30 : int element = PG_GETARG_INT32(1);
973 ECB : JsonbValue *v;
974 :
975 CBC 30 : if (!JB_ROOT_IS_ARRAY(jb))
976 GIC 6 : PG_RETURN_NULL();
977 :
978 : /* Handle negative subscript */
979 CBC 24 : if (element < 0)
980 : {
981 LBC 0 : uint32 nelements = JB_ROOT_COUNT(jb);
982 ECB :
983 UIC 0 : if (-element > nelements)
984 0 : PG_RETURN_NULL();
985 ECB : else
986 UIC 0 : element += nelements;
987 ECB : }
988 :
989 GIC 24 : v = getIthJsonbValueFromContainer(&jb->root, element);
990 ECB :
991 GIC 24 : if (v != NULL && v->type != jbvNull)
992 12 : PG_RETURN_TEXT_P(JsonbValueAsText(v));
993 :
994 CBC 12 : PG_RETURN_NULL();
995 : }
996 ECB :
997 : Datum
998 GIC 144 : json_extract_path(PG_FUNCTION_ARGS)
999 : {
1000 CBC 144 : return get_path_all(fcinfo, false);
1001 ECB : }
1002 :
1003 : Datum
1004 CBC 90 : json_extract_path_text(PG_FUNCTION_ARGS)
1005 : {
1006 GBC 90 : return get_path_all(fcinfo, true);
1007 : }
1008 EUB :
1009 : /*
1010 : * common routine for extract_path functions
1011 : */
1012 : static Datum
1013 GIC 234 : get_path_all(FunctionCallInfo fcinfo, bool as_text)
1014 ECB : {
1015 GIC 234 : text *json = PG_GETARG_TEXT_PP(0);
1016 CBC 234 : ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
1017 ECB : 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 GIC 234 : if (array_contains_nulls(path))
1033 6 : PG_RETURN_NULL();
1034 :
1035 GNC 228 : deconstruct_array_builtin(path, TEXTOID, &pathtext, &pathnulls, &npath);
1036 :
1037 CBC 228 : tpath = palloc(npath * sizeof(char *));
1038 GIC 228 : ipath = palloc(npath * sizeof(int));
1039 ECB :
1040 CBC 624 : for (i = 0; i < npath; i++)
1041 : {
1042 GIC 396 : Assert(!pathnulls[i]);
1043 396 : 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 396 : if (*tpath[i] != '\0')
1051 : {
1052 : int ind;
1053 : char *endptr;
1054 :
1055 390 : errno = 0;
1056 CBC 390 : ind = strtoint(tpath[i], &endptr, 10);
1057 390 : if (endptr == tpath[i] || *endptr != '\0' || errno != 0)
1058 GIC 282 : ipath[i] = INT_MIN;
1059 ECB : else
1060 GIC 108 : ipath[i] = ind;
1061 ECB : }
1062 : else
1063 GIC 6 : ipath[i] = INT_MIN;
1064 ECB : }
1065 :
1066 CBC 228 : result = get_worker(json, tpath, ipath, npath, as_text);
1067 ECB :
1068 GIC 228 : if (result != NULL)
1069 168 : PG_RETURN_TEXT_P(result);
1070 : else
1071 60 : PG_RETURN_NULL();
1072 : }
1073 :
1074 ECB : /*
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 CBC 1344 : get_worker(text *json,
1093 ECB : char **tpath,
1094 : int *ipath,
1095 : int npath,
1096 : bool normalize_results)
1097 : {
1098 GIC 1344 : JsonLexContext *lex = makeJsonLexContext(json, true);
1099 1344 : JsonSemAction *sem = palloc0(sizeof(JsonSemAction));
1100 1344 : GetState *state = palloc0(sizeof(GetState));
1101 :
1102 1344 : Assert(npath >= 0);
1103 :
1104 1344 : state->lex = lex;
1105 : /* is it "_as_text" variant? */
1106 1344 : state->normalize_results = normalize_results;
1107 1344 : state->npath = npath;
1108 1344 : state->path_names = tpath;
1109 1344 : state->path_indexes = ipath;
1110 1344 : state->pathok = palloc0(sizeof(bool) * npath);
1111 1344 : state->array_cur_index = palloc(sizeof(int) * npath);
1112 :
1113 1344 : if (npath > 0)
1114 1314 : state->pathok[0] = true;
1115 :
1116 CBC 1344 : 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 1344 : sem->scalar = get_scalar;
1123 1344 : if (npath == 0)
1124 ECB : {
1125 GIC 30 : sem->object_start = get_object_start;
1126 CBC 30 : sem->object_end = get_object_end;
1127 GIC 30 : sem->array_start = get_array_start;
1128 CBC 30 : sem->array_end = get_array_end;
1129 : }
1130 1344 : if (tpath != NULL)
1131 ECB : {
1132 CBC 1180 : sem->object_field_start = get_object_field_start;
1133 1180 : sem->object_field_end = get_object_field_end;
1134 ECB : }
1135 CBC 1344 : if (ipath != NULL)
1136 : {
1137 392 : sem->array_start = get_array_start;
1138 392 : sem->array_element_start = get_array_element_start;
1139 GIC 392 : sem->array_element_end = get_array_element_end;
1140 ECB : }
1141 :
1142 GIC 1344 : pg_parse_json_or_ereport(lex, sem);
1143 :
1144 1329 : return state->tresult;
1145 : }
1146 ECB :
1147 : static JsonParseErrorType
1148 GIC 18 : get_object_start(void *state)
1149 ECB : {
1150 CBC 18 : GetState *_state = (GetState *) state;
1151 18 : int lex_level = _state->lex->lex_level;
1152 ECB :
1153 GIC 18 : if (lex_level == 0 && _state->npath == 0)
1154 ECB : {
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 GIC 6 : _state->result_start = _state->lex->token_start;
1161 ECB : }
1162 :
1163 GNC 18 : return JSON_SUCCESS;
1164 ECB : }
1165 :
1166 : static JsonParseErrorType
1167 GIC 18 : get_object_end(void *state)
1168 ECB : {
1169 GIC 18 : GetState *_state = (GetState *) state;
1170 CBC 18 : int lex_level = _state->lex->lex_level;
1171 :
1172 GIC 18 : if (lex_level == 0 && _state->npath == 0)
1173 : {
1174 ECB : /* Special case: return the entire object */
1175 GIC 6 : char *start = _state->result_start;
1176 CBC 6 : int len = _state->lex->prev_token_terminator - start;
1177 ECB :
1178 GIC 6 : _state->tresult = cstring_to_text_with_len(start, len);
1179 ECB : }
1180 :
1181 GNC 18 : return JSON_SUCCESS;
1182 : }
1183 :
1184 : static JsonParseErrorType
1185 GIC 53456 : get_object_field_start(void *state, char *fname, bool isnull)
1186 : {
1187 53456 : GetState *_state = (GetState *) state;
1188 CBC 53456 : bool get_next = false;
1189 GIC 53456 : int lex_level = _state->lex->lex_level;
1190 :
1191 CBC 53456 : if (lex_level <= _state->npath &&
1192 GIC 14069 : _state->pathok[lex_level - 1] &&
1193 13949 : _state->path_names != NULL &&
1194 13949 : _state->path_names[lex_level - 1] != NULL &&
1195 CBC 13949 : strcmp(fname, _state->path_names[lex_level - 1]) == 0)
1196 : {
1197 1066 : if (lex_level < _state->npath)
1198 ECB : {
1199 : /* if not at end of path just mark path ok */
1200 CBC 108 : _state->pathok[lex_level] = true;
1201 : }
1202 : else
1203 ECB : {
1204 : /* end of path, so we want this value */
1205 GIC 958 : get_next = true;
1206 ECB : }
1207 : }
1208 :
1209 CBC 53456 : if (get_next)
1210 : {
1211 : /* this object overrides any previous matching object */
1212 GIC 958 : _state->tresult = NULL;
1213 CBC 958 : _state->result_start = NULL;
1214 :
1215 958 : if (_state->normalize_results &&
1216 480 : _state->lex->token_type == JSON_TOKEN_STRING)
1217 ECB : {
1218 : /* for as_text variants, tell get_scalar to set it for us */
1219 CBC 339 : _state->next_scalar = true;
1220 ECB : }
1221 : else
1222 : {
1223 : /* for non-as_text variants, just note the json starting point */
1224 GIC 619 : _state->result_start = _state->lex->token_start;
1225 ECB : }
1226 : }
1227 :
1228 GNC 53456 : return JSON_SUCCESS;
1229 : }
1230 ECB :
1231 : static JsonParseErrorType
1232 GIC 53456 : get_object_field_end(void *state, char *fname, bool isnull)
1233 : {
1234 53456 : GetState *_state = (GetState *) state;
1235 CBC 53456 : bool get_last = false;
1236 GIC 53456 : int lex_level = _state->lex->lex_level;
1237 :
1238 : /* same tests as in get_object_field_start */
1239 CBC 53456 : if (lex_level <= _state->npath &&
1240 GIC 14069 : _state->pathok[lex_level - 1] &&
1241 13949 : _state->path_names != NULL &&
1242 CBC 13949 : _state->path_names[lex_level - 1] != NULL &&
1243 13949 : strcmp(fname, _state->path_names[lex_level - 1]) == 0)
1244 : {
1245 1066 : if (lex_level < _state->npath)
1246 ECB : {
1247 : /* done with this field so reset pathok */
1248 GIC 108 : _state->pathok[lex_level] = false;
1249 ECB : }
1250 : else
1251 : {
1252 : /* end of path, so we want this value */
1253 GIC 958 : get_last = true;
1254 ECB : }
1255 : }
1256 :
1257 : /* for as_text scalar case, our work is already done */
1258 CBC 53456 : if (get_last && _state->result_start != NULL)
1259 : {
1260 : /*
1261 : * make a text object from the string from the previously noted json
1262 ECB : * 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 CBC 619 : if (isnull && _state->normalize_results)
1266 12 : _state->tresult = (text *) NULL;
1267 : else
1268 : {
1269 607 : char *start = _state->result_start;
1270 607 : int len = _state->lex->prev_token_terminator - start;
1271 ECB :
1272 CBC 607 : _state->tresult = cstring_to_text_with_len(start, len);
1273 ECB : }
1274 :
1275 : /* this should be unnecessary but let's do it for cleanliness: */
1276 GIC 619 : _state->result_start = NULL;
1277 : }
1278 :
1279 GNC 53456 : return JSON_SUCCESS;
1280 ECB : }
1281 :
1282 : static JsonParseErrorType
1283 GIC 928 : get_array_start(void *state)
1284 : {
1285 CBC 928 : GetState *_state = (GetState *) state;
1286 GIC 928 : int lex_level = _state->lex->lex_level;
1287 :
1288 928 : if (lex_level < _state->npath)
1289 : {
1290 ECB : /* Initialize counting of elements in this array */
1291 GIC 257 : _state->array_cur_index[lex_level] = -1;
1292 :
1293 : /* INT_MIN value is reserved to represent invalid subscript */
1294 257 : if (_state->path_indexes[lex_level] < 0 &&
1295 15 : _state->path_indexes[lex_level] != INT_MIN)
1296 : {
1297 ECB : /* Negative subscript -- convert to positive-wise subscript */
1298 : JsonParseErrorType error;
1299 : int nelements;
1300 :
1301 CBC 3 : error = json_count_array_elements(_state->lex, &nelements);
1302 3 : if (error != JSON_SUCCESS)
1303 UNC 0 : json_errsave_error(error, _state->lex, NULL);
1304 ECB :
1305 GIC 3 : if (-_state->path_indexes[lex_level] <= nelements)
1306 3 : _state->path_indexes[lex_level] += nelements;
1307 : }
1308 ECB : }
1309 GIC 671 : else if (lex_level == 0 && _state->npath == 0)
1310 : {
1311 ECB : /*
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 GIC 6 : _state->result_start = _state->lex->token_start;
1317 ECB : }
1318 :
1319 GNC 928 : return JSON_SUCCESS;
1320 ECB : }
1321 :
1322 : static JsonParseErrorType
1323 GIC 6 : get_array_end(void *state)
1324 : {
1325 CBC 6 : GetState *_state = (GetState *) state;
1326 GIC 6 : int lex_level = _state->lex->lex_level;
1327 :
1328 CBC 6 : if (lex_level == 0 && _state->npath == 0)
1329 ECB : {
1330 : /* Special case: return the entire array */
1331 GIC 6 : char *start = _state->result_start;
1332 6 : int len = _state->lex->prev_token_terminator - start;
1333 :
1334 6 : _state->tresult = cstring_to_text_with_len(start, len);
1335 ECB : }
1336 :
1337 GNC 6 : return JSON_SUCCESS;
1338 ECB : }
1339 EUB :
1340 : static JsonParseErrorType
1341 CBC 965 : get_array_element_start(void *state, bool isnull)
1342 ECB : {
1343 GIC 965 : GetState *_state = (GetState *) state;
1344 965 : bool get_next = false;
1345 CBC 965 : int lex_level = _state->lex->lex_level;
1346 :
1347 : /* Update array element counter */
1348 GIC 965 : if (lex_level <= _state->npath)
1349 488 : _state->array_cur_index[lex_level - 1]++;
1350 :
1351 965 : if (lex_level <= _state->npath &&
1352 CBC 488 : _state->pathok[lex_level - 1] &&
1353 GIC 488 : _state->path_indexes != NULL &&
1354 488 : _state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
1355 ECB : {
1356 GIC 239 : if (lex_level < _state->npath)
1357 : {
1358 : /* if not at end of path just mark path ok */
1359 CBC 72 : _state->pathok[lex_level] = true;
1360 : }
1361 ECB : else
1362 : {
1363 : /* end of path, so we want this value */
1364 CBC 167 : get_next = true;
1365 : }
1366 : }
1367 ECB :
1368 : /* same logic as for objects */
1369 GIC 965 : if (get_next)
1370 ECB : {
1371 GIC 167 : _state->tresult = NULL;
1372 167 : _state->result_start = NULL;
1373 ECB :
1374 GIC 167 : if (_state->normalize_results &&
1375 30 : _state->lex->token_type == JSON_TOKEN_STRING)
1376 : {
1377 CBC 9 : _state->next_scalar = true;
1378 : }
1379 ECB : else
1380 : {
1381 CBC 158 : _state->result_start = _state->lex->token_start;
1382 : }
1383 : }
1384 :
1385 GNC 965 : return JSON_SUCCESS;
1386 ECB : }
1387 :
1388 : static JsonParseErrorType
1389 CBC 965 : get_array_element_end(void *state, bool isnull)
1390 ECB : {
1391 CBC 965 : GetState *_state = (GetState *) state;
1392 965 : bool get_last = false;
1393 GIC 965 : int lex_level = _state->lex->lex_level;
1394 ECB :
1395 : /* same tests as in get_array_element_start */
1396 GIC 965 : if (lex_level <= _state->npath &&
1397 CBC 488 : _state->pathok[lex_level - 1] &&
1398 GIC 488 : _state->path_indexes != NULL &&
1399 488 : _state->array_cur_index[lex_level - 1] == _state->path_indexes[lex_level - 1])
1400 : {
1401 239 : if (lex_level < _state->npath)
1402 ECB : {
1403 : /* done with this element so reset pathok */
1404 GIC 72 : _state->pathok[lex_level] = false;
1405 : }
1406 : else
1407 ECB : {
1408 : /* end of path, so we want this value */
1409 CBC 167 : get_last = true;
1410 ECB : }
1411 : }
1412 :
1413 : /* same logic as for objects */
1414 GIC 965 : if (get_last && _state->result_start != NULL)
1415 ECB : {
1416 GIC 158 : if (isnull && _state->normalize_results)
1417 6 : _state->tresult = (text *) NULL;
1418 : else
1419 ECB : {
1420 GIC 152 : char *start = _state->result_start;
1421 152 : int len = _state->lex->prev_token_terminator - start;
1422 :
1423 CBC 152 : _state->tresult = cstring_to_text_with_len(start, len);
1424 : }
1425 :
1426 GIC 158 : _state->result_start = NULL;
1427 ECB : }
1428 :
1429 GNC 965 : return JSON_SUCCESS;
1430 : }
1431 ECB :
1432 : static JsonParseErrorType
1433 CBC 52731 : get_scalar(void *state, char *token, JsonTokenType tokentype)
1434 : {
1435 GIC 52731 : GetState *_state = (GetState *) state;
1436 CBC 52731 : int lex_level = _state->lex->lex_level;
1437 ECB :
1438 : /* Check for whole-object match */
1439 CBC 52731 : if (lex_level == 0 && _state->npath == 0)
1440 : {
1441 18 : if (_state->normalize_results && tokentype == JSON_TOKEN_STRING)
1442 : {
1443 : /* we want the de-escaped string */
1444 3 : _state->next_scalar = true;
1445 : }
1446 GIC 15 : else if (_state->normalize_results && tokentype == JSON_TOKEN_NULL)
1447 : {
1448 3 : _state->tresult = (text *) NULL;
1449 ECB : }
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 CBC 12 : char *start = _state->lex->input;
1458 GIC 12 : int len = _state->lex->prev_token_terminator - start;
1459 :
1460 CBC 12 : _state->tresult = cstring_to_text_with_len(start, len);
1461 ECB : }
1462 : }
1463 :
1464 GIC 52731 : if (_state->next_scalar)
1465 : {
1466 ECB : /* a de-escaped text value is wanted, so supply it */
1467 GIC 351 : _state->tresult = cstring_to_text(token);
1468 : /* make sure the next call to get_scalar doesn't overwrite it */
1469 CBC 351 : _state->next_scalar = false;
1470 : }
1471 :
1472 GNC 52731 : return JSON_SUCCESS;
1473 : }
1474 :
1475 ECB : Datum
1476 GIC 135 : jsonb_extract_path(PG_FUNCTION_ARGS)
1477 ECB : {
1478 CBC 135 : return get_jsonb_path_all(fcinfo, false);
1479 : }
1480 :
1481 ECB : Datum
1482 GIC 90 : jsonb_extract_path_text(PG_FUNCTION_ARGS)
1483 ECB : {
1484 GIC 90 : return get_jsonb_path_all(fcinfo, true);
1485 : }
1486 ECB :
1487 : static Datum
1488 CBC 225 : get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
1489 : {
1490 225 : Jsonb *jb = PG_GETARG_JSONB_P(0);
1491 GIC 225 : 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 ECB : * 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 GIC 225 : if (array_contains_nulls(path))
1506 CBC 6 : PG_RETURN_NULL();
1507 :
1508 GNC 219 : deconstruct_array_builtin(path, TEXTOID, &pathtext, &pathnulls, &npath);
1509 :
1510 CBC 219 : res = jsonb_get_element(jb, pathtext, npath, &isnull, as_text);
1511 :
1512 GIC 219 : if (isnull)
1513 CBC 69 : PG_RETURN_NULL();
1514 : else
1515 GIC 150 : PG_RETURN_DATUM(res);
1516 : }
1517 ECB :
1518 : Datum
1519 CBC 315 : jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
1520 : {
1521 GIC 315 : JsonbContainer *container = &jb->root;
1522 315 : JsonbValue *jbvp = NULL;
1523 ECB : int i;
1524 GIC 315 : bool have_object = false,
1525 CBC 315 : have_array = false;
1526 :
1527 GIC 315 : *isnull = false;
1528 :
1529 ECB : /* Identify whether we have object, array, or scalar at top-level */
1530 GIC 315 : if (JB_ROOT_IS_OBJECT(jb))
1531 CBC 210 : have_object = true;
1532 105 : else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
1533 GIC 63 : have_array = true;
1534 : else
1535 : {
1536 42 : Assert(JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb));
1537 : /* Extract the scalar value, if it is what we'll return */
1538 42 : if (npath <= 0)
1539 18 : 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 ECB : * 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 GIC 315 : if (npath <= 0 && jbvp == NULL)
1551 ECB : {
1552 GIC 12 : if (as_text)
1553 ECB : {
1554 CBC 6 : return PointerGetDatum(cstring_to_text(JsonbToCString(NULL,
1555 : container,
1556 6 : VARSIZE(jb))));
1557 : }
1558 : else
1559 : {
1560 ECB : /* not text mode - just hand back the jsonb */
1561 GIC 6 : PG_RETURN_JSONB_P(jb);
1562 ECB : }
1563 : }
1564 :
1565 CBC 504 : for (i = 0; i < npath; i++)
1566 ECB : {
1567 GIC 486 : if (have_object)
1568 ECB : {
1569 GIC 312 : text *subscr = DatumGetTextPP(path[i]);
1570 :
1571 CBC 624 : jbvp = getKeyJsonValueFromContainer(container,
1572 312 : VARDATA_ANY(subscr),
1573 312 : VARSIZE_ANY_EXHDR(subscr),
1574 ECB : NULL);
1575 : }
1576 GIC 174 : else if (have_array)
1577 ECB : {
1578 : int lindex;
1579 : uint32 index;
1580 CBC 135 : char *indextext = TextDatumGetCString(path[i]);
1581 : char *endptr;
1582 :
1583 GIC 135 : errno = 0;
1584 135 : lindex = strtoint(indextext, &endptr, 10);
1585 135 : if (endptr == indextext || *endptr != '\0' || errno != 0)
1586 : {
1587 18 : *isnull = true;
1588 21 : return PointerGetDatum(NULL);
1589 : }
1590 :
1591 CBC 117 : if (lindex >= 0)
1592 : {
1593 105 : index = (uint32) lindex;
1594 : }
1595 ECB : else
1596 : {
1597 : /* Handle negative subscript */
1598 : uint32 nelements;
1599 :
1600 : /* Container must be array, but make sure */
1601 GIC 12 : if (!JsonContainerIsArray(container))
1602 LBC 0 : elog(ERROR, "not a jsonb array");
1603 :
1604 GIC 12 : nelements = JsonContainerSize(container);
1605 :
1606 CBC 12 : if (lindex == INT_MIN || -lindex > nelements)
1607 : {
1608 3 : *isnull = true;
1609 GIC 3 : return PointerGetDatum(NULL);
1610 ECB : }
1611 : else
1612 CBC 9 : index = nelements + lindex;
1613 ECB : }
1614 :
1615 GIC 114 : jbvp = getIthJsonbValueFromContainer(container, index);
1616 : }
1617 ECB : else
1618 : {
1619 : /* scalar, extraction yields a null */
1620 GIC 39 : *isnull = true;
1621 CBC 39 : return PointerGetDatum(NULL);
1622 : }
1623 :
1624 426 : if (jbvp == NULL)
1625 ECB : {
1626 CBC 39 : *isnull = true;
1627 GIC 39 : return PointerGetDatum(NULL);
1628 ECB : }
1629 CBC 387 : else if (i == npath - 1)
1630 GIC 186 : break;
1631 :
1632 CBC 201 : if (jbvp->type == jbvBinary)
1633 : {
1634 186 : container = jbvp->val.binary.data;
1635 GIC 186 : have_object = JsonContainerIsObject(container);
1636 186 : have_array = JsonContainerIsArray(container);
1637 186 : Assert(!JsonContainerIsScalar(container));
1638 : }
1639 : else
1640 : {
1641 15 : Assert(IsAJsonbScalar(jbvp));
1642 CBC 15 : have_object = false;
1643 GBC 15 : have_array = false;
1644 : }
1645 ECB : }
1646 :
1647 CBC 204 : if (as_text)
1648 : {
1649 57 : if (jbvp->type == jbvNull)
1650 ECB : {
1651 GIC 12 : *isnull = true;
1652 12 : return PointerGetDatum(NULL);
1653 ECB : }
1654 :
1655 GIC 45 : return PointerGetDatum(JsonbValueAsText(jbvp));
1656 ECB : }
1657 : else
1658 : {
1659 GIC 147 : Jsonb *res = JsonbValueToJsonb(jbvp);
1660 :
1661 ECB : /* not text mode - just hand back the jsonb */
1662 CBC 147 : PG_RETURN_JSONB_P(res);
1663 : }
1664 : }
1665 ECB :
1666 : Datum
1667 CBC 123 : jsonb_set_element(Jsonb *jb, Datum *path, int path_len,
1668 ECB : JsonbValue *newval)
1669 : {
1670 : JsonbValue *res;
1671 CBC 123 : JsonbParseState *state = NULL;
1672 : JsonbIterator *it;
1673 123 : bool *path_nulls = palloc0(path_len * sizeof(bool));
1674 :
1675 123 : if (newval->type == jbvArray && newval->val.array.rawScalar)
1676 LBC 0 : *newval = newval->val.array.elems[0];
1677 ECB :
1678 CBC 123 : it = JsonbIteratorInit(&jb->root);
1679 :
1680 GIC 123 : res = setPath(&it, path, path_nulls, path_len, &state, 0, newval,
1681 : JB_PATH_CREATE | JB_PATH_FILL_GAPS |
1682 ECB : JB_PATH_CONSISTENT_POSITION);
1683 :
1684 CBC 99 : pfree(path_nulls);
1685 :
1686 GIC 99 : PG_RETURN_JSONB_P(JsonbValueToJsonb(res));
1687 : }
1688 ECB :
1689 : static void
1690 CBC 54 : push_null_elements(JsonbParseState **ps, int num)
1691 : {
1692 ECB : JsonbValue null;
1693 :
1694 GIC 54 : null.type = jbvNull;
1695 :
1696 CBC 204 : while (num-- > 0)
1697 GIC 150 : pushJsonbValue(ps, WJB_ELEM, &null);
1698 54 : }
1699 :
1700 ECB : /*
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 GIC 36 : push_path(JsonbParseState **st, int level, Datum *path_elems,
1710 : bool *path_nulls, int path_len, JsonbValue *newval)
1711 : {
1712 ECB : /*
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 EUB : */
1718 GIC 36 : enum jbvType *tpath = palloc0((path_len - level) * sizeof(enum jbvType));
1719 ECB : 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 GIC 108 : for (int i = level + 1; i < path_len; i++)
1727 ECB : {
1728 : char *c,
1729 : *badp;
1730 : int lindex;
1731 :
1732 GIC 72 : if (path_nulls[i])
1733 UIC 0 : break;
1734 :
1735 ECB : /*
1736 : * Try to convert to an integer to find out the expected type, object
1737 : * or array.
1738 : */
1739 CBC 72 : c = TextDatumGetCString(path_elems[i]);
1740 GIC 72 : errno = 0;
1741 72 : lindex = strtoint(c, &badp, 10);
1742 72 : if (badp == c || *badp != '\0' || errno != 0)
1743 : {
1744 : /* text, an object is expected */
1745 33 : newkey.type = jbvString;
1746 33 : newkey.val.string.val = c;
1747 33 : newkey.val.string.len = strlen(c);
1748 :
1749 33 : (void) pushJsonbValue(st, WJB_BEGIN_OBJECT, NULL);
1750 CBC 33 : (void) pushJsonbValue(st, WJB_KEY, &newkey);
1751 :
1752 GIC 33 : tpath[i - level] = jbvObject;
1753 : }
1754 : else
1755 : {
1756 : /* integer, an array is expected */
1757 39 : (void) pushJsonbValue(st, WJB_BEGIN_ARRAY, NULL);
1758 :
1759 CBC 39 : push_null_elements(st, lindex);
1760 :
1761 GIC 39 : tpath[i - level] = jbvArray;
1762 : }
1763 : }
1764 :
1765 : /* Insert an actual value for either an object or array */
1766 36 : if (tpath[(path_len - level) - 1] == jbvArray)
1767 ECB : {
1768 GIC 24 : (void) pushJsonbValue(st, WJB_ELEM, newval);
1769 : }
1770 : else
1771 12 : (void) pushJsonbValue(st, WJB_VALUE, newval);
1772 :
1773 ECB : /*
1774 EUB : * Close everything up to the last but one level. The last one will be
1775 : * closed outside of this function.
1776 : */
1777 GIC 108 : for (int i = path_len - 1; i > level; i--)
1778 : {
1779 72 : if (path_nulls[i])
1780 LBC 0 : break;
1781 ECB :
1782 CBC 72 : if (tpath[i - level] == jbvObject)
1783 33 : (void) pushJsonbValue(st, WJB_END_OBJECT, NULL);
1784 : else
1785 GIC 39 : (void) pushJsonbValue(st, WJB_END_ARRAY, NULL);
1786 ECB : }
1787 CBC 36 : }
1788 ECB :
1789 : /*
1790 : * Return the text representation of the given JsonbValue.
1791 : */
1792 : static text *
1793 CBC 210 : JsonbValueAsText(JsonbValue *v)
1794 : {
1795 GIC 210 : switch (v->type)
1796 : {
1797 UIC 0 : case jbvNull:
1798 LBC 0 : return NULL;
1799 :
1800 CBC 12 : case jbvBool:
1801 GIC 12 : return v->val.boolean ?
1802 CBC 18 : cstring_to_text_with_len("true", 4) :
1803 GIC 6 : cstring_to_text_with_len("false", 5);
1804 :
1805 114 : case jbvString:
1806 114 : return cstring_to_text_with_len(v->val.string.val,
1807 ECB : v->val.string.len);
1808 :
1809 CBC 21 : case jbvNumeric:
1810 : {
1811 : Datum cstr;
1812 ECB :
1813 GIC 21 : cstr = DirectFunctionCall1(numeric_out,
1814 : PointerGetDatum(v->val.numeric));
1815 :
1816 21 : return cstring_to_text(DatumGetCString(cstr));
1817 : }
1818 ECB :
1819 GIC 63 : case jbvBinary:
1820 ECB : {
1821 EUB : StringInfoData jtext;
1822 :
1823 CBC 63 : initStringInfo(&jtext);
1824 63 : (void) JsonbToCString(&jtext, v->val.binary.data,
1825 : v->val.binary.len);
1826 ECB :
1827 GIC 63 : return cstring_to_text_with_len(jtext.data, jtext.len);
1828 ECB : }
1829 :
1830 UIC 0 : default:
1831 0 : elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
1832 : return NULL;
1833 : }
1834 ECB : }
1835 :
1836 : /*
1837 : * SQL function json_array_length(json) -> int
1838 EUB : */
1839 : Datum
1840 GIC 12 : json_array_length(PG_FUNCTION_ARGS)
1841 ECB : {
1842 CBC 12 : text *json = PG_GETARG_TEXT_PP(0);
1843 ECB : AlenState *state;
1844 : JsonLexContext *lex;
1845 : JsonSemAction *sem;
1846 :
1847 CBC 12 : lex = makeJsonLexContext(json, false);
1848 GIC 12 : state = palloc0(sizeof(AlenState));
1849 12 : sem = palloc0(sizeof(JsonSemAction));
1850 ECB :
1851 : /* palloc0 does this for us */
1852 : #if 0
1853 : state->count = 0;
1854 : #endif
1855 GIC 12 : state->lex = lex;
1856 :
1857 CBC 12 : sem->semstate = (void *) state;
1858 GIC 12 : sem->object_start = alen_object_start;
1859 12 : sem->scalar = alen_scalar;
1860 CBC 12 : sem->array_element_start = alen_array_element_start;
1861 :
1862 GIC 12 : pg_parse_json_or_ereport(lex, sem);
1863 :
1864 CBC 6 : PG_RETURN_INT32(state->count);
1865 ECB : }
1866 :
1867 : Datum
1868 CBC 156 : jsonb_array_length(PG_FUNCTION_ARGS)
1869 : {
1870 GIC 156 : Jsonb *jb = PG_GETARG_JSONB_P(0);
1871 EUB :
1872 GBC 156 : if (JB_ROOT_IS_SCALAR(jb))
1873 GIC 3 : ereport(ERROR,
1874 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1875 : errmsg("cannot get array length of a scalar")));
1876 153 : else if (!JB_ROOT_IS_ARRAY(jb))
1877 3 : ereport(ERROR,
1878 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1879 : errmsg("cannot get array length of a non-array")));
1880 :
1881 CBC 150 : PG_RETURN_INT32(JB_ROOT_COUNT(jb));
1882 : }
1883 ECB :
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 CBC 6 : alen_object_start(void *state)
1891 : {
1892 GIC 6 : AlenState *_state = (AlenState *) state;
1893 :
1894 : /* json structure check */
1895 6 : if (_state->lex->lex_level == 0)
1896 CBC 3 : ereport(ERROR,
1897 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1898 ECB : errmsg("cannot get array length of a non-array")));
1899 :
1900 GNC 3 : return JSON_SUCCESS;
1901 ECB : }
1902 :
1903 : static JsonParseErrorType
1904 GIC 24 : alen_scalar(void *state, char *token, JsonTokenType tokentype)
1905 ECB : {
1906 GIC 24 : AlenState *_state = (AlenState *) state;
1907 ECB :
1908 : /* json structure check */
1909 GIC 24 : if (_state->lex->lex_level == 0)
1910 3 : ereport(ERROR,
1911 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1912 : errmsg("cannot get array length of a scalar")));
1913 :
1914 GNC 21 : return JSON_SUCCESS;
1915 ECB : }
1916 :
1917 : static JsonParseErrorType
1918 CBC 21 : alen_array_element_start(void *state, bool isnull)
1919 : {
1920 GIC 21 : AlenState *_state = (AlenState *) state;
1921 ECB :
1922 : /* just count up all the level 1 elements */
1923 GIC 21 : if (_state->lex->lex_level == 1)
1924 15 : _state->count++;
1925 :
1926 GNC 21 : return JSON_SUCCESS;
1927 : }
1928 ECB :
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 GIC 6 : json_each(PG_FUNCTION_ARGS)
1941 : {
1942 CBC 6 : return each_worker(fcinfo, false);
1943 ECB : }
1944 :
1945 : Datum
1946 GIC 6084 : jsonb_each(PG_FUNCTION_ARGS)
1947 ECB : {
1948 GIC 6084 : return each_worker_jsonb(fcinfo, "jsonb_each", false);
1949 : }
1950 :
1951 ECB : Datum
1952 GIC 6 : json_each_text(PG_FUNCTION_ARGS)
1953 ECB : {
1954 GIC 6 : return each_worker(fcinfo, true);
1955 : }
1956 ECB :
1957 : Datum
1958 GIC 12 : jsonb_each_text(PG_FUNCTION_ARGS)
1959 : {
1960 12 : return each_worker_jsonb(fcinfo, "jsonb_each_text", true);
1961 ECB : }
1962 :
1963 : static Datum
1964 GIC 6096 : each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
1965 ECB : {
1966 GIC 6096 : Jsonb *jb = PG_GETARG_JSONB_P(0);
1967 ECB : ReturnSetInfo *rsi;
1968 : MemoryContext old_cxt,
1969 : tmp_cxt;
1970 CBC 6096 : bool skipNested = false;
1971 ECB : JsonbIterator *it;
1972 : JsonbValue v;
1973 : JsonbIteratorToken r;
1974 :
1975 GIC 6096 : if (!JB_ROOT_IS_OBJECT(jb))
1976 UIC 0 : ereport(ERROR,
1977 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1978 : errmsg("cannot call %s on a non-object",
1979 : funcname)));
1980 :
1981 GIC 6096 : rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1982 6096 : InitMaterializedSRF(fcinfo, MAT_SRF_BLESS);
1983 :
1984 6096 : tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
1985 : "jsonb_each temporary cxt",
1986 : ALLOCSET_DEFAULT_SIZES);
1987 ECB :
1988 GIC 6096 : it = JsonbIteratorInit(&jb->root);
1989 ECB :
1990 GIC 47145 : while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
1991 : {
1992 41049 : skipNested = true;
1993 ECB :
1994 GIC 41049 : if (r == WJB_KEY)
1995 ECB : {
1996 : text *key;
1997 : Datum values[2];
1998 GIC 28857 : bool nulls[2] = {false, false};
1999 ECB :
2000 : /* Use the tmp context so we can clean up after each tuple is done */
2001 CBC 28857 : old_cxt = MemoryContextSwitchTo(tmp_cxt);
2002 :
2003 GIC 28857 : key = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
2004 :
2005 ECB : /*
2006 : * The next thing the iterator fetches should be the value, no
2007 : * matter what shape it is.
2008 : */
2009 GIC 28857 : r = JsonbIteratorNext(&it, &v, skipNested);
2010 28857 : Assert(r != WJB_DONE);
2011 ECB :
2012 GIC 28857 : values[0] = PointerGetDatum(key);
2013 ECB :
2014 GIC 28857 : if (as_text)
2015 : {
2016 57 : if (v.type == jbvNull)
2017 ECB : {
2018 : /* a json null is an sql null in text mode */
2019 GIC 12 : nulls[1] = true;
2020 12 : values[1] = (Datum) NULL;
2021 : }
2022 ECB : else
2023 GBC 45 : values[1] = PointerGetDatum(JsonbValueAsText(&v));
2024 : }
2025 : else
2026 : {
2027 : /* Not in text mode, just return the Jsonb */
2028 CBC 28800 : Jsonb *val = JsonbValueToJsonb(&v);
2029 ECB :
2030 GIC 28800 : values[1] = PointerGetDatum(val);
2031 ECB : }
2032 :
2033 GIC 28857 : tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2034 :
2035 ECB : /* clean up and switch back */
2036 GIC 28857 : MemoryContextSwitchTo(old_cxt);
2037 CBC 28857 : MemoryContextReset(tmp_cxt);
2038 : }
2039 ECB : }
2040 :
2041 CBC 6096 : MemoryContextDelete(tmp_cxt);
2042 :
2043 GIC 6096 : PG_RETURN_NULL();
2044 : }
2045 ECB :
2046 :
2047 : static Datum
2048 CBC 12 : each_worker(FunctionCallInfo fcinfo, bool as_text)
2049 : {
2050 12 : text *json = PG_GETARG_TEXT_PP(0);
2051 : JsonLexContext *lex;
2052 : JsonSemAction *sem;
2053 : ReturnSetInfo *rsi;
2054 : EachState *state;
2055 :
2056 12 : lex = makeJsonLexContext(json, true);
2057 12 : state = palloc0(sizeof(EachState));
2058 GIC 12 : sem = palloc0(sizeof(JsonSemAction));
2059 ECB :
2060 GIC 12 : rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2061 ECB :
2062 GIC 12 : InitMaterializedSRF(fcinfo, MAT_SRF_BLESS);
2063 CBC 12 : state->tuple_store = rsi->setResult;
2064 GIC 12 : state->ret_tdesc = rsi->setDesc;
2065 :
2066 CBC 12 : sem->semstate = (void *) state;
2067 12 : sem->array_start = each_array_start;
2068 GIC 12 : sem->scalar = each_scalar;
2069 12 : sem->object_field_start = each_object_field_start;
2070 CBC 12 : sem->object_field_end = each_object_field_end;
2071 :
2072 GIC 12 : state->normalize_results = as_text;
2073 12 : state->next_scalar = false;
2074 12 : state->lex = lex;
2075 CBC 12 : state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
2076 : "json_each temporary cxt",
2077 ECB : ALLOCSET_DEFAULT_SIZES);
2078 :
2079 GIC 12 : pg_parse_json_or_ereport(lex, sem);
2080 ECB :
2081 GIC 12 : MemoryContextDelete(state->tmp_cxt);
2082 :
2083 CBC 12 : PG_RETURN_NULL();
2084 ECB : }
2085 :
2086 :
2087 : static JsonParseErrorType
2088 CBC 63 : each_object_field_start(void *state, char *fname, bool isnull)
2089 : {
2090 63 : EachState *_state = (EachState *) state;
2091 :
2092 : /* save a pointer to where the value starts */
2093 GIC 63 : if (_state->lex->lex_level == 1)
2094 : {
2095 ECB : /*
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 GIC 51 : if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2101 6 : _state->next_scalar = true;
2102 : else
2103 CBC 45 : _state->result_start = _state->lex->token_start;
2104 ECB : }
2105 :
2106 GNC 63 : return JSON_SUCCESS;
2107 ECB : }
2108 :
2109 : static JsonParseErrorType
2110 GIC 63 : each_object_field_end(void *state, char *fname, bool isnull)
2111 ECB : {
2112 CBC 63 : EachState *_state = (EachState *) state;
2113 ECB : MemoryContext old_cxt;
2114 : int len;
2115 : text *val;
2116 : HeapTuple tuple;
2117 : Datum values[2];
2118 CBC 63 : bool nulls[2] = {false, false};
2119 ECB :
2120 : /* skip over nested objects */
2121 CBC 63 : if (_state->lex->lex_level != 1)
2122 GNC 12 : return JSON_SUCCESS;
2123 ECB :
2124 : /* use the tmp context so we can clean up after each tuple is done */
2125 GIC 51 : old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2126 :
2127 51 : values[0] = CStringGetTextDatum(fname);
2128 ECB :
2129 GIC 51 : if (isnull && _state->normalize_results)
2130 ECB : {
2131 GIC 6 : nulls[1] = true;
2132 CBC 6 : values[1] = (Datum) 0;
2133 : }
2134 GIC 45 : else if (_state->next_scalar)
2135 : {
2136 6 : values[1] = CStringGetTextDatum(_state->normalized_scalar);
2137 CBC 6 : _state->next_scalar = false;
2138 : }
2139 ECB : else
2140 : {
2141 GIC 39 : len = _state->lex->prev_token_terminator - _state->result_start;
2142 CBC 39 : val = cstring_to_text_with_len(_state->result_start, len);
2143 GIC 39 : values[1] = PointerGetDatum(val);
2144 : }
2145 :
2146 51 : tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2147 :
2148 51 : tuplestore_puttuple(_state->tuple_store, tuple);
2149 ECB :
2150 : /* clean up and switch back */
2151 GIC 51 : MemoryContextSwitchTo(old_cxt);
2152 CBC 51 : MemoryContextReset(_state->tmp_cxt);
2153 :
2154 GNC 51 : return JSON_SUCCESS;
2155 : }
2156 :
2157 : static JsonParseErrorType
2158 GIC 12 : each_array_start(void *state)
2159 : {
2160 12 : EachState *_state = (EachState *) state;
2161 ECB :
2162 : /* json structure check */
2163 CBC 12 : if (_state->lex->lex_level == 0)
2164 UIC 0 : ereport(ERROR,
2165 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2166 : errmsg("cannot deconstruct an array as an object")));
2167 :
2168 GNC 12 : return JSON_SUCCESS;
2169 : }
2170 :
2171 : static JsonParseErrorType
2172 GIC 75 : each_scalar(void *state, char *token, JsonTokenType tokentype)
2173 : {
2174 CBC 75 : EachState *_state = (EachState *) state;
2175 ECB :
2176 : /* json structure check */
2177 GIC 75 : if (_state->lex->lex_level == 0)
2178 LBC 0 : ereport(ERROR,
2179 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2180 ECB : errmsg("cannot deconstruct a scalar")));
2181 :
2182 : /* supply de-escaped value if required */
2183 GIC 75 : if (_state->next_scalar)
2184 CBC 6 : _state->normalized_scalar = token;
2185 :
2186 GNC 75 : return JSON_SUCCESS;
2187 ECB : }
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 CBC 18 : jsonb_array_elements(PG_FUNCTION_ARGS)
2199 : {
2200 GIC 18 : return elements_worker_jsonb(fcinfo, "jsonb_array_elements", false);
2201 ECB : }
2202 :
2203 : Datum
2204 GIC 6 : jsonb_array_elements_text(PG_FUNCTION_ARGS)
2205 : {
2206 CBC 6 : return elements_worker_jsonb(fcinfo, "jsonb_array_elements_text", true);
2207 ECB : }
2208 :
2209 : static Datum
2210 GIC 24 : elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
2211 : bool as_text)
2212 : {
2213 CBC 24 : Jsonb *jb = PG_GETARG_JSONB_P(0);
2214 : ReturnSetInfo *rsi;
2215 ECB : MemoryContext old_cxt,
2216 : tmp_cxt;
2217 GIC 24 : bool skipNested = false;
2218 ECB : JsonbIterator *it;
2219 EUB : JsonbValue v;
2220 : JsonbIteratorToken r;
2221 :
2222 GIC 24 : if (JB_ROOT_IS_SCALAR(jb))
2223 LBC 0 : ereport(ERROR,
2224 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2225 : errmsg("cannot extract elements from a scalar")));
2226 GIC 24 : else if (!JB_ROOT_IS_ARRAY(jb))
2227 LBC 0 : ereport(ERROR,
2228 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2229 ECB : errmsg("cannot extract elements from an object")));
2230 :
2231 GIC 24 : rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2232 ECB :
2233 GBC 24 : InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC | MAT_SRF_BLESS);
2234 :
2235 GIC 24 : tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
2236 : "jsonb_array_elements temporary cxt",
2237 : ALLOCSET_DEFAULT_SIZES);
2238 ECB :
2239 CBC 24 : it = JsonbIteratorInit(&jb->root);
2240 :
2241 162 : while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
2242 : {
2243 GIC 138 : skipNested = true;
2244 :
2245 138 : if (r == WJB_ELEM)
2246 : {
2247 : Datum values[1];
2248 90 : bool nulls[1] = {false};
2249 :
2250 : /* use the tmp context so we can clean up after each tuple is done */
2251 90 : old_cxt = MemoryContextSwitchTo(tmp_cxt);
2252 :
2253 CBC 90 : if (as_text)
2254 : {
2255 42 : if (v.type == jbvNull)
2256 : {
2257 : /* a json null is an sql null in text mode */
2258 GIC 6 : nulls[0] = true;
2259 CBC 6 : values[0] = (Datum) NULL;
2260 : }
2261 ECB : else
2262 GIC 36 : values[0] = PointerGetDatum(JsonbValueAsText(&v));
2263 : }
2264 : else
2265 ECB : {
2266 : /* Not in text mode, just return the Jsonb */
2267 GIC 48 : Jsonb *val = JsonbValueToJsonb(&v);
2268 ECB :
2269 GIC 48 : values[0] = PointerGetDatum(val);
2270 : }
2271 :
2272 CBC 90 : tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls);
2273 :
2274 : /* clean up and switch back */
2275 GIC 90 : MemoryContextSwitchTo(old_cxt);
2276 90 : MemoryContextReset(tmp_cxt);
2277 ECB : }
2278 EUB : }
2279 :
2280 GIC 24 : MemoryContextDelete(tmp_cxt);
2281 ECB :
2282 GBC 24 : PG_RETURN_NULL();
2283 : }
2284 :
2285 : Datum
2286 CBC 195 : json_array_elements(PG_FUNCTION_ARGS)
2287 : {
2288 195 : return elements_worker(fcinfo, "json_array_elements", false);
2289 : }
2290 ECB :
2291 : Datum
2292 GIC 6 : json_array_elements_text(PG_FUNCTION_ARGS)
2293 : {
2294 CBC 6 : return elements_worker(fcinfo, "json_array_elements_text", true);
2295 : }
2296 ECB :
2297 : static Datum
2298 CBC 201 : elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
2299 : {
2300 201 : text *json = PG_GETARG_TEXT_PP(0);
2301 :
2302 : /* elements only needs escaped strings when as_text */
2303 201 : JsonLexContext *lex = makeJsonLexContext(json, as_text);
2304 : JsonSemAction *sem;
2305 : ReturnSetInfo *rsi;
2306 ECB : ElementsState *state;
2307 :
2308 CBC 201 : state = palloc0(sizeof(ElementsState));
2309 GIC 201 : sem = palloc0(sizeof(JsonSemAction));
2310 ECB :
2311 GIC 201 : InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC | MAT_SRF_BLESS);
2312 201 : rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2313 CBC 201 : state->tuple_store = rsi->setResult;
2314 201 : state->ret_tdesc = rsi->setDesc;
2315 :
2316 GIC 201 : sem->semstate = (void *) state;
2317 CBC 201 : sem->object_start = elements_object_start;
2318 GIC 201 : sem->scalar = elements_scalar;
2319 201 : sem->array_element_start = elements_array_element_start;
2320 201 : sem->array_element_end = elements_array_element_end;
2321 :
2322 CBC 201 : state->function_name = funcname;
2323 GIC 201 : state->normalize_results = as_text;
2324 CBC 201 : state->next_scalar = false;
2325 GIC 201 : state->lex = lex;
2326 201 : state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
2327 ECB : "json_array_elements temporary cxt",
2328 : ALLOCSET_DEFAULT_SIZES);
2329 :
2330 CBC 201 : pg_parse_json_or_ereport(lex, sem);
2331 ECB :
2332 GIC 201 : MemoryContextDelete(state->tmp_cxt);
2333 :
2334 201 : PG_RETURN_NULL();
2335 ECB : }
2336 :
2337 : static JsonParseErrorType
2338 GIC 1014 : elements_array_element_start(void *state, bool isnull)
2339 : {
2340 1014 : ElementsState *_state = (ElementsState *) state;
2341 ECB :
2342 : /* save a pointer to where the value starts */
2343 CBC 1014 : if (_state->lex->lex_level == 1)
2344 : {
2345 : /*
2346 : * next_scalar will be reset in the array_element_end handler, and
2347 ECB : * since we know the value is a scalar there is no danger of it being
2348 : * on while recursing down the tree.
2349 : */
2350 GIC 339 : if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
2351 6 : _state->next_scalar = true;
2352 : else
2353 CBC 333 : _state->result_start = _state->lex->token_start;
2354 : }
2355 :
2356 GNC 1014 : return JSON_SUCCESS;
2357 ECB : }
2358 :
2359 : static JsonParseErrorType
2360 CBC 1014 : elements_array_element_end(void *state, bool isnull)
2361 : {
2362 GIC 1014 : ElementsState *_state = (ElementsState *) state;
2363 : MemoryContext old_cxt;
2364 : int len;
2365 ECB : text *val;
2366 : HeapTuple tuple;
2367 : Datum values[1];
2368 CBC 1014 : bool nulls[1] = {false};
2369 ECB :
2370 : /* skip over nested objects */
2371 CBC 1014 : if (_state->lex->lex_level != 1)
2372 GNC 675 : return JSON_SUCCESS;
2373 ECB :
2374 : /* use the tmp context so we can clean up after each tuple is done */
2375 CBC 339 : old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
2376 ECB :
2377 CBC 339 : if (isnull && _state->normalize_results)
2378 : {
2379 6 : nulls[0] = true;
2380 6 : values[0] = (Datum) NULL;
2381 ECB : }
2382 CBC 333 : else if (_state->next_scalar)
2383 ECB : {
2384 GIC 6 : values[0] = CStringGetTextDatum(_state->normalized_scalar);
2385 6 : _state->next_scalar = false;
2386 : }
2387 ECB : else
2388 : {
2389 CBC 327 : len = _state->lex->prev_token_terminator - _state->result_start;
2390 GIC 327 : val = cstring_to_text_with_len(_state->result_start, len);
2391 CBC 327 : values[0] = PointerGetDatum(val);
2392 : }
2393 :
2394 GIC 339 : tuple = heap_form_tuple(_state->ret_tdesc, values, nulls);
2395 ECB :
2396 GIC 339 : tuplestore_puttuple(_state->tuple_store, tuple);
2397 ECB :
2398 : /* clean up and switch back */
2399 GIC 339 : MemoryContextSwitchTo(old_cxt);
2400 CBC 339 : MemoryContextReset(_state->tmp_cxt);
2401 :
2402 GNC 339 : return JSON_SUCCESS;
2403 : }
2404 :
2405 : static JsonParseErrorType
2406 GIC 858 : elements_object_start(void *state)
2407 : {
2408 858 : ElementsState *_state = (ElementsState *) state;
2409 ECB :
2410 : /* json structure check */
2411 GIC 858 : if (_state->lex->lex_level == 0)
2412 LBC 0 : ereport(ERROR,
2413 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2414 : errmsg("cannot call %s on a non-array",
2415 ECB : _state->function_name)));
2416 :
2417 GNC 858 : return JSON_SUCCESS;
2418 : }
2419 :
2420 : static JsonParseErrorType
2421 CBC 12768 : elements_scalar(void *state, char *token, JsonTokenType tokentype)
2422 : {
2423 12768 : ElementsState *_state = (ElementsState *) state;
2424 :
2425 : /* json structure check */
2426 GIC 12768 : if (_state->lex->lex_level == 0)
2427 UIC 0 : ereport(ERROR,
2428 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2429 ECB : errmsg("cannot call %s on a scalar",
2430 : _state->function_name)));
2431 :
2432 : /* supply de-escaped value if required */
2433 CBC 12768 : if (_state->next_scalar)
2434 GIC 6 : _state->normalized_scalar = token;
2435 :
2436 GNC 12768 : return JSON_SUCCESS;
2437 : }
2438 ECB :
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 CBC 411 : jsonb_populate_record(PG_FUNCTION_ARGS)
2453 ECB : {
2454 CBC 411 : return populate_record_worker(fcinfo, "jsonb_populate_record",
2455 : false, true);
2456 : }
2457 ECB :
2458 : Datum
2459 CBC 51 : jsonb_to_record(PG_FUNCTION_ARGS)
2460 : {
2461 GIC 51 : return populate_record_worker(fcinfo, "jsonb_to_record",
2462 ECB : false, false);
2463 : }
2464 :
2465 : Datum
2466 GIC 411 : json_populate_record(PG_FUNCTION_ARGS)
2467 : {
2468 411 : return populate_record_worker(fcinfo, "json_populate_record",
2469 ECB : true, true);
2470 : }
2471 :
2472 : Datum
2473 GIC 51 : json_to_record(PG_FUNCTION_ARGS)
2474 ECB : {
2475 GBC 51 : return populate_record_worker(fcinfo, "json_to_record",
2476 : true, false);
2477 : }
2478 :
2479 : /* helper function for diagnostics */
2480 ECB : static void
2481 GIC 78 : populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim)
2482 : {
2483 78 : if (ndim <= 0)
2484 ECB : {
2485 GIC 48 : if (ctx->colname)
2486 CBC 48 : ereport(ERROR,
2487 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2488 : errmsg("expected JSON array"),
2489 ECB : errhint("See the value of key \"%s\".", ctx->colname)));
2490 EUB : else
2491 UIC 0 : ereport(ERROR,
2492 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2493 : errmsg("expected JSON array")));
2494 : }
2495 : else
2496 ECB : {
2497 : StringInfoData indices;
2498 : int i;
2499 :
2500 GIC 30 : initStringInfo(&indices);
2501 :
2502 30 : Assert(ctx->ndims > 0 && ndim < ctx->ndims);
2503 :
2504 60 : for (i = 0; i < ndim; i++)
2505 30 : appendStringInfo(&indices, "[%d]", ctx->sizes[i]);
2506 :
2507 30 : if (ctx->colname)
2508 30 : 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 UIC 0 : ereport(ERROR,
2515 ECB : (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 CBC 876 : populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims)
2525 : {
2526 : int i;
2527 :
2528 GIC 876 : Assert(ctx->ndims <= 0);
2529 ECB :
2530 GIC 876 : if (ndims <= 0)
2531 CBC 24 : populate_array_report_expected_array(ctx, ndims);
2532 :
2533 GIC 852 : ctx->ndims = ndims;
2534 852 : ctx->dims = palloc(sizeof(int) * ndims);
2535 852 : ctx->sizes = palloc0(sizeof(int) * ndims);
2536 ECB :
2537 GIC 1872 : for (i = 0; i < ndims; i++)
2538 CBC 1020 : ctx->dims[i] = -1; /* dimensions are unknown yet */
2539 GIC 852 : }
2540 :
2541 : /* check the populated subarray dimension */
2542 : static void
2543 753 : populate_array_check_dimension(PopulateArrayContext *ctx, int ndim)
2544 ECB : {
2545 GIC 753 : int dim = ctx->sizes[ndim]; /* current dimension counter */
2546 ECB :
2547 GIC 753 : if (ctx->dims[ndim] == -1)
2548 CBC 561 : ctx->dims[ndim] = dim; /* assign dimension if not yet known */
2549 192 : else if (ctx->dims[ndim] != dim)
2550 GIC 24 : ereport(ERROR,
2551 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2552 : errmsg("malformed JSON array"),
2553 : errdetail("Multidimensional arrays must have "
2554 EUB : "sub-arrays with matching dimensions.")));
2555 :
2556 : /* reset the current array dimension size counter */
2557 GIC 729 : ctx->sizes[ndim] = 0;
2558 :
2559 : /* increment the parent dimension counter if it is a nested sub-array */
2560 729 : if (ndim > 0)
2561 336 : ctx->sizes[ndim - 1]++;
2562 729 : }
2563 ECB :
2564 : static void
2565 CBC 2952 : populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv)
2566 : {
2567 ECB : Datum element;
2568 : bool element_isnull;
2569 :
2570 : /* populate the array element */
2571 CBC 2952 : element = populate_record_field(ctx->aio->element_info,
2572 GIC 2952 : ctx->aio->element_type,
2573 2952 : ctx->aio->element_typmod,
2574 : NULL, ctx->mcxt, PointerGetDatum(NULL),
2575 : jsv, &element_isnull);
2576 :
2577 GBC 2940 : accumArrayResult(ctx->astate, element, element_isnull,
2578 GIC 2940 : ctx->aio->element_type, ctx->acxt);
2579 :
2580 2940 : Assert(ndim > 0);
2581 2940 : ctx->sizes[ndim - 1]++; /* increment current dimension counter */
2582 2940 : }
2583 :
2584 : /* json object start handler for populate_array_json() */
2585 : static JsonParseErrorType
2586 324 : populate_array_object_start(void *_state)
2587 ECB : {
2588 GIC 324 : PopulateArrayState *state = (PopulateArrayState *) _state;
2589 324 : int ndim = state->lex->lex_level;
2590 :
2591 CBC 324 : if (state->ctx->ndims <= 0)
2592 GIC 156 : populate_array_assign_ndims(state->ctx, ndim);
2593 CBC 168 : else if (ndim < state->ctx->ndims)
2594 6 : populate_array_report_expected_array(state->ctx, ndim);
2595 :
2596 GNC 318 : return JSON_SUCCESS;
2597 : }
2598 ECB :
2599 : /* json array end handler for populate_array_json() */
2600 : static JsonParseErrorType
2601 GIC 576 : populate_array_array_end(void *_state)
2602 ECB : {
2603 CBC 576 : PopulateArrayState *state = (PopulateArrayState *) _state;
2604 576 : PopulateArrayContext *ctx = state->ctx;
2605 GIC 576 : int ndim = state->lex->lex_level;
2606 :
2607 576 : if (ctx->ndims <= 0)
2608 CBC 6 : populate_array_assign_ndims(ctx, ndim + 1);
2609 :
2610 576 : if (ndim < ctx->ndims)
2611 GIC 573 : populate_array_check_dimension(ctx, ndim);
2612 :
2613 GNC 564 : return JSON_SUCCESS;
2614 ECB : }
2615 :
2616 : /* json array element start handler for populate_array_json() */
2617 : static JsonParseErrorType
2618 GIC 1683 : populate_array_element_start(void *_state, bool isnull)
2619 : {
2620 1683 : PopulateArrayState *state = (PopulateArrayState *) _state;
2621 1683 : int ndim = state->lex->lex_level;
2622 :
2623 1683 : if (state->ctx->ndims <= 0 || ndim == state->ctx->ndims)
2624 ECB : {
2625 : /* remember current array element start */
2626 GIC 1560 : state->element_start = state->lex->token_start;
2627 CBC 1560 : state->element_type = state->lex->token_type;
2628 1560 : state->element_scalar = NULL;
2629 ECB : }
2630 :
2631 GNC 1683 : return JSON_SUCCESS;
2632 : }
2633 :
2634 ECB : /* json array element end handler for populate_array_json() */
2635 : static JsonParseErrorType
2636 GIC 1656 : populate_array_element_end(void *_state, bool isnull)
2637 : {
2638 1656 : PopulateArrayState *state = (PopulateArrayState *) _state;
2639 1656 : PopulateArrayContext *ctx = state->ctx;
2640 CBC 1656 : int ndim = state->lex->lex_level;
2641 ECB :
2642 CBC 1656 : Assert(ctx->ndims > 0);
2643 :
2644 GIC 1656 : if (ndim == ctx->ndims)
2645 : {
2646 ECB : JsValue jsv;
2647 :
2648 GIC 1476 : jsv.is_json = true;
2649 CBC 1476 : jsv.val.json.type = state->element_type;
2650 ECB :
2651 CBC 1476 : if (isnull)
2652 : {
2653 GIC 354 : Assert(jsv.val.json.type == JSON_TOKEN_NULL);
2654 354 : jsv.val.json.str = NULL;
2655 CBC 354 : jsv.val.json.len = 0;
2656 : }
2657 1122 : else if (state->element_scalar)
2658 ECB : {
2659 GIC 804 : jsv.val.json.str = state->element_scalar;
2660 CBC 804 : jsv.val.json.len = -1; /* null-terminated */
2661 ECB : }
2662 : else
2663 : {
2664 GIC 318 : jsv.val.json.str = state->element_start;
2665 CBC 318 : jsv.val.json.len = (state->lex->prev_token_terminator -
2666 GIC 318 : state->element_start) * sizeof(char);
2667 : }
2668 :
2669 1476 : populate_array_element(ctx, ndim, &jsv);
2670 ECB : }
2671 :
2672 GNC 1650 : return JSON_SUCCESS;
2673 : }
2674 ECB :
2675 : /* json scalar handler for populate_array_json() */
2676 : static JsonParseErrorType
2677 GIC 1827 : populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
2678 ECB : {
2679 CBC 1827 : PopulateArrayState *state = (PopulateArrayState *) _state;
2680 GIC 1827 : PopulateArrayContext *ctx = state->ctx;
2681 CBC 1827 : int ndim = state->lex->lex_level;
2682 ECB :
2683 GIC 1827 : if (ctx->ndims <= 0)
2684 CBC 288 : populate_array_assign_ndims(ctx, ndim);
2685 GIC 1539 : else if (ndim < ctx->ndims)
2686 9 : populate_array_report_expected_array(ctx, ndim);
2687 :
2688 1794 : if (ndim == ctx->ndims)
2689 ECB : {
2690 : /* remember the scalar element token */
2691 CBC 1158 : state->element_scalar = token;
2692 ECB : /* element_type must already be set in populate_array_element_start() */
2693 GIC 1158 : Assert(state->element_type == tokentype);
2694 ECB : }
2695 :
2696 GNC 1794 : return JSON_SUCCESS;
2697 : }
2698 :
2699 ECB : /* parse a json array and populate array */
2700 : static void
2701 CBC 450 : populate_array_json(PopulateArrayContext *ctx, char *json, int len)
2702 : {
2703 : PopulateArrayState state;
2704 ECB : JsonSemAction sem;
2705 :
2706 GIC 450 : state.lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
2707 450 : state.ctx = ctx;
2708 :
2709 CBC 450 : memset(&sem, 0, sizeof(sem));
2710 GIC 450 : sem.semstate = (void *) &state;
2711 CBC 450 : sem.object_start = populate_array_object_start;
2712 450 : sem.array_end = populate_array_array_end;
2713 450 : sem.array_element_start = populate_array_element_start;
2714 GIC 450 : sem.array_element_end = populate_array_element_end;
2715 CBC 450 : sem.scalar = populate_array_scalar;
2716 :
2717 450 : pg_parse_json_or_ereport(state.lex, &sem);
2718 :
2719 : /* number of dimensions should be already known */
2720 GIC 393 : Assert(ctx->ndims > 0 && ctx->dims);
2721 ECB :
2722 CBC 393 : pfree(state.lex);
2723 GIC 393 : }
2724 ECB :
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 CBC 645 : populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */
2731 : JsonbValue *jbv, /* jsonb sub-array */
2732 ECB : int ndim) /* current dimension */
2733 : {
2734 GIC 645 : JsonbContainer *jbc = jbv->val.binary.data;
2735 : JsonbIterator *it;
2736 : JsonbIteratorToken tok;
2737 ECB : JsonbValue val;
2738 : JsValue jsv;
2739 :
2740 GIC 645 : check_stack_depth();
2741 :
2742 CBC 645 : if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc))
2743 GIC 39 : populate_array_report_expected_array(ctx, ndim - 1);
2744 :
2745 CBC 606 : Assert(!JsonContainerIsScalar(jbc));
2746 :
2747 GIC 606 : it = JsonbIteratorInit(jbc);
2748 :
2749 606 : tok = JsonbIteratorNext(&it, &val, true);
2750 CBC 606 : Assert(tok == WJB_BEGIN_ARRAY);
2751 :
2752 606 : tok = JsonbIteratorNext(&it, &val, true);
2753 ECB :
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 CBC 606 : if (ctx->ndims <= 0 &&
2760 GIC 504 : (tok == WJB_END_ARRAY ||
2761 CBC 504 : (tok == WJB_ELEM &&
2762 GIC 504 : (val.type != jbvBinary ||
2763 240 : !JsonContainerIsArray(val.val.binary.data)))))
2764 CBC 426 : populate_array_assign_ndims(ctx, ndim);
2765 :
2766 606 : jsv.is_json = false;
2767 GIC 606 : jsv.val.jsonb = &val;
2768 :
2769 ECB : /* process all the array elements */
2770 GIC 2244 : while (tok == WJB_ELEM)
2771 : {
2772 : /*
2773 : * Recurse only if the dimensions of dimensions is still unknown or if
2774 ECB : * it is not the innermost dimension.
2775 : */
2776 GIC 1671 : if (ctx->ndims > 0 && ndim >= ctx->ndims)
2777 1476 : populate_array_element(ctx, ndim, &jsv);
2778 : else
2779 ECB : {
2780 : /* populate child sub-array */
2781 GIC 195 : populate_array_dim_jsonb(ctx, &val, ndim + 1);
2782 ECB :
2783 : /* number of dimensions should be already known */
2784 CBC 180 : Assert(ctx->ndims > 0 && ctx->dims);
2785 ECB :
2786 CBC 180 : populate_array_check_dimension(ctx, ndim);
2787 ECB : }
2788 :
2789 GIC 1638 : tok = JsonbIteratorNext(&it, &val, true);
2790 ECB : }
2791 :
2792 GIC 573 : Assert(tok == WJB_END_ARRAY);
2793 ECB :
2794 : /* free iterator, iterating until WJB_DONE */
2795 CBC 573 : tok = JsonbIteratorNext(&it, &val, true);
2796 573 : Assert(tok == WJB_DONE && !it);
2797 GIC 573 : }
2798 :
2799 : /* recursively populate an array from json/jsonb */
2800 : static Datum
2801 900 : populate_array(ArrayIOData *aio,
2802 : const char *colname,
2803 ECB : MemoryContext mcxt,
2804 : JsValue *jsv)
2805 : {
2806 : PopulateArrayContext ctx;
2807 : Datum result;
2808 : int *lbs;
2809 : int i;
2810 :
2811 GIC 900 : ctx.aio = aio;
2812 900 : ctx.mcxt = mcxt;
2813 CBC 900 : ctx.acxt = CurrentMemoryContext;
2814 GIC 900 : ctx.astate = initArrayResult(aio->element_type, ctx.acxt, true);
2815 CBC 900 : ctx.colname = colname;
2816 900 : ctx.ndims = 0; /* unknown yet */
2817 GIC 900 : ctx.dims = NULL;
2818 CBC 900 : ctx.sizes = NULL;
2819 :
2820 900 : if (jsv->is_json)
2821 GIC 450 : populate_array_json(&ctx, jsv->val.json.str,
2822 CBC 450 : jsv->val.json.len >= 0 ? jsv->val.json.len
2823 450 : : strlen(jsv->val.json.str));
2824 : else
2825 ECB : {
2826 GIC 450 : populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1);
2827 393 : ctx.dims[0] = ctx.sizes[0];
2828 : }
2829 :
2830 786 : Assert(ctx.ndims > 0);
2831 :
2832 CBC 786 : lbs = palloc(sizeof(int) * ctx.ndims);
2833 ECB :
2834 CBC 1680 : for (i = 0; i < ctx.ndims; i++)
2835 894 : lbs[i] = 1;
2836 ECB :
2837 CBC 786 : result = makeMdArrayResult(ctx.astate, ctx.ndims, ctx.dims, lbs,
2838 : ctx.acxt, true);
2839 ECB :
2840 CBC 786 : pfree(ctx.dims);
2841 GIC 786 : pfree(ctx.sizes);
2842 786 : pfree(lbs);
2843 ECB :
2844 GIC 786 : return result;
2845 : }
2846 :
2847 : static void
2848 1884 : JsValueToJsObject(JsValue *jsv, JsObject *jso)
2849 ECB : {
2850 CBC 1884 : jso->is_json = jsv->is_json;
2851 :
2852 GIC 1884 : if (jsv->is_json)
2853 : {
2854 ECB : /* convert plain-text json into a hash table */
2855 GIC 933 : jso->val.json_hash =
2856 942 : get_json_object_as_hash(jsv->val.json.str,
2857 CBC 942 : jsv->val.json.len >= 0
2858 : ? jsv->val.json.len
2859 171 : : strlen(jsv->val.json.str),
2860 : "populate_composite");
2861 : }
2862 ECB : else
2863 : {
2864 GIC 942 : JsonbValue *jbv = jsv->val.jsonb;
2865 ECB :
2866 GIC 942 : if (jbv->type == jbvBinary &&
2867 936 : JsonContainerIsObject(jbv->val.binary.data))
2868 ECB : {
2869 CBC 933 : jso->val.jsonb_cont = jbv->val.binary.data;
2870 ECB : }
2871 : else
2872 : {
2873 : bool is_scalar;
2874 :
2875 GIC 12 : is_scalar = IsAJsonbScalar(jbv) ||
2876 3 : (jbv->type == jbvBinary &&
2877 3 : JsonContainerIsScalar(jbv->val.binary.data));
2878 9 : 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 ECB : "populate_composite")));
2885 : }
2886 : }
2887 CBC 1866 : }
2888 ECB :
2889 : /* acquire or update cached tuple descriptor for a composite type */
2890 : static void
2891 CBC 2283 : update_cached_tupdesc(CompositeIOData *io, MemoryContext mcxt)
2892 : {
2893 2283 : if (!io->tupdesc ||
2894 1308 : io->tupdesc->tdtypeid != io->base_typid ||
2895 1308 : io->tupdesc->tdtypmod != io->base_typmod)
2896 ECB : {
2897 GIC 975 : TupleDesc tupdesc = lookup_rowtype_tupdesc(io->base_typid,
2898 : io->base_typmod);
2899 ECB : MemoryContext oldcxt;
2900 :
2901 GIC 975 : if (io->tupdesc)
2902 UIC 0 : FreeTupleDesc(io->tupdesc);
2903 ECB :
2904 : /* copy tuple desc without constraints into cache memory context */
2905 CBC 975 : oldcxt = MemoryContextSwitchTo(mcxt);
2906 GIC 975 : io->tupdesc = CreateTupleDescCopy(tupdesc);
2907 CBC 975 : MemoryContextSwitchTo(oldcxt);
2908 ECB :
2909 GIC 975 : ReleaseTupleDesc(tupdesc);
2910 ECB : }
2911 GIC 2283 : }
2912 :
2913 ECB : /* recursively populate a composite (row type) value from json/jsonb */
2914 : static Datum
2915 CBC 1884 : populate_composite(CompositeIOData *io,
2916 : Oid typid,
2917 ECB : 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 GIC 1884 : update_cached_tupdesc(io, mcxt);
2927 :
2928 CBC 1884 : if (isnull)
2929 LBC 0 : result = (Datum) 0;
2930 ECB : else
2931 : {
2932 : HeapTupleHeader tuple;
2933 : JsObject jso;
2934 :
2935 : /* prepare input value */
2936 GIC 1884 : JsValueToJsObject(jsv, &jso);
2937 ECB :
2938 : /* populate resulting record tuple */
2939 CBC 1866 : tuple = populate_record(io->tupdesc, &io->record_io,
2940 ECB : defaultval, mcxt, &jso);
2941 GIC 1704 : result = HeapTupleHeaderGetDatum(tuple);
2942 ECB :
2943 GIC 1704 : JsObjectFree(&jso);
2944 : }
2945 :
2946 : /*
2947 : * If it's domain over composite, check domain constraints. (This should
2948 ECB : * 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 CBC 1704 : if (typid != io->base_typid && typid != RECORDOID)
2952 GIC 18 : domain_check(result, isnull, typid, &io->domain_info, mcxt);
2953 :
2954 1698 : return result;
2955 : }
2956 :
2957 : /* populate non-null scalar value from json/jsonb value */
2958 : static Datum
2959 3789 : populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv)
2960 ECB : {
2961 : Datum res;
2962 GIC 3789 : char *str = NULL;
2963 3789 : char *json = NULL;
2964 ECB :
2965 GIC 3789 : if (jsv->is_json)
2966 ECB : {
2967 CBC 1908 : int len = jsv->val.json.len;
2968 ECB :
2969 GIC 1908 : json = jsv->val.json.str;
2970 CBC 1908 : Assert(json);
2971 GIC 1908 : if (len >= 0)
2972 : {
2973 : /* Need to copy non-null-terminated string */
2974 CBC 6 : str = palloc(len + 1 * sizeof(char));
2975 GBC 6 : memcpy(str, json, len);
2976 GIC 6 : str[len] = '\0';
2977 : }
2978 ECB : else
2979 CBC 1902 : str = json; /* string is already null-terminated */
2980 ECB :
2981 : /* If converting to json/jsonb, make string into valid JSON literal */
2982 CBC 1908 : if ((typid == JSONOID || typid == JSONBOID) &&
2983 GIC 546 : jsv->val.json.type == JSON_TOKEN_STRING)
2984 ECB : {
2985 : StringInfoData buf;
2986 :
2987 GIC 177 : initStringInfo(&buf);
2988 CBC 177 : escape_json(&buf, str);
2989 : /* free temporary buffer */
2990 GIC 177 : if (str != json)
2991 UIC 0 : pfree(str);
2992 GIC 177 : str = buf.data;
2993 : }
2994 : }
2995 : else
2996 : {
2997 1881 : JsonbValue *jbv = jsv->val.jsonb;
2998 :
2999 CBC 1881 : if (typid == JSONBOID)
3000 : {
3001 33 : Jsonb *jsonb = JsonbValueToJsonb(jbv); /* directly use jsonb */
3002 EUB :
3003 GIC 33 : return JsonbPGetDatum(jsonb);
3004 : }
3005 : /* convert jsonb to string for typio call */
3006 1848 : else if (typid == JSONOID && jbv->type != jbvBinary)
3007 486 : {
3008 : /*
3009 ECB : * Convert scalar jsonb (non-scalars are passed here as jbvBinary)
3010 : * to json string, preserving quotes around top-level strings.
3011 : */
3012 CBC 486 : Jsonb *jsonb = JsonbValueToJsonb(jbv);
3013 :
3014 486 : str = JsonbToCString(NULL, &jsonb->root, VARSIZE(jsonb));
3015 : }
3016 1362 : else if (jbv->type == jbvString) /* quotes are stripped */
3017 GIC 771 : str = pnstrdup(jbv->val.string.val, jbv->val.string.len);
3018 591 : else if (jbv->type == jbvBool)
3019 3 : str = pstrdup(jbv->val.boolean ? "true" : "false");
3020 588 : else if (jbv->type == jbvNumeric)
3021 546 : str = DatumGetCString(DirectFunctionCall1(numeric_out,
3022 : PointerGetDatum(jbv->val.numeric)));
3023 42 : else if (jbv->type == jbvBinary)
3024 CBC 42 : str = JsonbToCString(NULL, jbv->val.binary.data,
3025 ECB : jbv->val.binary.len);
3026 : else
3027 LBC 0 : elog(ERROR, "unrecognized jsonb type: %d", (int) jbv->type);
3028 : }
3029 :
3030 GIC 3756 : res = InputFunctionCall(&io->typiofunc, str, io->typioparam, typmod);
3031 :
3032 ECB : /* free temporary buffer */
3033 GIC 3732 : if (str != json)
3034 2019 : pfree(str);
3035 ECB :
3036 CBC 3732 : return res;
3037 : }
3038 ECB :
3039 : static Datum
3040 CBC 1350 : populate_domain(DomainIOData *io,
3041 : Oid typid,
3042 ECB : const char *colname,
3043 : MemoryContext mcxt,
3044 : JsValue *jsv,
3045 : bool isnull)
3046 : {
3047 : Datum res;
3048 :
3049 CBC 1350 : if (isnull)
3050 GIC 1314 : res = (Datum) 0;
3051 : else
3052 ECB : {
3053 GIC 36 : res = populate_record_field(io->base_io,
3054 : io->base_typid, io->base_typmod,
3055 ECB : colname, mcxt, PointerGetDatum(NULL),
3056 : jsv, &isnull);
3057 GIC 30 : Assert(!isnull);
3058 : }
3059 :
3060 CBC 1344 : domain_check(res, isnull, typid, &io->domain_info, mcxt);
3061 ECB :
3062 GIC 1320 : return res;
3063 ECB : }
3064 EUB :
3065 ECB : /* prepare column metadata cache for the given type */
3066 : static void
3067 GIC 10131 : prepare_column_cache(ColumnIOData *column,
3068 : Oid typid,
3069 : int32 typmod,
3070 ECB : MemoryContext mcxt,
3071 : bool need_scalar)
3072 : {
3073 : HeapTuple tup;
3074 : Form_pg_type type;
3075 :
3076 CBC 10131 : column->typid = typid;
3077 GIC 10131 : column->typmod = typmod;
3078 :
3079 CBC 10131 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3080 10131 : if (!HeapTupleIsValid(tup))
3081 UIC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
3082 :
3083 GIC 10131 : type = (Form_pg_type) GETSTRUCT(tup);
3084 :
3085 CBC 10131 : if (type->typtype == TYPTYPE_DOMAIN)
3086 : {
3087 ECB : /*
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 CBC 978 : int32 base_typmod = typmod;
3093 ECB :
3094 CBC 978 : base_typid = getBaseTypeAndTypmod(typid, &base_typmod);
3095 GIC 978 : if (get_typtype(base_typid) == TYPTYPE_COMPOSITE)
3096 ECB : {
3097 : /* domain over composite has its own code path */
3098 GIC 36 : column->typcat = TYPECAT_COMPOSITE_DOMAIN;
3099 36 : column->io.composite.record_io = NULL;
3100 GBC 36 : column->io.composite.tupdesc = NULL;
3101 GIC 36 : column->io.composite.base_typid = base_typid;
3102 36 : column->io.composite.base_typmod = base_typmod;
3103 CBC 36 : column->io.composite.domain_info = NULL;
3104 : }
3105 : else
3106 ECB : {
3107 : /* domain over anything else */
3108 GIC 942 : column->typcat = TYPECAT_DOMAIN;
3109 CBC 942 : column->io.domain.base_typid = base_typid;
3110 GIC 942 : column->io.domain.base_typmod = base_typmod;
3111 942 : column->io.domain.base_io =
3112 942 : MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
3113 CBC 942 : column->io.domain.domain_info = NULL;
3114 : }
3115 : }
3116 GIC 9153 : else if (type->typtype == TYPTYPE_COMPOSITE || typid == RECORDOID)
3117 : {
3118 1269 : column->typcat = TYPECAT_COMPOSITE;
3119 1269 : column->io.composite.record_io = NULL;
3120 1269 : column->io.composite.tupdesc = NULL;
3121 1269 : column->io.composite.base_typid = typid;
3122 CBC 1269 : column->io.composite.base_typmod = typmod;
3123 1269 : column->io.composite.domain_info = NULL;
3124 : }
3125 GIC 7884 : else if (IsTrueArrayType(type))
3126 ECB : {
3127 GIC 3750 : column->typcat = TYPECAT_ARRAY;
3128 3750 : column->io.array.element_info = MemoryContextAllocZero(mcxt,
3129 : sizeof(ColumnIOData));
3130 CBC 3750 : column->io.array.element_type = type->typelem;
3131 : /* array element typemod stored in attribute's typmod */
3132 GIC 3750 : column->io.array.element_typmod = typmod;
3133 ECB : }
3134 : else
3135 : {
3136 GIC 4134 : column->typcat = TYPECAT_SCALAR;
3137 4134 : need_scalar = true;
3138 : }
3139 :
3140 ECB : /* caller can force us to look up scalar_io info even for non-scalars */
3141 GIC 10131 : if (need_scalar)
3142 : {
3143 : Oid typioproc;
3144 :
3145 9366 : getTypeInputInfo(typid, &typioproc, &column->scalar_io.typioparam);
3146 9366 : fmgr_info_cxt(typioproc, &column->scalar_io.typiofunc, mcxt);
3147 : }
3148 :
3149 CBC 10131 : ReleaseSysCache(tup);
3150 10131 : }
3151 :
3152 ECB : /* recursively populate a record field or an array element from a json/jsonb value */
3153 : static Datum
3154 GBC 17619 : populate_record_field(ColumnIOData *col,
3155 : Oid typid,
3156 ECB : int32 typmod,
3157 : const char *colname,
3158 : MemoryContext mcxt,
3159 : Datum defaultval,
3160 : JsValue *jsv,
3161 : bool *isnull)
3162 : {
3163 : TypeCat typcat;
3164 :
3165 CBC 17619 : check_stack_depth();
3166 :
3167 ECB : /*
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 CBC 17619 : if (col->typid != typid || col->typmod != typmod)
3172 9366 : prepare_column_cache(col, typid, typmod, mcxt, true);
3173 ECB :
3174 CBC 17619 : *isnull = JsValueIsNull(jsv);
3175 ECB :
3176 CBC 17619 : typcat = col->typcat;
3177 :
3178 : /* try to convert json string to a non-scalar type through input function */
3179 GIC 17619 : if (JsValueIsString(jsv) &&
3180 1881 : (typcat == TYPECAT_ARRAY ||
3181 CBC 1869 : typcat == TYPECAT_COMPOSITE ||
3182 ECB : typcat == TYPECAT_COMPOSITE_DOMAIN))
3183 CBC 24 : typcat = TYPECAT_SCALAR;
3184 ECB :
3185 : /* we must perform domain checks for NULLs, otherwise exit immediately */
3186 CBC 17619 : if (*isnull &&
3187 GIC 10614 : typcat != TYPECAT_DOMAIN &&
3188 : typcat != TYPECAT_COMPOSITE_DOMAIN)
3189 CBC 10614 : return (Datum) 0;
3190 :
3191 7005 : switch (typcat)
3192 ECB : {
3193 CBC 3789 : case TYPECAT_SCALAR:
3194 3789 : return populate_scalar(&col->scalar_io, typid, typmod, jsv);
3195 ECB :
3196 CBC 900 : case TYPECAT_ARRAY:
3197 GIC 900 : return populate_array(&col->io.array, colname, mcxt, jsv);
3198 ECB :
3199 GIC 966 : case TYPECAT_COMPOSITE:
3200 ECB : case TYPECAT_COMPOSITE_DOMAIN:
3201 CBC 972 : return populate_composite(&col->io.composite, typid,
3202 : colname, mcxt,
3203 966 : DatumGetPointer(defaultval)
3204 GIC 6 : ? DatumGetHeapTupleHeader(defaultval)
3205 ECB : : NULL,
3206 GIC 966 : jsv, *isnull);
3207 :
3208 1350 : case TYPECAT_DOMAIN:
3209 CBC 1350 : return populate_domain(&col->io.domain, typid, colname, mcxt,
3210 1350 : jsv, *isnull);
3211 :
3212 UIC 0 : default:
3213 0 : elog(ERROR, "unrecognized type category '%c'", typcat);
3214 ECB : return (Datum) 0;
3215 : }
3216 : }
3217 :
3218 : static RecordIOData *
3219 CBC 1071 : allocate_record_info(MemoryContext mcxt, int ncolumns)
3220 : {
3221 : RecordIOData *data = (RecordIOData *)
3222 1071 : MemoryContextAlloc(mcxt,
3223 ECB : offsetof(RecordIOData, columns) +
3224 GIC 1071 : ncolumns * sizeof(ColumnIOData));
3225 :
3226 1071 : data->record_type = InvalidOid;
3227 CBC 1071 : data->record_typmod = 0;
3228 GIC 1071 : data->ncolumns = ncolumns;
3229 19089 : MemSet(data->columns, 0, sizeof(ColumnIOData) * ncolumns);
3230 :
3231 1071 : return data;
3232 : }
3233 :
3234 : static bool
3235 15009 : JsObjectGetField(JsObject *obj, char *field, JsValue *jsv)
3236 : {
3237 15009 : jsv->is_json = obj->is_json;
3238 ECB :
3239 GIC 15009 : if (jsv->is_json)
3240 : {
3241 7518 : JsonHashEntry *hashentry = hash_search(obj->val.json_hash, field,
3242 : HASH_FIND, NULL);
3243 :
3244 CBC 7518 : jsv->val.json.type = hashentry ? hashentry->type : JSON_TOKEN_NULL;
3245 7518 : jsv->val.json.str = jsv->val.json.type == JSON_TOKEN_NULL ? NULL :
3246 : hashentry->val;
3247 7518 : jsv->val.json.len = jsv->val.json.str ? -1 : 0; /* null-terminated */
3248 :
3249 7518 : return hashentry != NULL;
3250 : }
3251 : else
3252 ECB : {
3253 CBC 7491 : jsv->val.jsonb = !obj->val.jsonb_cont ? NULL :
3254 7491 : getKeyJsonValueFromContainer(obj->val.jsonb_cont, field, strlen(field),
3255 : NULL);
3256 ECB :
3257 GIC 7491 : return jsv->val.jsonb != NULL;
3258 : }
3259 ECB : }
3260 :
3261 : /* populate a record tuple from json/jsonb value */
3262 : static HeapTupleHeader
3263 GIC 2106 : populate_record(TupleDesc tupdesc,
3264 ECB : RecordIOData **record_p,
3265 : HeapTupleHeader defaultval,
3266 : MemoryContext mcxt,
3267 : JsObject *obj)
3268 : {
3269 CBC 2106 : RecordIOData *record = *record_p;
3270 ECB : Datum *values;
3271 : bool *nulls;
3272 : HeapTuple res;
3273 GIC 2106 : int ncolumns = tupdesc->natts;
3274 ECB : 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 CBC 2106 : if (defaultval && JsObjectIsEmpty(obj))
3282 6 : return defaultval;
3283 ECB :
3284 : /* (re)allocate metadata cache */
3285 GBC 2100 : if (record == NULL ||
3286 1029 : record->ncolumns != ncolumns)
3287 GIC 1071 : *record_p = record = allocate_record_info(mcxt, ncolumns);
3288 :
3289 : /* invalidate metadata cache if the record type has changed */
3290 2100 : if (record->record_type != tupdesc->tdtypeid ||
3291 1029 : record->record_typmod != tupdesc->tdtypmod)
3292 ECB : {
3293 GIC 20199 : MemSet(record, 0, offsetof(RecordIOData, columns) +
3294 : ncolumns * sizeof(ColumnIOData));
3295 CBC 1071 : record->record_type = tupdesc->tdtypeid;
3296 GIC 1071 : record->record_typmod = tupdesc->tdtypmod;
3297 CBC 1071 : record->ncolumns = ncolumns;
3298 : }
3299 ECB :
3300 CBC 2100 : values = (Datum *) palloc(ncolumns * sizeof(Datum));
3301 2100 : nulls = (bool *) palloc(ncolumns * sizeof(bool));
3302 ECB :
3303 GIC 2100 : if (defaultval)
3304 ECB : {
3305 : HeapTupleData tuple;
3306 :
3307 : /* Build a temporary HeapTuple control structure */
3308 CBC 216 : tuple.t_len = HeapTupleHeaderGetDatumLength(defaultval);
3309 GIC 216 : ItemPointerSetInvalid(&(tuple.t_self));
3310 CBC 216 : tuple.t_tableOid = InvalidOid;
3311 GIC 216 : tuple.t_data = defaultval;
3312 ECB :
3313 : /* Break down the tuple into fields */
3314 CBC 216 : heap_deform_tuple(&tuple, tupdesc, values, nulls);
3315 : }
3316 : else
3317 ECB : {
3318 CBC 17319 : for (i = 0; i < ncolumns; ++i)
3319 : {
3320 15435 : values[i] = (Datum) 0;
3321 GIC 15435 : nulls[i] = true;
3322 ECB : }
3323 : }
3324 :
3325 GIC 16941 : for (i = 0; i < ncolumns; ++i)
3326 ECB : {
3327 CBC 15009 : Form_pg_attribute att = TupleDescAttr(tupdesc, i);
3328 GIC 15009 : char *colname = NameStr(att->attname);
3329 15009 : JsValue field = {0};
3330 ECB : bool found;
3331 :
3332 : /* Ignore dropped columns in datatype */
3333 GIC 15009 : if (att->attisdropped)
3334 : {
3335 UIC 0 : nulls[i] = true;
3336 CBC 378 : continue;
3337 : }
3338 :
3339 GIC 15009 : found = JsObjectGetField(obj, colname, &field);
3340 :
3341 : /*
3342 ECB : * 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 GIC 15009 : if (defaultval && !found)
3350 378 : continue;
3351 :
3352 14631 : values[i] = populate_record_field(&record->columns[i],
3353 : att->atttypid,
3354 ECB : att->atttypmod,
3355 : colname,
3356 : mcxt,
3357 GIC 14631 : nulls[i] ? (Datum) 0 : values[i],
3358 ECB : &field,
3359 : &nulls[i]);
3360 : }
3361 :
3362 GIC 1932 : res = heap_form_tuple(tupdesc, values, nulls);
3363 ECB :
3364 CBC 1932 : pfree(values);
3365 GIC 1932 : pfree(nulls);
3366 ECB :
3367 GIC 1932 : return res->t_data;
3368 ECB : }
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 CBC 765 : get_record_type_from_argument(FunctionCallInfo fcinfo,
3377 : const char *funcname,
3378 : PopulateRecordCache *cache)
3379 : {
3380 GIC 765 : cache->argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
3381 CBC 765 : prepare_column_cache(&cache->c,
3382 ECB : cache->argtype, -1,
3383 : cache->fn_mcxt, false);
3384 CBC 765 : if (cache->c.typcat != TYPECAT_COMPOSITE &&
3385 GIC 36 : cache->c.typcat != TYPECAT_COMPOSITE_DOMAIN)
3386 UIC 0 : ereport(ERROR,
3387 ECB : (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 CBC 765 : }
3392 :
3393 ECB : /*
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 CBC 156 : get_record_type_from_query(FunctionCallInfo fcinfo,
3403 : const char *funcname,
3404 : PopulateRecordCache *cache)
3405 : {
3406 ECB : TupleDesc tupdesc;
3407 : MemoryContext old_cxt;
3408 EUB :
3409 CBC 156 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3410 GIC 18 : ereport(ERROR,
3411 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3412 ECB : /* 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 GIC 138 : Assert(tupdesc);
3420 138 : cache->argtype = tupdesc->tdtypeid;
3421 :
3422 ECB : /* If we go through this more than once, avoid memory leak */
3423 CBC 138 : if (cache->c.io.composite.tupdesc)
3424 UIC 0 : FreeTupleDesc(cache->c.io.composite.tupdesc);
3425 ECB :
3426 : /* Save identified tupdesc */
3427 GIC 138 : old_cxt = MemoryContextSwitchTo(cache->fn_mcxt);
3428 138 : cache->c.io.composite.tupdesc = CreateTupleDescCopy(tupdesc);
3429 138 : cache->c.io.composite.base_typid = tupdesc->tdtypeid;
3430 CBC 138 : cache->c.io.composite.base_typmod = tupdesc->tdtypmod;
3431 GIC 138 : MemoryContextSwitchTo(old_cxt);
3432 138 : }
3433 :
3434 : /*
3435 ECB : * 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 GIC 924 : populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
3440 ECB : bool is_json, bool have_record_arg)
3441 : {
3442 GIC 924 : int json_arg_num = have_record_arg ? 1 : 0;
3443 924 : JsValue jsv = {0};
3444 : HeapTupleHeader rec;
3445 : Datum rettuple;
3446 : JsonbValue jbv;
3447 924 : MemoryContext fnmcxt = fcinfo->flinfo->fn_mcxt;
3448 924 : PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
3449 ECB :
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 GIC 924 : if (!cache)
3456 : {
3457 CBC 720 : fcinfo->flinfo->fn_extra = cache =
3458 720 : MemoryContextAllocZero(fnmcxt, sizeof(*cache));
3459 GBC 720 : cache->fn_mcxt = fnmcxt;
3460 :
3461 GIC 720 : if (have_record_arg)
3462 618 : get_record_type_from_argument(fcinfo, funcname, cache);
3463 : else
3464 CBC 102 : get_record_type_from_query(fcinfo, funcname, cache);
3465 : }
3466 :
3467 : /* Collect record arg if we have one */
3468 GIC 924 : if (!have_record_arg)
3469 102 : rec = NULL; /* it's json{b}_to_record() */
3470 822 : else if (!PG_ARGISNULL(0))
3471 : {
3472 54 : rec = PG_GETARG_HEAPTUPLEHEADER(0);
3473 :
3474 : /*
3475 ECB : * When declared arg type is RECORD, identify actual record type from
3476 : * the tuple itself.
3477 : */
3478 GIC 54 : if (cache->argtype == RECORDOID)
3479 : {
3480 6 : cache->c.io.composite.base_typid = HeapTupleHeaderGetTypeId(rec);
3481 6 : cache->c.io.composite.base_typmod = HeapTupleHeaderGetTypMod(rec);
3482 ECB : }
3483 : }
3484 : else
3485 : {
3486 GIC 768 : 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 CBC 768 : if (cache->argtype == RECORDOID)
3493 ECB : {
3494 GIC 12 : get_record_type_from_query(fcinfo, funcname, cache);
3495 : /* This can't change argtype, which is important for next time */
3496 CBC 6 : Assert(cache->argtype == RECORDOID);
3497 EUB : }
3498 : }
3499 :
3500 ECB : /* If no JSON argument, just return the record (if any) unchanged */
3501 CBC 918 : if (PG_ARGISNULL(json_arg_num))
3502 ECB : {
3503 LBC 0 : if (rec)
3504 0 : PG_RETURN_POINTER(rec);
3505 ECB : else
3506 UIC 0 : PG_RETURN_NULL();
3507 : }
3508 :
3509 GIC 918 : jsv.is_json = is_json;
3510 :
3511 918 : if (is_json)
3512 ECB : {
3513 GIC 459 : text *json = PG_GETARG_TEXT_PP(json_arg_num);
3514 :
3515 CBC 459 : jsv.val.json.str = VARDATA_ANY(json);
3516 459 : jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
3517 GIC 459 : jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
3518 : * populate_composite() */
3519 : }
3520 ECB : else
3521 : {
3522 GIC 459 : Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
3523 :
3524 459 : jsv.val.jsonb = &jbv;
3525 :
3526 : /* fill binary jsonb value pointing to jb */
3527 459 : jbv.type = jbvBinary;
3528 CBC 459 : jbv.val.binary.data = &jb->root;
3529 GIC 459 : jbv.val.binary.len = VARSIZE(jb) - VARHDRSZ;
3530 ECB : }
3531 :
3532 CBC 918 : rettuple = populate_composite(&cache->c.io.composite, cache->argtype,
3533 : NULL, fnmcxt, rec, &jsv, false);
3534 ECB :
3535 CBC 750 : PG_RETURN_DATUM(rettuple);
3536 : }
3537 ECB :
3538 : /*
3539 : * get_json_object_as_hash
3540 : *
3541 : * decompose a json object into a hash table.
3542 : */
3543 : static HTAB *
3544 GIC 942 : get_json_object_as_hash(char *json, int len, const char *funcname)
3545 ECB : {
3546 : HASHCTL ctl;
3547 : HTAB *tab;
3548 : JHashState *state;
3549 GIC 942 : JsonLexContext *lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
3550 : JsonSemAction *sem;
3551 ECB :
3552 GIC 942 : ctl.keysize = NAMEDATALEN;
3553 CBC 942 : ctl.entrysize = sizeof(JsonHashEntry);
3554 942 : ctl.hcxt = CurrentMemoryContext;
3555 GIC 942 : tab = hash_create("json object hashtable",
3556 : 100,
3557 : &ctl,
3558 : HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
3559 ECB :
3560 GIC 942 : state = palloc0(sizeof(JHashState));
3561 942 : sem = palloc0(sizeof(JsonSemAction));
3562 :
3563 942 : state->function_name = funcname;
3564 942 : state->hash = tab;
3565 CBC 942 : state->lex = lex;
3566 :
3567 942 : sem->semstate = (void *) state;
3568 GIC 942 : sem->array_start = hash_array_start;
3569 CBC 942 : sem->scalar = hash_scalar;
3570 GIC 942 : sem->object_field_start = hash_object_field_start;
3571 942 : sem->object_field_end = hash_object_field_end;
3572 :
3573 942 : pg_parse_json_or_ereport(lex, sem);
3574 ECB :
3575 GIC 933 : return tab;
3576 EUB : }
3577 :
3578 : static JsonParseErrorType
3579 GBC 3078 : hash_object_field_start(void *state, char *fname, bool isnull)
3580 : {
3581 GIC 3078 : JHashState *_state = (JHashState *) state;
3582 ECB :
3583 GIC 3078 : if (_state->lex->lex_level > 1)
3584 GNC 1158 : return JSON_SUCCESS;
3585 :
3586 ECB : /* remember token type */
3587 GIC 1920 : _state->saved_token_type = _state->lex->token_type;
3588 ECB :
3589 CBC 1920 : if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
3590 1470 : _state->lex->token_type == JSON_TOKEN_OBJECT_START)
3591 : {
3592 : /* remember start position of the whole text of the subobject */
3593 GIC 627 : _state->save_json_start = _state->lex->token_start;
3594 : }
3595 ECB : else
3596 : {
3597 : /* must be a scalar */
3598 GIC 1293 : _state->save_json_start = NULL;
3599 : }
3600 :
3601 GNC 1920 : return JSON_SUCCESS;
3602 ECB : }
3603 :
3604 : static JsonParseErrorType
3605 GIC 3078 : hash_object_field_end(void *state, char *fname, bool isnull)
3606 : {
3607 CBC 3078 : JHashState *_state = (JHashState *) state;
3608 : JsonHashEntry *hashentry;
3609 : bool found;
3610 ECB :
3611 : /*
3612 : * Ignore nested fields.
3613 : */
3614 GIC 3078 : if (_state->lex->lex_level > 1)
3615 GNC 1158 : return JSON_SUCCESS;
3616 :
3617 : /*
3618 : * Ignore field names >= NAMEDATALEN - they can't match a record field.
3619 ECB : * (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 CBC 1920 : if (strlen(fname) >= NAMEDATALEN)
3625 UNC 0 : return JSON_SUCCESS;
3626 :
3627 CBC 1920 : hashentry = hash_search(_state->hash, fname, HASH_ENTER, &found);
3628 ECB :
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 GIC 1920 : hashentry->type = _state->saved_token_type;
3635 CBC 1920 : Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
3636 ECB :
3637 GIC 1920 : if (_state->save_json_start != NULL)
3638 ECB : {
3639 CBC 627 : int len = _state->lex->prev_token_terminator - _state->save_json_start;
3640 627 : char *val = palloc((len + 1) * sizeof(char));
3641 :
3642 627 : memcpy(val, _state->save_json_start, len);
3643 627 : val[len] = '\0';
3644 627 : hashentry->val = val;
3645 ECB : }
3646 : else
3647 : {
3648 : /* must have had a scalar instead */
3649 GIC 1293 : hashentry->val = _state->saved_scalar;
3650 ECB : }
3651 :
3652 GNC 1920 : return JSON_SUCCESS;
3653 : }
3654 :
3655 : static JsonParseErrorType
3656 CBC 636 : hash_array_start(void *state)
3657 : {
3658 636 : JHashState *_state = (JHashState *) state;
3659 :
3660 636 : if (_state->lex->lex_level == 0)
3661 3 : ereport(ERROR,
3662 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3663 : errmsg("cannot call %s on an array", _state->function_name)));
3664 :
3665 GNC 633 : return JSON_SUCCESS;
3666 ECB : }
3667 :
3668 : static JsonParseErrorType
3669 CBC 3690 : hash_scalar(void *state, char *token, JsonTokenType tokentype)
3670 : {
3671 GIC 3690 : JHashState *_state = (JHashState *) state;
3672 ECB :
3673 GIC 3690 : if (_state->lex->lex_level == 0)
3674 6 : ereport(ERROR,
3675 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3676 : errmsg("cannot call %s on a scalar", _state->function_name)));
3677 ECB :
3678 GIC 3684 : if (_state->lex->lex_level == 1)
3679 : {
3680 CBC 1293 : _state->saved_scalar = token;
3681 : /* saved_token_type must already be set in hash_object_field_start() */
3682 GIC 1293 : Assert(_state->saved_token_type == tokentype);
3683 : }
3684 :
3685 GNC 3684 : return JSON_SUCCESS;
3686 ECB : }
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 GIC 75 : jsonb_populate_recordset(PG_FUNCTION_ARGS)
3701 : {
3702 75 : return populate_recordset_worker(fcinfo, "jsonb_populate_recordset",
3703 : false, true);
3704 : }
3705 ECB :
3706 EUB : Datum
3707 GIC 9 : jsonb_to_recordset(PG_FUNCTION_ARGS)
3708 ECB : {
3709 GIC 9 : return populate_recordset_worker(fcinfo, "jsonb_to_recordset",
3710 : false, false);
3711 : }
3712 :
3713 : Datum
3714 78 : json_populate_recordset(PG_FUNCTION_ARGS)
3715 ECB : {
3716 CBC 78 : return populate_recordset_worker(fcinfo, "json_populate_recordset",
3717 : true, true);
3718 ECB : }
3719 :
3720 : Datum
3721 CBC 9 : json_to_recordset(PG_FUNCTION_ARGS)
3722 : {
3723 9 : return populate_recordset_worker(fcinfo, "json_to_recordset",
3724 ECB : true, false);
3725 : }
3726 :
3727 : static void
3728 GIC 240 : populate_recordset_record(PopulateRecordsetState *state, JsObject *obj)
3729 : {
3730 CBC 240 : PopulateRecordCache *cache = state->cache;
3731 : HeapTupleHeader tuphead;
3732 : HeapTupleData tuple;
3733 ECB :
3734 : /* acquire/update cached tuple descriptor */
3735 GIC 240 : update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
3736 :
3737 ECB : /* replace record fields from json */
3738 GIC 240 : tuphead = populate_record(cache->c.io.composite.tupdesc,
3739 ECB : &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 GIC 234 : if (cache->c.typcat == TYPECAT_COMPOSITE_DOMAIN)
3746 CBC 24 : domain_check(HeapTupleHeaderGetDatum(tuphead), false,
3747 : cache->argtype,
3748 : &cache->c.io.composite.domain_info,
3749 : cache->fn_mcxt);
3750 ECB :
3751 : /* ok, save into tuplestore */
3752 CBC 228 : tuple.t_len = HeapTupleHeaderGetDatumLength(tuphead);
3753 GIC 228 : ItemPointerSetInvalid(&(tuple.t_self));
3754 CBC 228 : tuple.t_tableOid = InvalidOid;
3755 228 : tuple.t_data = tuphead;
3756 :
3757 GIC 228 : tuplestore_puttuple(state->tuple_store, &tuple);
3758 228 : }
3759 ECB :
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 GIC 171 : populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
3766 ECB : bool is_json, bool have_record_arg)
3767 : {
3768 GIC 171 : int json_arg_num = have_record_arg ? 1 : 0;
3769 : ReturnSetInfo *rsi;
3770 : MemoryContext old_cxt;
3771 : HeapTupleHeader rec;
3772 171 : PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
3773 : PopulateRecordsetState *state;
3774 :
3775 171 : rsi = (ReturnSetInfo *) fcinfo->resultinfo;
3776 :
3777 171 : if (!rsi || !IsA(rsi, ReturnSetInfo))
3778 UIC 0 : ereport(ERROR,
3779 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3780 : errmsg("set-valued function called in context that cannot accept a set")));
3781 ECB :
3782 GIC 171 : if (!(rsi->allowedModes & SFRM_Materialize))
3783 LBC 0 : ereport(ERROR,
3784 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3785 : errmsg("materialize mode required, but it is not allowed in this context")));
3786 :
3787 GIC 171 : rsi->returnMode = SFRM_Materialize;
3788 ECB :
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 GIC 171 : if (!cache)
3795 ECB : {
3796 GIC 165 : fcinfo->flinfo->fn_extra = cache =
3797 CBC 165 : MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, sizeof(*cache));
3798 GIC 165 : cache->fn_mcxt = fcinfo->flinfo->fn_mcxt;
3799 :
3800 165 : if (have_record_arg)
3801 147 : get_record_type_from_argument(fcinfo, funcname, cache);
3802 ECB : else
3803 GIC 18 : get_record_type_from_query(fcinfo, funcname, cache);
3804 ECB : }
3805 :
3806 : /* Collect record arg if we have one */
3807 GIC 171 : if (!have_record_arg)
3808 18 : rec = NULL; /* it's json{b}_to_recordset() */
3809 CBC 153 : else if (!PG_ARGISNULL(0))
3810 : {
3811 96 : rec = PG_GETARG_HEAPTUPLEHEADER(0);
3812 :
3813 : /*
3814 : * When declared arg type is RECORD, identify actual record type from
3815 : * the tuple itself.
3816 ECB : */
3817 GIC 96 : if (cache->argtype == RECORDOID)
3818 : {
3819 CBC 48 : cache->c.io.composite.base_typid = HeapTupleHeaderGetTypeId(rec);
3820 GIC 48 : cache->c.io.composite.base_typmod = HeapTupleHeaderGetTypMod(rec);
3821 : }
3822 : }
3823 : else
3824 : {
3825 57 : rec = NULL;
3826 ECB :
3827 : /*
3828 : * When declared arg type is RECORD, identify actual record type from
3829 : * calling query, or fail if we can't.
3830 : */
3831 GIC 57 : if (cache->argtype == RECORDOID)
3832 : {
3833 CBC 24 : get_record_type_from_query(fcinfo, funcname, cache);
3834 ECB : /* This can't change argtype, which is important for next time */
3835 CBC 12 : Assert(cache->argtype == RECORDOID);
3836 ECB : }
3837 : }
3838 :
3839 : /* if the json is null send back an empty set */
3840 GIC 159 : if (PG_ARGISNULL(json_arg_num))
3841 UIC 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 ECB : */
3847 GIC 159 : update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
3848 :
3849 CBC 159 : state = palloc0(sizeof(PopulateRecordsetState));
3850 :
3851 : /* make tuplestore in a sufficiently long-lived memory context */
3852 GIC 159 : old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
3853 CBC 159 : state->tuple_store = tuplestore_begin_heap(rsi->allowedModes &
3854 : SFRM_Materialize_Random,
3855 : false, work_mem);
3856 159 : MemoryContextSwitchTo(old_cxt);
3857 :
3858 159 : state->function_name = funcname;
3859 GBC 159 : state->cache = cache;
3860 GIC 159 : state->rec = rec;
3861 :
3862 159 : if (is_json)
3863 ECB : {
3864 GBC 81 : text *json = PG_GETARG_TEXT_PP(json_arg_num);
3865 : JsonLexContext *lex;
3866 : JsonSemAction *sem;
3867 :
3868 CBC 81 : sem = palloc0(sizeof(JsonSemAction));
3869 :
3870 GIC 81 : lex = makeJsonLexContext(json, true);
3871 :
3872 81 : sem->semstate = (void *) state;
3873 81 : sem->array_start = populate_recordset_array_start;
3874 81 : sem->array_element_start = populate_recordset_array_element_start;
3875 CBC 81 : sem->scalar = populate_recordset_scalar;
3876 GIC 81 : sem->object_field_start = populate_recordset_object_field_start;
3877 CBC 81 : sem->object_field_end = populate_recordset_object_field_end;
3878 81 : sem->object_start = populate_recordset_object_start;
3879 81 : sem->object_end = populate_recordset_object_end;
3880 :
3881 81 : state->lex = lex;
3882 ECB :
3883 GIC 81 : pg_parse_json_or_ereport(lex, sem);
3884 ECB : }
3885 : else
3886 : {
3887 GIC 78 : Jsonb *jb = PG_GETARG_JSONB_P(json_arg_num);
3888 ECB : JsonbIterator *it;
3889 : JsonbValue v;
3890 CBC 78 : bool skipNested = false;
3891 : JsonbIteratorToken r;
3892 ECB :
3893 GIC 78 : if (JB_ROOT_IS_SCALAR(jb) || !JB_ROOT_IS_ARRAY(jb))
3894 UIC 0 : ereport(ERROR,
3895 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3896 : errmsg("cannot call %s on a non-array",
3897 : funcname)));
3898 ECB :
3899 GIC 78 : it = JsonbIteratorInit(&jb->root);
3900 ECB :
3901 CBC 339 : while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
3902 : {
3903 GIC 267 : skipNested = true;
3904 :
3905 267 : if (r == WJB_ELEM)
3906 ECB : {
3907 : JsObject obj;
3908 :
3909 GIC 117 : if (v.type != jbvBinary ||
3910 117 : !JsonContainerIsObject(v.val.binary.data))
3911 UIC 0 : ereport(ERROR,
3912 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3913 : errmsg("argument of %s must be an array of objects",
3914 : funcname)));
3915 :
3916 CBC 117 : obj.is_json = false;
3917 GIC 117 : obj.val.jsonb_cont = v.val.binary.data;
3918 :
3919 117 : populate_recordset_record(state, &obj);
3920 : }
3921 ECB : }
3922 EUB : }
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 ECB : */
3929 GIC 147 : rsi->setResult = state->tuple_store;
3930 CBC 147 : rsi->setDesc = CreateTupleDescCopy(cache->c.io.composite.tupdesc);
3931 :
3932 GIC 147 : PG_RETURN_NULL();
3933 ECB : }
3934 :
3935 : static JsonParseErrorType
3936 GIC 141 : populate_recordset_object_start(void *state)
3937 ECB : {
3938 GIC 141 : PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
3939 CBC 141 : int lex_level = _state->lex->lex_level;
3940 ECB : HASHCTL ctl;
3941 :
3942 : /* Reject object at top level: we must have an array at level 0 */
3943 CBC 141 : if (lex_level == 0)
3944 UIC 0 : ereport(ERROR,
3945 ECB : (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 GIC 141 : if (lex_level > 1)
3951 GNC 18 : return JSON_SUCCESS;
3952 :
3953 ECB : /* Object at level 1: set up a new hash table for this object */
3954 CBC 123 : ctl.keysize = NAMEDATALEN;
3955 123 : ctl.entrysize = sizeof(JsonHashEntry);
3956 123 : ctl.hcxt = CurrentMemoryContext;
3957 123 : _state->json_hash = hash_create("json object hashtable",
3958 ECB : 100,
3959 : &ctl,
3960 : HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
3961 :
3962 GNC 123 : return JSON_SUCCESS;
3963 : }
3964 ECB :
3965 : static JsonParseErrorType
3966 CBC 141 : populate_recordset_object_end(void *state)
3967 : {
3968 GIC 141 : PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
3969 : JsObject obj;
3970 ECB :
3971 : /* Nested objects require no special processing */
3972 GIC 141 : if (_state->lex->lex_level > 1)
3973 GNC 18 : return JSON_SUCCESS;
3974 :
3975 GIC 123 : obj.is_json = true;
3976 CBC 123 : obj.val.json_hash = _state->json_hash;
3977 EUB :
3978 : /* Otherwise, construct and return a tuple based on this level-1 object */
3979 GIC 123 : populate_recordset_record(_state, &obj);
3980 :
3981 : /* Done with hash for this object */
3982 CBC 117 : hash_destroy(_state->json_hash);
3983 GIC 117 : _state->json_hash = NULL;
3984 :
3985 GNC 117 : return JSON_SUCCESS;
3986 ECB : }
3987 :
3988 : static JsonParseErrorType
3989 GIC 150 : populate_recordset_array_element_start(void *state, bool isnull)
3990 ECB : {
3991 GIC 150 : PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
3992 :
3993 150 : if (_state->lex->lex_level == 1 &&
3994 CBC 123 : _state->lex->token_type != JSON_TOKEN_OBJECT_START)
3995 LBC 0 : ereport(ERROR,
3996 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3997 : errmsg("argument of %s must be an array of objects",
3998 : _state->function_name)));
3999 :
4000 GNC 150 : return JSON_SUCCESS;
4001 : }
4002 :
4003 : static JsonParseErrorType
4004 CBC 90 : populate_recordset_array_start(void *state)
4005 : {
4006 ECB : /* nothing to do */
4007 GNC 90 : return JSON_SUCCESS;
4008 : }
4009 :
4010 : static JsonParseErrorType
4011 GIC 258 : populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
4012 : {
4013 258 : PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
4014 :
4015 258 : if (_state->lex->lex_level == 0)
4016 UIC 0 : ereport(ERROR,
4017 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4018 : errmsg("cannot call %s on a scalar",
4019 : _state->function_name)));
4020 :
4021 GIC 258 : if (_state->lex->lex_level == 2)
4022 210 : _state->saved_scalar = token;
4023 :
4024 GNC 258 : return JSON_SUCCESS;
4025 : }
4026 ECB :
4027 : static JsonParseErrorType
4028 CBC 258 : populate_recordset_object_field_start(void *state, char *fname, bool isnull)
4029 ECB : {
4030 GIC 258 : PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
4031 :
4032 258 : if (_state->lex->lex_level > 2)
4033 GNC 21 : return JSON_SUCCESS;
4034 EUB :
4035 GIC 237 : _state->saved_token_type = _state->lex->token_type;
4036 :
4037 237 : if (_state->lex->token_type == JSON_TOKEN_ARRAY_START ||
4038 228 : _state->lex->token_type == JSON_TOKEN_OBJECT_START)
4039 : {
4040 CBC 27 : _state->save_json_start = _state->lex->token_start;
4041 ECB : }
4042 : else
4043 : {
4044 CBC 210 : _state->save_json_start = NULL;
4045 ECB : }
4046 :
4047 GNC 237 : return JSON_SUCCESS;
4048 ECB : }
4049 :
4050 : static JsonParseErrorType
4051 GIC 258 : populate_recordset_object_field_end(void *state, char *fname, bool isnull)
4052 : {
4053 258 : PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
4054 ECB : JsonHashEntry *hashentry;
4055 : bool found;
4056 :
4057 : /*
4058 : * Ignore nested fields.
4059 : */
4060 CBC 258 : if (_state->lex->lex_level > 2)
4061 GNC 21 : return JSON_SUCCESS;
4062 :
4063 : /*
4064 ECB : * 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 GIC 237 : if (strlen(fname) >= NAMEDATALEN)
4071 UNC 0 : return JSON_SUCCESS;
4072 :
4073 GIC 237 : hashentry = hash_search(_state->json_hash, fname, HASH_ENTER, &found);
4074 ECB :
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 GIC 237 : hashentry->type = _state->saved_token_type;
4081 CBC 237 : Assert(isnull == (hashentry->type == JSON_TOKEN_NULL));
4082 :
4083 237 : if (_state->save_json_start != NULL)
4084 : {
4085 27 : int len = _state->lex->prev_token_terminator - _state->save_json_start;
4086 27 : char *val = palloc((len + 1) * sizeof(char));
4087 EUB :
4088 GIC 27 : memcpy(val, _state->save_json_start, len);
4089 27 : val[len] = '\0';
4090 27 : hashentry->val = val;
4091 : }
4092 ECB : else
4093 : {
4094 : /* must have had a scalar instead */
4095 GIC 210 : hashentry->val = _state->saved_scalar;
4096 ECB : }
4097 :
4098 GNC 237 : return JSON_SUCCESS;
4099 : }
4100 :
4101 ECB : /*
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 GIC 18 : sn_object_start(void *state)
4112 : {
4113 18 : StripnullState *_state = (StripnullState *) state;
4114 :
4115 CBC 18 : appendStringInfoCharMacro(_state->strval, '{');
4116 :
4117 GNC 18 : return JSON_SUCCESS;
4118 ECB : }
4119 :
4120 : static JsonParseErrorType
4121 GIC 18 : sn_object_end(void *state)
4122 : {
4123 18 : StripnullState *_state = (StripnullState *) state;
4124 ECB :
4125 GIC 18 : appendStringInfoCharMacro(_state->strval, '}');
4126 :
4127 GNC 18 : return JSON_SUCCESS;
4128 ECB : }
4129 :
4130 : static JsonParseErrorType
4131 CBC 9 : sn_array_start(void *state)
4132 : {
4133 9 : StripnullState *_state = (StripnullState *) state;
4134 :
4135 9 : appendStringInfoCharMacro(_state->strval, '[');
4136 :
4137 GNC 9 : return JSON_SUCCESS;
4138 ECB : }
4139 :
4140 : static JsonParseErrorType
4141 GIC 9 : sn_array_end(void *state)
4142 : {
4143 9 : StripnullState *_state = (StripnullState *) state;
4144 ECB :
4145 GIC 9 : appendStringInfoCharMacro(_state->strval, ']');
4146 :
4147 GNC 9 : return JSON_SUCCESS;
4148 : }
4149 ECB :
4150 : static JsonParseErrorType
4151 GIC 39 : sn_object_field_start(void *state, char *fname, bool isnull)
4152 : {
4153 CBC 39 : StripnullState *_state = (StripnullState *) state;
4154 :
4155 39 : 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 15 : _state->skip_next_null = true;
4163 GNC 15 : return JSON_SUCCESS;
4164 : }
4165 :
4166 GIC 24 : if (_state->strval->data[_state->strval->len - 1] != '{')
4167 12 : 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 ECB : */
4173 GBC 24 : escape_json(_state->strval, fname);
4174 :
4175 CBC 24 : appendStringInfoCharMacro(_state->strval, ':');
4176 :
4177 GNC 24 : return JSON_SUCCESS;
4178 : }
4179 :
4180 : static JsonParseErrorType
4181 GIC 33 : sn_array_element_start(void *state, bool isnull)
4182 : {
4183 33 : StripnullState *_state = (StripnullState *) state;
4184 ECB :
4185 CBC 33 : if (_state->strval->data[_state->strval->len - 1] != '[')
4186 GIC 24 : appendStringInfoCharMacro(_state->strval, ',');
4187 :
4188 GNC 33 : return JSON_SUCCESS;
4189 ECB : }
4190 :
4191 : static JsonParseErrorType
4192 CBC 66 : sn_scalar(void *state, char *token, JsonTokenType tokentype)
4193 : {
4194 66 : StripnullState *_state = (StripnullState *) state;
4195 ECB :
4196 CBC 66 : if (_state->skip_next_null)
4197 : {
4198 GIC 15 : Assert(tokentype == JSON_TOKEN_NULL);
4199 15 : _state->skip_next_null = false;
4200 GNC 15 : return JSON_SUCCESS;
4201 ECB : }
4202 :
4203 GIC 51 : if (tokentype == JSON_TOKEN_STRING)
4204 CBC 3 : escape_json(_state->strval, token);
4205 : else
4206 GIC 48 : appendStringInfoString(_state->strval, token);
4207 :
4208 GNC 51 : return JSON_SUCCESS;
4209 : }
4210 :
4211 : /*
4212 : * SQL function json_strip_nulls(json) -> json
4213 : */
4214 : Datum
4215 GIC 21 : json_strip_nulls(PG_FUNCTION_ARGS)
4216 : {
4217 21 : text *json = PG_GETARG_TEXT_PP(0);
4218 : StripnullState *state;
4219 ECB : JsonLexContext *lex;
4220 : JsonSemAction *sem;
4221 :
4222 GIC 21 : lex = makeJsonLexContext(json, true);
4223 CBC 21 : state = palloc0(sizeof(StripnullState));
4224 GIC 21 : sem = palloc0(sizeof(JsonSemAction));
4225 ECB :
4226 GIC 21 : state->strval = makeStringInfo();
4227 21 : state->skip_next_null = false;
4228 21 : state->lex = lex;
4229 ECB :
4230 GIC 21 : sem->semstate = (void *) state;
4231 CBC 21 : sem->object_start = sn_object_start;
4232 GIC 21 : sem->object_end = sn_object_end;
4233 CBC 21 : sem->array_start = sn_array_start;
4234 GIC 21 : sem->array_end = sn_array_end;
4235 CBC 21 : sem->scalar = sn_scalar;
4236 GIC 21 : sem->array_element_start = sn_array_element_start;
4237 21 : sem->object_field_start = sn_object_field_start;
4238 :
4239 CBC 21 : pg_parse_json_or_ereport(lex, sem);
4240 :
4241 21 : PG_RETURN_TEXT_P(cstring_to_text_with_len(state->strval->data,
4242 : state->strval->len));
4243 ECB : }
4244 :
4245 : /*
4246 : * SQL function jsonb_strip_nulls(jsonb) -> jsonb
4247 : */
4248 : Datum
4249 CBC 21 : jsonb_strip_nulls(PG_FUNCTION_ARGS)
4250 : {
4251 21 : Jsonb *jb = PG_GETARG_JSONB_P(0);
4252 : JsonbIterator *it;
4253 21 : JsonbParseState *parseState = NULL;
4254 GIC 21 : JsonbValue *res = NULL;
4255 ECB : JsonbValue v,
4256 : k;
4257 : JsonbIteratorToken type;
4258 GIC 21 : bool last_was_key = false;
4259 ECB :
4260 GIC 21 : if (JB_ROOT_IS_SCALAR(jb))
4261 CBC 9 : PG_RETURN_POINTER(jb);
4262 :
4263 12 : it = JsonbIteratorInit(&jb->root);
4264 :
4265 GIC 162 : while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
4266 : {
4267 150 : Assert(!(type == WJB_KEY && last_was_key));
4268 :
4269 150 : if (type == WJB_KEY)
4270 ECB : {
4271 : /* stash the key until we know if it has a null value */
4272 GIC 39 : k = v;
4273 39 : last_was_key = true;
4274 CBC 39 : continue;
4275 ECB : }
4276 :
4277 GIC 111 : if (last_was_key)
4278 : {
4279 : /* if the last element was a key this one can't be */
4280 39 : last_was_key = false;
4281 ECB :
4282 : /* skip this field if value is null */
4283 CBC 39 : if (type == WJB_VALUE && v.type == jbvNull)
4284 GIC 15 : continue;
4285 ECB :
4286 : /* otherwise, do a delayed push of the key */
4287 GIC 24 : (void) pushJsonbValue(&parseState, WJB_KEY, &k);
4288 : }
4289 ECB :
4290 GIC 96 : if (type == WJB_VALUE || type == WJB_ELEM)
4291 CBC 42 : res = pushJsonbValue(&parseState, type, &v);
4292 : else
4293 54 : res = pushJsonbValue(&parseState, type, NULL);
4294 ECB : }
4295 :
4296 CBC 12 : Assert(res != NULL);
4297 :
4298 GIC 12 : PG_RETURN_POINTER(JsonbValueToJsonb(res));
4299 : }
4300 ECB :
4301 : /*
4302 : * SQL function jsonb_pretty (jsonb)
4303 : *
4304 : * Pretty-printed text for the jsonb
4305 : */
4306 : Datum
4307 CBC 18 : jsonb_pretty(PG_FUNCTION_ARGS)
4308 ECB : {
4309 GIC 18 : Jsonb *jb = PG_GETARG_JSONB_P(0);
4310 18 : StringInfo str = makeStringInfo();
4311 ECB :
4312 CBC 18 : JsonbToCStringIndent(str, &jb->root, VARSIZE(jb));
4313 :
4314 18 : PG_RETURN_TEXT_P(cstring_to_text_with_len(str->data, str->len));
4315 : }
4316 ECB :
4317 : /*
4318 : * SQL function jsonb_concat (jsonb, jsonb)
4319 : *
4320 : * function for || operator
4321 : */
4322 : Datum
4323 CBC 189 : jsonb_concat(PG_FUNCTION_ARGS)
4324 : {
4325 189 : Jsonb *jb1 = PG_GETARG_JSONB_P(0);
4326 GIC 189 : Jsonb *jb2 = PG_GETARG_JSONB_P(1);
4327 189 : JsonbParseState *state = NULL;
4328 : JsonbValue *res;
4329 : JsonbIterator *it1,
4330 ECB : *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 CBC 189 : if (JB_ROOT_IS_OBJECT(jb1) == JB_ROOT_IS_OBJECT(jb2))
4339 ECB : {
4340 CBC 147 : if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
4341 99 : PG_RETURN_JSONB_P(jb2);
4342 48 : else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
4343 6 : PG_RETURN_JSONB_P(jb1);
4344 ECB : }
4345 :
4346 GIC 84 : it1 = JsonbIteratorInit(&jb1->root);
4347 CBC 84 : it2 = JsonbIteratorInit(&jb2->root);
4348 :
4349 84 : res = IteratorConcat(&it1, &it2, &state);
4350 :
4351 GIC 84 : Assert(res != NULL);
4352 :
4353 84 : PG_RETURN_JSONB_P(JsonbValueToJsonb(res));
4354 : }
4355 :
4356 :
4357 ECB : /*
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 GIC 90 : jsonb_delete(PG_FUNCTION_ARGS)
4365 : {
4366 CBC 90 : Jsonb *in = PG_GETARG_JSONB_P(0);
4367 GIC 90 : text *key = PG_GETARG_TEXT_PP(1);
4368 CBC 90 : char *keyptr = VARDATA_ANY(key);
4369 90 : int keylen = VARSIZE_ANY_EXHDR(key);
4370 GIC 90 : JsonbParseState *state = NULL;
4371 ECB : JsonbIterator *it;
4372 : JsonbValue v,
4373 CBC 90 : *res = NULL;
4374 GIC 90 : bool skipNested = false;
4375 ECB : JsonbIteratorToken r;
4376 :
4377 CBC 90 : if (JB_ROOT_IS_SCALAR(in))
4378 GIC 3 : ereport(ERROR,
4379 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4380 ECB : errmsg("cannot delete from scalar")));
4381 :
4382 CBC 87 : if (JB_ROOT_COUNT(in) == 0)
4383 GIC 6 : PG_RETURN_JSONB_P(in);
4384 :
4385 CBC 81 : it = JsonbIteratorInit(&in->root);
4386 :
4387 GIC 1074 : while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4388 ECB : {
4389 GIC 993 : skipNested = true;
4390 :
4391 CBC 993 : if ((r == WJB_ELEM || r == WJB_KEY) &&
4392 453 : (v.type == jbvString && keylen == v.val.string.len &&
4393 GIC 147 : memcmp(keyptr, v.val.string.val, keylen) == 0))
4394 : {
4395 ECB : /* skip corresponding value as well */
4396 GIC 75 : if (r == WJB_KEY)
4397 75 : (void) JsonbIteratorNext(&it, &v, true);
4398 ECB :
4399 CBC 75 : continue;
4400 : }
4401 ECB :
4402 GIC 918 : res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4403 : }
4404 ECB :
4405 GIC 81 : Assert(res != NULL);
4406 ECB :
4407 GIC 81 : 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 ECB : */
4416 : Datum
4417 CBC 9 : jsonb_delete_array(PG_FUNCTION_ARGS)
4418 ECB : {
4419 GIC 9 : Jsonb *in = PG_GETARG_JSONB_P(0);
4420 CBC 9 : ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
4421 : Datum *keys_elems;
4422 ECB : bool *keys_nulls;
4423 : int keys_len;
4424 GIC 9 : JsonbParseState *state = NULL;
4425 : JsonbIterator *it;
4426 : JsonbValue v,
4427 9 : *res = NULL;
4428 9 : bool skipNested = false;
4429 : JsonbIteratorToken r;
4430 :
4431 CBC 9 : if (ARR_NDIM(keys) > 1)
4432 UIC 0 : ereport(ERROR,
4433 ECB : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4434 : errmsg("wrong number of array subscripts")));
4435 :
4436 GIC 9 : if (JB_ROOT_IS_SCALAR(in))
4437 UIC 0 : ereport(ERROR,
4438 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4439 : errmsg("cannot delete from scalar")));
4440 :
4441 GIC 9 : if (JB_ROOT_COUNT(in) == 0)
4442 UIC 0 : PG_RETURN_JSONB_P(in);
4443 :
4444 GNC 9 : deconstruct_array_builtin(keys, TEXTOID, &keys_elems, &keys_nulls, &keys_len);
4445 ECB :
4446 GIC 9 : if (keys_len == 0)
4447 CBC 3 : PG_RETURN_JSONB_P(in);
4448 ECB :
4449 CBC 6 : it = JsonbIteratorInit(&in->root);
4450 ECB :
4451 GIC 45 : while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
4452 : {
4453 CBC 39 : skipNested = true;
4454 ECB :
4455 GIC 39 : if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString)
4456 ECB : {
4457 : int i;
4458 CBC 18 : bool found = false;
4459 :
4460 33 : for (i = 0; i < keys_len; i++)
4461 : {
4462 : char *keyptr;
4463 : int keylen;
4464 :
4465 GIC 24 : if (keys_nulls[i])
4466 UIC 0 : continue;
4467 :
4468 : /* We rely on the array elements not being toasted */
4469 GIC 24 : keyptr = VARDATA_ANY(keys_elems[i]);
4470 24 : keylen = VARSIZE_ANY_EXHDR(keys_elems[i]);
4471 CBC 24 : if (keylen == v.val.string.len &&
4472 GIC 24 : memcmp(keyptr, v.val.string.val, keylen) == 0)
4473 ECB : {
4474 CBC 9 : found = true;
4475 9 : break;
4476 ECB : }
4477 : }
4478 GIC 18 : if (found)
4479 : {
4480 ECB : /* skip corresponding value as well */
4481 CBC 9 : if (r == WJB_KEY)
4482 GIC 9 : (void) JsonbIteratorNext(&it, &v, true);
4483 :
4484 CBC 9 : continue;
4485 ECB : }
4486 : }
4487 :
4488 GIC 30 : res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4489 ECB : }
4490 :
4491 GIC 6 : Assert(res != NULL);
4492 ECB :
4493 GIC 6 : PG_RETURN_JSONB_P(JsonbValueToJsonb(res));
4494 ECB : }
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 CBC 129 : jsonb_delete_idx(PG_FUNCTION_ARGS)
4505 : {
4506 129 : Jsonb *in = PG_GETARG_JSONB_P(0);
4507 GIC 129 : int idx = PG_GETARG_INT32(1);
4508 129 : JsonbParseState *state = NULL;
4509 ECB : JsonbIterator *it;
4510 GIC 129 : uint32 i = 0,
4511 : n;
4512 ECB : JsonbValue v,
4513 GIC 129 : *res = NULL;
4514 ECB : JsonbIteratorToken r;
4515 :
4516 GIC 129 : if (JB_ROOT_IS_SCALAR(in))
4517 3 : ereport(ERROR,
4518 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4519 : errmsg("cannot delete from scalar")));
4520 :
4521 126 : if (JB_ROOT_IS_OBJECT(in))
4522 3 : ereport(ERROR,
4523 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4524 ECB : errmsg("cannot delete from object using integer index")));
4525 :
4526 CBC 123 : if (JB_ROOT_COUNT(in) == 0)
4527 3 : PG_RETURN_JSONB_P(in);
4528 :
4529 GIC 120 : it = JsonbIteratorInit(&in->root);
4530 :
4531 CBC 120 : r = JsonbIteratorNext(&it, &v, false);
4532 GIC 120 : Assert(r == WJB_BEGIN_ARRAY);
4533 120 : n = v.val.array.nElems;
4534 ECB :
4535 CBC 120 : if (idx < 0)
4536 : {
4537 GIC 12 : if (-idx > n)
4538 CBC 3 : idx = n;
4539 EUB : else
4540 GIC 9 : idx = n + idx;
4541 : }
4542 :
4543 CBC 120 : if (idx >= n)
4544 GBC 6 : PG_RETURN_JSONB_P(in);
4545 :
4546 GIC 114 : pushJsonbValue(&state, r, NULL);
4547 :
4548 CBC 378 : while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
4549 EUB : {
4550 GIC 264 : if (r == WJB_ELEM)
4551 ECB : {
4552 GIC 150 : if (i++ == idx)
4553 CBC 114 : continue;
4554 ECB : }
4555 :
4556 CBC 150 : res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
4557 : }
4558 ECB :
4559 GIC 114 : Assert(res != NULL);
4560 ECB :
4561 GIC 114 : PG_RETURN_JSONB_P(JsonbValueToJsonb(res));
4562 ECB : }
4563 :
4564 : /*
4565 : * SQL function jsonb_set(jsonb, text[], jsonb, boolean)
4566 : */
4567 : Datum
4568 GIC 144 : jsonb_set(PG_FUNCTION_ARGS)
4569 : {
4570 144 : Jsonb *in = PG_GETARG_JSONB_P(0);
4571 144 : ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
4572 CBC 144 : Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
4573 EUB : JsonbValue newval;
4574 GIC 144 : bool create = PG_GETARG_BOOL(3);
4575 144 : JsonbValue *res = NULL;
4576 ECB : Datum *path_elems;
4577 : bool *path_nulls;
4578 : int path_len;
4579 : JsonbIterator *it;
4580 GIC 144 : JsonbParseState *st = NULL;
4581 ECB :
4582 CBC 144 : JsonbToJsonbValue(newjsonb, &newval);
4583 :
4584 GIC 144 : if (ARR_NDIM(path) > 1)
4585 LBC 0 : ereport(ERROR,
4586 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4587 : errmsg("wrong number of array subscripts")));
4588 ECB :
4589 CBC 144 : if (JB_ROOT_IS_SCALAR(in))
4590 GIC 3 : ereport(ERROR,
4591 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4592 : errmsg("cannot set path in scalar")));
4593 :
4594 GIC 141 : if (JB_ROOT_COUNT(in) == 0 && !create)
4595 CBC 6 : PG_RETURN_JSONB_P(in);
4596 :
4597 GNC 135 : deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4598 :
4599 CBC 135 : if (path_len == 0)
4600 UIC 0 : PG_RETURN_JSONB_P(in);
4601 :
4602 GIC 135 : it = JsonbIteratorInit(&in->root);
4603 :
4604 135 : res = setPath(&it, path_elems, path_nulls, path_len, &st,
4605 : 0, &newval, create ? JB_PATH_CREATE : JB_PATH_REPLACE);
4606 :
4607 120 : Assert(res != NULL);
4608 :
4609 120 : PG_RETURN_JSONB_P(JsonbValueToJsonb(res));
4610 ECB : }
4611 :
4612 :
4613 : /*
4614 : * SQL function jsonb_set_lax(jsonb, text[], jsonb, boolean, text)
4615 : */
4616 : Datum
4617 GIC 30 : jsonb_set_lax(PG_FUNCTION_ARGS)
4618 : {
4619 ECB : /* 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 GIC 30 : if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
4627 LBC 0 : PG_RETURN_NULL();
4628 ECB :
4629 : /* could happen if they pass in an explicit NULL */
4630 GIC 30 : if (PG_ARGISNULL(4))
4631 3 : ereport(ERROR,
4632 ECB : (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 GIC 27 : if (!PG_ARGISNULL(2))
4637 CBC 6 : return jsonb_set(fcinfo);
4638 ECB :
4639 CBC 21 : handle_null = PG_GETARG_TEXT_P(4);
4640 GIC 21 : handle_val = text_to_cstring(handle_null);
4641 ECB :
4642 GIC 21 : if (strcmp(handle_val, "raise_exception") == 0)
4643 ECB : {
4644 CBC 3 : ereport(ERROR,
4645 : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4646 ECB : 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 GIC 18 : else if (strcmp(handle_val, "use_json_null") == 0)
4652 ECB : {
4653 : Datum newval;
4654 :
4655 GIC 9 : newval = DirectFunctionCall1(jsonb_in, CStringGetDatum("null"));
4656 ECB :
4657 GIC 9 : fcinfo->args[2].value = newval;
4658 CBC 9 : fcinfo->args[2].isnull = false;
4659 9 : return jsonb_set(fcinfo);
4660 : }
4661 GIC 9 : else if (strcmp(handle_val, "delete_key") == 0)
4662 ECB : {
4663 GIC 3 : return jsonb_delete_path(fcinfo);
4664 : }
4665 CBC 6 : else if (strcmp(handle_val, "return_target") == 0)
4666 : {
4667 3 : Jsonb *in = PG_GETARG_JSONB_P(0);
4668 :
4669 GIC 3 : PG_RETURN_JSONB_P(in);
4670 : }
4671 : else
4672 : {
4673 3 : ereport(ERROR,
4674 ECB : (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 GIC 45 : jsonb_delete_path(PG_FUNCTION_ARGS)
4685 : {
4686 CBC 45 : Jsonb *in = PG_GETARG_JSONB_P(0);
4687 GIC 45 : ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
4688 CBC 45 : JsonbValue *res = NULL;
4689 : Datum *path_elems;
4690 ECB : bool *path_nulls;
4691 EUB : int path_len;
4692 : JsonbIterator *it;
4693 GIC 45 : JsonbParseState *st = NULL;
4694 :
4695 CBC 45 : if (ARR_NDIM(path) > 1)
4696 LBC 0 : ereport(ERROR,
4697 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4698 : errmsg("wrong number of array subscripts")));
4699 :
4700 CBC 45 : if (JB_ROOT_IS_SCALAR(in))
4701 3 : ereport(ERROR,
4702 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4703 ECB : errmsg("cannot delete path in scalar")));
4704 :
4705 CBC 42 : if (JB_ROOT_COUNT(in) == 0)
4706 GBC 6 : PG_RETURN_JSONB_P(in);
4707 :
4708 GNC 36 : deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4709 ECB :
4710 GIC 36 : if (path_len == 0)
4711 UIC 0 : PG_RETURN_JSONB_P(in);
4712 ECB :
4713 GIC 36 : it = JsonbIteratorInit(&in->root);
4714 ECB :
4715 GIC 36 : res = setPath(&it, path_elems, path_nulls, path_len, &st,
4716 : 0, NULL, JB_PATH_DELETE);
4717 :
4718 33 : Assert(res != NULL);
4719 :
4720 33 : PG_RETURN_JSONB_P(JsonbValueToJsonb(res));
4721 : }
4722 ECB :
4723 : /*
4724 : * SQL function jsonb_insert(jsonb, text[], jsonb, boolean)
4725 : */
4726 : Datum
4727 GIC 66 : jsonb_insert(PG_FUNCTION_ARGS)
4728 : {
4729 66 : Jsonb *in = PG_GETARG_JSONB_P(0);
4730 66 : ArrayType *path = PG_GETARG_ARRAYTYPE_P(1);
4731 CBC 66 : Jsonb *newjsonb = PG_GETARG_JSONB_P(2);
4732 EUB : JsonbValue newval;
4733 GIC 66 : bool after = PG_GETARG_BOOL(3);
4734 66 : JsonbValue *res = NULL;
4735 ECB : Datum *path_elems;
4736 : bool *path_nulls;
4737 : int path_len;
4738 : JsonbIterator *it;
4739 GIC 66 : JsonbParseState *st = NULL;
4740 :
4741 CBC 66 : JsonbToJsonbValue(newjsonb, &newval);
4742 ECB :
4743 GIC 66 : if (ARR_NDIM(path) > 1)
4744 LBC 0 : ereport(ERROR,
4745 ECB : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4746 : errmsg("wrong number of array subscripts")));
4747 :
4748 GIC 66 : if (JB_ROOT_IS_SCALAR(in))
4749 LBC 0 : ereport(ERROR,
4750 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4751 : errmsg("cannot set path in scalar")));
4752 :
4753 GNC 66 : deconstruct_array_builtin(path, TEXTOID, &path_elems, &path_nulls, &path_len);
4754 :
4755 CBC 66 : if (path_len == 0)
4756 UIC 0 : PG_RETURN_JSONB_P(in);
4757 :
4758 GIC 66 : it = JsonbIteratorInit(&in->root);
4759 ECB :
4760 GIC 66 : res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, &newval,
4761 ECB : after ? JB_PATH_INSERT_AFTER : JB_PATH_INSERT_BEFORE);
4762 :
4763 CBC 60 : Assert(res != NULL);
4764 :
4765 60 : PG_RETURN_JSONB_P(JsonbValueToJsonb(res));
4766 : }
4767 ECB :
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 GIC 84 : IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
4777 ECB : JsonbParseState **state)
4778 : {
4779 : JsonbValue v1,
4780 : v2,
4781 GIC 84 : *res = NULL;
4782 : JsonbIteratorToken r1,
4783 : r2,
4784 : rk1,
4785 : rk2;
4786 :
4787 84 : rk1 = JsonbIteratorNext(it1, &v1, false);
4788 CBC 84 : rk2 = JsonbIteratorNext(it2, &v2, false);
4789 :
4790 ECB : /*
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 GIC 84 : if (rk1 == WJB_BEGIN_OBJECT && rk2 == WJB_BEGIN_OBJECT)
4795 : {
4796 : /*
4797 ECB : * Both inputs are objects.
4798 : *
4799 : * Append all the tokens from v1 to res, except last WJB_END_OBJECT
4800 EUB : * (because res will not be finished yet).
4801 : */
4802 GIC 15 : pushJsonbValue(state, rk1, NULL);
4803 87 : while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_OBJECT)
4804 CBC 72 : pushJsonbValue(state, r1, &v1);
4805 ECB :
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 GIC 78 : while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
4812 CBC 63 : res = pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
4813 : }
4814 69 : else if (rk1 == WJB_BEGIN_ARRAY && rk2 == WJB_BEGIN_ARRAY)
4815 EUB : {
4816 : /*
4817 ECB : * Both inputs are arrays.
4818 : */
4819 CBC 27 : pushJsonbValue(state, rk1, NULL);
4820 :
4821 GIC 60 : while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
4822 ECB : {
4823 GIC 33 : Assert(r1 == WJB_ELEM);
4824 CBC 33 : pushJsonbValue(state, r1, &v1);
4825 : }
4826 :
4827 GIC 60 : while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_END_ARRAY)
4828 : {
4829 33 : Assert(r2 == WJB_ELEM);
4830 33 : pushJsonbValue(state, WJB_ELEM, &v2);
4831 ECB : }
4832 :
4833 CBC 27 : res = pushJsonbValue(state, WJB_END_ARRAY, NULL /* signal to sort */ );
4834 ECB : }
4835 CBC 42 : else if (rk1 == WJB_BEGIN_OBJECT)
4836 : {
4837 ECB : /*
4838 : * We have object || array.
4839 : */
4840 GIC 9 : Assert(rk2 == WJB_BEGIN_ARRAY);
4841 :
4842 9 : pushJsonbValue(state, WJB_BEGIN_ARRAY, NULL);
4843 ECB :
4844 GIC 9 : pushJsonbValue(state, WJB_BEGIN_OBJECT, NULL);
4845 CBC 36 : while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_DONE)
4846 GIC 27 : pushJsonbValue(state, r1, r1 != WJB_END_OBJECT ? &v1 : NULL);
4847 ECB :
4848 GBC 27 : while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
4849 GIC 18 : res = pushJsonbValue(state, r2, r2 != WJB_END_ARRAY ? &v2 : NULL);
4850 : }
4851 : else
4852 ECB : {
4853 EUB : /*
4854 : * We have array || object.
4855 : */
4856 GIC 33 : Assert(rk1 == WJB_BEGIN_ARRAY);
4857 CBC 33 : Assert(rk2 == WJB_BEGIN_OBJECT);
4858 :
4859 33 : pushJsonbValue(state, WJB_BEGIN_ARRAY, NULL);
4860 EUB :
4861 GIC 48 : while ((r1 = JsonbIteratorNext(it1, &v1, true)) != WJB_END_ARRAY)
4862 CBC 15 : pushJsonbValue(state, r1, &v1);
4863 :
4864 33 : pushJsonbValue(state, WJB_BEGIN_OBJECT, NULL);
4865 GIC 426 : while ((r2 = JsonbIteratorNext(it2, &v2, true)) != WJB_DONE)
4866 393 : pushJsonbValue(state, r2, r2 != WJB_END_OBJECT ? &v2 : NULL);
4867 ECB :
4868 GIC 33 : res = pushJsonbValue(state, WJB_END_ARRAY, NULL);
4869 ECB : }
4870 :
4871 GIC 84 : 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 ECB : * 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 GIC 657 : setPath(JsonbIterator **it, Datum *path_elems,
4905 : bool *path_nulls, int path_len,
4906 ECB : JsonbParseState **st, int level, JsonbValue *newval, int op_type)
4907 : {
4908 : JsonbValue v;
4909 : JsonbIteratorToken r;
4910 : JsonbValue *res;
4911 :
4912 GIC 657 : check_stack_depth();
4913 :
4914 657 : if (path_nulls[level])
4915 CBC 9 : ereport(ERROR,
4916 ECB : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4917 : errmsg("path element at position %d is null",
4918 : level + 1)));
4919 :
4920 GIC 648 : r = JsonbIteratorNext(it, &v, false);
4921 :
4922 648 : switch (r)
4923 ECB : {
4924 GIC 189 : case WJB_BEGIN_ARRAY:
4925 ECB :
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 GIC 189 : if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) &&
4933 CBC 45 : v.val.array.rawScalar)
4934 6 : ereport(ERROR,
4935 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4936 : errmsg("cannot replace existing key"),
4937 ECB : errdetail("The path assumes key is a composite object, "
4938 : "but it is a scalar value.")));
4939 :
4940 GIC 183 : (void) pushJsonbValue(st, r, NULL);
4941 183 : setPathArray(it, path_elems, path_nulls, path_len, st, level,
4942 183 : newval, v.val.array.nElems, op_type);
4943 171 : r = JsonbIteratorNext(it, &v, false);
4944 CBC 171 : Assert(r == WJB_END_ARRAY);
4945 GIC 171 : res = pushJsonbValue(st, r, NULL);
4946 CBC 171 : break;
4947 GIC 444 : case WJB_BEGIN_OBJECT:
4948 CBC 444 : (void) pushJsonbValue(st, r, NULL);
4949 444 : setPathObject(it, path_elems, path_nulls, path_len, st, level,
4950 444 : newval, v.val.object.nPairs, op_type);
4951 GIC 393 : r = JsonbIteratorNext(it, &v, true);
4952 CBC 393 : Assert(r == WJB_END_OBJECT);
4953 393 : res = pushJsonbValue(st, r, NULL);
4954 GIC 393 : break;
4955 15 : case WJB_ELEM:
4956 : case WJB_VALUE:
4957 :
4958 : /*
4959 : * If instructed complain about attempts to replace within a
4960 ECB : * 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 GIC 15 : if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1))
4965 CBC 15 : ereport(ERROR,
4966 ECB : (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 UIC 0 : res = pushJsonbValue(st, r, &v);
4972 LBC 0 : break;
4973 UIC 0 : default:
4974 0 : elog(ERROR, "unrecognized iterator result: %d", (int) r);
4975 ECB : res = NULL; /* keep compiler quiet */
4976 : break;
4977 : }
4978 :
4979 GIC 564 : return res;
4980 : }
4981 :
4982 : /*
4983 : * Object walker for setPath
4984 : */
4985 : static void
4986 444 : 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 444 : text *pathelem = NULL;
4991 : int i;
4992 : JsonbValue k,
4993 : v;
4994 444 : bool done = false;
4995 :
4996 444 : if (level >= path_len || path_nulls[level])
4997 UIC 0 : done = true;
4998 : else
4999 : {
5000 : /* The path Datum could be toasted, in which case we must detoast it */
5001 GIC 444 : pathelem = DatumGetTextPP(path_elems[level]);
5002 : }
5003 :
5004 : /* empty object is a special case for create */
5005 444 : if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
5006 27 : (level == path_len - 1))
5007 : {
5008 ECB : JsonbValue newkey;
5009 :
5010 GIC 9 : newkey.type = jbvString;
5011 9 : newkey.val.string.val = VARDATA_ANY(pathelem);
5012 9 : newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5013 :
5014 9 : (void) pushJsonbValue(st, WJB_KEY, &newkey);
5015 9 : (void) pushJsonbValue(st, WJB_VALUE, newval);
5016 ECB : }
5017 :
5018 CBC 2313 : for (i = 0; i < npairs; i++)
5019 ECB : {
5020 GIC 1920 : JsonbIteratorToken r = JsonbIteratorNext(it, &k, true);
5021 :
5022 1920 : Assert(r == WJB_KEY);
5023 :
5024 CBC 3033 : if (!done &&
5025 GIC 1113 : k.val.string.len == VARSIZE_ANY_EXHDR(pathelem) &&
5026 CBC 564 : memcmp(k.val.string.val, VARDATA_ANY(pathelem),
5027 GIC 564 : k.val.string.len) == 0)
5028 ECB : {
5029 GIC 345 : done = true;
5030 :
5031 345 : if (level == path_len - 1)
5032 : {
5033 : /*
5034 : * called from jsonb_insert(), it forbids redefining an
5035 : * existing value
5036 ECB : */
5037 CBC 84 : if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER))
5038 6 : 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 78 : r = JsonbIteratorNext(it, &v, true); /* skip value */
5045 78 : if (!(op_type & JB_PATH_DELETE))
5046 ECB : {
5047 CBC 57 : (void) pushJsonbValue(st, WJB_KEY, &k);
5048 57 : (void) pushJsonbValue(st, WJB_VALUE, newval);
5049 ECB : }
5050 : }
5051 : else
5052 : {
5053 CBC 261 : (void) pushJsonbValue(st, r, &k);
5054 261 : setPath(it, path_elems, path_nulls, path_len,
5055 ECB : st, level + 1, newval, op_type);
5056 : }
5057 : }
5058 : else
5059 : {
5060 GIC 1575 : if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done &&
5061 168 : level == path_len - 1 && i == npairs - 1)
5062 : {
5063 : JsonbValue newkey;
5064 :
5065 30 : newkey.type = jbvString;
5066 30 : newkey.val.string.val = VARDATA_ANY(pathelem);
5067 30 : newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5068 ECB :
5069 CBC 30 : (void) pushJsonbValue(st, WJB_KEY, &newkey);
5070 GIC 30 : (void) pushJsonbValue(st, WJB_VALUE, newval);
5071 : }
5072 :
5073 1575 : (void) pushJsonbValue(st, r, &k);
5074 1575 : r = JsonbIteratorNext(it, &v, false);
5075 GBC 1575 : (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5076 1575 : if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5077 EUB : {
5078 GBC 408 : int walking_level = 1;
5079 :
5080 GIC 3795 : while (walking_level != 0)
5081 : {
5082 3387 : r = JsonbIteratorNext(it, &v, false);
5083 ECB :
5084 GIC 3387 : if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5085 132 : ++walking_level;
5086 3387 : if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5087 540 : --walking_level;
5088 :
5089 3387 : (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5090 ECB : }
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 EUB : * 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 CBC 393 : if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5106 : {
5107 : JsonbValue newkey;
5108 :
5109 24 : newkey.type = jbvString;
5110 24 : newkey.val.string.val = VARDATA_ANY(pathelem);
5111 GIC 24 : newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
5112 :
5113 24 : (void) pushJsonbValue(st, WJB_KEY, &newkey);
5114 CBC 24 : (void) push_path(st, level, path_elems, path_nulls,
5115 ECB : path_len, newval);
5116 :
5117 : /* Result is closed with WJB_END_OBJECT outside of this function */
5118 : }
5119 CBC 393 : }
5120 :
5121 : /*
5122 ECB : * Array walker for setPath
5123 : */
5124 : static void
5125 GIC 183 : setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
5126 ECB : 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 GIC 183 : bool done = false;
5133 ECB :
5134 : /* pick correct index */
5135 CBC 183 : if (level < path_len && !path_nulls[level])
5136 GIC 174 : {
5137 183 : char *c = TextDatumGetCString(path_elems[level]);
5138 : char *badp;
5139 :
5140 183 : errno = 0;
5141 CBC 183 : idx = strtoint(c, &badp, 10);
5142 183 : if (badp == c || *badp != '\0' || errno != 0)
5143 GIC 9 : 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 ECB : else
5149 LBC 0 : idx = nelems;
5150 :
5151 CBC 174 : if (idx < 0)
5152 ECB : {
5153 GIC 39 : if (-idx > nelems)
5154 : {
5155 : /*
5156 : * If asked to keep elements position consistent, it's not allowed
5157 ECB : * to prepend the array.
5158 : */
5159 GIC 12 : if (op_type & JB_PATH_CONSISTENT_POSITION)
5160 3 : 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 ECB : else
5165 CBC 9 : idx = INT_MIN;
5166 : }
5167 : else
5168 GIC 27 : idx = nelems + idx;
5169 ECB : }
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 GIC 171 : if (!(op_type & JB_PATH_FILL_GAPS))
5176 : {
5177 CBC 135 : if (idx > 0 && idx > nelems)
5178 24 : idx = nelems;
5179 ECB : }
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 CBC 171 : if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) &&
5187 GIC 33 : (op_type & JB_PATH_CREATE_OR_INSERT))
5188 ECB : {
5189 CBC 33 : Assert(newval != NULL);
5190 ECB :
5191 CBC 33 : if (op_type & JB_PATH_FILL_GAPS && nelems == 0 && idx > 0)
5192 GIC 3 : push_null_elements(st, idx);
5193 ECB :
5194 GIC 33 : (void) pushJsonbValue(st, WJB_ELEM, newval);
5195 :
5196 33 : done = true;
5197 : }
5198 :
5199 : /* iterate over the array elements */
5200 483 : for (i = 0; i < nelems; i++)
5201 : {
5202 : JsonbIteratorToken r;
5203 :
5204 312 : if (i == idx && level < path_len)
5205 : {
5206 108 : done = true;
5207 :
5208 108 : if (level == path_len - 1)
5209 ECB : {
5210 GIC 72 : r = JsonbIteratorNext(it, &v, true); /* skip */
5211 :
5212 72 : if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_CREATE))
5213 CBC 42 : (void) pushJsonbValue(st, WJB_ELEM, newval);
5214 ECB :
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 GIC 72 : if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_INSERT_BEFORE))
5221 36 : (void) pushJsonbValue(st, r, &v);
5222 :
5223 CBC 72 : if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE))
5224 GIC 18 : (void) pushJsonbValue(st, WJB_ELEM, newval);
5225 : }
5226 : else
5227 36 : (void) setPath(it, path_elems, path_nulls, path_len,
5228 : st, level + 1, newval, op_type);
5229 ECB : }
5230 : else
5231 : {
5232 GIC 204 : r = JsonbIteratorNext(it, &v, false);
5233 :
5234 204 : (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5235 :
5236 CBC 204 : if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5237 : {
5238 GIC 3 : int walking_level = 1;
5239 ECB :
5240 CBC 12 : while (walking_level != 0)
5241 ECB : {
5242 GIC 9 : r = JsonbIteratorNext(it, &v, false);
5243 :
5244 CBC 9 : if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT)
5245 LBC 0 : ++walking_level;
5246 CBC 9 : if (r == WJB_END_ARRAY || r == WJB_END_OBJECT)
5247 3 : --walking_level;
5248 :
5249 GIC 9 : (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
5250 : }
5251 : }
5252 : }
5253 EUB : }
5254 :
5255 CBC 171 : if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1)
5256 : {
5257 ECB : /*
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 GIC 18 : if (op_type & JB_PATH_FILL_GAPS && idx > nelems)
5262 6 : push_null_elements(st, idx - nelems);
5263 ECB :
5264 CBC 18 : (void) pushJsonbValue(st, WJB_ELEM, newval);
5265 GIC 18 : done = true;
5266 : }
5267 :
5268 : /*--
5269 ECB : * 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 GIC 171 : if (!done && (op_type & JB_PATH_FILL_GAPS) && (level < path_len - 1))
5279 ECB : {
5280 GIC 12 : if (idx > 0)
5281 CBC 6 : push_null_elements(st, idx - nelems);
5282 ECB :
5283 GIC 12 : (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 171 : }
5289 :
5290 ECB : /*
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 CBC 126 : parse_jsonb_index_flags(Jsonb *jb)
5297 : {
5298 ECB : JsonbIterator *it;
5299 : JsonbValue v;
5300 : JsonbIteratorToken type;
5301 GIC 126 : uint32 flags = 0;
5302 :
5303 126 : it = JsonbIteratorInit(&jb->root);
5304 ECB :
5305 GIC 126 : type = JsonbIteratorNext(&it, &v, false);
5306 :
5307 : /*
5308 ECB : * 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 CBC 126 : if (type != WJB_BEGIN_ARRAY)
5313 GIC 6 : ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5314 ECB : errmsg("wrong flag type, only arrays and scalars are allowed")));
5315 :
5316 CBC 234 : while ((type = JsonbIteratorNext(&it, &v, false)) == WJB_ELEM)
5317 ECB : {
5318 GIC 132 : if (v.type != jbvString)
5319 12 : 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 CBC 174 : if (v.val.string.len == 3 &&
5325 54 : pg_strncasecmp(v.val.string.val, "all", 3) == 0)
5326 GIC 42 : flags |= jtiAll;
5327 CBC 90 : else if (v.val.string.len == 3 &&
5328 12 : pg_strncasecmp(v.val.string.val, "key", 3) == 0)
5329 GIC 12 : flags |= jtiKey;
5330 90 : else if (v.val.string.len == 6 &&
5331 CBC 24 : pg_strncasecmp(v.val.string.val, "string", 6) == 0)
5332 GIC 24 : flags |= jtiString;
5333 78 : else if (v.val.string.len == 7 &&
5334 36 : pg_strncasecmp(v.val.string.val, "numeric", 7) == 0)
5335 24 : flags |= jtiNumeric;
5336 CBC 30 : else if (v.val.string.len == 7 &&
5337 GIC 12 : pg_strncasecmp(v.val.string.val, "boolean", 7) == 0)
5338 CBC 12 : flags |= jtiBool;
5339 : else
5340 6 : ereport(ERROR,
5341 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5342 ECB : 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 CBC 102 : if (type != WJB_END_ARRAY)
5349 UBC 0 : elog(ERROR, "unexpected end of flag array");
5350 ECB :
5351 : /* get final WJB_DONE and free iterator */
5352 GIC 102 : type = JsonbIteratorNext(&it, &v, false);
5353 CBC 102 : if (type != WJB_DONE)
5354 UIC 0 : elog(ERROR, "unexpected end of flag array");
5355 :
5356 GIC 102 : return flags;
5357 : }
5358 :
5359 ECB : /*
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 GIC 75 : iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state,
5365 ECB : JsonIterateStringValuesAction action)
5366 : {
5367 : JsonbIterator *it;
5368 : JsonbValue v;
5369 : JsonbIteratorToken type;
5370 :
5371 GIC 75 : it = JsonbIteratorInit(&jb->root);
5372 :
5373 : /*
5374 : * Just recursively iterating over jsonb and call callback on all
5375 : * corresponding elements
5376 : */
5377 822 : while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5378 : {
5379 747 : if (type == WJB_KEY)
5380 : {
5381 279 : if (flags & jtiKey)
5382 CBC 72 : action(state, v.val.string.val, v.val.string.len);
5383 :
5384 279 : continue;
5385 ECB : }
5386 GIC 468 : else if (!(type == WJB_VALUE || type == WJB_ELEM))
5387 ECB : {
5388 : /* do not call callback for composite JsonbValue */
5389 GIC 186 : continue;
5390 : }
5391 :
5392 ECB : /* JsonbValue is a value of object or element of array */
5393 GIC 282 : switch (v.type)
5394 : {
5395 75 : case jbvString:
5396 75 : if (flags & jtiString)
5397 54 : action(state, v.val.string.val, v.val.string.len);
5398 75 : break;
5399 84 : case jbvNumeric:
5400 CBC 84 : if (flags & jtiNumeric)
5401 : {
5402 : char *val;
5403 :
5404 GIC 36 : val = DatumGetCString(DirectFunctionCall1(numeric_out,
5405 ECB : NumericGetDatum(v.val.numeric)));
5406 :
5407 CBC 36 : action(state, val, strlen(val));
5408 GIC 36 : pfree(val);
5409 ECB : }
5410 GIC 84 : break;
5411 78 : case jbvBool:
5412 78 : if (flags & jtiBool)
5413 : {
5414 24 : if (v.val.boolean)
5415 12 : action(state, "true", 4);
5416 ECB : else
5417 CBC 12 : action(state, "false", 5);
5418 : }
5419 GIC 78 : break;
5420 CBC 45 : default:
5421 : /* do not call callback for composite JsonbValue */
5422 45 : break;
5423 ECB : }
5424 : }
5425 GIC 75 : }
5426 :
5427 : /*
5428 ECB : * 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 CBC 75 : iterate_json_values(text *json, uint32 flags, void *action_state,
5433 ECB : JsonIterateStringValuesAction action)
5434 : {
5435 CBC 75 : JsonLexContext *lex = makeJsonLexContext(json, true);
5436 75 : JsonSemAction *sem = palloc0(sizeof(JsonSemAction));
5437 75 : IterateJsonStringValuesState *state = palloc0(sizeof(IterateJsonStringValuesState));
5438 ECB :
5439 CBC 75 : state->lex = lex;
5440 75 : state->action = action;
5441 75 : state->action_state = action_state;
5442 75 : state->flags = flags;
5443 :
5444 75 : sem->semstate = (void *) state;
5445 GIC 75 : sem->scalar = iterate_values_scalar;
5446 75 : sem->object_field_start = iterate_values_object_field_start;
5447 :
5448 75 : pg_parse_json_or_ereport(lex, sem);
5449 75 : }
5450 :
5451 : /*
5452 ECB : * An auxiliary function for iterate_json_values to invoke a specified
5453 EUB : * JsonIterateStringValuesAction for specified values.
5454 : */
5455 : static JsonParseErrorType
5456 CBC 282 : iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
5457 ECB : {
5458 GBC 282 : IterateJsonStringValuesState *_state = (IterateJsonStringValuesState *) state;
5459 :
5460 CBC 282 : switch (tokentype)
5461 : {
5462 GIC 75 : case JSON_TOKEN_STRING:
5463 75 : if (_state->flags & jtiString)
5464 54 : _state->action(_state->action_state, token, strlen(token));
5465 75 : break;
5466 84 : case JSON_TOKEN_NUMBER:
5467 84 : if (_state->flags & jtiNumeric)
5468 CBC 36 : _state->action(_state->action_state, token, strlen(token));
5469 GIC 84 : break;
5470 78 : case JSON_TOKEN_TRUE:
5471 : case JSON_TOKEN_FALSE:
5472 78 : if (_state->flags & jtiBool)
5473 24 : _state->action(_state->action_state, token, strlen(token));
5474 78 : break;
5475 CBC 45 : default:
5476 : /* do not call callback for any other token */
5477 GIC 45 : break;
5478 : }
5479 :
5480 GNC 282 : return JSON_SUCCESS;
5481 : }
5482 :
5483 : static JsonParseErrorType
5484 GIC 279 : iterate_values_object_field_start(void *state, char *fname, bool isnull)
5485 ECB : {
5486 GIC 279 : IterateJsonStringValuesState *_state = (IterateJsonStringValuesState *) state;
5487 ECB :
5488 CBC 279 : if (_state->flags & jtiKey)
5489 : {
5490 72 : char *val = pstrdup(fname);
5491 :
5492 72 : _state->action(_state->action_state, val, strlen(val));
5493 : }
5494 :
5495 GNC 279 : return JSON_SUCCESS;
5496 : }
5497 ECB :
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 CBC 21 : transform_jsonb_string_values(Jsonb *jsonb, void *action_state,
5506 ECB : JsonTransformStringValuesAction transform_action)
5507 : {
5508 : JsonbIterator *it;
5509 : JsonbValue v,
5510 GIC 21 : *res = NULL;
5511 : JsonbIteratorToken type;
5512 CBC 21 : JsonbParseState *st = NULL;
5513 : text *out;
5514 GIC 21 : bool is_scalar = false;
5515 ECB :
5516 CBC 21 : it = JsonbIteratorInit(&jsonb->root);
5517 GIC 21 : is_scalar = it->isScalar;
5518 ECB :
5519 CBC 228 : while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
5520 ECB : {
5521 GIC 207 : if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
5522 ECB : {
5523 CBC 57 : 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 57 : out = pg_detoast_datum_packed(out);
5526 GIC 57 : v.val.string.val = VARDATA_ANY(out);
5527 CBC 57 : v.val.string.len = VARSIZE_ANY_EXHDR(out);
5528 57 : res = pushJsonbValue(&st, type, type < WJB_BEGIN_ARRAY ? &v : NULL);
5529 : }
5530 ECB : else
5531 : {
5532 GIC 243 : res = pushJsonbValue(&st, type, (type == WJB_KEY ||
5533 CBC 93 : type == WJB_VALUE ||
5534 : type == WJB_ELEM) ? &v : NULL);
5535 : }
5536 : }
5537 :
5538 GIC 21 : if (res->type == jbvArray)
5539 6 : res->val.array.rawScalar = is_scalar;
5540 ECB :
5541 GIC 21 : return JsonbValueToJsonb(res);
5542 : }
5543 ECB :
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 CBC 21 : transform_json_string_values(text *json, void *action_state,
5553 ECB : JsonTransformStringValuesAction transform_action)
5554 : {
5555 GIC 21 : JsonLexContext *lex = makeJsonLexContext(json, true);
5556 CBC 21 : JsonSemAction *sem = palloc0(sizeof(JsonSemAction));
5557 21 : TransformJsonStringValuesState *state = palloc0(sizeof(TransformJsonStringValuesState));
5558 :
5559 GIC 21 : state->lex = lex;
5560 21 : state->strval = makeStringInfo();
5561 21 : state->action = transform_action;
5562 21 : state->action_state = action_state;
5563 :
5564 CBC 21 : sem->semstate = (void *) state;
5565 21 : sem->object_start = transform_string_values_object_start;
5566 GIC 21 : sem->object_end = transform_string_values_object_end;
5567 CBC 21 : sem->array_start = transform_string_values_array_start;
5568 GIC 21 : sem->array_end = transform_string_values_array_end;
5569 CBC 21 : sem->scalar = transform_string_values_scalar;
5570 21 : sem->array_element_start = transform_string_values_array_element_start;
5571 21 : sem->object_field_start = transform_string_values_object_field_start;
5572 ECB :
5573 CBC 21 : pg_parse_json_or_ereport(lex, sem);
5574 ECB :
5575 CBC 21 : return cstring_to_text_with_len(state->strval->data, state->strval->len);
5576 ECB : }
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 CBC 27 : transform_string_values_object_start(void *state)
5585 : {
5586 GIC 27 : TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
5587 ECB :
5588 GIC 27 : appendStringInfoCharMacro(_state->strval, '{');
5589 :
5590 GNC 27 : return JSON_SUCCESS;
5591 : }
5592 :
5593 : static JsonParseErrorType
5594 GIC 27 : transform_string_values_object_end(void *state)
5595 ECB : {
5596 GIC 27 : TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
5597 ECB :
5598 GIC 27 : appendStringInfoCharMacro(_state->strval, '}');
5599 :
5600 GNC 27 : return JSON_SUCCESS;
5601 ECB : }
5602 :
5603 : static JsonParseErrorType
5604 GIC 15 : transform_string_values_array_start(void *state)
5605 : {
5606 CBC 15 : TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
5607 :
5608 GIC 15 : appendStringInfoCharMacro(_state->strval, '[');
5609 :
5610 GNC 15 : return JSON_SUCCESS;
5611 : }
5612 :
5613 : static JsonParseErrorType
5614 GIC 15 : transform_string_values_array_end(void *state)
5615 : {
5616 15 : TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
5617 :
5618 CBC 15 : appendStringInfoCharMacro(_state->strval, ']');
5619 :
5620 GNC 15 : return JSON_SUCCESS;
5621 : }
5622 :
5623 : static JsonParseErrorType
5624 GIC 57 : transform_string_values_object_field_start(void *state, char *fname, bool isnull)
5625 ECB : {
5626 GIC 57 : TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
5627 ECB :
5628 GIC 57 : if (_state->strval->data[_state->strval->len - 1] != '{')
5629 CBC 33 : appendStringInfoCharMacro(_state->strval, ',');
5630 :
5631 ECB : /*
5632 : * Unfortunately we don't have the quoted and escaped string any more, so
5633 : * we have to re-escape it.
5634 : */
5635 GIC 57 : escape_json(_state->strval, fname);
5636 CBC 57 : appendStringInfoCharMacro(_state->strval, ':');
5637 :
5638 GNC 57 : return JSON_SUCCESS;
5639 : }
5640 ECB :
5641 : static JsonParseErrorType
5642 CBC 24 : transform_string_values_array_element_start(void *state, bool isnull)
5643 ECB : {
5644 CBC 24 : TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
5645 ECB :
5646 GIC 24 : if (_state->strval->data[_state->strval->len - 1] != '[')
5647 12 : appendStringInfoCharMacro(_state->strval, ',');
5648 :
5649 GNC 24 : return JSON_SUCCESS;
5650 : }
5651 ECB :
5652 : static JsonParseErrorType
5653 GIC 60 : transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype)
5654 : {
5655 60 : TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
5656 :
5657 CBC 60 : if (tokentype == JSON_TOKEN_STRING)
5658 ECB : {
5659 GIC 57 : text *out = _state->action(_state->action_state, token, strlen(token));
5660 ECB :
5661 GIC 57 : escape_json(_state->strval, text_to_cstring(out));
5662 : }
5663 : else
5664 3 : appendStringInfoString(_state->strval, token);
5665 :
5666 GNC 60 : return JSON_SUCCESS;
5667 : }
5668 :
5669 : JsonTokenType
5670 336 : json_get_first_token(text *json, bool throw_error)
5671 : {
5672 : JsonLexContext *lex;
5673 : JsonParseErrorType result;
5674 :
5675 336 : lex = makeJsonLexContext(json, false);
5676 :
5677 : /* Lex exactly one token from the input and check its type. */
5678 336 : result = json_lex(lex);
5679 :
5680 336 : if (result == JSON_SUCCESS)
5681 327 : return lex->token_type;
5682 :
5683 9 : if (throw_error)
5684 UNC 0 : json_errsave_error(result, lex, NULL);
5685 :
5686 GNC 9 : return JSON_TOKEN_INVALID; /* invalid json */
5687 : }
|