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 15:15:32 Functions: 93.8 % 48 45 1 2 23 22 3 42 3
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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
     124 GIC        2478 : json_in(PG_FUNCTION_ARGS)
     125                 : {
     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);
     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 */
     136 GIC        2379 :     PG_RETURN_TEXT_P(result);
     137                 : }
     138                 : 
     139                 : /*
     140                 :  * Output.
     141                 :  */
     142                 : Datum
     143            1373 : json_out(PG_FUNCTION_ARGS)
     144                 : {
     145                 :     /* we needn't detoast because text_to_cstring will handle that */
     146            1373 :     Datum       txt = PG_GETARG_DATUM(0);
     147                 : 
     148            1373 :     PG_RETURN_CSTRING(TextDatumGetCString(txt));
     149                 : }
     150                 : 
     151                 : /*
     152                 :  * Binary send.
     153                 :  */
     154                 : Datum
     155 UIC           0 : json_send(PG_FUNCTION_ARGS)
     156                 : {
     157               0 :     text       *t = PG_GETARG_TEXT_PP(0);
     158                 :     StringInfoData buf;
     159                 : 
     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;
     173 ECB             :     int         nbytes;
     174                 :     JsonLexContext *lex;
     175                 : 
     176 LBC           0 :     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
     177                 : 
     178                 :     /* Validate it. */
     179 UIC           0 :     lex = makeJsonLexContextCstringLen(str, nbytes, GetDatabaseEncoding(), false);
     180 LBC           0 :     pg_parse_json_or_ereport(lex, &nullSemAction);
     181 ECB             : 
     182 LBC           0 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(str, nbytes));
     183                 : }
     184                 : 
     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                 :  */
     192                 : static void
     193 GIC        1895 : json_categorize_type(Oid typoid,
     194                 :                      JsonTypeCategory *tcategory,
     195 ECB             :                      Oid *outfuncoid)
     196                 : {
     197                 :     bool        typisvarlena;
     198                 : 
     199                 :     /* Look through any domain */
     200 GIC        1895 :     typoid = getBaseType(typoid);
     201                 : 
     202            1895 :     *outfuncoid = InvalidOid;
     203                 : 
     204 EUB             :     /*
     205                 :      * We need to get the output function for everything except date and
     206                 :      * timestamp types, array and composite types, booleans, and non-builtin
     207                 :      * types where there's a cast to json.
     208                 :      */
     209                 : 
     210 GBC        1895 :     switch (typoid)
     211 EUB             :     {
     212 GIC           9 :         case BOOLOID:
     213               9 :             *tcategory = JSONTYPE_BOOL;
     214               9 :             break;
     215                 : 
     216            1097 :         case INT2OID:
     217                 :         case INT4OID:
     218 EUB             :         case INT8OID:
     219                 :         case FLOAT4OID:
     220                 :         case FLOAT8OID:
     221                 :         case NUMERICOID:
     222 GIC        1097 :             getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
     223            1097 :             *tcategory = JSONTYPE_NUMERIC;
     224            1097 :             break;
     225 EUB             : 
     226 GIC           9 :         case DATEOID:
     227               9 :             *tcategory = JSONTYPE_DATE;
     228 GBC           9 :             break;
     229 EUB             : 
     230 GIC           9 :         case TIMESTAMPOID:
     231 GBC           9 :             *tcategory = JSONTYPE_TIMESTAMP;
     232 GIC           9 :             break;
     233                 : 
     234              12 :         case TIMESTAMPTZOID:
     235              12 :             *tcategory = JSONTYPE_TIMESTAMPTZ;
     236              12 :             break;
     237                 : 
     238              59 :         case JSONOID:
     239                 :         case JSONBOID:
     240              59 :             getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
     241              59 :             *tcategory = JSONTYPE_JSON;
     242 CBC          59 :             break;
     243                 : 
     244 GIC         700 :         default:
     245                 :             /* Check for arrays and composites */
     246             700 :             if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
     247             532 :                 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
     248             168 :                 *tcategory = JSONTYPE_ARRAY;
     249 CBC         532 :             else if (type_is_rowtype(typoid))   /* includes RECORDOID */
     250 GIC         107 :                 *tcategory = JSONTYPE_COMPOSITE;
     251 ECB             :             else
     252                 :             {
     253                 :                 /* It's probably the general case ... */
     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;
     259 ECB             :                     CoercionPathType ctype;
     260                 : 
     261 CBC           2 :                     ctype = find_coercion_pathway(JSONOID, typoid,
     262 ECB             :                                                   COERCION_EXPLICIT,
     263                 :                                                   &castfunc);
     264 GIC           2 :                     if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
     265 ECB             :                     {
     266 GIC           2 :                         *tcategory = JSONTYPE_CAST;
     267               2 :                         *outfuncoid = castfunc;
     268                 :                     }
     269                 :                     else
     270                 :                     {
     271 ECB             :                         /* non builtin type with no cast */
     272 LBC           0 :                         getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
     273 ECB             :                     }
     274                 :                 }
     275                 :                 else
     276                 :                 {
     277                 :                     /* any other builtin type */
     278 GIC         423 :                     getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
     279 ECB             :                 }
     280                 :             }
     281 CBC         700 :             break;
     282                 :     }
     283            1895 : }
     284 ECB             : 
     285                 : /*
     286                 :  * Turn a Datum into JSON text, appending the string to "result".
     287                 :  *
     288                 :  * tcategory and outfuncoid are from a previous call to json_categorize_type,
     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.
     293                 :  */
     294                 : static void
     295 CBC        2608 : datum_to_json(Datum val, bool is_null, StringInfo result,
     296 ECB             :               JsonTypeCategory tcategory, Oid outfuncoid,
     297                 :               bool key_scalar)
     298                 : {
     299                 :     char       *outputstr;
     300                 :     text       *jsontext;
     301                 : 
     302 GIC        2608 :     check_stack_depth();
     303 ECB             : 
     304                 :     /* callers are expected to ensure that null keys are not passed in */
     305 CBC        2608 :     Assert(!(key_scalar && is_null));
     306                 : 
     307 GIC        2608 :     if (is_null)
     308                 :     {
     309             150 :         appendStringInfoString(result, "null");
     310 CBC         150 :         return;
     311                 :     }
     312                 : 
     313            2458 :     if (key_scalar &&
     314 GIC         307 :         (tcategory == JSONTYPE_ARRAY ||
     315 CBC         304 :          tcategory == JSONTYPE_COMPOSITE ||
     316             298 :          tcategory == JSONTYPE_JSON ||
     317                 :          tcategory == JSONTYPE_CAST))
     318 GIC          18 :         ereport(ERROR,
     319                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     320                 :                  errmsg("key value must be scalar, not array, composite, or json")));
     321 EUB             : 
     322 GIC        2440 :     switch (tcategory)
     323                 :     {
     324             162 :         case JSONTYPE_ARRAY:
     325             162 :             array_to_json_internal(val, result, false);
     326             162 :             break;
     327 CBC         226 :         case JSONTYPE_COMPOSITE:
     328 GIC         226 :             composite_to_json(val, result, false);
     329             226 :             break;
     330 CBC           9 :         case JSONTYPE_BOOL:
     331 GIC           9 :             outputstr = DatumGetBool(val) ? "true" : "false";
     332 CBC           9 :             if (key_scalar)
     333 UIC           0 :                 escape_json(result, outputstr);
     334                 :             else
     335 GIC           9 :                 appendStringInfoString(result, outputstr);
     336               9 :             break;
     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                 :              */
     344 CBC        1481 :             if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr)))
     345 GIC        1367 :                 appendStringInfoString(result, outputstr);
     346                 :             else
     347             114 :                 escape_json(result, outputstr);
     348            1481 :             pfree(outputstr);
     349            1481 :             break;
     350               9 :         case JSONTYPE_DATE:
     351 ECB             :             {
     352                 :                 char        buf[MAXDATELEN + 1];
     353                 : 
     354 CBC           9 :                 JsonEncodeDateTime(buf, val, DATEOID, NULL);
     355 GIC           9 :                 appendStringInfo(result, "\"%s\"", buf);
     356 ECB             :             }
     357 GIC           9 :             break;
     358 CBC           9 :         case JSONTYPE_TIMESTAMP:
     359 ECB             :             {
     360                 :                 char        buf[MAXDATELEN + 1];
     361                 : 
     362 CBC           9 :                 JsonEncodeDateTime(buf, val, TIMESTAMPOID, NULL);
     363               9 :                 appendStringInfo(result, "\"%s\"", buf);
     364 ECB             :             }
     365 CBC           9 :             break;
     366 GIC          12 :         case JSONTYPE_TIMESTAMPTZ:
     367 ECB             :             {
     368                 :                 char        buf[MAXDATELEN + 1];
     369                 : 
     370 GIC          12 :                 JsonEncodeDateTime(buf, val, TIMESTAMPTZOID, NULL);
     371 CBC          12 :                 appendStringInfo(result, "\"%s\"", buf);
     372                 :             }
     373              12 :             break;
     374              86 :         case JSONTYPE_JSON:
     375 ECB             :             /* JSON and JSONB output will already be escaped */
     376 CBC          86 :             outputstr = OidOutputFunctionCall(outfuncoid, val);
     377              86 :             appendStringInfoString(result, outputstr);
     378              86 :             pfree(outputstr);
     379              86 :             break;
     380               2 :         case JSONTYPE_CAST:
     381 ECB             :             /* outfuncoid refers to a cast function, not an output function */
     382 GBC           2 :             jsontext = DatumGetTextPP(OidFunctionCall1(outfuncoid, val));
     383 GIC           2 :             outputstr = text_to_cstring(jsontext);
     384 CBC           2 :             appendStringInfoString(result, outputstr);
     385               2 :             pfree(outputstr);
     386               2 :             pfree(jsontext);
     387               2 :             break;
     388 GIC         444 :         default:
     389             444 :             outputstr = OidOutputFunctionCall(outfuncoid, val);
     390             444 :             escape_json(result, outputstr);
     391             444 :             pfree(outputstr);
     392             444 :             break;
     393 ECB             :     }
     394                 : }
     395                 : 
     396                 : /*
     397                 :  * Encode 'value' of datetime type 'typid' into JSON string in ISO format using
     398                 :  * optionally preallocated buffer 'buf'.  Optional 'tzp' determines time-zone
     399                 :  * offset (in seconds) in which we want to show timestamptz.
     400                 :  */
     401                 : char *
     402 GIC         297 : JsonEncodeDateTime(char *buf, Datum value, Oid typid, const int *tzp)
     403 ECB             : {
     404 CBC         297 :     if (!buf)
     405 GIC          30 :         buf = palloc(MAXDATELEN + 1);
     406 ECB             : 
     407 CBC         297 :     switch (typid)
     408                 :     {
     409 GIC          48 :         case DATEOID:
     410                 :             {
     411 ECB             :                 DateADT     date;
     412                 :                 struct pg_tm tm;
     413                 : 
     414 CBC          48 :                 date = DatumGetDateADT(value);
     415 ECB             : 
     416                 :                 /* Same as date_out(), but forcing DateStyle */
     417 GIC          48 :                 if (DATE_NOT_FINITE(date))
     418              12 :                     EncodeSpecialDate(date, buf);
     419 ECB             :                 else
     420                 :                 {
     421 GIC          36 :                     j2date(date + POSTGRES_EPOCH_JDATE,
     422 ECB             :                            &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
     423 CBC          36 :                     EncodeDateOnly(&tm, USE_XSD_DATES, buf);
     424                 :                 }
     425 ECB             :             }
     426 CBC          48 :             break;
     427              30 :         case TIMEOID:
     428 ECB             :             {
     429 CBC          30 :                 TimeADT     time = DatumGetTimeADT(value);
     430                 :                 struct pg_tm tt,
     431              30 :                            *tm = &tt;
     432 ECB             :                 fsec_t      fsec;
     433                 : 
     434                 :                 /* Same as time_out(), but forcing DateStyle */
     435 CBC          30 :                 time2tm(time, tm, &fsec);
     436              30 :                 EncodeTimeOnly(tm, fsec, false, 0, USE_XSD_DATES, buf);
     437 ECB             :             }
     438 CBC          30 :             break;
     439              60 :         case TIMETZOID:
     440 ECB             :             {
     441 CBC          60 :                 TimeTzADT  *time = DatumGetTimeTzADTP(value);
     442                 :                 struct pg_tm tt,
     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                 :             }
     451 CBC          60 :             break;
     452 GIC          63 :         case TIMESTAMPOID:
     453 ECB             :             {
     454                 :                 Timestamp   timestamp;
     455                 :                 struct pg_tm tm;
     456                 :                 fsec_t      fsec;
     457                 : 
     458 CBC          63 :                 timestamp = DatumGetTimestamp(value);
     459                 :                 /* Same as timestamp_out(), but forcing DateStyle */
     460 GIC          63 :                 if (TIMESTAMP_NOT_FINITE(timestamp))
     461              12 :                     EncodeSpecialTimestamp(timestamp, buf);
     462              51 :                 else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
     463 CBC          51 :                     EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
     464                 :                 else
     465 UIC           0 :                     ereport(ERROR,
     466 ECB             :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     467                 :                              errmsg("timestamp out of range")));
     468                 :             }
     469 GIC          63 :             break;
     470 CBC          96 :         case TIMESTAMPTZOID:
     471                 :             {
     472 ECB             :                 TimestampTz timestamp;
     473                 :                 struct pg_tm tm;
     474                 :                 int         tz;
     475                 :                 fsec_t      fsec;
     476 CBC          96 :                 const char *tzn = NULL;
     477                 : 
     478              96 :                 timestamp = DatumGetTimestampTz(value);
     479                 : 
     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                 :                  */
     486 GIC          96 :                 if (tzp)
     487 ECB             :                 {
     488 CBC          72 :                     tz = *tzp;
     489 GIC          72 :                     timestamp -= (TimestampTz) tz * USECS_PER_SEC;
     490 ECB             :                 }
     491                 : 
     492                 :                 /* Same as timestamptz_out(), but forcing DateStyle */
     493 GIC          96 :                 if (TIMESTAMP_NOT_FINITE(timestamp))
     494              12 :                     EncodeSpecialTimestamp(timestamp, buf);
     495              84 :                 else if (timestamp2tm(timestamp, tzp ? NULL : &tz, &tm, &fsec,
     496                 :                                       tzp ? NULL : &tzn, NULL) == 0)
     497 ECB             :                 {
     498 CBC          84 :                     if (tzp)
     499 GIC          72 :                         tm.tm_isdst = 1;    /* set time-zone presence flag */
     500 ECB             : 
     501 CBC          84 :                     EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
     502                 :                 }
     503                 :                 else
     504 UIC           0 :                     ereport(ERROR,
     505                 :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     506                 :                              errmsg("timestamp out of range")));
     507 ECB             :             }
     508 GIC          96 :             break;
     509 LBC           0 :         default:
     510               0 :             elog(ERROR, "unknown jsonb value datetime type oid %u", typid);
     511 ECB             :             return NULL;
     512                 :     }
     513                 : 
     514 GBC         297 :     return buf;
     515                 : }
     516                 : 
     517                 : /*
     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
     523 GIC         189 : array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals,
     524                 :                   bool *nulls, int *valcount, JsonTypeCategory tcategory,
     525 ECB             :                   Oid outfuncoid, bool use_line_feeds)
     526                 : {
     527                 :     int         i;
     528                 :     const char *sep;
     529                 : 
     530 GIC         189 :     Assert(dim < ndims);
     531                 : 
     532             189 :     sep = use_line_feeds ? ",\n " : ",";
     533                 : 
     534             189 :     appendStringInfoChar(result, '[');
     535 ECB             : 
     536 GIC         705 :     for (i = 1; i <= dims[dim]; i++)
     537 ECB             :     {
     538 CBC         516 :         if (i > 1)
     539 GIC         327 :             appendStringInfoString(result, sep);
     540                 : 
     541             516 :         if (dim + 1 == ndims)
     542 ECB             :         {
     543 CBC         510 :             datum_to_json(vals[*valcount], nulls[*valcount], result, tcategory,
     544 ECB             :                           outfuncoid, false);
     545 GIC         510 :             (*valcount)++;
     546                 :         }
     547 ECB             :         else
     548                 :         {
     549                 :             /*
     550                 :              * Do we want line feeds on inner dimensions of arrays? For now
     551                 :              * we'll say no.
     552                 :              */
     553 GBC           6 :             array_dim_to_json(result, dim + 1, ndims, dims, vals, nulls,
     554                 :                               valcount, tcategory, outfuncoid, false);
     555                 :         }
     556                 :     }
     557 ECB             : 
     558 GBC         189 :     appendStringInfoChar(result, ']');
     559             189 : }
     560                 : 
     561                 : /*
     562                 :  * Turn an array into JSON.
     563 ECB             :  */
     564                 : static void
     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;
     572 CBC         183 :     int         count = 0;
     573                 :     Datum      *elements;
     574                 :     bool       *nulls;
     575                 :     int16       typlen;
     576                 :     bool        typbyval;
     577                 :     char        typalign;
     578                 :     JsonTypeCategory tcategory;
     579 ECB             :     Oid         outfuncoid;
     580                 : 
     581 CBC         183 :     ndim = ARR_NDIM(v);
     582 GIC         183 :     dim = ARR_DIMS(v);
     583 CBC         183 :     nitems = ArrayGetNItems(ndim, dim);
     584                 : 
     585             183 :     if (nitems <= 0)
     586                 :     {
     587 LBC           0 :         appendStringInfoString(result, "[]");
     588               0 :         return;
     589                 :     }
     590 ECB             : 
     591 GIC         183 :     get_typlenbyvalalign(element_type,
     592 ECB             :                          &typlen, &typbyval, &typalign);
     593                 : 
     594 CBC         183 :     json_categorize_type(element_type,
     595                 :                          &tcategory, &outfuncoid);
     596                 : 
     597 GIC         183 :     deconstruct_array(v, element_type, typlen, typbyval,
     598                 :                       typalign, &elements, &nulls,
     599                 :                       &nitems);
     600                 : 
     601             183 :     array_dim_to_json(result, 0, ndim, dim, elements, nulls, &count, tcategory,
     602 ECB             :                       outfuncoid, use_line_feeds);
     603                 : 
     604 GIC         183 :     pfree(elements);
     605             183 :     pfree(nulls);
     606                 : }
     607 ECB             : 
     608                 : /*
     609                 :  * Turn a composite / record into JSON.
     610                 :  */
     611                 : static void
     612 GIC         490 : composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
     613                 : {
     614 ECB             :     HeapTupleHeader td;
     615                 :     Oid         tupType;
     616                 :     int32       tupTypmod;
     617                 :     TupleDesc   tupdesc;
     618                 :     HeapTupleData tmptup,
     619                 :                *tuple;
     620                 :     int         i;
     621 CBC         490 :     bool        needsep = false;
     622                 :     const char *sep;
     623                 : 
     624 GIC         490 :     sep = use_line_feeds ? ",\n " : ",";
     625                 : 
     626             490 :     td = DatumGetHeapTupleHeader(composite);
     627                 : 
     628                 :     /* Extract rowtype info and find a tupdesc */
     629             490 :     tupType = HeapTupleHeaderGetTypeId(td);
     630 CBC         490 :     tupTypmod = HeapTupleHeaderGetTypMod(td);
     631             490 :     tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
     632 ECB             : 
     633                 :     /* Build a temporary HeapTuple control structure */
     634 CBC         490 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
     635 GIC         490 :     tmptup.t_data = td;
     636 GBC         490 :     tuple = &tmptup;
     637 EUB             : 
     638 GIC         490 :     appendStringInfoChar(result, '{');
     639                 : 
     640 CBC        1554 :     for (i = 0; i < tupdesc->natts; i++)
     641                 :     {
     642                 :         Datum       val;
     643 ECB             :         bool        isnull;
     644                 :         char       *attname;
     645                 :         JsonTypeCategory tcategory;
     646                 :         Oid         outfuncoid;
     647 GIC        1064 :         Form_pg_attribute att = TupleDescAttr(tupdesc, i);
     648                 : 
     649            1064 :         if (att->attisdropped)
     650 LBC           0 :             continue;
     651                 : 
     652 GIC        1064 :         if (needsep)
     653 CBC         574 :             appendStringInfoString(result, sep);
     654            1064 :         needsep = true;
     655                 : 
     656 GIC        1064 :         attname = NameStr(att->attname);
     657            1064 :         escape_json(result, attname);
     658            1064 :         appendStringInfoChar(result, ':');
     659                 : 
     660            1064 :         val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
     661 ECB             : 
     662 GIC        1064 :         if (isnull)
     663                 :         {
     664              84 :             tcategory = JSONTYPE_NULL;
     665              84 :             outfuncoid = InvalidOid;
     666                 :         }
     667                 :         else
     668             980 :             json_categorize_type(att->atttypid, &tcategory, &outfuncoid);
     669                 : 
     670 CBC        1064 :         datum_to_json(val, isnull, result, tcategory, outfuncoid, false);
     671                 :     }
     672                 : 
     673             490 :     appendStringInfoChar(result, '}');
     674 GIC         490 :     ReleaseTupleDesc(tupdesc);
     675 CBC         490 : }
     676                 : 
     677                 : /*
     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.
     683                 :  */
     684                 : static void
     685 CBC         583 : add_json(Datum val, bool is_null, StringInfo result,
     686                 :          Oid val_type, bool key_scalar)
     687 ECB             : {
     688                 :     JsonTypeCategory tcategory;
     689                 :     Oid         outfuncoid;
     690                 : 
     691 GIC         583 :     if (val_type == InvalidOid)
     692 UIC           0 :         ereport(ERROR,
     693                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     694                 :                  errmsg("could not determine input data type")));
     695                 : 
     696 CBC         583 :     if (is_null)
     697                 :     {
     698              33 :         tcategory = JSONTYPE_NULL;
     699 GBC          33 :         outfuncoid = InvalidOid;
     700                 :     }
     701 ECB             :     else
     702 CBC         550 :         json_categorize_type(val_type,
     703 ECB             :                              &tcategory, &outfuncoid);
     704                 : 
     705 CBC         583 :     datum_to_json(val, is_null, result, tcategory, outfuncoid, key_scalar);
     706             565 : }
     707 ECB             : 
     708                 : /*
     709                 :  * SQL function array_to_json(row)
     710                 :  */
     711                 : Datum
     712 GIC           9 : array_to_json(PG_FUNCTION_ARGS)
     713 ECB             : {
     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                 : 
     721 GIC           9 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
     722 ECB             : }
     723                 : 
     724                 : /*
     725                 :  * SQL function array_to_json(row, prettybool)
     726                 :  */
     727                 : Datum
     728 GIC          12 : array_to_json_pretty(PG_FUNCTION_ARGS)
     729                 : {
     730              12 :     Datum       array = PG_GETARG_DATUM(0);
     731              12 :     bool        use_line_feeds = PG_GETARG_BOOL(1);
     732                 :     StringInfo  result;
     733                 : 
     734 CBC          12 :     result = makeStringInfo();
     735                 : 
     736 GIC          12 :     array_to_json_internal(array, result, use_line_feeds);
     737                 : 
     738              12 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
     739                 : }
     740 ECB             : 
     741 EUB             : /*
     742                 :  * SQL function row_to_json(row)
     743                 :  */
     744                 : Datum
     745 CBC         240 : row_to_json(PG_FUNCTION_ARGS)
     746                 : {
     747             240 :     Datum       array = PG_GETARG_DATUM(0);
     748 ECB             :     StringInfo  result;
     749                 : 
     750 GIC         240 :     result = makeStringInfo();
     751 ECB             : 
     752 GIC         240 :     composite_to_json(array, result, false);
     753                 : 
     754 CBC         240 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
     755 ECB             : }
     756                 : 
     757                 : /*
     758                 :  * SQL function row_to_json(row, prettybool)
     759                 :  */
     760                 : Datum
     761 CBC          24 : row_to_json_pretty(PG_FUNCTION_ARGS)
     762                 : {
     763              24 :     Datum       array = PG_GETARG_DATUM(0);
     764 GIC          24 :     bool        use_line_feeds = PG_GETARG_BOOL(1);
     765                 :     StringInfo  result;
     766 ECB             : 
     767 GIC          24 :     result = makeStringInfo();
     768 ECB             : 
     769 GIC          24 :     composite_to_json(array, result, use_line_feeds);
     770 ECB             : 
     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
     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                 :  */
     819 ECB             : Datum
     820 GIC          66 : to_json(PG_FUNCTION_ARGS)
     821 ECB             : {
     822 CBC          66 :     Datum       val = PG_GETARG_DATUM(0);
     823 GIC          66 :     Oid         val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
     824                 :     StringInfo  result;
     825 ECB             :     JsonTypeCategory tcategory;
     826                 :     Oid         outfuncoid;
     827                 : 
     828 GIC          66 :     if (val_type == InvalidOid)
     829 LBC           0 :         ereport(ERROR,
     830                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     831                 :                  errmsg("could not determine input data type")));
     832                 : 
     833 GIC          66 :     json_categorize_type(val_type,
     834                 :                          &tcategory, &outfuncoid);
     835                 : 
     836 CBC          66 :     result = makeStringInfo();
     837                 : 
     838              66 :     datum_to_json(val, false, result, tcategory, outfuncoid, false);
     839                 : 
     840 GIC          66 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
     841 ECB             : }
     842                 : 
     843                 : /*
     844                 :  * json_agg transition function
     845                 :  *
     846                 :  * aggregate input column as a json array value.
     847                 :  */
     848                 : static Datum
     849 GNC         271 : json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
     850                 : {
     851                 :     MemoryContext aggcontext,
     852 ECB             :                 oldcontext;
     853                 :     JsonAggState *state;
     854                 :     Datum       val;
     855                 : 
     856 GIC         271 :     if (!AggCheckCallContext(fcinfo, &aggcontext))
     857                 :     {
     858 ECB             :         /* cannot be called directly because of internal-type argument */
     859 UIC           0 :         elog(ERROR, "json_agg_transfn called in non-aggregate context");
     860 ECB             :     }
     861                 : 
     862 CBC         271 :     if (PG_ARGISNULL(0))
     863                 :     {
     864 GIC          56 :         Oid         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
     865                 : 
     866              56 :         if (arg_type == InvalidOid)
     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
     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                 :          */
     877 GIC          56 :         oldcontext = MemoryContextSwitchTo(aggcontext);
     878 GBC          56 :         state = (JsonAggState *) palloc(sizeof(JsonAggState));
     879 GIC          56 :         state->str = makeStringInfo();
     880 GBC          56 :         MemoryContextSwitchTo(oldcontext);
     881                 : 
     882              56 :         appendStringInfoChar(state->str, '[');
     883 GIC          56 :         json_categorize_type(arg_type, &state->val_category,
     884                 :                              &state->val_output_func);
     885 EUB             :     }
     886                 :     else
     887                 :     {
     888 GIC         215 :         state = (JsonAggState *) PG_GETARG_POINTER(0);
     889 EUB             :     }
     890                 : 
     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                 : 
     897 EUB             :     /* fast path for NULLs */
     898 GBC         226 :     if (PG_ARGISNULL(1))
     899                 :     {
     900              27 :         datum_to_json((Datum) 0, true, state->str, JSONTYPE_NULL,
     901 EUB             :                       InvalidOid, false);
     902 GIC          27 :         PG_RETURN_POINTER(state);
     903 EUB             :     }
     904                 : 
     905 GIC         199 :     val = PG_GETARG_DATUM(1);
     906 EUB             : 
     907                 :     /* add some whitespace if structured type and not first item */
     908 GNC         199 :     if (!PG_ARGISNULL(0) && state->str->len > 1 &&
     909 GBC         149 :         (state->val_category == JSONTYPE_ARRAY ||
     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,
     916 ECB             :                   state->val_output_func, false);
     917                 : 
     918                 :     /*
     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                 :      */
     923 GIC         199 :     PG_RETURN_POINTER(state);
     924 ECB             : }
     925 EUB             : 
     926                 : 
     927                 : /*
     928                 :  * json_agg aggregate function
     929                 :  */
     930                 : Datum
     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                 :  */
     948 ECB             : Datum
     949 GIC          62 : json_agg_finalfn(PG_FUNCTION_ARGS)
     950                 : {
     951 ECB             :     JsonAggState *state;
     952                 : 
     953                 :     /* cannot be called directly because of internal-type argument */
     954 GIC          62 :     Assert(AggCheckCallContext(fcinfo, NULL));
     955 ECB             : 
     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 */
     961              62 :     if (state == NULL)
     962               6 :         PG_RETURN_NULL();
     963                 : 
     964 ECB             :     /* Else return state with appropriate array terminator added */
     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
     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)
     987 UNC           0 :         return entry1->object_id > entry2->object_id ? 1 : -1;
     988                 : 
     989 GNC          38 :     if (entry1->key_len != entry2->key_len)
     990 UNC           0 :         return entry1->key_len > entry2->key_len ? 1 : -1;
     991                 : 
     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                 :  *
    1069 ECB             :  * aggregate two input columns as a single json object value.
    1070                 :  */
    1071                 : static Datum
    1072 GNC          99 : json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
    1073                 :                                bool absent_on_null, bool unique_keys)
    1074                 : {
    1075                 :     MemoryContext aggcontext,
    1076 ECB             :                 oldcontext;
    1077                 :     JsonAggState *state;
    1078                 :     StringInfo  out;
    1079                 :     Datum       arg;
    1080                 :     bool        skip;
    1081                 :     int         key_offset;
    1082                 : 
    1083 CBC          99 :     if (!AggCheckCallContext(fcinfo, &aggcontext))
    1084 EUB             :     {
    1085                 :         /* cannot be called directly because of internal-type argument */
    1086 UIC           0 :         elog(ERROR, "json_object_agg_transfn called in non-aggregate context");
    1087                 :     }
    1088                 : 
    1089 GIC          99 :     if (PG_ARGISNULL(0))
    1090                 :     {
    1091                 :         Oid         arg_type;
    1092                 : 
    1093                 :         /*
    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                 :          */
    1099 CBC          30 :         oldcontext = MemoryContextSwitchTo(aggcontext);
    1100              30 :         state = (JsonAggState *) palloc(sizeof(JsonAggState));
    1101 GIC          30 :         state->str = makeStringInfo();
    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));
    1106 GIC          30 :         MemoryContextSwitchTo(oldcontext);
    1107                 : 
    1108              30 :         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    1109 ECB             : 
    1110 GIC          30 :         if (arg_type == InvalidOid)
    1111 UIC           0 :             ereport(ERROR,
    1112 ECB             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1113                 :                      errmsg("could not determine data type for argument %d", 1)));
    1114                 : 
    1115 CBC          30 :         json_categorize_type(arg_type, &state->key_category,
    1116 ECB             :                              &state->key_output_func);
    1117                 : 
    1118 GIC          30 :         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
    1119 ECB             : 
    1120 GIC          30 :         if (arg_type == InvalidOid)
    1121 LBC           0 :             ereport(ERROR,
    1122                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1123 ECB             :                      errmsg("could not determine data type for argument %d", 2)));
    1124                 : 
    1125 GIC          30 :         json_categorize_type(arg_type, &state->val_category,
    1126 ECB             :                              &state->val_output_func);
    1127                 : 
    1128 GIC          30 :         appendStringInfoString(state->str, "{ ");
    1129 ECB             :     }
    1130                 :     else
    1131                 :     {
    1132 GIC          69 :         state = (JsonAggState *) PG_GETARG_POINTER(0);
    1133                 :     }
    1134                 : 
    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                 : 
    1143 CBC          99 :     if (PG_ARGISNULL(1))
    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 */
    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                 : 
    1175 GIC          87 :     arg = PG_GETARG_DATUM(1);
    1176                 : 
    1177 GNC          87 :     key_offset = out->len;
    1178                 : 
    1179              87 :     datum_to_json(arg, false, out, state->key_category,
    1180 ECB             :                   state->key_output_func, true);
    1181                 : 
    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                 : 
    1195 CBC          72 :     appendStringInfoString(state->str, " : ");
    1196                 : 
    1197 GIC          72 :     if (PG_ARGISNULL(2))
    1198               6 :         arg = (Datum) 0;
    1199                 :     else
    1200              66 :         arg = PG_GETARG_DATUM(2);
    1201                 : 
    1202 CBC          72 :     datum_to_json(arg, PG_ARGISNULL(2), state->str, state->val_category,
    1203                 :                   state->val_output_func, false);
    1204 ECB             : 
    1205 GIC          72 :     PG_RETURN_POINTER(state);
    1206                 : }
    1207                 : 
    1208                 : /*
    1209                 :  * json_object_agg aggregate function
    1210                 :  */
    1211                 : Datum
    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                 :  */
    1247 ECB             : Datum
    1248 GIC          21 : json_object_agg_finalfn(PG_FUNCTION_ARGS)
    1249                 : {
    1250                 :     JsonAggState *state;
    1251                 : 
    1252 ECB             :     /* cannot be called directly because of internal-type argument */
    1253 GIC          21 :     Assert(AggCheckCallContext(fcinfo, NULL));
    1254 ECB             : 
    1255 CBC          21 :     state = PG_ARGISNULL(0) ? NULL : (JsonAggState *) PG_GETARG_POINTER(0);
    1256 ECB             : 
    1257                 :     /* NULL result for no rows in, as is standard with aggregates */
    1258 GIC          21 :     if (state == NULL)
    1259 CBC           3 :         PG_RETURN_NULL();
    1260 ECB             : 
    1261                 :     /* Else return state with appropriate object terminator added */
    1262 GIC          18 :     PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, " }"));
    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 *
    1271 CBC          74 : catenate_stringinfo_string(StringInfo buffer, const char *addon)
    1272                 : {
    1273 ECB             :     /* custom version of cstring_to_text_with_len */
    1274 GIC          74 :     int         buflen = buffer->len;
    1275 CBC          74 :     int         addlen = strlen(addon);
    1276 GIC          74 :     text       *result = (text *) palloc(buflen + addlen + VARHDRSZ);
    1277                 : 
    1278              74 :     SET_VARSIZE(result, buflen + addlen + VARHDRSZ);
    1279 CBC          74 :     memcpy(VARDATA(result), buffer->data, buflen);
    1280 GIC          74 :     memcpy(VARDATA(result) + buflen, addon, addlen);
    1281 ECB             : 
    1282 CBC          74 :     return result;
    1283                 : }
    1284 ECB             : 
    1285 EUB             : Datum
    1286 GNC         196 : json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
    1287                 :                          bool absent_on_null, bool unique_keys)
    1288 ECB             : {
    1289                 :     int         i;
    1290 GIC         196 :     const char *sep = "";
    1291                 :     StringInfo  result;
    1292                 :     JsonUniqueBuilderState unique_check;
    1293 ECB             : 
    1294 CBC         196 :     if (nargs % 2 != 0)
    1295               9 :         ereport(ERROR,
    1296 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1297                 :                  errmsg("argument list must have even number of elements"),
    1298                 :         /* translator: %s is a SQL function name */
    1299                 :                  errhint("The arguments of %s must consist of alternating keys and values.",
    1300                 :                          "json_build_object()")));
    1301                 : 
    1302 GIC         187 :     result = makeStringInfo();
    1303                 : 
    1304 CBC         187 :     appendStringInfoChar(result, '{');
    1305                 : 
    1306 GNC         187 :     if (unique_keys)
    1307              13 :         json_unique_builder_init(&unique_check);
    1308                 : 
    1309 GIC         392 :     for (i = 0; i < nargs; i += 2)
    1310 ECB             :     {
    1311                 :         StringInfo  out;
    1312                 :         bool        skip;
    1313                 :         int         key_offset;
    1314                 : 
    1315                 :         /* Skip null values if absent_on_null */
    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                 :         }
    1332 ECB             : 
    1333                 :         /* process key */
    1334 CBC         241 :         if (nulls[i])
    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 */
    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                 : 
    1358 CBC         195 :         appendStringInfoString(result, " : ");
    1359 ECB             : 
    1360                 :         /* process value */
    1361 GIC         195 :         add_json(args[i + 1], nulls[i + 1], result, types[i + 1], false);
    1362 ECB             :     }
    1363                 : 
    1364 CBC         144 :     appendStringInfoChar(result, '}');
    1365                 : 
    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
    1393 CBC           3 : json_build_object_noargs(PG_FUNCTION_ARGS)
    1394                 : {
    1395               3 :     PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
    1396                 : }
    1397 ECB             : 
    1398                 : Datum
    1399 GNC          94 : json_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types,
    1400                 :                         bool absent_on_null)
    1401                 : {
    1402                 :     int         i;
    1403 CBC          94 :     const char *sep = "";
    1404                 :     StringInfo  result;
    1405 ECB             : 
    1406 GIC          94 :     result = makeStringInfo();
    1407                 : 
    1408              94 :     appendStringInfoChar(result, '[');
    1409                 : 
    1410             262 :     for (i = 0; i < nargs; i++)
    1411                 :     {
    1412 GNC         168 :         if (absent_on_null && nulls[i])
    1413               9 :             continue;
    1414                 : 
    1415 GIC         159 :         appendStringInfoString(result, sep);
    1416             159 :         sep = ", ";
    1417             159 :         add_json(args[i], nulls[i], result, types[i], false);
    1418                 :     }
    1419 ECB             : 
    1420 GIC          94 :     appendStringInfoChar(result, ']');
    1421                 : 
    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                 : 
    1445 ECB             : /*
    1446                 :  * degenerate case of json_build_array where it gets 0 arguments.
    1447                 :  */
    1448                 : Datum
    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                 : /*
    1455 ECB             :  * SQL function json_object(text[])
    1456                 :  *
    1457                 :  * take a one or two dimensional array of text as key/value pairs
    1458                 :  * for a json object.
    1459                 :  */
    1460                 : Datum
    1461 CBC          24 : json_object(PG_FUNCTION_ARGS)
    1462 ECB             : {
    1463 GIC          24 :     ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
    1464 CBC          24 :     int         ndims = ARR_NDIM(in_array);
    1465                 :     StringInfoData result;
    1466 ECB             :     Datum      *in_datums;
    1467 EUB             :     bool       *in_nulls;
    1468                 :     int         in_count,
    1469                 :                 count,
    1470                 :                 i;
    1471 ECB             :     text       *rval;
    1472                 :     char       *v;
    1473                 : 
    1474 CBC          24 :     switch (ndims)
    1475                 :     {
    1476               3 :         case 0:
    1477 GBC           3 :             PG_RETURN_DATUM(CStringGetTextDatum("{}"));
    1478                 :             break;
    1479                 : 
    1480 GIC           9 :         case 1:
    1481 CBC           9 :             if ((ARR_DIMS(in_array)[0]) % 2)
    1482 GIC           3 :                 ereport(ERROR,
    1483                 :                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    1484 ECB             :                          errmsg("array must have even number of elements")));
    1485 GIC           6 :             break;
    1486                 : 
    1487               9 :         case 2:
    1488 CBC           9 :             if ((ARR_DIMS(in_array)[1]) != 2)
    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                 :     }
    1499 ECB             : 
    1500 GNC           9 :     deconstruct_array_builtin(in_array, TEXTOID, &in_datums, &in_nulls, &in_count);
    1501                 : 
    1502 GIC           9 :     count = in_count / 2;
    1503 ECB             : 
    1504 GIC           9 :     initStringInfo(&result);
    1505 ECB             : 
    1506 GIC           9 :     appendStringInfoChar(&result, '{');
    1507                 : 
    1508             933 :     for (i = 0; i < count; ++i)
    1509                 :     {
    1510             924 :         if (in_nulls[i * 2])
    1511 UIC           0 :             ereport(ERROR,
    1512 ECB             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    1513                 :                      errmsg("null value not allowed for object key")));
    1514                 : 
    1515 CBC         924 :         v = TextDatumGetCString(in_datums[i * 2]);
    1516 GIC         924 :         if (i > 0)
    1517             915 :             appendStringInfoString(&result, ", ");
    1518             924 :         escape_json(&result, v);
    1519 CBC         924 :         appendStringInfoString(&result, " : ");
    1520 GIC         924 :         pfree(v);
    1521             924 :         if (in_nulls[i * 2 + 1])
    1522               6 :             appendStringInfoString(&result, "null");
    1523                 :         else
    1524                 :         {
    1525 CBC         918 :             v = TextDatumGetCString(in_datums[i * 2 + 1]);
    1526             918 :             escape_json(&result, v);
    1527 GIC         918 :             pfree(v);
    1528                 :         }
    1529 ECB             :     }
    1530                 : 
    1531 CBC           9 :     appendStringInfoChar(&result, '}');
    1532                 : 
    1533               9 :     pfree(in_datums);
    1534 GIC           9 :     pfree(in_nulls);
    1535                 : 
    1536 CBC           9 :     rval = cstring_to_text_with_len(result.data, result.len);
    1537 GIC           9 :     pfree(result.data);
    1538 ECB             : 
    1539 GIC           9 :     PG_RETURN_TEXT_P(rval);
    1540 ECB             : }
    1541                 : 
    1542                 : /*
    1543                 :  * SQL function json_object(text[], text[])
    1544                 :  *
    1545                 :  * take separate key and value arrays of text to construct a json object
    1546                 :  * pairwise.
    1547                 :  */
    1548                 : Datum
    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);
    1553 GIC          21 :     int         nkdims = ARR_NDIM(key_array);
    1554 CBC          21 :     int         nvdims = ARR_NDIM(val_array);
    1555                 :     StringInfoData result;
    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                 : 
    1566 CBC          21 :     if (nkdims > 1 || nkdims != nvdims)
    1567 GIC           3 :         ereport(ERROR,
    1568 ECB             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    1569                 :                  errmsg("wrong number of array subscripts")));
    1570                 : 
    1571 GIC          18 :     if (nkdims == 0)
    1572               3 :         PG_RETURN_DATUM(CStringGetTextDatum("{}"));
    1573                 : 
    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                 : 
    1577 GIC          15 :     if (key_count != val_count)
    1578               6 :         ereport(ERROR,
    1579 ECB             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    1580                 :                  errmsg("mismatched array dimensions")));
    1581                 : 
    1582 GIC           9 :     initStringInfo(&result);
    1583                 : 
    1584               9 :     appendStringInfoChar(&result, '{');
    1585                 : 
    1586              39 :     for (i = 0; i < key_count; ++i)
    1587                 :     {
    1588 CBC          33 :         if (key_nulls[i])
    1589 GIC           3 :             ereport(ERROR,
    1590 ECB             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    1591                 :                      errmsg("null value not allowed for object key")));
    1592                 : 
    1593 GIC          30 :         v = TextDatumGetCString(key_datums[i]);
    1594              30 :         if (i > 0)
    1595              21 :             appendStringInfoString(&result, ", ");
    1596              30 :         escape_json(&result, v);
    1597 CBC          30 :         appendStringInfoString(&result, " : ");
    1598 GIC          30 :         pfree(v);
    1599              30 :         if (val_nulls[i])
    1600 UIC           0 :             appendStringInfoString(&result, "null");
    1601                 :         else
    1602 ECB             :         {
    1603 GIC          30 :             v = TextDatumGetCString(val_datums[i]);
    1604 CBC          30 :             escape_json(&result, v);
    1605 GIC          30 :             pfree(v);
    1606                 :         }
    1607 ECB             :     }
    1608                 : 
    1609 GIC           6 :     appendStringInfoChar(&result, '}');
    1610                 : 
    1611 CBC           6 :     pfree(key_datums);
    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);
    1620 ECB             : }
    1621                 : 
    1622                 : 
    1623                 : /*
    1624                 :  * Produce a JSON string literal, properly escaping characters in the text.
    1625                 :  */
    1626                 : void
    1627 CBC      168556 : escape_json(StringInfo buf, const char *str)
    1628 ECB             : {
    1629                 :     const char *p;
    1630                 : 
    1631 CBC      168556 :     appendStringInfoCharMacro(buf, '"');
    1632 GIC     1908271 :     for (p = str; *p; p++)
    1633                 :     {
    1634         1739715 :         switch (*p)
    1635 ECB             :         {
    1636 GIC           9 :             case '\b':
    1637               9 :                 appendStringInfoString(buf, "\\b");
    1638               9 :                 break;
    1639 CBC           3 :             case '\f':
    1640 GIC           3 :                 appendStringInfoString(buf, "\\f");
    1641               3 :                 break;
    1642              12 :             case '\n':
    1643 CBC          12 :                 appendStringInfoString(buf, "\\n");
    1644              12 :                 break;
    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;
    1651 CBC          75 :             case '"':
    1652 GIC          75 :                 appendStringInfoString(buf, "\\\"");
    1653 CBC          75 :                 break;
    1654 GIC          45 :             case '\\':
    1655 CBC          45 :                 appendStringInfoString(buf, "\\\\");
    1656              45 :                 break;
    1657 GIC     1739562 :             default:
    1658 CBC     1739562 :                 if ((unsigned char) *p < ' ')
    1659 GIC           3 :                     appendStringInfo(buf, "\\u%04x", (int) *p);
    1660                 :                 else
    1661         1739559 :                     appendStringInfoCharMacro(buf, *p);
    1662         1739562 :                 break;
    1663                 :         }
    1664                 :     }
    1665 CBC      168556 :     appendStringInfoCharMacro(buf, '"');
    1666 GIC      168556 : }
    1667 ECB             : 
    1668                 : /* Semantic actions for key uniqueness check */
    1669                 : static JsonParseErrorType
    1670 GNC          86 : json_unique_object_start(void *_state)
    1671                 : {
    1672              86 :     JsonUniqueParsingState *state = _state;
    1673                 :     JsonUniqueStackEntry *entry;
    1674                 : 
    1675              86 :     if (!state->unique)
    1676 UNC           0 :         return JSON_SUCCESS;
    1677                 : 
    1678                 :     /* push object entry to stack */
    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)
    1709 UNC           0 :         return JSON_SUCCESS;
    1710                 : 
    1711                 :     /* find key collision in the current object */
    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)
    1754 UNC           0 :             json_errsave_error(result, lex, NULL);
    1755                 : 
    1756 GNC         105 :         return false;           /* invalid json */
    1757                 :     }
    1758                 : 
    1759             534 :     if (check_unique_keys && !state.unique)
    1760                 :     {
    1761              19 :         if (throw_error)
    1762 UNC           0 :             ereport(ERROR,
    1763                 :                     (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
    1764                 :                      errmsg("duplicate JSON object key value")));
    1765                 : 
    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
    1774 ECB             :  *
    1775                 :  * Returns the type of the outermost JSON value as TEXT.  Possible types are
    1776                 :  * "object", "array", "string", "number", "boolean", and "null".
    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
    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
    1785 GIC          30 : json_typeof(PG_FUNCTION_ARGS)
    1786                 : {
    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;
    1792 ECB             : 
    1793                 :     /* Lex exactly one token from the input and check its type. */
    1794 GIC          30 :     result = json_lex(lex);
    1795              30 :     if (result != JSON_SUCCESS)
    1796 UNC           0 :         json_errsave_error(result, lex, NULL);
    1797 GIC          30 :     tok = lex->token_type;
    1798                 : 
    1799 CBC          30 :     switch (tok)
    1800 ECB             :     {
    1801 GIC           6 :         case JSON_TOKEN_OBJECT_START:
    1802               6 :             type = "object";
    1803               6 :             break;
    1804 CBC           6 :         case JSON_TOKEN_ARRAY_START:
    1805               6 :             type = "array";
    1806 GIC           6 :             break;
    1807               3 :         case JSON_TOKEN_STRING:
    1808 CBC           3 :             type = "string";
    1809 GIC           3 :             break;
    1810               6 :         case JSON_TOKEN_NUMBER:
    1811 CBC           6 :             type = "number";
    1812 GIC           6 :             break;
    1813               6 :         case JSON_TOKEN_TRUE:
    1814 ECB             :         case JSON_TOKEN_FALSE:
    1815 GIC           6 :             type = "boolean";
    1816 CBC           6 :             break;
    1817 GIC           3 :         case JSON_TOKEN_NULL:
    1818               3 :             type = "null";
    1819               3 :             break;
    1820 UIC           0 :         default:
    1821               0 :             elog(ERROR, "unexpected json token: %d", tok);
    1822                 :     }
    1823 ECB             : 
    1824 GIC          30 :     PG_RETURN_TEXT_P(cstring_to_text(type));
    1825                 : }
        

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