LCOV - code coverage report
Current view: top level - src/backend/utils/adt - json.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 804 878 91.6 %
Date: 2019-06-19 14:06:47 Functions: 47 49 95.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * json.c
       4             :  *      JSON data type support.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, 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 "access/htup_details.h"
      17             : #include "access/transam.h"
      18             : #include "catalog/pg_type.h"
      19             : #include "executor/spi.h"
      20             : #include "funcapi.h"
      21             : #include "lib/stringinfo.h"
      22             : #include "libpq/pqformat.h"
      23             : #include "mb/pg_wchar.h"
      24             : #include "miscadmin.h"
      25             : #include "parser/parse_coerce.h"
      26             : #include "utils/array.h"
      27             : #include "utils/builtins.h"
      28             : #include "utils/date.h"
      29             : #include "utils/datetime.h"
      30             : #include "utils/lsyscache.h"
      31             : #include "utils/json.h"
      32             : #include "utils/jsonapi.h"
      33             : #include "utils/typcache.h"
      34             : #include "utils/syscache.h"
      35             : 
      36             : /*
      37             :  * The context of the parser is maintained by the recursive descent
      38             :  * mechanism, but is passed explicitly to the error reporting routine
      39             :  * for better diagnostics.
      40             :  */
      41             : typedef enum                    /* contexts of JSON parser */
      42             : {
      43             :     JSON_PARSE_VALUE,           /* expecting a value */
      44             :     JSON_PARSE_STRING,          /* expecting a string (for a field name) */
      45             :     JSON_PARSE_ARRAY_START,     /* saw '[', expecting value or ']' */
      46             :     JSON_PARSE_ARRAY_NEXT,      /* saw array element, expecting ',' or ']' */
      47             :     JSON_PARSE_OBJECT_START,    /* saw '{', expecting label or '}' */
      48             :     JSON_PARSE_OBJECT_LABEL,    /* saw object label, expecting ':' */
      49             :     JSON_PARSE_OBJECT_NEXT,     /* saw object value, expecting ',' or '}' */
      50             :     JSON_PARSE_OBJECT_COMMA,    /* saw object ',', expecting next label */
      51             :     JSON_PARSE_END              /* saw the end of a document, expect nothing */
      52             : } JsonParseContext;
      53             : 
      54             : typedef enum                    /* type categories for datum_to_json */
      55             : {
      56             :     JSONTYPE_NULL,              /* null, so we didn't bother to identify */
      57             :     JSONTYPE_BOOL,              /* boolean (built-in types only) */
      58             :     JSONTYPE_NUMERIC,           /* numeric (ditto) */
      59             :     JSONTYPE_DATE,              /* we use special formatting for datetimes */
      60             :     JSONTYPE_TIMESTAMP,
      61             :     JSONTYPE_TIMESTAMPTZ,
      62             :     JSONTYPE_JSON,              /* JSON itself (and JSONB) */
      63             :     JSONTYPE_ARRAY,             /* array */
      64             :     JSONTYPE_COMPOSITE,         /* composite */
      65             :     JSONTYPE_CAST,              /* something with an explicit cast to JSON */
      66             :     JSONTYPE_OTHER              /* all else */
      67             : } JsonTypeCategory;
      68             : 
      69             : typedef struct JsonAggState
      70             : {
      71             :     StringInfo  str;
      72             :     JsonTypeCategory key_category;
      73             :     Oid         key_output_func;
      74             :     JsonTypeCategory val_category;
      75             :     Oid         val_output_func;
      76             : } JsonAggState;
      77             : 
      78             : static inline void json_lex(JsonLexContext *lex);
      79             : static inline void json_lex_string(JsonLexContext *lex);
      80             : static inline void json_lex_number(JsonLexContext *lex, char *s,
      81             :                                    bool *num_err, int *total_len);
      82             : static inline void parse_scalar(JsonLexContext *lex, JsonSemAction *sem);
      83             : static void parse_object_field(JsonLexContext *lex, JsonSemAction *sem);
      84             : static void parse_object(JsonLexContext *lex, JsonSemAction *sem);
      85             : static void parse_array_element(JsonLexContext *lex, JsonSemAction *sem);
      86             : static void parse_array(JsonLexContext *lex, JsonSemAction *sem);
      87             : static void report_parse_error(JsonParseContext ctx, JsonLexContext *lex) pg_attribute_noreturn();
      88             : static void report_invalid_token(JsonLexContext *lex) pg_attribute_noreturn();
      89             : static int  report_json_context(JsonLexContext *lex);
      90             : static char *extract_mb_char(char *s);
      91             : static void composite_to_json(Datum composite, StringInfo result,
      92             :                               bool use_line_feeds);
      93             : static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims,
      94             :                               Datum *vals, bool *nulls, int *valcount,
      95             :                               JsonTypeCategory tcategory, Oid outfuncoid,
      96             :                               bool use_line_feeds);
      97             : static void array_to_json_internal(Datum array, StringInfo result,
      98             :                                    bool use_line_feeds);
      99             : static void json_categorize_type(Oid typoid,
     100             :                                  JsonTypeCategory *tcategory,
     101             :                                  Oid *outfuncoid);
     102             : static void datum_to_json(Datum val, bool is_null, StringInfo result,
     103             :                           JsonTypeCategory tcategory, Oid outfuncoid,
     104             :                           bool key_scalar);
     105             : static void add_json(Datum val, bool is_null, StringInfo result,
     106             :                      Oid val_type, bool key_scalar);
     107             : static text *catenate_stringinfo_string(StringInfo buffer, const char *addon);
     108             : 
     109             : /* the null action object used for pure validation */
     110             : static JsonSemAction nullSemAction =
     111             : {
     112             :     NULL, NULL, NULL, NULL, NULL,
     113             :     NULL, NULL, NULL, NULL, NULL
     114             : };
     115             : 
     116             : /* Recursive Descent parser support routines */
     117             : 
     118             : /*
     119             :  * lex_peek
     120             :  *
     121             :  * what is the current look_ahead token?
     122             : */
     123             : static inline JsonTokenType
     124      317544 : lex_peek(JsonLexContext *lex)
     125             : {
     126      317544 :     return lex->token_type;
     127             : }
     128             : 
     129             : /*
     130             :  * lex_accept
     131             :  *
     132             :  * accept the look_ahead token and move the lexer to the next token if the
     133             :  * look_ahead token matches the token parameter. In that case, and if required,
     134             :  * also hand back the de-escaped lexeme.
     135             :  *
     136             :  * returns true if the token matched, false otherwise.
     137             :  */
     138             : static inline bool
     139      566606 : lex_accept(JsonLexContext *lex, JsonTokenType token, char **lexeme)
     140             : {
     141      566606 :     if (lex->token_type == token)
     142             :     {
     143      538498 :         if (lexeme != NULL)
     144             :         {
     145      203276 :             if (lex->token_type == JSON_TOKEN_STRING)
     146             :             {
     147      126358 :                 if (lex->strval != NULL)
     148      122486 :                     *lexeme = pstrdup(lex->strval->data);
     149             :             }
     150             :             else
     151             :             {
     152       76918 :                 int         len = (lex->token_terminator - lex->token_start);
     153       76918 :                 char       *tokstr = palloc(len + 1);
     154             : 
     155       76918 :                 memcpy(tokstr, lex->token_start, len);
     156       76918 :                 tokstr[len] = '\0';
     157       76918 :                 *lexeme = tokstr;
     158             :             }
     159             :         }
     160      538498 :         json_lex(lex);
     161      538446 :         return true;
     162             :     }
     163       28108 :     return false;
     164             : }
     165             : 
     166             : /*
     167             :  * lex_accept
     168             :  *
     169             :  * move the lexer to the next token if the current look_ahead token matches
     170             :  * the parameter token. Otherwise, report an error.
     171             :  */
     172             : static inline void
     173      206016 : lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
     174             : {
     175      206016 :     if (!lex_accept(lex, token, NULL))
     176          56 :         report_parse_error(ctx, lex);
     177      205916 : }
     178             : 
     179             : /* chars to consider as part of an alphanumeric token */
     180             : #define JSON_ALPHANUMERIC_CHAR(c)  \
     181             :     (((c) >= 'a' && (c) <= 'z') || \
     182             :      ((c) >= 'A' && (c) <= 'Z') || \
     183             :      ((c) >= '0' && (c) <= '9') || \
     184             :      (c) == '_' || \
     185             :      IS_HIGHBIT_SET(c))
     186             : 
     187             : /*
     188             :  * Utility function to check if a string is a valid JSON number.
     189             :  *
     190             :  * str is of length len, and need not be null-terminated.
     191             :  */
     192             : bool
     193        1578 : IsValidJsonNumber(const char *str, int len)
     194             : {
     195             :     bool        numeric_error;
     196             :     int         total_len;
     197             :     JsonLexContext dummy_lex;
     198             : 
     199        1578 :     if (len <= 0)
     200           0 :         return false;
     201             : 
     202             :     /*
     203             :      * json_lex_number expects a leading  '-' to have been eaten already.
     204             :      *
     205             :      * having to cast away the constness of str is ugly, but there's not much
     206             :      * easy alternative.
     207             :      */
     208        1578 :     if (*str == '-')
     209             :     {
     210          48 :         dummy_lex.input = unconstify(char *, str) +1;
     211          48 :         dummy_lex.input_length = len - 1;
     212             :     }
     213             :     else
     214             :     {
     215        1530 :         dummy_lex.input = unconstify(char *, str);
     216        1530 :         dummy_lex.input_length = len;
     217             :     }
     218             : 
     219        1578 :     json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error, &total_len);
     220             : 
     221        1578 :     return (!numeric_error) && (total_len == dummy_lex.input_length);
     222             : }
     223             : 
     224             : /*
     225             :  * Input.
     226             :  */
     227             : Datum
     228        2772 : json_in(PG_FUNCTION_ARGS)
     229             : {
     230        2772 :     char       *json = PG_GETARG_CSTRING(0);
     231        2772 :     text       *result = cstring_to_text(json);
     232             :     JsonLexContext *lex;
     233             : 
     234             :     /* validate it */
     235        2772 :     lex = makeJsonLexContext(result, false);
     236        2772 :     pg_parse_json(lex, &nullSemAction);
     237             : 
     238             :     /* Internal representation is the same as text, for now */
     239        2656 :     PG_RETURN_TEXT_P(result);
     240             : }
     241             : 
     242             : /*
     243             :  * Output.
     244             :  */
     245             : Datum
     246        1262 : json_out(PG_FUNCTION_ARGS)
     247             : {
     248             :     /* we needn't detoast because text_to_cstring will handle that */
     249        1262 :     Datum       txt = PG_GETARG_DATUM(0);
     250             : 
     251        1262 :     PG_RETURN_CSTRING(TextDatumGetCString(txt));
     252             : }
     253             : 
     254             : /*
     255             :  * Binary send.
     256             :  */
     257             : Datum
     258           0 : json_send(PG_FUNCTION_ARGS)
     259             : {
     260           0 :     text       *t = PG_GETARG_TEXT_PP(0);
     261             :     StringInfoData buf;
     262             : 
     263           0 :     pq_begintypsend(&buf);
     264           0 :     pq_sendtext(&buf, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t));
     265           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     266             : }
     267             : 
     268             : /*
     269             :  * Binary receive.
     270             :  */
     271             : Datum
     272           0 : json_recv(PG_FUNCTION_ARGS)
     273             : {
     274           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     275             :     char       *str;
     276             :     int         nbytes;
     277             :     JsonLexContext *lex;
     278             : 
     279           0 :     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
     280             : 
     281             :     /* Validate it. */
     282           0 :     lex = makeJsonLexContextCstringLen(str, nbytes, false);
     283           0 :     pg_parse_json(lex, &nullSemAction);
     284             : 
     285           0 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(str, nbytes));
     286             : }
     287             : 
     288             : /*
     289             :  * makeJsonLexContext
     290             :  *
     291             :  * lex constructor, with or without StringInfo object
     292             :  * for de-escaped lexemes.
     293             :  *
     294             :  * Without is better as it makes the processing faster, so only make one
     295             :  * if really required.
     296             :  *
     297             :  * If you already have the json as a text* value, use the first of these
     298             :  * functions, otherwise use  makeJsonLexContextCstringLen().
     299             :  */
     300             : JsonLexContext *
     301        4788 : makeJsonLexContext(text *json, bool need_escapes)
     302             : {
     303       19152 :     return makeJsonLexContextCstringLen(VARDATA_ANY(json),
     304       14364 :                                         VARSIZE_ANY_EXHDR(json),
     305             :                                         need_escapes);
     306             : }
     307             : 
     308             : JsonLexContext *
     309       17278 : makeJsonLexContextCstringLen(char *json, int len, bool need_escapes)
     310             : {
     311       17278 :     JsonLexContext *lex = palloc0(sizeof(JsonLexContext));
     312             : 
     313       17278 :     lex->input = lex->token_terminator = lex->line_start = json;
     314       17278 :     lex->line_number = 1;
     315       17278 :     lex->input_length = len;
     316       17278 :     if (need_escapes)
     317       14190 :         lex->strval = makeStringInfo();
     318       17278 :     return lex;
     319             : }
     320             : 
     321             : /*
     322             :  * pg_parse_json
     323             :  *
     324             :  * Publicly visible entry point for the JSON parser.
     325             :  *
     326             :  * lex is a lexing context, set up for the json to be processed by calling
     327             :  * makeJsonLexContext(). sem is a structure of function pointers to semantic
     328             :  * action routines to be called at appropriate spots during parsing, and a
     329             :  * pointer to a state object to be passed to those routines.
     330             :  */
     331             : void
     332       17238 : pg_parse_json(JsonLexContext *lex, JsonSemAction *sem)
     333             : {
     334             :     JsonTokenType tok;
     335             : 
     336             :     /* get the initial token */
     337       17238 :     json_lex(lex);
     338             : 
     339       17130 :     tok = lex_peek(lex);
     340             : 
     341             :     /* parse by recursive descent */
     342       17130 :     switch (tok)
     343             :     {
     344             :         case JSON_TOKEN_OBJECT_START:
     345       11850 :             parse_object(lex, sem);
     346       11738 :             break;
     347             :         case JSON_TOKEN_ARRAY_START:
     348        2672 :             parse_array(lex, sem);
     349        2580 :             break;
     350             :         default:
     351        2608 :             parse_scalar(lex, sem); /* json can be a bare scalar */
     352             :     }
     353             : 
     354       16862 :     lex_expect(JSON_PARSE_END, lex, JSON_TOKEN_END);
     355             : 
     356       16846 : }
     357             : 
     358             : /*
     359             :  * json_count_array_elements
     360             :  *
     361             :  * Returns number of array elements in lex context at start of array token
     362             :  * until end of array token at same nesting level.
     363             :  *
     364             :  * Designed to be called from array_start routines.
     365             :  */
     366             : int
     367           4 : json_count_array_elements(JsonLexContext *lex)
     368             : {
     369             :     JsonLexContext copylex;
     370             :     int         count;
     371             : 
     372             :     /*
     373             :      * It's safe to do this with a shallow copy because the lexical routines
     374             :      * don't scribble on the input. They do scribble on the other pointers
     375             :      * etc, so doing this with a copy makes that safe.
     376             :      */
     377           4 :     memcpy(&copylex, lex, sizeof(JsonLexContext));
     378           4 :     copylex.strval = NULL;      /* not interested in values here */
     379           4 :     copylex.lex_level++;
     380             : 
     381           4 :     count = 0;
     382           4 :     lex_expect(JSON_PARSE_ARRAY_START, &copylex, JSON_TOKEN_ARRAY_START);
     383           4 :     if (lex_peek(&copylex) != JSON_TOKEN_ARRAY_END)
     384             :     {
     385             :         do
     386             :         {
     387          32 :             count++;
     388          32 :             parse_array_element(&copylex, &nullSemAction);
     389             :         }
     390          32 :         while (lex_accept(&copylex, JSON_TOKEN_COMMA, NULL));
     391             :     }
     392           4 :     lex_expect(JSON_PARSE_ARRAY_NEXT, &copylex, JSON_TOKEN_ARRAY_END);
     393             : 
     394           4 :     return count;
     395             : }
     396             : 
     397             : /*
     398             :  *  Recursive Descent parse routines. There is one for each structural
     399             :  *  element in a json document:
     400             :  *    - scalar (string, number, true, false, null)
     401             :  *    - array  ( [ ] )
     402             :  *    - array element
     403             :  *    - object ( { } )
     404             :  *    - object field
     405             :  */
     406             : static inline void
     407      115734 : parse_scalar(JsonLexContext *lex, JsonSemAction *sem)
     408             : {
     409      115734 :     char       *val = NULL;
     410      115734 :     json_scalar_action sfunc = sem->scalar;
     411             :     char      **valaddr;
     412      115734 :     JsonTokenType tok = lex_peek(lex);
     413             : 
     414      115734 :     valaddr = sfunc == NULL ? NULL : &val;
     415             : 
     416             :     /* a scalar must be a string, a number, true, false, or null */
     417      115734 :     switch (tok)
     418             :     {
     419             :         case JSON_TOKEN_TRUE:
     420        4642 :             lex_accept(lex, JSON_TOKEN_TRUE, valaddr);
     421        4642 :             break;
     422             :         case JSON_TOKEN_FALSE:
     423        6180 :             lex_accept(lex, JSON_TOKEN_FALSE, valaddr);
     424        6180 :             break;
     425             :         case JSON_TOKEN_NULL:
     426        2614 :             lex_accept(lex, JSON_TOKEN_NULL, valaddr);
     427        2614 :             break;
     428             :         case JSON_TOKEN_NUMBER:
     429       66782 :             lex_accept(lex, JSON_TOKEN_NUMBER, valaddr);
     430       66782 :             break;
     431             :         case JSON_TOKEN_STRING:
     432       35484 :             lex_accept(lex, JSON_TOKEN_STRING, valaddr);
     433       35484 :             break;
     434             :         default:
     435          32 :             report_parse_error(JSON_PARSE_VALUE, lex);
     436             :     }
     437             : 
     438      115702 :     if (sfunc != NULL)
     439      110762 :         (*sfunc) (sem->semstate, val, tok);
     440      115642 : }
     441             : 
     442             : static void
     443      115302 : parse_object_field(JsonLexContext *lex, JsonSemAction *sem)
     444             : {
     445             :     /*
     446             :      * An object field is "fieldname" : value where value can be a scalar,
     447             :      * object or array.  Note: in user-facing docs and error messages, we
     448             :      * generally call a field name a "key".
     449             :      */
     450             : 
     451      115302 :     char       *fname = NULL;   /* keep compiler quiet */
     452      115302 :     json_ofield_action ostart = sem->object_field_start;
     453      115302 :     json_ofield_action oend = sem->object_field_end;
     454             :     bool        isnull;
     455      115302 :     char      **fnameaddr = NULL;
     456             :     JsonTokenType tok;
     457             : 
     458      115302 :     if (ostart != NULL || oend != NULL)
     459       92518 :         fnameaddr = &fname;
     460             : 
     461      115302 :     if (!lex_accept(lex, JSON_TOKEN_STRING, fnameaddr))
     462           8 :         report_parse_error(JSON_PARSE_STRING, lex);
     463             : 
     464      115286 :     lex_expect(JSON_PARSE_OBJECT_LABEL, lex, JSON_TOKEN_COLON);
     465             : 
     466      115226 :     tok = lex_peek(lex);
     467      115226 :     isnull = tok == JSON_TOKEN_NULL;
     468             : 
     469      115226 :     if (ostart != NULL)
     470       92458 :         (*ostart) (sem->semstate, fname, isnull);
     471             : 
     472      115226 :     switch (tok)
     473             :     {
     474             :         case JSON_TOKEN_OBJECT_START:
     475        7490 :             parse_object(lex, sem);
     476        2246 :             break;
     477             :         case JSON_TOKEN_ARRAY_START:
     478        5238 :             parse_array(lex, sem);
     479        5238 :             break;
     480             :         default:
     481      102498 :             parse_scalar(lex, sem);
     482             :     }
     483             : 
     484      109974 :     if (oend != NULL)
     485       61492 :         (*oend) (sem->semstate, fname, isnull);
     486      109974 : }
     487             : 
     488             : static void
     489       26232 : parse_object(JsonLexContext *lex, JsonSemAction *sem)
     490             : {
     491             :     /*
     492             :      * an object is a possibly empty sequence of object fields, separated by
     493             :      * commas and surrounded by curly braces.
     494             :      */
     495       26232 :     json_struct_action ostart = sem->object_start;
     496       26232 :     json_struct_action oend = sem->object_end;
     497             :     JsonTokenType tok;
     498             : 
     499       26232 :     check_stack_depth();
     500             : 
     501       26224 :     if (ostart != NULL)
     502       15040 :         (*ostart) (sem->semstate);
     503             : 
     504             :     /*
     505             :      * Data inside an object is at a higher nesting level than the object
     506             :      * itself. Note that we increment this after we call the semantic routine
     507             :      * for the object start and restore it before we call the routine for the
     508             :      * object end.
     509             :      */
     510       26212 :     lex->lex_level++;
     511             : 
     512             :     /* we know this will succeed, just clearing the token */
     513       26212 :     lex_expect(JSON_PARSE_OBJECT_START, lex, JSON_TOKEN_OBJECT_START);
     514             : 
     515       26212 :     tok = lex_peek(lex);
     516       26212 :     switch (tok)
     517             :     {
     518             :         case JSON_TOKEN_STRING:
     519       23858 :             parse_object_field(lex, sem);
     520      128512 :             while (lex_accept(lex, JSON_TOKEN_COMMA, NULL))
     521       91444 :                 parse_object_field(lex, sem);
     522       18530 :             break;
     523             :         case JSON_TOKEN_OBJECT_END:
     524        2346 :             break;
     525             :         default:
     526             :             /* case of an invalid initial token inside the object */
     527           8 :             report_parse_error(JSON_PARSE_OBJECT_START, lex);
     528             :     }
     529             : 
     530       20876 :     lex_expect(JSON_PARSE_OBJECT_NEXT, lex, JSON_TOKEN_OBJECT_END);
     531             : 
     532       20868 :     lex->lex_level--;
     533             : 
     534       20868 :     if (oend != NULL)
     535       10784 :         (*oend) (sem->semstate);
     536       20860 : }
     537             : 
     538             : static void
     539       26412 : parse_array_element(JsonLexContext *lex, JsonSemAction *sem)
     540             : {
     541       26412 :     json_aelem_action astart = sem->array_element_start;
     542       26412 :     json_aelem_action aend = sem->array_element_end;
     543       26412 :     JsonTokenType tok = lex_peek(lex);
     544             : 
     545             :     bool        isnull;
     546             : 
     547       26412 :     isnull = tok == JSON_TOKEN_NULL;
     548             : 
     549       26412 :     if (astart != NULL)
     550        4956 :         (*astart) (sem->semstate, isnull);
     551             : 
     552             :     /* an array element is any object, array or scalar */
     553       26412 :     switch (tok)
     554             :     {
     555             :         case JSON_TOKEN_OBJECT_START:
     556        6892 :             parse_object(lex, sem);
     557        6876 :             break;
     558             :         case JSON_TOKEN_ARRAY_START:
     559        8892 :             parse_array(lex, sem);
     560        2136 :             break;
     561             :         default:
     562       10628 :             parse_scalar(lex, sem);
     563             :     }
     564             : 
     565       19620 :     if (aend != NULL)
     566        4620 :         (*aend) (sem->semstate, isnull);
     567       19612 : }
     568             : 
     569             : static void
     570       16802 : parse_array(JsonLexContext *lex, JsonSemAction *sem)
     571             : {
     572             :     /*
     573             :      * an array is a possibly empty sequence of array elements, separated by
     574             :      * commas and surrounded by square brackets.
     575             :      */
     576       16802 :     json_struct_action astart = sem->array_start;
     577       16802 :     json_struct_action aend = sem->array_end;
     578             : 
     579       16802 :     check_stack_depth();
     580             : 
     581       16794 :     if (astart != NULL)
     582        8338 :         (*astart) (sem->semstate);
     583             : 
     584             :     /*
     585             :      * Data inside an array is at a higher nesting level than the array
     586             :      * itself. Note that we increment this after we call the semantic routine
     587             :      * for the array start and restore it before we call the routine for the
     588             :      * array end.
     589             :      */
     590       16786 :     lex->lex_level++;
     591             : 
     592       16786 :     lex_expect(JSON_PARSE_ARRAY_START, lex, JSON_TOKEN_ARRAY_START);
     593       16786 :     if (lex_peek(lex) != JSON_TOKEN_ARRAY_END)
     594             :     {
     595             : 
     596       16310 :         parse_array_element(lex, sem);
     597             : 
     598       29134 :         while (lex_accept(lex, JSON_TOKEN_COMMA, NULL))
     599       10070 :             parse_array_element(lex, sem);
     600             :     }
     601             : 
     602        9986 :     lex_expect(JSON_PARSE_ARRAY_NEXT, lex, JSON_TOKEN_ARRAY_END);
     603             : 
     604        9970 :     lex->lex_level--;
     605             : 
     606        9970 :     if (aend != NULL)
     607        4106 :         (*aend) (sem->semstate);
     608        9954 : }
     609             : 
     610             : /*
     611             :  * Lex one token from the input stream.
     612             :  */
     613             : static inline void
     614      555776 : json_lex(JsonLexContext *lex)
     615             : {
     616             :     char       *s;
     617             :     int         len;
     618             : 
     619             :     /* Skip leading whitespace. */
     620      555776 :     s = lex->token_terminator;
     621      555776 :     len = s - lex->input;
     622     5121456 :     while (len < lex->input_length &&
     623     2874156 :            (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
     624             :     {
     625     1743952 :         if (*s == '\n')
     626       85568 :             ++lex->line_number;
     627     1743952 :         ++s;
     628     1743952 :         ++len;
     629             :     }
     630      555776 :     lex->token_start = s;
     631             : 
     632             :     /* Determine token type. */
     633      555776 :     if (len >= lex->input_length)
     634             :     {
     635       33776 :         lex->token_start = NULL;
     636       33776 :         lex->prev_token_terminator = lex->token_terminator;
     637       33776 :         lex->token_terminator = s;
     638       33776 :         lex->token_type = JSON_TOKEN_END;
     639             :     }
     640             :     else
     641      522000 :         switch (*s)
     642             :         {
     643             :                 /* Single-character token, some kind of punctuation mark. */
     644             :             case '{':
     645       26240 :                 lex->prev_token_terminator = lex->token_terminator;
     646       26240 :                 lex->token_terminator = s + 1;
     647       26240 :                 lex->token_type = JSON_TOKEN_OBJECT_START;
     648       26240 :                 break;
     649             :             case '}':
     650       20876 :                 lex->prev_token_terminator = lex->token_terminator;
     651       20876 :                 lex->token_terminator = s + 1;
     652       20876 :                 lex->token_type = JSON_TOKEN_OBJECT_END;
     653       20876 :                 break;
     654             :             case '[':
     655       16810 :                 lex->prev_token_terminator = lex->token_terminator;
     656       16810 :                 lex->token_terminator = s + 1;
     657       16810 :                 lex->token_type = JSON_TOKEN_ARRAY_START;
     658       16810 :                 break;
     659             :             case ']':
     660       10014 :                 lex->prev_token_terminator = lex->token_terminator;
     661       10014 :                 lex->token_terminator = s + 1;
     662       10014 :                 lex->token_type = JSON_TOKEN_ARRAY_END;
     663       10014 :                 break;
     664             :             case ',':
     665      101570 :                 lex->prev_token_terminator = lex->token_terminator;
     666      101570 :                 lex->token_terminator = s + 1;
     667      101570 :                 lex->token_type = JSON_TOKEN_COMMA;
     668      101570 :                 break;
     669             :             case ':':
     670      115286 :                 lex->prev_token_terminator = lex->token_terminator;
     671      115286 :                 lex->token_terminator = s + 1;
     672      115286 :                 lex->token_type = JSON_TOKEN_COLON;
     673      115286 :                 break;
     674             :             case '"':
     675             :                 /* string */
     676      150878 :                 json_lex_string(lex);
     677      150782 :                 lex->token_type = JSON_TOKEN_STRING;
     678      150782 :                 break;
     679             :             case '-':
     680             :                 /* Negative number. */
     681         122 :                 json_lex_number(lex, s + 1, NULL, NULL);
     682         122 :                 lex->token_type = JSON_TOKEN_NUMBER;
     683         122 :                 break;
     684             :             case '0':
     685             :             case '1':
     686             :             case '2':
     687             :             case '3':
     688             :             case '4':
     689             :             case '5':
     690             :             case '6':
     691             :             case '7':
     692             :             case '8':
     693             :             case '9':
     694             :                 /* Positive number. */
     695       66716 :                 json_lex_number(lex, s, NULL, NULL);
     696       66684 :                 lex->token_type = JSON_TOKEN_NUMBER;
     697       66684 :                 break;
     698             :             default:
     699             :                 {
     700             :                     char       *p;
     701             : 
     702             :                     /*
     703             :                      * We're not dealing with a string, number, legal
     704             :                      * punctuation mark, or end of string.  The only legal
     705             :                      * tokens we might find here are true, false, and null,
     706             :                      * but for error reporting purposes we scan until we see a
     707             :                      * non-alphanumeric character.  That way, we can report
     708             :                      * the whole word as an unexpected token, rather than just
     709             :                      * some unintuitive prefix thereof.
     710             :                      */
     711       13488 :                     for (p = s; p - s < lex->input_length - len && JSON_ALPHANUMERIC_CHAR(*p); p++)
     712             :                          /* skip */ ;
     713             : 
     714             :                     /*
     715             :                      * We got some sort of unexpected punctuation or an
     716             :                      * otherwise unexpected character, so just complain about
     717             :                      * that one character.
     718             :                      */
     719       13488 :                     if (p == s)
     720             :                     {
     721          16 :                         lex->prev_token_terminator = lex->token_terminator;
     722          16 :                         lex->token_terminator = s + 1;
     723          16 :                         report_invalid_token(lex);
     724             :                     }
     725             : 
     726             :                     /*
     727             :                      * We've got a real alphanumeric token here.  If it
     728             :                      * happens to be true, false, or null, all is well.  If
     729             :                      * not, error out.
     730             :                      */
     731       13472 :                     lex->prev_token_terminator = lex->token_terminator;
     732       13472 :                     lex->token_terminator = p;
     733       13472 :                     if (p - s == 4)
     734             :                     {
     735        7272 :                         if (memcmp(s, "true", 4) == 0)
     736        4646 :                             lex->token_type = JSON_TOKEN_TRUE;
     737        2626 :                         else if (memcmp(s, "null", 4) == 0)
     738        2618 :                             lex->token_type = JSON_TOKEN_NULL;
     739             :                         else
     740           8 :                             report_invalid_token(lex);
     741             :                     }
     742        6200 :                     else if (p - s == 5 && memcmp(s, "false", 5) == 0)
     743        6192 :                         lex->token_type = JSON_TOKEN_FALSE;
     744             :                     else
     745           8 :                         report_invalid_token(lex);
     746             : 
     747             :                 }
     748             :         }                       /* end of switch */
     749      555616 : }
     750             : 
     751             : /*
     752             :  * The next token in the input stream is known to be a string; lex it.
     753             :  */
     754             : static inline void
     755      150878 : json_lex_string(JsonLexContext *lex)
     756             : {
     757             :     char       *s;
     758             :     int         len;
     759      150878 :     int         hi_surrogate = -1;
     760             : 
     761      150878 :     if (lex->strval != NULL)
     762      123534 :         resetStringInfo(lex->strval);
     763             : 
     764             :     Assert(lex->input_length > 0);
     765      150878 :     s = lex->token_start;
     766      150878 :     len = lex->token_start - lex->input;
     767             :     for (;;)
     768             :     {
     769     2568906 :         s++;
     770     1359892 :         len++;
     771             :         /* Premature end of the string. */
     772     1359892 :         if (len >= lex->input_length)
     773             :         {
     774           8 :             lex->token_terminator = s;
     775           8 :             report_invalid_token(lex);
     776             :         }
     777     1359884 :         else if (*s == '"')
     778      150782 :             break;
     779     1209102 :         else if ((unsigned char) *s < 32)
     780             :         {
     781             :             /* Per RFC4627, these characters MUST be escaped. */
     782             :             /* Since *s isn't printable, exclude it from the context string */
     783           8 :             lex->token_terminator = s;
     784           8 :             ereport(ERROR,
     785             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     786             :                      errmsg("invalid input syntax for type %s", "json"),
     787             :                      errdetail("Character with value 0x%02x must be escaped.",
     788             :                                (unsigned char) *s),
     789             :                      report_json_context(lex)));
     790             :         }
     791     1209094 :         else if (*s == '\\')
     792             :         {
     793             :             /* OK, we have an escape character. */
     794         400 :             s++;
     795         400 :             len++;
     796         400 :             if (len >= lex->input_length)
     797             :             {
     798           0 :                 lex->token_terminator = s;
     799           0 :                 report_invalid_token(lex);
     800             :             }
     801         400 :             else if (*s == 'u')
     802             :             {
     803             :                 int         i;
     804         216 :                 int         ch = 0;
     805             : 
     806        1024 :                 for (i = 1; i <= 4; i++)
     807             :                 {
     808         832 :                     s++;
     809         832 :                     len++;
     810         832 :                     if (len >= lex->input_length)
     811             :                     {
     812           0 :                         lex->token_terminator = s;
     813           0 :                         report_invalid_token(lex);
     814             :                     }
     815         832 :                     else if (*s >= '0' && *s <= '9')
     816         532 :                         ch = (ch * 16) + (*s - '0');
     817         300 :                     else if (*s >= 'a' && *s <= 'f')
     818         260 :                         ch = (ch * 16) + (*s - 'a') + 10;
     819          40 :                     else if (*s >= 'A' && *s <= 'F')
     820          16 :                         ch = (ch * 16) + (*s - 'A') + 10;
     821             :                     else
     822             :                     {
     823          24 :                         lex->token_terminator = s + pg_mblen(s);
     824          24 :                         ereport(ERROR,
     825             :                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     826             :                                  errmsg("invalid input syntax for type %s",
     827             :                                         "json"),
     828             :                                  errdetail("\"\\u\" must be followed by four hexadecimal digits."),
     829             :                                  report_json_context(lex)));
     830             :                     }
     831             :                 }
     832         192 :                 if (lex->strval != NULL)
     833             :                 {
     834             :                     char        utf8str[5];
     835             :                     int         utf8len;
     836             : 
     837         120 :                     if (ch >= 0xd800 && ch <= 0xdbff)
     838             :                     {
     839          40 :                         if (hi_surrogate != -1)
     840           8 :                             ereport(ERROR,
     841             :                                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     842             :                                      errmsg("invalid input syntax for type %s",
     843             :                                             "json"),
     844             :                                      errdetail("Unicode high surrogate must not follow a high surrogate."),
     845             :                                      report_json_context(lex)));
     846          32 :                         hi_surrogate = (ch & 0x3ff) << 10;
     847          32 :                         continue;
     848             :                     }
     849          80 :                     else if (ch >= 0xdc00 && ch <= 0xdfff)
     850             :                     {
     851          32 :                         if (hi_surrogate == -1)
     852          16 :                             ereport(ERROR,
     853             :                                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     854             :                                      errmsg("invalid input syntax for type %s", "json"),
     855             :                                      errdetail("Unicode low surrogate must follow a high surrogate."),
     856             :                                      report_json_context(lex)));
     857          16 :                         ch = 0x10000 + hi_surrogate + (ch & 0x3ff);
     858          16 :                         hi_surrogate = -1;
     859             :                     }
     860             : 
     861          64 :                     if (hi_surrogate != -1)
     862           0 :                         ereport(ERROR,
     863             :                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     864             :                                  errmsg("invalid input syntax for type %s", "json"),
     865             :                                  errdetail("Unicode low surrogate must follow a high surrogate."),
     866             :                                  report_json_context(lex)));
     867             : 
     868             :                     /*
     869             :                      * For UTF8, replace the escape sequence by the actual
     870             :                      * utf8 character in lex->strval. Do this also for other
     871             :                      * encodings if the escape designates an ASCII character,
     872             :                      * otherwise raise an error.
     873             :                      */
     874             : 
     875          64 :                     if (ch == 0)
     876             :                     {
     877             :                         /* We can't allow this, since our TEXT type doesn't */
     878          16 :                         ereport(ERROR,
     879             :                                 (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
     880             :                                  errmsg("unsupported Unicode escape sequence"),
     881             :                                  errdetail("\\u0000 cannot be converted to text."),
     882             :                                  report_json_context(lex)));
     883             :                     }
     884          48 :                     else if (GetDatabaseEncoding() == PG_UTF8)
     885             :                     {
     886          48 :                         unicode_to_utf8(ch, (unsigned char *) utf8str);
     887          48 :                         utf8len = pg_utf_mblen((unsigned char *) utf8str);
     888          48 :                         appendBinaryStringInfo(lex->strval, utf8str, utf8len);
     889             :                     }
     890           0 :                     else if (ch <= 0x007f)
     891             :                     {
     892             :                         /*
     893             :                          * This is the only way to designate things like a
     894             :                          * form feed character in JSON, so it's useful in all
     895             :                          * encodings.
     896             :                          */
     897           0 :                         appendStringInfoChar(lex->strval, (char) ch);
     898             :                     }
     899             :                     else
     900             :                     {
     901           0 :                         ereport(ERROR,
     902             :                                 (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
     903             :                                  errmsg("unsupported Unicode escape sequence"),
     904             :                                  errdetail("Unicode escape values cannot be used for code point values above 007F when the server encoding is not UTF8."),
     905             :                                  report_json_context(lex)));
     906             :                     }
     907             : 
     908             :                 }
     909             :             }
     910         184 :             else if (lex->strval != NULL)
     911             :             {
     912         112 :                 if (hi_surrogate != -1)
     913           0 :                     ereport(ERROR,
     914             :                             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     915             :                              errmsg("invalid input syntax for type %s",
     916             :                                     "json"),
     917             :                              errdetail("Unicode low surrogate must follow a high surrogate."),
     918             :                              report_json_context(lex)));
     919             : 
     920         112 :                 switch (*s)
     921             :                 {
     922             :                     case '"':
     923             :                     case '\\':
     924             :                     case '/':
     925          88 :                         appendStringInfoChar(lex->strval, *s);
     926          88 :                         break;
     927             :                     case 'b':
     928           0 :                         appendStringInfoChar(lex->strval, '\b');
     929           0 :                         break;
     930             :                     case 'f':
     931           0 :                         appendStringInfoChar(lex->strval, '\f');
     932           0 :                         break;
     933             :                     case 'n':
     934          20 :                         appendStringInfoChar(lex->strval, '\n');
     935          20 :                         break;
     936             :                     case 'r':
     937           0 :                         appendStringInfoChar(lex->strval, '\r');
     938           0 :                         break;
     939             :                     case 't':
     940           0 :                         appendStringInfoChar(lex->strval, '\t');
     941           0 :                         break;
     942             :                     default:
     943             :                         /* Not a valid string escape, so error out. */
     944           4 :                         lex->token_terminator = s + pg_mblen(s);
     945           4 :                         ereport(ERROR,
     946             :                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     947             :                                  errmsg("invalid input syntax for type %s",
     948             :                                         "json"),
     949             :                                  errdetail("Escape sequence \"\\%s\" is invalid.",
     950             :                                            extract_mb_char(s)),
     951             :                                  report_json_context(lex)));
     952             :                 }
     953             :             }
     954          72 :             else if (strchr("\"\\/bfnrt", *s) == NULL)
     955             :             {
     956             :                 /*
     957             :                  * Simpler processing if we're not bothered about de-escaping
     958             :                  *
     959             :                  * It's very tempting to remove the strchr() call here and
     960             :                  * replace it with a switch statement, but testing so far has
     961             :                  * shown it's not a performance win.
     962             :                  */
     963           4 :                 lex->token_terminator = s + pg_mblen(s);
     964           4 :                 ereport(ERROR,
     965             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     966             :                          errmsg("invalid input syntax for type %s", "json"),
     967             :                          errdetail("Escape sequence \"\\%s\" is invalid.",
     968             :                                    extract_mb_char(s)),
     969             :                          report_json_context(lex)));
     970             :             }
     971             : 
     972             :         }
     973     1208694 :         else if (lex->strval != NULL)
     974             :         {
     975      965634 :             if (hi_surrogate != -1)
     976           8 :                 ereport(ERROR,
     977             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     978             :                          errmsg("invalid input syntax for type %s", "json"),
     979             :                          errdetail("Unicode low surrogate must follow a high surrogate."),
     980             :                          report_json_context(lex)));
     981             : 
     982      965626 :             appendStringInfoChar(lex->strval, *s);
     983             :         }
     984             : 
     985             :     }
     986             : 
     987      150782 :     if (hi_surrogate != -1)
     988           0 :         ereport(ERROR,
     989             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     990             :                  errmsg("invalid input syntax for type %s", "json"),
     991             :                  errdetail("Unicode low surrogate must follow a high surrogate."),
     992             :                  report_json_context(lex)));
     993             : 
     994             :     /* Hooray, we found the end of the string! */
     995      150782 :     lex->prev_token_terminator = lex->token_terminator;
     996      150782 :     lex->token_terminator = s + 1;
     997      150782 : }
     998             : 
     999             : /*
    1000             :  * The next token in the input stream is known to be a number; lex it.
    1001             :  *
    1002             :  * In JSON, a number consists of four parts:
    1003             :  *
    1004             :  * (1) An optional minus sign ('-').
    1005             :  *
    1006             :  * (2) Either a single '0', or a string of one or more digits that does not
    1007             :  *     begin with a '0'.
    1008             :  *
    1009             :  * (3) An optional decimal part, consisting of a period ('.') followed by
    1010             :  *     one or more digits.  (Note: While this part can be omitted
    1011             :  *     completely, it's not OK to have only the decimal point without
    1012             :  *     any digits afterwards.)
    1013             :  *
    1014             :  * (4) An optional exponent part, consisting of 'e' or 'E', optionally
    1015             :  *     followed by '+' or '-', followed by one or more digits.  (Note:
    1016             :  *     As with the decimal part, if 'e' or 'E' is present, it must be
    1017             :  *     followed by at least one digit.)
    1018             :  *
    1019             :  * The 's' argument to this function points to the ostensible beginning
    1020             :  * of part 2 - i.e. the character after any optional minus sign, or the
    1021             :  * first character of the string if there is none.
    1022             :  *
    1023             :  * If num_err is not NULL, we return an error flag to *num_err rather than
    1024             :  * raising an error for a badly-formed number.  Also, if total_len is not NULL
    1025             :  * the distance from lex->input to the token end+1 is returned to *total_len.
    1026             :  */
    1027             : static inline void
    1028       68416 : json_lex_number(JsonLexContext *lex, char *s,
    1029             :                 bool *num_err, int *total_len)
    1030             : {
    1031       68416 :     bool        error = false;
    1032       68416 :     int         len = s - lex->input;
    1033             : 
    1034             :     /* Part (1): leading sign indicator. */
    1035             :     /* Caller already did this for us; so do nothing. */
    1036             : 
    1037             :     /* Part (2): parse main digit string. */
    1038       68416 :     if (len < lex->input_length && *s == '0')
    1039             :     {
    1040        5282 :         s++;
    1041        5282 :         len++;
    1042             :     }
    1043      126254 :     else if (len < lex->input_length && *s >= '1' && *s <= '9')
    1044             :     {
    1045             :         do
    1046             :         {
    1047      145842 :             s++;
    1048      145842 :             len++;
    1049      145842 :         } while (len < lex->input_length && *s >= '0' && *s <= '9');
    1050             :     }
    1051             :     else
    1052          14 :         error = true;
    1053             : 
    1054             :     /* Part (3): parse optional decimal portion. */
    1055       68416 :     if (len < lex->input_length && *s == '.')
    1056             :     {
    1057       21744 :         s++;
    1058       21744 :         len++;
    1059       21744 :         if (len == lex->input_length || *s < '0' || *s > '9')
    1060           8 :             error = true;
    1061             :         else
    1062             :         {
    1063             :             do
    1064             :             {
    1065       53312 :                 s++;
    1066       53312 :                 len++;
    1067       53312 :             } while (len < lex->input_length && *s >= '0' && *s <= '9');
    1068             :         }
    1069             :     }
    1070             : 
    1071             :     /* Part (4): parse optional exponent. */
    1072       68416 :     if (len < lex->input_length && (*s == 'e' || *s == 'E'))
    1073             :     {
    1074          38 :         s++;
    1075          38 :         len++;
    1076          38 :         if (len < lex->input_length && (*s == '+' || *s == '-'))
    1077             :         {
    1078          10 :             s++;
    1079          10 :             len++;
    1080             :         }
    1081          38 :         if (len == lex->input_length || *s < '0' || *s > '9')
    1082           8 :             error = true;
    1083             :         else
    1084             :         {
    1085             :             do
    1086             :             {
    1087          72 :                 s++;
    1088          72 :                 len++;
    1089          72 :             } while (len < lex->input_length && *s >= '0' && *s <= '9');
    1090             :         }
    1091             :     }
    1092             : 
    1093             :     /*
    1094             :      * Check for trailing garbage.  As in json_lex(), any alphanumeric stuff
    1095             :      * here should be considered part of the token for error-reporting
    1096             :      * purposes.
    1097             :      */
    1098       68612 :     for (; len < lex->input_length && JSON_ALPHANUMERIC_CHAR(*s); s++, len++)
    1099         196 :         error = true;
    1100             : 
    1101       68416 :     if (total_len != NULL)
    1102        1578 :         *total_len = len;
    1103             : 
    1104       68416 :     if (num_err != NULL)
    1105             :     {
    1106             :         /* let the caller handle any error */
    1107        1578 :         *num_err = error;
    1108             :     }
    1109             :     else
    1110             :     {
    1111             :         /* return token endpoint */
    1112       66838 :         lex->prev_token_terminator = lex->token_terminator;
    1113       66838 :         lex->token_terminator = s;
    1114             :         /* handle error if any */
    1115       66838 :         if (error)
    1116          32 :             report_invalid_token(lex);
    1117             :     }
    1118       68384 : }
    1119             : 
    1120             : /*
    1121             :  * Report a parse error.
    1122             :  *
    1123             :  * lex->token_start and lex->token_terminator must identify the current token.
    1124             :  */
    1125             : static void
    1126         104 : report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
    1127             : {
    1128             :     char       *token;
    1129             :     int         toklen;
    1130             : 
    1131             :     /* Handle case where the input ended prematurely. */
    1132         104 :     if (lex->token_start == NULL || lex->token_type == JSON_TOKEN_END)
    1133          32 :         ereport(ERROR,
    1134             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1135             :                  errmsg("invalid input syntax for type %s", "json"),
    1136             :                  errdetail("The input string ended unexpectedly."),
    1137             :                  report_json_context(lex)));
    1138             : 
    1139             :     /* Separate out the current token. */
    1140          72 :     toklen = lex->token_terminator - lex->token_start;
    1141          72 :     token = palloc(toklen + 1);
    1142          72 :     memcpy(token, lex->token_start, toklen);
    1143          72 :     token[toklen] = '\0';
    1144             : 
    1145             :     /* Complain, with the appropriate detail message. */
    1146          72 :     if (ctx == JSON_PARSE_END)
    1147          16 :         ereport(ERROR,
    1148             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1149             :                  errmsg("invalid input syntax for type %s", "json"),
    1150             :                  errdetail("Expected end of input, but found \"%s\".",
    1151             :                            token),
    1152             :                  report_json_context(lex)));
    1153             :     else
    1154             :     {
    1155          56 :         switch (ctx)
    1156             :         {
    1157             :             case JSON_PARSE_VALUE:
    1158          16 :                 ereport(ERROR,
    1159             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1160             :                          errmsg("invalid input syntax for type %s", "json"),
    1161             :                          errdetail("Expected JSON value, but found \"%s\".",
    1162             :                                    token),
    1163             :                          report_json_context(lex)));
    1164             :                 break;
    1165             :             case JSON_PARSE_STRING:
    1166           8 :                 ereport(ERROR,
    1167             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1168             :                          errmsg("invalid input syntax for type %s", "json"),
    1169             :                          errdetail("Expected string, but found \"%s\".",
    1170             :                                    token),
    1171             :                          report_json_context(lex)));
    1172             :                 break;
    1173             :             case JSON_PARSE_ARRAY_START:
    1174           0 :                 ereport(ERROR,
    1175             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1176             :                          errmsg("invalid input syntax for type %s", "json"),
    1177             :                          errdetail("Expected array element or \"]\", but found \"%s\".",
    1178             :                                    token),
    1179             :                          report_json_context(lex)));
    1180             :                 break;
    1181             :             case JSON_PARSE_ARRAY_NEXT:
    1182           0 :                 ereport(ERROR,
    1183             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1184             :                          errmsg("invalid input syntax for type %s", "json"),
    1185             :                          errdetail("Expected \",\" or \"]\", but found \"%s\".",
    1186             :                                    token),
    1187             :                          report_json_context(lex)));
    1188             :                 break;
    1189             :             case JSON_PARSE_OBJECT_START:
    1190           8 :                 ereport(ERROR,
    1191             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1192             :                          errmsg("invalid input syntax for type %s", "json"),
    1193             :                          errdetail("Expected string or \"}\", but found \"%s\".",
    1194             :                                    token),
    1195             :                          report_json_context(lex)));
    1196             :                 break;
    1197             :             case JSON_PARSE_OBJECT_LABEL:
    1198          16 :                 ereport(ERROR,
    1199             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1200             :                          errmsg("invalid input syntax for type %s", "json"),
    1201             :                          errdetail("Expected \":\", but found \"%s\".",
    1202             :                                    token),
    1203             :                          report_json_context(lex)));
    1204             :                 break;
    1205             :             case JSON_PARSE_OBJECT_NEXT:
    1206           8 :                 ereport(ERROR,
    1207             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1208             :                          errmsg("invalid input syntax for type %s", "json"),
    1209             :                          errdetail("Expected \",\" or \"}\", but found \"%s\".",
    1210             :                                    token),
    1211             :                          report_json_context(lex)));
    1212             :                 break;
    1213             :             case JSON_PARSE_OBJECT_COMMA:
    1214           0 :                 ereport(ERROR,
    1215             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1216             :                          errmsg("invalid input syntax for type %s", "json"),
    1217             :                          errdetail("Expected string, but found \"%s\".",
    1218             :                                    token),
    1219             :                          report_json_context(lex)));
    1220             :                 break;
    1221             :             default:
    1222           0 :                 elog(ERROR, "unexpected json parse state: %d", ctx);
    1223             :         }
    1224             :     }
    1225             : }
    1226             : 
    1227             : /*
    1228             :  * Report an invalid input token.
    1229             :  *
    1230             :  * lex->token_start and lex->token_terminator must identify the token.
    1231             :  */
    1232             : static void
    1233          72 : report_invalid_token(JsonLexContext *lex)
    1234             : {
    1235             :     char       *token;
    1236             :     int         toklen;
    1237             : 
    1238             :     /* Separate out the offending token. */
    1239          72 :     toklen = lex->token_terminator - lex->token_start;
    1240          72 :     token = palloc(toklen + 1);
    1241          72 :     memcpy(token, lex->token_start, toklen);
    1242          72 :     token[toklen] = '\0';
    1243             : 
    1244          72 :     ereport(ERROR,
    1245             :             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1246             :              errmsg("invalid input syntax for type %s", "json"),
    1247             :              errdetail("Token \"%s\" is invalid.", token),
    1248             :              report_json_context(lex)));
    1249             : }
    1250             : 
    1251             : /*
    1252             :  * Report a CONTEXT line for bogus JSON input.
    1253             :  *
    1254             :  * lex->token_terminator must be set to identify the spot where we detected
    1255             :  * the error.  Note that lex->token_start might be NULL, in case we recognized
    1256             :  * error at EOF.
    1257             :  *
    1258             :  * The return value isn't meaningful, but we make it non-void so that this
    1259             :  * can be invoked inside ereport().
    1260             :  */
    1261             : static int
    1262         264 : report_json_context(JsonLexContext *lex)
    1263             : {
    1264             :     const char *context_start;
    1265             :     const char *context_end;
    1266             :     const char *line_start;
    1267             :     int         line_number;
    1268             :     char       *ctxt;
    1269             :     int         ctxtlen;
    1270             :     const char *prefix;
    1271             :     const char *suffix;
    1272             : 
    1273             :     /* Choose boundaries for the part of the input we will display */
    1274         264 :     context_start = lex->input;
    1275         264 :     context_end = lex->token_terminator;
    1276         264 :     line_start = context_start;
    1277         264 :     line_number = 1;
    1278             :     for (;;)
    1279             :     {
    1280             :         /* Always advance over newlines */
    1281         264 :         if (context_start < context_end && *context_start == '\n')
    1282             :         {
    1283           0 :             context_start++;
    1284           0 :             line_start = context_start;
    1285           0 :             line_number++;
    1286           0 :             continue;
    1287             :         }
    1288             :         /* Otherwise, done as soon as we are close enough to context_end */
    1289         264 :         if (context_end - context_start < 50)
    1290         264 :             break;
    1291             :         /* Advance to next multibyte character */
    1292           0 :         if (IS_HIGHBIT_SET(*context_start))
    1293           0 :             context_start += pg_mblen(context_start);
    1294             :         else
    1295           0 :             context_start++;
    1296             :     }
    1297             : 
    1298             :     /*
    1299             :      * We add "..." to indicate that the excerpt doesn't start at the
    1300             :      * beginning of the line ... but if we're within 3 characters of the
    1301             :      * beginning of the line, we might as well just show the whole line.
    1302             :      */
    1303         264 :     if (context_start - line_start <= 3)
    1304         264 :         context_start = line_start;
    1305             : 
    1306             :     /* Get a null-terminated copy of the data to present */
    1307         264 :     ctxtlen = context_end - context_start;
    1308         264 :     ctxt = palloc(ctxtlen + 1);
    1309         264 :     memcpy(ctxt, context_start, ctxtlen);
    1310         264 :     ctxt[ctxtlen] = '\0';
    1311             : 
    1312             :     /*
    1313             :      * Show the context, prefixing "..." if not starting at start of line, and
    1314             :      * suffixing "..." if not ending at end of line.
    1315             :      */
    1316         264 :     prefix = (context_start > line_start) ? "..." : "";
    1317         264 :     suffix = (lex->token_type != JSON_TOKEN_END && context_end - lex->input < lex->input_length && *context_end != '\n' && *context_end != '\r') ? "..." : "";
    1318             : 
    1319         264 :     return errcontext("JSON data, line %d: %s%s%s",
    1320             :                       line_number, prefix, ctxt, suffix);
    1321             : }
    1322             : 
    1323             : /*
    1324             :  * Extract a single, possibly multi-byte char from the input string.
    1325             :  */
    1326             : static char *
    1327           8 : extract_mb_char(char *s)
    1328             : {
    1329             :     char       *res;
    1330             :     int         len;
    1331             : 
    1332           8 :     len = pg_mblen(s);
    1333           8 :     res = palloc(len + 1);
    1334           8 :     memcpy(res, s, len);
    1335           8 :     res[len] = '\0';
    1336             : 
    1337           8 :     return res;
    1338             : }
    1339             : 
    1340             : /*
    1341             :  * Determine how we want to print values of a given type in datum_to_json.
    1342             :  *
    1343             :  * Given the datatype OID, return its JsonTypeCategory, as well as the type's
    1344             :  * output function OID.  If the returned category is JSONTYPE_CAST, we
    1345             :  * return the OID of the type->JSON cast function instead.
    1346             :  */
    1347             : static void
    1348        2032 : json_categorize_type(Oid typoid,
    1349             :                      JsonTypeCategory *tcategory,
    1350             :                      Oid *outfuncoid)
    1351             : {
    1352             :     bool        typisvarlena;
    1353             : 
    1354             :     /* Look through any domain */
    1355        2032 :     typoid = getBaseType(typoid);
    1356             : 
    1357        2032 :     *outfuncoid = InvalidOid;
    1358             : 
    1359             :     /*
    1360             :      * We need to get the output function for everything except date and
    1361             :      * timestamp types, array and composite types, booleans, and non-builtin
    1362             :      * types where there's a cast to json.
    1363             :      */
    1364             : 
    1365        2032 :     switch (typoid)
    1366             :     {
    1367             :         case BOOLOID:
    1368          12 :             *tcategory = JSONTYPE_BOOL;
    1369          12 :             break;
    1370             : 
    1371             :         case INT2OID:
    1372             :         case INT4OID:
    1373             :         case INT8OID:
    1374             :         case FLOAT4OID:
    1375             :         case FLOAT8OID:
    1376             :         case NUMERICOID:
    1377        1244 :             getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
    1378        1244 :             *tcategory = JSONTYPE_NUMERIC;
    1379        1244 :             break;
    1380             : 
    1381             :         case DATEOID:
    1382          12 :             *tcategory = JSONTYPE_DATE;
    1383          12 :             break;
    1384             : 
    1385             :         case TIMESTAMPOID:
    1386          12 :             *tcategory = JSONTYPE_TIMESTAMP;
    1387          12 :             break;
    1388             : 
    1389             :         case TIMESTAMPTZOID:
    1390          16 :             *tcategory = JSONTYPE_TIMESTAMPTZ;
    1391          16 :             break;
    1392             : 
    1393             :         case JSONOID:
    1394             :         case JSONBOID:
    1395          44 :             getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
    1396          44 :             *tcategory = JSONTYPE_JSON;
    1397          44 :             break;
    1398             : 
    1399             :         default:
    1400             :             /* Check for arrays and composites */
    1401         692 :             if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
    1402         480 :                 || typoid == RECORDARRAYOID)
    1403         212 :                 *tcategory = JSONTYPE_ARRAY;
    1404         480 :             else if (type_is_rowtype(typoid))   /* includes RECORDOID */
    1405         136 :                 *tcategory = JSONTYPE_COMPOSITE;
    1406             :             else
    1407             :             {
    1408             :                 /* It's probably the general case ... */
    1409         344 :                 *tcategory = JSONTYPE_OTHER;
    1410             :                 /* but let's look for a cast to json, if it's not built-in */
    1411         344 :                 if (typoid >= FirstNormalObjectId)
    1412             :                 {
    1413             :                     Oid         castfunc;
    1414             :                     CoercionPathType ctype;
    1415             : 
    1416           4 :                     ctype = find_coercion_pathway(JSONOID, typoid,
    1417             :                                                   COERCION_EXPLICIT,
    1418             :                                                   &castfunc);
    1419           4 :                     if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
    1420             :                     {
    1421           4 :                         *tcategory = JSONTYPE_CAST;
    1422           4 :                         *outfuncoid = castfunc;
    1423             :                     }
    1424             :                     else
    1425             :                     {
    1426             :                         /* non builtin type with no cast */
    1427           0 :                         getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
    1428             :                     }
    1429             :                 }
    1430             :                 else
    1431             :                 {
    1432             :                     /* any other builtin type */
    1433         340 :                     getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
    1434             :                 }
    1435             :             }
    1436         692 :             break;
    1437             :     }
    1438        2032 : }
    1439             : 
    1440             : /*
    1441             :  * Turn a Datum into JSON text, appending the string to "result".
    1442             :  *
    1443             :  * tcategory and outfuncoid are from a previous call to json_categorize_type,
    1444             :  * except that if is_null is true then they can be invalid.
    1445             :  *
    1446             :  * If key_scalar is true, the value is being printed as a key, so insist
    1447             :  * it's of an acceptable type, and force it to be quoted.
    1448             :  */
    1449             : static void
    1450        2676 : datum_to_json(Datum val, bool is_null, StringInfo result,
    1451             :               JsonTypeCategory tcategory, Oid outfuncoid,
    1452             :               bool key_scalar)
    1453             : {
    1454             :     char       *outputstr;
    1455             :     text       *jsontext;
    1456             : 
    1457        2676 :     check_stack_depth();
    1458             : 
    1459             :     /* callers are expected to ensure that null keys are not passed in */
    1460             :     Assert(!(key_scalar && is_null));
    1461             : 
    1462        2676 :     if (is_null)
    1463             :     {
    1464         124 :         appendStringInfoString(result, "null");
    1465         124 :         return;
    1466             :     }
    1467             : 
    1468        2552 :     if (key_scalar &&
    1469         156 :         (tcategory == JSONTYPE_ARRAY ||
    1470         152 :          tcategory == JSONTYPE_COMPOSITE ||
    1471         148 :          tcategory == JSONTYPE_JSON ||
    1472             :          tcategory == JSONTYPE_CAST))
    1473          16 :         ereport(ERROR,
    1474             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1475             :                  errmsg("key value must be scalar, not array, composite, or json")));
    1476             : 
    1477        2536 :     switch (tcategory)
    1478             :     {
    1479             :         case JSONTYPE_ARRAY:
    1480         204 :             array_to_json_internal(val, result, false);
    1481         204 :             break;
    1482             :         case JSONTYPE_COMPOSITE:
    1483         256 :             composite_to_json(val, result, false);
    1484         256 :             break;
    1485             :         case JSONTYPE_BOOL:
    1486          12 :             outputstr = DatumGetBool(val) ? "true" : "false";
    1487          12 :             if (key_scalar)
    1488           0 :                 escape_json(result, outputstr);
    1489             :             else
    1490          12 :                 appendStringInfoString(result, outputstr);
    1491          12 :             break;
    1492             :         case JSONTYPE_NUMERIC:
    1493        1568 :             outputstr = OidOutputFunctionCall(outfuncoid, val);
    1494             : 
    1495             :             /*
    1496             :              * Don't call escape_json for a non-key if it's a valid JSON
    1497             :              * number.
    1498             :              */
    1499        1568 :             if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr)))
    1500        1520 :                 appendStringInfoString(result, outputstr);
    1501             :             else
    1502          48 :                 escape_json(result, outputstr);
    1503        1568 :             pfree(outputstr);
    1504        1568 :             break;
    1505             :         case JSONTYPE_DATE:
    1506             :             {
    1507             :                 char        buf[MAXDATELEN + 1];
    1508             : 
    1509          12 :                 JsonEncodeDateTime(buf, val, DATEOID);
    1510          12 :                 appendStringInfo(result, "\"%s\"", buf);
    1511             :             }
    1512          12 :             break;
    1513             :         case JSONTYPE_TIMESTAMP:
    1514             :             {
    1515             :                 char        buf[MAXDATELEN + 1];
    1516             : 
    1517          12 :                 JsonEncodeDateTime(buf, val, TIMESTAMPOID);
    1518          12 :                 appendStringInfo(result, "\"%s\"", buf);
    1519             :             }
    1520          12 :             break;
    1521             :         case JSONTYPE_TIMESTAMPTZ:
    1522             :             {
    1523             :                 char        buf[MAXDATELEN + 1];
    1524             : 
    1525          16 :                 JsonEncodeDateTime(buf, val, TIMESTAMPTZOID);
    1526          16 :                 appendStringInfo(result, "\"%s\"", buf);
    1527             :             }
    1528          16 :             break;
    1529             :         case JSONTYPE_JSON:
    1530             :             /* JSON and JSONB output will already be escaped */
    1531          52 :             outputstr = OidOutputFunctionCall(outfuncoid, val);
    1532          52 :             appendStringInfoString(result, outputstr);
    1533          52 :             pfree(outputstr);
    1534          52 :             break;
    1535             :         case JSONTYPE_CAST:
    1536             :             /* outfuncoid refers to a cast function, not an output function */
    1537           4 :             jsontext = DatumGetTextPP(OidFunctionCall1(outfuncoid, val));
    1538           4 :             outputstr = text_to_cstring(jsontext);
    1539           4 :             appendStringInfoString(result, outputstr);
    1540           4 :             pfree(outputstr);
    1541           4 :             pfree(jsontext);
    1542           4 :             break;
    1543             :         default:
    1544         400 :             outputstr = OidOutputFunctionCall(outfuncoid, val);
    1545         400 :             escape_json(result, outputstr);
    1546         400 :             pfree(outputstr);
    1547         400 :             break;
    1548             :     }
    1549             : }
    1550             : 
    1551             : /*
    1552             :  * Encode 'value' of datetime type 'typid' into JSON string in ISO format using
    1553             :  * optionally preallocated buffer 'buf'.
    1554             :  */
    1555             : char *
    1556          80 : JsonEncodeDateTime(char *buf, Datum value, Oid typid)
    1557             : {
    1558          80 :     if (!buf)
    1559          40 :         buf = palloc(MAXDATELEN + 1);
    1560             : 
    1561          80 :     switch (typid)
    1562             :     {
    1563             :         case DATEOID:
    1564             :             {
    1565             :                 DateADT     date;
    1566             :                 struct pg_tm tm;
    1567             : 
    1568          24 :                 date = DatumGetDateADT(value);
    1569             : 
    1570             :                 /* Same as date_out(), but forcing DateStyle */
    1571          24 :                 if (DATE_NOT_FINITE(date))
    1572          16 :                     EncodeSpecialDate(date, buf);
    1573             :                 else
    1574             :                 {
    1575           8 :                     j2date(date + POSTGRES_EPOCH_JDATE,
    1576             :                            &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
    1577           8 :                     EncodeDateOnly(&tm, USE_XSD_DATES, buf);
    1578             :                 }
    1579             :             }
    1580          24 :             break;
    1581             :         case TIMEOID:
    1582             :             {
    1583           0 :                 TimeADT     time = DatumGetTimeADT(value);
    1584             :                 struct pg_tm tt,
    1585           0 :                            *tm = &tt;
    1586             :                 fsec_t      fsec;
    1587             : 
    1588             :                 /* Same as time_out(), but forcing DateStyle */
    1589           0 :                 time2tm(time, tm, &fsec);
    1590           0 :                 EncodeTimeOnly(tm, fsec, false, 0, USE_XSD_DATES, buf);
    1591             :             }
    1592           0 :             break;
    1593             :         case TIMETZOID:
    1594             :             {
    1595           0 :                 TimeTzADT  *time = DatumGetTimeTzADTP(value);
    1596             :                 struct pg_tm tt,
    1597           0 :                            *tm = &tt;
    1598             :                 fsec_t      fsec;
    1599             :                 int         tz;
    1600             : 
    1601             :                 /* Same as timetz_out(), but forcing DateStyle */
    1602           0 :                 timetz2tm(time, tm, &fsec, &tz);
    1603           0 :                 EncodeTimeOnly(tm, fsec, true, tz, USE_XSD_DATES, buf);
    1604             :             }
    1605           0 :             break;
    1606             :         case TIMESTAMPOID:
    1607             :             {
    1608             :                 Timestamp   timestamp;
    1609             :                 struct pg_tm tm;
    1610             :                 fsec_t      fsec;
    1611             : 
    1612          24 :                 timestamp = DatumGetTimestamp(value);
    1613             :                 /* Same as timestamp_out(), but forcing DateStyle */
    1614          24 :                 if (TIMESTAMP_NOT_FINITE(timestamp))
    1615          16 :                     EncodeSpecialTimestamp(timestamp, buf);
    1616           8 :                 else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
    1617           8 :                     EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
    1618             :                 else
    1619           0 :                     ereport(ERROR,
    1620             :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1621             :                              errmsg("timestamp out of range")));
    1622             :             }
    1623          24 :             break;
    1624             :         case TIMESTAMPTZOID:
    1625             :             {
    1626             :                 TimestampTz timestamp;
    1627             :                 struct pg_tm tm;
    1628             :                 int         tz;
    1629             :                 fsec_t      fsec;
    1630          32 :                 const char *tzn = NULL;
    1631             : 
    1632          32 :                 timestamp = DatumGetTimestampTz(value);
    1633             :                 /* Same as timestamptz_out(), but forcing DateStyle */
    1634          32 :                 if (TIMESTAMP_NOT_FINITE(timestamp))
    1635          16 :                     EncodeSpecialTimestamp(timestamp, buf);
    1636          16 :                 else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
    1637          16 :                     EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
    1638             :                 else
    1639           0 :                     ereport(ERROR,
    1640             :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1641             :                              errmsg("timestamp out of range")));
    1642             :             }
    1643          32 :             break;
    1644             :         default:
    1645           0 :             elog(ERROR, "unknown jsonb value datetime type oid %d", typid);
    1646             :             return NULL;
    1647             :     }
    1648             : 
    1649          80 :     return buf;
    1650             : }
    1651             : 
    1652             : /*
    1653             :  * Process a single dimension of an array.
    1654             :  * If it's the innermost dimension, output the values, otherwise call
    1655             :  * ourselves recursively to process the next dimension.
    1656             :  */
    1657             : static void
    1658         240 : array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals,
    1659             :                   bool *nulls, int *valcount, JsonTypeCategory tcategory,
    1660             :                   Oid outfuncoid, bool use_line_feeds)
    1661             : {
    1662             :     int         i;
    1663             :     const char *sep;
    1664             : 
    1665             :     Assert(dim < ndims);
    1666             : 
    1667         240 :     sep = use_line_feeds ? ",\n " : ",";
    1668             : 
    1669         240 :     appendStringInfoChar(result, '[');
    1670             : 
    1671         920 :     for (i = 1; i <= dims[dim]; i++)
    1672             :     {
    1673         680 :         if (i > 1)
    1674         440 :             appendStringInfoString(result, sep);
    1675             : 
    1676         680 :         if (dim + 1 == ndims)
    1677             :         {
    1678         672 :             datum_to_json(vals[*valcount], nulls[*valcount], result, tcategory,
    1679             :                           outfuncoid, false);
    1680         672 :             (*valcount)++;
    1681             :         }
    1682             :         else
    1683             :         {
    1684             :             /*
    1685             :              * Do we want line feeds on inner dimensions of arrays? For now
    1686             :              * we'll say no.
    1687             :              */
    1688           8 :             array_dim_to_json(result, dim + 1, ndims, dims, vals, nulls,
    1689             :                               valcount, tcategory, outfuncoid, false);
    1690             :         }
    1691             :     }
    1692             : 
    1693         240 :     appendStringInfoChar(result, ']');
    1694         240 : }
    1695             : 
    1696             : /*
    1697             :  * Turn an array into JSON.
    1698             :  */
    1699             : static void
    1700         232 : array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
    1701             : {
    1702         232 :     ArrayType  *v = DatumGetArrayTypeP(array);
    1703         232 :     Oid         element_type = ARR_ELEMTYPE(v);
    1704             :     int        *dim;
    1705             :     int         ndim;
    1706             :     int         nitems;
    1707         232 :     int         count = 0;
    1708             :     Datum      *elements;
    1709             :     bool       *nulls;
    1710             :     int16       typlen;
    1711             :     bool        typbyval;
    1712             :     char        typalign;
    1713             :     JsonTypeCategory tcategory;
    1714             :     Oid         outfuncoid;
    1715             : 
    1716         232 :     ndim = ARR_NDIM(v);
    1717         232 :     dim = ARR_DIMS(v);
    1718         232 :     nitems = ArrayGetNItems(ndim, dim);
    1719             : 
    1720         232 :     if (nitems <= 0)
    1721             :     {
    1722           0 :         appendStringInfoString(result, "[]");
    1723           0 :         return;
    1724             :     }
    1725             : 
    1726         232 :     get_typlenbyvalalign(element_type,
    1727             :                          &typlen, &typbyval, &typalign);
    1728             : 
    1729         232 :     json_categorize_type(element_type,
    1730             :                          &tcategory, &outfuncoid);
    1731             : 
    1732         232 :     deconstruct_array(v, element_type, typlen, typbyval,
    1733             :                       typalign, &elements, &nulls,
    1734             :                       &nitems);
    1735             : 
    1736         232 :     array_dim_to_json(result, 0, ndim, dim, elements, nulls, &count, tcategory,
    1737             :                       outfuncoid, use_line_feeds);
    1738             : 
    1739         232 :     pfree(elements);
    1740         232 :     pfree(nulls);
    1741             : }
    1742             : 
    1743             : /*
    1744             :  * Turn a composite / record into JSON.
    1745             :  */
    1746             : static void
    1747         636 : composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
    1748             : {
    1749             :     HeapTupleHeader td;
    1750             :     Oid         tupType;
    1751             :     int32       tupTypmod;
    1752             :     TupleDesc   tupdesc;
    1753             :     HeapTupleData tmptup,
    1754             :                *tuple;
    1755             :     int         i;
    1756         636 :     bool        needsep = false;
    1757             :     const char *sep;
    1758             : 
    1759         636 :     sep = use_line_feeds ? ",\n " : ",";
    1760             : 
    1761         636 :     td = DatumGetHeapTupleHeader(composite);
    1762             : 
    1763             :     /* Extract rowtype info and find a tupdesc */
    1764         636 :     tupType = HeapTupleHeaderGetTypeId(td);
    1765         636 :     tupTypmod = HeapTupleHeaderGetTypMod(td);
    1766         636 :     tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    1767             : 
    1768             :     /* Build a temporary HeapTuple control structure */
    1769         636 :     tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
    1770         636 :     tmptup.t_data = td;
    1771         636 :     tuple = &tmptup;
    1772             : 
    1773         636 :     appendStringInfoChar(result, '{');
    1774             : 
    1775        2072 :     for (i = 0; i < tupdesc->natts; i++)
    1776             :     {
    1777             :         Datum       val;
    1778             :         bool        isnull;
    1779             :         char       *attname;
    1780             :         JsonTypeCategory tcategory;
    1781             :         Oid         outfuncoid;
    1782        1436 :         Form_pg_attribute att = TupleDescAttr(tupdesc, i);
    1783             : 
    1784        1436 :         if (att->attisdropped)
    1785           0 :             continue;
    1786             : 
    1787        1436 :         if (needsep)
    1788         800 :             appendStringInfoString(result, sep);
    1789        1436 :         needsep = true;
    1790             : 
    1791        1436 :         attname = NameStr(att->attname);
    1792        1436 :         escape_json(result, attname);
    1793        1436 :         appendStringInfoChar(result, ':');
    1794             : 
    1795        1436 :         val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
    1796             : 
    1797        1436 :         if (isnull)
    1798             :         {
    1799         100 :             tcategory = JSONTYPE_NULL;
    1800         100 :             outfuncoid = InvalidOid;
    1801             :         }
    1802             :         else
    1803        1336 :             json_categorize_type(att->atttypid, &tcategory, &outfuncoid);
    1804             : 
    1805        1436 :         datum_to_json(val, isnull, result, tcategory, outfuncoid, false);
    1806             :     }
    1807             : 
    1808         636 :     appendStringInfoChar(result, '}');
    1809         636 :     ReleaseTupleDesc(tupdesc);
    1810         636 : }
    1811             : 
    1812             : /*
    1813             :  * Append JSON text for "val" to "result".
    1814             :  *
    1815             :  * This is just a thin wrapper around datum_to_json.  If the same type will be
    1816             :  * printed many times, avoid using this; better to do the json_categorize_type
    1817             :  * lookups only once.
    1818             :  */
    1819             : static void
    1820         364 : add_json(Datum val, bool is_null, StringInfo result,
    1821             :          Oid val_type, bool key_scalar)
    1822             : {
    1823             :     JsonTypeCategory tcategory;
    1824             :     Oid         outfuncoid;
    1825             : 
    1826         364 :     if (val_type == InvalidOid)
    1827           0 :         ereport(ERROR,
    1828             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1829             :                  errmsg("could not determine input data type")));
    1830             : 
    1831         364 :     if (is_null)
    1832             :     {
    1833          24 :         tcategory = JSONTYPE_NULL;
    1834          24 :         outfuncoid = InvalidOid;
    1835             :     }
    1836             :     else
    1837         340 :         json_categorize_type(val_type,
    1838             :                              &tcategory, &outfuncoid);
    1839             : 
    1840         364 :     datum_to_json(val, is_null, result, tcategory, outfuncoid, key_scalar);
    1841         348 : }
    1842             : 
    1843             : /*
    1844             :  * SQL function array_to_json(row)
    1845             :  */
    1846             : Datum
    1847          12 : array_to_json(PG_FUNCTION_ARGS)
    1848             : {
    1849          12 :     Datum       array = PG_GETARG_DATUM(0);
    1850             :     StringInfo  result;
    1851             : 
    1852          12 :     result = makeStringInfo();
    1853             : 
    1854          12 :     array_to_json_internal(array, result, false);
    1855             : 
    1856          12 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
    1857             : }
    1858             : 
    1859             : /*
    1860             :  * SQL function array_to_json(row, prettybool)
    1861             :  */
    1862             : Datum
    1863          16 : array_to_json_pretty(PG_FUNCTION_ARGS)
    1864             : {
    1865          16 :     Datum       array = PG_GETARG_DATUM(0);
    1866          16 :     bool        use_line_feeds = PG_GETARG_BOOL(1);
    1867             :     StringInfo  result;
    1868             : 
    1869          16 :     result = makeStringInfo();
    1870             : 
    1871          16 :     array_to_json_internal(array, result, use_line_feeds);
    1872             : 
    1873          16 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
    1874             : }
    1875             : 
    1876             : /*
    1877             :  * SQL function row_to_json(row)
    1878             :  */
    1879             : Datum
    1880         348 : row_to_json(PG_FUNCTION_ARGS)
    1881             : {
    1882         348 :     Datum       array = PG_GETARG_DATUM(0);
    1883             :     StringInfo  result;
    1884             : 
    1885         348 :     result = makeStringInfo();
    1886             : 
    1887         348 :     composite_to_json(array, result, false);
    1888             : 
    1889         348 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
    1890             : }
    1891             : 
    1892             : /*
    1893             :  * SQL function row_to_json(row, prettybool)
    1894             :  */
    1895             : Datum
    1896          32 : row_to_json_pretty(PG_FUNCTION_ARGS)
    1897             : {
    1898          32 :     Datum       array = PG_GETARG_DATUM(0);
    1899          32 :     bool        use_line_feeds = PG_GETARG_BOOL(1);
    1900             :     StringInfo  result;
    1901             : 
    1902          32 :     result = makeStringInfo();
    1903             : 
    1904          32 :     composite_to_json(array, result, use_line_feeds);
    1905             : 
    1906          32 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
    1907             : }
    1908             : 
    1909             : /*
    1910             :  * SQL function to_json(anyvalue)
    1911             :  */
    1912             : Datum
    1913          84 : to_json(PG_FUNCTION_ARGS)
    1914             : {
    1915          84 :     Datum       val = PG_GETARG_DATUM(0);
    1916          84 :     Oid         val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
    1917             :     StringInfo  result;
    1918             :     JsonTypeCategory tcategory;
    1919             :     Oid         outfuncoid;
    1920             : 
    1921          84 :     if (val_type == InvalidOid)
    1922           0 :         ereport(ERROR,
    1923             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1924             :                  errmsg("could not determine input data type")));
    1925             : 
    1926          84 :     json_categorize_type(val_type,
    1927             :                          &tcategory, &outfuncoid);
    1928             : 
    1929          84 :     result = makeStringInfo();
    1930             : 
    1931          84 :     datum_to_json(val, false, result, tcategory, outfuncoid, false);
    1932             : 
    1933          84 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
    1934             : }
    1935             : 
    1936             : /*
    1937             :  * json_agg transition function
    1938             :  *
    1939             :  * aggregate input column as a json array value.
    1940             :  */
    1941             : Datum
    1942          48 : json_agg_transfn(PG_FUNCTION_ARGS)
    1943             : {
    1944             :     MemoryContext aggcontext,
    1945             :                 oldcontext;
    1946             :     JsonAggState *state;
    1947             :     Datum       val;
    1948             : 
    1949          48 :     if (!AggCheckCallContext(fcinfo, &aggcontext))
    1950             :     {
    1951             :         /* cannot be called directly because of internal-type argument */
    1952           0 :         elog(ERROR, "json_agg_transfn called in non-aggregate context");
    1953             :     }
    1954             : 
    1955          48 :     if (PG_ARGISNULL(0))
    1956             :     {
    1957          16 :         Oid         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    1958             : 
    1959          16 :         if (arg_type == InvalidOid)
    1960           0 :             ereport(ERROR,
    1961             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1962             :                      errmsg("could not determine input data type")));
    1963             : 
    1964             :         /*
    1965             :          * Make this state object in a context where it will persist for the
    1966             :          * duration of the aggregate call.  MemoryContextSwitchTo is only
    1967             :          * needed the first time, as the StringInfo routines make sure they
    1968             :          * use the right context to enlarge the object if necessary.
    1969             :          */
    1970          16 :         oldcontext = MemoryContextSwitchTo(aggcontext);
    1971          16 :         state = (JsonAggState *) palloc(sizeof(JsonAggState));
    1972          16 :         state->str = makeStringInfo();
    1973          16 :         MemoryContextSwitchTo(oldcontext);
    1974             : 
    1975          16 :         appendStringInfoChar(state->str, '[');
    1976          16 :         json_categorize_type(arg_type, &state->val_category,
    1977             :                              &state->val_output_func);
    1978             :     }
    1979             :     else
    1980             :     {
    1981          32 :         state = (JsonAggState *) PG_GETARG_POINTER(0);
    1982          32 :         appendStringInfoString(state->str, ", ");
    1983             :     }
    1984             : 
    1985             :     /* fast path for NULLs */
    1986          48 :     if (PG_ARGISNULL(1))
    1987             :     {
    1988           0 :         datum_to_json((Datum) 0, true, state->str, JSONTYPE_NULL,
    1989             :                       InvalidOid, false);
    1990           0 :         PG_RETURN_POINTER(state);
    1991             :     }
    1992             : 
    1993          48 :     val = PG_GETARG_DATUM(1);
    1994             : 
    1995             :     /* add some whitespace if structured type and not first item */
    1996          80 :     if (!PG_ARGISNULL(0) &&
    1997          64 :         (state->val_category == JSONTYPE_ARRAY ||
    1998          32 :          state->val_category == JSONTYPE_COMPOSITE))
    1999             :     {
    2000          32 :         appendStringInfoString(state->str, "\n ");
    2001             :     }
    2002             : 
    2003          48 :     datum_to_json(val, false, state->str, state->val_category,
    2004             :                   state->val_output_func, false);
    2005             : 
    2006             :     /*
    2007             :      * The transition type for json_agg() is declared to be "internal", which
    2008             :      * is a pass-by-value type the same size as a pointer.  So we can safely
    2009             :      * pass the JsonAggState pointer through nodeAgg.c's machinations.
    2010             :      */
    2011          48 :     PG_RETURN_POINTER(state);
    2012             : }
    2013             : 
    2014             : /*
    2015             :  * json_agg final function
    2016             :  */
    2017             : Datum
    2018          16 : json_agg_finalfn(PG_FUNCTION_ARGS)
    2019             : {
    2020             :     JsonAggState *state;
    2021             : 
    2022             :     /* cannot be called directly because of internal-type argument */
    2023             :     Assert(AggCheckCallContext(fcinfo, NULL));
    2024             : 
    2025          32 :     state = PG_ARGISNULL(0) ?
    2026          32 :         NULL :
    2027          16 :         (JsonAggState *) PG_GETARG_POINTER(0);
    2028             : 
    2029             :     /* NULL result for no rows in, as is standard with aggregates */
    2030          16 :     if (state == NULL)
    2031           0 :         PG_RETURN_NULL();
    2032             : 
    2033             :     /* Else return state with appropriate array terminator added */
    2034          16 :     PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, "]"));
    2035             : }
    2036             : 
    2037             : /*
    2038             :  * json_object_agg transition function.
    2039             :  *
    2040             :  * aggregate two input columns as a single json object value.
    2041             :  */
    2042             : Datum
    2043          40 : json_object_agg_transfn(PG_FUNCTION_ARGS)
    2044             : {
    2045             :     MemoryContext aggcontext,
    2046             :                 oldcontext;
    2047             :     JsonAggState *state;
    2048             :     Datum       arg;
    2049             : 
    2050          40 :     if (!AggCheckCallContext(fcinfo, &aggcontext))
    2051             :     {
    2052             :         /* cannot be called directly because of internal-type argument */
    2053           0 :         elog(ERROR, "json_object_agg_transfn called in non-aggregate context");
    2054             :     }
    2055             : 
    2056          40 :     if (PG_ARGISNULL(0))
    2057             :     {
    2058             :         Oid         arg_type;
    2059             : 
    2060             :         /*
    2061             :          * Make the StringInfo in a context where it will persist for the
    2062             :          * duration of the aggregate call. Switching context is only needed
    2063             :          * for this initial step, as the StringInfo routines make sure they
    2064             :          * use the right context to enlarge the object if necessary.
    2065             :          */
    2066          12 :         oldcontext = MemoryContextSwitchTo(aggcontext);
    2067          12 :         state = (JsonAggState *) palloc(sizeof(JsonAggState));
    2068          12 :         state->str = makeStringInfo();
    2069          12 :         MemoryContextSwitchTo(oldcontext);
    2070             : 
    2071          12 :         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    2072             : 
    2073          12 :         if (arg_type == InvalidOid)
    2074           0 :             ereport(ERROR,
    2075             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2076             :                      errmsg("could not determine data type for argument %d", 1)));
    2077             : 
    2078          12 :         json_categorize_type(arg_type, &state->key_category,
    2079             :                              &state->key_output_func);
    2080             : 
    2081          12 :         arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
    2082             : 
    2083          12 :         if (arg_type == InvalidOid)
    2084           0 :             ereport(ERROR,
    2085             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2086             :                      errmsg("could not determine data type for argument %d", 2)));
    2087             : 
    2088          12 :         json_categorize_type(arg_type, &state->val_category,
    2089             :                              &state->val_output_func);
    2090             : 
    2091          12 :         appendStringInfoString(state->str, "{ ");
    2092             :     }
    2093             :     else
    2094             :     {
    2095          28 :         state = (JsonAggState *) PG_GETARG_POINTER(0);
    2096          28 :         appendStringInfoString(state->str, ", ");
    2097             :     }
    2098             : 
    2099             :     /*
    2100             :      * Note: since json_object_agg() is declared as taking type "any", the
    2101             :      * parser will not do any type conversion on unknown-type literals (that
    2102             :      * is, undecorated strings or NULLs).  Such values will arrive here as
    2103             :      * type UNKNOWN, which fortunately does not matter to us, since
    2104             :      * unknownout() works fine.
    2105             :      */
    2106             : 
    2107          40 :     if (PG_ARGISNULL(1))
    2108           4 :         ereport(ERROR,
    2109             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2110             :                  errmsg("field name must not be null")));
    2111             : 
    2112          36 :     arg = PG_GETARG_DATUM(1);
    2113             : 
    2114          36 :     datum_to_json(arg, false, state->str, state->key_category,
    2115             :                   state->key_output_func, true);
    2116             : 
    2117          36 :     appendStringInfoString(state->str, " : ");
    2118             : 
    2119          36 :     if (PG_ARGISNULL(2))
    2120           0 :         arg = (Datum) 0;
    2121             :     else
    2122          36 :         arg = PG_GETARG_DATUM(2);
    2123             : 
    2124          36 :     datum_to_json(arg, PG_ARGISNULL(2), state->str, state->val_category,
    2125             :                   state->val_output_func, false);
    2126             : 
    2127          36 :     PG_RETURN_POINTER(state);
    2128             : }
    2129             : 
    2130             : /*
    2131             :  * json_object_agg final function.
    2132             :  */
    2133             : Datum
    2134           8 : json_object_agg_finalfn(PG_FUNCTION_ARGS)
    2135             : {
    2136             :     JsonAggState *state;
    2137             : 
    2138             :     /* cannot be called directly because of internal-type argument */
    2139             :     Assert(AggCheckCallContext(fcinfo, NULL));
    2140             : 
    2141           8 :     state = PG_ARGISNULL(0) ? NULL : (JsonAggState *) PG_GETARG_POINTER(0);
    2142             : 
    2143             :     /* NULL result for no rows in, as is standard with aggregates */
    2144           8 :     if (state == NULL)
    2145           0 :         PG_RETURN_NULL();
    2146             : 
    2147             :     /* Else return state with appropriate object terminator added */
    2148           8 :     PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, " }"));
    2149             : }
    2150             : 
    2151             : /*
    2152             :  * Helper function for aggregates: return given StringInfo's contents plus
    2153             :  * specified trailing string, as a text datum.  We need this because aggregate
    2154             :  * final functions are not allowed to modify the aggregate state.
    2155             :  */
    2156             : static text *
    2157          24 : catenate_stringinfo_string(StringInfo buffer, const char *addon)
    2158             : {
    2159             :     /* custom version of cstring_to_text_with_len */
    2160          24 :     int         buflen = buffer->len;
    2161          24 :     int         addlen = strlen(addon);
    2162          24 :     text       *result = (text *) palloc(buflen + addlen + VARHDRSZ);
    2163             : 
    2164          24 :     SET_VARSIZE(result, buflen + addlen + VARHDRSZ);
    2165          24 :     memcpy(VARDATA(result), buffer->data, buflen);
    2166          24 :     memcpy(VARDATA(result) + buflen, addon, addlen);
    2167             : 
    2168          24 :     return result;
    2169             : }
    2170             : 
    2171             : /*
    2172             :  * SQL function json_build_object(variadic "any")
    2173             :  */
    2174             : Datum
    2175         104 : json_build_object(PG_FUNCTION_ARGS)
    2176             : {
    2177         104 :     int         nargs = PG_NARGS();
    2178             :     int         i;
    2179         104 :     const char *sep = "";
    2180             :     StringInfo  result;
    2181             :     Datum      *args;
    2182             :     bool       *nulls;
    2183             :     Oid        *types;
    2184             : 
    2185             :     /* fetch argument values to build the object */
    2186         104 :     nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
    2187             : 
    2188         104 :     if (nargs < 0)
    2189           4 :         PG_RETURN_NULL();
    2190             : 
    2191         100 :     if (nargs % 2 != 0)
    2192          12 :         ereport(ERROR,
    2193             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2194             :                  errmsg("argument list must have even number of elements"),
    2195             :         /* translator: %s is a SQL function name */
    2196             :                  errhint("The arguments of %s must consist of alternating keys and values.",
    2197             :                          "json_build_object()")));
    2198             : 
    2199          88 :     result = makeStringInfo();
    2200             : 
    2201          88 :     appendStringInfoChar(result, '{');
    2202             : 
    2203         200 :     for (i = 0; i < nargs; i += 2)
    2204             :     {
    2205         140 :         appendStringInfoString(result, sep);
    2206         140 :         sep = ", ";
    2207             : 
    2208             :         /* process key */
    2209         140 :         if (nulls[i])
    2210          12 :             ereport(ERROR,
    2211             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2212             :                      errmsg("argument %d cannot be null", i + 1),
    2213             :                      errhint("Object keys should be text.")));
    2214             : 
    2215         128 :         add_json(args[i], false, result, types[i], true);
    2216             : 
    2217         112 :         appendStringInfoString(result, " : ");
    2218             : 
    2219             :         /* process value */
    2220         112 :         add_json(args[i + 1], nulls[i + 1], result, types[i + 1], false);
    2221             :     }
    2222             : 
    2223          60 :     appendStringInfoChar(result, '}');
    2224             : 
    2225          60 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
    2226             : }
    2227             : 
    2228             : /*
    2229             :  * degenerate case of json_build_object where it gets 0 arguments.
    2230             :  */
    2231             : Datum
    2232           4 : json_build_object_noargs(PG_FUNCTION_ARGS)
    2233             : {
    2234           4 :     PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
    2235             : }
    2236             : 
    2237             : /*
    2238             :  * SQL function json_build_array(variadic "any")
    2239             :  */
    2240             : Datum
    2241          36 : json_build_array(PG_FUNCTION_ARGS)
    2242             : {
    2243             :     int         nargs;
    2244             :     int         i;
    2245          36 :     const char *sep = "";
    2246             :     StringInfo  result;
    2247             :     Datum      *args;
    2248             :     bool       *nulls;
    2249             :     Oid        *types;
    2250             : 
    2251             :     /* fetch argument values to build the array */
    2252          36 :     nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
    2253             : 
    2254          36 :     if (nargs < 0)
    2255           4 :         PG_RETURN_NULL();
    2256             : 
    2257          32 :     result = makeStringInfo();
    2258             : 
    2259          32 :     appendStringInfoChar(result, '[');
    2260             : 
    2261         156 :     for (i = 0; i < nargs; i++)
    2262             :     {
    2263         124 :         appendStringInfoString(result, sep);
    2264         124 :         sep = ", ";
    2265         124 :         add_json(args[i], nulls[i], result, types[i], false);
    2266             :     }
    2267             : 
    2268          32 :     appendStringInfoChar(result, ']');
    2269             : 
    2270          32 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
    2271             : }
    2272             : 
    2273             : /*
    2274             :  * degenerate case of json_build_array where it gets 0 arguments.
    2275             :  */
    2276             : Datum
    2277           4 : json_build_array_noargs(PG_FUNCTION_ARGS)
    2278             : {
    2279           4 :     PG_RETURN_TEXT_P(cstring_to_text_with_len("[]", 2));
    2280             : }
    2281             : 
    2282             : /*
    2283             :  * SQL function json_object(text[])
    2284             :  *
    2285             :  * take a one or two dimensional array of text as key/value pairs
    2286             :  * for a json object.
    2287             :  */
    2288             : Datum
    2289          32 : json_object(PG_FUNCTION_ARGS)
    2290             : {
    2291          32 :     ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
    2292          32 :     int         ndims = ARR_NDIM(in_array);
    2293             :     StringInfoData result;
    2294             :     Datum      *in_datums;
    2295             :     bool       *in_nulls;
    2296             :     int         in_count,
    2297             :                 count,
    2298             :                 i;
    2299             :     text       *rval;
    2300             :     char       *v;
    2301             : 
    2302          32 :     switch (ndims)
    2303             :     {
    2304             :         case 0:
    2305           4 :             PG_RETURN_DATUM(CStringGetTextDatum("{}"));
    2306             :             break;
    2307             : 
    2308             :         case 1:
    2309          12 :             if ((ARR_DIMS(in_array)[0]) % 2)
    2310           4 :                 ereport(ERROR,
    2311             :                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2312             :                          errmsg("array must have even number of elements")));
    2313           8 :             break;
    2314             : 
    2315             :         case 2:
    2316          12 :             if ((ARR_DIMS(in_array)[1]) != 2)
    2317           8 :                 ereport(ERROR,
    2318             :                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2319             :                          errmsg("array must have two columns")));
    2320           4 :             break;
    2321             : 
    2322             :         default:
    2323           4 :             ereport(ERROR,
    2324             :                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2325             :                      errmsg("wrong number of array subscripts")));
    2326             :     }
    2327             : 
    2328          12 :     deconstruct_array(in_array,
    2329             :                       TEXTOID, -1, false, 'i',
    2330             :                       &in_datums, &in_nulls, &in_count);
    2331             : 
    2332          12 :     count = in_count / 2;
    2333             : 
    2334          12 :     initStringInfo(&result);
    2335             : 
    2336          12 :     appendStringInfoChar(&result, '{');
    2337             : 
    2338        1244 :     for (i = 0; i < count; ++i)
    2339             :     {
    2340        1232 :         if (in_nulls[i * 2])
    2341           0 :             ereport(ERROR,
    2342             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2343             :                      errmsg("null value not allowed for object key")));
    2344             : 
    2345        1232 :         v = TextDatumGetCString(in_datums[i * 2]);
    2346        1232 :         if (i > 0)
    2347        1220 :             appendStringInfoString(&result, ", ");
    2348        1232 :         escape_json(&result, v);
    2349        1232 :         appendStringInfoString(&result, " : ");
    2350        1232 :         pfree(v);
    2351        1232 :         if (in_nulls[i * 2 + 1])
    2352           8 :             appendStringInfoString(&result, "null");
    2353             :         else
    2354             :         {
    2355        1224 :             v = TextDatumGetCString(in_datums[i * 2 + 1]);
    2356        1224 :             escape_json(&result, v);
    2357        1224 :             pfree(v);
    2358             :         }
    2359             :     }
    2360             : 
    2361          12 :     appendStringInfoChar(&result, '}');
    2362             : 
    2363          12 :     pfree(in_datums);
    2364          12 :     pfree(in_nulls);
    2365             : 
    2366          12 :     rval = cstring_to_text_with_len(result.data, result.len);
    2367          12 :     pfree(result.data);
    2368             : 
    2369          12 :     PG_RETURN_TEXT_P(rval);
    2370             : 
    2371             : }
    2372             : 
    2373             : /*
    2374             :  * SQL function json_object(text[], text[])
    2375             :  *
    2376             :  * take separate key and value arrays of text to construct a json object
    2377             :  * pairwise.
    2378             :  */
    2379             : Datum
    2380          28 : json_object_two_arg(PG_FUNCTION_ARGS)
    2381             : {
    2382          28 :     ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(0);
    2383          28 :     ArrayType  *val_array = PG_GETARG_ARRAYTYPE_P(1);
    2384          28 :     int         nkdims = ARR_NDIM(key_array);
    2385          28 :     int         nvdims = ARR_NDIM(val_array);
    2386             :     StringInfoData result;
    2387             :     Datum      *key_datums,
    2388             :                *val_datums;
    2389             :     bool       *key_nulls,
    2390             :                *val_nulls;
    2391             :     int         key_count,
    2392             :                 val_count,
    2393             :                 i;
    2394             :     text       *rval;
    2395             :     char       *v;
    2396             : 
    2397          28 :     if (nkdims > 1 || nkdims != nvdims)
    2398           4 :         ereport(ERROR,
    2399             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2400             :                  errmsg("wrong number of array subscripts")));
    2401             : 
    2402          24 :     if (nkdims == 0)
    2403           4 :         PG_RETURN_DATUM(CStringGetTextDatum("{}"));
    2404             : 
    2405          20 :     deconstruct_array(key_array,
    2406             :                       TEXTOID, -1, false, 'i',
    2407             :                       &key_datums, &key_nulls, &key_count);
    2408             : 
    2409          20 :     deconstruct_array(val_array,
    2410             :                       TEXTOID, -1, false, 'i',
    2411             :                       &val_datums, &val_nulls, &val_count);
    2412             : 
    2413          20 :     if (key_count != val_count)
    2414           8 :         ereport(ERROR,
    2415             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2416             :                  errmsg("mismatched array dimensions")));
    2417             : 
    2418          12 :     initStringInfo(&result);
    2419             : 
    2420          12 :     appendStringInfoChar(&result, '{');
    2421             : 
    2422          52 :     for (i = 0; i < key_count; ++i)
    2423             :     {
    2424          44 :         if (key_nulls[i])
    2425           4 :             ereport(ERROR,
    2426             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2427             :                      errmsg("null value not allowed for object key")));
    2428             : 
    2429          40 :         v = TextDatumGetCString(key_datums[i]);
    2430          40 :         if (i > 0)
    2431          28 :             appendStringInfoString(&result, ", ");
    2432          40 :         escape_json(&result, v);
    2433          40 :         appendStringInfoString(&result, " : ");
    2434          40 :         pfree(v);
    2435          40 :         if (val_nulls[i])
    2436           0 :             appendStringInfoString(&result, "null");
    2437             :         else
    2438             :         {
    2439          40 :             v = TextDatumGetCString(val_datums[i]);
    2440          40 :             escape_json(&result, v);
    2441          40 :             pfree(v);
    2442             :         }
    2443             :     }
    2444             : 
    2445           8 :     appendStringInfoChar(&result, '}');
    2446             : 
    2447           8 :     pfree(key_datums);
    2448           8 :     pfree(key_nulls);
    2449           8 :     pfree(val_datums);
    2450           8 :     pfree(val_nulls);
    2451             : 
    2452           8 :     rval = cstring_to_text_with_len(result.data, result.len);
    2453           8 :     pfree(result.data);
    2454             : 
    2455           8 :     PG_RETURN_TEXT_P(rval);
    2456             : }
    2457             : 
    2458             : 
    2459             : /*
    2460             :  * Produce a JSON string literal, properly escaping characters in the text.
    2461             :  */
    2462             : void
    2463       47060 : escape_json(StringInfo buf, const char *str)
    2464             : {
    2465             :     const char *p;
    2466             : 
    2467       47060 :     appendStringInfoCharMacro(buf, '"');
    2468      295456 :     for (p = str; *p; p++)
    2469             :     {
    2470      248396 :         switch (*p)
    2471             :         {
    2472             :             case '\b':
    2473           8 :                 appendStringInfoString(buf, "\\b");
    2474           8 :                 break;
    2475             :             case '\f':
    2476           8 :                 appendStringInfoString(buf, "\\f");
    2477           8 :                 break;
    2478             :             case '\n':
    2479          16 :                 appendStringInfoString(buf, "\\n");
    2480          16 :                 break;
    2481             :             case '\r':
    2482           8 :                 appendStringInfoString(buf, "\\r");
    2483           8 :                 break;
    2484             :             case '\t':
    2485          12 :                 appendStringInfoString(buf, "\\t");
    2486          12 :                 break;
    2487             :             case '"':
    2488          56 :                 appendStringInfoString(buf, "\\\"");
    2489          56 :                 break;
    2490             :             case '\\':
    2491          36 :                 appendStringInfoString(buf, "\\\\");
    2492          36 :                 break;
    2493             :             default:
    2494      248252 :                 if ((unsigned char) *p < ' ')
    2495           8 :                     appendStringInfo(buf, "\\u%04x", (int) *p);
    2496             :                 else
    2497      248244 :                     appendStringInfoCharMacro(buf, *p);
    2498      248252 :                 break;
    2499             :         }
    2500             :     }
    2501       47060 :     appendStringInfoCharMacro(buf, '"');
    2502       47060 : }
    2503             : 
    2504             : /*
    2505             :  * SQL function json_typeof(json) -> text
    2506             :  *
    2507             :  * Returns the type of the outermost JSON value as TEXT.  Possible types are
    2508             :  * "object", "array", "string", "number", "boolean", and "null".
    2509             :  *
    2510             :  * Performs a single call to json_lex() to get the first token of the supplied
    2511             :  * value.  This initial token uniquely determines the value's type.  As our
    2512             :  * input must already have been validated by json_in() or json_recv(), the
    2513             :  * initial token should never be JSON_TOKEN_OBJECT_END, JSON_TOKEN_ARRAY_END,
    2514             :  * JSON_TOKEN_COLON, JSON_TOKEN_COMMA, or JSON_TOKEN_END.
    2515             :  */
    2516             : Datum
    2517          40 : json_typeof(PG_FUNCTION_ARGS)
    2518             : {
    2519             :     text       *json;
    2520             : 
    2521             :     JsonLexContext *lex;
    2522             :     JsonTokenType tok;
    2523             :     char       *type;
    2524             : 
    2525          40 :     json = PG_GETARG_TEXT_PP(0);
    2526          40 :     lex = makeJsonLexContext(json, false);
    2527             : 
    2528             :     /* Lex exactly one token from the input and check its type. */
    2529          40 :     json_lex(lex);
    2530          40 :     tok = lex_peek(lex);
    2531          40 :     switch (tok)
    2532             :     {
    2533             :         case JSON_TOKEN_OBJECT_START:
    2534           8 :             type = "object";
    2535           8 :             break;
    2536             :         case JSON_TOKEN_ARRAY_START:
    2537           8 :             type = "array";
    2538           8 :             break;
    2539             :         case JSON_TOKEN_STRING:
    2540           4 :             type = "string";
    2541           4 :             break;
    2542             :         case JSON_TOKEN_NUMBER:
    2543           8 :             type = "number";
    2544           8 :             break;
    2545             :         case JSON_TOKEN_TRUE:
    2546             :         case JSON_TOKEN_FALSE:
    2547           8 :             type = "boolean";
    2548           8 :             break;
    2549             :         case JSON_TOKEN_NULL:
    2550           4 :             type = "null";
    2551           4 :             break;
    2552             :         default:
    2553           0 :             elog(ERROR, "unexpected json token: %d", tok);
    2554             :     }
    2555             : 
    2556          40 :     PG_RETURN_TEXT_P(cstring_to_text(type));
    2557             : }

Generated by: LCOV version 1.13