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

Generated by: LCOV version 2.0-1