LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonb.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 755 851 88.7 %
Date: 2023-12-05 07:10:55 Functions: 53 57 93.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14