PostgreSQL Source Code  git master
jsonapi.c File Reference
#include "postgres.h"
#include "common/jsonapi.h"
#include "mb/pg_wchar.h"
#include "port/pg_lfind.h"
#include "miscadmin.h"
Include dependency graph for jsonapi.c:

Go to the source code of this file.

Macros

#define JSON_ALPHANUMERIC_CHAR(c)
 
#define FAIL_AT_CHAR_START(code)
 
#define FAIL_AT_CHAR_END(code)
 

Enumerations

enum  JsonParseContext {
  JSON_PARSE_VALUE , JSON_PARSE_STRING , JSON_PARSE_ARRAY_START , JSON_PARSE_ARRAY_NEXT ,
  JSON_PARSE_OBJECT_START , JSON_PARSE_OBJECT_LABEL , JSON_PARSE_OBJECT_NEXT , JSON_PARSE_OBJECT_COMMA ,
  JSON_PARSE_END
}
 

Functions

static JsonParseErrorType json_lex_string (JsonLexContext *lex)
 
static JsonParseErrorType json_lex_number (JsonLexContext *lex, char *s, bool *num_err, int *total_len)
 
static JsonParseErrorType parse_scalar (JsonLexContext *lex, JsonSemAction *sem)
 
static JsonParseErrorType parse_object_field (JsonLexContext *lex, JsonSemAction *sem)
 
static JsonParseErrorType parse_object (JsonLexContext *lex, JsonSemAction *sem)
 
static JsonParseErrorType parse_array_element (JsonLexContext *lex, JsonSemAction *sem)
 
static JsonParseErrorType parse_array (JsonLexContext *lex, JsonSemAction *sem)
 
static JsonParseErrorType report_parse_error (JsonParseContext ctx, JsonLexContext *lex)
 
static JsonTokenType lex_peek (JsonLexContext *lex)
 
static JsonParseErrorType lex_expect (JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
 
bool IsValidJsonNumber (const char *str, int len)
 
JsonLexContextmakeJsonLexContextCstringLen (char *json, int len, int encoding, bool need_escapes)
 
JsonParseErrorType pg_parse_json (JsonLexContext *lex, JsonSemAction *sem)
 
JsonParseErrorType json_count_array_elements (JsonLexContext *lex, int *elements)
 
JsonParseErrorType json_lex (JsonLexContext *lex)
 
static char * extract_token (JsonLexContext *lex)
 
char * json_errdetail (JsonParseErrorType error, JsonLexContext *lex)
 

Variables

JsonSemAction nullSemAction
 

Macro Definition Documentation

◆ FAIL_AT_CHAR_END

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

◆ FAIL_AT_CHAR_START

#define FAIL_AT_CHAR_START (   code)
Value:
do { \
lex->token_terminator = s; \
return code; \
} while (0)

◆ JSON_ALPHANUMERIC_CHAR

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

Definition at line 92 of file jsonapi.c.

Enumeration Type Documentation

◆ JsonParseContext

Enumerator
JSON_PARSE_VALUE 
JSON_PARSE_STRING 
JSON_PARSE_ARRAY_START 
JSON_PARSE_ARRAY_NEXT 
JSON_PARSE_OBJECT_START 
JSON_PARSE_OBJECT_LABEL 
JSON_PARSE_OBJECT_NEXT 
JSON_PARSE_OBJECT_COMMA 
JSON_PARSE_END 

Definition at line 33 of file jsonapi.c.

34 {
35  JSON_PARSE_VALUE, /* expecting a value */
36  JSON_PARSE_STRING, /* expecting a string (for a field name) */
37  JSON_PARSE_ARRAY_START, /* saw '[', expecting value or ']' */
38  JSON_PARSE_ARRAY_NEXT, /* saw array element, expecting ',' or ']' */
39  JSON_PARSE_OBJECT_START, /* saw '{', expecting label or '}' */
40  JSON_PARSE_OBJECT_LABEL, /* saw object label, expecting ':' */
41  JSON_PARSE_OBJECT_NEXT, /* saw object value, expecting ',' or '}' */
42  JSON_PARSE_OBJECT_COMMA, /* saw object ',', expecting next label */
43  JSON_PARSE_END /* saw the end of a document, expect nothing */
JsonParseContext
Definition: jsonapi.c:34
@ JSON_PARSE_OBJECT_LABEL
Definition: jsonapi.c:40
@ JSON_PARSE_VALUE
Definition: jsonapi.c:35
@ JSON_PARSE_OBJECT_START
Definition: jsonapi.c:39
@ JSON_PARSE_ARRAY_START
Definition: jsonapi.c:37
@ JSON_PARSE_END
Definition: jsonapi.c:43
@ JSON_PARSE_OBJECT_NEXT
Definition: jsonapi.c:41
@ JSON_PARSE_ARRAY_NEXT
Definition: jsonapi.c:38
@ JSON_PARSE_OBJECT_COMMA
Definition: jsonapi.c:42
@ JSON_PARSE_STRING
Definition: jsonapi.c:36

Function Documentation

◆ extract_token()

static char* extract_token ( JsonLexContext lex)
static

Definition at line 1118 of file jsonapi.c.

1119 {
1120  int toklen = lex->token_terminator - lex->token_start;
1121  char *token = palloc(toklen + 1);
1122 
1123  memcpy(token, lex->token_start, toklen);
1124  token[toklen] = '\0';
1125  return token;
1126 }
#define token
Definition: indent_globs.h:126
void * palloc(Size size)
Definition: mcxt.c:1226
char * token_start
Definition: jsonapi.h:79
char * token_terminator
Definition: jsonapi.h:80

References palloc(), token, JsonLexContext::token_start, and JsonLexContext::token_terminator.

Referenced by json_errdetail().

◆ IsValidJsonNumber()

bool IsValidJsonNumber ( const char *  str,
int  len 
)

Definition at line 105 of file jsonapi.c.

106 {
107  bool numeric_error;
108  int total_len;
109  JsonLexContext dummy_lex;
110 
111  if (len <= 0)
112  return false;
113 
114  /*
115  * json_lex_number expects a leading '-' to have been eaten already.
116  *
117  * having to cast away the constness of str is ugly, but there's not much
118  * easy alternative.
119  */
120  if (*str == '-')
121  {
122  dummy_lex.input = unconstify(char *, str) + 1;
123  dummy_lex.input_length = len - 1;
124  }
125  else
126  {
127  dummy_lex.input = unconstify(char *, str);
128  dummy_lex.input_length = len;
129  }
130 
131  json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error, &total_len);
132 
133  return (!numeric_error) && (total_len == dummy_lex.input_length);
134 }
#define unconstify(underlying_type, expr)
Definition: c.h:1250
static JsonParseErrorType json_lex_number(JsonLexContext *lex, char *s, bool *num_err, int *total_len)
Definition: jsonapi.c:975
const void size_t len
char * input
Definition: jsonapi.h:76
int input_length
Definition: jsonapi.h:77

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

Referenced by datum_to_json(), 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 209 of file jsonapi.c.

210 {
211  JsonLexContext copylex;
212  int count;
213  JsonParseErrorType result;
214 
215  /*
216  * It's safe to do this with a shallow copy because the lexical routines
217  * don't scribble on the input. They do scribble on the other pointers
218  * etc, so doing this with a copy makes that safe.
219  */
220  memcpy(&copylex, lex, sizeof(JsonLexContext));
221  copylex.strval = NULL; /* not interested in values here */
222  copylex.lex_level++;
223 
224  count = 0;
225  result = lex_expect(JSON_PARSE_ARRAY_START, &copylex,
227  if (result != JSON_SUCCESS)
228  return result;
229  if (lex_peek(&copylex) != JSON_TOKEN_ARRAY_END)
230  {
231  while (1)
232  {
233  count++;
234  result = parse_array_element(&copylex, &nullSemAction);
235  if (result != JSON_SUCCESS)
236  return result;
237  if (copylex.token_type != JSON_TOKEN_COMMA)
238  break;
239  result = json_lex(&copylex);
240  if (result != JSON_SUCCESS)
241  return result;
242  }
243  }
244  result = lex_expect(JSON_PARSE_ARRAY_NEXT, &copylex,
246  if (result != JSON_SUCCESS)
247  return result;
248 
249  *elements = count;
250  return JSON_SUCCESS;
251 }
static JsonParseErrorType parse_array_element(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:443
static JsonTokenType lex_peek(JsonLexContext *lex)
Definition: jsonapi.c:71
JsonSemAction nullSemAction
Definition: jsonapi.c:57
static JsonParseErrorType lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
Definition: jsonapi.c:83
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:552
JsonParseErrorType
Definition: jsonapi.h:37
@ JSON_SUCCESS
Definition: jsonapi.h:38
@ JSON_TOKEN_COMMA
Definition: jsonapi.h:28
@ JSON_TOKEN_ARRAY_END
Definition: jsonapi.h:27
@ JSON_TOKEN_ARRAY_START
Definition: jsonapi.h:26
StringInfo strval
Definition: jsonapi.h:86
int lex_level
Definition: jsonapi.h:83
JsonTokenType token_type
Definition: jsonapi.h:82

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

Referenced by get_array_start().

◆ json_errdetail()

char* json_errdetail ( JsonParseErrorType  error,
JsonLexContext lex 
)

Definition at line 1136 of file jsonapi.c.

1137 {
1138  switch (error)
1139  {
1140  case JSON_SUCCESS:
1141  /* fall through to the error code after switch */
1142  break;
1143  case JSON_ESCAPING_INVALID:
1144  return psprintf(_("Escape sequence \"\\%s\" is invalid."),
1145  extract_token(lex));
1147  return psprintf(_("Character with value 0x%02x must be escaped."),
1148  (unsigned char) *(lex->token_terminator));
1149  case JSON_EXPECTED_END:
1150  return psprintf(_("Expected end of input, but found \"%s\"."),
1151  extract_token(lex));
1153  return psprintf(_("Expected array element or \"]\", but found \"%s\"."),
1154  extract_token(lex));
1156  return psprintf(_("Expected \",\" or \"]\", but found \"%s\"."),
1157  extract_token(lex));
1158  case JSON_EXPECTED_COLON:
1159  return psprintf(_("Expected \":\", but found \"%s\"."),
1160  extract_token(lex));
1161  case JSON_EXPECTED_JSON:
1162  return psprintf(_("Expected JSON value, but found \"%s\"."),
1163  extract_token(lex));
1164  case JSON_EXPECTED_MORE:
1165  return _("The input string ended unexpectedly.");
1167  return psprintf(_("Expected string or \"}\", but found \"%s\"."),
1168  extract_token(lex));
1170  return psprintf(_("Expected \",\" or \"}\", but found \"%s\"."),
1171  extract_token(lex));
1172  case JSON_EXPECTED_STRING:
1173  return psprintf(_("Expected string, but found \"%s\"."),
1174  extract_token(lex));
1175  case JSON_INVALID_TOKEN:
1176  return psprintf(_("Token \"%s\" is invalid."),
1177  extract_token(lex));
1179  return _("\\u0000 cannot be converted to text.");
1181  return _("\"\\u\" must be followed by four hexadecimal digits.");
1183  /* note: this case is only reachable in frontend not backend */
1184  return _("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8.");
1186  /* note: this case is only reachable in backend not frontend */
1187  return psprintf(_("Unicode escape value could not be translated to the server's encoding %s."),
1190  return _("Unicode high surrogate must not follow a high surrogate.");
1192  return _("Unicode low surrogate must follow a high surrogate.");
1194  /* fall through to the error code after switch */
1195  break;
1196  }
1197 
1198  /*
1199  * We don't use a default: case, so that the compiler will warn about
1200  * unhandled enum values. But this needs to be here anyway to cover the
1201  * possibility of an incorrect input.
1202  */
1203  elog(ERROR, "unexpected json parse error type: %d", (int) error);
1204  return NULL;
1205 }
#define _(x)
Definition: elog.c:91
#define ERROR
Definition: elog.h:39
static char * extract_token(JsonLexContext *lex)
Definition: jsonapi.c:1118
@ JSON_SEM_ACTION_FAILED
Definition: jsonapi.h:57
@ JSON_EXPECTED_ARRAY_FIRST
Definition: jsonapi.h:41
@ JSON_EXPECTED_MORE
Definition: jsonapi.h:46
@ JSON_UNICODE_HIGH_SURROGATE
Definition: jsonapi.h:55
@ JSON_EXPECTED_COLON
Definition: jsonapi.h:43
@ JSON_EXPECTED_OBJECT_FIRST
Definition: jsonapi.h:47
@ JSON_UNICODE_CODE_POINT_ZERO
Definition: jsonapi.h:51
@ JSON_EXPECTED_STRING
Definition: jsonapi.h:49
@ JSON_UNICODE_ESCAPE_FORMAT
Definition: jsonapi.h:52
@ JSON_UNICODE_UNTRANSLATABLE
Definition: jsonapi.h:54
@ JSON_EXPECTED_OBJECT_NEXT
Definition: jsonapi.h:48
@ JSON_ESCAPING_REQUIRED
Definition: jsonapi.h:40
@ JSON_EXPECTED_JSON
Definition: jsonapi.h:45
@ JSON_INVALID_TOKEN
Definition: jsonapi.h:50
@ JSON_ESCAPING_INVALID
Definition: jsonapi.h:39
@ JSON_EXPECTED_END
Definition: jsonapi.h:44
@ JSON_EXPECTED_ARRAY_NEXT
Definition: jsonapi.h:42
@ JSON_UNICODE_HIGH_ESCAPE
Definition: jsonapi.h:53
@ JSON_UNICODE_LOW_SURROGATE
Definition: jsonapi.h:56
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1274
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static void error(void)
Definition: sql-dyntest.c:147

References _, elog(), ERROR, error(), extract_token(), GetDatabaseEncodingName(), 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_SEM_ACTION_FAILED, JSON_SUCCESS, JSON_UNICODE_CODE_POINT_ZERO, JSON_UNICODE_ESCAPE_FORMAT, JSON_UNICODE_HIGH_ESCAPE, JSON_UNICODE_HIGH_SURROGATE, JSON_UNICODE_LOW_SURROGATE, JSON_UNICODE_UNTRANSLATABLE, psprintf(), and JsonLexContext::token_terminator.

Referenced by json_errsave_error().

◆ json_lex()

JsonParseErrorType json_lex ( JsonLexContext lex)

Definition at line 552 of file jsonapi.c.

553 {
554  char *s;
555  char *const end = lex->input + lex->input_length;
556  JsonParseErrorType result;
557 
558  /* Skip leading whitespace. */
559  s = lex->token_terminator;
560  while (s < end && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
561  {
562  if (*s++ == '\n')
563  {
564  ++lex->line_number;
565  lex->line_start = s;
566  }
567  }
568  lex->token_start = s;
569 
570  /* Determine token type. */
571  if (s >= end)
572  {
573  lex->token_start = NULL;
575  lex->token_terminator = s;
576  lex->token_type = JSON_TOKEN_END;
577  }
578  else
579  {
580  switch (*s)
581  {
582  /* Single-character token, some kind of punctuation mark. */
583  case '{':
585  lex->token_terminator = s + 1;
587  break;
588  case '}':
590  lex->token_terminator = s + 1;
592  break;
593  case '[':
595  lex->token_terminator = s + 1;
597  break;
598  case ']':
600  lex->token_terminator = s + 1;
602  break;
603  case ',':
605  lex->token_terminator = s + 1;
607  break;
608  case ':':
610  lex->token_terminator = s + 1;
612  break;
613  case '"':
614  /* string */
615  result = json_lex_string(lex);
616  if (result != JSON_SUCCESS)
617  return result;
619  break;
620  case '-':
621  /* Negative number. */
622  result = json_lex_number(lex, s + 1, NULL, NULL);
623  if (result != JSON_SUCCESS)
624  return result;
626  break;
627  case '0':
628  case '1':
629  case '2':
630  case '3':
631  case '4':
632  case '5':
633  case '6':
634  case '7':
635  case '8':
636  case '9':
637  /* Positive number. */
638  result = json_lex_number(lex, s, NULL, NULL);
639  if (result != JSON_SUCCESS)
640  return result;
642  break;
643  default:
644  {
645  char *p;
646 
647  /*
648  * We're not dealing with a string, number, legal
649  * punctuation mark, or end of string. The only legal
650  * tokens we might find here are true, false, and null,
651  * but for error reporting purposes we scan until we see a
652  * non-alphanumeric character. That way, we can report
653  * the whole word as an unexpected token, rather than just
654  * some unintuitive prefix thereof.
655  */
656  for (p = s; p < end && JSON_ALPHANUMERIC_CHAR(*p); p++)
657  /* skip */ ;
658 
659  /*
660  * We got some sort of unexpected punctuation or an
661  * otherwise unexpected character, so just complain about
662  * that one character.
663  */
664  if (p == s)
665  {
667  lex->token_terminator = s + 1;
668  return JSON_INVALID_TOKEN;
669  }
670 
671  /*
672  * We've got a real alphanumeric token here. If it
673  * happens to be true, false, or null, all is well. If
674  * not, error out.
675  */
677  lex->token_terminator = p;
678  if (p - s == 4)
679  {
680  if (memcmp(s, "true", 4) == 0)
682  else if (memcmp(s, "null", 4) == 0)
684  else
685  return JSON_INVALID_TOKEN;
686  }
687  else if (p - s == 5 && memcmp(s, "false", 5) == 0)
689  else
690  return JSON_INVALID_TOKEN;
691  }
692  } /* end of switch */
693  }
694 
695  return JSON_SUCCESS;
696 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static JsonParseErrorType json_lex_string(JsonLexContext *lex)
Definition: jsonapi.c:710
#define JSON_ALPHANUMERIC_CHAR(c)
Definition: jsonapi.c:92
@ JSON_TOKEN_FALSE
Definition: jsonapi.h:31
@ JSON_TOKEN_END
Definition: jsonapi.h:33
@ JSON_TOKEN_TRUE
Definition: jsonapi.h:30
@ JSON_TOKEN_OBJECT_END
Definition: jsonapi.h:25
@ JSON_TOKEN_NULL
Definition: jsonapi.h:32
@ JSON_TOKEN_OBJECT_START
Definition: jsonapi.h:24
@ JSON_TOKEN_NUMBER
Definition: jsonapi.h:23
@ JSON_TOKEN_STRING
Definition: jsonapi.h:22
@ JSON_TOKEN_COLON
Definition: jsonapi.h:29
char * prev_token_terminator
Definition: jsonapi.h:81
char * line_start
Definition: jsonapi.h:85
int line_number
Definition: jsonapi.h:84

References if(), JsonLexContext::input, JsonLexContext::input_length, JSON_ALPHANUMERIC_CHAR, JSON_INVALID_TOKEN, json_lex_number(), json_lex_string(), 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, JsonLexContext::line_number, JsonLexContext::line_start, JsonLexContext::prev_token_terminator, 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(), and pg_parse_json().

◆ json_lex_number()

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

Definition at line 975 of file jsonapi.c.

977 {
978  bool error = false;
979  int len = s - lex->input;
980 
981  /* Part (1): leading sign indicator. */
982  /* Caller already did this for us; so do nothing. */
983 
984  /* Part (2): parse main digit string. */
985  if (len < lex->input_length && *s == '0')
986  {
987  s++;
988  len++;
989  }
990  else if (len < lex->input_length && *s >= '1' && *s <= '9')
991  {
992  do
993  {
994  s++;
995  len++;
996  } while (len < lex->input_length && *s >= '0' && *s <= '9');
997  }
998  else
999  error = true;
1000 
1001  /* Part (3): parse optional decimal portion. */
1002  if (len < lex->input_length && *s == '.')
1003  {
1004  s++;
1005  len++;
1006  if (len == lex->input_length || *s < '0' || *s > '9')
1007  error = true;
1008  else
1009  {
1010  do
1011  {
1012  s++;
1013  len++;
1014  } while (len < lex->input_length && *s >= '0' && *s <= '9');
1015  }
1016  }
1017 
1018  /* Part (4): parse optional exponent. */
1019  if (len < lex->input_length && (*s == 'e' || *s == 'E'))
1020  {
1021  s++;
1022  len++;
1023  if (len < lex->input_length && (*s == '+' || *s == '-'))
1024  {
1025  s++;
1026  len++;
1027  }
1028  if (len == lex->input_length || *s < '0' || *s > '9')
1029  error = true;
1030  else
1031  {
1032  do
1033  {
1034  s++;
1035  len++;
1036  } while (len < lex->input_length && *s >= '0' && *s <= '9');
1037  }
1038  }
1039 
1040  /*
1041  * Check for trailing garbage. As in json_lex(), any alphanumeric stuff
1042  * here should be considered part of the token for error-reporting
1043  * purposes.
1044  */
1045  for (; len < lex->input_length && JSON_ALPHANUMERIC_CHAR(*s); s++, len++)
1046  error = true;
1047 
1048  if (total_len != NULL)
1049  *total_len = len;
1050 
1051  if (num_err != NULL)
1052  {
1053  /* let the caller handle any error */
1054  *num_err = error;
1055  }
1056  else
1057  {
1058  /* return token endpoint */
1060  lex->token_terminator = s;
1061  /* handle error if any */
1062  if (error)
1063  return JSON_INVALID_TOKEN;
1064  }
1065 
1066  return JSON_SUCCESS;
1067 }

References error(), JsonLexContext::input, JsonLexContext::input_length, JSON_ALPHANUMERIC_CHAR, JSON_INVALID_TOKEN, JSON_SUCCESS, len, JsonLexContext::prev_token_terminator, and JsonLexContext::token_terminator.

Referenced by IsValidJsonNumber(), and json_lex().

◆ json_lex_string()

static JsonParseErrorType json_lex_string ( JsonLexContext lex)
inlinestatic

Definition at line 710 of file jsonapi.c.

711 {
712  char *s;
713  char *const end = lex->input + lex->input_length;
714  int hi_surrogate = -1;
715 
716  /* Convenience macros for error exits */
717 #define FAIL_AT_CHAR_START(code) \
718  do { \
719  lex->token_terminator = s; \
720  return code; \
721  } while (0)
722 #define FAIL_AT_CHAR_END(code) \
723  do { \
724  lex->token_terminator = \
725  s + pg_encoding_mblen_bounded(lex->input_encoding, s); \
726  return code; \
727  } while (0)
728 
729  if (lex->strval != NULL)
730  resetStringInfo(lex->strval);
731 
732  Assert(lex->input_length > 0);
733  s = lex->token_start;
734  for (;;)
735  {
736  s++;
737  /* Premature end of the string. */
738  if (s >= end)
740  else if (*s == '"')
741  break;
742  else if (*s == '\\')
743  {
744  /* OK, we have an escape character. */
745  s++;
746  if (s >= end)
748  else if (*s == 'u')
749  {
750  int i;
751  int ch = 0;
752 
753  for (i = 1; i <= 4; i++)
754  {
755  s++;
756  if (s >= end)
758  else if (*s >= '0' && *s <= '9')
759  ch = (ch * 16) + (*s - '0');
760  else if (*s >= 'a' && *s <= 'f')
761  ch = (ch * 16) + (*s - 'a') + 10;
762  else if (*s >= 'A' && *s <= 'F')
763  ch = (ch * 16) + (*s - 'A') + 10;
764  else
766  }
767  if (lex->strval != NULL)
768  {
769  /*
770  * Combine surrogate pairs.
771  */
772  if (is_utf16_surrogate_first(ch))
773  {
774  if (hi_surrogate != -1)
776  hi_surrogate = ch;
777  continue;
778  }
779  else if (is_utf16_surrogate_second(ch))
780  {
781  if (hi_surrogate == -1)
783  ch = surrogate_pair_to_codepoint(hi_surrogate, ch);
784  hi_surrogate = -1;
785  }
786 
787  if (hi_surrogate != -1)
789 
790  /*
791  * Reject invalid cases. We can't have a value above
792  * 0xFFFF here (since we only accepted 4 hex digits
793  * above), so no need to test for out-of-range chars.
794  */
795  if (ch == 0)
796  {
797  /* We can't allow this, since our TEXT type doesn't */
799  }
800 
801  /*
802  * Add the represented character to lex->strval. In the
803  * backend, we can let pg_unicode_to_server_noerror()
804  * handle any required character set conversion; in
805  * frontend, we can only deal with trivial conversions.
806  */
807 #ifndef FRONTEND
808  {
809  char cbuf[MAX_UNICODE_EQUIVALENT_STRING + 1];
810 
811  if (!pg_unicode_to_server_noerror(ch, (unsigned char *) cbuf))
813  appendStringInfoString(lex->strval, cbuf);
814  }
815 #else
816  if (lex->input_encoding == PG_UTF8)
817  {
818  /* OK, we can map the code point to UTF8 easily */
819  char utf8str[5];
820  int utf8len;
821 
822  unicode_to_utf8(ch, (unsigned char *) utf8str);
823  utf8len = pg_utf_mblen((unsigned char *) utf8str);
824  appendBinaryStringInfo(lex->strval, utf8str, utf8len);
825  }
826  else if (ch <= 0x007f)
827  {
828  /* The ASCII range is the same in all encodings */
829  appendStringInfoChar(lex->strval, (char) ch);
830  }
831  else
833 #endif /* FRONTEND */
834  }
835  }
836  else if (lex->strval != NULL)
837  {
838  if (hi_surrogate != -1)
840 
841  switch (*s)
842  {
843  case '"':
844  case '\\':
845  case '/':
846  appendStringInfoChar(lex->strval, *s);
847  break;
848  case 'b':
849  appendStringInfoChar(lex->strval, '\b');
850  break;
851  case 'f':
852  appendStringInfoChar(lex->strval, '\f');
853  break;
854  case 'n':
855  appendStringInfoChar(lex->strval, '\n');
856  break;
857  case 'r':
858  appendStringInfoChar(lex->strval, '\r');
859  break;
860  case 't':
861  appendStringInfoChar(lex->strval, '\t');
862  break;
863  default:
864 
865  /*
866  * Not a valid string escape, so signal error. We
867  * adjust token_start so that just the escape sequence
868  * is reported, not the whole string.
869  */
870  lex->token_start = s;
872  }
873  }
874  else if (strchr("\"\\/bfnrt", *s) == NULL)
875  {
876  /*
877  * Simpler processing if we're not bothered about de-escaping
878  *
879  * It's very tempting to remove the strchr() call here and
880  * replace it with a switch statement, but testing so far has
881  * shown it's not a performance win.
882  */
883  lex->token_start = s;
885  }
886  }
887  else
888  {
889  char *p = s;
890 
891  if (hi_surrogate != -1)
893 
894  /*
895  * Skip to the first byte that requires special handling, so we
896  * can batch calls to appendBinaryStringInfo.
897  */
898  while (p < end - sizeof(Vector8) &&
899  !pg_lfind8('\\', (uint8 *) p, sizeof(Vector8)) &&
900  !pg_lfind8('"', (uint8 *) p, sizeof(Vector8)) &&
901  !pg_lfind8_le(31, (uint8 *) p, sizeof(Vector8)))
902  p += sizeof(Vector8);
903 
904  for (; p < end; p++)
905  {
906  if (*p == '\\' || *p == '"')
907  break;
908  else if ((unsigned char) *p <= 31)
909  {
910  /* Per RFC4627, these characters MUST be escaped. */
911  /*
912  * Since *p isn't printable, exclude it from the context
913  * string
914  */
915  lex->token_terminator = p;
916  return JSON_ESCAPING_REQUIRED;
917  }
918  }
919 
920  if (lex->strval != NULL)
921  appendBinaryStringInfo(lex->strval, s, p - s);
922 
923  /*
924  * s will be incremented at the top of the loop, so set it to just
925  * behind our lookahead position
926  */
927  s = p - 1;
928  }
929  }
930 
931  if (hi_surrogate != -1)
932  {
933  lex->token_terminator = s + 1;
935  }
936 
937  /* Hooray, we found the end of the string! */
939  lex->token_terminator = s + 1;
940  return JSON_SUCCESS;
941 
942 #undef FAIL_AT_CHAR_START
943 #undef FAIL_AT_CHAR_END
944 }
unsigned char uint8
Definition: c.h:488
int i
Definition: isn.c:73
#define FAIL_AT_CHAR_START(code)
#define FAIL_AT_CHAR_END(code)
Assert(fmt[strlen(fmt) - 1] !='\n')
bool pg_unicode_to_server_noerror(pg_wchar c, unsigned char *s)
Definition: mbutils.c:927
static bool pg_lfind8_le(uint8 key, uint8 *base, uint32 nelem)
Definition: pg_lfind.h:58
static bool pg_lfind8(uint8 key, uint8 *base, uint32 nelem)
Definition: pg_lfind.h:26
@ PG_UTF8
Definition: pg_wchar.h:232
#define MAX_UNICODE_EQUIVALENT_STRING
Definition: pg_wchar.h:329
static pg_wchar surrogate_pair_to_codepoint(pg_wchar first, pg_wchar second)
Definition: pg_wchar.h:543
static bool is_utf16_surrogate_first(pg_wchar c)
Definition: pg_wchar.h:531
static bool is_utf16_surrogate_second(pg_wchar c)
Definition: pg_wchar.h:537
uint64 Vector8
Definition: simd.h:60
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:75
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:227
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
int input_encoding
Definition: jsonapi.h:78
unsigned char * unicode_to_utf8(pg_wchar c, unsigned char *utf8string)
Definition: wchar.c:483
int pg_utf_mblen(const unsigned char *s)
Definition: wchar.c:549

References appendBinaryStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), FAIL_AT_CHAR_END, FAIL_AT_CHAR_START, i, JsonLexContext::input, JsonLexContext::input_encoding, JsonLexContext::input_length, is_utf16_surrogate_first(), is_utf16_surrogate_second(), JSON_ESCAPING_INVALID, JSON_ESCAPING_REQUIRED, JSON_INVALID_TOKEN, JSON_SUCCESS, JSON_UNICODE_CODE_POINT_ZERO, JSON_UNICODE_ESCAPE_FORMAT, JSON_UNICODE_HIGH_ESCAPE, JSON_UNICODE_HIGH_SURROGATE, JSON_UNICODE_LOW_SURROGATE, JSON_UNICODE_UNTRANSLATABLE, MAX_UNICODE_EQUIVALENT_STRING, pg_lfind8(), pg_lfind8_le(), pg_unicode_to_server_noerror(), PG_UTF8, pg_utf_mblen(), JsonLexContext::prev_token_terminator, resetStringInfo(), JsonLexContext::strval, surrogate_pair_to_codepoint(), JsonLexContext::token_start, JsonLexContext::token_terminator, and unicode_to_utf8().

Referenced by json_lex().

◆ lex_expect()

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

Definition at line 83 of file jsonapi.c.

84 {
85  if (lex_peek(lex) == token)
86  return json_lex(lex);
87  else
88  return report_parse_error(ctx, lex);
89 }
static JsonParseErrorType report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
Definition: jsonapi.c:1075

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

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

◆ lex_peek()

static JsonTokenType lex_peek ( JsonLexContext lex)
inlinestatic

◆ makeJsonLexContextCstringLen()

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

Definition at line 145 of file jsonapi.c.

146 {
147  JsonLexContext *lex = palloc0(sizeof(JsonLexContext));
148 
149  lex->input = lex->token_terminator = lex->line_start = json;
150  lex->line_number = 1;
151  lex->input_length = len;
152  lex->input_encoding = encoding;
153  if (need_escapes)
154  lex->strval = makeStringInfo();
155  return lex;
156 }
void * palloc0(Size size)
Definition: mcxt.c:1257
int32 encoding
Definition: pg_database.h:41
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41

References encoding, JsonLexContext::input, JsonLexContext::input_encoding, JsonLexContext::input_length, len, JsonLexContext::line_number, JsonLexContext::line_start, makeStringInfo(), palloc0(), JsonLexContext::strval, and JsonLexContext::token_terminator.

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

◆ parse_array()

static JsonParseErrorType parse_array ( JsonLexContext lex,
JsonSemAction sem 
)
static

Definition at line 487 of file jsonapi.c.

488 {
489  /*
490  * an array is a possibly empty sequence of array elements, separated by
491  * commas and surrounded by square brackets.
492  */
493  json_struct_action astart = sem->array_start;
494  json_struct_action aend = sem->array_end;
495  JsonParseErrorType result;
496 
497 #ifndef FRONTEND
499 #endif
500 
501  if (astart != NULL)
502  {
503  result = (*astart) (sem->semstate);
504  if (result != JSON_SUCCESS)
505  return result;
506  }
507 
508  /*
509  * Data inside an array is at a higher nesting level than the array
510  * itself. Note that we increment this after we call the semantic routine
511  * for the array start and restore it before we call the routine for the
512  * array end.
513  */
514  lex->lex_level++;
515 
517  if (result == JSON_SUCCESS && lex_peek(lex) != JSON_TOKEN_ARRAY_END)
518  {
519  result = parse_array_element(lex, sem);
520 
521  while (result == JSON_SUCCESS && lex_peek(lex) == JSON_TOKEN_COMMA)
522  {
523  result = json_lex(lex);
524  if (result != JSON_SUCCESS)
525  break;
526  result = parse_array_element(lex, sem);
527  }
528  }
529  if (result != JSON_SUCCESS)
530  return result;
531 
533  if (result != JSON_SUCCESS)
534  return result;
535 
536  lex->lex_level--;
537 
538  if (aend != NULL)
539  {
540  result = (*aend) (sem->semstate);
541  if (result != JSON_SUCCESS)
542  return result;
543  }
544 
545  return JSON_SUCCESS;
546 }
JsonParseErrorType(* json_struct_action)(void *state)
Definition: jsonapi.h:89
void check_stack_depth(void)
Definition: postgres.c:3508
json_struct_action array_end
Definition: jsonapi.h:118
void * semstate
Definition: jsonapi.h:114
json_struct_action array_start
Definition: jsonapi.h:117

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

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

◆ parse_array_element()

static JsonParseErrorType parse_array_element ( JsonLexContext lex,
JsonSemAction sem 
)
static

Definition at line 443 of file jsonapi.c.

444 {
447  JsonTokenType tok = lex_peek(lex);
448  JsonParseErrorType result;
449  bool isnull;
450 
451  isnull = tok == JSON_TOKEN_NULL;
452 
453  if (astart != NULL)
454  {
455  result = (*astart) (sem->semstate, isnull);
456  if (result != JSON_SUCCESS)
457  return result;
458  }
459 
460  /* an array element is any object, array or scalar */
461  switch (tok)
462  {
464  result = parse_object(lex, sem);
465  break;
467  result = parse_array(lex, sem);
468  break;
469  default:
470  result = parse_scalar(lex, sem);
471  }
472 
473  if (result != JSON_SUCCESS)
474  return result;
475 
476  if (aend != NULL)
477  {
478  result = (*aend) (sem->semstate, isnull);
479  if (result != JSON_SUCCESS)
480  return result;
481  }
482 
483  return JSON_SUCCESS;
484 }
static JsonParseErrorType parse_object(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:369
static JsonParseErrorType parse_array(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:487
static JsonParseErrorType parse_scalar(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:263
JsonParseErrorType(* json_aelem_action)(void *state, bool isnull)
Definition: jsonapi.h:91
JsonTokenType
Definition: jsonapi.h:20
json_aelem_action array_element_start
Definition: jsonapi.h:121
json_aelem_action array_element_end
Definition: jsonapi.h:122

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

Referenced by json_count_array_elements(), and parse_array().

◆ parse_object()

static JsonParseErrorType parse_object ( JsonLexContext lex,
JsonSemAction sem 
)
static

Definition at line 369 of file jsonapi.c.

370 {
371  /*
372  * an object is a possibly empty sequence of object fields, separated by
373  * commas and surrounded by curly braces.
374  */
375  json_struct_action ostart = sem->object_start;
376  json_struct_action oend = sem->object_end;
377  JsonTokenType tok;
378  JsonParseErrorType result;
379 
380 #ifndef FRONTEND
382 #endif
383 
384  if (ostart != NULL)
385  {
386  result = (*ostart) (sem->semstate);
387  if (result != JSON_SUCCESS)
388  return result;
389  }
390 
391  /*
392  * Data inside an object is at a higher nesting level than the object
393  * itself. Note that we increment this after we call the semantic routine
394  * for the object start and restore it before we call the routine for the
395  * object end.
396  */
397  lex->lex_level++;
398 
400  result = json_lex(lex);
401  if (result != JSON_SUCCESS)
402  return result;
403 
404  tok = lex_peek(lex);
405  switch (tok)
406  {
407  case JSON_TOKEN_STRING:
408  result = parse_object_field(lex, sem);
409  while (result == JSON_SUCCESS && lex_peek(lex) == JSON_TOKEN_COMMA)
410  {
411  result = json_lex(lex);
412  if (result != JSON_SUCCESS)
413  break;
414  result = parse_object_field(lex, sem);
415  }
416  break;
418  break;
419  default:
420  /* case of an invalid initial token inside the object */
422  }
423  if (result != JSON_SUCCESS)
424  return result;
425 
427  if (result != JSON_SUCCESS)
428  return result;
429 
430  lex->lex_level--;
431 
432  if (oend != NULL)
433  {
434  result = (*oend) (sem->semstate);
435  if (result != JSON_SUCCESS)
436  return result;
437  }
438 
439  return JSON_SUCCESS;
440 }
static JsonParseErrorType parse_object_field(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:307
json_struct_action object_start
Definition: jsonapi.h:115
json_struct_action object_end
Definition: jsonapi.h:116

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

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

◆ parse_object_field()

static JsonParseErrorType parse_object_field ( JsonLexContext lex,
JsonSemAction sem 
)
static

Definition at line 307 of file jsonapi.c.

308 {
309  /*
310  * An object field is "fieldname" : value where value can be a scalar,
311  * object or array. Note: in user-facing docs and error messages, we
312  * generally call a field name a "key".
313  */
314 
315  char *fname = NULL; /* keep compiler quiet */
318  bool isnull;
319  JsonTokenType tok;
320  JsonParseErrorType result;
321 
322  if (lex_peek(lex) != JSON_TOKEN_STRING)
324  if ((ostart != NULL || oend != NULL) && lex->strval != NULL)
325  fname = pstrdup(lex->strval->data);
326  result = json_lex(lex);
327  if (result != JSON_SUCCESS)
328  return result;
329 
331  if (result != JSON_SUCCESS)
332  return result;
333 
334  tok = lex_peek(lex);
335  isnull = tok == JSON_TOKEN_NULL;
336 
337  if (ostart != NULL)
338  {
339  result = (*ostart) (sem->semstate, fname, isnull);
340  if (result != JSON_SUCCESS)
341  return result;
342  }
343 
344  switch (tok)
345  {
347  result = parse_object(lex, sem);
348  break;
350  result = parse_array(lex, sem);
351  break;
352  default:
353  result = parse_scalar(lex, sem);
354  }
355  if (result != JSON_SUCCESS)
356  return result;
357 
358  if (oend != NULL)
359  {
360  result = (*oend) (sem->semstate, fname, isnull);
361  if (result != JSON_SUCCESS)
362  return result;
363  }
364 
365  return JSON_SUCCESS;
366 }
JsonParseErrorType(* json_ofield_action)(void *state, char *fname, bool isnull)
Definition: jsonapi.h:90
char * pstrdup(const char *in)
Definition: mcxt.c:1644
json_ofield_action object_field_start
Definition: jsonapi.h:119
json_ofield_action object_field_end
Definition: jsonapi.h:120

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

Referenced by parse_object().

◆ parse_scalar()

static JsonParseErrorType parse_scalar ( JsonLexContext lex,
JsonSemAction sem 
)
inlinestatic

Definition at line 263 of file jsonapi.c.

264 {
265  char *val = NULL;
266  json_scalar_action sfunc = sem->scalar;
267  JsonTokenType tok = lex_peek(lex);
268  JsonParseErrorType result;
269 
270  /* a scalar must be a string, a number, true, false, or null */
271  if (tok != JSON_TOKEN_STRING && tok != JSON_TOKEN_NUMBER &&
272  tok != JSON_TOKEN_TRUE && tok != JSON_TOKEN_FALSE &&
273  tok != JSON_TOKEN_NULL)
275 
276  /* if no semantic function, just consume the token */
277  if (sfunc == NULL)
278  return json_lex(lex);
279 
280  /* extract the de-escaped string value, or the raw lexeme */
281  if (lex_peek(lex) == JSON_TOKEN_STRING)
282  {
283  if (lex->strval != NULL)
284  val = pstrdup(lex->strval->data);
285  }
286  else
287  {
288  int len = (lex->token_terminator - lex->token_start);
289 
290  val = palloc(len + 1);
291  memcpy(val, lex->token_start, len);
292  val[len] = '\0';
293  }
294 
295  /* consume the token */
296  result = json_lex(lex);
297  if (result != JSON_SUCCESS)
298  return result;
299 
300  /* invoke the callback */
301  result = (*sfunc) (sem->semstate, val, tok);
302 
303  return result;
304 }
long val
Definition: informix.c:664
JsonParseErrorType(* json_scalar_action)(void *state, char *token, JsonTokenType tokentype)
Definition: jsonapi.h:92
json_scalar_action scalar
Definition: jsonapi.h:123

References StringInfoData::data, json_lex(), JSON_PARSE_VALUE, JSON_SUCCESS, JSON_TOKEN_FALSE, JSON_TOKEN_NULL, JSON_TOKEN_NUMBER, JSON_TOKEN_STRING, JSON_TOKEN_TRUE, len, lex_peek(), palloc(), pstrdup(), report_parse_error(), JsonSemAction::scalar, JsonSemAction::semstate, JsonLexContext::strval, JsonLexContext::token_start, JsonLexContext::token_terminator, and val.

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

◆ pg_parse_json()

JsonParseErrorType pg_parse_json ( JsonLexContext lex,
JsonSemAction sem 
)

Definition at line 169 of file jsonapi.c.

170 {
171  JsonTokenType tok;
172  JsonParseErrorType result;
173 
174  /* get the initial token */
175  result = json_lex(lex);
176  if (result != JSON_SUCCESS)
177  return result;
178 
179  tok = lex_peek(lex);
180 
181  /* parse by recursive descent */
182  switch (tok)
183  {
185  result = parse_object(lex, sem);
186  break;
188  result = parse_array(lex, sem);
189  break;
190  default:
191  result = parse_scalar(lex, sem); /* json can be a bare scalar */
192  }
193 
194  if (result == JSON_SUCCESS)
195  result = lex_expect(JSON_PARSE_END, lex, JSON_TOKEN_END);
196 
197  return result;
198 }

References json_lex(), JSON_PARSE_END, JSON_SUCCESS, JSON_TOKEN_ARRAY_START, JSON_TOKEN_END, JSON_TOKEN_OBJECT_START, lex_expect(), lex_peek(), parse_array(), parse_object(), and parse_scalar().

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

◆ report_parse_error()

static JsonParseErrorType report_parse_error ( JsonParseContext  ctx,
JsonLexContext lex 
)
static

Definition at line 1075 of file jsonapi.c.

1076 {
1077  /* Handle case where the input ended prematurely. */
1078  if (lex->token_start == NULL || lex->token_type == JSON_TOKEN_END)
1079  return JSON_EXPECTED_MORE;
1080 
1081  /* Otherwise choose the error type based on the parsing context. */
1082  switch (ctx)
1083  {
1084  case JSON_PARSE_END:
1085  return JSON_EXPECTED_END;
1086  case JSON_PARSE_VALUE:
1087  return JSON_EXPECTED_JSON;
1088  case JSON_PARSE_STRING:
1089  return JSON_EXPECTED_STRING;
1092  case JSON_PARSE_ARRAY_NEXT:
1093  return JSON_EXPECTED_ARRAY_NEXT;
1097  return JSON_EXPECTED_COLON;
1101  return JSON_EXPECTED_STRING;
1102  }
1103 
1104  /*
1105  * We don't use a default: case, so that the compiler will warn about
1106  * unhandled enum values.
1107  */
1108  Assert(false);
1109  return JSON_SUCCESS; /* silence stupider compilers */
1110 }

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

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

Variable Documentation

◆ nullSemAction

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

Definition at line 57 of file jsonapi.c.

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