LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 2029 2117 95.8 %
Date: 2024-11-21 08:14:44 Functions: 150 150 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14