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

Generated by: LCOV version 1.13