LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonb.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15beta1 Lines: 805 905 89.0 %
Date: 2022-05-18 02:09:37 Functions: 57 61 93.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * jsonb.c
       4             :  *      I/O routines for jsonb type
       5             :  *
       6             :  * Copyright (c) 2014-2022, PostgreSQL Global Development Group
       7             :  *
       8             :  * IDENTIFICATION
       9             :  *    src/backend/utils/adt/jsonb.c
      10             :  *
      11             :  *-------------------------------------------------------------------------
      12             :  */
      13             : #include "postgres.h"
      14             : 
      15             : #include "access/htup_details.h"
      16             : #include "access/transam.h"
      17             : #include "catalog/pg_proc.h"
      18             : #include "catalog/pg_type.h"
      19             : #include "funcapi.h"
      20             : #include "libpq/pqformat.h"
      21             : #include "miscadmin.h"
      22             : #include "parser/parse_coerce.h"
      23             : #include "utils/builtins.h"
      24             : #include "utils/date.h"
      25             : #include "utils/datetime.h"
      26             : #include "utils/json.h"
      27             : #include "utils/jsonb.h"
      28             : #include "utils/jsonfuncs.h"
      29             : #include "utils/lsyscache.h"
      30             : #include "utils/syscache.h"
      31             : #include "utils/typcache.h"
      32             : 
      33             : typedef struct JsonbInState
      34             : {
      35             :     JsonbParseState *parseState;
      36             :     JsonbValue *res;
      37             :     bool        unique_keys;
      38             : } JsonbInState;
      39             : 
      40             : typedef struct JsonbAggState
      41             : {
      42             :     JsonbInState *res;
      43             :     JsonbTypeCategory key_category;
      44             :     Oid         key_output_func;
      45             :     JsonbTypeCategory val_category;
      46             :     Oid         val_output_func;
      47             : } JsonbAggState;
      48             : 
      49             : static inline Datum jsonb_from_cstring(char *json, int len, bool unique_keys);
      50             : static size_t checkStringLen(size_t len);
      51             : static void jsonb_in_object_start(void *pstate);
      52             : static void jsonb_in_object_end(void *pstate);
      53             : static void jsonb_in_array_start(void *pstate);
      54             : static void jsonb_in_array_end(void *pstate);
      55             : static void jsonb_in_object_field_start(void *pstate, char *fname, bool isnull);
      56             : static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal);
      57             : static void jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype);
      58             : static void composite_to_jsonb(Datum composite, JsonbInState *result);
      59             : static void array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims,
      60             :                                Datum *vals, bool *nulls, int *valcount,
      61             :                                JsonbTypeCategory tcategory, Oid outfuncoid);
      62             : static void array_to_jsonb_internal(Datum array, JsonbInState *result);
      63             : static void datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
      64             :                            JsonbTypeCategory tcategory, Oid outfuncoid,
      65             :                            bool key_scalar);
      66             : static void add_jsonb(Datum val, bool is_null, JsonbInState *result,
      67             :                       Oid val_type, bool key_scalar);
      68             : static JsonbParseState *clone_parse_state(JsonbParseState *state);
      69             : static char *JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent);
      70             : static void add_indent(StringInfo out, bool indent, int level);
      71             : 
      72             : /*
      73             :  * jsonb type input function
      74             :  */
      75             : Datum
      76      322272 : jsonb_in(PG_FUNCTION_ARGS)
      77             : {
      78      322272 :     char       *json = PG_GETARG_CSTRING(0);
      79             : 
      80      322272 :     return jsonb_from_cstring(json, strlen(json), false);
      81             : }
      82             : 
      83             : /*
      84             :  * jsonb type recv function
      85             :  *
      86             :  * The type is sent as text in binary mode, so this is almost the same
      87             :  * as the input function, but it's prefixed with a version number so we
      88             :  * can change the binary format sent in future if necessary. For now,
      89             :  * only version 1 is supported.
      90             :  */
      91             : Datum
      92           0 : jsonb_recv(PG_FUNCTION_ARGS)
      93             : {
      94           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
      95           0 :     int         version = pq_getmsgint(buf, 1);
      96             :     char       *str;
      97             :     int         nbytes;
      98             : 
      99           0 :     if (version == 1)
     100           0 :         str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
     101             :     else
     102           0 :         elog(ERROR, "unsupported jsonb version number %d", version);
     103             : 
     104           0 :     return jsonb_from_cstring(str, nbytes, false);
     105             : }
     106             : 
     107             : /*
     108             :  * jsonb type output function
     109             :  */
     110             : Datum
     111       20884 : jsonb_out(PG_FUNCTION_ARGS)
     112             : {
     113       20884 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     114             :     char       *out;
     115             : 
     116       20884 :     out = JsonbToCString(NULL, &jb->root, VARSIZE(jb));
     117             : 
     118       20884 :     PG_RETURN_CSTRING(out);
     119             : }
     120             : 
     121             : /*
     122             :  * jsonb type send function
     123             :  *
     124             :  * Just send jsonb as a version number, then a string of text
     125             :  */
     126             : Datum
     127           0 : jsonb_send(PG_FUNCTION_ARGS)
     128             : {
     129           0 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     130             :     StringInfoData buf;
     131           0 :     StringInfo  jtext = makeStringInfo();
     132           0 :     int         version = 1;
     133             : 
     134           0 :     (void) JsonbToCString(jtext, &jb->root, VARSIZE(jb));
     135             : 
     136           0 :     pq_begintypsend(&buf);
     137           0 :     pq_sendint8(&buf, version);
     138           0 :     pq_sendtext(&buf, jtext->data, jtext->len);
     139           0 :     pfree(jtext->data);
     140           0 :     pfree(jtext);
     141             : 
     142           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     143             : }
     144             : 
     145             : Datum
     146           0 : jsonb_from_text(text *js, bool unique_keys)
     147             : {
     148           0 :     return jsonb_from_cstring(VARDATA_ANY(js),
     149           0 :                               VARSIZE_ANY_EXHDR(js),
     150             :                               unique_keys);
     151             : }
     152             : 
     153             : /*
     154             :  * Get the type name of a jsonb container.
     155             :  */
     156             : static const char *
     157         306 : JsonbContainerTypeName(JsonbContainer *jbc)
     158             : {
     159             :     JsonbValue  scalar;
     160             : 
     161         306 :     if (JsonbExtractScalar(jbc, &scalar))
     162          66 :         return JsonbTypeName(&scalar);
     163         240 :     else if (JsonContainerIsArray(jbc))
     164         102 :         return "array";
     165         138 :     else if (JsonContainerIsObject(jbc))
     166         138 :         return "object";
     167             :     else
     168             :     {
     169           0 :         elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
     170             :         return "unknown";
     171             :     }
     172             : }
     173             : 
     174             : /*
     175             :  * Get the type name of a jsonb value.
     176             :  */
     177             : const char *
     178         276 : JsonbTypeName(JsonbValue *jbv)
     179             : {
     180         276 :     switch (jbv->type)
     181             :     {
     182          24 :         case jbvBinary:
     183          24 :             return JsonbContainerTypeName(jbv->val.binary.data);
     184           0 :         case jbvObject:
     185           0 :             return "object";
     186           0 :         case jbvArray:
     187           0 :             return "array";
     188          90 :         case jbvNumeric:
     189          90 :             return "number";
     190          30 :         case jbvString:
     191          30 :             return "string";
     192          36 :         case jbvBool:
     193          36 :             return "boolean";
     194          24 :         case jbvNull:
     195          24 :             return "null";
     196          72 :         case jbvDatetime:
     197          72 :             switch (jbv->val.datetime.typid)
     198             :             {
     199          12 :                 case DATEOID:
     200          12 :                     return "date";
     201          12 :                 case TIMEOID:
     202          12 :                     return "time without time zone";
     203          18 :                 case TIMETZOID:
     204          18 :                     return "time with time zone";
     205          12 :                 case TIMESTAMPOID:
     206          12 :                     return "timestamp without time zone";
     207          18 :                 case TIMESTAMPTZOID:
     208          18 :                     return "timestamp with time zone";
     209           0 :                 default:
     210           0 :                     elog(ERROR, "unrecognized jsonb value datetime type: %d",
     211             :                          jbv->val.datetime.typid);
     212             :             }
     213             :             return "unknown";
     214           0 :         default:
     215           0 :             elog(ERROR, "unrecognized jsonb value type: %d", jbv->type);
     216             :             return "unknown";
     217             :     }
     218             : }
     219             : 
     220             : /*
     221             :  * SQL function jsonb_typeof(jsonb) -> text
     222             :  *
     223             :  * This function is here because the analog json function is in json.c, since
     224             :  * it uses the json parser internals not exposed elsewhere.
     225             :  */
     226             : Datum
     227         282 : jsonb_typeof(PG_FUNCTION_ARGS)
     228             : {
     229         282 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
     230         282 :     const char *result = JsonbContainerTypeName(&in->root);
     231             : 
     232         282 :     PG_RETURN_TEXT_P(cstring_to_text(result));
     233             : }
     234             : 
     235             : /*
     236             :  * jsonb_from_cstring
     237             :  *
     238             :  * Turns json string into a jsonb Datum.
     239             :  *
     240             :  * Uses the json parser (with hooks) to construct a jsonb.
     241             :  */
     242             : static inline Datum
     243      322272 : jsonb_from_cstring(char *json, int len, bool unique_keys)
     244             : {
     245             :     JsonLexContext *lex;
     246             :     JsonbInState state;
     247             :     JsonSemAction sem;
     248             : 
     249      322272 :     memset(&state, 0, sizeof(state));
     250      322272 :     memset(&sem, 0, sizeof(sem));
     251      322272 :     lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
     252             : 
     253      322272 :     state.unique_keys = unique_keys;
     254             : 
     255      322272 :     sem.semstate = (void *) &state;
     256             : 
     257      322272 :     sem.object_start = jsonb_in_object_start;
     258      322272 :     sem.array_start = jsonb_in_array_start;
     259      322272 :     sem.object_end = jsonb_in_object_end;
     260      322272 :     sem.array_end = jsonb_in_array_end;
     261      322272 :     sem.scalar = jsonb_in_scalar;
     262      322272 :     sem.object_field_start = jsonb_in_object_field_start;
     263             : 
     264      322272 :     pg_parse_json_or_ereport(lex, &sem);
     265             : 
     266             :     /* after parsing, the item member has the composed jsonb structure */
     267      322008 :     PG_RETURN_POINTER(JsonbValueToJsonb(state.res));
     268             : }
     269             : 
     270             : static size_t
     271       71044 : checkStringLen(size_t len)
     272             : {
     273       71044 :     if (len > JENTRY_OFFLENMASK)
     274           0 :         ereport(ERROR,
     275             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     276             :                  errmsg("string too long to represent as jsonb string"),
     277             :                  errdetail("Due to an implementation restriction, jsonb strings cannot exceed %d bytes.",
     278             :                            JENTRY_OFFLENMASK)));
     279             : 
     280       71044 :     return len;
     281             : }
     282             : 
     283             : static void
     284       24200 : jsonb_in_object_start(void *pstate)
     285             : {
     286       24200 :     JsonbInState *_state = (JsonbInState *) pstate;
     287             : 
     288       24200 :     _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_OBJECT, NULL);
     289       24200 :     _state->parseState->unique_keys = _state->unique_keys;
     290       24200 : }
     291             : 
     292             : static void
     293       20192 : jsonb_in_object_end(void *pstate)
     294             : {
     295       20192 :     JsonbInState *_state = (JsonbInState *) pstate;
     296             : 
     297       20192 :     _state->res = pushJsonbValue(&_state->parseState, WJB_END_OBJECT, NULL);
     298       20192 : }
     299             : 
     300             : static void
     301       10932 : jsonb_in_array_start(void *pstate)
     302             : {
     303       10932 :     JsonbInState *_state = (JsonbInState *) pstate;
     304             : 
     305       10932 :     _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, NULL);
     306       10932 : }
     307             : 
     308             : static void
     309        6510 : jsonb_in_array_end(void *pstate)
     310             : {
     311        6510 :     JsonbInState *_state = (JsonbInState *) pstate;
     312             : 
     313        6510 :     _state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
     314        6510 : }
     315             : 
     316             : static void
     317       48024 : jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
     318             : {
     319       48024 :     JsonbInState *_state = (JsonbInState *) pstate;
     320             :     JsonbValue  v;
     321             : 
     322             :     Assert(fname != NULL);
     323       48024 :     v.type = jbvString;
     324       48024 :     v.val.string.len = checkStringLen(strlen(fname));
     325       48024 :     v.val.string.val = fname;
     326             : 
     327       48024 :     _state->res = pushJsonbValue(&_state->parseState, WJB_KEY, &v);
     328       48024 : }
     329             : 
     330             : static void
     331      104696 : jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal)
     332             : {
     333      104696 :     switch (scalarVal->type)
     334             :     {
     335        1144 :         case jbvNull:
     336        1144 :             appendBinaryStringInfo(out, "null", 4);
     337        1144 :             break;
     338       69310 :         case jbvString:
     339       69310 :             escape_json(out, pnstrdup(scalarVal->val.string.val, scalarVal->val.string.len));
     340       69310 :             break;
     341       21862 :         case jbvNumeric:
     342       21862 :             appendStringInfoString(out,
     343       21862 :                                    DatumGetCString(DirectFunctionCall1(numeric_out,
     344             :                                                                        PointerGetDatum(scalarVal->val.numeric))));
     345       21862 :             break;
     346       12380 :         case jbvBool:
     347       12380 :             if (scalarVal->val.boolean)
     348        5884 :                 appendBinaryStringInfo(out, "true", 4);
     349             :             else
     350        6496 :                 appendBinaryStringInfo(out, "false", 5);
     351       12380 :             break;
     352           0 :         default:
     353           0 :             elog(ERROR, "unknown jsonb scalar type");
     354             :     }
     355      104696 : }
     356             : 
     357             : /*
     358             :  * For jsonb we always want the de-escaped value - that's what's in token
     359             :  */
     360             : static void
     361      354488 : jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
     362             : {
     363      354488 :     JsonbInState *_state = (JsonbInState *) pstate;
     364             :     JsonbValue  v;
     365             :     Datum       numd;
     366             : 
     367      354488 :     switch (tokentype)
     368             :     {
     369             : 
     370       22018 :         case JSON_TOKEN_STRING:
     371             :             Assert(token != NULL);
     372       22018 :             v.type = jbvString;
     373       22018 :             v.val.string.len = checkStringLen(strlen(token));
     374       22018 :             v.val.string.val = token;
     375       22018 :             break;
     376      323876 :         case JSON_TOKEN_NUMBER:
     377             : 
     378             :             /*
     379             :              * No need to check size of numeric values, because maximum
     380             :              * numeric size is well below the JsonbValue restriction
     381             :              */
     382             :             Assert(token != NULL);
     383      323876 :             v.type = jbvNumeric;
     384      323876 :             numd = DirectFunctionCall3(numeric_in,
     385             :                                        CStringGetDatum(token),
     386             :                                        ObjectIdGetDatum(InvalidOid),
     387             :                                        Int32GetDatum(-1));
     388      323876 :             v.val.numeric = DatumGetNumeric(numd);
     389      323876 :             break;
     390        3296 :         case JSON_TOKEN_TRUE:
     391        3296 :             v.type = jbvBool;
     392        3296 :             v.val.boolean = true;
     393        3296 :             break;
     394        3250 :         case JSON_TOKEN_FALSE:
     395        3250 :             v.type = jbvBool;
     396        3250 :             v.val.boolean = false;
     397        3250 :             break;
     398        2048 :         case JSON_TOKEN_NULL:
     399        2048 :             v.type = jbvNull;
     400        2048 :             break;
     401           0 :         default:
     402             :             /* should not be possible */
     403           0 :             elog(ERROR, "invalid json token type");
     404             :             break;
     405             :     }
     406             : 
     407      354488 :     if (_state->parseState == NULL)
     408             :     {
     409             :         /* single scalar */
     410             :         JsonbValue  va;
     411             : 
     412      303096 :         va.type = jbvArray;
     413      303096 :         va.val.array.rawScalar = true;
     414      303096 :         va.val.array.nElems = 1;
     415             : 
     416      303096 :         _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, &va);
     417      303096 :         _state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v);
     418      303096 :         _state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
     419             :     }
     420             :     else
     421             :     {
     422       51392 :         JsonbValue *o = &_state->parseState->contVal;
     423             : 
     424       51392 :         switch (o->type)
     425             :         {
     426       11474 :             case jbvArray:
     427       11474 :                 _state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v);
     428       11474 :                 break;
     429       39918 :             case jbvObject:
     430       39918 :                 _state->res = pushJsonbValue(&_state->parseState, WJB_VALUE, &v);
     431       39918 :                 break;
     432           0 :             default:
     433           0 :                 elog(ERROR, "unexpected parent of nested structure");
     434             :         }
     435             :     }
     436      354488 : }
     437             : 
     438             : /*
     439             :  * JsonbToCString
     440             :  *     Converts jsonb value to a C-string.
     441             :  *
     442             :  * If 'out' argument is non-null, the resulting C-string is stored inside the
     443             :  * StringBuffer.  The resulting string is always returned.
     444             :  *
     445             :  * A typical case for passing the StringInfo in rather than NULL is where the
     446             :  * caller wants access to the len attribute without having to call strlen, e.g.
     447             :  * if they are converting it to a text* object.
     448             :  */
     449             : char *
     450       22114 : JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len)
     451             : {
     452       22114 :     return JsonbToCStringWorker(out, in, estimated_len, false);
     453             : }
     454             : 
     455             : /*
     456             :  * same thing but with indentation turned on
     457             :  */
     458             : char *
     459          36 : JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
     460             : {
     461          36 :     return JsonbToCStringWorker(out, in, estimated_len, true);
     462             : }
     463             : 
     464             : /*
     465             :  * common worker for above two functions
     466             :  */
     467             : static char *
     468       22150 : JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent)
     469             : {
     470       22150 :     bool        first = true;
     471             :     JsonbIterator *it;
     472             :     JsonbValue  v;
     473       22150 :     JsonbIteratorToken type = WJB_DONE;
     474       22150 :     int         level = 0;
     475       22150 :     bool        redo_switch = false;
     476             : 
     477             :     /* If we are indenting, don't add a space after a comma */
     478       22150 :     int         ispaces = indent ? 1 : 2;
     479             : 
     480             :     /*
     481             :      * Don't indent the very first item. This gets set to the indent flag at
     482             :      * the bottom of the loop.
     483             :      */
     484       22150 :     bool        use_indent = false;
     485       22150 :     bool        raw_scalar = false;
     486       22150 :     bool        last_was_key = false;
     487             : 
     488       22150 :     if (out == NULL)
     489       21988 :         out = makeStringInfo();
     490             : 
     491       22150 :     enlargeStringInfo(out, (estimated_len >= 0) ? estimated_len : 64);
     492             : 
     493       22150 :     it = JsonbIteratorInit(in);
     494             : 
     495      265090 :     while (redo_switch ||
     496      131756 :            ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE))
     497             :     {
     498      111184 :         redo_switch = false;
     499      111184 :         switch (type)
     500             :         {
     501       12360 :             case WJB_BEGIN_ARRAY:
     502       12360 :                 if (!first)
     503         138 :                     appendBinaryStringInfo(out, ", ", ispaces);
     504             : 
     505       12360 :                 if (!v.val.array.rawScalar)
     506             :                 {
     507        3740 :                     add_indent(out, use_indent && !last_was_key, level);
     508        3740 :                     appendStringInfoCharMacro(out, '[');
     509             :                 }
     510             :                 else
     511        8620 :                     raw_scalar = true;
     512             : 
     513       12360 :                 first = true;
     514       12360 :                 level++;
     515       12360 :                 break;
     516       12814 :             case WJB_BEGIN_OBJECT:
     517       12814 :                 if (!first)
     518         346 :                     appendBinaryStringInfo(out, ", ", ispaces);
     519             : 
     520       12814 :                 add_indent(out, use_indent && !last_was_key, level);
     521       12814 :                 appendStringInfoCharMacro(out, '{');
     522             : 
     523       12814 :                 first = true;
     524       12814 :                 level++;
     525       12814 :                 break;
     526       45438 :             case WJB_KEY:
     527       45438 :                 if (!first)
     528       33842 :                     appendBinaryStringInfo(out, ", ", ispaces);
     529       45438 :                 first = true;
     530             : 
     531       45438 :                 add_indent(out, use_indent, level);
     532             : 
     533             :                 /* json rules guarantee this is a string */
     534       45438 :                 jsonb_put_escaped_value(out, &v);
     535       45438 :                 appendBinaryStringInfo(out, ": ", 2);
     536             : 
     537       45438 :                 type = JsonbIteratorNext(&it, &v, false);
     538       45438 :                 if (type == WJB_VALUE)
     539             :                 {
     540       43860 :                     first = false;
     541       43860 :                     jsonb_put_escaped_value(out, &v);
     542             :                 }
     543             :                 else
     544             :                 {
     545             :                     Assert(type == WJB_BEGIN_OBJECT || type == WJB_BEGIN_ARRAY);
     546             : 
     547             :                     /*
     548             :                      * We need to rerun the current switch() since we need to
     549             :                      * output the object which we just got from the iterator
     550             :                      * before calling the iterator again.
     551             :                      */
     552        1578 :                     redo_switch = true;
     553             :                 }
     554       45438 :                 break;
     555       15398 :             case WJB_ELEM:
     556       15398 :                 if (!first)
     557        4196 :                     appendBinaryStringInfo(out, ", ", ispaces);
     558       15398 :                 first = false;
     559             : 
     560       15398 :                 if (!raw_scalar)
     561        6778 :                     add_indent(out, use_indent, level);
     562       15398 :                 jsonb_put_escaped_value(out, &v);
     563       15398 :                 break;
     564       12360 :             case WJB_END_ARRAY:
     565       12360 :                 level--;
     566       12360 :                 if (!raw_scalar)
     567             :                 {
     568        3740 :                     add_indent(out, use_indent, level);
     569        3740 :                     appendStringInfoCharMacro(out, ']');
     570             :                 }
     571       12360 :                 first = false;
     572       12360 :                 break;
     573       12814 :             case WJB_END_OBJECT:
     574       12814 :                 level--;
     575       12814 :                 add_indent(out, use_indent, level);
     576       12814 :                 appendStringInfoCharMacro(out, '}');
     577       12814 :                 first = false;
     578       12814 :                 break;
     579           0 :             default:
     580           0 :                 elog(ERROR, "unknown jsonb iterator token type");
     581             :         }
     582      111184 :         use_indent = indent;
     583      111184 :         last_was_key = redo_switch;
     584             :     }
     585             : 
     586             :     Assert(level == 0);
     587             : 
     588       22150 :     return out->data;
     589             : }
     590             : 
     591             : static void
     592       85324 : add_indent(StringInfo out, bool indent, int level)
     593             : {
     594       85324 :     if (indent)
     595             :     {
     596             :         int         i;
     597             : 
     598        1566 :         appendStringInfoCharMacro(out, '\n');
     599        7590 :         for (i = 0; i < level; i++)
     600        6024 :             appendBinaryStringInfo(out, "    ", 4);
     601             :     }
     602       85324 : }
     603             : 
     604             : 
     605             : /*
     606             :  * Determine how we want to render values of a given type in datum_to_jsonb.
     607             :  *
     608             :  * Given the datatype OID, return its JsonbTypeCategory, as well as the type's
     609             :  * output function OID.  If the returned category is JSONBTYPE_JSONCAST,
     610             :  * we return the OID of the relevant cast function instead.
     611             :  */
     612             : void
     613        2322 : jsonb_categorize_type(Oid typoid,
     614             :                       JsonbTypeCategory *tcategory,
     615             :                       Oid *outfuncoid)
     616             : {
     617             :     bool        typisvarlena;
     618             : 
     619             :     /* Look through any domain */
     620        2322 :     typoid = getBaseType(typoid);
     621             : 
     622        2322 :     *outfuncoid = InvalidOid;
     623             : 
     624             :     /*
     625             :      * We need to get the output function for everything except date and
     626             :      * timestamp types, booleans, array and composite types, json and jsonb,
     627             :      * and non-builtin types where there's a cast to json. In this last case
     628             :      * we return the oid of the cast function instead.
     629             :      */
     630             : 
     631        2322 :     switch (typoid)
     632             :     {
     633          48 :         case BOOLOID:
     634          48 :             *tcategory = JSONBTYPE_BOOL;
     635          48 :             break;
     636             : 
     637         648 :         case INT2OID:
     638             :         case INT4OID:
     639             :         case INT8OID:
     640             :         case FLOAT4OID:
     641             :         case FLOAT8OID:
     642             :         case NUMERICOID:
     643         648 :             getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
     644         648 :             *tcategory = JSONBTYPE_NUMERIC;
     645         648 :             break;
     646             : 
     647          18 :         case DATEOID:
     648          18 :             *tcategory = JSONBTYPE_DATE;
     649          18 :             break;
     650             : 
     651          18 :         case TIMESTAMPOID:
     652          18 :             *tcategory = JSONBTYPE_TIMESTAMP;
     653          18 :             break;
     654             : 
     655          24 :         case TIMESTAMPTZOID:
     656          24 :             *tcategory = JSONBTYPE_TIMESTAMPTZ;
     657          24 :             break;
     658             : 
     659         366 :         case JSONBOID:
     660         366 :             *tcategory = JSONBTYPE_JSONB;
     661         366 :             break;
     662             : 
     663          42 :         case JSONOID:
     664          42 :             *tcategory = JSONBTYPE_JSON;
     665          42 :             break;
     666             : 
     667        1158 :         default:
     668             :             /* Check for arrays and composites */
     669        1158 :             if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
     670        1044 :                 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
     671         114 :                 *tcategory = JSONBTYPE_ARRAY;
     672        1044 :             else if (type_is_rowtype(typoid))   /* includes RECORDOID */
     673          72 :                 *tcategory = JSONBTYPE_COMPOSITE;
     674             :             else
     675             :             {
     676             :                 /* It's probably the general case ... */
     677         972 :                 *tcategory = JSONBTYPE_OTHER;
     678             : 
     679             :                 /*
     680             :                  * but first let's look for a cast to json (note: not to
     681             :                  * jsonb) if it's not built-in.
     682             :                  */
     683         972 :                 if (typoid >= FirstNormalObjectId)
     684             :                 {
     685             :                     Oid         castfunc;
     686             :                     CoercionPathType ctype;
     687             : 
     688           0 :                     ctype = find_coercion_pathway(JSONOID, typoid,
     689             :                                                   COERCION_EXPLICIT, &castfunc);
     690           0 :                     if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
     691             :                     {
     692           0 :                         *tcategory = JSONBTYPE_JSONCAST;
     693           0 :                         *outfuncoid = castfunc;
     694             :                     }
     695             :                     else
     696             :                     {
     697             :                         /* not a cast type, so just get the usual output func */
     698           0 :                         getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
     699             :                     }
     700             :                 }
     701             :                 else
     702             :                 {
     703             :                     /* any other builtin type */
     704         972 :                     getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
     705             :                 }
     706         972 :                 break;
     707             :             }
     708             :     }
     709        2322 : }
     710             : 
     711             : /*
     712             :  * Turn a Datum into jsonb, adding it to the result JsonbInState.
     713             :  *
     714             :  * tcategory and outfuncoid are from a previous call to json_categorize_type,
     715             :  * except that if is_null is true then they can be invalid.
     716             :  *
     717             :  * If key_scalar is true, the value is stored as a key, so insist
     718             :  * it's of an acceptable type, and force it to be a jbvString.
     719             :  */
     720             : static void
     721        3078 : datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
     722             :                JsonbTypeCategory tcategory, Oid outfuncoid,
     723             :                bool key_scalar)
     724             : {
     725             :     char       *outputstr;
     726             :     bool        numeric_error;
     727             :     JsonbValue  jb;
     728        3078 :     bool        scalar_jsonb = false;
     729             : 
     730        3078 :     check_stack_depth();
     731             : 
     732             :     /* Convert val to a JsonbValue in jb (in most cases) */
     733        3078 :     if (is_null)
     734             :     {
     735             :         Assert(!key_scalar);
     736         216 :         jb.type = jbvNull;
     737             :     }
     738        2862 :     else if (key_scalar &&
     739         828 :              (tcategory == JSONBTYPE_ARRAY ||
     740         822 :               tcategory == JSONBTYPE_COMPOSITE ||
     741         816 :               tcategory == JSONBTYPE_JSON ||
     742         816 :               tcategory == JSONBTYPE_JSONB ||
     743             :               tcategory == JSONBTYPE_JSONCAST))
     744             :     {
     745          24 :         ereport(ERROR,
     746             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     747             :                  errmsg("key value must be scalar, not array, composite, or json")));
     748             :     }
     749             :     else
     750             :     {
     751        2838 :         if (tcategory == JSONBTYPE_JSONCAST)
     752           0 :             val = OidFunctionCall1(outfuncoid, val);
     753             : 
     754        2838 :         switch (tcategory)
     755             :         {
     756         108 :             case JSONBTYPE_ARRAY:
     757         108 :                 array_to_jsonb_internal(val, result);
     758         108 :                 break;
     759         192 :             case JSONBTYPE_COMPOSITE:
     760         192 :                 composite_to_jsonb(val, result);
     761         192 :                 break;
     762          48 :             case JSONBTYPE_BOOL:
     763          48 :                 if (key_scalar)
     764             :                 {
     765           0 :                     outputstr = DatumGetBool(val) ? "true" : "false";
     766           0 :                     jb.type = jbvString;
     767           0 :                     jb.val.string.len = strlen(outputstr);
     768           0 :                     jb.val.string.val = outputstr;
     769             :                 }
     770             :                 else
     771             :                 {
     772          48 :                     jb.type = jbvBool;
     773          48 :                     jb.val.boolean = DatumGetBool(val);
     774             :                 }
     775          48 :                 break;
     776        1020 :             case JSONBTYPE_NUMERIC:
     777        1020 :                 outputstr = OidOutputFunctionCall(outfuncoid, val);
     778        1020 :                 if (key_scalar)
     779             :                 {
     780             :                     /* always quote keys */
     781         246 :                     jb.type = jbvString;
     782         246 :                     jb.val.string.len = strlen(outputstr);
     783         246 :                     jb.val.string.val = outputstr;
     784             :                 }
     785             :                 else
     786             :                 {
     787             :                     /*
     788             :                      * Make it numeric if it's a valid JSON number, otherwise
     789             :                      * a string. Invalid numeric output will always have an
     790             :                      * 'N' or 'n' in it (I think).
     791             :                      */
     792        1548 :                     numeric_error = (strchr(outputstr, 'N') != NULL ||
     793         774 :                                      strchr(outputstr, 'n') != NULL);
     794         774 :                     if (!numeric_error)
     795             :                     {
     796             :                         Datum       numd;
     797             : 
     798         774 :                         jb.type = jbvNumeric;
     799         774 :                         numd = DirectFunctionCall3(numeric_in,
     800             :                                                    CStringGetDatum(outputstr),
     801             :                                                    ObjectIdGetDatum(InvalidOid),
     802             :                                                    Int32GetDatum(-1));
     803         774 :                         jb.val.numeric = DatumGetNumeric(numd);
     804         774 :                         pfree(outputstr);
     805             :                     }
     806             :                     else
     807             :                     {
     808           0 :                         jb.type = jbvString;
     809           0 :                         jb.val.string.len = strlen(outputstr);
     810           0 :                         jb.val.string.val = outputstr;
     811             :                     }
     812             :                 }
     813        1020 :                 break;
     814          18 :             case JSONBTYPE_DATE:
     815          18 :                 jb.type = jbvString;
     816          18 :                 jb.val.string.val = JsonEncodeDateTime(NULL, val,
     817             :                                                        DATEOID, NULL);
     818          18 :                 jb.val.string.len = strlen(jb.val.string.val);
     819          18 :                 break;
     820          18 :             case JSONBTYPE_TIMESTAMP:
     821          18 :                 jb.type = jbvString;
     822          18 :                 jb.val.string.val = JsonEncodeDateTime(NULL, val,
     823             :                                                        TIMESTAMPOID, NULL);
     824          18 :                 jb.val.string.len = strlen(jb.val.string.val);
     825          18 :                 break;
     826          24 :             case JSONBTYPE_TIMESTAMPTZ:
     827          24 :                 jb.type = jbvString;
     828          24 :                 jb.val.string.val = JsonEncodeDateTime(NULL, val,
     829             :                                                        TIMESTAMPTZOID, NULL);
     830          24 :                 jb.val.string.len = strlen(jb.val.string.val);
     831          24 :                 break;
     832          36 :             case JSONBTYPE_JSONCAST:
     833             :             case JSONBTYPE_JSON:
     834             :                 {
     835             :                     /* parse the json right into the existing result object */
     836             :                     JsonLexContext *lex;
     837             :                     JsonSemAction sem;
     838          36 :                     text       *json = DatumGetTextPP(val);
     839             : 
     840          36 :                     lex = makeJsonLexContext(json, true);
     841             : 
     842          36 :                     memset(&sem, 0, sizeof(sem));
     843             : 
     844          36 :                     sem.semstate = (void *) result;
     845             : 
     846          36 :                     sem.object_start = jsonb_in_object_start;
     847          36 :                     sem.array_start = jsonb_in_array_start;
     848          36 :                     sem.object_end = jsonb_in_object_end;
     849          36 :                     sem.array_end = jsonb_in_array_end;
     850          36 :                     sem.scalar = jsonb_in_scalar;
     851          36 :                     sem.object_field_start = jsonb_in_object_field_start;
     852             : 
     853          36 :                     pg_parse_json_or_ereport(lex, &sem);
     854             :                 }
     855          36 :                 break;
     856         372 :             case JSONBTYPE_JSONB:
     857             :                 {
     858         372 :                     Jsonb      *jsonb = DatumGetJsonbP(val);
     859             :                     JsonbIterator *it;
     860             : 
     861         372 :                     it = JsonbIteratorInit(&jsonb->root);
     862             : 
     863         372 :                     if (JB_ROOT_IS_SCALAR(jsonb))
     864             :                     {
     865         216 :                         (void) JsonbIteratorNext(&it, &jb, true);
     866             :                         Assert(jb.type == jbvArray);
     867         216 :                         (void) JsonbIteratorNext(&it, &jb, true);
     868         216 :                         scalar_jsonb = true;
     869             :                     }
     870             :                     else
     871             :                     {
     872             :                         JsonbIteratorToken type;
     873             : 
     874        7260 :                         while ((type = JsonbIteratorNext(&it, &jb, false))
     875             :                                != WJB_DONE)
     876             :                         {
     877        7104 :                             if (type == WJB_END_ARRAY || type == WJB_END_OBJECT ||
     878        5706 :                                 type == WJB_BEGIN_ARRAY || type == WJB_BEGIN_OBJECT)
     879        1860 :                                 result->res = pushJsonbValue(&result->parseState,
     880             :                                                              type, NULL);
     881             :                             else
     882        5244 :                                 result->res = pushJsonbValue(&result->parseState,
     883             :                                                              type, &jb);
     884             :                         }
     885             :                     }
     886             :                 }
     887         372 :                 break;
     888        1002 :             default:
     889        1002 :                 outputstr = OidOutputFunctionCall(outfuncoid, val);
     890        1002 :                 jb.type = jbvString;
     891        1002 :                 jb.val.string.len = checkStringLen(strlen(outputstr));
     892        1002 :                 jb.val.string.val = outputstr;
     893        1002 :                 break;
     894             :         }
     895             :     }
     896             : 
     897             :     /* Now insert jb into result, unless we did it recursively */
     898        3054 :     if (!is_null && !scalar_jsonb &&
     899        1494 :         tcategory >= JSONBTYPE_JSON && tcategory <= JSONBTYPE_JSONCAST)
     900             :     {
     901             :         /* work has been done recursively */
     902         492 :         return;
     903             :     }
     904        2562 :     else if (result->parseState == NULL)
     905             :     {
     906             :         /* single root scalar */
     907             :         JsonbValue  va;
     908             : 
     909         594 :         va.type = jbvArray;
     910         594 :         va.val.array.rawScalar = true;
     911         594 :         va.val.array.nElems = 1;
     912             : 
     913         594 :         result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, &va);
     914         594 :         result->res = pushJsonbValue(&result->parseState, WJB_ELEM, &jb);
     915         594 :         result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
     916             :     }
     917             :     else
     918             :     {
     919        1968 :         JsonbValue *o = &result->parseState->contVal;
     920             : 
     921        1968 :         switch (o->type)
     922             :         {
     923         474 :             case jbvArray:
     924         474 :                 result->res = pushJsonbValue(&result->parseState, WJB_ELEM, &jb);
     925         474 :                 break;
     926        1494 :             case jbvObject:
     927        1494 :                 result->res = pushJsonbValue(&result->parseState,
     928             :                                              key_scalar ? WJB_KEY : WJB_VALUE,
     929             :                                              &jb);
     930        1494 :                 break;
     931           0 :             default:
     932           0 :                 elog(ERROR, "unexpected parent of nested structure");
     933             :         }
     934             :     }
     935             : }
     936             : 
     937             : /*
     938             :  * Process a single dimension of an array.
     939             :  * If it's the innermost dimension, output the values, otherwise call
     940             :  * ourselves recursively to process the next dimension.
     941             :  */
     942             : static void
     943         108 : array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, Datum *vals,
     944             :                    bool *nulls, int *valcount, JsonbTypeCategory tcategory,
     945             :                    Oid outfuncoid)
     946             : {
     947             :     int         i;
     948             : 
     949             :     Assert(dim < ndims);
     950             : 
     951         108 :     result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL);
     952             : 
     953         396 :     for (i = 1; i <= dims[dim]; i++)
     954             :     {
     955         288 :         if (dim + 1 == ndims)
     956             :         {
     957         288 :             datum_to_jsonb(vals[*valcount], nulls[*valcount], result, tcategory,
     958             :                            outfuncoid, false);
     959         288 :             (*valcount)++;
     960             :         }
     961             :         else
     962             :         {
     963           0 :             array_dim_to_jsonb(result, dim + 1, ndims, dims, vals, nulls,
     964             :                                valcount, tcategory, outfuncoid);
     965             :         }
     966             :     }
     967             : 
     968         108 :     result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
     969         108 : }
     970             : 
     971             : /*
     972             :  * Turn an array into JSON.
     973             :  */
     974             : static void
     975         108 : array_to_jsonb_internal(Datum array, JsonbInState *result)
     976             : {
     977         108 :     ArrayType  *v = DatumGetArrayTypeP(array);
     978         108 :     Oid         element_type = ARR_ELEMTYPE(v);
     979             :     int        *dim;
     980             :     int         ndim;
     981             :     int         nitems;
     982         108 :     int         count = 0;
     983             :     Datum      *elements;
     984             :     bool       *nulls;
     985             :     int16       typlen;
     986             :     bool        typbyval;
     987             :     char        typalign;
     988             :     JsonbTypeCategory tcategory;
     989             :     Oid         outfuncoid;
     990             : 
     991         108 :     ndim = ARR_NDIM(v);
     992         108 :     dim = ARR_DIMS(v);
     993         108 :     nitems = ArrayGetNItems(ndim, dim);
     994             : 
     995         108 :     if (nitems <= 0)
     996             :     {
     997           0 :         result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL);
     998           0 :         result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
     999           0 :         return;
    1000             :     }
    1001             : 
    1002         108 :     get_typlenbyvalalign(element_type,
    1003             :                          &typlen, &typbyval, &typalign);
    1004             : 
    1005         108 :     jsonb_categorize_type(element_type,
    1006             :                           &tcategory, &outfuncoid);
    1007             : 
    1008         108 :     deconstruct_array(v, element_type, typlen, typbyval,
    1009             :                       typalign, &elements, &nulls,
    1010             :                       &nitems);
    1011             : 
    1012         108 :     array_dim_to_jsonb(result, 0, ndim, dim, elements, nulls, &count, tcategory,
    1013             :                        outfuncoid);
    1014             : 
    1015         108 :     pfree(elements);
    1016         108 :     pfree(nulls);
    1017             : }
    1018             : 
    1019             : /*
    1020             :  * Turn a composite / record into JSON.
    1021             :  */
    1022             : static void
    1023         192 : composite_to_jsonb(Datum composite, JsonbInState *result)
    1024             : {
    1025             :     HeapTupleHeader td;
    1026             :     Oid         tupType;
    1027             :     int32       tupTypmod;
    1028             :     TupleDesc   tupdesc;
    1029             :     HeapTupleData tmptup,
    1030             :                *tuple;
    1031             :     int         i;
    1032             : 
    1033         192 :     td = DatumGetHeapTupleHeader(composite);
    1034             : 
    1035             :     /* Extract rowtype info and find a tupdesc */
    1036         192 :     tupType = HeapTupleHeaderGetTypeId(td);
    1037         192 :     tupTypmod = HeapTupleHeaderGetTypMod(td);
    1038         192 :     tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    1039             : 
    1040             :     /* Build a temporary HeapTuple control structure */
    1041         192 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
    1042         192 :     tmptup.t_data = td;
    1043         192 :     tuple = &tmptup;
    1044             : 
    1045         192 :     result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_OBJECT, NULL);
    1046             : 
    1047         588 :     for (i = 0; i < tupdesc->natts; i++)
    1048             :     {
    1049             :         Datum       val;
    1050             :         bool        isnull;
    1051             :         char       *attname;
    1052             :         JsonbTypeCategory tcategory;
    1053             :         Oid         outfuncoid;
    1054             :         JsonbValue  v;
    1055         396 :         Form_pg_attribute att = TupleDescAttr(tupdesc, i);
    1056             : 
    1057         396 :         if (att->attisdropped)
    1058           0 :             continue;
    1059             : 
    1060         396 :         attname = NameStr(att->attname);
    1061             : 
    1062         396 :         v.type = jbvString;
    1063             :         /* don't need checkStringLen here - can't exceed maximum name length */
    1064         396 :         v.val.string.len = strlen(attname);
    1065         396 :         v.val.string.val = attname;
    1066             : 
    1067         396 :         result->res = pushJsonbValue(&result->parseState, WJB_KEY, &v);
    1068             : 
    1069         396 :         val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
    1070             : 
    1071         396 :         if (isnull)
    1072             :         {
    1073          30 :             tcategory = JSONBTYPE_NULL;
    1074          30 :             outfuncoid = InvalidOid;
    1075             :         }
    1076             :         else
    1077         366 :             jsonb_categorize_type(att->atttypid, &tcategory, &outfuncoid);
    1078             : 
    1079         396 :         datum_to_jsonb(val, isnull, result, tcategory, outfuncoid, false);
    1080             :     }
    1081             : 
    1082         192 :     result->res = pushJsonbValue(&result->parseState, WJB_END_OBJECT, NULL);
    1083         192 :     ReleaseTupleDesc(tupdesc);
    1084         192 : }
    1085             : 
    1086             : /*
    1087             :  * Append JSON text for "val" to "result".
    1088             :  *
    1089             :  * This is just a thin wrapper around datum_to_jsonb.  If the same type will be
    1090             :  * printed many times, avoid using this; better to do the jsonb_categorize_type
    1091             :  * lookups only once.
    1092             :  */
    1093             : 
    1094             : static void
    1095        1614 : add_jsonb(Datum val, bool is_null, JsonbInState *result,
    1096             :           Oid val_type, bool key_scalar)
    1097             : {
    1098             :     JsonbTypeCategory tcategory;
    1099             :     Oid         outfuncoid;
    1100             : 
    1101        1614 :     if (val_type == InvalidOid)
    1102           0 :         ereport(ERROR,
    1103             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1104             :                  errmsg("could not determine input data type")));
    1105             : 
    1106        1614 :     if (is_null)
    1107             :     {
    1108          78 :         tcategory = JSONBTYPE_NULL;
    1109          78 :         outfuncoid = InvalidOid;
    1110             :     }
    1111             :     else
    1112        1536 :         jsonb_categorize_type(val_type,
    1113             :                               &tcategory, &outfuncoid);
    1114             : 
    1115        1614 :     datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar);
    1116        1590 : }
    1117             : 
    1118             : Datum
    1119          96 : to_jsonb_worker(Datum val, JsonbTypeCategory tcategory, Oid outfuncoid)
    1120             : {
    1121             :     JsonbInState result;
    1122             : 
    1123          96 :     memset(&result, 0, sizeof(JsonbInState));
    1124             : 
    1125          96 :     datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false);
    1126             : 
    1127          96 :     return JsonbPGetDatum(JsonbValueToJsonb(result.res));
    1128             : }
    1129             : 
    1130             : bool
    1131           0 : to_jsonb_is_immutable(Oid typoid)
    1132             : {
    1133             :     JsonbTypeCategory tcategory;
    1134             :     Oid         outfuncoid;
    1135             : 
    1136           0 :     jsonb_categorize_type(typoid, &tcategory, &outfuncoid);
    1137             : 
    1138           0 :     switch (tcategory)
    1139             :     {
    1140           0 :         case JSONBTYPE_BOOL:
    1141             :         case JSONBTYPE_JSON:
    1142             :         case JSONBTYPE_JSONB:
    1143           0 :             return true;
    1144             : 
    1145           0 :         case JSONBTYPE_DATE:
    1146             :         case JSONBTYPE_TIMESTAMP:
    1147             :         case JSONBTYPE_TIMESTAMPTZ:
    1148           0 :             return false;
    1149             : 
    1150           0 :         case JSONBTYPE_ARRAY:
    1151           0 :             return false;       /* TODO recurse into elements */
    1152             : 
    1153           0 :         case JSONBTYPE_COMPOSITE:
    1154           0 :             return false;       /* TODO recurse into fields */
    1155             : 
    1156           0 :         case JSONBTYPE_NUMERIC:
    1157             :         case JSONBTYPE_JSONCAST:
    1158             :         default:
    1159           0 :             return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE;
    1160             :     }
    1161             : }
    1162             : 
    1163             : /*
    1164             :  * SQL function to_jsonb(anyvalue)
    1165             :  */
    1166             : Datum
    1167          96 : to_jsonb(PG_FUNCTION_ARGS)
    1168             : {
    1169          96 :     Datum       val = PG_GETARG_DATUM(0);
    1170          96 :     Oid         val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
    1171             :     JsonbTypeCategory tcategory;
    1172             :     Oid         outfuncoid;
    1173             : 
    1174          96 :     if (val_type == InvalidOid)
    1175           0 :         ereport(ERROR,
    1176             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1177             :                  errmsg("could not determine input data type")));
    1178             : 
    1179          96 :     jsonb_categorize_type(val_type,
    1180             :                           &tcategory, &outfuncoid);
    1181             : 
    1182          96 :     PG_RETURN_DATUM(to_jsonb_worker(val, tcategory, outfuncoid));
    1183             : }
    1184             : 
    1185             : Datum
    1186         402 : jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
    1187             :                           bool absent_on_null, bool unique_keys)
    1188             : {
    1189             :     int         i;
    1190             :     JsonbInState result;
    1191             : 
    1192         402 :     if (nargs % 2 != 0)
    1193          18 :         ereport(ERROR,
    1194             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1195             :                  errmsg("argument list must have even number of elements"),
    1196             :         /* translator: %s is a SQL function name */
    1197             :                  errhint("The arguments of %s must consist of alternating keys and values.",
    1198             :                          "jsonb_build_object()")));
    1199             : 
    1200         384 :     memset(&result, 0, sizeof(JsonbInState));
    1201             : 
    1202         384 :     result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
    1203         384 :     result.parseState->unique_keys = unique_keys;
    1204         384 :     result.parseState->skip_nulls = absent_on_null;
    1205             : 
    1206        1008 :     for (i = 0; i < nargs; i += 2)
    1207             :     {
    1208             :         /* process key */
    1209             :         bool        skip;
    1210             : 
    1211         666 :         if (nulls[i])
    1212          18 :             ereport(ERROR,
    1213             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1214             :                      errmsg("argument %d: key must not be null", i + 1)));
    1215             : 
    1216             :         /* skip null values if absent_on_null */
    1217         648 :         skip = absent_on_null && nulls[i + 1];
    1218             : 
    1219             :         /* we need to save skipped keys for the key uniqueness check */
    1220         648 :         if (skip && !unique_keys)
    1221           6 :             continue;
    1222             : 
    1223         642 :         add_jsonb(args[i], false, &result, types[i], true);
    1224             : 
    1225             :         /* process value */
    1226         618 :         add_jsonb(args[i + 1], nulls[i + 1], &result, types[i + 1], false);
    1227             :     }
    1228             : 
    1229         342 :     result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
    1230             : 
    1231         324 :     return JsonbPGetDatum(JsonbValueToJsonb(result.res));
    1232             : }
    1233             : 
    1234             : /*
    1235             :  * SQL function jsonb_build_object(variadic "any")
    1236             :  */
    1237             : Datum
    1238         336 : jsonb_build_object(PG_FUNCTION_ARGS)
    1239             : {
    1240             :     Datum      *args;
    1241             :     bool       *nulls;
    1242             :     Oid        *types;
    1243             : 
    1244             :     /* build argument values to build the object */
    1245         336 :     int         nargs = extract_variadic_args(fcinfo, 0, true,
    1246             :                                               &args, &types, &nulls);
    1247             : 
    1248         336 :     if (nargs < 0)
    1249           6 :         PG_RETURN_NULL();
    1250             : 
    1251         330 :     PG_RETURN_DATUM(jsonb_build_object_worker(nargs, args, nulls, types, false, false));
    1252             : }
    1253             : 
    1254             : /*
    1255             :  * degenerate case of jsonb_build_object where it gets 0 arguments.
    1256             :  */
    1257             : Datum
    1258           6 : jsonb_build_object_noargs(PG_FUNCTION_ARGS)
    1259             : {
    1260             :     JsonbInState result;
    1261             : 
    1262           6 :     memset(&result, 0, sizeof(JsonbInState));
    1263             : 
    1264           6 :     (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
    1265           6 :     result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
    1266             : 
    1267           6 :     PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
    1268             : }
    1269             : 
    1270             : Datum
    1271         174 : jsonb_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types,
    1272             :                          bool absent_on_null)
    1273             : {
    1274             :     int         i;
    1275             :     JsonbInState result;
    1276             : 
    1277         174 :     memset(&result, 0, sizeof(JsonbInState));
    1278             : 
    1279         174 :     result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
    1280             : 
    1281         552 :     for (i = 0; i < nargs; i++)
    1282             :     {
    1283         378 :         if (absent_on_null && nulls[i])
    1284          24 :             continue;
    1285             : 
    1286         354 :         add_jsonb(args[i], nulls[i], &result, types[i], false);
    1287             :     }
    1288             : 
    1289         174 :     result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
    1290             : 
    1291         174 :     return JsonbPGetDatum(JsonbValueToJsonb(result.res));
    1292             : }
    1293             : 
    1294             : /*
    1295             :  * SQL function jsonb_build_array(variadic "any")
    1296             :  */
    1297             : Datum
    1298         150 : jsonb_build_array(PG_FUNCTION_ARGS)
    1299             : {
    1300             :     Datum      *args;
    1301             :     bool       *nulls;
    1302             :     Oid        *types;
    1303             : 
    1304             :     /* build argument values to build the object */
    1305         150 :     int         nargs = extract_variadic_args(fcinfo, 0, true,
    1306             :                                               &args, &types, &nulls);
    1307             : 
    1308         150 :     if (nargs < 0)
    1309           6 :         PG_RETURN_NULL();
    1310             : 
    1311         144 :     PG_RETURN_DATUM(jsonb_build_array_worker(nargs, args, nulls, types, false));
    1312             : }
    1313             : 
    1314             : 
    1315             : /*
    1316             :  * degenerate case of jsonb_build_array where it gets 0 arguments.
    1317             :  */
    1318             : Datum
    1319           6 : jsonb_build_array_noargs(PG_FUNCTION_ARGS)
    1320             : {
    1321             :     JsonbInState result;
    1322             : 
    1323           6 :     memset(&result, 0, sizeof(JsonbInState));
    1324             : 
    1325           6 :     (void) pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
    1326           6 :     result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
    1327             : 
    1328           6 :     PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
    1329             : }
    1330             : 
    1331             : 
    1332             : /*
    1333             :  * SQL function jsonb_object(text[])
    1334             :  *
    1335             :  * take a one or two dimensional array of text as name value pairs
    1336             :  * for a jsonb object.
    1337             :  *
    1338             :  */
    1339             : Datum
    1340          42 : jsonb_object(PG_FUNCTION_ARGS)
    1341             : {
    1342          42 :     ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
    1343          42 :     int         ndims = ARR_NDIM(in_array);
    1344             :     Datum      *in_datums;
    1345             :     bool       *in_nulls;
    1346             :     int         in_count,
    1347             :                 count,
    1348             :                 i;
    1349             :     JsonbInState result;
    1350             : 
    1351          42 :     memset(&result, 0, sizeof(JsonbInState));
    1352             : 
    1353          42 :     (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
    1354             : 
    1355          42 :     switch (ndims)
    1356             :     {
    1357           6 :         case 0:
    1358           6 :             goto close_object;
    1359             :             break;
    1360             : 
    1361          12 :         case 1:
    1362          12 :             if ((ARR_DIMS(in_array)[0]) % 2)
    1363           6 :                 ereport(ERROR,
    1364             :                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    1365             :                          errmsg("array must have even number of elements")));
    1366           6 :             break;
    1367             : 
    1368          18 :         case 2:
    1369          18 :             if ((ARR_DIMS(in_array)[1]) != 2)
    1370          12 :                 ereport(ERROR,
    1371             :                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    1372             :                          errmsg("array must have two columns")));
    1373           6 :             break;
    1374             : 
    1375           6 :         default:
    1376           6 :             ereport(ERROR,
    1377             :                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    1378             :                      errmsg("wrong number of array subscripts")));
    1379             :     }
    1380             : 
    1381          12 :     deconstruct_array(in_array,
    1382             :                       TEXTOID, -1, false, TYPALIGN_INT,
    1383             :                       &in_datums, &in_nulls, &in_count);
    1384             : 
    1385          12 :     count = in_count / 2;
    1386             : 
    1387          60 :     for (i = 0; i < count; ++i)
    1388             :     {
    1389             :         JsonbValue  v;
    1390             :         char       *str;
    1391             :         int         len;
    1392             : 
    1393          48 :         if (in_nulls[i * 2])
    1394           0 :             ereport(ERROR,
    1395             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    1396             :                      errmsg("null value not allowed for object key")));
    1397             : 
    1398          48 :         str = TextDatumGetCString(in_datums[i * 2]);
    1399          48 :         len = strlen(str);
    1400             : 
    1401          48 :         v.type = jbvString;
    1402             : 
    1403          48 :         v.val.string.len = len;
    1404          48 :         v.val.string.val = str;
    1405             : 
    1406          48 :         (void) pushJsonbValue(&result.parseState, WJB_KEY, &v);
    1407             : 
    1408          48 :         if (in_nulls[i * 2 + 1])
    1409             :         {
    1410          12 :             v.type = jbvNull;
    1411             :         }
    1412             :         else
    1413             :         {
    1414          36 :             str = TextDatumGetCString(in_datums[i * 2 + 1]);
    1415          36 :             len = strlen(str);
    1416             : 
    1417          36 :             v.type = jbvString;
    1418             : 
    1419          36 :             v.val.string.len = len;
    1420          36 :             v.val.string.val = str;
    1421             :         }
    1422             : 
    1423          48 :         (void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
    1424             :     }
    1425             : 
    1426          12 :     pfree(in_datums);
    1427          12 :     pfree(in_nulls);
    1428             : 
    1429          18 : close_object:
    1430          18 :     result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
    1431             : 
    1432          18 :     PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
    1433             : }
    1434             : 
    1435             : /*
    1436             :  * SQL function jsonb_object(text[], text[])
    1437             :  *
    1438             :  * take separate name and value arrays of text to construct a jsonb object
    1439             :  * pairwise.
    1440             :  */
    1441             : Datum
    1442          42 : jsonb_object_two_arg(PG_FUNCTION_ARGS)
    1443             : {
    1444          42 :     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(0);
    1445          42 :     ArrayType  *val_array = PG_GETARG_ARRAYTYPE_P(1);
    1446          42 :     int         nkdims = ARR_NDIM(key_array);
    1447          42 :     int         nvdims = ARR_NDIM(val_array);
    1448             :     Datum      *key_datums,
    1449             :                *val_datums;
    1450             :     bool       *key_nulls,
    1451             :                *val_nulls;
    1452             :     int         key_count,
    1453             :                 val_count,
    1454             :                 i;
    1455             :     JsonbInState result;
    1456             : 
    1457          42 :     memset(&result, 0, sizeof(JsonbInState));
    1458             : 
    1459          42 :     (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
    1460             : 
    1461          42 :     if (nkdims > 1 || nkdims != nvdims)
    1462           6 :         ereport(ERROR,
    1463             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    1464             :                  errmsg("wrong number of array subscripts")));
    1465             : 
    1466          36 :     if (nkdims == 0)
    1467           6 :         goto close_object;
    1468             : 
    1469          30 :     deconstruct_array(key_array,
    1470             :                       TEXTOID, -1, false, TYPALIGN_INT,
    1471             :                       &key_datums, &key_nulls, &key_count);
    1472             : 
    1473          30 :     deconstruct_array(val_array,
    1474             :                       TEXTOID, -1, false, TYPALIGN_INT,
    1475             :                       &val_datums, &val_nulls, &val_count);
    1476             : 
    1477          30 :     if (key_count != val_count)
    1478          12 :         ereport(ERROR,
    1479             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    1480             :                  errmsg("mismatched array dimensions")));
    1481             : 
    1482          78 :     for (i = 0; i < key_count; ++i)
    1483             :     {
    1484             :         JsonbValue  v;
    1485             :         char       *str;
    1486             :         int         len;
    1487             : 
    1488          66 :         if (key_nulls[i])
    1489           6 :             ereport(ERROR,
    1490             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    1491             :                      errmsg("null value not allowed for object key")));
    1492             : 
    1493          60 :         str = TextDatumGetCString(key_datums[i]);
    1494          60 :         len = strlen(str);
    1495             : 
    1496          60 :         v.type = jbvString;
    1497             : 
    1498          60 :         v.val.string.len = len;
    1499          60 :         v.val.string.val = str;
    1500             : 
    1501          60 :         (void) pushJsonbValue(&result.parseState, WJB_KEY, &v);
    1502             : 
    1503          60 :         if (val_nulls[i])
    1504             :         {
    1505           0 :             v.type = jbvNull;
    1506             :         }
    1507             :         else
    1508             :         {
    1509          60 :             str = TextDatumGetCString(val_datums[i]);
    1510          60 :             len = strlen(str);
    1511             : 
    1512          60 :             v.type = jbvString;
    1513             : 
    1514          60 :             v.val.string.len = len;
    1515          60 :             v.val.string.val = str;
    1516             :         }
    1517             : 
    1518          60 :         (void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
    1519             :     }
    1520             : 
    1521          12 :     pfree(key_datums);
    1522          12 :     pfree(key_nulls);
    1523          12 :     pfree(val_datums);
    1524          12 :     pfree(val_nulls);
    1525             : 
    1526          18 : close_object:
    1527          18 :     result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
    1528             : 
    1529          18 :     PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
    1530             : }
    1531             : 
    1532             : 
    1533             : /*
    1534             :  * shallow clone of a parse state, suitable for use in aggregate
    1535             :  * final functions that will only append to the values rather than
    1536             :  * change them.
    1537             :  */
    1538             : static JsonbParseState *
    1539         120 : clone_parse_state(JsonbParseState *state)
    1540             : {
    1541             :     JsonbParseState *result,
    1542             :                *icursor,
    1543             :                *ocursor;
    1544             : 
    1545         120 :     if (state == NULL)
    1546           0 :         return NULL;
    1547             : 
    1548         120 :     result = palloc(sizeof(JsonbParseState));
    1549         120 :     icursor = state;
    1550         120 :     ocursor = result;
    1551             :     for (;;)
    1552             :     {
    1553         120 :         ocursor->contVal = icursor->contVal;
    1554         120 :         ocursor->size = icursor->size;
    1555         120 :         ocursor->unique_keys = icursor->unique_keys;
    1556         120 :         ocursor->skip_nulls = icursor->skip_nulls;
    1557         120 :         icursor = icursor->next;
    1558         120 :         if (icursor == NULL)
    1559         120 :             break;
    1560           0 :         ocursor->next = palloc(sizeof(JsonbParseState));
    1561           0 :         ocursor = ocursor->next;
    1562             :     }
    1563         120 :     ocursor->next = NULL;
    1564             : 
    1565         120 :     return result;
    1566             : }
    1567             : 
    1568             : static Datum
    1569         366 : jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
    1570             : {
    1571             :     MemoryContext oldcontext,
    1572             :                 aggcontext;
    1573             :     JsonbAggState *state;
    1574             :     JsonbInState elem;
    1575             :     Datum       val;
    1576             :     JsonbInState *result;
    1577         366 :     bool        single_scalar = false;
    1578             :     JsonbIterator *it;
    1579             :     Jsonb      *jbelem;
    1580             :     JsonbValue  v;
    1581             :     JsonbIteratorToken type;
    1582             : 
    1583         366 :     if (!AggCheckCallContext(fcinfo, &aggcontext))
    1584             :     {
    1585             :         /* cannot be called directly because of internal-type argument */
    1586           0 :         elog(ERROR, "jsonb_agg_transfn called in non-aggregate context");
    1587             :     }
    1588             : 
    1589             :     /* set up the accumulator on the first go round */
    1590             : 
    1591         366 :     if (PG_ARGISNULL(0))
    1592             :     {
    1593          66 :         Oid         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    1594             : 
    1595          66 :         if (arg_type == InvalidOid)
    1596           0 :             ereport(ERROR,
    1597             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1598             :                      errmsg("could not determine input data type")));
    1599             : 
    1600          66 :         oldcontext = MemoryContextSwitchTo(aggcontext);
    1601          66 :         state = palloc(sizeof(JsonbAggState));
    1602          66 :         result = palloc0(sizeof(JsonbInState));
    1603          66 :         state->res = result;
    1604          66 :         result->res = pushJsonbValue(&result->parseState,
    1605             :                                      WJB_BEGIN_ARRAY, NULL);
    1606          66 :         MemoryContextSwitchTo(oldcontext);
    1607             : 
    1608          66 :         jsonb_categorize_type(arg_type, &state->val_category,
    1609             :                               &state->val_output_func);
    1610             :     }
    1611             :     else
    1612             :     {
    1613         300 :         state = (JsonbAggState *) PG_GETARG_POINTER(0);
    1614         300 :         result = state->res;
    1615             :     }
    1616             : 
    1617         366 :     if (absent_on_null && PG_ARGISNULL(1))
    1618          78 :         PG_RETURN_POINTER(state);
    1619             : 
    1620             :     /* turn the argument into jsonb in the normal function context */
    1621             : 
    1622         288 :     val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
    1623             : 
    1624         288 :     memset(&elem, 0, sizeof(JsonbInState));
    1625             : 
    1626         288 :     datum_to_jsonb(val, PG_ARGISNULL(1), &elem, state->val_category,
    1627             :                    state->val_output_func, false);
    1628             : 
    1629         288 :     jbelem = JsonbValueToJsonb(elem.res);
    1630             : 
    1631             :     /* switch to the aggregate context for accumulation operations */
    1632             : 
    1633         288 :     oldcontext = MemoryContextSwitchTo(aggcontext);
    1634             : 
    1635         288 :     it = JsonbIteratorInit(&jbelem->root);
    1636             : 
    1637        1968 :     while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
    1638             :     {
    1639        1680 :         switch (type)
    1640             :         {
    1641         228 :             case WJB_BEGIN_ARRAY:
    1642         228 :                 if (v.val.array.rawScalar)
    1643         144 :                     single_scalar = true;
    1644             :                 else
    1645          84 :                     result->res = pushJsonbValue(&result->parseState,
    1646             :                                                  type, NULL);
    1647         228 :                 break;
    1648         228 :             case WJB_END_ARRAY:
    1649         228 :                 if (!single_scalar)
    1650          84 :                     result->res = pushJsonbValue(&result->parseState,
    1651             :                                                  type, NULL);
    1652         228 :                 break;
    1653         360 :             case WJB_BEGIN_OBJECT:
    1654             :             case WJB_END_OBJECT:
    1655         360 :                 result->res = pushJsonbValue(&result->parseState,
    1656             :                                              type, NULL);
    1657         360 :                 break;
    1658         864 :             case WJB_ELEM:
    1659             :             case WJB_KEY:
    1660             :             case WJB_VALUE:
    1661         864 :                 if (v.type == jbvString)
    1662             :                 {
    1663             :                     /* copy string values in the aggregate context */
    1664         372 :                     char       *buf = palloc(v.val.string.len + 1);
    1665             : 
    1666         372 :                     snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
    1667         372 :                     v.val.string.val = buf;
    1668             :                 }
    1669         492 :                 else if (v.type == jbvNumeric)
    1670             :                 {
    1671             :                     /* same for numeric */
    1672         408 :                     v.val.numeric =
    1673         408 :                         DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
    1674             :                                                             NumericGetDatum(v.val.numeric)));
    1675             :                 }
    1676         864 :                 result->res = pushJsonbValue(&result->parseState,
    1677             :                                              type, &v);
    1678         864 :                 break;
    1679           0 :             default:
    1680           0 :                 elog(ERROR, "unknown jsonb iterator token type");
    1681             :         }
    1682             :     }
    1683             : 
    1684         288 :     MemoryContextSwitchTo(oldcontext);
    1685             : 
    1686         288 :     PG_RETURN_POINTER(state);
    1687             : }
    1688             : 
    1689             : /*
    1690             :  * jsonb_agg aggregate function
    1691             :  */
    1692             : Datum
    1693         144 : jsonb_agg_transfn(PG_FUNCTION_ARGS)
    1694             : {
    1695         144 :     return jsonb_agg_transfn_worker(fcinfo, false);
    1696             : }
    1697             : 
    1698             : /*
    1699             :  * jsonb_agg_strict aggregate function
    1700             :  */
    1701             : Datum
    1702         222 : jsonb_agg_strict_transfn(PG_FUNCTION_ARGS)
    1703             : {
    1704         222 :     return jsonb_agg_transfn_worker(fcinfo, true);
    1705             : }
    1706             : 
    1707             : Datum
    1708          72 : jsonb_agg_finalfn(PG_FUNCTION_ARGS)
    1709             : {
    1710             :     JsonbAggState *arg;
    1711             :     JsonbInState result;
    1712             :     Jsonb      *out;
    1713             : 
    1714             :     /* cannot be called directly because of internal-type argument */
    1715             :     Assert(AggCheckCallContext(fcinfo, NULL));
    1716             : 
    1717          72 :     if (PG_ARGISNULL(0))
    1718           6 :         PG_RETURN_NULL();       /* returns null iff no input values */
    1719             : 
    1720          66 :     arg = (JsonbAggState *) PG_GETARG_POINTER(0);
    1721             : 
    1722             :     /*
    1723             :      * We need to do a shallow clone of the argument in case the final
    1724             :      * function is called more than once, so we avoid changing the argument. A
    1725             :      * shallow clone is sufficient as we aren't going to change any of the
    1726             :      * values, just add the final array end marker.
    1727             :      */
    1728             : 
    1729          66 :     result.parseState = clone_parse_state(arg->res->parseState);
    1730             : 
    1731          66 :     result.res = pushJsonbValue(&result.parseState,
    1732             :                                 WJB_END_ARRAY, NULL);
    1733             : 
    1734          66 :     out = JsonbValueToJsonb(result.res);
    1735             : 
    1736          66 :     PG_RETURN_POINTER(out);
    1737             : }
    1738             : 
    1739             : static Datum
    1740         228 : jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
    1741             :                                 bool absent_on_null, bool unique_keys)
    1742             : {
    1743             :     MemoryContext oldcontext,
    1744             :                 aggcontext;
    1745             :     JsonbInState elem;
    1746             :     JsonbAggState *state;
    1747             :     Datum       val;
    1748             :     JsonbInState *result;
    1749             :     bool        single_scalar;
    1750             :     JsonbIterator *it;
    1751             :     Jsonb      *jbkey,
    1752             :                *jbval;
    1753             :     JsonbValue  v;
    1754             :     JsonbIteratorToken type;
    1755             :     bool        skip;
    1756             : 
    1757         228 :     if (!AggCheckCallContext(fcinfo, &aggcontext))
    1758             :     {
    1759             :         /* cannot be called directly because of internal-type argument */
    1760           0 :         elog(ERROR, "jsonb_object_agg_transfn called in non-aggregate context");
    1761             :     }
    1762             : 
    1763             :     /* set up the accumulator on the first go round */
    1764             : 
    1765         228 :     if (PG_ARGISNULL(0))
    1766             :     {
    1767             :         Oid         arg_type;
    1768             : 
    1769          72 :         oldcontext = MemoryContextSwitchTo(aggcontext);
    1770          72 :         state = palloc(sizeof(JsonbAggState));
    1771          72 :         result = palloc0(sizeof(JsonbInState));
    1772          72 :         state->res = result;
    1773          72 :         result->res = pushJsonbValue(&result->parseState,
    1774             :                                      WJB_BEGIN_OBJECT, NULL);
    1775          72 :         result->parseState->unique_keys = unique_keys;
    1776          72 :         result->parseState->skip_nulls = absent_on_null;
    1777             : 
    1778          72 :         MemoryContextSwitchTo(oldcontext);
    1779             : 
    1780          72 :         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    1781             : 
    1782          72 :         if (arg_type == InvalidOid)
    1783           0 :             ereport(ERROR,
    1784             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1785             :                      errmsg("could not determine input data type")));
    1786             : 
    1787          72 :         jsonb_categorize_type(arg_type, &state->key_category,
    1788             :                               &state->key_output_func);
    1789             : 
    1790          72 :         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
    1791             : 
    1792          72 :         if (arg_type == InvalidOid)
    1793           0 :             ereport(ERROR,
    1794             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1795             :                      errmsg("could not determine input data type")));
    1796             : 
    1797          72 :         jsonb_categorize_type(arg_type, &state->val_category,
    1798             :                               &state->val_output_func);
    1799             :     }
    1800             :     else
    1801             :     {
    1802         156 :         state = (JsonbAggState *) PG_GETARG_POINTER(0);
    1803         156 :         result = state->res;
    1804             :     }
    1805             : 
    1806             :     /* turn the argument into jsonb in the normal function context */
    1807             : 
    1808         228 :     if (PG_ARGISNULL(1))
    1809          18 :         ereport(ERROR,
    1810             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1811             :                  errmsg("field name must not be null")));
    1812             : 
    1813             :     /*
    1814             :      * Skip null values if absent_on_null unless key uniqueness check is
    1815             :      * needed (because we must save keys in this case).
    1816             :      */
    1817         210 :     skip = absent_on_null && PG_ARGISNULL(2);
    1818             : 
    1819         210 :     if (skip && !unique_keys)
    1820          12 :         PG_RETURN_POINTER(state);
    1821             : 
    1822         198 :     val = PG_GETARG_DATUM(1);
    1823             : 
    1824         198 :     memset(&elem, 0, sizeof(JsonbInState));
    1825             : 
    1826         198 :     datum_to_jsonb(val, false, &elem, state->key_category,
    1827             :                    state->key_output_func, true);
    1828             : 
    1829         198 :     jbkey = JsonbValueToJsonb(elem.res);
    1830             : 
    1831         198 :     val = PG_ARGISNULL(2) ? (Datum) 0 : PG_GETARG_DATUM(2);
    1832             : 
    1833         198 :     memset(&elem, 0, sizeof(JsonbInState));
    1834             : 
    1835         198 :     datum_to_jsonb(val, PG_ARGISNULL(2), &elem, state->val_category,
    1836             :                    state->val_output_func, false);
    1837             : 
    1838         198 :     jbval = JsonbValueToJsonb(elem.res);
    1839             : 
    1840         198 :     it = JsonbIteratorInit(&jbkey->root);
    1841             : 
    1842             :     /* switch to the aggregate context for accumulation operations */
    1843             : 
    1844         198 :     oldcontext = MemoryContextSwitchTo(aggcontext);
    1845             : 
    1846             :     /*
    1847             :      * keys should be scalar, and we should have already checked for that
    1848             :      * above when calling datum_to_jsonb, so we only need to look for these
    1849             :      * things.
    1850             :      */
    1851             : 
    1852         732 :     while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
    1853             :     {
    1854         564 :         switch (type)
    1855             :         {
    1856         198 :             case WJB_BEGIN_ARRAY:
    1857         198 :                 if (!v.val.array.rawScalar)
    1858           0 :                     elog(ERROR, "unexpected structure for key");
    1859         198 :                 break;
    1860         198 :             case WJB_ELEM:
    1861         198 :                 if (v.type == jbvString)
    1862             :                 {
    1863             :                     /* copy string values in the aggregate context */
    1864         198 :                     char       *buf = palloc(v.val.string.len + 1);
    1865             : 
    1866         198 :                     snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
    1867         198 :                     v.val.string.val = buf;
    1868             :                 }
    1869             :                 else
    1870             :                 {
    1871           0 :                     ereport(ERROR,
    1872             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1873             :                              errmsg("object keys must be strings")));
    1874             :                 }
    1875         198 :                 result->res = pushJsonbValue(&result->parseState,
    1876             :                                              WJB_KEY, &v);
    1877             : 
    1878         198 :                 if (skip)
    1879             :                 {
    1880          30 :                     v.type = jbvNull;
    1881          30 :                     result->res = pushJsonbValue(&result->parseState,
    1882             :                                                  WJB_VALUE, &v);
    1883          30 :                     MemoryContextSwitchTo(oldcontext);
    1884          30 :                     PG_RETURN_POINTER(state);
    1885             :                 }
    1886             : 
    1887         168 :                 break;
    1888         168 :             case WJB_END_ARRAY:
    1889         168 :                 break;
    1890           0 :             default:
    1891           0 :                 elog(ERROR, "unexpected structure for key");
    1892             :                 break;
    1893             :         }
    1894             :     }
    1895             : 
    1896         168 :     it = JsonbIteratorInit(&jbval->root);
    1897             : 
    1898         168 :     single_scalar = false;
    1899             : 
    1900             :     /*
    1901             :      * values can be anything, including structured and null, so we treat them
    1902             :      * as in json_agg_transfn, except that single scalars are always pushed as
    1903             :      * WJB_VALUE items.
    1904             :      */
    1905             : 
    1906         726 :     while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
    1907             :     {
    1908         558 :         switch (type)
    1909             :         {
    1910         150 :             case WJB_BEGIN_ARRAY:
    1911         150 :                 if (v.val.array.rawScalar)
    1912         150 :                     single_scalar = true;
    1913             :                 else
    1914           0 :                     result->res = pushJsonbValue(&result->parseState,
    1915             :                                                  type, NULL);
    1916         150 :                 break;
    1917         150 :             case WJB_END_ARRAY:
    1918         150 :                 if (!single_scalar)
    1919           0 :                     result->res = pushJsonbValue(&result->parseState,
    1920             :                                                  type, NULL);
    1921         150 :                 break;
    1922          36 :             case WJB_BEGIN_OBJECT:
    1923             :             case WJB_END_OBJECT:
    1924          36 :                 result->res = pushJsonbValue(&result->parseState,
    1925             :                                              type, NULL);
    1926          36 :                 break;
    1927         222 :             case WJB_ELEM:
    1928             :             case WJB_KEY:
    1929             :             case WJB_VALUE:
    1930         222 :                 if (v.type == jbvString)
    1931             :                 {
    1932             :                     /* copy string values in the aggregate context */
    1933         108 :                     char       *buf = palloc(v.val.string.len + 1);
    1934             : 
    1935         108 :                     snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
    1936         108 :                     v.val.string.val = buf;
    1937             :                 }
    1938         114 :                 else if (v.type == jbvNumeric)
    1939             :                 {
    1940             :                     /* same for numeric */
    1941          90 :                     v.val.numeric =
    1942          90 :                         DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
    1943             :                                                             NumericGetDatum(v.val.numeric)));
    1944             :                 }
    1945         222 :                 result->res = pushJsonbValue(&result->parseState,
    1946             :                                              single_scalar ? WJB_VALUE : type,
    1947             :                                              &v);
    1948         222 :                 break;
    1949           0 :             default:
    1950           0 :                 elog(ERROR, "unknown jsonb iterator token type");
    1951             :         }
    1952             :     }
    1953             : 
    1954         168 :     MemoryContextSwitchTo(oldcontext);
    1955             : 
    1956         168 :     PG_RETURN_POINTER(state);
    1957             : }
    1958             : 
    1959             : /*
    1960             :  * jsonb_object_agg aggregate function
    1961             :  */
    1962             : Datum
    1963         132 : jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
    1964             : {
    1965         132 :     return jsonb_object_agg_transfn_worker(fcinfo, false, false);
    1966             : }
    1967             : 
    1968             : 
    1969             : /*
    1970             :  * jsonb_object_agg_strict aggregate function
    1971             :  */
    1972             : Datum
    1973          24 : jsonb_object_agg_strict_transfn(PG_FUNCTION_ARGS)
    1974             : {
    1975          24 :     return jsonb_object_agg_transfn_worker(fcinfo, true, false);
    1976             : }
    1977             : 
    1978             : /*
    1979             :  * jsonb_object_agg_unique aggregate function
    1980             :  */
    1981             : Datum
    1982          18 : jsonb_object_agg_unique_transfn(PG_FUNCTION_ARGS)
    1983             : {
    1984          18 :     return jsonb_object_agg_transfn_worker(fcinfo, false, true);
    1985             : }
    1986             : 
    1987             : /*
    1988             :  * jsonb_object_agg_unique_strict aggregate function
    1989             :  */
    1990             : Datum
    1991          54 : jsonb_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS)
    1992             : {
    1993          54 :     return jsonb_object_agg_transfn_worker(fcinfo, true, true);
    1994             : }
    1995             : 
    1996             : Datum
    1997          60 : jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
    1998             : {
    1999             :     JsonbAggState *arg;
    2000             :     JsonbInState result;
    2001             :     Jsonb      *out;
    2002             : 
    2003             :     /* cannot be called directly because of internal-type argument */
    2004             :     Assert(AggCheckCallContext(fcinfo, NULL));
    2005             : 
    2006          60 :     if (PG_ARGISNULL(0))
    2007           6 :         PG_RETURN_NULL();       /* returns null iff no input values */
    2008             : 
    2009          54 :     arg = (JsonbAggState *) PG_GETARG_POINTER(0);
    2010             : 
    2011             :     /*
    2012             :      * We need to do a shallow clone of the argument's res field in case the
    2013             :      * final function is called more than once, so we avoid changing the
    2014             :      * aggregate state value.  A shallow clone is sufficient as we aren't
    2015             :      * going to change any of the values, just add the final object end
    2016             :      * marker.
    2017             :      */
    2018             : 
    2019          54 :     result.parseState = clone_parse_state(arg->res->parseState);
    2020             : 
    2021          54 :     result.res = pushJsonbValue(&result.parseState,
    2022             :                                 WJB_END_OBJECT, NULL);
    2023             : 
    2024          42 :     out = JsonbValueToJsonb(result.res);
    2025             : 
    2026          42 :     PG_RETURN_POINTER(out);
    2027             : }
    2028             : 
    2029             : 
    2030             : /*
    2031             :  * Extract scalar value from raw-scalar pseudo-array jsonb.
    2032             :  */
    2033             : bool
    2034      797952 : JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
    2035             : {
    2036             :     JsonbIterator *it;
    2037             :     JsonbIteratorToken tok PG_USED_FOR_ASSERTS_ONLY;
    2038             :     JsonbValue  tmp;
    2039             : 
    2040      797952 :     if (!JsonContainerIsArray(jbc) || !JsonContainerIsScalar(jbc))
    2041             :     {
    2042             :         /* inform caller about actual type of container */
    2043      192942 :         res->type = (JsonContainerIsArray(jbc)) ? jbvArray : jbvObject;
    2044      192942 :         return false;
    2045             :     }
    2046             : 
    2047             :     /*
    2048             :      * A root scalar is stored as an array of one element, so we get the array
    2049             :      * and then its first (and only) member.
    2050             :      */
    2051      605010 :     it = JsonbIteratorInit(jbc);
    2052             : 
    2053      605010 :     tok = JsonbIteratorNext(&it, &tmp, true);
    2054             :     Assert(tok == WJB_BEGIN_ARRAY);
    2055             :     Assert(tmp.val.array.nElems == 1 && tmp.val.array.rawScalar);
    2056             : 
    2057      605010 :     tok = JsonbIteratorNext(&it, res, true);
    2058             :     Assert(tok == WJB_ELEM);
    2059             :     Assert(IsAJsonbScalar(res));
    2060             : 
    2061      605010 :     tok = JsonbIteratorNext(&it, &tmp, true);
    2062             :     Assert(tok == WJB_END_ARRAY);
    2063             : 
    2064      605010 :     tok = JsonbIteratorNext(&it, &tmp, true);
    2065             :     Assert(tok == WJB_DONE);
    2066             : 
    2067      605010 :     return true;
    2068             : }
    2069             : 
    2070             : /*
    2071             :  * Emit correct, translatable cast error message
    2072             :  */
    2073             : static void
    2074          24 : cannotCastJsonbValue(enum jbvType type, const char *sqltype)
    2075             : {
    2076             :     static const struct
    2077             :     {
    2078             :         enum jbvType type;
    2079             :         const char *msg;
    2080             :     }
    2081             :                 messages[] =
    2082             :     {
    2083             :         {jbvNull, gettext_noop("cannot cast jsonb null to type %s")},
    2084             :         {jbvString, gettext_noop("cannot cast jsonb string to type %s")},
    2085             :         {jbvNumeric, gettext_noop("cannot cast jsonb numeric to type %s")},
    2086             :         {jbvBool, gettext_noop("cannot cast jsonb boolean to type %s")},
    2087             :         {jbvArray, gettext_noop("cannot cast jsonb array to type %s")},
    2088             :         {jbvObject, gettext_noop("cannot cast jsonb object to type %s")},
    2089             :         {jbvBinary, gettext_noop("cannot cast jsonb array or object to type %s")}
    2090             :     };
    2091             :     int         i;
    2092             : 
    2093         108 :     for (i = 0; i < lengthof(messages); i++)
    2094         108 :         if (messages[i].type == type)
    2095          24 :             ereport(ERROR,
    2096             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2097             :                      errmsg(messages[i].msg, sqltype)));
    2098             : 
    2099             :     /* should be unreachable */
    2100           0 :     elog(ERROR, "unknown jsonb type: %d", (int) type);
    2101             : }
    2102             : 
    2103             : Datum
    2104          12 : jsonb_bool(PG_FUNCTION_ARGS)
    2105             : {
    2106          12 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
    2107             :     JsonbValue  v;
    2108             : 
    2109          12 :     if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvBool)
    2110           6 :         cannotCastJsonbValue(v.type, "boolean");
    2111             : 
    2112           6 :     PG_FREE_IF_COPY(in, 0);
    2113             : 
    2114           6 :     PG_RETURN_BOOL(v.val.boolean);
    2115             : }
    2116             : 
    2117             : Datum
    2118          24 : jsonb_numeric(PG_FUNCTION_ARGS)
    2119             : {
    2120          24 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
    2121             :     JsonbValue  v;
    2122             :     Numeric     retValue;
    2123             : 
    2124          24 :     if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
    2125           6 :         cannotCastJsonbValue(v.type, "numeric");
    2126             : 
    2127             :     /*
    2128             :      * v.val.numeric points into jsonb body, so we need to make a copy to
    2129             :      * return
    2130             :      */
    2131          18 :     retValue = DatumGetNumericCopy(NumericGetDatum(v.val.numeric));
    2132             : 
    2133          18 :     PG_FREE_IF_COPY(in, 0);
    2134             : 
    2135          18 :     PG_RETURN_NUMERIC(retValue);
    2136             : }
    2137             : 
    2138             : Datum
    2139          12 : jsonb_int2(PG_FUNCTION_ARGS)
    2140             : {
    2141          12 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
    2142             :     JsonbValue  v;
    2143             :     Datum       retValue;
    2144             : 
    2145          12 :     if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
    2146           0 :         cannotCastJsonbValue(v.type, "smallint");
    2147             : 
    2148          12 :     retValue = DirectFunctionCall1(numeric_int2,
    2149             :                                    NumericGetDatum(v.val.numeric));
    2150             : 
    2151          12 :     PG_FREE_IF_COPY(in, 0);
    2152             : 
    2153          12 :     PG_RETURN_DATUM(retValue);
    2154             : }
    2155             : 
    2156             : Datum
    2157          30 : jsonb_int4(PG_FUNCTION_ARGS)
    2158             : {
    2159          30 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
    2160             :     JsonbValue  v;
    2161             :     Datum       retValue;
    2162             : 
    2163          30 :     if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
    2164           6 :         cannotCastJsonbValue(v.type, "integer");
    2165             : 
    2166          24 :     retValue = DirectFunctionCall1(numeric_int4,
    2167             :                                    NumericGetDatum(v.val.numeric));
    2168             : 
    2169          24 :     PG_FREE_IF_COPY(in, 0);
    2170             : 
    2171          24 :     PG_RETURN_DATUM(retValue);
    2172             : }
    2173             : 
    2174             : Datum
    2175          48 : jsonb_int8(PG_FUNCTION_ARGS)
    2176             : {
    2177          48 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
    2178             :     JsonbValue  v;
    2179             :     Datum       retValue;
    2180             : 
    2181          48 :     if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
    2182           0 :         cannotCastJsonbValue(v.type, "bigint");
    2183             : 
    2184          48 :     retValue = DirectFunctionCall1(numeric_int8,
    2185             :                                    NumericGetDatum(v.val.numeric));
    2186             : 
    2187          48 :     PG_FREE_IF_COPY(in, 0);
    2188             : 
    2189          48 :     PG_RETURN_DATUM(retValue);
    2190             : }
    2191             : 
    2192             : Datum
    2193          12 : jsonb_float4(PG_FUNCTION_ARGS)
    2194             : {
    2195          12 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
    2196             :     JsonbValue  v;
    2197             :     Datum       retValue;
    2198             : 
    2199          12 :     if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
    2200           0 :         cannotCastJsonbValue(v.type, "real");
    2201             : 
    2202          12 :     retValue = DirectFunctionCall1(numeric_float4,
    2203             :                                    NumericGetDatum(v.val.numeric));
    2204             : 
    2205          12 :     PG_FREE_IF_COPY(in, 0);
    2206             : 
    2207          12 :     PG_RETURN_DATUM(retValue);
    2208             : }
    2209             : 
    2210             : Datum
    2211          24 : jsonb_float8(PG_FUNCTION_ARGS)
    2212             : {
    2213          24 :     Jsonb      *in = PG_GETARG_JSONB_P(0);
    2214             :     JsonbValue  v;
    2215             :     Datum       retValue;
    2216             : 
    2217          24 :     if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
    2218           6 :         cannotCastJsonbValue(v.type, "double precision");
    2219             : 
    2220          18 :     retValue = DirectFunctionCall1(numeric_float8,
    2221             :                                    NumericGetDatum(v.val.numeric));
    2222             : 
    2223          18 :     PG_FREE_IF_COPY(in, 0);
    2224             : 
    2225          18 :     PG_RETURN_DATUM(retValue);
    2226             : }
    2227             : 
    2228             : /*
    2229             :  * Construct an empty array jsonb.
    2230             :  */
    2231             : Jsonb *
    2232          84 : JsonbMakeEmptyArray(void)
    2233             : {
    2234             :     JsonbValue  jbv;
    2235             : 
    2236          84 :     jbv.type = jbvArray;
    2237          84 :     jbv.val.array.elems = NULL;
    2238          84 :     jbv.val.array.nElems = 0;
    2239          84 :     jbv.val.array.rawScalar = false;
    2240             : 
    2241          84 :     return JsonbValueToJsonb(&jbv);
    2242             : }
    2243             : 
    2244             : /*
    2245             :  * Construct an empty object jsonb.
    2246             :  */
    2247             : Jsonb *
    2248          36 : JsonbMakeEmptyObject(void)
    2249             : {
    2250             :     JsonbValue  jbv;
    2251             : 
    2252          36 :     jbv.type = jbvObject;
    2253          36 :     jbv.val.object.pairs = NULL;
    2254          36 :     jbv.val.object.nPairs = 0;
    2255             : 
    2256          36 :     return JsonbValueToJsonb(&jbv);
    2257             : }
    2258             : 
    2259             : /*
    2260             :  * Convert jsonb to a C-string stripping quotes from scalar strings.
    2261             :  */
    2262             : char *
    2263         168 : JsonbUnquote(Jsonb *jb)
    2264             : {
    2265         168 :     if (JB_ROOT_IS_SCALAR(jb))
    2266             :     {
    2267             :         JsonbValue  v;
    2268             : 
    2269         168 :         (void) JsonbExtractScalar(&jb->root, &v);
    2270             : 
    2271         168 :         if (v.type == jbvString)
    2272          90 :             return pnstrdup(v.val.string.val, v.val.string.len);
    2273          78 :         else if (v.type == jbvBool)
    2274          24 :             return pstrdup(v.val.boolean ? "true" : "false");
    2275          54 :         else if (v.type == jbvNumeric)
    2276          42 :             return DatumGetCString(DirectFunctionCall1(numeric_out,
    2277             :                                                        PointerGetDatum(v.val.numeric)));
    2278          12 :         else if (v.type == jbvNull)
    2279          12 :             return pstrdup("null");
    2280             :         else
    2281             :         {
    2282           0 :             elog(ERROR, "unrecognized jsonb value type %d", v.type);
    2283             :             return NULL;
    2284             :         }
    2285             :     }
    2286             :     else
    2287           0 :         return JsonbToCString(NULL, &jb->root, VARSIZE(jb));
    2288             : }

Generated by: LCOV version 1.14