PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
jsonapi.c File Reference
#include "postgres.h"
#include "common/jsonapi.h"
#include "mb/pg_wchar.h"
#include "port/pg_lfind.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
Include dependency graph for jsonapi.c:

Go to the source code of this file.

Data Structures

struct  JsonParserStack
 
struct  JsonIncrementalState
 
struct  td_entry
 

Macros

#define STRDUP(s)   pstrdup(s)
 
#define ALLOC(size)   palloc(size)
 
#define ALLOC0(size)   palloc0(size)
 
#define REALLOC   repalloc
 
#define FREE(s)
 
#define jsonapi_appendStringInfo   appendStringInfo
 
#define jsonapi_appendBinaryStringInfo   appendBinaryStringInfo
 
#define jsonapi_appendStringInfoChar   appendStringInfoChar
 
#define jsonapi_appendStringInfoCharMacro   appendStringInfoCharMacro
 
#define jsonapi_makeStringInfo   makeStringInfo
 
#define jsonapi_initStringInfo   initStringInfo
 
#define jsonapi_resetStringInfo   resetStringInfo
 
#define jsonapi_termStringInfo(s)   pfree((s)->data)
 
#define jsonapi_destroyStringInfo   destroyStringInfo
 
#define JSON_NUM_TERMINALS   13
 
#define JSON_NUM_NONTERMINALS   5
 
#define JSON_NT_OFFSET   JSON_NT_JSON
 
#define OFS(NT)   (NT) - JSON_NT_OFFSET
 
#define IS_SEM(x)   ((x) & 0x40)
 
#define IS_NT(x)   ((x) & 0x20)
 
#define TD_ENTRY(PROD)   { sizeof(PROD) - 1, (PROD) }
 
#define JSON_ALPHANUMERIC_CHAR(c)
 
#define JS_STACK_CHUNK_SIZE   64
 
#define JS_MAX_PROD_LEN   10 /* more than we need */
 
#define JSON_TD_MAX_STACK
 
#define FAIL_OR_INCOMPLETE_AT_CHAR_START(code)
 
#define FAIL_AT_CHAR_END(code)
 
#define json_token_error(lex, format)
 

Enumerations

enum  JsonParseContext {
  JSON_PARSE_VALUE , JSON_PARSE_STRING , JSON_PARSE_ARRAY_START , JSON_PARSE_ARRAY_NEXT ,
  JSON_PARSE_OBJECT_START , JSON_PARSE_OBJECT_LABEL , JSON_PARSE_OBJECT_NEXT , JSON_PARSE_OBJECT_COMMA ,
  JSON_PARSE_END
}
 
enum  JsonNonTerminal {
  JSON_NT_JSON = 32 , JSON_NT_ARRAY_ELEMENTS , JSON_NT_MORE_ARRAY_ELEMENTS , JSON_NT_KEY_PAIRS ,
  JSON_NT_MORE_KEY_PAIRS
}
 
enum  JsonParserSem {
  JSON_SEM_OSTART = 64 , JSON_SEM_OEND , JSON_SEM_ASTART , JSON_SEM_AEND ,
  JSON_SEM_OFIELD_INIT , JSON_SEM_OFIELD_START , JSON_SEM_OFIELD_END , JSON_SEM_AELEM_START ,
  JSON_SEM_AELEM_END , JSON_SEM_SCALAR_INIT , JSON_SEM_SCALAR_CALL
}
 

Functions

static JsonParseErrorType json_lex_string (JsonLexContext *lex)
 
static JsonParseErrorType json_lex_number (JsonLexContext *lex, const char *s, bool *num_err, size_t *total_len)
 
static JsonParseErrorType parse_scalar (JsonLexContext *lex, const JsonSemAction *sem)
 
static JsonParseErrorType parse_object_field (JsonLexContext *lex, const JsonSemAction *sem)
 
static JsonParseErrorType parse_object (JsonLexContext *lex, const JsonSemAction *sem)
 
static JsonParseErrorType parse_array_element (JsonLexContext *lex, const JsonSemAction *sem)
 
static JsonParseErrorType parse_array (JsonLexContext *lex, const JsonSemAction *sem)
 
static JsonParseErrorType report_parse_error (JsonParseContext ctx, JsonLexContext *lex)
 
static bool allocate_incremental_state (JsonLexContext *lex)
 
static JsonTokenType lex_peek (JsonLexContext *lex)
 
static JsonParseErrorType lex_expect (JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
 
bool IsValidJsonNumber (const char *str, size_t len)
 
JsonLexContextmakeJsonLexContextCstringLen (JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
 
JsonLexContextmakeJsonLexContextIncremental (JsonLexContext *lex, int encoding, bool need_escapes)
 
static bool inc_lex_level (JsonLexContext *lex)
 
static void dec_lex_level (JsonLexContext *lex)
 
static void push_prediction (JsonParserStack *pstack, td_entry entry)
 
static char pop_prediction (JsonParserStack *pstack)
 
static char next_prediction (JsonParserStack *pstack)
 
static bool have_prediction (JsonParserStack *pstack)
 
static void set_fname (JsonLexContext *lex, char *fname)
 
static char * get_fname (JsonLexContext *lex)
 
static void set_fnull (JsonLexContext *lex, bool fnull)
 
static bool get_fnull (JsonLexContext *lex)
 
void freeJsonLexContext (JsonLexContext *lex)
 
JsonParseErrorType pg_parse_json (JsonLexContext *lex, const JsonSemAction *sem)
 
JsonParseErrorType json_count_array_elements (JsonLexContext *lex, int *elements)
 
JsonParseErrorType pg_parse_json_incremental (JsonLexContext *lex, const JsonSemAction *sem, const char *json, size_t len, bool is_last)
 
JsonParseErrorType json_lex (JsonLexContext *lex)
 
char * json_errdetail (JsonParseErrorType error, JsonLexContext *lex)
 

Variables

static char JSON_PROD_EPSILON [] = {0}
 
static char JSON_PROD_SCALAR_STRING [] = {JSON_SEM_SCALAR_CALL, JSON_TOKEN_STRING, JSON_SEM_SCALAR_INIT, 0}
 
static char JSON_PROD_SCALAR_NUMBER [] = {JSON_SEM_SCALAR_CALL, JSON_TOKEN_NUMBER, JSON_SEM_SCALAR_INIT, 0}
 
static char JSON_PROD_SCALAR_TRUE [] = {JSON_SEM_SCALAR_CALL, JSON_TOKEN_TRUE, JSON_SEM_SCALAR_INIT, 0}
 
static char JSON_PROD_SCALAR_FALSE [] = {JSON_SEM_SCALAR_CALL, JSON_TOKEN_FALSE, JSON_SEM_SCALAR_INIT, 0}
 
static char JSON_PROD_SCALAR_NULL [] = {JSON_SEM_SCALAR_CALL, JSON_TOKEN_NULL, JSON_SEM_SCALAR_INIT, 0}
 
static char JSON_PROD_OBJECT [] = {JSON_SEM_OEND, JSON_TOKEN_OBJECT_END, JSON_NT_KEY_PAIRS, JSON_TOKEN_OBJECT_START, JSON_SEM_OSTART, 0}
 
static char JSON_PROD_ARRAY [] = {JSON_SEM_AEND, JSON_TOKEN_ARRAY_END, JSON_NT_ARRAY_ELEMENTS, JSON_TOKEN_ARRAY_START, JSON_SEM_ASTART, 0}
 
static char JSON_PROD_ARRAY_ELEMENTS [] = {JSON_NT_MORE_ARRAY_ELEMENTS, JSON_SEM_AELEM_END, JSON_NT_JSON, JSON_SEM_AELEM_START, 0}
 
static char JSON_PROD_MORE_ARRAY_ELEMENTS [] = {JSON_NT_MORE_ARRAY_ELEMENTS, JSON_SEM_AELEM_END, JSON_NT_JSON, JSON_SEM_AELEM_START, JSON_TOKEN_COMMA, 0}
 
static char JSON_PROD_KEY_PAIRS [] = {JSON_NT_MORE_KEY_PAIRS, JSON_SEM_OFIELD_END, JSON_NT_JSON, JSON_SEM_OFIELD_START, JSON_TOKEN_COLON, JSON_TOKEN_STRING, JSON_SEM_OFIELD_INIT, 0}
 
static char JSON_PROD_MORE_KEY_PAIRS [] = {JSON_NT_MORE_KEY_PAIRS, JSON_SEM_OFIELD_END, JSON_NT_JSON, JSON_SEM_OFIELD_START, JSON_TOKEN_COLON, JSON_TOKEN_STRING, JSON_SEM_OFIELD_INIT, JSON_TOKEN_COMMA, 0}
 
static td_entry td_parser_table [JSON_NUM_NONTERMINALS][JSON_NUM_TERMINALS]
 
static char JSON_PROD_GOAL [] = {JSON_TOKEN_END, JSON_NT_JSON, 0}
 
const JsonSemAction nullSemAction
 
static JsonLexContext failed_oom
 
static JsonIncrementalState failed_inc_oom
 

Macro Definition Documentation

◆ ALLOC

#define ALLOC (   size)    palloc(size)

Definition at line 57 of file jsonapi.c.

◆ ALLOC0

#define ALLOC0 (   size)    palloc0(size)

Definition at line 58 of file jsonapi.c.

◆ FAIL_AT_CHAR_END

#define FAIL_AT_CHAR_END (   code)
Value:
do { \
const char *term = s + pg_encoding_mblen(lex->input_encoding, s); \
lex->token_terminator = (term <= end) ? term : end; \
return code; \
} while (0)
int pg_encoding_mblen(int encoding, const char *mbstr)
Definition: wchar.c:2069

◆ FAIL_OR_INCOMPLETE_AT_CHAR_START

#define FAIL_OR_INCOMPLETE_AT_CHAR_START (   code)
Value:
do { \
if (lex->incremental && !lex->inc_state->is_last_chunk) \
{ \
jsonapi_appendBinaryStringInfo(&lex->inc_state->partial_token, \
lex->token_start, \
end - lex->token_start); \
return JSON_INCOMPLETE; \
} \
lex->token_terminator = s; \
return code; \
} while (0)
@ JSON_INCOMPLETE
Definition: jsonapi.h:37

◆ FREE

#define FREE (   s)
Value:
do { \
void *__v = (s); \
if (__v) \
pfree(__v); \
} while (0)

Definition at line 69 of file jsonapi.c.

◆ IS_NT

#define IS_NT (   x)    ((x) & 0x20)

Definition at line 179 of file jsonapi.c.

◆ IS_SEM

#define IS_SEM (   x)    ((x) & 0x40)

Definition at line 178 of file jsonapi.c.

◆ JS_MAX_PROD_LEN

#define JS_MAX_PROD_LEN   10 /* more than we need */

Definition at line 428 of file jsonapi.c.

◆ JS_STACK_CHUNK_SIZE

#define JS_STACK_CHUNK_SIZE   64

Definition at line 427 of file jsonapi.c.

◆ JSON_ALPHANUMERIC_CHAR

#define JSON_ALPHANUMERIC_CHAR (   c)
Value:
(((c) >= 'a' && (c) <= 'z') || \
((c) >= 'A' && (c) <= 'Z') || \
((c) >= '0' && (c) <= '9') || \
(c) == '_' || \
IS_HIGHBIT_SET(c))
char * c

Definition at line 324 of file jsonapi.c.

◆ JSON_NT_OFFSET

#define JSON_NT_OFFSET   JSON_NT_JSON

Definition at line 174 of file jsonapi.c.

◆ JSON_NUM_NONTERMINALS

#define JSON_NUM_NONTERMINALS   5

Definition at line 173 of file jsonapi.c.

◆ JSON_NUM_TERMINALS

#define JSON_NUM_TERMINALS   13

Definition at line 172 of file jsonapi.c.

◆ JSON_TD_MAX_STACK

#define JSON_TD_MAX_STACK
Value:
6400 /* hard coded for now - this is a REALLY high
* number */

Definition at line 429 of file jsonapi.c.

◆ json_token_error

#define json_token_error (   lex,
  format 
)
Value:
jsonapi_appendStringInfo((lex)->errormsg, _(format), \
(int) ((lex)->token_terminator - (lex)->token_start), \
(lex)->token_start);
#define _(x)
Definition: elog.c:90
#define jsonapi_appendStringInfo
Definition: jsonapi.c:76
static char format
char * token_start

◆ jsonapi_appendBinaryStringInfo

#define jsonapi_appendBinaryStringInfo   appendBinaryStringInfo

Definition at line 77 of file jsonapi.c.

◆ jsonapi_appendStringInfo

#define jsonapi_appendStringInfo   appendStringInfo

Definition at line 76 of file jsonapi.c.

◆ jsonapi_appendStringInfoChar

#define jsonapi_appendStringInfoChar   appendStringInfoChar

Definition at line 78 of file jsonapi.c.

◆ jsonapi_appendStringInfoCharMacro

#define jsonapi_appendStringInfoCharMacro   appendStringInfoCharMacro

Definition at line 79 of file jsonapi.c.

◆ jsonapi_destroyStringInfo

#define jsonapi_destroyStringInfo   destroyStringInfo

Definition at line 84 of file jsonapi.c.

◆ jsonapi_initStringInfo

#define jsonapi_initStringInfo   initStringInfo

Definition at line 81 of file jsonapi.c.

◆ jsonapi_makeStringInfo

#define jsonapi_makeStringInfo   makeStringInfo

Definition at line 80 of file jsonapi.c.

◆ jsonapi_resetStringInfo

#define jsonapi_resetStringInfo   resetStringInfo

Definition at line 82 of file jsonapi.c.

◆ jsonapi_termStringInfo

#define jsonapi_termStringInfo (   s)    pfree((s)->data)

Definition at line 83 of file jsonapi.c.

◆ OFS

#define OFS (   NT)    (NT) - JSON_NT_OFFSET

Definition at line 176 of file jsonapi.c.

◆ REALLOC

#define REALLOC   repalloc

Definition at line 59 of file jsonapi.c.

◆ STRDUP

#define STRDUP (   s)    pstrdup(s)

Definition at line 56 of file jsonapi.c.

◆ TD_ENTRY

#define TD_ENTRY (   PROD)    { sizeof(PROD) - 1, (PROD) }

Definition at line 238 of file jsonapi.c.

Enumeration Type Documentation

◆ JsonNonTerminal

Enumerator
JSON_NT_JSON 
JSON_NT_ARRAY_ELEMENTS 
JSON_NT_MORE_ARRAY_ELEMENTS 
JSON_NT_KEY_PAIRS 
JSON_NT_MORE_KEY_PAIRS 

Definition at line 113 of file jsonapi.c.

114 {
115  JSON_NT_JSON = 32,
120 };
@ JSON_NT_JSON
Definition: jsonapi.c:115
@ JSON_NT_MORE_ARRAY_ELEMENTS
Definition: jsonapi.c:117
@ JSON_NT_MORE_KEY_PAIRS
Definition: jsonapi.c:119
@ JSON_NT_ARRAY_ELEMENTS
Definition: jsonapi.c:116
@ JSON_NT_KEY_PAIRS
Definition: jsonapi.c:118

◆ JsonParseContext

Enumerator
JSON_PARSE_VALUE 
JSON_PARSE_STRING 
JSON_PARSE_ARRAY_START 
JSON_PARSE_ARRAY_NEXT 
JSON_PARSE_OBJECT_START 
JSON_PARSE_OBJECT_LABEL 
JSON_PARSE_OBJECT_NEXT 
JSON_PARSE_OBJECT_COMMA 
JSON_PARSE_END 

Definition at line 93 of file jsonapi.c.

94 {
95  JSON_PARSE_VALUE, /* expecting a value */
96  JSON_PARSE_STRING, /* expecting a string (for a field name) */
97  JSON_PARSE_ARRAY_START, /* saw '[', expecting value or ']' */
98  JSON_PARSE_ARRAY_NEXT, /* saw array element, expecting ',' or ']' */
99  JSON_PARSE_OBJECT_START, /* saw '{', expecting label or '}' */
100  JSON_PARSE_OBJECT_LABEL, /* saw object label, expecting ':' */
101  JSON_PARSE_OBJECT_NEXT, /* saw object value, expecting ',' or '}' */
102  JSON_PARSE_OBJECT_COMMA, /* saw object ',', expecting next label */
103  JSON_PARSE_END, /* saw the end of a document, expect nothing */
JsonParseContext
Definition: jsonapi.c:94
@ JSON_PARSE_OBJECT_LABEL
Definition: jsonapi.c:100
@ JSON_PARSE_VALUE
Definition: jsonapi.c:95
@ JSON_PARSE_OBJECT_START
Definition: jsonapi.c:99
@ JSON_PARSE_ARRAY_START
Definition: jsonapi.c:97
@ JSON_PARSE_END
Definition: jsonapi.c:103
@ JSON_PARSE_OBJECT_NEXT
Definition: jsonapi.c:101
@ JSON_PARSE_ARRAY_NEXT
Definition: jsonapi.c:98
@ JSON_PARSE_OBJECT_COMMA
Definition: jsonapi.c:102
@ JSON_PARSE_STRING
Definition: jsonapi.c:96

◆ JsonParserSem

Enumerator
JSON_SEM_OSTART 
JSON_SEM_OEND 
JSON_SEM_ASTART 
JSON_SEM_AEND 
JSON_SEM_OFIELD_INIT 
JSON_SEM_OFIELD_START 
JSON_SEM_OFIELD_END 
JSON_SEM_AELEM_START 
JSON_SEM_AELEM_END 
JSON_SEM_SCALAR_INIT 
JSON_SEM_SCALAR_CALL 

Definition at line 122 of file jsonapi.c.

123 {
124  JSON_SEM_OSTART = 64,
135 };
@ JSON_SEM_SCALAR_CALL
Definition: jsonapi.c:134
@ JSON_SEM_OSTART
Definition: jsonapi.c:124
@ JSON_SEM_AELEM_START
Definition: jsonapi.c:131
@ JSON_SEM_AELEM_END
Definition: jsonapi.c:132
@ JSON_SEM_SCALAR_INIT
Definition: jsonapi.c:133
@ JSON_SEM_ASTART
Definition: jsonapi.c:126
@ JSON_SEM_OFIELD_INIT
Definition: jsonapi.c:128
@ JSON_SEM_OFIELD_END
Definition: jsonapi.c:130
@ JSON_SEM_OEND
Definition: jsonapi.c:125
@ JSON_SEM_OFIELD_START
Definition: jsonapi.c:129
@ JSON_SEM_AEND
Definition: jsonapi.c:127

Function Documentation

◆ allocate_incremental_state()

static bool allocate_incremental_state ( JsonLexContext lex)
static

Definition at line 431 of file jsonapi.c.

433 {
434  void *pstack,
435  *prediction,
436  *fnames,
437  *fnull;
438 
439  lex->inc_state = ALLOC0(sizeof(JsonIncrementalState));
440  pstack = ALLOC(sizeof(JsonParserStack));
441  prediction = ALLOC(JS_STACK_CHUNK_SIZE * JS_MAX_PROD_LEN);
442  fnames = ALLOC(JS_STACK_CHUNK_SIZE * sizeof(char *));
443  fnull = ALLOC(JS_STACK_CHUNK_SIZE * sizeof(bool));
444 
445 #ifdef JSONAPI_USE_PQEXPBUFFER
446  if (!lex->inc_state
447  || !pstack
448  || !prediction
449  || !fnames
450  || !fnull)
451  {
452  FREE(lex->inc_state);
453  FREE(pstack);
454  FREE(prediction);
455  FREE(fnames);
456  FREE(fnull);
457 
458  lex->inc_state = &failed_inc_oom;
459  return false;
460  }
461 #endif
462 
464  lex->pstack = pstack;
466  lex->pstack->prediction = prediction;
467  lex->pstack->pred_index = 0;
468  lex->pstack->fnames = fnames;
469  lex->pstack->fnull = fnull;
470 
471  lex->incremental = true;
472  return true;
#define JS_MAX_PROD_LEN
Definition: jsonapi.c:428
#define ALLOC0(size)
Definition: jsonapi.c:58
#define jsonapi_initStringInfo
Definition: jsonapi.c:81
#define JS_STACK_CHUNK_SIZE
Definition: jsonapi.c:427
static JsonIncrementalState failed_inc_oom
Definition: jsonapi.c:293
#define ALLOC(size)
Definition: jsonapi.c:57
#define FREE(s)
Definition: jsonapi.c:69
jsonapi_StrValType partial_token
Definition: jsonapi.c:166
JsonParserStack * pstack
Definition: jsonapi.h:112
JsonIncrementalState * inc_state
Definition: jsonapi.h:113
bool incremental
Definition: jsonapi.h:106
bool * fnull
Definition: jsonapi.c:151
char * prediction
Definition: jsonapi.c:147
size_t pred_index
Definition: jsonapi.c:148
char ** fnames
Definition: jsonapi.c:150

References ALLOC, ALLOC0, failed_inc_oom, JsonParserStack::fnames, JsonParserStack::fnull, FREE, JsonLexContext::inc_state, JsonLexContext::incremental, JS_MAX_PROD_LEN, JS_STACK_CHUNK_SIZE, jsonapi_initStringInfo, JsonIncrementalState::partial_token, JsonParserStack::pred_index, JsonParserStack::prediction, JsonLexContext::pstack, and JsonParserStack::stack_size.

Referenced by makeJsonLexContextIncremental(), and pg_parse_json().

◆ dec_lex_level()

static void dec_lex_level ( JsonLexContext lex)
inlinestatic

Definition at line 575 of file jsonapi.c.

577 {
578  lex->lex_level -= 1;

References JsonLexContext::lex_level.

Referenced by pg_parse_json_incremental().

◆ freeJsonLexContext()

void freeJsonLexContext ( JsonLexContext lex)

Definition at line 639 of file jsonapi.c.

641 {
642  static const JsonLexContext empty = {0};
643 
644  if (!lex || lex == &failed_oom)
645  return;
646 
647  if (lex->flags & JSONLEX_FREE_STRVAL)
649 
650  if (lex->errormsg)
652 
653  if (lex->incremental)
654  {
656  FREE(lex->inc_state);
657  FREE(lex->pstack->prediction);
658  FREE(lex->pstack->fnames);
659  FREE(lex->pstack->fnull);
660  FREE(lex->pstack);
661  }
662 
663  if (lex->flags & JSONLEX_FREE_STRUCT)
664  FREE(lex);
665  else
666  *lex = empty;
#define jsonapi_destroyStringInfo
Definition: jsonapi.c:84
static JsonLexContext failed_oom
Definition: jsonapi.c:292
#define jsonapi_termStringInfo(s)
Definition: jsonapi.c:83
#define JSONLEX_FREE_STRVAL
Definition: jsonapi.h:97
#define JSONLEX_FREE_STRUCT
Definition: jsonapi.h:96
bits32 flags
Definition: jsonapi.h:109
struct jsonapi_StrValType * strval
Definition: jsonapi.h:115
struct jsonapi_StrValType * errormsg
Definition: jsonapi.h:116

References JsonLexContext::errormsg, failed_oom, JsonLexContext::flags, JsonParserStack::fnames, JsonParserStack::fnull, FREE, JsonLexContext::inc_state, JsonLexContext::incremental, jsonapi_destroyStringInfo, jsonapi_termStringInfo, JSONLEX_FREE_STRUCT, JSONLEX_FREE_STRVAL, JsonIncrementalState::partial_token, JsonParserStack::prediction, JsonLexContext::pstack, and JsonLexContext::strval.

Referenced by datum_to_jsonb_internal(), each_worker(), elements_worker(), get_json_object_as_hash(), get_worker(), iterate_json_values(), json_object_keys(), json_parse_manifest(), json_parse_manifest_incremental_shutdown(), json_validate(), main(), populate_array_json(), populate_recordset_worker(), and transform_json_string_values().

◆ get_fname()

static char* get_fname ( JsonLexContext lex)
inlinestatic

Definition at line 614 of file jsonapi.c.

616 {
617  return lex->pstack->fnames[lex->lex_level];

References JsonParserStack::fnames, JsonLexContext::lex_level, and JsonLexContext::pstack.

Referenced by pg_parse_json_incremental().

◆ get_fnull()

static bool get_fnull ( JsonLexContext lex)
inlinestatic

Definition at line 626 of file jsonapi.c.

628 {
629  return lex->pstack->fnull[lex->lex_level];

References JsonParserStack::fnull, JsonLexContext::lex_level, and JsonLexContext::pstack.

Referenced by pg_parse_json_incremental().

◆ have_prediction()

static bool have_prediction ( JsonParserStack pstack)
inlinestatic

Definition at line 602 of file jsonapi.c.

604 {
605  return pstack->pred_index > 0;

References JsonParserStack::pred_index.

Referenced by pg_parse_json_incremental().

◆ inc_lex_level()

static bool inc_lex_level ( JsonLexContext lex)
inlinestatic

Definition at line 533 of file jsonapi.c.

535 {
536  if (lex->incremental && (lex->lex_level + 1) >= lex->pstack->stack_size)
537  {
538  size_t new_stack_size;
539  char *new_prediction;
540  char **new_fnames;
541  bool *new_fnull;
542 
543  new_stack_size = lex->pstack->stack_size + JS_STACK_CHUNK_SIZE;
544 
545  new_prediction = REALLOC(lex->pstack->prediction,
546  new_stack_size * JS_MAX_PROD_LEN);
547 #ifdef JSONAPI_USE_PQEXPBUFFER
548  if (!new_prediction)
549  return false;
550 #endif
551  lex->pstack->prediction = new_prediction;
552 
553  new_fnames = REALLOC(lex->pstack->fnames,
554  new_stack_size * sizeof(char *));
555 #ifdef JSONAPI_USE_PQEXPBUFFER
556  if (!new_fnames)
557  return false;
558 #endif
559  lex->pstack->fnames = new_fnames;
560 
561  new_fnull = REALLOC(lex->pstack->fnull, new_stack_size * sizeof(bool));
562 #ifdef JSONAPI_USE_PQEXPBUFFER
563  if (!new_fnull)
564  return false;
565 #endif
566  lex->pstack->fnull = new_fnull;
567 
568  lex->pstack->stack_size = new_stack_size;
569  }
570 
571  lex->lex_level += 1;
572  return true;
#define REALLOC
Definition: jsonapi.c:59

References JsonParserStack::fnames, JsonParserStack::fnull, JsonLexContext::incremental, JS_MAX_PROD_LEN, JS_STACK_CHUNK_SIZE, JsonLexContext::lex_level, JsonParserStack::prediction, JsonLexContext::pstack, REALLOC, and JsonParserStack::stack_size.

Referenced by pg_parse_json_incremental().

◆ IsValidJsonNumber()

bool IsValidJsonNumber ( const char *  str,
size_t  len 
)

Definition at line 337 of file jsonapi.c.

338 {
339  bool numeric_error;
340  size_t total_len;
341  JsonLexContext dummy_lex = {0};
342 
343  if (len <= 0)
344  return false;
345 
346  /*
347  * json_lex_number expects a leading '-' to have been eaten already.
348  *
349  * having to cast away the constness of str is ugly, but there's not much
350  * easy alternative.
351  */
352  if (*str == '-')
353  {
354  dummy_lex.input = str + 1;
355  dummy_lex.input_length = len - 1;
356  }
357  else
358  {
359  dummy_lex.input = str;
360  dummy_lex.input_length = len;
361  }
362 
363  dummy_lex.token_start = dummy_lex.input;
364 
365  json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error, &total_len);
366 
367  return (!numeric_error) && (total_len == dummy_lex.input_length);
368 }
const char * str
static JsonParseErrorType json_lex_number(JsonLexContext *lex, const char *s, bool *num_err, size_t *total_len)
Definition: jsonapi.c:2157
const void size_t len
const char * input
Definition: jsonapi.h:100
const char * token_start
Definition: jsonapi.h:103
size_t input_length
Definition: jsonapi.h:101

References JsonLexContext::input, JsonLexContext::input_length, json_lex_number(), len, str, and JsonLexContext::token_start.

Referenced by hstore_to_json_loose(), and hstore_to_jsonb_loose().

◆ json_count_array_elements()

JsonParseErrorType json_count_array_elements ( JsonLexContext lex,
int *  elements 
)

Definition at line 744 of file jsonapi.c.

746 {
747  JsonLexContext copylex;
748  int count;
749  JsonParseErrorType result;
750 
751  if (lex == &failed_oom)
752  return JSON_OUT_OF_MEMORY;
753 
754  /*
755  * It's safe to do this with a shallow copy because the lexical routines
756  * don't scribble on the input. They do scribble on the other pointers
757  * etc, so doing this with a copy makes that safe.
758  */
759  memcpy(&copylex, lex, sizeof(JsonLexContext));
760  copylex.need_escapes = false; /* not interested in values here */
761  copylex.lex_level++;
762 
763  count = 0;
764  result = lex_expect(JSON_PARSE_ARRAY_START, &copylex,
766  if (result != JSON_SUCCESS)
767  return result;
768  if (lex_peek(&copylex) != JSON_TOKEN_ARRAY_END)
769  {
770  while (1)
771  {
772  count++;
773  result = parse_array_element(&copylex, &nullSemAction);
774  if (result != JSON_SUCCESS)
775  return result;
776  if (copylex.token_type != JSON_TOKEN_COMMA)
777  break;
778  result = json_lex(&copylex);
779  if (result != JSON_SUCCESS)
780  return result;
781  }
782  }
783  result = lex_expect(JSON_PARSE_ARRAY_NEXT, &copylex,
785  if (result != JSON_SUCCESS)
786  return result;
787 
788  *elements = count;
789  return JSON_SUCCESS;
static JsonTokenType lex_peek(JsonLexContext *lex)
Definition: jsonapi.c:303
static JsonParseErrorType lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
Definition: jsonapi.c:315
const JsonSemAction nullSemAction
Definition: jsonapi.c:285
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:1498
static JsonParseErrorType parse_array_element(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1377
JsonParseErrorType
Definition: jsonapi.h:35
@ JSON_OUT_OF_MEMORY
Definition: jsonapi.h:52
@ JSON_SUCCESS
Definition: jsonapi.h:36
@ JSON_TOKEN_COMMA
Definition: jsonapi.h:26
@ JSON_TOKEN_ARRAY_END
Definition: jsonapi.h:25
@ JSON_TOKEN_ARRAY_START
Definition: jsonapi.h:24
bool need_escapes
Definition: jsonapi.h:114
JsonTokenType token_type
Definition: jsonapi.h:107

References failed_oom, json_lex(), JSON_OUT_OF_MEMORY, JSON_PARSE_ARRAY_NEXT, JSON_PARSE_ARRAY_START, JSON_SUCCESS, JSON_TOKEN_ARRAY_END, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COMMA, lex_expect(), JsonLexContext::lex_level, lex_peek(), JsonLexContext::need_escapes, nullSemAction, parse_array_element(), and JsonLexContext::token_type.

Referenced by get_array_start().

◆ json_errdetail()

char* json_errdetail ( JsonParseErrorType  error,
JsonLexContext lex 
)

Definition at line 2311 of file jsonapi.c.

2313 {
2314  if (error == JSON_OUT_OF_MEMORY || lex == &failed_oom)
2315  {
2316  /* Short circuit. Allocating anything for this case is unhelpful. */
2317  return _("out of memory");
2318  }
2319 
2320  if (lex->errormsg)
2322  else
2324 
2325  /*
2326  * A helper for error messages that should print the current token. The
2327  * format must contain exactly one %.*s specifier.
2328  */
2329 #define json_token_error(lex, format) \
2330  jsonapi_appendStringInfo((lex)->errormsg, _(format), \
2331  (int) ((lex)->token_terminator - (lex)->token_start), \
2332  (lex)->token_start);
2333 
2334  switch (error)
2335  {
2336  case JSON_INCOMPLETE:
2337  case JSON_SUCCESS:
2338  /* fall through to the error code after switch */
2339  break;
2341  if (lex->incremental)
2342  return _("Recursive descent parser cannot use incremental lexer.");
2343  else
2344  return _("Incremental parser requires incremental lexer.");
2345  case JSON_NESTING_TOO_DEEP:
2346  return (_("JSON nested too deep, maximum permitted depth is 6400."));
2347  case JSON_ESCAPING_INVALID:
2348  json_token_error(lex, "Escape sequence \"\\%.*s\" is invalid.");
2349  break;
2352  _("Character with value 0x%02x must be escaped."),
2353  (unsigned char) *(lex->token_terminator));
2354  break;
2355  case JSON_EXPECTED_END:
2356  json_token_error(lex, "Expected end of input, but found \"%.*s\".");
2357  break;
2359  json_token_error(lex, "Expected array element or \"]\", but found \"%.*s\".");
2360  break;
2362  json_token_error(lex, "Expected \",\" or \"]\", but found \"%.*s\".");
2363  break;
2364  case JSON_EXPECTED_COLON:
2365  json_token_error(lex, "Expected \":\", but found \"%.*s\".");
2366  break;
2367  case JSON_EXPECTED_JSON:
2368  json_token_error(lex, "Expected JSON value, but found \"%.*s\".");
2369  break;
2370  case JSON_EXPECTED_MORE:
2371  return _("The input string ended unexpectedly.");
2373  json_token_error(lex, "Expected string or \"}\", but found \"%.*s\".");
2374  break;
2376  json_token_error(lex, "Expected \",\" or \"}\", but found \"%.*s\".");
2377  break;
2378  case JSON_EXPECTED_STRING:
2379  json_token_error(lex, "Expected string, but found \"%.*s\".");
2380  break;
2381  case JSON_INVALID_TOKEN:
2382  json_token_error(lex, "Token \"%.*s\" is invalid.");
2383  break;
2384  case JSON_OUT_OF_MEMORY:
2385  /* should have been handled above; use the error path */
2386  break;
2388  return _("\\u0000 cannot be converted to text.");
2390  return _("\"\\u\" must be followed by four hexadecimal digits.");
2392  /* note: this case is only reachable in frontend not backend */
2393  return _("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8.");
2395 
2396  /*
2397  * Note: this case is only reachable in backend and not frontend.
2398  * #ifdef it away so the frontend doesn't try to link against
2399  * backend functionality.
2400  */
2401 #ifndef FRONTEND
2402  return psprintf(_("Unicode escape value could not be translated to the server's encoding %s."),
2404 #else
2405  Assert(false);
2406  break;
2407 #endif
2409  return _("Unicode high surrogate must not follow a high surrogate.");
2411  return _("Unicode low surrogate must follow a high surrogate.");
2413  /* fall through to the error code after switch */
2414  break;
2415  }
2416 #undef json_token_error
2417 
2418  /* Note that lex->errormsg can be NULL in shlib code. */
2419  if (lex->errormsg && lex->errormsg->len == 0)
2420  {
2421  /*
2422  * We don't use a default: case, so that the compiler will warn about
2423  * unhandled enum values. But this needs to be here anyway to cover
2424  * the possibility of an incorrect input.
2425  */
2427  "unexpected json parse error type: %d",
2428  (int) error);
2429  }
2430 
2431 #ifdef JSONAPI_USE_PQEXPBUFFER
2432  if (PQExpBufferBroken(lex->errormsg))
2433  return _("out of memory while constructing error description");
2434 #endif
2435 
2436  return lex->errormsg->data;
#define Assert(condition)
Definition: c.h:863
#define json_token_error(lex, format)
#define jsonapi_makeStringInfo
Definition: jsonapi.c:80
#define jsonapi_resetStringInfo
Definition: jsonapi.c:82
@ JSON_SEM_ACTION_FAILED
Definition: jsonapi.h:59
@ JSON_EXPECTED_ARRAY_FIRST
Definition: jsonapi.h:42
@ JSON_EXPECTED_MORE
Definition: jsonapi.h:47
@ JSON_UNICODE_HIGH_SURROGATE
Definition: jsonapi.h:57
@ JSON_EXPECTED_COLON
Definition: jsonapi.h:44
@ JSON_EXPECTED_OBJECT_FIRST
Definition: jsonapi.h:48
@ JSON_UNICODE_CODE_POINT_ZERO
Definition: jsonapi.h:53
@ JSON_INVALID_LEXER_TYPE
Definition: jsonapi.h:38
@ JSON_EXPECTED_STRING
Definition: jsonapi.h:50
@ JSON_UNICODE_ESCAPE_FORMAT
Definition: jsonapi.h:54
@ JSON_UNICODE_UNTRANSLATABLE
Definition: jsonapi.h:56
@ JSON_EXPECTED_OBJECT_NEXT
Definition: jsonapi.h:49
@ JSON_ESCAPING_REQUIRED
Definition: jsonapi.h:41
@ JSON_EXPECTED_JSON
Definition: jsonapi.h:46
@ JSON_INVALID_TOKEN
Definition: jsonapi.h:51
@ JSON_ESCAPING_INVALID
Definition: jsonapi.h:40
@ JSON_EXPECTED_END
Definition: jsonapi.h:45
@ JSON_EXPECTED_ARRAY_NEXT
Definition: jsonapi.h:43
@ JSON_UNICODE_HIGH_ESCAPE
Definition: jsonapi.h:55
@ JSON_NESTING_TOO_DEEP
Definition: jsonapi.h:39
@ JSON_UNICODE_LOW_SURROGATE
Definition: jsonapi.h:58
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1267
#define PQExpBufferBroken(str)
Definition: pqexpbuffer.h:59
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
static void error(void)
Definition: sql-dyntest.c:147
const char * token_terminator
Definition: jsonapi.h:104

References _, Assert, error(), JsonLexContext::errormsg, failed_oom, GetDatabaseEncodingName(), JsonLexContext::incremental, JSON_ESCAPING_INVALID, JSON_ESCAPING_REQUIRED, JSON_EXPECTED_ARRAY_FIRST, JSON_EXPECTED_ARRAY_NEXT, JSON_EXPECTED_COLON, JSON_EXPECTED_END, JSON_EXPECTED_JSON, JSON_EXPECTED_MORE, JSON_EXPECTED_OBJECT_FIRST, JSON_EXPECTED_OBJECT_NEXT, JSON_EXPECTED_STRING, JSON_INCOMPLETE, JSON_INVALID_LEXER_TYPE, JSON_INVALID_TOKEN, JSON_NESTING_TOO_DEEP, JSON_OUT_OF_MEMORY, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, json_token_error, JSON_UNICODE_CODE_POINT_ZERO, JSON_UNICODE_ESCAPE_FORMAT, JSON_UNICODE_HIGH_ESCAPE, JSON_UNICODE_HIGH_SURROGATE, JSON_UNICODE_LOW_SURROGATE, JSON_UNICODE_UNTRANSLATABLE, jsonapi_appendStringInfo, jsonapi_makeStringInfo, jsonapi_resetStringInfo, PQExpBufferBroken, psprintf(), and JsonLexContext::token_terminator.

Referenced by json_errsave_error(), json_parse_manifest(), json_parse_manifest_incremental_chunk(), and main().

◆ json_lex()

JsonParseErrorType json_lex ( JsonLexContext lex)

Definition at line 1498 of file jsonapi.c.

1500 {
1501  const char *s;
1502  const char *const end = lex->input + lex->input_length;
1503  JsonParseErrorType result;
1504 
1505  if (lex == &failed_oom || lex->inc_state == &failed_inc_oom)
1506  return JSON_OUT_OF_MEMORY;
1507 
1508  if (lex->incremental)
1509  {
1510  if (lex->inc_state->partial_completed)
1511  {
1512  /*
1513  * We just lexed a completed partial token on the last call, so
1514  * reset everything
1515  */
1517  lex->token_terminator = lex->input;
1518  lex->inc_state->partial_completed = false;
1519  }
1520 
1521 #ifdef JSONAPI_USE_PQEXPBUFFER
1522  /* Make sure our partial token buffer is valid before using it below. */
1524  return JSON_OUT_OF_MEMORY;
1525 #endif
1526  }
1527 
1528  s = lex->token_terminator;
1529 
1530  if (lex->incremental && lex->inc_state->partial_token.len)
1531  {
1532  /*
1533  * We have a partial token. Extend it and if completed lex it by a
1534  * recursive call
1535  */
1536  jsonapi_StrValType *ptok = &(lex->inc_state->partial_token);
1537  size_t added = 0;
1538  bool tok_done = false;
1539  JsonLexContext dummy_lex = {0};
1540  JsonParseErrorType partial_result;
1541 
1542  if (ptok->data[0] == '"')
1543  {
1544  /*
1545  * It's a string. Accumulate characters until we reach an
1546  * unescaped '"'.
1547  */
1548  int escapes = 0;
1549 
1550  for (int i = ptok->len - 1; i > 0; i--)
1551  {
1552  /* count the trailing backslashes on the partial token */
1553  if (ptok->data[i] == '\\')
1554  escapes++;
1555  else
1556  break;
1557  }
1558 
1559  for (size_t i = 0; i < lex->input_length; i++)
1560  {
1561  char c = lex->input[i];
1562 
1564  added++;
1565  if (c == '"' && escapes % 2 == 0)
1566  {
1567  tok_done = true;
1568  break;
1569  }
1570  if (c == '\\')
1571  escapes++;
1572  else
1573  escapes = 0;
1574  }
1575  }
1576  else
1577  {
1578  /* not a string */
1579  char c = ptok->data[0];
1580 
1581  if (c == '-' || (c >= '0' && c <= '9'))
1582  {
1583  /* for numbers look for possible numeric continuations */
1584 
1585  bool numend = false;
1586 
1587  for (size_t i = 0; i < lex->input_length && !numend; i++)
1588  {
1589  char cc = lex->input[i];
1590 
1591  switch (cc)
1592  {
1593  case '+':
1594  case '-':
1595  case 'e':
1596  case 'E':
1597  case '0':
1598  case '1':
1599  case '2':
1600  case '3':
1601  case '4':
1602  case '5':
1603  case '6':
1604  case '7':
1605  case '8':
1606  case '9':
1607  {
1609  added++;
1610  }
1611  break;
1612  default:
1613  numend = true;
1614  }
1615  }
1616  }
1617 
1618  /*
1619  * Add any remaining alphanumeric chars. This takes care of the
1620  * {null, false, true} literals as well as any trailing
1621  * alphanumeric junk on non-string tokens.
1622  */
1623  for (size_t i = added; i < lex->input_length; i++)
1624  {
1625  char cc = lex->input[i];
1626 
1627  if (JSON_ALPHANUMERIC_CHAR(cc))
1628  {
1630  added++;
1631  }
1632  else
1633  {
1634  tok_done = true;
1635  break;
1636  }
1637  }
1638  if (added == lex->input_length &&
1639  lex->inc_state->is_last_chunk)
1640  {
1641  tok_done = true;
1642  }
1643  }
1644 
1645  if (!tok_done)
1646  {
1647  /* We should have consumed the whole chunk in this case. */
1648  Assert(added == lex->input_length);
1649 
1650  if (!lex->inc_state->is_last_chunk)
1651  return JSON_INCOMPLETE;
1652 
1653  /* json_errdetail() needs access to the accumulated token. */
1654  lex->token_start = ptok->data;
1655  lex->token_terminator = ptok->data + ptok->len;
1656  return JSON_INVALID_TOKEN;
1657  }
1658 
1659  /*
1660  * Everything up to lex->input[added] has been added to the partial
1661  * token, so move the input past it.
1662  */
1663  lex->input += added;
1664  lex->input_length -= added;
1665 
1666  dummy_lex.input = dummy_lex.token_terminator =
1667  dummy_lex.line_start = ptok->data;
1668  dummy_lex.line_number = lex->line_number;
1669  dummy_lex.input_length = ptok->len;
1670  dummy_lex.input_encoding = lex->input_encoding;
1671  dummy_lex.incremental = false;
1672  dummy_lex.need_escapes = lex->need_escapes;
1673  dummy_lex.strval = lex->strval;
1674 
1675  partial_result = json_lex(&dummy_lex);
1676 
1677  /*
1678  * We either have a complete token or an error. In either case we need
1679  * to point to the partial token data for the semantic or error
1680  * routines. If it's not an error we'll readjust on the next call to
1681  * json_lex.
1682  */
1683  lex->token_type = dummy_lex.token_type;
1684  lex->line_number = dummy_lex.line_number;
1685 
1686  /*
1687  * We know the prev_token_terminator must be back in some previous
1688  * piece of input, so we just make it NULL.
1689  */
1690  lex->prev_token_terminator = NULL;
1691 
1692  /*
1693  * Normally token_start would be ptok->data, but it could be later,
1694  * see json_lex_string's handling of invalid escapes.
1695  */
1696  lex->token_start = dummy_lex.token_start;
1697  lex->token_terminator = dummy_lex.token_terminator;
1698  if (partial_result == JSON_SUCCESS)
1699  {
1700  /* make sure we've used all the input */
1701  if (lex->token_terminator - lex->token_start != ptok->len)
1702  {
1703  Assert(false);
1704  return JSON_INVALID_TOKEN;
1705  }
1706 
1707  lex->inc_state->partial_completed = true;
1708  }
1709  return partial_result;
1710  /* end of partial token processing */
1711  }
1712 
1713  /* Skip leading whitespace. */
1714  while (s < end && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
1715  {
1716  if (*s++ == '\n')
1717  {
1718  ++lex->line_number;
1719  lex->line_start = s;
1720  }
1721  }
1722  lex->token_start = s;
1723 
1724  /* Determine token type. */
1725  if (s >= end)
1726  {
1727  lex->token_start = NULL;
1729  lex->token_terminator = s;
1730  lex->token_type = JSON_TOKEN_END;
1731  }
1732  else
1733  {
1734  switch (*s)
1735  {
1736  /* Single-character token, some kind of punctuation mark. */
1737  case '{':
1739  lex->token_terminator = s + 1;
1741  break;
1742  case '}':
1744  lex->token_terminator = s + 1;
1746  break;
1747  case '[':
1749  lex->token_terminator = s + 1;
1751  break;
1752  case ']':
1754  lex->token_terminator = s + 1;
1756  break;
1757  case ',':
1759  lex->token_terminator = s + 1;
1761  break;
1762  case ':':
1764  lex->token_terminator = s + 1;
1766  break;
1767  case '"':
1768  /* string */
1769  result = json_lex_string(lex);
1770  if (result != JSON_SUCCESS)
1771  return result;
1773  break;
1774  case '-':
1775  /* Negative number. */
1776  result = json_lex_number(lex, s + 1, NULL, NULL);
1777  if (result != JSON_SUCCESS)
1778  return result;
1780  break;
1781  case '0':
1782  case '1':
1783  case '2':
1784  case '3':
1785  case '4':
1786  case '5':
1787  case '6':
1788  case '7':
1789  case '8':
1790  case '9':
1791  /* Positive number. */
1792  result = json_lex_number(lex, s, NULL, NULL);
1793  if (result != JSON_SUCCESS)
1794  return result;
1796  break;
1797  default:
1798  {
1799  const char *p;
1800 
1801  /*
1802  * We're not dealing with a string, number, legal
1803  * punctuation mark, or end of string. The only legal
1804  * tokens we might find here are true, false, and null,
1805  * but for error reporting purposes we scan until we see a
1806  * non-alphanumeric character. That way, we can report
1807  * the whole word as an unexpected token, rather than just
1808  * some unintuitive prefix thereof.
1809  */
1810  for (p = s; p < end && JSON_ALPHANUMERIC_CHAR(*p); p++)
1811  /* skip */ ;
1812 
1813  /*
1814  * We got some sort of unexpected punctuation or an
1815  * otherwise unexpected character, so just complain about
1816  * that one character.
1817  */
1818  if (p == s)
1819  {
1821  lex->token_terminator = s + 1;
1822  return JSON_INVALID_TOKEN;
1823  }
1824 
1825  if (lex->incremental && !lex->inc_state->is_last_chunk &&
1826  p == lex->input + lex->input_length)
1827  {
1829  return JSON_INCOMPLETE;
1830  }
1831 
1832  /*
1833  * We've got a real alphanumeric token here. If it
1834  * happens to be true, false, or null, all is well. If
1835  * not, error out.
1836  */
1838  lex->token_terminator = p;
1839  if (p - s == 4)
1840  {
1841  if (memcmp(s, "true", 4) == 0)
1842  lex->token_type = JSON_TOKEN_TRUE;
1843  else if (memcmp(s, "null", 4) == 0)
1844  lex->token_type = JSON_TOKEN_NULL;
1845  else
1846  return JSON_INVALID_TOKEN;
1847  }
1848  else if (p - s == 5 && memcmp(s, "false", 5) == 0)
1850  else
1851  return JSON_INVALID_TOKEN;
1852  }
1853  } /* end of switch */
1854  }
1855 
1856  if (lex->incremental && lex->token_type == JSON_TOKEN_END && !lex->inc_state->is_last_chunk)
1857  return JSON_INCOMPLETE;
1858  else
1859  return JSON_SUCCESS;
int i
Definition: isn.c:72
static JsonParseErrorType json_lex_string(JsonLexContext *lex)
Definition: jsonapi.c:1873
#define JSON_ALPHANUMERIC_CHAR(c)
Definition: jsonapi.c:324
#define jsonapi_appendStringInfoCharMacro
Definition: jsonapi.c:79
#define jsonapi_appendBinaryStringInfo
Definition: jsonapi.c:77
#define jsonapi_StrValType
Definition: jsonapi.h:73
@ JSON_TOKEN_FALSE
Definition: jsonapi.h:29
@ JSON_TOKEN_END
Definition: jsonapi.h:31
@ JSON_TOKEN_TRUE
Definition: jsonapi.h:28
@ JSON_TOKEN_OBJECT_END
Definition: jsonapi.h:23
@ JSON_TOKEN_NULL
Definition: jsonapi.h:30
@ JSON_TOKEN_OBJECT_START
Definition: jsonapi.h:22
@ JSON_TOKEN_NUMBER
Definition: jsonapi.h:21
@ JSON_TOKEN_STRING
Definition: jsonapi.h:20
@ JSON_TOKEN_COLON
Definition: jsonapi.h:27
#define PQExpBufferDataBroken(buf)
Definition: pqexpbuffer.h:67
int input_encoding
Definition: jsonapi.h:102
const char * prev_token_terminator
Definition: jsonapi.h:105
const char * line_start
Definition: jsonapi.h:111
int line_number
Definition: jsonapi.h:110

References Assert, failed_inc_oom, failed_oom, i, JsonLexContext::inc_state, JsonLexContext::incremental, JsonLexContext::input, JsonLexContext::input_encoding, JsonLexContext::input_length, JsonIncrementalState::is_last_chunk, JSON_ALPHANUMERIC_CHAR, JSON_INCOMPLETE, JSON_INVALID_TOKEN, json_lex_number(), json_lex_string(), JSON_OUT_OF_MEMORY, JSON_SUCCESS, JSON_TOKEN_ARRAY_END, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COLON, JSON_TOKEN_COMMA, JSON_TOKEN_END, JSON_TOKEN_FALSE, JSON_TOKEN_NULL, JSON_TOKEN_NUMBER, JSON_TOKEN_OBJECT_END, JSON_TOKEN_OBJECT_START, JSON_TOKEN_STRING, JSON_TOKEN_TRUE, jsonapi_appendBinaryStringInfo, jsonapi_appendStringInfoCharMacro, jsonapi_resetStringInfo, jsonapi_StrValType, JsonLexContext::line_number, JsonLexContext::line_start, JsonLexContext::need_escapes, JsonIncrementalState::partial_completed, JsonIncrementalState::partial_token, PQExpBufferDataBroken, JsonLexContext::prev_token_terminator, JsonLexContext::strval, JsonLexContext::token_start, JsonLexContext::token_terminator, and JsonLexContext::token_type.

Referenced by json_count_array_elements(), json_get_first_token(), json_typeof(), lex_expect(), parse_array(), parse_object(), parse_object_field(), parse_scalar(), pg_parse_json(), and pg_parse_json_incremental().

◆ json_lex_number()

static JsonParseErrorType json_lex_number ( JsonLexContext lex,
const char *  s,
bool num_err,
size_t *  total_len 
)
inlinestatic

Definition at line 2157 of file jsonapi.c.

2160 {
2161  bool error = false;
2162  int len = s - lex->input;
2163 
2164  /* Part (1): leading sign indicator. */
2165  /* Caller already did this for us; so do nothing. */
2166 
2167  /* Part (2): parse main digit string. */
2168  if (len < lex->input_length && *s == '0')
2169  {
2170  s++;
2171  len++;
2172  }
2173  else if (len < lex->input_length && *s >= '1' && *s <= '9')
2174  {
2175  do
2176  {
2177  s++;
2178  len++;
2179  } while (len < lex->input_length && *s >= '0' && *s <= '9');
2180  }
2181  else
2182  error = true;
2183 
2184  /* Part (3): parse optional decimal portion. */
2185  if (len < lex->input_length && *s == '.')
2186  {
2187  s++;
2188  len++;
2189  if (len == lex->input_length || *s < '0' || *s > '9')
2190  error = true;
2191  else
2192  {
2193  do
2194  {
2195  s++;
2196  len++;
2197  } while (len < lex->input_length && *s >= '0' && *s <= '9');
2198  }
2199  }
2200 
2201  /* Part (4): parse optional exponent. */
2202  if (len < lex->input_length && (*s == 'e' || *s == 'E'))
2203  {
2204  s++;
2205  len++;
2206  if (len < lex->input_length && (*s == '+' || *s == '-'))
2207  {
2208  s++;
2209  len++;
2210  }
2211  if (len == lex->input_length || *s < '0' || *s > '9')
2212  error = true;
2213  else
2214  {
2215  do
2216  {
2217  s++;
2218  len++;
2219  } while (len < lex->input_length && *s >= '0' && *s <= '9');
2220  }
2221  }
2222 
2223  /*
2224  * Check for trailing garbage. As in json_lex(), any alphanumeric stuff
2225  * here should be considered part of the token for error-reporting
2226  * purposes.
2227  */
2228  for (; len < lex->input_length && JSON_ALPHANUMERIC_CHAR(*s); s++, len++)
2229  error = true;
2230 
2231  if (total_len != NULL)
2232  *total_len = len;
2233 
2234  if (lex->incremental && !lex->inc_state->is_last_chunk &&
2235  len >= lex->input_length)
2236  {
2238  lex->token_start, s - lex->token_start);
2239  if (num_err != NULL)
2240  *num_err = error;
2241 
2242  return JSON_INCOMPLETE;
2243  }
2244  else if (num_err != NULL)
2245  {
2246  /* let the caller handle any error */
2247  *num_err = error;
2248  }
2249  else
2250  {
2251  /* return token endpoint */
2253  lex->token_terminator = s;
2254  /* handle error if any */
2255  if (error)
2256  return JSON_INVALID_TOKEN;
2257  }
2258 
2259  return JSON_SUCCESS;

References error(), JsonLexContext::inc_state, JsonLexContext::incremental, JsonLexContext::input, JsonLexContext::input_length, JsonIncrementalState::is_last_chunk, JSON_ALPHANUMERIC_CHAR, JSON_INCOMPLETE, JSON_INVALID_TOKEN, JSON_SUCCESS, jsonapi_appendBinaryStringInfo, len, JsonIncrementalState::partial_token, JsonLexContext::prev_token_terminator, JsonLexContext::token_start, and JsonLexContext::token_terminator.

Referenced by IsValidJsonNumber(), and json_lex().

◆ json_lex_string()

static JsonParseErrorType json_lex_string ( JsonLexContext lex)
inlinestatic

Definition at line 1873 of file jsonapi.c.

1875 {
1876  const char *s;
1877  const char *const end = lex->input + lex->input_length;
1878  int hi_surrogate = -1;
1879 
1880  /* Convenience macros for error exits */
1881 #define FAIL_OR_INCOMPLETE_AT_CHAR_START(code) \
1882  do { \
1883  if (lex->incremental && !lex->inc_state->is_last_chunk) \
1884  { \
1885  jsonapi_appendBinaryStringInfo(&lex->inc_state->partial_token, \
1886  lex->token_start, \
1887  end - lex->token_start); \
1888  return JSON_INCOMPLETE; \
1889  } \
1890  lex->token_terminator = s; \
1891  return code; \
1892  } while (0)
1893 #define FAIL_AT_CHAR_END(code) \
1894  do { \
1895  const char *term = s + pg_encoding_mblen(lex->input_encoding, s); \
1896  lex->token_terminator = (term <= end) ? term : end; \
1897  return code; \
1898  } while (0)
1899 
1900  if (lex->need_escapes)
1901  {
1902 #ifdef JSONAPI_USE_PQEXPBUFFER
1903  /* make sure initialization succeeded */
1904  if (lex->strval == NULL)
1905  return JSON_OUT_OF_MEMORY;
1906 #endif
1908  }
1909 
1910  Assert(lex->input_length > 0);
1911  s = lex->token_start;
1912  for (;;)
1913  {
1914  s++;
1915  /* Premature end of the string. */
1916  if (s >= end)
1918  else if (*s == '"')
1919  break;
1920  else if (*s == '\\')
1921  {
1922  /* OK, we have an escape character. */
1923  s++;
1924  if (s >= end)
1926  else if (*s == 'u')
1927  {
1928  int i;
1929  int ch = 0;
1930 
1931  for (i = 1; i <= 4; i++)
1932  {
1933  s++;
1934  if (s >= end)
1936  else if (*s >= '0' && *s <= '9')
1937  ch = (ch * 16) + (*s - '0');
1938  else if (*s >= 'a' && *s <= 'f')
1939  ch = (ch * 16) + (*s - 'a') + 10;
1940  else if (*s >= 'A' && *s <= 'F')
1941  ch = (ch * 16) + (*s - 'A') + 10;
1942  else
1944  }
1945  if (lex->need_escapes)
1946  {
1947  /*
1948  * Combine surrogate pairs.
1949  */
1950  if (is_utf16_surrogate_first(ch))
1951  {
1952  if (hi_surrogate != -1)
1954  hi_surrogate = ch;
1955  continue;
1956  }
1957  else if (is_utf16_surrogate_second(ch))
1958  {
1959  if (hi_surrogate == -1)
1961  ch = surrogate_pair_to_codepoint(hi_surrogate, ch);
1962  hi_surrogate = -1;
1963  }
1964 
1965  if (hi_surrogate != -1)
1967 
1968  /*
1969  * Reject invalid cases. We can't have a value above
1970  * 0xFFFF here (since we only accepted 4 hex digits
1971  * above), so no need to test for out-of-range chars.
1972  */
1973  if (ch == 0)
1974  {
1975  /* We can't allow this, since our TEXT type doesn't */
1977  }
1978 
1979  /*
1980  * Add the represented character to lex->strval. In the
1981  * backend, we can let pg_unicode_to_server_noerror()
1982  * handle any required character set conversion; in
1983  * frontend, we can only deal with trivial conversions.
1984  */
1985 #ifndef FRONTEND
1986  {
1987  char cbuf[MAX_UNICODE_EQUIVALENT_STRING + 1];
1988 
1989  if (!pg_unicode_to_server_noerror(ch, (unsigned char *) cbuf))
1991  appendStringInfoString(lex->strval, cbuf);
1992  }
1993 #else
1994  if (lex->input_encoding == PG_UTF8)
1995  {
1996  /* OK, we can map the code point to UTF8 easily */
1997  char utf8str[5];
1998  int utf8len;
1999 
2000  unicode_to_utf8(ch, (unsigned char *) utf8str);
2001  utf8len = pg_utf_mblen((unsigned char *) utf8str);
2002  jsonapi_appendBinaryStringInfo(lex->strval, utf8str, utf8len);
2003  }
2004  else if (ch <= 0x007f)
2005  {
2006  /* The ASCII range is the same in all encodings */
2007  jsonapi_appendStringInfoChar(lex->strval, (char) ch);
2008  }
2009  else
2011 #endif /* FRONTEND */
2012  }
2013  }
2014  else if (lex->need_escapes)
2015  {
2016  if (hi_surrogate != -1)
2018 
2019  switch (*s)
2020  {
2021  case '"':
2022  case '\\':
2023  case '/':
2025  break;
2026  case 'b':
2028  break;
2029  case 'f':
2031  break;
2032  case 'n':
2034  break;
2035  case 'r':
2037  break;
2038  case 't':
2040  break;
2041  default:
2042 
2043  /*
2044  * Not a valid string escape, so signal error. We
2045  * adjust token_start so that just the escape sequence
2046  * is reported, not the whole string.
2047  */
2048  lex->token_start = s;
2050  }
2051  }
2052  else if (strchr("\"\\/bfnrt", *s) == NULL)
2053  {
2054  /*
2055  * Simpler processing if we're not bothered about de-escaping
2056  *
2057  * It's very tempting to remove the strchr() call here and
2058  * replace it with a switch statement, but testing so far has
2059  * shown it's not a performance win.
2060  */
2061  lex->token_start = s;
2063  }
2064  }
2065  else
2066  {
2067  const char *p = s;
2068 
2069  if (hi_surrogate != -1)
2071 
2072  /*
2073  * Skip to the first byte that requires special handling, so we
2074  * can batch calls to jsonapi_appendBinaryStringInfo.
2075  */
2076  while (p < end - sizeof(Vector8) &&
2077  !pg_lfind8('\\', (uint8 *) p, sizeof(Vector8)) &&
2078  !pg_lfind8('"', (uint8 *) p, sizeof(Vector8)) &&
2079  !pg_lfind8_le(31, (uint8 *) p, sizeof(Vector8)))
2080  p += sizeof(Vector8);
2081 
2082  for (; p < end; p++)
2083  {
2084  if (*p == '\\' || *p == '"')
2085  break;
2086  else if ((unsigned char) *p <= 31)
2087  {
2088  /* Per RFC4627, these characters MUST be escaped. */
2089  /*
2090  * Since *p isn't printable, exclude it from the context
2091  * string
2092  */
2093  lex->token_terminator = p;
2094  return JSON_ESCAPING_REQUIRED;
2095  }
2096  }
2097 
2098  if (lex->need_escapes)
2099  jsonapi_appendBinaryStringInfo(lex->strval, s, p - s);
2100 
2101  /*
2102  * s will be incremented at the top of the loop, so set it to just
2103  * behind our lookahead position
2104  */
2105  s = p - 1;
2106  }
2107  }
2108 
2109  if (hi_surrogate != -1)
2110  {
2111  lex->token_terminator = s + 1;
2113  }
2114 
2115 #ifdef JSONAPI_USE_PQEXPBUFFER
2116  if (lex->need_escapes && PQExpBufferBroken(lex->strval))
2117  return JSON_OUT_OF_MEMORY;
2118 #endif
2119 
2120  /* Hooray, we found the end of the string! */
2122  lex->token_terminator = s + 1;
2123  return JSON_SUCCESS;
2124 
2125 #undef FAIL_OR_INCOMPLETE_AT_CHAR_START
2126 #undef FAIL_AT_CHAR_END
unsigned char uint8
Definition: c.h:516
#define jsonapi_appendStringInfoChar
Definition: jsonapi.c:78
#define FAIL_OR_INCOMPLETE_AT_CHAR_START(code)
#define FAIL_AT_CHAR_END(code)
bool pg_unicode_to_server_noerror(pg_wchar c, unsigned char *s)
Definition: mbutils.c:926
static bool pg_lfind8_le(uint8 key, uint8 *base, uint32 nelem)
Definition: pg_lfind.h:58
static bool pg_lfind8(uint8 key, uint8 *base, uint32 nelem)
Definition: pg_lfind.h:26
#define pg_utf_mblen
Definition: pg_wchar.h:633
@ PG_UTF8
Definition: pg_wchar.h:232
static unsigned char * unicode_to_utf8(pg_wchar c, unsigned char *utf8string)
Definition: pg_wchar.h:575
#define MAX_UNICODE_EQUIVALENT_STRING
Definition: pg_wchar.h:329
static pg_wchar surrogate_pair_to_codepoint(pg_wchar first, pg_wchar second)
Definition: pg_wchar.h:537
static bool is_utf16_surrogate_first(pg_wchar c)
Definition: pg_wchar.h:525
static bool is_utf16_surrogate_second(pg_wchar c)
Definition: pg_wchar.h:531
uint64 Vector8
Definition: simd.h:60
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:179

References appendStringInfoString(), Assert, FAIL_AT_CHAR_END, FAIL_OR_INCOMPLETE_AT_CHAR_START, i, JsonLexContext::input, JsonLexContext::input_encoding, JsonLexContext::input_length, is_utf16_surrogate_first(), is_utf16_surrogate_second(), JSON_ESCAPING_INVALID, JSON_ESCAPING_REQUIRED, JSON_INVALID_TOKEN, JSON_OUT_OF_MEMORY, JSON_SUCCESS, JSON_UNICODE_CODE_POINT_ZERO, JSON_UNICODE_ESCAPE_FORMAT, JSON_UNICODE_HIGH_ESCAPE, JSON_UNICODE_HIGH_SURROGATE, JSON_UNICODE_LOW_SURROGATE, JSON_UNICODE_UNTRANSLATABLE, jsonapi_appendBinaryStringInfo, jsonapi_appendStringInfoChar, jsonapi_resetStringInfo, MAX_UNICODE_EQUIVALENT_STRING, JsonLexContext::need_escapes, pg_lfind8(), pg_lfind8_le(), pg_unicode_to_server_noerror(), PG_UTF8, pg_utf_mblen, PQExpBufferBroken, JsonLexContext::prev_token_terminator, JsonLexContext::strval, surrogate_pair_to_codepoint(), JsonLexContext::token_start, JsonLexContext::token_terminator, and unicode_to_utf8().

Referenced by json_lex().

◆ lex_expect()

static JsonParseErrorType lex_expect ( JsonParseContext  ctx,
JsonLexContext lex,
JsonTokenType  token 
)
inlinestatic

Definition at line 315 of file jsonapi.c.

316 {
317  if (lex_peek(lex) == token)
318  return json_lex(lex);
319  else
320  return report_parse_error(ctx, lex);
321 }
#define token
Definition: indent_globs.h:126
static JsonParseErrorType report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
Definition: jsonapi.c:2267

References json_lex(), lex_peek(), report_parse_error(), and token.

Referenced by json_count_array_elements(), parse_array(), parse_object(), parse_object_field(), and pg_parse_json().

◆ lex_peek()

◆ makeJsonLexContextCstringLen()

JsonLexContext* makeJsonLexContextCstringLen ( JsonLexContext lex,
const char *  json,
size_t  len,
int  encoding,
bool  need_escapes 
)

Definition at line 390 of file jsonapi.c.

392 {
393  if (lex == NULL)
394  {
395  lex = ALLOC0(sizeof(JsonLexContext));
396  if (!lex)
397  return &failed_oom;
398  lex->flags |= JSONLEX_FREE_STRUCT;
399  }
400  else
401  memset(lex, 0, sizeof(JsonLexContext));
402 
403  lex->errormsg = NULL;
404  lex->input = lex->token_terminator = lex->line_start = json;
405  lex->line_number = 1;
406  lex->input_length = len;
407  lex->input_encoding = encoding;
408  lex->need_escapes = need_escapes;
409  if (need_escapes)
410  {
411  /*
412  * This call can fail in shlib code. We defer error handling to time
413  * of use (json_lex_string()) since we might not need to parse any
414  * strings anyway.
415  */
417  lex->flags |= JSONLEX_FREE_STRVAL;
418  }
419 
420  return lex;
421 }
int32 encoding
Definition: pg_database.h:41

References ALLOC0, encoding, JsonLexContext::errormsg, failed_oom, JsonLexContext::flags, JsonLexContext::input, JsonLexContext::input_encoding, JsonLexContext::input_length, jsonapi_makeStringInfo, JSONLEX_FREE_STRUCT, JSONLEX_FREE_STRVAL, len, JsonLexContext::line_number, JsonLexContext::line_start, JsonLexContext::need_escapes, JsonLexContext::strval, and JsonLexContext::token_terminator.

Referenced by get_json_object_as_hash(), json_parse_manifest(), json_recv(), jsonb_from_cstring(), main(), makeJsonLexContext(), and populate_array_json().

◆ makeJsonLexContextIncremental()

JsonLexContext* makeJsonLexContextIncremental ( JsonLexContext lex,
int  encoding,
bool  need_escapes 
)

Definition at line 488 of file jsonapi.c.

491 {
492  if (lex == NULL)
493  {
494  lex = ALLOC0(sizeof(JsonLexContext));
495  if (!lex)
496  return &failed_oom;
497 
498  lex->flags |= JSONLEX_FREE_STRUCT;
499  }
500  else
501  memset(lex, 0, sizeof(JsonLexContext));
502 
503  lex->line_number = 1;
504  lex->input_encoding = encoding;
505 
506  if (!allocate_incremental_state(lex))
507  {
508  if (lex->flags & JSONLEX_FREE_STRUCT)
509  {
510  FREE(lex);
511  return &failed_oom;
512  }
513 
514  /* lex->inc_state tracks the OOM failure; we can return here. */
515  return lex;
516  }
517 
518  lex->need_escapes = need_escapes;
519  if (need_escapes)
520  {
521  /*
522  * This call can fail in shlib code. We defer error handling to time
523  * of use (json_lex_string()) since we might not need to parse any
524  * strings anyway.
525  */
527  lex->flags |= JSONLEX_FREE_STRVAL;
528  }
529 
530  return lex;
static bool allocate_incremental_state(JsonLexContext *lex)
Definition: jsonapi.c:431

References ALLOC0, allocate_incremental_state(), encoding, failed_oom, JsonLexContext::flags, FREE, JsonLexContext::input_encoding, jsonapi_makeStringInfo, JSONLEX_FREE_STRUCT, JSONLEX_FREE_STRVAL, JsonLexContext::line_number, JsonLexContext::need_escapes, and JsonLexContext::strval.

Referenced by json_parse_manifest_incremental_init(), and main().

◆ next_prediction()

static char next_prediction ( JsonParserStack pstack)
inlinestatic

Definition at line 595 of file jsonapi.c.

597 {
598  Assert(pstack->pred_index > 0);
599  return pstack->prediction[pstack->pred_index - 1];

References Assert, JsonParserStack::pred_index, and JsonParserStack::prediction.

Referenced by pg_parse_json_incremental().

◆ parse_array()

static JsonParseErrorType parse_array ( JsonLexContext lex,
const JsonSemAction sem 
)
static

Definition at line 1421 of file jsonapi.c.

1423 {
1424  /*
1425  * an array is a possibly empty sequence of array elements, separated by
1426  * commas and surrounded by square brackets.
1427  */
1430  JsonParseErrorType result;
1431 
1432 #ifndef FRONTEND
1434 #endif
1435 
1436  if (astart != NULL)
1437  {
1438  result = (*astart) (sem->semstate);
1439  if (result != JSON_SUCCESS)
1440  return result;
1441  }
1442 
1443  /*
1444  * Data inside an array is at a higher nesting level than the array
1445  * itself. Note that we increment this after we call the semantic routine
1446  * for the array start and restore it before we call the routine for the
1447  * array end.
1448  */
1449  lex->lex_level++;
1450 
1452  if (result == JSON_SUCCESS && lex_peek(lex) != JSON_TOKEN_ARRAY_END)
1453  {
1454  result = parse_array_element(lex, sem);
1455 
1456  while (result == JSON_SUCCESS && lex_peek(lex) == JSON_TOKEN_COMMA)
1457  {
1458  result = json_lex(lex);
1459  if (result != JSON_SUCCESS)
1460  break;
1461  result = parse_array_element(lex, sem);
1462  }
1463  }
1464  if (result != JSON_SUCCESS)
1465  return result;
1466 
1468  if (result != JSON_SUCCESS)
1469  return result;
1470 
1471  lex->lex_level--;
1472 
1473  if (aend != NULL)
1474  {
1475  result = (*aend) (sem->semstate);
1476  if (result != JSON_SUCCESS)
1477  return result;
1478  }
1479 
1480  return JSON_SUCCESS;
JsonParseErrorType(* json_struct_action)(void *state)
Definition: jsonapi.h:119
void check_stack_depth(void)
Definition: postgres.c:3563
json_struct_action array_end
Definition: jsonapi.h:148
void * semstate
Definition: jsonapi.h:144
json_struct_action array_start
Definition: jsonapi.h:147
static JsonSemAction sem

References JsonSemAction::array_end, JsonSemAction::array_start, check_stack_depth(), json_lex(), JSON_PARSE_ARRAY_NEXT, JSON_PARSE_ARRAY_START, JSON_SUCCESS, JSON_TOKEN_ARRAY_END, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COMMA, lex_expect(), JsonLexContext::lex_level, lex_peek(), parse_array_element(), sem, and JsonSemAction::semstate.

Referenced by parse_array_element(), parse_object_field(), and pg_parse_json().

◆ parse_array_element()

static JsonParseErrorType parse_array_element ( JsonLexContext lex,
const JsonSemAction sem 
)
static

Definition at line 1377 of file jsonapi.c.

1379 {
1382  JsonTokenType tok = lex_peek(lex);
1383  JsonParseErrorType result;
1384  bool isnull;
1385 
1386  isnull = tok == JSON_TOKEN_NULL;
1387 
1388  if (astart != NULL)
1389  {
1390  result = (*astart) (sem->semstate, isnull);
1391  if (result != JSON_SUCCESS)
1392  return result;
1393  }
1394 
1395  /* an array element is any object, array or scalar */
1396  switch (tok)
1397  {
1399  result = parse_object(lex, sem);
1400  break;
1402  result = parse_array(lex, sem);
1403  break;
1404  default:
1405  result = parse_scalar(lex, sem);
1406  }
1407 
1408  if (result != JSON_SUCCESS)
1409  return result;
1410 
1411  if (aend != NULL)
1412  {
1413  result = (*aend) (sem->semstate, isnull);
1414  if (result != JSON_SUCCESS)
1415  return result;
1416  }
1417 
1418  return JSON_SUCCESS;
static JsonParseErrorType parse_object(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1298
static JsonParseErrorType parse_scalar(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1181
static JsonParseErrorType parse_array(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1421
JsonParseErrorType(* json_aelem_action)(void *state, bool isnull)
Definition: jsonapi.h:121
JsonTokenType
Definition: jsonapi.h:18
json_aelem_action array_element_start
Definition: jsonapi.h:151
json_aelem_action array_element_end
Definition: jsonapi.h:152

References JsonSemAction::array_element_end, JsonSemAction::array_element_start, JSON_SUCCESS, JSON_TOKEN_ARRAY_START, JSON_TOKEN_NULL, JSON_TOKEN_OBJECT_START, lex_peek(), parse_array(), parse_object(), parse_scalar(), sem, and JsonSemAction::semstate.

Referenced by json_count_array_elements(), and parse_array().

◆ parse_object()

static JsonParseErrorType parse_object ( JsonLexContext lex,
const JsonSemAction sem 
)
static

Definition at line 1298 of file jsonapi.c.

1300 {
1301  /*
1302  * an object is a possibly empty sequence of object fields, separated by
1303  * commas and surrounded by curly braces.
1304  */
1307  JsonTokenType tok;
1308  JsonParseErrorType result;
1309 
1310 #ifndef FRONTEND
1311 
1312  /*
1313  * TODO: clients need some way to put a bound on stack growth. Parse level
1314  * limits maybe?
1315  */
1317 #endif
1318 
1319  if (ostart != NULL)
1320  {
1321  result = (*ostart) (sem->semstate);
1322  if (result != JSON_SUCCESS)
1323  return result;
1324  }
1325 
1326  /*
1327  * Data inside an object is at a higher nesting level than the object
1328  * itself. Note that we increment this after we call the semantic routine
1329  * for the object start and restore it before we call the routine for the
1330  * object end.
1331  */
1332  lex->lex_level++;
1333 
1335  result = json_lex(lex);
1336  if (result != JSON_SUCCESS)
1337  return result;
1338 
1339  tok = lex_peek(lex);
1340  switch (tok)
1341  {
1342  case JSON_TOKEN_STRING:
1343  result = parse_object_field(lex, sem);
1344  while (result == JSON_SUCCESS && lex_peek(lex) == JSON_TOKEN_COMMA)
1345  {
1346  result = json_lex(lex);
1347  if (result != JSON_SUCCESS)
1348  break;
1349  result = parse_object_field(lex, sem);
1350  }
1351  break;
1352  case JSON_TOKEN_OBJECT_END:
1353  break;
1354  default:
1355  /* case of an invalid initial token inside the object */
1357  }
1358  if (result != JSON_SUCCESS)
1359  return result;
1360 
1362  if (result != JSON_SUCCESS)
1363  return result;
1364 
1365  lex->lex_level--;
1366 
1367  if (oend != NULL)
1368  {
1369  result = (*oend) (sem->semstate);
1370  if (result != JSON_SUCCESS)
1371  return result;
1372  }
1373 
1374  return JSON_SUCCESS;
static JsonParseErrorType parse_object_field(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1232
json_struct_action object_start
Definition: jsonapi.h:145
json_struct_action object_end
Definition: jsonapi.h:146

References Assert, check_stack_depth(), json_lex(), JSON_PARSE_OBJECT_NEXT, JSON_PARSE_OBJECT_START, JSON_SUCCESS, JSON_TOKEN_COMMA, JSON_TOKEN_OBJECT_END, JSON_TOKEN_OBJECT_START, JSON_TOKEN_STRING, lex_expect(), JsonLexContext::lex_level, lex_peek(), JsonSemAction::object_end, JsonSemAction::object_start, parse_object_field(), report_parse_error(), sem, and JsonSemAction::semstate.

Referenced by parse_array_element(), parse_object_field(), and pg_parse_json().

◆ parse_object_field()

static JsonParseErrorType parse_object_field ( JsonLexContext lex,
const JsonSemAction sem 
)
static

Definition at line 1232 of file jsonapi.c.

1234 {
1235  /*
1236  * An object field is "fieldname" : value where value can be a scalar,
1237  * object or array. Note: in user-facing docs and error messages, we
1238  * generally call a field name a "key".
1239  */
1240 
1241  char *fname = NULL; /* keep compiler quiet */
1244  bool isnull;
1245  JsonTokenType tok;
1246  JsonParseErrorType result;
1247 
1248  if (lex_peek(lex) != JSON_TOKEN_STRING)
1250  if ((ostart != NULL || oend != NULL) && lex->need_escapes)
1251  {
1252  fname = STRDUP(lex->strval->data);
1253  if (fname == NULL)
1254  return JSON_OUT_OF_MEMORY;
1255  }
1256  result = json_lex(lex);
1257  if (result != JSON_SUCCESS)
1258  return result;
1259 
1261  if (result != JSON_SUCCESS)
1262  return result;
1263 
1264  tok = lex_peek(lex);
1265  isnull = tok == JSON_TOKEN_NULL;
1266 
1267  if (ostart != NULL)
1268  {
1269  result = (*ostart) (sem->semstate, fname, isnull);
1270  if (result != JSON_SUCCESS)
1271  return result;
1272  }
1273 
1274  switch (tok)
1275  {
1277  result = parse_object(lex, sem);
1278  break;
1280  result = parse_array(lex, sem);
1281  break;
1282  default:
1283  result = parse_scalar(lex, sem);
1284  }
1285  if (result != JSON_SUCCESS)
1286  return result;
1287 
1288  if (oend != NULL)
1289  {
1290  result = (*oend) (sem->semstate, fname, isnull);
1291  if (result != JSON_SUCCESS)
1292  return result;
1293  }
1294 
1295  return JSON_SUCCESS;
#define STRDUP(s)
Definition: jsonapi.c:56
JsonParseErrorType(* json_ofield_action)(void *state, char *fname, bool isnull)
Definition: jsonapi.h:120
json_ofield_action object_field_start
Definition: jsonapi.h:149
json_ofield_action object_field_end
Definition: jsonapi.h:150

References json_lex(), JSON_OUT_OF_MEMORY, JSON_PARSE_OBJECT_LABEL, JSON_PARSE_STRING, JSON_SUCCESS, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COLON, JSON_TOKEN_NULL, JSON_TOKEN_OBJECT_START, JSON_TOKEN_STRING, lex_expect(), lex_peek(), JsonLexContext::need_escapes, JsonSemAction::object_field_end, JsonSemAction::object_field_start, parse_array(), parse_object(), parse_scalar(), report_parse_error(), sem, JsonSemAction::semstate, STRDUP, and JsonLexContext::strval.

Referenced by parse_object().

◆ parse_scalar()

static JsonParseErrorType parse_scalar ( JsonLexContext lex,
const JsonSemAction sem 
)
inlinestatic

Definition at line 1181 of file jsonapi.c.

1183 {
1184  char *val = NULL;
1185  json_scalar_action sfunc = sem->scalar;
1186  JsonTokenType tok = lex_peek(lex);
1187  JsonParseErrorType result;
1188 
1189  /* a scalar must be a string, a number, true, false, or null */
1190  if (tok != JSON_TOKEN_STRING && tok != JSON_TOKEN_NUMBER &&
1191  tok != JSON_TOKEN_TRUE && tok != JSON_TOKEN_FALSE &&
1192  tok != JSON_TOKEN_NULL)
1193  return report_parse_error(JSON_PARSE_VALUE, lex);
1194 
1195  /* if no semantic function, just consume the token */
1196  if (sfunc == NULL)
1197  return json_lex(lex);
1198 
1199  /* extract the de-escaped string value, or the raw lexeme */
1200  if (lex_peek(lex) == JSON_TOKEN_STRING)
1201  {
1202  if (lex->need_escapes)
1203  {
1204  val = STRDUP(lex->strval->data);
1205  if (val == NULL)
1206  return JSON_OUT_OF_MEMORY;
1207  }
1208  }
1209  else
1210  {
1211  int len = (lex->token_terminator - lex->token_start);
1212 
1213  val = ALLOC(len + 1);
1214  if (val == NULL)
1215  return JSON_OUT_OF_MEMORY;
1216 
1217  memcpy(val, lex->token_start, len);
1218  val[len] = '\0';
1219  }
1220 
1221  /* consume the token */
1222  result = json_lex(lex);
1223  if (result != JSON_SUCCESS)
1224  return result;
1225 
1226  /* invoke the callback */
1227  result = (*sfunc) (sem->semstate, val, tok);
1228 
1229  return result;
long val
Definition: informix.c:689
JsonParseErrorType(* json_scalar_action)(void *state, char *token, JsonTokenType tokentype)
Definition: jsonapi.h:122
json_scalar_action scalar
Definition: jsonapi.h:153

References ALLOC, json_lex(), JSON_OUT_OF_MEMORY, JSON_PARSE_VALUE, JSON_SUCCESS, JSON_TOKEN_FALSE, JSON_TOKEN_NULL, JSON_TOKEN_NUMBER, JSON_TOKEN_STRING, JSON_TOKEN_TRUE, len, lex_peek(), JsonLexContext::need_escapes, report_parse_error(), JsonSemAction::scalar, sem, JsonSemAction::semstate, STRDUP, JsonLexContext::strval, JsonLexContext::token_start, JsonLexContext::token_terminator, and val.

Referenced by parse_array_element(), parse_object_field(), and pg_parse_json().

◆ pg_parse_json()

JsonParseErrorType pg_parse_json ( JsonLexContext lex,
const JsonSemAction sem 
)

Definition at line 685 of file jsonapi.c.

687 {
688 #ifdef FORCE_JSON_PSTACK
689  /*
690  * We don't need partial token processing, there is only one chunk. But we
691  * still need to init the partial token string so that freeJsonLexContext
692  * works, so perform the full incremental initialization.
693  */
694  if (!allocate_incremental_state(lex))
695  return JSON_OUT_OF_MEMORY;
696 
697  return pg_parse_json_incremental(lex, sem, lex->input, lex->input_length, true);
698 
699 #else
700 
701  JsonTokenType tok;
702  JsonParseErrorType result;
703 
704  if (lex == &failed_oom)
705  return JSON_OUT_OF_MEMORY;
706  if (lex->incremental)
708 
709  /* get the initial token */
710  result = json_lex(lex);
711  if (result != JSON_SUCCESS)
712  return result;
713 
714  tok = lex_peek(lex);
715 
716  /* parse by recursive descent */
717  switch (tok)
718  {
720  result = parse_object(lex, sem);
721  break;
723  result = parse_array(lex, sem);
724  break;
725  default:
726  result = parse_scalar(lex, sem); /* json can be a bare scalar */
727  }
728 
729  if (result == JSON_SUCCESS)
730  result = lex_expect(JSON_PARSE_END, lex, JSON_TOKEN_END);
731 
732  return result;
733 #endif
JsonParseErrorType pg_parse_json_incremental(JsonLexContext *lex, const JsonSemAction *sem, const char *json, size_t len, bool is_last)
Definition: jsonapi.c:809

References allocate_incremental_state(), failed_oom, JsonLexContext::incremental, JsonLexContext::input, JsonLexContext::input_length, JSON_INVALID_LEXER_TYPE, json_lex(), JSON_OUT_OF_MEMORY, JSON_PARSE_END, JSON_SUCCESS, JSON_TOKEN_ARRAY_START, JSON_TOKEN_END, JSON_TOKEN_OBJECT_START, lex_expect(), lex_peek(), parse_array(), parse_object(), parse_scalar(), pg_parse_json_incremental(), and sem.

Referenced by json_parse_manifest(), json_validate(), main(), and pg_parse_json_or_errsave().

◆ pg_parse_json_incremental()

JsonParseErrorType pg_parse_json_incremental ( JsonLexContext lex,
const JsonSemAction sem,
const char *  json,
size_t  len,
bool  is_last 
)

Definition at line 809 of file jsonapi.c.

815 {
816  JsonTokenType tok;
817  JsonParseErrorType result;
819  JsonParserStack *pstack = lex->pstack;
820 
821  if (lex == &failed_oom || lex->inc_state == &failed_inc_oom)
822  return JSON_OUT_OF_MEMORY;
823  if (!lex->incremental)
825 
826  lex->input = lex->token_terminator = lex->line_start = json;
827  lex->input_length = len;
828  lex->inc_state->is_last_chunk = is_last;
829 
830  /* get the initial token */
831  result = json_lex(lex);
832  if (result != JSON_SUCCESS)
833  return result;
834 
835  tok = lex_peek(lex);
836 
837  /* use prediction stack for incremental parsing */
838 
839  if (!have_prediction(pstack))
840  {
842 
843  push_prediction(pstack, goal);
844  }
845 
846  while (have_prediction(pstack))
847  {
848  char top = pop_prediction(pstack);
849  td_entry entry;
850 
851  /*
852  * these first two branches are the guts of the Table Driven method
853  */
854  if (top == tok)
855  {
856  /*
857  * tok can only be a terminal symbol, so top must be too. the
858  * token matches the top of the stack, so get the next token.
859  */
860  if (tok < JSON_TOKEN_END)
861  {
862  result = json_lex(lex);
863  if (result != JSON_SUCCESS)
864  return result;
865  tok = lex_peek(lex);
866  }
867  }
868  else if (IS_NT(top) && (entry = td_parser_table[OFS(top)][tok]).prod != NULL)
869  {
870  /*
871  * the token is in the director set for a production of the
872  * non-terminal at the top of the stack, so push the reversed RHS
873  * of the production onto the stack.
874  */
875  push_prediction(pstack, entry);
876  }
877  else if (IS_SEM(top))
878  {
879  /*
880  * top is a semantic action marker, so take action accordingly.
881  * It's important to have these markers in the prediction stack
882  * before any token they might need so we don't advance the token
883  * prematurely. Note in a couple of cases we need to do something
884  * both before and after the token.
885  */
886  switch (top)
887  {
888  case JSON_SEM_OSTART:
889  {
891 
892  if (lex->lex_level >= JSON_TD_MAX_STACK)
893  return JSON_NESTING_TOO_DEEP;
894 
895  if (ostart != NULL)
896  {
897  result = (*ostart) (sem->semstate);
898  if (result != JSON_SUCCESS)
899  return result;
900  }
901 
902  if (!inc_lex_level(lex))
903  return JSON_OUT_OF_MEMORY;
904  }
905  break;
906  case JSON_SEM_OEND:
907  {
909 
910  dec_lex_level(lex);
911  if (oend != NULL)
912  {
913  result = (*oend) (sem->semstate);
914  if (result != JSON_SUCCESS)
915  return result;
916  }
917  }
918  break;
919  case JSON_SEM_ASTART:
920  {
922 
923  if (lex->lex_level >= JSON_TD_MAX_STACK)
924  return JSON_NESTING_TOO_DEEP;
925 
926  if (astart != NULL)
927  {
928  result = (*astart) (sem->semstate);
929  if (result != JSON_SUCCESS)
930  return result;
931  }
932 
933  if (!inc_lex_level(lex))
934  return JSON_OUT_OF_MEMORY;
935  }
936  break;
937  case JSON_SEM_AEND:
938  {
940 
941  dec_lex_level(lex);
942  if (aend != NULL)
943  {
944  result = (*aend) (sem->semstate);
945  if (result != JSON_SUCCESS)
946  return result;
947  }
948  }
949  break;
951  {
952  /*
953  * all we do here is save out the field name. We have
954  * to wait to get past the ':' to see if the next
955  * value is null so we can call the semantic routine
956  */
957  char *fname = NULL;
960 
961  if ((ostart != NULL || oend != NULL) && lex->need_escapes)
962  {
963  fname = STRDUP(lex->strval->data);
964  if (fname == NULL)
965  return JSON_OUT_OF_MEMORY;
966  }
967  set_fname(lex, fname);
968  }
969  break;
971  {
972  /*
973  * the current token should be the first token of the
974  * value
975  */
976  bool isnull = tok == JSON_TOKEN_NULL;
978 
979  set_fnull(lex, isnull);
980 
981  if (ostart != NULL)
982  {
983  char *fname = get_fname(lex);
984 
985  result = (*ostart) (sem->semstate, fname, isnull);
986  if (result != JSON_SUCCESS)
987  return result;
988  }
989  }
990  break;
991  case JSON_SEM_OFIELD_END:
992  {
994 
995  if (oend != NULL)
996  {
997  char *fname = get_fname(lex);
998  bool isnull = get_fnull(lex);
999 
1000  result = (*oend) (sem->semstate, fname, isnull);
1001  if (result != JSON_SUCCESS)
1002  return result;
1003  }
1004  }
1005  break;
1006  case JSON_SEM_AELEM_START:
1007  {
1009  bool isnull = tok == JSON_TOKEN_NULL;
1010 
1011  set_fnull(lex, isnull);
1012 
1013  if (astart != NULL)
1014  {
1015  result = (*astart) (sem->semstate, isnull);
1016  if (result != JSON_SUCCESS)
1017  return result;
1018  }
1019  }
1020  break;
1021  case JSON_SEM_AELEM_END:
1022  {
1024 
1025  if (aend != NULL)
1026  {
1027  bool isnull = get_fnull(lex);
1028 
1029  result = (*aend) (sem->semstate, isnull);
1030  if (result != JSON_SUCCESS)
1031  return result;
1032  }
1033  }
1034  break;
1035  case JSON_SEM_SCALAR_INIT:
1036  {
1037  json_scalar_action sfunc = sem->scalar;
1038 
1039  pstack->scalar_val = NULL;
1040 
1041  if (sfunc != NULL)
1042  {
1043  /*
1044  * extract the de-escaped string value, or the raw
1045  * lexeme
1046  */
1047  /*
1048  * XXX copied from RD parser but looks like a
1049  * buglet
1050  */
1051  if (tok == JSON_TOKEN_STRING)
1052  {
1053  if (lex->need_escapes)
1054  {
1055  pstack->scalar_val = STRDUP(lex->strval->data);
1056  if (pstack->scalar_val == NULL)
1057  return JSON_OUT_OF_MEMORY;
1058  }
1059  }
1060  else
1061  {
1062  ptrdiff_t tlen = (lex->token_terminator - lex->token_start);
1063 
1064  pstack->scalar_val = ALLOC(tlen + 1);
1065  if (pstack->scalar_val == NULL)
1066  return JSON_OUT_OF_MEMORY;
1067 
1068  memcpy(pstack->scalar_val, lex->token_start, tlen);
1069  pstack->scalar_val[tlen] = '\0';
1070  }
1071  pstack->scalar_tok = tok;
1072  }
1073  }
1074  break;
1075  case JSON_SEM_SCALAR_CALL:
1076  {
1077  /*
1078  * We'd like to be able to get rid of this business of
1079  * two bits of scalar action, but we can't. It breaks
1080  * certain semantic actions which expect that when
1081  * called the lexer has consumed the item. See for
1082  * example get_scalar() in jsonfuncs.c.
1083  */
1084  json_scalar_action sfunc = sem->scalar;
1085 
1086  if (sfunc != NULL)
1087  {
1088  result = (*sfunc) (sem->semstate, pstack->scalar_val, pstack->scalar_tok);
1089  if (result != JSON_SUCCESS)
1090  return result;
1091  }
1092  }
1093  break;
1094  default:
1095  /* should not happen */
1096  break;
1097  }
1098  }
1099  else
1100  {
1101  /*
1102  * The token didn't match the stack top if it's a terminal nor a
1103  * production for the stack top if it's a non-terminal.
1104  *
1105  * Various cases here are Asserted to be not possible, as the
1106  * token would not appear at the top of the prediction stack
1107  * unless the lookahead matched.
1108  */
1109  switch (top)
1110  {
1111  case JSON_TOKEN_STRING:
1112  if (next_prediction(pstack) == JSON_TOKEN_COLON)
1113  ctx = JSON_PARSE_STRING;
1114  else
1115  {
1116  Assert(false);
1117  ctx = JSON_PARSE_VALUE;
1118  }
1119  break;
1120  case JSON_TOKEN_NUMBER:
1121  case JSON_TOKEN_TRUE:
1122  case JSON_TOKEN_FALSE:
1123  case JSON_TOKEN_NULL:
1126  Assert(false);
1127  ctx = JSON_PARSE_VALUE;
1128  break;
1129  case JSON_TOKEN_ARRAY_END:
1130  Assert(false);
1131  ctx = JSON_PARSE_ARRAY_NEXT;
1132  break;
1133  case JSON_TOKEN_OBJECT_END:
1134  Assert(false);
1135  ctx = JSON_PARSE_OBJECT_NEXT;
1136  break;
1137  case JSON_TOKEN_COMMA:
1138  Assert(false);
1139  if (next_prediction(pstack) == JSON_TOKEN_STRING)
1140  ctx = JSON_PARSE_OBJECT_NEXT;
1141  else
1142  ctx = JSON_PARSE_ARRAY_NEXT;
1143  break;
1144  case JSON_TOKEN_COLON:
1146  break;
1147  case JSON_TOKEN_END:
1148  ctx = JSON_PARSE_END;
1149  break;
1151  ctx = JSON_PARSE_ARRAY_NEXT;
1152  break;
1154  ctx = JSON_PARSE_ARRAY_START;
1155  break;
1157  ctx = JSON_PARSE_OBJECT_NEXT;
1158  break;
1159  case JSON_NT_KEY_PAIRS:
1161  break;
1162  default:
1163  ctx = JSON_PARSE_VALUE;
1164  }
1165  return report_parse_error(ctx, lex);
1166  }
1167  }
1168 
1169  return JSON_SUCCESS;
#define JSON_TD_MAX_STACK
Definition: jsonapi.c:429
#define TD_ENTRY(PROD)
Definition: jsonapi.c:238
static void set_fnull(JsonLexContext *lex, bool fnull)
Definition: jsonapi.c:620
#define OFS(NT)
Definition: jsonapi.c:176
static bool inc_lex_level(JsonLexContext *lex)
Definition: jsonapi.c:533
static bool have_prediction(JsonParserStack *pstack)
Definition: jsonapi.c:602
static void set_fname(JsonLexContext *lex, char *fname)
Definition: jsonapi.c:608
static char next_prediction(JsonParserStack *pstack)
Definition: jsonapi.c:595
static void push_prediction(JsonParserStack *pstack, td_entry entry)
Definition: jsonapi.c:581
#define IS_NT(x)
Definition: jsonapi.c:179
static char JSON_PROD_GOAL[]
Definition: jsonapi.c:271
#define IS_SEM(x)
Definition: jsonapi.c:178
static td_entry td_parser_table[JSON_NUM_NONTERMINALS][JSON_NUM_TERMINALS]
Definition: jsonapi.c:240
static char * get_fname(JsonLexContext *lex)
Definition: jsonapi.c:614
static char pop_prediction(JsonParserStack *pstack)
Definition: jsonapi.c:588
static bool get_fnull(JsonLexContext *lex)
Definition: jsonapi.c:626
static void dec_lex_level(JsonLexContext *lex)
Definition: jsonapi.c:575
JsonTokenType scalar_tok
Definition: jsonapi.c:152
char * scalar_val
Definition: jsonapi.c:153
Definition: jsonapi.c:233

References ALLOC, JsonSemAction::array_element_end, JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, Assert, dec_lex_level(), failed_inc_oom, failed_oom, get_fname(), get_fnull(), have_prediction(), inc_lex_level(), JsonLexContext::inc_state, JsonLexContext::incremental, JsonLexContext::input, JsonLexContext::input_length, JsonIncrementalState::is_last_chunk, IS_NT, IS_SEM, JSON_INVALID_LEXER_TYPE, json_lex(), JSON_NESTING_TOO_DEEP, JSON_NT_ARRAY_ELEMENTS, JSON_NT_KEY_PAIRS, JSON_NT_MORE_ARRAY_ELEMENTS, JSON_NT_MORE_KEY_PAIRS, JSON_OUT_OF_MEMORY, JSON_PARSE_ARRAY_NEXT, JSON_PARSE_ARRAY_START, JSON_PARSE_END, JSON_PARSE_OBJECT_LABEL, JSON_PARSE_OBJECT_NEXT, JSON_PARSE_OBJECT_START, JSON_PARSE_STRING, JSON_PARSE_VALUE, JSON_PROD_GOAL, JSON_SEM_AELEM_END, JSON_SEM_AELEM_START, JSON_SEM_AEND, JSON_SEM_ASTART, JSON_SEM_OEND, JSON_SEM_OFIELD_END, JSON_SEM_OFIELD_INIT, JSON_SEM_OFIELD_START, JSON_SEM_OSTART, JSON_SEM_SCALAR_CALL, JSON_SEM_SCALAR_INIT, JSON_SUCCESS, JSON_TD_MAX_STACK, JSON_TOKEN_ARRAY_END, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COLON, JSON_TOKEN_COMMA, JSON_TOKEN_END, JSON_TOKEN_FALSE, JSON_TOKEN_NULL, JSON_TOKEN_NUMBER, JSON_TOKEN_OBJECT_END, JSON_TOKEN_OBJECT_START, JSON_TOKEN_STRING, JSON_TOKEN_TRUE, len, JsonLexContext::lex_level, lex_peek(), JsonLexContext::line_start, JsonLexContext::need_escapes, next_prediction(), JsonSemAction::object_end, JsonSemAction::object_field_end, JsonSemAction::object_field_start, JsonSemAction::object_start, OFS, pop_prediction(), JsonLexContext::pstack, push_prediction(), report_parse_error(), JsonSemAction::scalar, JsonParserStack::scalar_tok, JsonParserStack::scalar_val, sem, JsonSemAction::semstate, set_fname(), set_fnull(), STRDUP, JsonLexContext::strval, TD_ENTRY, td_parser_table, JsonLexContext::token_start, and JsonLexContext::token_terminator.

Referenced by json_parse_manifest_incremental_chunk(), main(), and pg_parse_json().

◆ pop_prediction()

static char pop_prediction ( JsonParserStack pstack)
inlinestatic

Definition at line 588 of file jsonapi.c.

590 {
591  Assert(pstack->pred_index > 0);
592  return pstack->prediction[--pstack->pred_index];

References Assert, JsonParserStack::pred_index, and JsonParserStack::prediction.

Referenced by pg_parse_json_incremental().

◆ push_prediction()

static void push_prediction ( JsonParserStack pstack,
td_entry  entry 
)
inlinestatic

Definition at line 581 of file jsonapi.c.

583 {
584  memcpy(pstack->prediction + pstack->pred_index, entry.prod, entry.len);
585  pstack->pred_index += entry.len;
char * prod
Definition: jsonapi.c:235
size_t len
Definition: jsonapi.c:234

References td_entry::len, JsonParserStack::pred_index, JsonParserStack::prediction, and td_entry::prod.

Referenced by pg_parse_json_incremental().

◆ report_parse_error()

static JsonParseErrorType report_parse_error ( JsonParseContext  ctx,
JsonLexContext lex 
)
static

Definition at line 2267 of file jsonapi.c.

2269 {
2270  /* Handle case where the input ended prematurely. */
2271  if (lex->token_start == NULL || lex->token_type == JSON_TOKEN_END)
2272  return JSON_EXPECTED_MORE;
2273 
2274  /* Otherwise choose the error type based on the parsing context. */
2275  switch (ctx)
2276  {
2277  case JSON_PARSE_END:
2278  return JSON_EXPECTED_END;
2279  case JSON_PARSE_VALUE:
2280  return JSON_EXPECTED_JSON;
2281  case JSON_PARSE_STRING:
2282  return JSON_EXPECTED_STRING;
2285  case JSON_PARSE_ARRAY_NEXT:
2286  return JSON_EXPECTED_ARRAY_NEXT;
2290  return JSON_EXPECTED_COLON;
2294  return JSON_EXPECTED_STRING;
2295  }
2296 
2297  /*
2298  * We don't use a default: case, so that the compiler will warn about
2299  * unhandled enum values.
2300  */
2301  Assert(false);
2302  return JSON_SUCCESS; /* silence stupider compilers */

References Assert, JSON_EXPECTED_ARRAY_FIRST, JSON_EXPECTED_ARRAY_NEXT, JSON_EXPECTED_COLON, JSON_EXPECTED_END, JSON_EXPECTED_JSON, JSON_EXPECTED_MORE, JSON_EXPECTED_OBJECT_FIRST, JSON_EXPECTED_OBJECT_NEXT, JSON_EXPECTED_STRING, JSON_PARSE_ARRAY_NEXT, JSON_PARSE_ARRAY_START, JSON_PARSE_END, JSON_PARSE_OBJECT_COMMA, JSON_PARSE_OBJECT_LABEL, JSON_PARSE_OBJECT_NEXT, JSON_PARSE_OBJECT_START, JSON_PARSE_STRING, JSON_PARSE_VALUE, JSON_SUCCESS, JSON_TOKEN_END, JsonLexContext::token_start, and JsonLexContext::token_type.

Referenced by lex_expect(), parse_object(), parse_object_field(), parse_scalar(), and pg_parse_json_incremental().

◆ set_fname()

static void set_fname ( JsonLexContext lex,
char *  fname 
)
inlinestatic

Definition at line 608 of file jsonapi.c.

610 {
611  lex->pstack->fnames[lex->lex_level] = fname;

References JsonParserStack::fnames, JsonLexContext::lex_level, and JsonLexContext::pstack.

Referenced by pg_parse_json_incremental().

◆ set_fnull()

static void set_fnull ( JsonLexContext lex,
bool  fnull 
)
inlinestatic

Definition at line 620 of file jsonapi.c.

622 {
623  lex->pstack->fnull[lex->lex_level] = fnull;

References JsonParserStack::fnull, JsonLexContext::lex_level, and JsonLexContext::pstack.

Referenced by pg_parse_json_incremental().

Variable Documentation

◆ failed_inc_oom

JsonIncrementalState failed_inc_oom
static

Definition at line 293 of file jsonapi.c.

Referenced by allocate_incremental_state(), json_lex(), and pg_parse_json_incremental().

◆ failed_oom

◆ JSON_PROD_ARRAY

Definition at line 206 of file jsonapi.c.

◆ JSON_PROD_ARRAY_ELEMENTS

char JSON_PROD_ARRAY_ELEMENTS[] = {JSON_NT_MORE_ARRAY_ELEMENTS, JSON_SEM_AELEM_END, JSON_NT_JSON, JSON_SEM_AELEM_START, 0}
static

Definition at line 209 of file jsonapi.c.

◆ JSON_PROD_EPSILON

char JSON_PROD_EPSILON[] = {0}
static

Definition at line 185 of file jsonapi.c.

◆ JSON_PROD_GOAL

char JSON_PROD_GOAL[] = {JSON_TOKEN_END, JSON_NT_JSON, 0}
static

Definition at line 271 of file jsonapi.c.

Referenced by pg_parse_json_incremental().

◆ JSON_PROD_KEY_PAIRS

◆ JSON_PROD_MORE_ARRAY_ELEMENTS

Definition at line 212 of file jsonapi.c.

◆ JSON_PROD_MORE_KEY_PAIRS

◆ JSON_PROD_OBJECT

Definition at line 203 of file jsonapi.c.

◆ JSON_PROD_SCALAR_FALSE

char JSON_PROD_SCALAR_FALSE[] = {JSON_SEM_SCALAR_CALL, JSON_TOKEN_FALSE, JSON_SEM_SCALAR_INIT, 0}
static

Definition at line 197 of file jsonapi.c.

◆ JSON_PROD_SCALAR_NULL

char JSON_PROD_SCALAR_NULL[] = {JSON_SEM_SCALAR_CALL, JSON_TOKEN_NULL, JSON_SEM_SCALAR_INIT, 0}
static

Definition at line 200 of file jsonapi.c.

◆ JSON_PROD_SCALAR_NUMBER

char JSON_PROD_SCALAR_NUMBER[] = {JSON_SEM_SCALAR_CALL, JSON_TOKEN_NUMBER, JSON_SEM_SCALAR_INIT, 0}
static

Definition at line 191 of file jsonapi.c.

◆ JSON_PROD_SCALAR_STRING

char JSON_PROD_SCALAR_STRING[] = {JSON_SEM_SCALAR_CALL, JSON_TOKEN_STRING, JSON_SEM_SCALAR_INIT, 0}
static

Definition at line 188 of file jsonapi.c.

◆ JSON_PROD_SCALAR_TRUE

char JSON_PROD_SCALAR_TRUE[] = {JSON_SEM_SCALAR_CALL, JSON_TOKEN_TRUE, JSON_SEM_SCALAR_INIT, 0}
static

Definition at line 194 of file jsonapi.c.

◆ nullSemAction

const JsonSemAction nullSemAction
Initial value:
=
{
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL
}

Definition at line 285 of file jsonapi.c.

Referenced by json_count_array_elements(), json_in(), json_recv(), json_validate(), and main().

◆ td_parser_table

Initial value:
=
{
}
static char JSON_PROD_MORE_KEY_PAIRS[]
Definition: jsonapi.c:218
static char JSON_PROD_KEY_PAIRS[]
Definition: jsonapi.c:215
static char JSON_PROD_SCALAR_STRING[]
Definition: jsonapi.c:188
static char JSON_PROD_ARRAY_ELEMENTS[]
Definition: jsonapi.c:209
static char JSON_PROD_SCALAR_NUMBER[]
Definition: jsonapi.c:191
static char JSON_PROD_EPSILON[]
Definition: jsonapi.c:185
static char JSON_PROD_SCALAR_NULL[]
Definition: jsonapi.c:200
static char JSON_PROD_MORE_ARRAY_ELEMENTS[]
Definition: jsonapi.c:212
static char JSON_PROD_SCALAR_FALSE[]
Definition: jsonapi.c:197
static char JSON_PROD_OBJECT[]
Definition: jsonapi.c:203
static char JSON_PROD_ARRAY[]
Definition: jsonapi.c:206
static char JSON_PROD_SCALAR_TRUE[]
Definition: jsonapi.c:194

Definition at line 240 of file jsonapi.c.

Referenced by pg_parse_json_incremental().