LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 1979 2049 96.6 %
Date: 2023-12-05 08:11:01 Functions: 148 148 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14