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

Generated by: LCOV version 2.0-1