LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonb.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 787 885 88.9 %
Date: 2023-05-31 02:11:47 Functions: 53 56 94.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14