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

Generated by: LCOV version 1.11