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

Generated by: LCOV version 1.13