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

Generated by: LCOV version 1.14