LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonb.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 767 863 88.9 %
Date: 2024-11-21 08:14:44 Functions: 54 58 93.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14