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

Generated by: LCOV version 1.16