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

Generated by: LCOV version 1.11