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

Generated by: LCOV version 1.13