LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - json.c (source / functions) Coverage Total Hit UNC LBC UIC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 92.3 % 677 625 21 11 20 17 292 165 151 32 446 3 17
Current Date: 2023-04-08 17:13:01 Functions: 93.8 % 48 45 1 2 23 22 3 42 3
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 88.9 % 180 160 20 160
Legend: Lines: hit not hit (60,120] days: 66.7 % 3 2 1 2
(180,240] days: 100.0 % 6 6 4 2 1 2
(240..) days: 93.6 % 488 457 11 20 17 288 3 149 22 239
Function coverage date bins:
[..60] days: 95.7 % 23 22 1 22
(180,240] days: 0.0 % 2 0 2
(240..) days: 41.1 % 56 23 2 23 3 28

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * json.c
                                  4                 :  *      JSON data type support.
                                  5                 :  *
                                  6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  7                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :  *
                                  9                 :  * IDENTIFICATION
                                 10                 :  *    src/backend/utils/adt/json.c
                                 11                 :  *
                                 12                 :  *-------------------------------------------------------------------------
                                 13                 :  */
                                 14                 : #include "postgres.h"
                                 15                 : 
                                 16                 : #include "catalog/pg_proc.h"
                                 17                 : #include "catalog/pg_type.h"
                                 18                 : #include "common/hashfn.h"
                                 19                 : #include "funcapi.h"
                                 20                 : #include "libpq/pqformat.h"
                                 21                 : #include "miscadmin.h"
                                 22                 : #include "parser/parse_coerce.h"
                                 23                 : #include "utils/array.h"
                                 24                 : #include "utils/builtins.h"
                                 25                 : #include "utils/date.h"
                                 26                 : #include "utils/datetime.h"
                                 27                 : #include "utils/json.h"
                                 28                 : #include "utils/jsonfuncs.h"
                                 29                 : #include "utils/lsyscache.h"
                                 30                 : #include "utils/typcache.h"
                                 31                 : 
                                 32                 : typedef enum                    /* type categories for datum_to_json */
                                 33                 : {
                                 34                 :     JSONTYPE_NULL,              /* null, so we didn't bother to identify */
                                 35                 :     JSONTYPE_BOOL,              /* boolean (built-in types only) */
                                 36                 :     JSONTYPE_NUMERIC,           /* numeric (ditto) */
                                 37                 :     JSONTYPE_DATE,              /* we use special formatting for datetimes */
                                 38                 :     JSONTYPE_TIMESTAMP,
                                 39                 :     JSONTYPE_TIMESTAMPTZ,
                                 40                 :     JSONTYPE_JSON,              /* JSON itself (and JSONB) */
                                 41                 :     JSONTYPE_ARRAY,             /* array */
                                 42                 :     JSONTYPE_COMPOSITE,         /* composite */
                                 43                 :     JSONTYPE_CAST,              /* something with an explicit cast to JSON */
                                 44                 :     JSONTYPE_OTHER              /* all else */
                                 45                 : } JsonTypeCategory;
                                 46                 : 
                                 47                 : 
                                 48                 : /*
                                 49                 :  * Support for fast key uniqueness checking.
                                 50                 :  *
                                 51                 :  * We maintain a hash table of used keys in JSON objects for fast detection
                                 52                 :  * of duplicates.
                                 53                 :  */
                                 54                 : /* Common context for key uniqueness check */
                                 55                 : typedef struct HTAB *JsonUniqueCheckState;  /* hash table for key names */
                                 56                 : 
                                 57                 : /* Hash entry for JsonUniqueCheckState */
                                 58                 : typedef struct JsonUniqueHashEntry
                                 59                 : {
                                 60                 :     const char *key;
                                 61                 :     int         key_len;
                                 62                 :     int         object_id;
                                 63                 : } JsonUniqueHashEntry;
                                 64                 : 
                                 65                 : /* Stack element for key uniqueness check during JSON parsing */
                                 66                 : typedef struct JsonUniqueStackEntry
                                 67                 : {
                                 68                 :     struct JsonUniqueStackEntry *parent;
                                 69                 :     int         object_id;
                                 70                 : } JsonUniqueStackEntry;
                                 71                 : 
                                 72                 : /* Context struct for key uniqueness check during JSON parsing */
                                 73                 : typedef struct JsonUniqueParsingState
                                 74                 : {
                                 75                 :     JsonLexContext *lex;
                                 76                 :     JsonUniqueCheckState check;
                                 77                 :     JsonUniqueStackEntry *stack;
                                 78                 :     int         id_counter;
                                 79                 :     bool        unique;
                                 80                 : } JsonUniqueParsingState;
                                 81                 : 
                                 82                 : /* Context struct for key uniqueness check during JSON building */
                                 83                 : typedef struct JsonUniqueBuilderState
                                 84                 : {
                                 85                 :     JsonUniqueCheckState check; /* unique check */
                                 86                 :     StringInfoData skipped_keys;    /* skipped keys with NULL values */
                                 87                 :     MemoryContext mcxt;         /* context for saving skipped keys */
                                 88                 : } JsonUniqueBuilderState;
                                 89                 : 
                                 90                 : 
                                 91                 : /* State struct for JSON aggregation */
                                 92                 : typedef struct JsonAggState
                                 93                 : {
                                 94                 :     StringInfo  str;
                                 95                 :     JsonTypeCategory key_category;
                                 96                 :     Oid         key_output_func;
                                 97                 :     JsonTypeCategory val_category;
                                 98                 :     Oid         val_output_func;
                                 99                 :     JsonUniqueBuilderState unique_check;
                                100                 : } JsonAggState;
                                101                 : 
                                102                 : static void composite_to_json(Datum composite, StringInfo result,
                                103                 :                               bool use_line_feeds);
                                104                 : static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims,
                                105                 :                               Datum *vals, bool *nulls, int *valcount,
                                106                 :                               JsonTypeCategory tcategory, Oid outfuncoid,
                                107                 :                               bool use_line_feeds);
                                108                 : static void array_to_json_internal(Datum array, StringInfo result,
                                109                 :                                    bool use_line_feeds);
                                110                 : static void json_categorize_type(Oid typoid,
                                111                 :                                  JsonTypeCategory *tcategory,
                                112                 :                                  Oid *outfuncoid);
                                113                 : static void datum_to_json(Datum val, bool is_null, StringInfo result,
                                114                 :                           JsonTypeCategory tcategory, Oid outfuncoid,
                                115                 :                           bool key_scalar);
                                116                 : static void add_json(Datum val, bool is_null, StringInfo result,
                                117                 :                      Oid val_type, bool key_scalar);
                                118                 : static text *catenate_stringinfo_string(StringInfo buffer, const char *addon);
                                119                 : 
                                120                 : /*
                                121                 :  * Input.
                                122                 :  */
                                123                 : Datum
 4086 rhaas                     124 GIC        2478 : json_in(PG_FUNCTION_ARGS)
                                125                 : {
 3663 andrew                    126            2478 :     char       *json = PG_GETARG_CSTRING(0);
                                127            2478 :     text       *result = cstring_to_text(json);
                                128                 :     JsonLexContext *lex;
                                129                 : 
                                130                 :     /* validate it */
                                131            2478 :     lex = makeJsonLexContext(result, false);
  119 tgl                       132 GNC        2478 :     if (!pg_parse_json_or_errsave(lex, &nullSemAction, fcinfo->context))
                                133               6 :         PG_RETURN_NULL();
                                134                 : 
                                135                 :     /* Internal representation is the same as text */
 3663 andrew                    136 GIC        2379 :     PG_RETURN_TEXT_P(result);
                                137                 : }
                                138                 : 
                                139                 : /*
                                140                 :  * Output.
                                141                 :  */
                                142                 : Datum
 4086 rhaas                     143            1373 : json_out(PG_FUNCTION_ARGS)
                                144                 : {
                                145                 :     /* we needn't detoast because text_to_cstring will handle that */
 3955 bruce                     146            1373 :     Datum       txt = PG_GETARG_DATUM(0);
                                147                 : 
 4086 rhaas                     148            1373 :     PG_RETURN_CSTRING(TextDatumGetCString(txt));
                                149                 : }
                                150                 : 
                                151                 : /*
                                152                 :  * Binary send.
                                153                 :  */
                                154                 : Datum
 4086 rhaas                     155 UIC           0 : json_send(PG_FUNCTION_ARGS)
                                156                 : {
 3955 bruce                     157               0 :     text       *t = PG_GETARG_TEXT_PP(0);
                                158                 :     StringInfoData buf;
                                159                 : 
 4086 rhaas                     160               0 :     pq_begintypsend(&buf);
                                161               0 :     pq_sendtext(&buf, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t));
                                162               0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
                                163                 : }
                                164                 : 
                                165                 : /*
                                166                 :  * Binary receive.
                                167                 :  */
                                168                 : Datum
                                169               0 : json_recv(PG_FUNCTION_ARGS)
                                170                 : {
                                171               0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
                                172                 :     char       *str;
 4086 rhaas                     173 ECB             :     int         nbytes;
                                174                 :     JsonLexContext *lex;
                                175                 : 
 4086 rhaas                     176 LBC           0 :     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
                                177                 : 
                                178                 :     /* Validate it. */
 1166 rhaas                     179 UIC           0 :     lex = makeJsonLexContextCstringLen(str, nbytes, GetDatabaseEncoding(), false);
 1168 rhaas                     180 LBC           0 :     pg_parse_json_or_ereport(lex, &nullSemAction);
 4086 rhaas                     181 ECB             : 
 3304 andrew                    182 LBC           0 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(str, nbytes));
                                183                 : }
                                184                 : 
 4083 andrew                    185 ECB             : /*
                                186                 :  * Determine how we want to print values of a given type in datum_to_json.
                                187                 :  *
                                188                 :  * Given the datatype OID, return its JsonTypeCategory, as well as the type's
                                189                 :  * output function OID.  If the returned category is JSONTYPE_CAST, we
                                190                 :  * return the OID of the type->JSON cast function instead.
                                191                 :  */
  220                           192                 : static void
 3257 tgl                       193 GIC        1895 : json_categorize_type(Oid typoid,
                                194                 :                      JsonTypeCategory *tcategory,
 3257 tgl                       195 ECB             :                      Oid *outfuncoid)
                                196                 : {
                                197                 :     bool        typisvarlena;
                                198                 : 
                                199                 :     /* Look through any domain */
 3257 tgl                       200 GIC        1895 :     typoid = getBaseType(typoid);
                                201                 : 
 3040 andrew                    202            1895 :     *outfuncoid = InvalidOid;
                                203                 : 
 3040 andrew                    204 EUB             :     /*
                                205                 :      * We need to get the output function for everything except date and
 2991 tgl                       206                 :      * timestamp types, array and composite types, booleans, and non-builtin
                                207                 :      * types where there's a cast to json.
                                208                 :      */
 3257                           209                 : 
 3257 tgl                       210 GBC        1895 :     switch (typoid)
 3257 tgl                       211 EUB             :     {
 3257 tgl                       212 GIC           9 :         case BOOLOID:
                                213               9 :             *tcategory = JSONTYPE_BOOL;
                                214               9 :             break;
                                215                 : 
                                216            1097 :         case INT2OID:
                                217                 :         case INT4OID:
 3257 tgl                       218 EUB             :         case INT8OID:
                                219                 :         case FLOAT4OID:
                                220                 :         case FLOAT8OID:
                                221                 :         case NUMERICOID:
 3040 andrew                    222 GIC        1097 :             getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
 3257 tgl                       223            1097 :             *tcategory = JSONTYPE_NUMERIC;
                                224            1097 :             break;
 3257 tgl                       225 EUB             : 
 3157 tgl                       226 GIC           9 :         case DATEOID:
                                227               9 :             *tcategory = JSONTYPE_DATE;
 3157 tgl                       228 GBC           9 :             break;
 3157 tgl                       229 EUB             : 
 3232 andrew                    230 GIC           9 :         case TIMESTAMPOID:
 3232 andrew                    231 GBC           9 :             *tcategory = JSONTYPE_TIMESTAMP;
 3232 andrew                    232 GIC           9 :             break;
                                233                 : 
                                234              12 :         case TIMESTAMPTZOID:
                                235              12 :             *tcategory = JSONTYPE_TIMESTAMPTZ;
                                236              12 :             break;
                                237                 : 
 3257 tgl                       238              59 :         case JSONOID:
                                239                 :         case JSONBOID:
 3040 andrew                    240              59 :             getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
 3257 tgl                       241              59 :             *tcategory = JSONTYPE_JSON;
 3257 tgl                       242 CBC          59 :             break;
                                243                 : 
 3257 tgl                       244 GIC         700 :         default:
                                245                 :             /* Check for arrays and composites */
 2237 andrew                    246             700 :             if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
 1116 tgl                       247             532 :                 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
 3257                           248             168 :                 *tcategory = JSONTYPE_ARRAY;
 2153 bruce                     249 CBC         532 :             else if (type_is_rowtype(typoid))   /* includes RECORDOID */
 3257 tgl                       250 GIC         107 :                 *tcategory = JSONTYPE_COMPOSITE;
 3257 tgl                       251 ECB             :             else
                                252                 :             {
                                253                 :                 /* It's probably the general case ... */
 3257 tgl                       254 GIC         425 :                 *tcategory = JSONTYPE_OTHER;
                                255                 :                 /* but let's look for a cast to json, if it's not built-in */
                                256             425 :                 if (typoid >= FirstNormalObjectId)
                                257                 :                 {
                                258                 :                     Oid         castfunc;
 3040 andrew                    259 ECB             :                     CoercionPathType ctype;
                                260                 : 
 3040 andrew                    261 CBC           2 :                     ctype = find_coercion_pathway(JSONOID, typoid,
 2991 tgl                       262 ECB             :                                                   COERCION_EXPLICIT,
                                263                 :                                                   &castfunc);
 3040 andrew                    264 GIC           2 :                     if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
 3257 tgl                       265 ECB             :                     {
 3040 andrew                    266 GIC           2 :                         *tcategory = JSONTYPE_CAST;
                                267               2 :                         *outfuncoid = castfunc;
                                268                 :                     }
                                269                 :                     else
                                270                 :                     {
 3040 andrew                    271 ECB             :                         /* non builtin type with no cast */
 3040 andrew                    272 LBC           0 :                         getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
 3040 andrew                    273 ECB             :                     }
                                274                 :                 }
                                275                 :                 else
                                276                 :                 {
                                277                 :                     /* any other builtin type */
 3040 andrew                    278 GIC         423 :                     getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
 3257 tgl                       279 ECB             :                 }
                                280                 :             }
 3257 tgl                       281 CBC         700 :             break;
                                282                 :     }
                                283            1895 : }
 3257 tgl                       284 ECB             : 
                                285                 : /*
                                286                 :  * Turn a Datum into JSON text, appending the string to "result".
 3953                           287                 :  *
                                288                 :  * tcategory and outfuncoid are from a previous call to json_categorize_type,
 3257                           289                 :  * except that if is_null is true then they can be invalid.
                                290                 :  *
                                291                 :  * If key_scalar is true, the value is being printed as a key, so insist
                                292                 :  * it's of an acceptable type, and force it to be quoted.
 4083 andrew                    293                 :  */
                                294                 : static void
 3953 tgl                       295 CBC        2608 : datum_to_json(Datum val, bool is_null, StringInfo result,
 3257 tgl                       296 ECB             :               JsonTypeCategory tcategory, Oid outfuncoid,
                                297                 :               bool key_scalar)
 4083 andrew                    298                 : {
 3955 bruce                     299                 :     char       *outputstr;
                                300                 :     text       *jsontext;
                                301                 : 
 2743 noah                      302 GIC        2608 :     check_stack_depth();
 2743 noah                      303 ECB             : 
                                304                 :     /* callers are expected to ensure that null keys are not passed in */
 3050 tgl                       305 CBC        2608 :     Assert(!(key_scalar && is_null));
                                306                 : 
 4063 andrew                    307 GIC        2608 :     if (is_null)
                                308                 :     {
 3955 bruce                     309             150 :         appendStringInfoString(result, "null");
 4083 andrew                    310 CBC         150 :         return;
                                311                 :     }
                                312                 : 
 3257 tgl                       313            2458 :     if (key_scalar &&
 3257 tgl                       314 GIC         307 :         (tcategory == JSONTYPE_ARRAY ||
 3257 tgl                       315 CBC         304 :          tcategory == JSONTYPE_COMPOSITE ||
                                316             298 :          tcategory == JSONTYPE_JSON ||
                                317                 :          tcategory == JSONTYPE_CAST))
 3257 tgl                       318 GIC          18 :         ereport(ERROR,
                                319                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                320                 :                  errmsg("key value must be scalar, not array, composite, or json")));
 3257 tgl                       321 EUB             : 
 4083 andrew                    322 GIC        2440 :     switch (tcategory)
                                323                 :     {
 3257 tgl                       324             162 :         case JSONTYPE_ARRAY:
 4083 andrew                    325             162 :             array_to_json_internal(val, result, false);
                                326             162 :             break;
 3257 tgl                       327 CBC         226 :         case JSONTYPE_COMPOSITE:
 3114 sfrost                    328 GIC         226 :             composite_to_json(val, result, false);
 4083 andrew                    329             226 :             break;
 3257 tgl                       330 CBC           9 :         case JSONTYPE_BOOL:
 3257 tgl                       331 GIC           9 :             outputstr = DatumGetBool(val) ? "true" : "false";
 3257 tgl                       332 CBC           9 :             if (key_scalar)
 3257 tgl                       333 UIC           0 :                 escape_json(result, outputstr);
                                334                 :             else
 3257 tgl                       335 GIC           9 :                 appendStringInfoString(result, outputstr);
 4083 andrew                    336               9 :             break;
 3257 tgl                       337            1481 :         case JSONTYPE_NUMERIC:
                                338            1481 :             outputstr = OidOutputFunctionCall(outfuncoid, val);
                                339                 : 
                                340                 :             /*
                                341                 :              * Don't call escape_json for a non-key if it's a valid JSON
                                342                 :              * number.
                                343                 :              */
 3051 andrew                    344 CBC        1481 :             if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr)))
 3051 andrew                    345 GIC        1367 :                 appendStringInfoString(result, outputstr);
                                346                 :             else
                                347             114 :                 escape_json(result, outputstr);
 4066                           348            1481 :             pfree(outputstr);
                                349            1481 :             break;
 3157 tgl                       350               9 :         case JSONTYPE_DATE:
 1909 andrew                    351 ECB             :             {
                                352                 :                 char        buf[MAXDATELEN + 1];
                                353                 : 
 1292 akorotkov                 354 CBC           9 :                 JsonEncodeDateTime(buf, val, DATEOID, NULL);
 1909 andrew                    355 GIC           9 :                 appendStringInfo(result, "\"%s\"", buf);
 1909 andrew                    356 ECB             :             }
 1909 andrew                    357 GIC           9 :             break;
 1909 andrew                    358 CBC           9 :         case JSONTYPE_TIMESTAMP:
 1909 andrew                    359 ECB             :             {
                                360                 :                 char        buf[MAXDATELEN + 1];
                                361                 : 
 1292 akorotkov                 362 CBC           9 :                 JsonEncodeDateTime(buf, val, TIMESTAMPOID, NULL);
 1909 andrew                    363               9 :                 appendStringInfo(result, "\"%s\"", buf);
 1909 andrew                    364 ECB             :             }
 1909 andrew                    365 CBC           9 :             break;
 1909 andrew                    366 GIC          12 :         case JSONTYPE_TIMESTAMPTZ:
 1909 andrew                    367 ECB             :             {
                                368                 :                 char        buf[MAXDATELEN + 1];
                                369                 : 
 1292 akorotkov                 370 GIC          12 :                 JsonEncodeDateTime(buf, val, TIMESTAMPTZOID, NULL);
 1909 andrew                    371 CBC          12 :                 appendStringInfo(result, "\"%s\"", buf);
                                372                 :             }
                                373              12 :             break;
                                374              86 :         case JSONTYPE_JSON:
 1909 andrew                    375 ECB             :             /* JSON and JSONB output will already be escaped */
 1909 andrew                    376 CBC          86 :             outputstr = OidOutputFunctionCall(outfuncoid, val);
                                377              86 :             appendStringInfoString(result, outputstr);
                                378              86 :             pfree(outputstr);
                                379              86 :             break;
                                380               2 :         case JSONTYPE_CAST:
 1909 andrew                    381 ECB             :             /* outfuncoid refers to a cast function, not an output function */
 1909 andrew                    382 GBC           2 :             jsontext = DatumGetTextPP(OidFunctionCall1(outfuncoid, val));
 1909 andrew                    383 GIC           2 :             outputstr = text_to_cstring(jsontext);
 1909 andrew                    384 CBC           2 :             appendStringInfoString(result, outputstr);
                                385               2 :             pfree(outputstr);
                                386               2 :             pfree(jsontext);
                                387               2 :             break;
 1909 andrew                    388 GIC         444 :         default:
                                389             444 :             outputstr = OidOutputFunctionCall(outfuncoid, val);
                                390             444 :             escape_json(result, outputstr);
                                391             444 :             pfree(outputstr);
                                392             444 :             break;
 1909 andrew                    393 ECB             :     }
                                394                 : }
                                395                 : 
                                396                 : /*
                                397                 :  * Encode 'value' of datetime type 'typid' into JSON string in ISO format using
 1292 akorotkov                 398                 :  * optionally preallocated buffer 'buf'.  Optional 'tzp' determines time-zone
                                399                 :  * offset (in seconds) in which we want to show timestamptz.
                                400                 :  */
                                401                 : char *
 1292 akorotkov                 402 GIC         297 : JsonEncodeDateTime(char *buf, Datum value, Oid typid, const int *tzp)
 1909 andrew                    403 ECB             : {
 1909 andrew                    404 CBC         297 :     if (!buf)
 1909 andrew                    405 GIC          30 :         buf = palloc(MAXDATELEN + 1);
 1909 andrew                    406 ECB             : 
 1909 andrew                    407 CBC         297 :     switch (typid)
                                408                 :     {
 1909 andrew                    409 GIC          48 :         case DATEOID:
                                410                 :             {
 3157 tgl                       411 ECB             :                 DateADT     date;
                                412                 :                 struct pg_tm tm;
                                413                 : 
 1909 andrew                    414 CBC          48 :                 date = DatumGetDateADT(value);
 1909 andrew                    415 ECB             : 
                                416                 :                 /* Same as date_out(), but forcing DateStyle */
 3157 tgl                       417 GIC          48 :                 if (DATE_NOT_FINITE(date))
 2728                           418              12 :                     EncodeSpecialDate(date, buf);
 3157 tgl                       419 ECB             :                 else
                                420                 :                 {
 3157 tgl                       421 GIC          36 :                     j2date(date + POSTGRES_EPOCH_JDATE,
 3157 tgl                       422 ECB             :                            &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
 3157 tgl                       423 CBC          36 :                     EncodeDateOnly(&tm, USE_XSD_DATES, buf);
                                424                 :                 }
 3157 tgl                       425 ECB             :             }
 3157 tgl                       426 CBC          48 :             break;
 1909 andrew                    427              30 :         case TIMEOID:
 1909 andrew                    428 ECB             :             {
 1909 andrew                    429 CBC          30 :                 TimeADT     time = DatumGetTimeADT(value);
                                430                 :                 struct pg_tm tt,
                                431              30 :                            *tm = &tt;
 1909 andrew                    432 ECB             :                 fsec_t      fsec;
                                433                 : 
                                434                 :                 /* Same as time_out(), but forcing DateStyle */
 1909 andrew                    435 CBC          30 :                 time2tm(time, tm, &fsec);
                                436              30 :                 EncodeTimeOnly(tm, fsec, false, 0, USE_XSD_DATES, buf);
 1909 andrew                    437 ECB             :             }
 1909 andrew                    438 CBC          30 :             break;
                                439              60 :         case TIMETZOID:
 1909 andrew                    440 ECB             :             {
 1909 andrew                    441 CBC          60 :                 TimeTzADT  *time = DatumGetTimeTzADTP(value);
                                442                 :                 struct pg_tm tt,
 1909 andrew                    443 GIC          60 :                            *tm = &tt;
                                444                 :                 fsec_t      fsec;
                                445                 :                 int         tz;
                                446                 : 
                                447                 :                 /* Same as timetz_out(), but forcing DateStyle */
                                448              60 :                 timetz2tm(time, tm, &fsec, &tz);
                                449              60 :                 EncodeTimeOnly(tm, fsec, true, tz, USE_XSD_DATES, buf);
                                450                 :             }
 1909 andrew                    451 CBC          60 :             break;
 1909 andrew                    452 GIC          63 :         case TIMESTAMPOID:
 3232 andrew                    453 ECB             :             {
                                454                 :                 Timestamp   timestamp;
                                455                 :                 struct pg_tm tm;
                                456                 :                 fsec_t      fsec;
                                457                 : 
 1909 andrew                    458 CBC          63 :                 timestamp = DatumGetTimestamp(value);
                                459                 :                 /* Same as timestamp_out(), but forcing DateStyle */
 3232 andrew                    460 GIC          63 :                 if (TIMESTAMP_NOT_FINITE(timestamp))
 2728 tgl                       461              12 :                     EncodeSpecialTimestamp(timestamp, buf);
 3232 andrew                    462              51 :                 else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
 3232 andrew                    463 CBC          51 :                     EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
                                464                 :                 else
 3232 andrew                    465 UIC           0 :                     ereport(ERROR,
 3232 andrew                    466 ECB             :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                467                 :                              errmsg("timestamp out of range")));
                                468                 :             }
 3232 andrew                    469 GIC          63 :             break;
 1909 andrew                    470 CBC          96 :         case TIMESTAMPTZOID:
                                471                 :             {
 3232 andrew                    472 ECB             :                 TimestampTz timestamp;
                                473                 :                 struct pg_tm tm;
                                474                 :                 int         tz;
                                475                 :                 fsec_t      fsec;
 3232 andrew                    476 CBC          96 :                 const char *tzn = NULL;
                                477                 : 
 1909                           478              96 :                 timestamp = DatumGetTimestampTz(value);
                                479                 : 
 1292 akorotkov                 480 ECB             :                 /*
                                481                 :                  * If a time zone is specified, we apply the time-zone shift,
                                482                 :                  * convert timestamptz to pg_tm as if it were without a time
                                483                 :                  * zone, and then use the specified time zone for converting
                                484                 :                  * the timestamp into a string.
                                485                 :                  */
 1292 akorotkov                 486 GIC          96 :                 if (tzp)
 1292 akorotkov                 487 ECB             :                 {
 1292 akorotkov                 488 CBC          72 :                     tz = *tzp;
 1292 akorotkov                 489 GIC          72 :                     timestamp -= (TimestampTz) tz * USECS_PER_SEC;
 1292 akorotkov                 490 ECB             :                 }
                                491                 : 
 2728 tgl                       492                 :                 /* Same as timestamptz_out(), but forcing DateStyle */
 3232 andrew                    493 GIC          96 :                 if (TIMESTAMP_NOT_FINITE(timestamp))
 2728 tgl                       494              12 :                     EncodeSpecialTimestamp(timestamp, buf);
 1292 akorotkov                 495              84 :                 else if (timestamp2tm(timestamp, tzp ? NULL : &tz, &tm, &fsec,
                                496                 :                                       tzp ? NULL : &tzn, NULL) == 0)
 1292 akorotkov                 497 ECB             :                 {
 1292 akorotkov                 498 CBC          84 :                     if (tzp)
 1292 akorotkov                 499 GIC          72 :                         tm.tm_isdst = 1;    /* set time-zone presence flag */
 1292 akorotkov                 500 ECB             : 
 3232 andrew                    501 CBC          84 :                     EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
                                502                 :                 }
                                503                 :                 else
 3232 andrew                    504 UIC           0 :                     ereport(ERROR,
                                505                 :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                506                 :                              errmsg("timestamp out of range")));
 3232 andrew                    507 ECB             :             }
 3232 andrew                    508 GIC          96 :             break;
 4083 andrew                    509 LBC           0 :         default:
  984 michael                   510               0 :             elog(ERROR, "unknown jsonb value datetime type oid %u", typid);
 1909 andrew                    511 ECB             :             return NULL;
 4083                           512                 :     }
                                513                 : 
 1909 andrew                    514 GBC         297 :     return buf;
                                515                 : }
                                516                 : 
                                517                 : /*
 4083 andrew                    518 ECB             :  * Process a single dimension of an array.
                                519                 :  * If it's the innermost dimension, output the values, otherwise call
                                520                 :  * ourselves recursively to process the next dimension.
                                521                 :  */
                                522                 : static void
 3955 bruce                     523 GIC         189 : array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals,
                                524                 :                   bool *nulls, int *valcount, JsonTypeCategory tcategory,
 3257 tgl                       525 ECB             :                   Oid outfuncoid, bool use_line_feeds)
                                526                 : {
 3955 bruce                     527                 :     int         i;
                                528                 :     const char *sep;
                                529                 : 
 4083 andrew                    530 GIC         189 :     Assert(dim < ndims);
                                531                 : 
                                532             189 :     sep = use_line_feeds ? ",\n " : ",";
                                533                 : 
                                534             189 :     appendStringInfoChar(result, '[');
 4083 andrew                    535 ECB             : 
 4083 andrew                    536 GIC         705 :     for (i = 1; i <= dims[dim]; i++)
 4083 andrew                    537 ECB             :     {
 4083 andrew                    538 CBC         516 :         if (i > 1)
 3955 bruce                     539 GIC         327 :             appendStringInfoString(result, sep);
                                540                 : 
 4083 andrew                    541             516 :         if (dim + 1 == ndims)
 4083 andrew                    542 ECB             :         {
 4063 andrew                    543 CBC         510 :             datum_to_json(vals[*valcount], nulls[*valcount], result, tcategory,
 3257 tgl                       544 ECB             :                           outfuncoid, false);
 4083 andrew                    545 GIC         510 :             (*valcount)++;
                                546                 :         }
 4083 andrew                    547 ECB             :         else
                                548                 :         {
                                549                 :             /*
 3955 bruce                     550                 :              * Do we want line feeds on inner dimensions of arrays? For now
                                551                 :              * we'll say no.
                                552                 :              */
 3955 bruce                     553 GBC           6 :             array_dim_to_json(result, dim + 1, ndims, dims, vals, nulls,
                                554                 :                               valcount, tcategory, outfuncoid, false);
                                555                 :         }
                                556                 :     }
 4083 andrew                    557 ECB             : 
 4083 andrew                    558 GBC         189 :     appendStringInfoChar(result, ']');
                                559             189 : }
                                560                 : 
                                561                 : /*
                                562                 :  * Turn an array into JSON.
 4083 andrew                    563 ECB             :  */
                                564                 : static void
 4083 andrew                    565 GIC         183 : array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
                                566                 : {
                                567             183 :     ArrayType  *v = DatumGetArrayTypeP(array);
                                568             183 :     Oid         element_type = ARR_ELEMTYPE(v);
                                569                 :     int        *dim;
                                570                 :     int         ndim;
                                571                 :     int         nitems;
 3955 bruce                     572 CBC         183 :     int         count = 0;
                                573                 :     Datum      *elements;
                                574                 :     bool       *nulls;
                                575                 :     int16       typlen;
                                576                 :     bool        typbyval;
                                577                 :     char        typalign;
                                578                 :     JsonTypeCategory tcategory;
 3257 tgl                       579 ECB             :     Oid         outfuncoid;
                                580                 : 
 4083 andrew                    581 CBC         183 :     ndim = ARR_NDIM(v);
 4083 andrew                    582 GIC         183 :     dim = ARR_DIMS(v);
 4083 andrew                    583 CBC         183 :     nitems = ArrayGetNItems(ndim, dim);
                                584                 : 
                                585             183 :     if (nitems <= 0)
                                586                 :     {
 3955 bruce                     587 LBC           0 :         appendStringInfoString(result, "[]");
 4083 andrew                    588               0 :         return;
                                589                 :     }
 4083 andrew                    590 ECB             : 
 3257 tgl                       591 GIC         183 :     get_typlenbyvalalign(element_type,
 3257 tgl                       592 ECB             :                          &typlen, &typbyval, &typalign);
                                593                 : 
 3257 tgl                       594 CBC         183 :     json_categorize_type(element_type,
                                595                 :                          &tcategory, &outfuncoid);
                                596                 : 
 4083 andrew                    597 GIC         183 :     deconstruct_array(v, element_type, typlen, typbyval,
                                598                 :                       typalign, &elements, &nulls,
                                599                 :                       &nitems);
                                600                 : 
 4063                           601             183 :     array_dim_to_json(result, 0, ndim, dim, elements, nulls, &count, tcategory,
 3257 tgl                       602 ECB             :                       outfuncoid, use_line_feeds);
                                603                 : 
 4083 andrew                    604 GIC         183 :     pfree(elements);
                                605             183 :     pfree(nulls);
                                606                 : }
 4083 andrew                    607 ECB             : 
                                608                 : /*
                                609                 :  * Turn a composite / record into JSON.
                                610                 :  */
                                611                 : static void
 3114 sfrost                    612 GIC         490 : composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
                                613                 : {
 3955 bruce                     614 ECB             :     HeapTupleHeader td;
                                615                 :     Oid         tupType;
                                616                 :     int32       tupTypmod;
                                617                 :     TupleDesc   tupdesc;
                                618                 :     HeapTupleData tmptup,
                                619                 :                *tuple;
                                620                 :     int         i;
 3955 bruce                     621 CBC         490 :     bool        needsep = false;
                                622                 :     const char *sep;
                                623                 : 
 4083 andrew                    624 GIC         490 :     sep = use_line_feeds ? ",\n " : ",";
                                625                 : 
 3955 bruce                     626             490 :     td = DatumGetHeapTupleHeader(composite);
                                627                 : 
                                628                 :     /* Extract rowtype info and find a tupdesc */
                                629             490 :     tupType = HeapTupleHeaderGetTypeId(td);
 3955 bruce                     630 CBC         490 :     tupTypmod = HeapTupleHeaderGetTypMod(td);
                                631             490 :     tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
 4083 andrew                    632 ECB             : 
                                633                 :     /* Build a temporary HeapTuple control structure */
 3955 bruce                     634 CBC         490 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
 3955 bruce                     635 GIC         490 :     tmptup.t_data = td;
 4083 andrew                    636 GBC         490 :     tuple = &tmptup;
 4083 andrew                    637 EUB             : 
 3955 bruce                     638 GIC         490 :     appendStringInfoChar(result, '{');
                                639                 : 
 3955 bruce                     640 CBC        1554 :     for (i = 0; i < tupdesc->natts; i++)
                                641                 :     {
                                642                 :         Datum       val;
 3955 bruce                     643 ECB             :         bool        isnull;
                                644                 :         char       *attname;
                                645                 :         JsonTypeCategory tcategory;
 3257 tgl                       646                 :         Oid         outfuncoid;
 2058 andres                    647 GIC        1064 :         Form_pg_attribute att = TupleDescAttr(tupdesc, i);
                                648                 : 
                                649            1064 :         if (att->attisdropped)
 3955 bruce                     650 LBC           0 :             continue;
                                651                 : 
 4083 andrew                    652 GIC        1064 :         if (needsep)
 3955 bruce                     653 CBC         574 :             appendStringInfoString(result, sep);
 4083 andrew                    654            1064 :         needsep = true;
                                655                 : 
 2058 andres                    656 GIC        1064 :         attname = NameStr(att->attname);
 3955 bruce                     657            1064 :         escape_json(result, attname);
                                658            1064 :         appendStringInfoChar(result, ':');
                                659                 : 
 3114 sfrost                    660            1064 :         val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
 3114 sfrost                    661 ECB             : 
 3257 tgl                       662 GIC        1064 :         if (isnull)
                                663                 :         {
                                664              84 :             tcategory = JSONTYPE_NULL;
                                665              84 :             outfuncoid = InvalidOid;
                                666                 :         }
                                667                 :         else
 2058 andres                    668             980 :             json_categorize_type(att->atttypid, &tcategory, &outfuncoid);
                                669                 : 
 3257 tgl                       670 CBC        1064 :         datum_to_json(val, isnull, result, tcategory, outfuncoid, false);
                                671                 :     }
                                672                 : 
 3955 bruce                     673             490 :     appendStringInfoChar(result, '}');
 3955 bruce                     674 GIC         490 :     ReleaseTupleDesc(tupdesc);
 4083 andrew                    675 CBC         490 : }
                                676                 : 
                                677                 : /*
 3257 tgl                       678 ECB             :  * Append JSON text for "val" to "result".
                                679                 :  *
                                680                 :  * This is just a thin wrapper around datum_to_json.  If the same type will be
                                681                 :  * printed many times, avoid using this; better to do the json_categorize_type
                                682                 :  * lookups only once.
 3358 andrew                    683                 :  */
                                684                 : static void
 3257 tgl                       685 CBC         583 : add_json(Datum val, bool is_null, StringInfo result,
                                686                 :          Oid val_type, bool key_scalar)
 3358 andrew                    687 ECB             : {
                                688                 :     JsonTypeCategory tcategory;
 3257 tgl                       689                 :     Oid         outfuncoid;
                                690                 : 
 3358 andrew                    691 GIC         583 :     if (val_type == InvalidOid)
 3358 andrew                    692 UIC           0 :         ereport(ERROR,
                                693                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                694                 :                  errmsg("could not determine input data type")));
                                695                 : 
 3257 tgl                       696 CBC         583 :     if (is_null)
                                697                 :     {
                                698              33 :         tcategory = JSONTYPE_NULL;
 3257 tgl                       699 GBC          33 :         outfuncoid = InvalidOid;
                                700                 :     }
 3358 andrew                    701 ECB             :     else
 3257 tgl                       702 CBC         550 :         json_categorize_type(val_type,
 3257 tgl                       703 ECB             :                              &tcategory, &outfuncoid);
                                704                 : 
 3257 tgl                       705 CBC         583 :     datum_to_json(val, is_null, result, tcategory, outfuncoid, key_scalar);
 3358 andrew                    706             565 : }
 3358 andrew                    707 ECB             : 
                                708                 : /*
 3114 sfrost                    709                 :  * SQL function array_to_json(row)
                                710                 :  */
 1875 tgl                       711                 : Datum
 3132 sfrost                    712 GIC           9 : array_to_json(PG_FUNCTION_ARGS)
 3114 sfrost                    713 ECB             : {
 3114 sfrost                    714 CBC           9 :     Datum       array = PG_GETARG_DATUM(0);
                                715                 :     StringInfo  result;
                                716                 : 
                                717               9 :     result = makeStringInfo();
                                718                 : 
                                719               9 :     array_to_json_internal(array, result, false);
                                720                 : 
 3114 sfrost                    721 GIC           9 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
 3114 sfrost                    722 ECB             : }
                                723                 : 
                                724                 : /*
                                725                 :  * SQL function array_to_json(row, prettybool)
                                726                 :  */
                                727                 : Datum
 3114 sfrost                    728 GIC          12 : array_to_json_pretty(PG_FUNCTION_ARGS)
                                729                 : {
 3955 bruce                     730              12 :     Datum       array = PG_GETARG_DATUM(0);
                                731              12 :     bool        use_line_feeds = PG_GETARG_BOOL(1);
                                732                 :     StringInfo  result;
                                733                 : 
 4083 andrew                    734 CBC          12 :     result = makeStringInfo();
                                735                 : 
 4083 andrew                    736 GIC          12 :     array_to_json_internal(array, result, use_line_feeds);
                                737                 : 
 3429 rhaas                     738              12 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
                                739                 : }
 4083 andrew                    740 ECB             : 
 4083 andrew                    741 EUB             : /*
                                742                 :  * SQL function row_to_json(row)
                                743                 :  */
                                744                 : Datum
 4083 andrew                    745 CBC         240 : row_to_json(PG_FUNCTION_ARGS)
                                746                 : {
 3114 sfrost                    747             240 :     Datum       array = PG_GETARG_DATUM(0);
 3114 sfrost                    748 ECB             :     StringInfo  result;
                                749                 : 
 3114 sfrost                    750 GIC         240 :     result = makeStringInfo();
 3114 sfrost                    751 ECB             : 
 3114 sfrost                    752 GIC         240 :     composite_to_json(array, result, false);
                                753                 : 
 3114 sfrost                    754 CBC         240 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
 3114 sfrost                    755 ECB             : }
                                756                 : 
                                757                 : /*
                                758                 :  * SQL function row_to_json(row, prettybool)
                                759                 :  */
                                760                 : Datum
 3114 sfrost                    761 CBC          24 : row_to_json_pretty(PG_FUNCTION_ARGS)
                                762                 : {
 3955 bruce                     763              24 :     Datum       array = PG_GETARG_DATUM(0);
 3955 bruce                     764 GIC          24 :     bool        use_line_feeds = PG_GETARG_BOOL(1);
                                765                 :     StringInfo  result;
 4083 andrew                    766 ECB             : 
 4083 andrew                    767 GIC          24 :     result = makeStringInfo();
 4083 andrew                    768 ECB             : 
 3114 sfrost                    769 GIC          24 :     composite_to_json(array, result, use_line_feeds);
 4083 andrew                    770 ECB             : 
 3429 rhaas                     771 GIC          24 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
                                772                 : }
                                773                 : 
                                774                 : /*
                                775                 :  * Is the given type immutable when coming out of a JSON context?
                                776                 :  *
                                777                 :  * At present, datetimes are all considered mutable, because they
                                778                 :  * depend on timezone.  XXX we should also drill down into objects
                                779                 :  * and arrays, but do not.
                                780                 :  */
                                781                 : bool
   11 alvherre                  782 UNC           0 : to_json_is_immutable(Oid typoid)
                                783                 : {
                                784                 :     JsonTypeCategory tcategory;
                                785                 :     Oid         outfuncoid;
                                786                 : 
                                787               0 :     json_categorize_type(typoid, &tcategory, &outfuncoid);
                                788                 : 
                                789               0 :     switch (tcategory)
                                790                 :     {
                                791               0 :         case JSONTYPE_BOOL:
                                792                 :         case JSONTYPE_JSON:
                                793                 :         case JSONTYPE_NULL:
                                794               0 :             return true;
                                795                 : 
                                796               0 :         case JSONTYPE_DATE:
                                797                 :         case JSONTYPE_TIMESTAMP:
                                798                 :         case JSONTYPE_TIMESTAMPTZ:
                                799               0 :             return false;
                                800                 : 
                                801               0 :         case JSONTYPE_ARRAY:
                                802               0 :             return false;       /* TODO recurse into elements */
                                803                 : 
                                804               0 :         case JSONTYPE_COMPOSITE:
                                805               0 :             return false;       /* TODO recurse into fields */
                                806                 : 
                                807               0 :         case JSONTYPE_NUMERIC:
                                808                 :         case JSONTYPE_CAST:
                                809                 :         case JSONTYPE_OTHER:
                                810               0 :             return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE;
                                811                 :     }
                                812                 : 
                                813               0 :     return false;               /* not reached */
                                814                 : }
                                815                 : 
                                816                 : /*
                                817                 :  * SQL function to_json(anyvalue)
                                818                 :  */
 3682 andrew                    819 ECB             : Datum
 3682 andrew                    820 GIC          66 : to_json(PG_FUNCTION_ARGS)
 3682 andrew                    821 ECB             : {
 3444 tgl                       822 CBC          66 :     Datum       val = PG_GETARG_DATUM(0);
 3682 andrew                    823 GIC          66 :     Oid         val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
                                824                 :     StringInfo  result;
 3257 tgl                       825 ECB             :     JsonTypeCategory tcategory;
                                826                 :     Oid         outfuncoid;
 3682 andrew                    827                 : 
 3682 andrew                    828 GIC          66 :     if (val_type == InvalidOid)
 3682 andrew                    829 LBC           0 :         ereport(ERROR,
                                830                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                831                 :                  errmsg("could not determine input data type")));
                                832                 : 
 3257 tgl                       833 GIC          66 :     json_categorize_type(val_type,
                                834                 :                          &tcategory, &outfuncoid);
                                835                 : 
  220 andrew                    836 CBC          66 :     result = makeStringInfo();
                                837                 : 
                                838              66 :     datum_to_json(val, false, result, tcategory, outfuncoid, false);
                                839                 : 
  220 andrew                    840 GIC          66 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
 3682 andrew                    841 ECB             : }
                                842                 : 
                                843                 : /*
                                844                 :  * json_agg transition function
 3050 tgl                       845                 :  *
                                846                 :  * aggregate input column as a json array value.
                                847                 :  */
                                848                 : static Datum
   11 alvherre                  849 GNC         271 : json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
                                850                 : {
                                851                 :     MemoryContext aggcontext,
 3682 andrew                    852 ECB             :                 oldcontext;
                                853                 :     JsonAggState *state;
 3444 tgl                       854                 :     Datum       val;
 3682 andrew                    855                 : 
 3682 andrew                    856 GIC         271 :     if (!AggCheckCallContext(fcinfo, &aggcontext))
                                857                 :     {
 3682 andrew                    858 ECB             :         /* cannot be called directly because of internal-type argument */
 3682 andrew                    859 UIC           0 :         elog(ERROR, "json_agg_transfn called in non-aggregate context");
 3682 andrew                    860 ECB             :     }
                                861                 : 
 3682 andrew                    862 CBC         271 :     if (PG_ARGISNULL(0))
                                863                 :     {
 2728 tgl                       864 GIC          56 :         Oid         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
                                865                 : 
 2760 andrew                    866              56 :         if (arg_type == InvalidOid)
 2760 andrew                    867 UIC           0 :             ereport(ERROR,
                                868                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                869                 :                      errmsg("could not determine input data type")));
                                870                 : 
                                871                 :         /*
                                872                 :          * Make this state object in a context where it will persist for the
 3257 tgl                       873 EUB             :          * duration of the aggregate call.  MemoryContextSwitchTo is only
                                874                 :          * needed the first time, as the StringInfo routines make sure they
                                875                 :          * use the right context to enlarge the object if necessary.
                                876                 :          */
 3682 andrew                    877 GIC          56 :         oldcontext = MemoryContextSwitchTo(aggcontext);
 2760 andrew                    878 GBC          56 :         state = (JsonAggState *) palloc(sizeof(JsonAggState));
 2760 andrew                    879 GIC          56 :         state->str = makeStringInfo();
 3682 andrew                    880 GBC          56 :         MemoryContextSwitchTo(oldcontext);
                                881                 : 
 2760                           882              56 :         appendStringInfoChar(state->str, '[');
 2728 tgl                       883 GIC          56 :         json_categorize_type(arg_type, &state->val_category,
                                884                 :                              &state->val_output_func);
 3682 andrew                    885 EUB             :     }
                                886                 :     else
                                887                 :     {
 2760 andrew                    888 GIC         215 :         state = (JsonAggState *) PG_GETARG_POINTER(0);
  220 andrew                    889 EUB             :     }
                                890                 : 
   11 alvherre                  891 GNC         271 :     if (absent_on_null && PG_ARGISNULL(1))
                                892              45 :         PG_RETURN_POINTER(state);
                                893                 : 
                                894             226 :     if (state->str->len > 1)
                                895             173 :         appendStringInfoString(state->str, ", ");
                                896                 : 
 3682 andrew                    897 EUB             :     /* fast path for NULLs */
 3682 andrew                    898 GBC         226 :     if (PG_ARGISNULL(1))
                                899                 :     {
 2760                           900              27 :         datum_to_json((Datum) 0, true, state->str, JSONTYPE_NULL,
 2760 andrew                    901 EUB             :                       InvalidOid, false);
 3682 andrew                    902 GIC          27 :         PG_RETURN_POINTER(state);
 3682 andrew                    903 EUB             :     }
                                904                 : 
 3444 tgl                       905 GIC         199 :     val = PG_GETARG_DATUM(1);
 3682 andrew                    906 EUB             : 
                                907                 :     /* add some whitespace if structured type and not first item */
   11 alvherre                  908 GNC         199 :     if (!PG_ARGISNULL(0) && state->str->len > 1 &&
 2760 andrew                    909 GBC         149 :         (state->val_category == JSONTYPE_ARRAY ||
 2760 andrew                    910 GIC         146 :          state->val_category == JSONTYPE_COMPOSITE))
                                911                 :     {
                                912              56 :         appendStringInfoString(state->str, "\n ");
                                913                 :     }
                                914                 : 
                                915             199 :     datum_to_json(val, false, state->str, state->val_category,
 2760 andrew                    916 ECB             :                   state->val_output_func, false);
                                917                 : 
 3682                           918                 :     /*
 1938 magnus                    919                 :      * The transition type for json_agg() is declared to be "internal", which
                                920                 :      * is a pass-by-value type the same size as a pointer.  So we can safely
                                921                 :      * pass the JsonAggState pointer through nodeAgg.c's machinations.
                                922                 :      */
 3682 andrew                    923 GIC         199 :     PG_RETURN_POINTER(state);
 3682 andrew                    924 ECB             : }
 3682 andrew                    925 EUB             : 
                                926                 : 
                                927                 : /*
                                928                 :  * json_agg aggregate function
                                929                 :  */
                                930                 : Datum
   11 alvherre                  931 GNC          76 : json_agg_transfn(PG_FUNCTION_ARGS)
                                932                 : {
                                933              76 :     return json_agg_transfn_worker(fcinfo, false);
                                934                 : }
                                935                 : 
                                936                 : /*
                                937                 :  * json_agg_strict aggregate function
                                938                 :  */
                                939                 : Datum
                                940             195 : json_agg_strict_transfn(PG_FUNCTION_ARGS)
                                941                 : {
                                942             195 :     return json_agg_transfn_worker(fcinfo, true);
                                943                 : }
                                944                 : 
                                945                 : /*
                                946                 :  * json_agg final function
                                947                 :  */
 3682 andrew                    948 ECB             : Datum
 3682 andrew                    949 GIC          62 : json_agg_finalfn(PG_FUNCTION_ARGS)
                                950                 : {
 2728 tgl                       951 ECB             :     JsonAggState *state;
                                952                 : 
 3682 andrew                    953                 :     /* cannot be called directly because of internal-type argument */
 3682 andrew                    954 GIC          62 :     Assert(AggCheckCallContext(fcinfo, NULL));
 3682 andrew                    955 ECB             : 
 2760 andrew                    956 GIC         124 :     state = PG_ARGISNULL(0) ?
                                957              62 :         NULL :
                                958              56 :         (JsonAggState *) PG_GETARG_POINTER(0);
                                959                 : 
                                960                 :     /* NULL result for no rows in, as is standard with aggregates */
 3682                           961              62 :     if (state == NULL)
                                962               6 :         PG_RETURN_NULL();
                                963                 : 
 3050 tgl                       964 ECB             :     /* Else return state with appropriate array terminator added */
 2760 andrew                    965 GIC          56 :     PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, "]"));
                                966                 : }
                                967                 : 
                                968                 : /* Functions implementing hash table for key uniqueness check */
                                969                 : static uint32
   11 alvherre                  970 GNC         181 : json_unique_hash(const void *key, Size keysize)
                                971                 : {
                                972             181 :     const JsonUniqueHashEntry *entry = (JsonUniqueHashEntry *) key;
                                973             181 :     uint32      hash = hash_bytes_uint32(entry->object_id);
                                974                 : 
                                975             181 :     hash ^= hash_bytes((const unsigned char *) entry->key, entry->key_len);
                                976                 : 
                                977             181 :     return DatumGetUInt32(hash);
                                978                 : }
                                979                 : 
                                980                 : static int
                                981              38 : json_unique_hash_match(const void *key1, const void *key2, Size keysize)
                                982                 : {
                                983              38 :     const JsonUniqueHashEntry *entry1 = (const JsonUniqueHashEntry *) key1;
                                984              38 :     const JsonUniqueHashEntry *entry2 = (const JsonUniqueHashEntry *) key2;
                                985                 : 
                                986              38 :     if (entry1->object_id != entry2->object_id)
   11 alvherre                  987 UNC           0 :         return entry1->object_id > entry2->object_id ? 1 : -1;
                                988                 : 
   11 alvherre                  989 GNC          38 :     if (entry1->key_len != entry2->key_len)
   11 alvherre                  990 UNC           0 :         return entry1->key_len > entry2->key_len ? 1 : -1;
                                991                 : 
   11 alvherre                  992 GNC          38 :     return strncmp(entry1->key, entry2->key, entry1->key_len);
                                993                 : }
                                994                 : 
                                995                 : /*
                                996                 :  * Uniqueness detection support.
                                997                 :  *
                                998                 :  * In order to detect uniqueness during building or parsing of a JSON
                                999                 :  * object, we maintain a hash table of key names already seen.
                               1000                 :  */
                               1001                 : static void
                               1002             134 : json_unique_check_init(JsonUniqueCheckState *cxt)
                               1003                 : {
                               1004                 :     HASHCTL     ctl;
                               1005                 : 
                               1006             134 :     memset(&ctl, 0, sizeof(ctl));
                               1007             134 :     ctl.keysize = sizeof(JsonUniqueHashEntry);
                               1008             134 :     ctl.entrysize = sizeof(JsonUniqueHashEntry);
                               1009             134 :     ctl.hcxt = CurrentMemoryContext;
                               1010             134 :     ctl.hash = json_unique_hash;
                               1011             134 :     ctl.match = json_unique_hash_match;
                               1012                 : 
                               1013             134 :     *cxt = hash_create("json object hashtable",
                               1014                 :                        32,
                               1015                 :                        &ctl,
                               1016                 :                        HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION | HASH_COMPARE);
                               1017             134 : }
                               1018                 : 
                               1019                 : static void
                               1020              22 : json_unique_builder_init(JsonUniqueBuilderState *cxt)
                               1021                 : {
                               1022              22 :     json_unique_check_init(&cxt->check);
                               1023              22 :     cxt->mcxt = CurrentMemoryContext;
                               1024              22 :     cxt->skipped_keys.data = NULL;
                               1025              22 : }
                               1026                 : 
                               1027                 : static bool
                               1028             181 : json_unique_check_key(JsonUniqueCheckState *cxt, const char *key, int object_id)
                               1029                 : {
                               1030                 :     JsonUniqueHashEntry entry;
                               1031                 :     bool        found;
                               1032                 : 
                               1033             181 :     entry.key = key;
                               1034             181 :     entry.key_len = strlen(key);
                               1035             181 :     entry.object_id = object_id;
                               1036                 : 
                               1037             181 :     (void) hash_search(*cxt, &entry, HASH_ENTER, &found);
                               1038                 : 
                               1039             181 :     return !found;
                               1040                 : }
                               1041                 : 
                               1042                 : /*
                               1043                 :  * On-demand initialization of a throwaway StringInfo.  This is used to
                               1044                 :  * read a key name that we don't need to store in the output object, for
                               1045                 :  * duplicate key detection when the value is NULL.
                               1046                 :  */
                               1047                 : static StringInfo
                               1048              18 : json_unique_builder_get_throwawaybuf(JsonUniqueBuilderState *cxt)
                               1049                 : {
                               1050              18 :     StringInfo  out = &cxt->skipped_keys;
                               1051                 : 
                               1052              18 :     if (!out->data)
                               1053                 :     {
                               1054              12 :         MemoryContext oldcxt = MemoryContextSwitchTo(cxt->mcxt);
                               1055                 : 
                               1056              12 :         initStringInfo(out);
                               1057              12 :         MemoryContextSwitchTo(oldcxt);
                               1058                 :     }
                               1059                 :     else
                               1060                 :         /* Just reset the string to empty */
                               1061               6 :         out->len = 0;
                               1062                 : 
                               1063              18 :     return out;
                               1064                 : }
                               1065                 : 
                               1066                 : /*
                               1067                 :  * json_object_agg transition function.
                               1068                 :  *
 3050 tgl                      1069 ECB             :  * aggregate two input columns as a single json object value.
                               1070                 :  */
                               1071                 : static Datum
   11 alvherre                 1072 GNC          99 : json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
                               1073                 :                                bool absent_on_null, bool unique_keys)
                               1074                 : {
                               1075                 :     MemoryContext aggcontext,
 3358 andrew                   1076 ECB             :                 oldcontext;
                               1077                 :     JsonAggState *state;
                               1078                 :     StringInfo  out;
                               1079                 :     Datum       arg;
                               1080                 :     bool        skip;
                               1081                 :     int         key_offset;
                               1082                 : 
 3358 andrew                   1083 CBC          99 :     if (!AggCheckCallContext(fcinfo, &aggcontext))
 3358 andrew                   1084 EUB             :     {
                               1085                 :         /* cannot be called directly because of internal-type argument */
 3050 tgl                      1086 UIC           0 :         elog(ERROR, "json_object_agg_transfn called in non-aggregate context");
                               1087                 :     }
                               1088                 : 
 3358 andrew                   1089 GIC          99 :     if (PG_ARGISNULL(0))
                               1090                 :     {
                               1091                 :         Oid         arg_type;
                               1092                 : 
                               1093                 :         /*
 3165 tgl                      1094 ECB             :          * Make the StringInfo in a context where it will persist for the
                               1095                 :          * duration of the aggregate call. Switching context is only needed
                               1096                 :          * for this initial step, as the StringInfo and dynahash routines make
                               1097                 :          * sure they use the right context to enlarge the object if necessary.
                               1098                 :          */
 3358 andrew                   1099 CBC          30 :         oldcontext = MemoryContextSwitchTo(aggcontext);
 2760                          1100              30 :         state = (JsonAggState *) palloc(sizeof(JsonAggState));
 2760 andrew                   1101 GIC          30 :         state->str = makeStringInfo();
   11 alvherre                 1102 GNC          30 :         if (unique_keys)
                               1103               9 :             json_unique_builder_init(&state->unique_check);
                               1104                 :         else
                               1105              21 :             memset(&state->unique_check, 0, sizeof(state->unique_check));
 3358 andrew                   1106 GIC          30 :         MemoryContextSwitchTo(oldcontext);
                               1107                 : 
 2760                          1108              30 :         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
 2760 andrew                   1109 ECB             : 
 2760 andrew                   1110 GIC          30 :         if (arg_type == InvalidOid)
 2760 andrew                   1111 UIC           0 :             ereport(ERROR,
 2760 andrew                   1112 ECB             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 2118 tgl                      1113                 :                      errmsg("could not determine data type for argument %d", 1)));
                               1114                 : 
 2728 tgl                      1115 CBC          30 :         json_categorize_type(arg_type, &state->key_category,
 2760 andrew                   1116 ECB             :                              &state->key_output_func);
                               1117                 : 
 2760 andrew                   1118 GIC          30 :         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
 2760 andrew                   1119 ECB             : 
 2760 andrew                   1120 GIC          30 :         if (arg_type == InvalidOid)
 2760 andrew                   1121 LBC           0 :             ereport(ERROR,
                               1122                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 2118 tgl                      1123 ECB             :                      errmsg("could not determine data type for argument %d", 2)));
                               1124                 : 
 2728 tgl                      1125 GIC          30 :         json_categorize_type(arg_type, &state->val_category,
 2760 andrew                   1126 ECB             :                              &state->val_output_func);
                               1127                 : 
 2760 andrew                   1128 GIC          30 :         appendStringInfoString(state->str, "{ ");
 3358 andrew                   1129 ECB             :     }
                               1130                 :     else
                               1131                 :     {
 2760 andrew                   1132 GIC          69 :         state = (JsonAggState *) PG_GETARG_POINTER(0);
                               1133                 :     }
                               1134                 : 
 3358 andrew                   1135 ECB             :     /*
                               1136                 :      * Note: since json_object_agg() is declared as taking type "any", the
                               1137                 :      * parser will not do any type conversion on unknown-type literals (that
                               1138                 :      * is, undecorated strings or NULLs).  Such values will arrive here as
                               1139                 :      * type UNKNOWN, which fortunately does not matter to us, since
                               1140                 :      * unknownout() works fine.
                               1141                 :      */
                               1142                 : 
 3165 tgl                      1143 CBC          99 :     if (PG_ARGISNULL(1))
 3165 tgl                      1144 GIC           6 :         ereport(ERROR,
                               1145                 :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                               1146                 :                  errmsg("null value not allowed for object key")));
                               1147                 : 
                               1148                 :     /* Skip null values if absent_on_null */
   11 alvherre                 1149 GNC          93 :     skip = absent_on_null && PG_ARGISNULL(2);
                               1150                 : 
                               1151              93 :     if (skip)
                               1152                 :     {
                               1153                 :         /*
                               1154                 :          * We got a NULL value and we're not storing those; if we're not
                               1155                 :          * testing key uniqueness, we're done.  If we are, use the throwaway
                               1156                 :          * buffer to store the key name so that we can check it.
                               1157                 :          */
                               1158              18 :         if (!unique_keys)
                               1159               6 :             PG_RETURN_POINTER(state);
                               1160                 : 
                               1161              12 :         out = json_unique_builder_get_throwawaybuf(&state->unique_check);
                               1162                 :     }
                               1163                 :     else
                               1164                 :     {
                               1165              75 :         out = state->str;
                               1166                 : 
                               1167                 :         /*
                               1168                 :          * Append comma delimiter only if we have already output some fields
                               1169                 :          * after the initial string "{ ".
                               1170                 :          */
                               1171              75 :         if (out->len > 2)
                               1172              48 :             appendStringInfoString(out, ", ");
                               1173                 :     }
                               1174                 : 
 3165 tgl                      1175 GIC          87 :     arg = PG_GETARG_DATUM(1);
                               1176                 : 
   11 alvherre                 1177 GNC          87 :     key_offset = out->len;
                               1178                 : 
                               1179              87 :     datum_to_json(arg, false, out, state->key_category,
 2760 andrew                   1180 ECB             :                   state->key_output_func, true);
                               1181                 : 
   11 alvherre                 1182 GNC          87 :     if (unique_keys)
                               1183                 :     {
                               1184              27 :         const char *key = &out->data[key_offset];
                               1185                 : 
                               1186              27 :         if (!json_unique_check_key(&state->unique_check.check, key, 0))
                               1187               6 :             ereport(ERROR,
                               1188                 :                     errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
                               1189                 :                     errmsg("duplicate JSON key %s", key));
                               1190                 : 
                               1191              21 :         if (skip)
                               1192               9 :             PG_RETURN_POINTER(state);
                               1193                 :     }
                               1194                 : 
 2760 andrew                   1195 CBC          72 :     appendStringInfoString(state->str, " : ");
                               1196                 : 
 3165 tgl                      1197 GIC          72 :     if (PG_ARGISNULL(2))
                               1198               6 :         arg = (Datum) 0;
                               1199                 :     else
                               1200              66 :         arg = PG_GETARG_DATUM(2);
                               1201                 : 
 2760 andrew                   1202 CBC          72 :     datum_to_json(arg, PG_ARGISNULL(2), state->str, state->val_category,
                               1203                 :                   state->val_output_func, false);
 3358 andrew                   1204 ECB             : 
 3358 andrew                   1205 GIC          72 :     PG_RETURN_POINTER(state);
                               1206                 : }
                               1207                 : 
                               1208                 : /*
                               1209                 :  * json_object_agg aggregate function
                               1210                 :  */
                               1211                 : Datum
   11 alvherre                 1212 GNC          60 : json_object_agg_transfn(PG_FUNCTION_ARGS)
                               1213                 : {
                               1214              60 :     return json_object_agg_transfn_worker(fcinfo, false, false);
                               1215                 : }
                               1216                 : 
                               1217                 : /*
                               1218                 :  * json_object_agg_strict aggregate function
                               1219                 :  */
                               1220                 : Datum
                               1221              12 : json_object_agg_strict_transfn(PG_FUNCTION_ARGS)
                               1222                 : {
                               1223              12 :     return json_object_agg_transfn_worker(fcinfo, true, false);
                               1224                 : }
                               1225                 : 
                               1226                 : /*
                               1227                 :  * json_object_agg_unique aggregate function
                               1228                 :  */
                               1229                 : Datum
                               1230               6 : json_object_agg_unique_transfn(PG_FUNCTION_ARGS)
                               1231                 : {
                               1232               6 :     return json_object_agg_transfn_worker(fcinfo, false, true);
                               1233                 : }
                               1234                 : 
                               1235                 : /*
                               1236                 :  * json_object_agg_unique_strict aggregate function
                               1237                 :  */
                               1238                 : Datum
                               1239              21 : json_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS)
                               1240                 : {
                               1241              21 :     return json_object_agg_transfn_worker(fcinfo, true, true);
                               1242                 : }
                               1243                 : 
                               1244                 : /*
                               1245                 :  * json_object_agg final function.
                               1246                 :  */
 3358 andrew                   1247 ECB             : Datum
 3358 andrew                   1248 GIC          21 : json_object_agg_finalfn(PG_FUNCTION_ARGS)
                               1249                 : {
                               1250                 :     JsonAggState *state;
                               1251                 : 
 3358 andrew                   1252 ECB             :     /* cannot be called directly because of internal-type argument */
 3358 andrew                   1253 GIC          21 :     Assert(AggCheckCallContext(fcinfo, NULL));
 3358 andrew                   1254 ECB             : 
 2760 andrew                   1255 CBC          21 :     state = PG_ARGISNULL(0) ? NULL : (JsonAggState *) PG_GETARG_POINTER(0);
 3358 andrew                   1256 ECB             : 
                               1257                 :     /* NULL result for no rows in, as is standard with aggregates */
 3358 andrew                   1258 GIC          21 :     if (state == NULL)
 3118 andrew                   1259 CBC           3 :         PG_RETURN_NULL();
 3358 andrew                   1260 ECB             : 
                               1261                 :     /* Else return state with appropriate object terminator added */
 2760 andrew                   1262 GIC          18 :     PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, " }"));
 3050 tgl                      1263 ECB             : }
                               1264                 : 
                               1265                 : /*
                               1266                 :  * Helper function for aggregates: return given StringInfo's contents plus
                               1267                 :  * specified trailing string, as a text datum.  We need this because aggregate
                               1268                 :  * final functions are not allowed to modify the aggregate state.
                               1269                 :  */
                               1270                 : static text *
 3050 tgl                      1271 CBC          74 : catenate_stringinfo_string(StringInfo buffer, const char *addon)
                               1272                 : {
 3050 tgl                      1273 ECB             :     /* custom version of cstring_to_text_with_len */
 3050 tgl                      1274 GIC          74 :     int         buflen = buffer->len;
 3050 tgl                      1275 CBC          74 :     int         addlen = strlen(addon);
 3050 tgl                      1276 GIC          74 :     text       *result = (text *) palloc(buflen + addlen + VARHDRSZ);
                               1277                 : 
                               1278              74 :     SET_VARSIZE(result, buflen + addlen + VARHDRSZ);
 3050 tgl                      1279 CBC          74 :     memcpy(VARDATA(result), buffer->data, buflen);
 3050 tgl                      1280 GIC          74 :     memcpy(VARDATA(result) + buflen, addon, addlen);
 3358 andrew                   1281 ECB             : 
 3050 tgl                      1282 CBC          74 :     return result;
                               1283                 : }
 3358 andrew                   1284 ECB             : 
 3358 andrew                   1285 EUB             : Datum
   11 alvherre                 1286 GNC         196 : json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
                               1287                 :                          bool absent_on_null, bool unique_keys)
 3358 andrew                   1288 ECB             : {
                               1289                 :     int         i;
 3165 tgl                      1290 GIC         196 :     const char *sep = "";
                               1291                 :     StringInfo  result;
                               1292                 :     JsonUniqueBuilderState unique_check;
 3358 andrew                   1293 ECB             : 
 3358 andrew                   1294 CBC         196 :     if (nargs % 2 != 0)
                               1295               9 :         ereport(ERROR,
 3358 andrew                   1296 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 3165 tgl                      1297                 :                  errmsg("argument list must have even number of elements"),
 1418                          1298                 :         /* translator: %s is a SQL function name */
                               1299                 :                  errhint("The arguments of %s must consist of alternating keys and values.",
 1446 alvherre                 1300                 :                          "json_build_object()")));
                               1301                 : 
 3358 andrew                   1302 GIC         187 :     result = makeStringInfo();
                               1303                 : 
 3358 andrew                   1304 CBC         187 :     appendStringInfoChar(result, '{');
                               1305                 : 
   11 alvherre                 1306 GNC         187 :     if (unique_keys)
                               1307              13 :         json_unique_builder_init(&unique_check);
                               1308                 : 
 3358 andrew                   1309 GIC         392 :     for (i = 0; i < nargs; i += 2)
 3358 andrew                   1310 ECB             :     {
                               1311                 :         StringInfo  out;
                               1312                 :         bool        skip;
                               1313                 :         int         key_offset;
                               1314                 : 
                               1315                 :         /* Skip null values if absent_on_null */
   11 alvherre                 1316 GNC         248 :         skip = absent_on_null && nulls[i + 1];
                               1317                 : 
                               1318             248 :         if (skip)
                               1319                 :         {
                               1320                 :             /* If key uniqueness check is needed we must save skipped keys */
                               1321              13 :             if (!unique_keys)
                               1322               7 :                 continue;
                               1323                 : 
                               1324               6 :             out = json_unique_builder_get_throwawaybuf(&unique_check);
                               1325                 :         }
                               1326                 :         else
                               1327                 :         {
                               1328             235 :             appendStringInfoString(result, sep);
                               1329             235 :             sep = ", ";
                               1330             235 :             out = result;
                               1331                 :         }
 3165 tgl                      1332 ECB             : 
 3358 andrew                   1333                 :         /* process key */
 1992 andrew                   1334 CBC         241 :         if (nulls[i])
 3358 andrew                   1335 GIC          12 :             ereport(ERROR,
                               1336                 :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                               1337                 :                      errmsg("null value not allowed for object key")));
                               1338                 : 
                               1339                 :         /* save key offset before appending it */
   11 alvherre                 1340 GNC         229 :         key_offset = out->len;
                               1341                 : 
                               1342             229 :         add_json(args[i], false, out, types[i], true);
                               1343                 : 
                               1344             211 :         if (unique_keys)
                               1345                 :         {
                               1346                 :             /* check key uniqueness after key appending */
                               1347              32 :             const char *key = &out->data[key_offset];
                               1348                 : 
                               1349              32 :             if (!json_unique_check_key(&unique_check.check, key, 0))
                               1350              13 :                 ereport(ERROR,
                               1351                 :                         errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
                               1352                 :                         errmsg("duplicate JSON key %s", key));
                               1353                 : 
                               1354              19 :             if (skip)
                               1355               3 :                 continue;
                               1356                 :         }
                               1357                 : 
 3358 andrew                   1358 CBC         195 :         appendStringInfoString(result, " : ");
 3358 andrew                   1359 ECB             : 
                               1360                 :         /* process value */
 1992 andrew                   1361 GIC         195 :         add_json(args[i + 1], nulls[i + 1], result, types[i + 1], false);
 3358 andrew                   1362 ECB             :     }
                               1363                 : 
 3358 andrew                   1364 CBC         144 :     appendStringInfoChar(result, '}');
                               1365                 : 
   11 alvherre                 1366 GNC         144 :     return PointerGetDatum(cstring_to_text_with_len(result->data, result->len));
                               1367                 : }
                               1368                 : 
                               1369                 : /*
                               1370                 :  * SQL function json_build_object(variadic "any")
                               1371                 :  */
                               1372                 : Datum
                               1373              78 : json_build_object(PG_FUNCTION_ARGS)
                               1374                 : {
                               1375                 :     Datum      *args;
                               1376                 :     bool       *nulls;
                               1377                 :     Oid        *types;
                               1378                 : 
                               1379                 :     /* build argument values to build the object */
                               1380              78 :     int         nargs = extract_variadic_args(fcinfo, 0, true,
                               1381                 :                                               &args, &types, &nulls);
                               1382                 : 
                               1383              78 :     if (nargs < 0)
                               1384               3 :         PG_RETURN_NULL();
                               1385                 : 
                               1386              75 :     PG_RETURN_DATUM(json_build_object_worker(nargs, args, nulls, types, false, false));
                               1387                 : }
                               1388                 : 
                               1389                 : /*
                               1390                 :  * degenerate case of json_build_object where it gets 0 arguments.
                               1391                 :  */
                               1392                 : Datum
 3358 andrew                   1393 CBC           3 : json_build_object_noargs(PG_FUNCTION_ARGS)
                               1394                 : {
                               1395               3 :     PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
                               1396                 : }
 3358 andrew                   1397 ECB             : 
                               1398                 : Datum
   11 alvherre                 1399 GNC          94 : json_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types,
                               1400                 :                         bool absent_on_null)
                               1401                 : {
                               1402                 :     int         i;
 3165 tgl                      1403 CBC          94 :     const char *sep = "";
                               1404                 :     StringInfo  result;
 3358 andrew                   1405 ECB             : 
 3358 andrew                   1406 GIC          94 :     result = makeStringInfo();
                               1407                 : 
                               1408              94 :     appendStringInfoChar(result, '[');
                               1409                 : 
                               1410             262 :     for (i = 0; i < nargs; i++)
                               1411                 :     {
   11 alvherre                 1412 GNC         168 :         if (absent_on_null && nulls[i])
                               1413               9 :             continue;
                               1414                 : 
 3165 tgl                      1415 GIC         159 :         appendStringInfoString(result, sep);
                               1416             159 :         sep = ", ";
 1992 andrew                   1417             159 :         add_json(args[i], nulls[i], result, types[i], false);
                               1418                 :     }
 3165 tgl                      1419 ECB             : 
 3358 andrew                   1420 GIC          94 :     appendStringInfoChar(result, ']');
                               1421                 : 
   11 alvherre                 1422 GNC          94 :     return PointerGetDatum(cstring_to_text_with_len(result->data, result->len));
                               1423                 : }
                               1424                 : 
                               1425                 : /*
                               1426                 :  * SQL function json_build_array(variadic "any")
                               1427                 :  */
                               1428                 : Datum
                               1429              27 : json_build_array(PG_FUNCTION_ARGS)
                               1430                 : {
                               1431                 :     Datum      *args;
                               1432                 :     bool       *nulls;
                               1433                 :     Oid        *types;
                               1434                 : 
                               1435                 :     /* build argument values to build the object */
                               1436              27 :     int         nargs = extract_variadic_args(fcinfo, 0, true,
                               1437                 :                                               &args, &types, &nulls);
                               1438                 : 
                               1439              27 :     if (nargs < 0)
                               1440               3 :         PG_RETURN_NULL();
                               1441                 : 
                               1442              24 :     PG_RETURN_DATUM(json_build_array_worker(nargs, args, nulls, types, false));
                               1443                 : }
                               1444                 : 
 3358 andrew                   1445 ECB             : /*
                               1446                 :  * degenerate case of json_build_array where it gets 0 arguments.
                               1447                 :  */
                               1448                 : Datum
 3358 andrew                   1449 GIC           3 : json_build_array_noargs(PG_FUNCTION_ARGS)
                               1450                 : {
                               1451               3 :     PG_RETURN_TEXT_P(cstring_to_text_with_len("[]", 2));
                               1452                 : }
                               1453                 : 
                               1454                 : /*
 3358 andrew                   1455 ECB             :  * SQL function json_object(text[])
                               1456                 :  *
 3165 tgl                      1457                 :  * take a one or two dimensional array of text as key/value pairs
 3358 andrew                   1458                 :  * for a json object.
                               1459                 :  */
                               1460                 : Datum
 3358 andrew                   1461 CBC          24 : json_object(PG_FUNCTION_ARGS)
 3358 andrew                   1462 ECB             : {
 3358 andrew                   1463 GIC          24 :     ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
 3358 andrew                   1464 CBC          24 :     int         ndims = ARR_NDIM(in_array);
                               1465                 :     StringInfoData result;
 3358 andrew                   1466 ECB             :     Datum      *in_datums;
 3358 andrew                   1467 EUB             :     bool       *in_nulls;
                               1468                 :     int         in_count,
                               1469                 :                 count,
                               1470                 :                 i;
 3358 andrew                   1471 ECB             :     text       *rval;
                               1472                 :     char       *v;
                               1473                 : 
 3358 andrew                   1474 CBC          24 :     switch (ndims)
                               1475                 :     {
                               1476               3 :         case 0:
 3358 andrew                   1477 GBC           3 :             PG_RETURN_DATUM(CStringGetTextDatum("{}"));
                               1478                 :             break;
                               1479                 : 
 3358 andrew                   1480 GIC           9 :         case 1:
 3358 andrew                   1481 CBC           9 :             if ((ARR_DIMS(in_array)[0]) % 2)
 3358 andrew                   1482 GIC           3 :                 ereport(ERROR,
                               1483                 :                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
 3358 andrew                   1484 ECB             :                          errmsg("array must have even number of elements")));
 3358 andrew                   1485 GIC           6 :             break;
                               1486                 : 
                               1487               9 :         case 2:
 3358 andrew                   1488 CBC           9 :             if ((ARR_DIMS(in_array)[1]) != 2)
 3358 andrew                   1489 GIC           6 :                 ereport(ERROR,
                               1490                 :                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                               1491                 :                          errmsg("array must have two columns")));
                               1492               3 :             break;
                               1493                 : 
                               1494               3 :         default:
                               1495               3 :             ereport(ERROR,
                               1496                 :                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                               1497                 :                      errmsg("wrong number of array subscripts")));
                               1498                 :     }
 3358 andrew                   1499 ECB             : 
  282 peter                    1500 GNC           9 :     deconstruct_array_builtin(in_array, TEXTOID, &in_datums, &in_nulls, &in_count);
                               1501                 : 
 3358 andrew                   1502 GIC           9 :     count = in_count / 2;
 3358 andrew                   1503 ECB             : 
 3358 andrew                   1504 GIC           9 :     initStringInfo(&result);
 3358 andrew                   1505 ECB             : 
 3358 andrew                   1506 GIC           9 :     appendStringInfoChar(&result, '{');
                               1507                 : 
                               1508             933 :     for (i = 0; i < count; ++i)
                               1509                 :     {
                               1510             924 :         if (in_nulls[i * 2])
 3358 andrew                   1511 UIC           0 :             ereport(ERROR,
 3358 andrew                   1512 ECB             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                               1513                 :                      errmsg("null value not allowed for object key")));
                               1514                 : 
 3358 andrew                   1515 CBC         924 :         v = TextDatumGetCString(in_datums[i * 2]);
 3358 andrew                   1516 GIC         924 :         if (i > 0)
                               1517             915 :             appendStringInfoString(&result, ", ");
                               1518             924 :         escape_json(&result, v);
 3358 andrew                   1519 CBC         924 :         appendStringInfoString(&result, " : ");
 3358 andrew                   1520 GIC         924 :         pfree(v);
                               1521             924 :         if (in_nulls[i * 2 + 1])
                               1522               6 :             appendStringInfoString(&result, "null");
                               1523                 :         else
                               1524                 :         {
 3358 andrew                   1525 CBC         918 :             v = TextDatumGetCString(in_datums[i * 2 + 1]);
                               1526             918 :             escape_json(&result, v);
 3358 andrew                   1527 GIC         918 :             pfree(v);
                               1528                 :         }
 3358 andrew                   1529 ECB             :     }
                               1530                 : 
 3358 andrew                   1531 CBC           9 :     appendStringInfoChar(&result, '}');
                               1532                 : 
                               1533               9 :     pfree(in_datums);
 3358 andrew                   1534 GIC           9 :     pfree(in_nulls);
                               1535                 : 
 3358 andrew                   1536 CBC           9 :     rval = cstring_to_text_with_len(result.data, result.len);
 3358 andrew                   1537 GIC           9 :     pfree(result.data);
 3358 andrew                   1538 ECB             : 
 3358 andrew                   1539 GIC           9 :     PG_RETURN_TEXT_P(rval);
 3358 andrew                   1540 ECB             : }
                               1541                 : 
                               1542                 : /*
                               1543                 :  * SQL function json_object(text[], text[])
                               1544                 :  *
 3165 tgl                      1545                 :  * take separate key and value arrays of text to construct a json object
 3358 andrew                   1546                 :  * pairwise.
                               1547                 :  */
                               1548                 : Datum
 3358 andrew                   1549 CBC          21 : json_object_two_arg(PG_FUNCTION_ARGS)
                               1550                 : {
                               1551              21 :     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(0);
                               1552              21 :     ArrayType  *val_array = PG_GETARG_ARRAYTYPE_P(1);
 3358 andrew                   1553 GIC          21 :     int         nkdims = ARR_NDIM(key_array);
 3358 andrew                   1554 CBC          21 :     int         nvdims = ARR_NDIM(val_array);
                               1555                 :     StringInfoData result;
 3358 andrew                   1556 ECB             :     Datum      *key_datums,
                               1557                 :                *val_datums;
                               1558                 :     bool       *key_nulls,
                               1559                 :                *val_nulls;
                               1560                 :     int         key_count,
                               1561                 :                 val_count,
                               1562                 :                 i;
                               1563                 :     text       *rval;
                               1564                 :     char       *v;
                               1565                 : 
 3358 andrew                   1566 CBC          21 :     if (nkdims > 1 || nkdims != nvdims)
 3358 andrew                   1567 GIC           3 :         ereport(ERROR,
 3358 andrew                   1568 ECB             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                               1569                 :                  errmsg("wrong number of array subscripts")));
                               1570                 : 
 3358 andrew                   1571 GIC          18 :     if (nkdims == 0)
                               1572               3 :         PG_RETURN_DATUM(CStringGetTextDatum("{}"));
                               1573                 : 
  282 peter                    1574 GNC          15 :     deconstruct_array_builtin(key_array, TEXTOID, &key_datums, &key_nulls, &key_count);
                               1575              15 :     deconstruct_array_builtin(val_array, TEXTOID, &val_datums, &val_nulls, &val_count);
                               1576                 : 
 3358 andrew                   1577 GIC          15 :     if (key_count != val_count)
                               1578               6 :         ereport(ERROR,
 3358 andrew                   1579 ECB             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                               1580                 :                  errmsg("mismatched array dimensions")));
                               1581                 : 
 3358 andrew                   1582 GIC           9 :     initStringInfo(&result);
                               1583                 : 
                               1584               9 :     appendStringInfoChar(&result, '{');
                               1585                 : 
                               1586              39 :     for (i = 0; i < key_count; ++i)
                               1587                 :     {
 3358 andrew                   1588 CBC          33 :         if (key_nulls[i])
 3358 andrew                   1589 GIC           3 :             ereport(ERROR,
 3358 andrew                   1590 ECB             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                               1591                 :                      errmsg("null value not allowed for object key")));
                               1592                 : 
 3358 andrew                   1593 GIC          30 :         v = TextDatumGetCString(key_datums[i]);
                               1594              30 :         if (i > 0)
                               1595              21 :             appendStringInfoString(&result, ", ");
                               1596              30 :         escape_json(&result, v);
 3358 andrew                   1597 CBC          30 :         appendStringInfoString(&result, " : ");
 3358 andrew                   1598 GIC          30 :         pfree(v);
                               1599              30 :         if (val_nulls[i])
 3358 andrew                   1600 UIC           0 :             appendStringInfoString(&result, "null");
                               1601                 :         else
 3358 andrew                   1602 ECB             :         {
 3358 andrew                   1603 GIC          30 :             v = TextDatumGetCString(val_datums[i]);
 3358 andrew                   1604 CBC          30 :             escape_json(&result, v);
 3358 andrew                   1605 GIC          30 :             pfree(v);
                               1606                 :         }
 3358 andrew                   1607 ECB             :     }
                               1608                 : 
 3358 andrew                   1609 GIC           6 :     appendStringInfoChar(&result, '}');
                               1610                 : 
 3358 andrew                   1611 CBC           6 :     pfree(key_datums);
 3358 andrew                   1612 GIC           6 :     pfree(key_nulls);
                               1613               6 :     pfree(val_datums);
                               1614               6 :     pfree(val_nulls);
                               1615                 : 
                               1616               6 :     rval = cstring_to_text_with_len(result.data, result.len);
                               1617               6 :     pfree(result.data);
                               1618                 : 
                               1619               6 :     PG_RETURN_TEXT_P(rval);
 3358 andrew                   1620 ECB             : }
                               1621                 : 
                               1622                 : 
 4083                          1623                 : /*
                               1624                 :  * Produce a JSON string literal, properly escaping characters in the text.
                               1625                 :  */
                               1626                 : void
 4083 andrew                   1627 CBC      168556 : escape_json(StringInfo buf, const char *str)
 4083 andrew                   1628 ECB             : {
                               1629                 :     const char *p;
                               1630                 : 
 2665 peter_e                  1631 CBC      168556 :     appendStringInfoCharMacro(buf, '"');
 4083 andrew                   1632 GIC     1908271 :     for (p = str; *p; p++)
                               1633                 :     {
                               1634         1739715 :         switch (*p)
 4083 andrew                   1635 ECB             :         {
 4083 andrew                   1636 GIC           9 :             case '\b':
                               1637               9 :                 appendStringInfoString(buf, "\\b");
                               1638               9 :                 break;
 4083 andrew                   1639 CBC           3 :             case '\f':
 4083 andrew                   1640 GIC           3 :                 appendStringInfoString(buf, "\\f");
                               1641               3 :                 break;
                               1642              12 :             case '\n':
 4083 andrew                   1643 CBC          12 :                 appendStringInfoString(buf, "\\n");
                               1644              12 :                 break;
 4083 andrew                   1645 GIC           3 :             case '\r':
                               1646               3 :                 appendStringInfoString(buf, "\\r");
                               1647               3 :                 break;
                               1648               6 :             case '\t':
                               1649               6 :                 appendStringInfoString(buf, "\\t");
                               1650               6 :                 break;
 4083 andrew                   1651 CBC          75 :             case '"':
 4083 andrew                   1652 GIC          75 :                 appendStringInfoString(buf, "\\\"");
 4083 andrew                   1653 CBC          75 :                 break;
 4083 andrew                   1654 GIC          45 :             case '\\':
 2991 tgl                      1655 CBC          45 :                 appendStringInfoString(buf, "\\\\");
 4083 andrew                   1656              45 :                 break;
 4083 andrew                   1657 GIC     1739562 :             default:
 4083 andrew                   1658 CBC     1739562 :                 if ((unsigned char) *p < ' ')
 4083 andrew                   1659 GIC           3 :                     appendStringInfo(buf, "\\u%04x", (int) *p);
                               1660                 :                 else
                               1661         1739559 :                     appendStringInfoCharMacro(buf, *p);
                               1662         1739562 :                 break;
                               1663                 :         }
                               1664                 :     }
 2665 peter_e                  1665 CBC      168556 :     appendStringInfoCharMacro(buf, '"');
 4083 andrew                   1666 GIC      168556 : }
 3468 andrew                   1667 ECB             : 
                               1668                 : /* Semantic actions for key uniqueness check */
                               1669                 : static JsonParseErrorType
    9 alvherre                 1670 GNC          86 : json_unique_object_start(void *_state)
                               1671                 : {
                               1672              86 :     JsonUniqueParsingState *state = _state;
                               1673                 :     JsonUniqueStackEntry *entry;
                               1674                 : 
                               1675              86 :     if (!state->unique)
    9 alvherre                 1676 UNC           0 :         return JSON_SUCCESS;
                               1677                 : 
                               1678                 :     /* push object entry to stack */
    9 alvherre                 1679 GNC          86 :     entry = palloc(sizeof(*entry));
                               1680              86 :     entry->object_id = state->id_counter++;
                               1681              86 :     entry->parent = state->stack;
                               1682              86 :     state->stack = entry;
                               1683                 : 
                               1684              86 :     return JSON_SUCCESS;
                               1685                 : }
                               1686                 : 
                               1687                 : static JsonParseErrorType
                               1688              83 : json_unique_object_end(void *_state)
                               1689                 : {
                               1690              83 :     JsonUniqueParsingState *state = _state;
                               1691                 :     JsonUniqueStackEntry *entry;
                               1692                 : 
                               1693              83 :     if (!state->unique)
                               1694              29 :         return JSON_SUCCESS;
                               1695                 : 
                               1696              54 :     entry = state->stack;
                               1697              54 :     state->stack = entry->parent; /* pop object from stack */
                               1698              54 :     pfree(entry);
                               1699              54 :     return JSON_SUCCESS;
                               1700                 : }
                               1701                 : 
                               1702                 : static JsonParseErrorType
                               1703             122 : json_unique_object_field_start(void *_state, char *field, bool isnull)
                               1704                 : {
                               1705             122 :     JsonUniqueParsingState *state = _state;
                               1706                 :     JsonUniqueStackEntry *entry;
                               1707                 : 
                               1708             122 :     if (!state->unique)
    9 alvherre                 1709 UNC           0 :         return JSON_SUCCESS;
                               1710                 : 
                               1711                 :     /* find key collision in the current object */
    9 alvherre                 1712 GNC         122 :     if (json_unique_check_key(&state->check, field, state->stack->object_id))
                               1713             103 :         return JSON_SUCCESS;
                               1714                 : 
                               1715              19 :     state->unique = false;
                               1716                 : 
                               1717                 :     /* pop all objects entries */
                               1718              48 :     while ((entry = state->stack))
                               1719                 :     {
                               1720              29 :         state->stack = entry->parent;
                               1721              29 :         pfree(entry);
                               1722                 :     }
                               1723              19 :     return JSON_SUCCESS;
                               1724                 : }
                               1725                 : 
                               1726                 : /* Validate JSON text and additionally check key uniqueness */
                               1727                 : bool
                               1728             639 : json_validate(text *json, bool check_unique_keys, bool throw_error)
                               1729                 : {
                               1730             639 :     JsonLexContext *lex = makeJsonLexContext(json, check_unique_keys);
                               1731             639 :     JsonSemAction uniqueSemAction = {0};
                               1732                 :     JsonUniqueParsingState state;
                               1733                 :     JsonParseErrorType result;
                               1734                 : 
                               1735             639 :     if (check_unique_keys)
                               1736                 :     {
                               1737             112 :         state.lex = lex;
                               1738             112 :         state.stack = NULL;
                               1739             112 :         state.id_counter = 0;
                               1740             112 :         state.unique = true;
                               1741             112 :         json_unique_check_init(&state.check);
                               1742                 : 
                               1743             112 :         uniqueSemAction.semstate = &state;
                               1744             112 :         uniqueSemAction.object_start = json_unique_object_start;
                               1745             112 :         uniqueSemAction.object_field_start = json_unique_object_field_start;
                               1746             112 :         uniqueSemAction.object_end = json_unique_object_end;
                               1747                 :     }
                               1748                 : 
                               1749             639 :     result = pg_parse_json(lex, check_unique_keys ? &uniqueSemAction : &nullSemAction);
                               1750                 : 
                               1751             639 :     if (result != JSON_SUCCESS)
                               1752                 :     {
                               1753             105 :         if (throw_error)
    9 alvherre                 1754 UNC           0 :             json_errsave_error(result, lex, NULL);
                               1755                 : 
    9 alvherre                 1756 GNC         105 :         return false;           /* invalid json */
                               1757                 :     }
                               1758                 : 
                               1759             534 :     if (check_unique_keys && !state.unique)
                               1760                 :     {
                               1761              19 :         if (throw_error)
    9 alvherre                 1762 UNC           0 :             ereport(ERROR,
                               1763                 :                     (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
                               1764                 :                      errmsg("duplicate JSON object key value")));
                               1765                 : 
    9 alvherre                 1766 GNC          19 :         return false;           /* not unique keys */
                               1767                 :     }
                               1768                 : 
                               1769             515 :     return true;                /* ok */
                               1770                 : }
                               1771                 : 
                               1772                 : /*
                               1773                 :  * SQL function json_typeof(json) -> text
 3468 andrew                   1774 ECB             :  *
                               1775                 :  * Returns the type of the outermost JSON value as TEXT.  Possible types are
                               1776                 :  * "object", "array", "string", "number", "boolean", and "null".
 3437 peter_e                  1777                 :  *
                               1778                 :  * Performs a single call to json_lex() to get the first token of the supplied
                               1779                 :  * value.  This initial token uniquely determines the value's type.  As our
                               1780                 :  * input must already have been validated by json_in() or json_recv(), the
 3468 andrew                   1781                 :  * initial token should never be JSON_TOKEN_OBJECT_END, JSON_TOKEN_ARRAY_END,
                               1782                 :  * JSON_TOKEN_COLON, JSON_TOKEN_COMMA, or JSON_TOKEN_END.
                               1783                 :  */
                               1784                 : Datum
 3468 andrew                   1785 GIC          30 : json_typeof(PG_FUNCTION_ARGS)
                               1786                 : {
    9 alvherre                 1787 GNC          30 :     text       *json = PG_GETARG_TEXT_PP(0);
                               1788              30 :     JsonLexContext *lex = makeJsonLexContext(json, false);
                               1789                 :     char       *type;
                               1790                 :     JsonTokenType tok;
                               1791                 :     JsonParseErrorType result;
 3304 andrew                   1792 ECB             : 
  220                          1793                 :     /* Lex exactly one token from the input and check its type. */
  220 andrew                   1794 GIC          30 :     result = json_lex(lex);
                               1795              30 :     if (result != JSON_SUCCESS)
  119 tgl                      1796 UNC           0 :         json_errsave_error(result, lex, NULL);
  220 andrew                   1797 GIC          30 :     tok = lex->token_type;
                               1798                 : 
 3437 peter_e                  1799 CBC          30 :     switch (tok)
 3437 peter_e                  1800 ECB             :     {
 3364 andrew                   1801 GIC           6 :         case JSON_TOKEN_OBJECT_START:
                               1802               6 :             type = "object";
                               1803               6 :             break;
 3364 andrew                   1804 CBC           6 :         case JSON_TOKEN_ARRAY_START:
                               1805               6 :             type = "array";
 3364 andrew                   1806 GIC           6 :             break;
                               1807               3 :         case JSON_TOKEN_STRING:
 3364 andrew                   1808 CBC           3 :             type = "string";
 3364 andrew                   1809 GIC           3 :             break;
                               1810               6 :         case JSON_TOKEN_NUMBER:
 3364 andrew                   1811 CBC           6 :             type = "number";
 3364 andrew                   1812 GIC           6 :             break;
                               1813               6 :         case JSON_TOKEN_TRUE:
 3364 andrew                   1814 ECB             :         case JSON_TOKEN_FALSE:
 3364 andrew                   1815 GIC           6 :             type = "boolean";
 3364 andrew                   1816 CBC           6 :             break;
 3364 andrew                   1817 GIC           3 :         case JSON_TOKEN_NULL:
                               1818               3 :             type = "null";
                               1819               3 :             break;
 3364 andrew                   1820 UIC           0 :         default:
                               1821               0 :             elog(ERROR, "unexpected json token: %d", tok);
                               1822                 :     }
 3437 peter_e                  1823 ECB             : 
 3437 peter_e                  1824 GIC          30 :     PG_RETURN_TEXT_P(cstring_to_text(type));
                               1825                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a