PostgreSQL Source Code  git master
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)
 
#define JSONLEX_CTX_OWNS_TOKENS   (1 << 2)
 

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 setJsonLexContextOwnsTokens (JsonLexContext *lex, bool owned_by_context)
 
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_CTX_OWNS_TOKENS

#define JSONLEX_CTX_OWNS_TOKENS   (1 << 2)

Definition at line 99 of file jsonapi.h.

◆ JSONLEX_FREE_STRUCT

#define JSONLEX_FREE_STRUCT   (1 << 0)

Definition at line 97 of file jsonapi.h.

◆ JSONLEX_FREE_STRVAL

#define JSONLEX_FREE_STRVAL   (1 << 1)

Definition at line 98 of file jsonapi.h.

Typedef Documentation

◆ json_aelem_action

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

Definition at line 123 of file jsonapi.h.

◆ json_ofield_action

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

Definition at line 122 of file jsonapi.h.

◆ json_scalar_action

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

Definition at line 124 of file jsonapi.h.

◆ json_struct_action

typedef JsonParseErrorType(* json_struct_action) (void *state)

Definition at line 121 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 687 of file jsonapi.c.

689 {
690  static const JsonLexContext empty = {0};
691 
692  if (!lex || lex == &failed_oom)
693  return;
694 
695  if (lex->flags & JSONLEX_FREE_STRVAL)
697 
698  if (lex->errormsg)
700 
701  if (lex->incremental)
702  {
704  FREE(lex->inc_state);
705  FREE(lex->pstack->prediction);
706 
707  if (lex->flags & JSONLEX_CTX_OWNS_TOKENS)
708  {
709  int i;
710 
711  /* Clean up any tokens that were left behind. */
712  for (i = 0; i <= lex->lex_level; i++)
713  FREE(lex->pstack->fnames[i]);
714  }
715 
716  FREE(lex->pstack->fnames);
717  FREE(lex->pstack->fnull);
718  FREE(lex->pstack->scalar_val);
719  FREE(lex->pstack);
720  }
721 
722  if (lex->flags & JSONLEX_FREE_STRUCT)
723  FREE(lex);
724  else
725  *lex = empty;
int i
Definition: isn.c:72
#define jsonapi_destroyStringInfo
Definition: jsonapi.c:84
static JsonLexContext failed_oom
Definition: jsonapi.c:294
#define jsonapi_termStringInfo(s)
Definition: jsonapi.c:83
#define FREE(s)
Definition: jsonapi.c:69
#define JSONLEX_FREE_STRVAL
Definition: jsonapi.h:98
#define JSONLEX_FREE_STRUCT
Definition: jsonapi.h:97
#define JSONLEX_CTX_OWNS_TOKENS
Definition: jsonapi.h:99
jsonapi_StrValType partial_token
Definition: jsonapi.c:167
bits32 flags
Definition: jsonapi.h:111
struct jsonapi_StrValType * strval
Definition: jsonapi.h:117
struct jsonapi_StrValType * errormsg
Definition: jsonapi.h:118
JsonParserStack * pstack
Definition: jsonapi.h:114
JsonIncrementalState * inc_state
Definition: jsonapi.h:115
bool incremental
Definition: jsonapi.h:108
bool * fnull
Definition: jsonapi.c:151
char * prediction
Definition: jsonapi.c:147
char * scalar_val
Definition: jsonapi.c:153
char ** fnames
Definition: jsonapi.c:150

References JsonLexContext::errormsg, failed_oom, JsonLexContext::flags, JsonParserStack::fnames, JsonParserStack::fnull, FREE, i, JsonLexContext::inc_state, JsonLexContext::incremental, jsonapi_destroyStringInfo, jsonapi_termStringInfo, JSONLEX_CTX_OWNS_TOKENS, JSONLEX_FREE_STRUCT, JSONLEX_FREE_STRVAL, JsonLexContext::lex_level, JsonIncrementalState::partial_token, JsonParserStack::prediction, JsonLexContext::pstack, JsonParserStack::scalar_val, 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 339 of file jsonapi.c.

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

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 803 of file jsonapi.c.

805 {
806  JsonLexContext copylex;
807  int count;
808  JsonParseErrorType result;
809 
810  if (lex == &failed_oom)
811  return JSON_OUT_OF_MEMORY;
812 
813  /*
814  * It's safe to do this with a shallow copy because the lexical routines
815  * don't scribble on the input. They do scribble on the other pointers
816  * etc, so doing this with a copy makes that safe.
817  */
818  memcpy(&copylex, lex, sizeof(JsonLexContext));
819  copylex.need_escapes = false; /* not interested in values here */
820  copylex.lex_level++;
821 
822  count = 0;
823  result = lex_expect(JSON_PARSE_ARRAY_START, &copylex,
825  if (result != JSON_SUCCESS)
826  return result;
827  if (lex_peek(&copylex) != JSON_TOKEN_ARRAY_END)
828  {
829  while (1)
830  {
831  count++;
832  result = parse_array_element(&copylex, &nullSemAction);
833  if (result != JSON_SUCCESS)
834  return result;
835  if (copylex.token_type != JSON_TOKEN_COMMA)
836  break;
837  result = json_lex(&copylex);
838  if (result != JSON_SUCCESS)
839  return result;
840  }
841  }
842  result = lex_expect(JSON_PARSE_ARRAY_NEXT, &copylex,
844  if (result != JSON_SUCCESS)
845  return result;
846 
847  *elements = count;
848  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:305
static JsonParseErrorType lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
Definition: jsonapi.c:317
const JsonSemAction nullSemAction
Definition: jsonapi.c:287
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:1584
static JsonParseErrorType parse_array_element(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1463
bool need_escapes
Definition: jsonapi.h:116
JsonTokenType token_type
Definition: jsonapi.h:109

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 2397 of file jsonapi.c.

2399 {
2400  if (error == JSON_OUT_OF_MEMORY || lex == &failed_oom)
2401  {
2402  /* Short circuit. Allocating anything for this case is unhelpful. */
2403  return _("out of memory");
2404  }
2405 
2406  if (lex->errormsg)
2408  else
2410 
2411  /*
2412  * A helper for error messages that should print the current token. The
2413  * format must contain exactly one %.*s specifier.
2414  */
2415 #define json_token_error(lex, format) \
2416  jsonapi_appendStringInfo((lex)->errormsg, _(format), \
2417  (int) ((lex)->token_terminator - (lex)->token_start), \
2418  (lex)->token_start);
2419 
2420  switch (error)
2421  {
2422  case JSON_INCOMPLETE:
2423  case JSON_SUCCESS:
2424  /* fall through to the error code after switch */
2425  break;
2427  if (lex->incremental)
2428  return _("Recursive descent parser cannot use incremental lexer.");
2429  else
2430  return _("Incremental parser requires incremental lexer.");
2431  case JSON_NESTING_TOO_DEEP:
2432  return (_("JSON nested too deep, maximum permitted depth is 6400."));
2433  case JSON_ESCAPING_INVALID:
2434  json_token_error(lex, "Escape sequence \"\\%.*s\" is invalid.");
2435  break;
2438  _("Character with value 0x%02x must be escaped."),
2439  (unsigned char) *(lex->token_terminator));
2440  break;
2441  case JSON_EXPECTED_END:
2442  json_token_error(lex, "Expected end of input, but found \"%.*s\".");
2443  break;
2445  json_token_error(lex, "Expected array element or \"]\", but found \"%.*s\".");
2446  break;
2448  json_token_error(lex, "Expected \",\" or \"]\", but found \"%.*s\".");
2449  break;
2450  case JSON_EXPECTED_COLON:
2451  json_token_error(lex, "Expected \":\", but found \"%.*s\".");
2452  break;
2453  case JSON_EXPECTED_JSON:
2454  json_token_error(lex, "Expected JSON value, but found \"%.*s\".");
2455  break;
2456  case JSON_EXPECTED_MORE:
2457  return _("The input string ended unexpectedly.");
2459  json_token_error(lex, "Expected string or \"}\", but found \"%.*s\".");
2460  break;
2462  json_token_error(lex, "Expected \",\" or \"}\", but found \"%.*s\".");
2463  break;
2464  case JSON_EXPECTED_STRING:
2465  json_token_error(lex, "Expected string, but found \"%.*s\".");
2466  break;
2467  case JSON_INVALID_TOKEN:
2468  json_token_error(lex, "Token \"%.*s\" is invalid.");
2469  break;
2470  case JSON_OUT_OF_MEMORY:
2471  /* should have been handled above; use the error path */
2472  break;
2474  return _("\\u0000 cannot be converted to text.");
2476  return _("\"\\u\" must be followed by four hexadecimal digits.");
2478  /* note: this case is only reachable in frontend not backend */
2479  return _("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8.");
2481 
2482  /*
2483  * Note: this case is only reachable in backend and not frontend.
2484  * #ifdef it away so the frontend doesn't try to link against
2485  * backend functionality.
2486  */
2487 #ifndef FRONTEND
2488  return psprintf(_("Unicode escape value could not be translated to the server's encoding %s."),
2490 #else
2491  Assert(false);
2492  break;
2493 #endif
2495  return _("Unicode high surrogate must not follow a high surrogate.");
2497  return _("Unicode low surrogate must follow a high surrogate.");
2499  /* fall through to the error code after switch */
2500  break;
2501  }
2502 #undef json_token_error
2503 
2504  /* Note that lex->errormsg can be NULL in shlib code. */
2505  if (lex->errormsg && lex->errormsg->len == 0)
2506  {
2507  /*
2508  * We don't use a default: case, so that the compiler will warn about
2509  * unhandled enum values. But this needs to be here anyway to cover
2510  * the possibility of an incorrect input.
2511  */
2513  "unexpected json parse error type: %d",
2514  (int) error);
2515  }
2516 
2517 #ifdef JSONAPI_USE_PQEXPBUFFER
2518  if (PQExpBufferBroken(lex->errormsg))
2519  return _("out of memory while constructing error description");
2520 #endif
2521 
2522  return lex->errormsg->data;
#define Assert(condition)
Definition: c.h:812
#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:106

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 1584 of file jsonapi.c.

1586 {
1587  const char *s;
1588  const char *const end = lex->input + lex->input_length;
1589  JsonParseErrorType result;
1590 
1591  if (lex == &failed_oom || lex->inc_state == &failed_inc_oom)
1592  return JSON_OUT_OF_MEMORY;
1593 
1594  if (lex->incremental)
1595  {
1596  if (lex->inc_state->partial_completed)
1597  {
1598  /*
1599  * We just lexed a completed partial token on the last call, so
1600  * reset everything
1601  */
1603  lex->token_terminator = lex->input;
1604  lex->inc_state->partial_completed = false;
1605  }
1606 
1607 #ifdef JSONAPI_USE_PQEXPBUFFER
1608  /* Make sure our partial token buffer is valid before using it below. */
1610  return JSON_OUT_OF_MEMORY;
1611 #endif
1612  }
1613 
1614  s = lex->token_terminator;
1615 
1616  if (lex->incremental && lex->inc_state->partial_token.len)
1617  {
1618  /*
1619  * We have a partial token. Extend it and if completed lex it by a
1620  * recursive call
1621  */
1622  jsonapi_StrValType *ptok = &(lex->inc_state->partial_token);
1623  size_t added = 0;
1624  bool tok_done = false;
1625  JsonLexContext dummy_lex = {0};
1626  JsonParseErrorType partial_result;
1627 
1628  if (ptok->data[0] == '"')
1629  {
1630  /*
1631  * It's a string. Accumulate characters until we reach an
1632  * unescaped '"'.
1633  */
1634  int escapes = 0;
1635 
1636  for (int i = ptok->len - 1; i > 0; i--)
1637  {
1638  /* count the trailing backslashes on the partial token */
1639  if (ptok->data[i] == '\\')
1640  escapes++;
1641  else
1642  break;
1643  }
1644 
1645  for (size_t i = 0; i < lex->input_length; i++)
1646  {
1647  char c = lex->input[i];
1648 
1650  added++;
1651  if (c == '"' && escapes % 2 == 0)
1652  {
1653  tok_done = true;
1654  break;
1655  }
1656  if (c == '\\')
1657  escapes++;
1658  else
1659  escapes = 0;
1660  }
1661  }
1662  else
1663  {
1664  /* not a string */
1665  char c = ptok->data[0];
1666 
1667  if (c == '-' || (c >= '0' && c <= '9'))
1668  {
1669  /* for numbers look for possible numeric continuations */
1670 
1671  bool numend = false;
1672 
1673  for (size_t i = 0; i < lex->input_length && !numend; i++)
1674  {
1675  char cc = lex->input[i];
1676 
1677  switch (cc)
1678  {
1679  case '+':
1680  case '-':
1681  case 'e':
1682  case 'E':
1683  case '0':
1684  case '1':
1685  case '2':
1686  case '3':
1687  case '4':
1688  case '5':
1689  case '6':
1690  case '7':
1691  case '8':
1692  case '9':
1693  {
1695  added++;
1696  }
1697  break;
1698  default:
1699  numend = true;
1700  }
1701  }
1702  }
1703 
1704  /*
1705  * Add any remaining alphanumeric chars. This takes care of the
1706  * {null, false, true} literals as well as any trailing
1707  * alphanumeric junk on non-string tokens.
1708  */
1709  for (size_t i = added; i < lex->input_length; i++)
1710  {
1711  char cc = lex->input[i];
1712 
1713  if (JSON_ALPHANUMERIC_CHAR(cc))
1714  {
1716  added++;
1717  }
1718  else
1719  {
1720  tok_done = true;
1721  break;
1722  }
1723  }
1724  if (added == lex->input_length &&
1725  lex->inc_state->is_last_chunk)
1726  {
1727  tok_done = true;
1728  }
1729  }
1730 
1731  if (!tok_done)
1732  {
1733  /* We should have consumed the whole chunk in this case. */
1734  Assert(added == lex->input_length);
1735 
1736  if (!lex->inc_state->is_last_chunk)
1737  return JSON_INCOMPLETE;
1738 
1739  /* json_errdetail() needs access to the accumulated token. */
1740  lex->token_start = ptok->data;
1741  lex->token_terminator = ptok->data + ptok->len;
1742  return JSON_INVALID_TOKEN;
1743  }
1744 
1745  /*
1746  * Everything up to lex->input[added] has been added to the partial
1747  * token, so move the input past it.
1748  */
1749  lex->input += added;
1750  lex->input_length -= added;
1751 
1752  dummy_lex.input = dummy_lex.token_terminator =
1753  dummy_lex.line_start = ptok->data;
1754  dummy_lex.line_number = lex->line_number;
1755  dummy_lex.input_length = ptok->len;
1756  dummy_lex.input_encoding = lex->input_encoding;
1757  dummy_lex.incremental = false;
1758  dummy_lex.need_escapes = lex->need_escapes;
1759  dummy_lex.strval = lex->strval;
1760 
1761  partial_result = json_lex(&dummy_lex);
1762 
1763  /*
1764  * We either have a complete token or an error. In either case we need
1765  * to point to the partial token data for the semantic or error
1766  * routines. If it's not an error we'll readjust on the next call to
1767  * json_lex.
1768  */
1769  lex->token_type = dummy_lex.token_type;
1770  lex->line_number = dummy_lex.line_number;
1771 
1772  /*
1773  * We know the prev_token_terminator must be back in some previous
1774  * piece of input, so we just make it NULL.
1775  */
1776  lex->prev_token_terminator = NULL;
1777 
1778  /*
1779  * Normally token_start would be ptok->data, but it could be later,
1780  * see json_lex_string's handling of invalid escapes.
1781  */
1782  lex->token_start = dummy_lex.token_start;
1783  lex->token_terminator = dummy_lex.token_terminator;
1784  if (partial_result == JSON_SUCCESS)
1785  {
1786  /* make sure we've used all the input */
1787  if (lex->token_terminator - lex->token_start != ptok->len)
1788  {
1789  Assert(false);
1790  return JSON_INVALID_TOKEN;
1791  }
1792 
1793  lex->inc_state->partial_completed = true;
1794  }
1795  return partial_result;
1796  /* end of partial token processing */
1797  }
1798 
1799  /* Skip leading whitespace. */
1800  while (s < end && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
1801  {
1802  if (*s++ == '\n')
1803  {
1804  ++lex->line_number;
1805  lex->line_start = s;
1806  }
1807  }
1808  lex->token_start = s;
1809 
1810  /* Determine token type. */
1811  if (s >= end)
1812  {
1813  lex->token_start = NULL;
1815  lex->token_terminator = s;
1816  lex->token_type = JSON_TOKEN_END;
1817  }
1818  else
1819  {
1820  switch (*s)
1821  {
1822  /* Single-character token, some kind of punctuation mark. */
1823  case '{':
1825  lex->token_terminator = s + 1;
1827  break;
1828  case '}':
1830  lex->token_terminator = s + 1;
1832  break;
1833  case '[':
1835  lex->token_terminator = s + 1;
1837  break;
1838  case ']':
1840  lex->token_terminator = s + 1;
1842  break;
1843  case ',':
1845  lex->token_terminator = s + 1;
1847  break;
1848  case ':':
1850  lex->token_terminator = s + 1;
1852  break;
1853  case '"':
1854  /* string */
1855  result = json_lex_string(lex);
1856  if (result != JSON_SUCCESS)
1857  return result;
1859  break;
1860  case '-':
1861  /* Negative number. */
1862  result = json_lex_number(lex, s + 1, NULL, NULL);
1863  if (result != JSON_SUCCESS)
1864  return result;
1866  break;
1867  case '0':
1868  case '1':
1869  case '2':
1870  case '3':
1871  case '4':
1872  case '5':
1873  case '6':
1874  case '7':
1875  case '8':
1876  case '9':
1877  /* Positive number. */
1878  result = json_lex_number(lex, s, NULL, NULL);
1879  if (result != JSON_SUCCESS)
1880  return result;
1882  break;
1883  default:
1884  {
1885  const char *p;
1886 
1887  /*
1888  * We're not dealing with a string, number, legal
1889  * punctuation mark, or end of string. The only legal
1890  * tokens we might find here are true, false, and null,
1891  * but for error reporting purposes we scan until we see a
1892  * non-alphanumeric character. That way, we can report
1893  * the whole word as an unexpected token, rather than just
1894  * some unintuitive prefix thereof.
1895  */
1896  for (p = s; p < end && JSON_ALPHANUMERIC_CHAR(*p); p++)
1897  /* skip */ ;
1898 
1899  /*
1900  * We got some sort of unexpected punctuation or an
1901  * otherwise unexpected character, so just complain about
1902  * that one character.
1903  */
1904  if (p == s)
1905  {
1907  lex->token_terminator = s + 1;
1908  return JSON_INVALID_TOKEN;
1909  }
1910 
1911  if (lex->incremental && !lex->inc_state->is_last_chunk &&
1912  p == lex->input + lex->input_length)
1913  {
1915  return JSON_INCOMPLETE;
1916  }
1917 
1918  /*
1919  * We've got a real alphanumeric token here. If it
1920  * happens to be true, false, or null, all is well. If
1921  * not, error out.
1922  */
1924  lex->token_terminator = p;
1925  if (p - s == 4)
1926  {
1927  if (memcmp(s, "true", 4) == 0)
1928  lex->token_type = JSON_TOKEN_TRUE;
1929  else if (memcmp(s, "null", 4) == 0)
1930  lex->token_type = JSON_TOKEN_NULL;
1931  else
1932  return JSON_INVALID_TOKEN;
1933  }
1934  else if (p - s == 5 && memcmp(s, "false", 5) == 0)
1936  else
1937  return JSON_INVALID_TOKEN;
1938  }
1939  } /* end of switch */
1940  }
1941 
1942  if (lex->incremental && lex->token_type == JSON_TOKEN_END && !lex->inc_state->is_last_chunk)
1943  return JSON_INCOMPLETE;
1944  else
1945  return JSON_SUCCESS;
static JsonParseErrorType json_lex_string(JsonLexContext *lex)
Definition: jsonapi.c:1959
#define JSON_ALPHANUMERIC_CHAR(c)
Definition: jsonapi.c:326
#define jsonapi_appendStringInfoCharMacro
Definition: jsonapi.c:79
static JsonIncrementalState failed_inc_oom
Definition: jsonapi.c:295
#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:104
const char * prev_token_terminator
Definition: jsonapi.h:107
const char * line_start
Definition: jsonapi.h:113
int line_number
Definition: jsonapi.h:112

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 392 of file jsonapi.c.

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

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

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 744 of file jsonapi.c.

746 {
747 #ifdef FORCE_JSON_PSTACK
748  /*
749  * We don't need partial token processing, there is only one chunk. But we
750  * still need to init the partial token string so that freeJsonLexContext
751  * works, so perform the full incremental initialization.
752  */
753  if (!allocate_incremental_state(lex))
754  return JSON_OUT_OF_MEMORY;
755 
756  return pg_parse_json_incremental(lex, sem, lex->input, lex->input_length, true);
757 
758 #else
759 
760  JsonTokenType tok;
761  JsonParseErrorType result;
762 
763  if (lex == &failed_oom)
764  return JSON_OUT_OF_MEMORY;
765  if (lex->incremental)
767 
768  /* get the initial token */
769  result = json_lex(lex);
770  if (result != JSON_SUCCESS)
771  return result;
772 
773  tok = lex_peek(lex);
774 
775  /* parse by recursive descent */
776  switch (tok)
777  {
779  result = parse_object(lex, sem);
780  break;
782  result = parse_array(lex, sem);
783  break;
784  default:
785  result = parse_scalar(lex, sem); /* json can be a bare scalar */
786  }
787 
788  if (result == JSON_SUCCESS)
789  result = lex_expect(JSON_PARSE_END, lex, JSON_TOKEN_END);
790 
791  return result;
792 #endif
JsonParseErrorType pg_parse_json_incremental(JsonLexContext *lex, const JsonSemAction *sem, const char *json, size_t len, bool is_last)
Definition: jsonapi.c:868
@ JSON_PARSE_END
Definition: jsonapi.c:103
static JsonParseErrorType parse_object(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1384
static JsonParseErrorType parse_scalar(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1252
static JsonParseErrorType parse_array(JsonLexContext *lex, const JsonSemAction *sem)
Definition: jsonapi.c:1507
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 868 of file jsonapi.c.

874 {
875  JsonTokenType tok;
876  JsonParseErrorType result;
878  JsonParserStack *pstack = lex->pstack;
879 
880  if (lex == &failed_oom || lex->inc_state == &failed_inc_oom)
881  return JSON_OUT_OF_MEMORY;
882  if (!lex->incremental)
884 
885  lex->input = lex->token_terminator = lex->line_start = json;
886  lex->input_length = len;
887  lex->inc_state->is_last_chunk = is_last;
888  lex->inc_state->started = true;
889 
890  /* get the initial token */
891  result = json_lex(lex);
892  if (result != JSON_SUCCESS)
893  return result;
894 
895  tok = lex_peek(lex);
896 
897  /* use prediction stack for incremental parsing */
898 
899  if (!have_prediction(pstack))
900  {
902 
903  push_prediction(pstack, goal);
904  }
905 
906  while (have_prediction(pstack))
907  {
908  char top = pop_prediction(pstack);
909  td_entry entry;
910 
911  /*
912  * these first two branches are the guts of the Table Driven method
913  */
914  if (top == tok)
915  {
916  /*
917  * tok can only be a terminal symbol, so top must be too. the
918  * token matches the top of the stack, so get the next token.
919  */
920  if (tok < JSON_TOKEN_END)
921  {
922  result = json_lex(lex);
923  if (result != JSON_SUCCESS)
924  return result;
925  tok = lex_peek(lex);
926  }
927  }
928  else if (IS_NT(top) && (entry = td_parser_table[OFS(top)][tok]).prod != NULL)
929  {
930  /*
931  * the token is in the director set for a production of the
932  * non-terminal at the top of the stack, so push the reversed RHS
933  * of the production onto the stack.
934  */
935  push_prediction(pstack, entry);
936  }
937  else if (IS_SEM(top))
938  {
939  /*
940  * top is a semantic action marker, so take action accordingly.
941  * It's important to have these markers in the prediction stack
942  * before any token they might need so we don't advance the token
943  * prematurely. Note in a couple of cases we need to do something
944  * both before and after the token.
945  */
946  switch (top)
947  {
948  case JSON_SEM_OSTART:
949  {
951 
952  if (lex->lex_level >= JSON_TD_MAX_STACK)
953  return JSON_NESTING_TOO_DEEP;
954 
955  if (ostart != NULL)
956  {
957  result = (*ostart) (sem->semstate);
958  if (result != JSON_SUCCESS)
959  return result;
960  }
961 
962  if (!inc_lex_level(lex))
963  return JSON_OUT_OF_MEMORY;
964  }
965  break;
966  case JSON_SEM_OEND:
967  {
969 
970  dec_lex_level(lex);
971  if (oend != NULL)
972  {
973  result = (*oend) (sem->semstate);
974  if (result != JSON_SUCCESS)
975  return result;
976  }
977  }
978  break;
979  case JSON_SEM_ASTART:
980  {
982 
983  if (lex->lex_level >= JSON_TD_MAX_STACK)
984  return JSON_NESTING_TOO_DEEP;
985 
986  if (astart != NULL)
987  {
988  result = (*astart) (sem->semstate);
989  if (result != JSON_SUCCESS)
990  return result;
991  }
992 
993  if (!inc_lex_level(lex))
994  return JSON_OUT_OF_MEMORY;
995  }
996  break;
997  case JSON_SEM_AEND:
998  {
1000 
1001  dec_lex_level(lex);
1002  if (aend != NULL)
1003  {
1004  result = (*aend) (sem->semstate);
1005  if (result != JSON_SUCCESS)
1006  return result;
1007  }
1008  }
1009  break;
1010  case JSON_SEM_OFIELD_INIT:
1011  {
1012  /*
1013  * all we do here is save out the field name. We have
1014  * to wait to get past the ':' to see if the next
1015  * value is null so we can call the semantic routine
1016  */
1017  char *fname = NULL;
1020 
1021  if ((ostart != NULL || oend != NULL) && lex->need_escapes)
1022  {
1023  fname = STRDUP(lex->strval->data);
1024  if (fname == NULL)
1025  return JSON_OUT_OF_MEMORY;
1026  }
1027  set_fname(lex, fname);
1028  }
1029  break;
1030  case JSON_SEM_OFIELD_START:
1031  {
1032  /*
1033  * the current token should be the first token of the
1034  * value
1035  */
1036  bool isnull = tok == JSON_TOKEN_NULL;
1038 
1039  set_fnull(lex, isnull);
1040 
1041  if (ostart != NULL)
1042  {
1043  char *fname = get_fname(lex);
1044 
1045  result = (*ostart) (sem->semstate, fname, isnull);
1046  if (result != JSON_SUCCESS)
1047  return result;
1048  }
1049  }
1050  break;
1051  case JSON_SEM_OFIELD_END:
1052  {
1054 
1055  if (oend != NULL)
1056  {
1057  char *fname = get_fname(lex);
1058  bool isnull = get_fnull(lex);
1059 
1060  result = (*oend) (sem->semstate, fname, isnull);
1061  if (result != JSON_SUCCESS)
1062  return result;
1063  }
1064  }
1065  break;
1066  case JSON_SEM_AELEM_START:
1067  {
1069  bool isnull = tok == JSON_TOKEN_NULL;
1070 
1071  set_fnull(lex, isnull);
1072 
1073  if (astart != NULL)
1074  {
1075  result = (*astart) (sem->semstate, isnull);
1076  if (result != JSON_SUCCESS)
1077  return result;
1078  }
1079  }
1080  break;
1081  case JSON_SEM_AELEM_END:
1082  {
1084 
1085  if (aend != NULL)
1086  {
1087  bool isnull = get_fnull(lex);
1088 
1089  result = (*aend) (sem->semstate, isnull);
1090  if (result != JSON_SUCCESS)
1091  return result;
1092  }
1093  }
1094  break;
1095  case JSON_SEM_SCALAR_INIT:
1096  {
1097  json_scalar_action sfunc = sem->scalar;
1098 
1099  pstack->scalar_val = NULL;
1100 
1101  if (sfunc != NULL)
1102  {
1103  /*
1104  * extract the de-escaped string value, or the raw
1105  * lexeme
1106  */
1107  /*
1108  * XXX copied from RD parser but looks like a
1109  * buglet
1110  */
1111  if (tok == JSON_TOKEN_STRING)
1112  {
1113  if (lex->need_escapes)
1114  {
1115  pstack->scalar_val = STRDUP(lex->strval->data);
1116  if (pstack->scalar_val == NULL)
1117  return JSON_OUT_OF_MEMORY;
1118  }
1119  }
1120  else
1121  {
1122  ptrdiff_t tlen = (lex->token_terminator - lex->token_start);
1123 
1124  pstack->scalar_val = ALLOC(tlen + 1);
1125  if (pstack->scalar_val == NULL)
1126  return JSON_OUT_OF_MEMORY;
1127 
1128  memcpy(pstack->scalar_val, lex->token_start, tlen);
1129  pstack->scalar_val[tlen] = '\0';
1130  }
1131  pstack->scalar_tok = tok;
1132  }
1133  }
1134  break;
1135  case JSON_SEM_SCALAR_CALL:
1136  {
1137  /*
1138  * We'd like to be able to get rid of this business of
1139  * two bits of scalar action, but we can't. It breaks
1140  * certain semantic actions which expect that when
1141  * called the lexer has consumed the item. See for
1142  * example get_scalar() in jsonfuncs.c.
1143  */
1144  json_scalar_action sfunc = sem->scalar;
1145 
1146  if (sfunc != NULL)
1147  {
1148  result = (*sfunc) (sem->semstate, pstack->scalar_val, pstack->scalar_tok);
1149 
1150  /*
1151  * Either ownership of the token passed to the
1152  * callback, or we need to free it now. Either
1153  * way, clear our pointer to it so it doesn't get
1154  * freed in the future.
1155  */
1156  if (lex->flags & JSONLEX_CTX_OWNS_TOKENS)
1157  FREE(pstack->scalar_val);
1158  pstack->scalar_val = NULL;
1159 
1160  if (result != JSON_SUCCESS)
1161  return result;
1162  }
1163  }
1164  break;
1165  default:
1166  /* should not happen */
1167  break;
1168  }
1169  }
1170  else
1171  {
1172  /*
1173  * The token didn't match the stack top if it's a terminal nor a
1174  * production for the stack top if it's a non-terminal.
1175  *
1176  * Various cases here are Asserted to be not possible, as the
1177  * token would not appear at the top of the prediction stack
1178  * unless the lookahead matched.
1179  */
1180  switch (top)
1181  {
1182  case JSON_TOKEN_STRING:
1183  if (next_prediction(pstack) == JSON_TOKEN_COLON)
1184  ctx = JSON_PARSE_STRING;
1185  else
1186  {
1187  Assert(false);
1188  ctx = JSON_PARSE_VALUE;
1189  }
1190  break;
1191  case JSON_TOKEN_NUMBER:
1192  case JSON_TOKEN_TRUE:
1193  case JSON_TOKEN_FALSE:
1194  case JSON_TOKEN_NULL:
1197  Assert(false);
1198  ctx = JSON_PARSE_VALUE;
1199  break;
1200  case JSON_TOKEN_ARRAY_END:
1201  Assert(false);
1202  ctx = JSON_PARSE_ARRAY_NEXT;
1203  break;
1204  case JSON_TOKEN_OBJECT_END:
1205  Assert(false);
1206  ctx = JSON_PARSE_OBJECT_NEXT;
1207  break;
1208  case JSON_TOKEN_COMMA:
1209  Assert(false);
1210  if (next_prediction(pstack) == JSON_TOKEN_STRING)
1211  ctx = JSON_PARSE_OBJECT_NEXT;
1212  else
1213  ctx = JSON_PARSE_ARRAY_NEXT;
1214  break;
1215  case JSON_TOKEN_COLON:
1217  break;
1218  case JSON_TOKEN_END:
1219  ctx = JSON_PARSE_END;
1220  break;
1222  ctx = JSON_PARSE_ARRAY_NEXT;
1223  break;
1225  ctx = JSON_PARSE_ARRAY_START;
1226  break;
1228  ctx = JSON_PARSE_OBJECT_NEXT;
1229  break;
1230  case JSON_NT_KEY_PAIRS:
1232  break;
1233  default:
1234  ctx = JSON_PARSE_VALUE;
1235  }
1236  return report_parse_error(ctx, lex);
1237  }
1238  }
1239 
1240  return JSON_SUCCESS;
#define JSON_TD_MAX_STACK
Definition: jsonapi.c:431
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:239
@ 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:668
#define OFS(NT)
Definition: jsonapi.c:177
static bool inc_lex_level(JsonLexContext *lex)
Definition: jsonapi.c:561
static bool have_prediction(JsonParserStack *pstack)
Definition: jsonapi.c:641
static void set_fname(JsonLexContext *lex, char *fname)
Definition: jsonapi.c:647
static char next_prediction(JsonParserStack *pstack)
Definition: jsonapi.c:634
static void push_prediction(JsonParserStack *pstack, td_entry entry)
Definition: jsonapi.c:620
#define IS_NT(x)
Definition: jsonapi.c:180
static char JSON_PROD_GOAL[]
Definition: jsonapi.c:272
#define STRDUP(s)
Definition: jsonapi.c:56
static JsonParseErrorType report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
Definition: jsonapi.c:2353
#define IS_SEM(x)
Definition: jsonapi.c:179
static td_entry td_parser_table[JSON_NUM_NONTERMINALS][JSON_NUM_TERMINALS]
Definition: jsonapi.c:241
static char * get_fname(JsonLexContext *lex)
Definition: jsonapi.c:662
static char pop_prediction(JsonParserStack *pstack)
Definition: jsonapi.c:627
#define ALLOC(size)
Definition: jsonapi.c:57
static bool get_fnull(JsonLexContext *lex)
Definition: jsonapi.c:674
@ 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:613
JsonParseErrorType(* json_struct_action)(void *state)
Definition: jsonapi.h:121
JsonParseErrorType(* json_aelem_action)(void *state, bool isnull)
Definition: jsonapi.h:123
JsonParseErrorType(* json_ofield_action)(void *state, char *fname, bool isnull)
Definition: jsonapi.h:122
JsonParseErrorType(* json_scalar_action)(void *state, char *token, JsonTokenType tokentype)
Definition: jsonapi.h:124
JsonTokenType scalar_tok
Definition: jsonapi.c:152
json_struct_action array_end
Definition: jsonapi.h:151
json_struct_action object_start
Definition: jsonapi.h:148
json_ofield_action object_field_start
Definition: jsonapi.h:152
json_aelem_action array_element_start
Definition: jsonapi.h:154
json_scalar_action scalar
Definition: jsonapi.h:156
void * semstate
Definition: jsonapi.h:147
json_aelem_action array_element_end
Definition: jsonapi.h:155
json_struct_action array_start
Definition: jsonapi.h:150
json_struct_action object_end
Definition: jsonapi.h:149
json_ofield_action object_field_end
Definition: jsonapi.h:153
Definition: jsonapi.c:234

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, JsonLexContext::flags, FREE, 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, JSONLEX_CTX_OWNS_TOKENS, 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(), JsonIncrementalState::started, 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().

◆ setJsonLexContextOwnsTokens()

void setJsonLexContextOwnsTokens ( JsonLexContext lex,
bool  owned_by_context 
)

Definition at line 542 of file jsonapi.c.

544 {
545  if (lex->incremental && lex->inc_state->started)
546  {
547  /*
548  * Switching this flag after parsing has already started is a
549  * programming error.
550  */
551  Assert(false);
552  return;
553  }
554 
555  if (owned_by_context)
557  else

References Assert, JsonLexContext::flags, JsonLexContext::inc_state, JsonLexContext::incremental, JSONLEX_CTX_OWNS_TOKENS, and JsonIncrementalState::started.

Referenced by main().

Variable Documentation

◆ nullSemAction

PGDLLIMPORT const JsonSemAction nullSemAction
extern

Definition at line 287 of file jsonapi.c.

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