Coverage Report

Created: 2026-10-16 06:48

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