LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - jsonb.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 89.1 % 880 784 12 84 59 725 14 79
Current Date: 2024-04-14 14:21:10 Functions: 93.1 % 58 54 4 15 39 6
Baseline: 16@8cea358b128 Branches: 67.1 % 517 347 18 152 22 325
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 85.7 % 14 12 2 12
(180,240] days: 100.0 % 8 8 8
(240..) days: 89.0 % 858 764 10 84 39 725
Function coverage date bins:
[..60] days: 100.0 % 1 1 1
(180,240] days: 100.0 % 3 3 3
(240..) days: 92.6 % 54 50 4 11 39
Branch coverage date bins:
[..60] days: 78.6 % 14 11 3 11
(180,240] days: 100.0 % 2 2 2
(240..) days: 66.7 % 501 334 15 152 9 325

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

Generated by: LCOV version 2.1-beta2-3-g6141622