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

Generated by: LCOV version 1.16