LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 95.8 % 2163 2072
Test Date: 2026-04-07 14:16:30 Functions: 100.0 % 151 151
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1