PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
jsonapi.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  JsonLexContext
 
struct  JsonSemAction
 

Macros

#define jsonapi_StrValType   StringInfoData
 
#define JSONLEX_FREE_STRUCT   (1 << 0)
 
#define JSONLEX_FREE_STRVAL   (1 << 1)
 

Typedefs

typedef enum JsonTokenType JsonTokenType
 
typedef enum JsonParseErrorType JsonParseErrorType
 
typedef struct JsonParserStack JsonParserStack
 
typedef struct JsonIncrementalState JsonIncrementalState
 
typedef struct JsonLexContext JsonLexContext
 
typedef JsonParseErrorType(* json_struct_action) (void *state)
 
typedef JsonParseErrorType(* json_ofield_action) (void *state, char *fname, bool isnull)
 
typedef JsonParseErrorType(* json_aelem_action) (void *state, bool isnull)
 
typedef JsonParseErrorType(* json_scalar_action) (void *state, char *token, JsonTokenType tokentype)
 
typedef struct JsonSemAction JsonSemAction
 

Enumerations

enum  JsonTokenType {
  JSON_TOKEN_INVALID , JSON_TOKEN_STRING , JSON_TOKEN_NUMBER , JSON_TOKEN_OBJECT_START ,
  JSON_TOKEN_OBJECT_END , JSON_TOKEN_ARRAY_START , JSON_TOKEN_ARRAY_END , JSON_TOKEN_COMMA ,
  JSON_TOKEN_COLON , JSON_TOKEN_TRUE , JSON_TOKEN_FALSE , JSON_TOKEN_NULL ,
  JSON_TOKEN_END
}
 
enum  JsonParseErrorType {
  JSON_SUCCESS , JSON_INCOMPLETE , JSON_INVALID_LEXER_TYPE , JSON_NESTING_TOO_DEEP ,
  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_INVALID_TOKEN ,
  JSON_OUT_OF_MEMORY , JSON_UNICODE_CODE_POINT_ZERO , JSON_UNICODE_ESCAPE_FORMAT , JSON_UNICODE_HIGH_ESCAPE ,
  JSON_UNICODE_UNTRANSLATABLE , JSON_UNICODE_HIGH_SURROGATE , JSON_UNICODE_LOW_SURROGATE , JSON_SEM_ACTION_FAILED
}
 

Functions

JsonParseErrorType pg_parse_json (JsonLexContext *lex, const JsonSemAction *sem)
 
JsonParseErrorType pg_parse_json_incremental (JsonLexContext *lex, const JsonSemAction *sem, const char *json, size_t len, bool is_last)
 
JsonParseErrorType json_count_array_elements (JsonLexContext *lex, int *elements)
 
JsonLexContextmakeJsonLexContextCstringLen (JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
 
JsonLexContextmakeJsonLexContextIncremental (JsonLexContext *lex, int encoding, bool need_escapes)
 
void freeJsonLexContext (JsonLexContext *lex)
 
JsonParseErrorType json_lex (JsonLexContext *lex)
 
char * json_errdetail (JsonParseErrorType error, JsonLexContext *lex)
 
bool IsValidJsonNumber (const char *str, size_t len)
 

Variables

PGDLLIMPORT const JsonSemAction nullSemAction
 

Macro Definition Documentation

◆ jsonapi_StrValType

#define jsonapi_StrValType   StringInfoData

Definition at line 73 of file jsonapi.h.

◆ JSONLEX_FREE_STRUCT

#define JSONLEX_FREE_STRUCT   (1 << 0)

Definition at line 96 of file jsonapi.h.

◆ JSONLEX_FREE_STRVAL

#define JSONLEX_FREE_STRVAL   (1 << 1)

Definition at line 97 of file jsonapi.h.

Typedef Documentation

◆ json_aelem_action

typedef JsonParseErrorType(* json_aelem_action) (void *state, bool isnull)

Definition at line 121 of file jsonapi.h.

◆ json_ofield_action

typedef JsonParseErrorType(* json_ofield_action) (void *state, char *fname, bool isnull)

Definition at line 120 of file jsonapi.h.

◆ json_scalar_action

typedef JsonParseErrorType(* json_scalar_action) (void *state, char *token, JsonTokenType tokentype)

Definition at line 122 of file jsonapi.h.

◆ json_struct_action

typedef JsonParseErrorType(* json_struct_action) (void *state)

Definition at line 119 of file jsonapi.h.

◆ JsonIncrementalState

Definition at line 1 of file jsonapi.h.

◆ JsonLexContext

◆ JsonParseErrorType

◆ JsonParserStack

Definition at line 1 of file jsonapi.h.

◆ JsonSemAction

typedef struct JsonSemAction JsonSemAction

◆ JsonTokenType

Enumeration Type Documentation

◆ JsonParseErrorType

Enumerator
JSON_SUCCESS 
JSON_INCOMPLETE 
JSON_INVALID_LEXER_TYPE 
JSON_NESTING_TOO_DEEP 
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_INVALID_TOKEN 
JSON_OUT_OF_MEMORY 
JSON_UNICODE_CODE_POINT_ZERO 
JSON_UNICODE_ESCAPE_FORMAT 
JSON_UNICODE_HIGH_ESCAPE 
JSON_UNICODE_UNTRANSLATABLE 
JSON_UNICODE_HIGH_SURROGATE 
JSON_UNICODE_LOW_SURROGATE 
JSON_SEM_ACTION_FAILED 

Definition at line 34 of file jsonapi.h.

35 {
59  JSON_SEM_ACTION_FAILED, /* error should already be reported */
JsonParseErrorType
Definition: jsonapi.h:35
@ JSON_OUT_OF_MEMORY
Definition: jsonapi.h:52
@ 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_SUCCESS
Definition: jsonapi.h:36
@ 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_INCOMPLETE
Definition: jsonapi.h:37
@ 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

◆ JsonTokenType

Enumerator
JSON_TOKEN_INVALID 
JSON_TOKEN_STRING 
JSON_TOKEN_NUMBER 
JSON_TOKEN_OBJECT_START 
JSON_TOKEN_OBJECT_END 
JSON_TOKEN_ARRAY_START 
JSON_TOKEN_ARRAY_END 
JSON_TOKEN_COMMA 
JSON_TOKEN_COLON 
JSON_TOKEN_TRUE 
JSON_TOKEN_FALSE 
JSON_TOKEN_NULL 
JSON_TOKEN_END 

Definition at line 17 of file jsonapi.h.

18 {
JsonTokenType
Definition: jsonapi.h:18
@ JSON_TOKEN_INVALID
Definition: jsonapi.h:19
@ JSON_TOKEN_COMMA
Definition: jsonapi.h:26
@ 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_ARRAY_END
Definition: jsonapi.h:25
@ 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
@ JSON_TOKEN_ARRAY_START
Definition: jsonapi.h:24

Function Documentation

◆ 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 FREE(s)
Definition: jsonapi.c:69
#define JSONLEX_FREE_STRVAL
Definition: jsonapi.h:97
#define JSONLEX_FREE_STRUCT
Definition: jsonapi.h:96
jsonapi_StrValType partial_token
Definition: jsonapi.c:166
bits32 flags
Definition: jsonapi.h:109
struct jsonapi_StrValType * strval
Definition: jsonapi.h:115
struct jsonapi_StrValType * errormsg
Definition: jsonapi.h:116
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
char ** fnames
Definition: jsonapi.c:150

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().

◆ 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;
@ JSON_PARSE_ARRAY_START
Definition: jsonapi.c:97
@ JSON_PARSE_ARRAY_NEXT
Definition: jsonapi.c:98
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
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 _(x)
Definition: elog.c:90
#define json_token_error(lex, format)
#define jsonapi_makeStringInfo
Definition: jsonapi.c:80
#define jsonapi_resetStringInfo
Definition: jsonapi.c:82
#define jsonapi_appendStringInfo
Definition: jsonapi.c:76
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
static JsonIncrementalState failed_inc_oom
Definition: jsonapi.c:293
#define jsonapi_appendBinaryStringInfo
Definition: jsonapi.c:77
#define jsonapi_StrValType
Definition: jsonapi.h:73
#define PQExpBufferDataBroken(buf)
Definition: pqexpbuffer.h:67
char * c
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().

◆ 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 }
#define ALLOC0(size)
Definition: jsonapi.c:58
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().

◆ 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
@ JSON_PARSE_END
Definition: jsonapi.c:103
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
static JsonSemAction sem

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
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_OBJECT_NEXT
Definition: jsonapi.c:101
@ JSON_PARSE_STRING
Definition: jsonapi.c:96
#define TD_ENTRY(PROD)
Definition: jsonapi.c:238
@ 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
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 STRDUP(s)
Definition: jsonapi.c:56
static JsonParseErrorType report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
Definition: jsonapi.c:2267
#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
#define ALLOC(size)
Definition: jsonapi.c:57
static bool get_fnull(JsonLexContext *lex)
Definition: jsonapi.c:626
@ 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
static void dec_lex_level(JsonLexContext *lex)
Definition: jsonapi.c:575
JsonParseErrorType(* json_struct_action)(void *state)
Definition: jsonapi.h:119
JsonParseErrorType(* json_aelem_action)(void *state, bool isnull)
Definition: jsonapi.h:121
JsonParseErrorType(* json_ofield_action)(void *state, char *fname, bool isnull)
Definition: jsonapi.h:120
JsonParseErrorType(* json_scalar_action)(void *state, char *token, JsonTokenType tokentype)
Definition: jsonapi.h:122
JsonTokenType scalar_tok
Definition: jsonapi.c:152
char * scalar_val
Definition: jsonapi.c:153
json_struct_action array_end
Definition: jsonapi.h:148
json_struct_action object_start
Definition: jsonapi.h:145
json_ofield_action object_field_start
Definition: jsonapi.h:149
json_aelem_action array_element_start
Definition: jsonapi.h:151
json_scalar_action scalar
Definition: jsonapi.h:153
void * semstate
Definition: jsonapi.h:144
json_aelem_action array_element_end
Definition: jsonapi.h:152
json_struct_action array_start
Definition: jsonapi.h:147
json_struct_action object_end
Definition: jsonapi.h:146
json_ofield_action object_field_end
Definition: jsonapi.h:150
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().

Variable Documentation

◆ nullSemAction

PGDLLIMPORT const JsonSemAction nullSemAction
extern

Definition at line 285 of file jsonapi.c.

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