LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonb.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 90.1 % 797 718
Test Date: 2026-07-22 12:15:41 Functions: 94.7 % 57 54
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 72.8 % 441 321

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

Generated by: LCOV version 2.0-1