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