LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonb.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 88.7 % 985 874
Test Date: 2026-01-26 10:56:24 Functions: 93.0 % 57 53
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 63.3 % 531 336

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

Generated by: LCOV version 2.3.2-1