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

Generated by: LCOV version 2.0-1