LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 2041 2129 95.9 %
Date: 2025-04-01 14:15:22 Functions: 150 150 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14