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