Coverage Report

Created: 2025-08-12 06:43

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