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

Generated by: LCOV version 1.14