PostgreSQL Source Code  git master
jsonapi.h File Reference
#include "lib/stringinfo.h"
Include dependency graph for jsonapi.h:
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
 

Typedefs

typedef struct JsonLexContext JsonLexContext
 
typedef void(* json_struct_action) (void *state)
 
typedef void(* json_ofield_action) (void *state, char *fname, bool isnull)
 
typedef void(* json_aelem_action) (void *state, bool isnull)
 
typedef void(* 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_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_UNICODE_CODE_POINT_ZERO, JSON_UNICODE_ESCAPE_FORMAT, JSON_UNICODE_HIGH_ESCAPE,
  JSON_UNICODE_HIGH_SURROGATE, JSON_UNICODE_LOW_SURROGATE
}
 

Functions

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

Variables

JsonSemAction nullSemAction
 

Typedef Documentation

◆ json_aelem_action

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

Definition at line 89 of file jsonapi.h.

◆ json_ofield_action

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

Definition at line 88 of file jsonapi.h.

◆ json_scalar_action

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

Definition at line 90 of file jsonapi.h.

◆ json_struct_action

typedef void(* json_struct_action) (void *state)

Definition at line 87 of file jsonapi.h.

◆ JsonLexContext

◆ JsonSemAction

typedef struct JsonSemAction JsonSemAction

Enumeration Type Documentation

◆ JsonParseErrorType

Enumerator
JSON_SUCCESS 
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_UNICODE_CODE_POINT_ZERO 
JSON_UNICODE_ESCAPE_FORMAT 
JSON_UNICODE_HIGH_ESCAPE 
JSON_UNICODE_HIGH_SURROGATE 
JSON_UNICODE_LOW_SURROGATE 

Definition at line 36 of file jsonapi.h.

◆ 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 19 of file jsonapi.h.

Function Documentation

◆ IsValidJsonNumber()

bool IsValidJsonNumber ( const char *  str,
int  len 
)

Definition at line 115 of file jsonapi.c.

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

Referenced by datum_to_json(), hstore_to_json_loose(), and hstore_to_jsonb_loose().

116 {
117  bool numeric_error;
118  int total_len;
119  JsonLexContext dummy_lex;
120 
121  if (len <= 0)
122  return false;
123 
124  /*
125  * json_lex_number expects a leading '-' to have been eaten already.
126  *
127  * having to cast away the constness of str is ugly, but there's not much
128  * easy alternative.
129  */
130  if (*str == '-')
131  {
132  dummy_lex.input = unconstify(char *, str) + 1;
133  dummy_lex.input_length = len - 1;
134  }
135  else
136  {
137  dummy_lex.input = unconstify(char *, str);
138  dummy_lex.input_length = len;
139  }
140 
141  json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error, &total_len);
142 
143  return (!numeric_error) && (total_len == dummy_lex.input_length);
144 }
int input_length
Definition: jsonapi.h:75
#define unconstify(underlying_type, expr)
Definition: c.h:1243
char * input
Definition: jsonapi.h:74
static JsonParseErrorType json_lex_number(JsonLexContext *lex, char *s, bool *num_err, int *total_len)
Definition: jsonapi.c:916

◆ json_count_array_elements()

JsonParseErrorType json_count_array_elements ( JsonLexContext lex,
int *  elements 
)

Definition at line 219 of file jsonapi.c.

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(), parse_array_element(), JsonLexContext::strval, and JsonLexContext::token_type.

Referenced by get_array_start().

220 {
221  JsonLexContext copylex;
222  int count;
223  JsonParseErrorType result;
224 
225  /*
226  * It's safe to do this with a shallow copy because the lexical routines
227  * don't scribble on the input. They do scribble on the other pointers
228  * etc, so doing this with a copy makes that safe.
229  */
230  memcpy(&copylex, lex, sizeof(JsonLexContext));
231  copylex.strval = NULL; /* not interested in values here */
232  copylex.lex_level++;
233 
234  count = 0;
235  result = lex_expect(JSON_PARSE_ARRAY_START, &copylex,
237  if (result != JSON_SUCCESS)
238  return result;
239  if (lex_peek(&copylex) != JSON_TOKEN_ARRAY_END)
240  {
241  while (1)
242  {
243  count++;
244  result = parse_array_element(&copylex, &nullSemAction);
245  if (result != JSON_SUCCESS)
246  return result;
247  if (copylex.token_type != JSON_TOKEN_COMMA)
248  break;
249  result = json_lex(&copylex);
250  if (result != JSON_SUCCESS)
251  return result;
252  }
253  }
254  result = lex_expect(JSON_PARSE_ARRAY_NEXT, &copylex,
256  if (result != JSON_SUCCESS)
257  return result;
258 
259  *elements = count;
260  return JSON_SUCCESS;
261 }
JsonTokenType token_type
Definition: jsonapi.h:80
JsonSemAction nullSemAction
Definition: jsonapi.c:67
int lex_level
Definition: jsonapi.h:81
StringInfo strval
Definition: jsonapi.h:84
JsonParseErrorType
Definition: jsonapi.h:36
static JsonParseErrorType parse_array_element(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:434
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:526
static JsonTokenType lex_peek(JsonLexContext *lex)
Definition: jsonapi.c:81
static JsonParseErrorType lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
Definition: jsonapi.c:93

◆ json_errdetail()

char* json_errdetail ( JsonParseErrorType  error,
JsonLexContext lex 
)

Definition at line 1058 of file jsonapi.c.

References _, extract_token(), 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_log_and_abort, JSON_SUCCESS, JSON_UNICODE_CODE_POINT_ZERO, JSON_UNICODE_ESCAPE_FORMAT, JSON_UNICODE_HIGH_ESCAPE, JSON_UNICODE_HIGH_SURROGATE, JSON_UNICODE_LOW_SURROGATE, psprintf(), and JsonLexContext::token_terminator.

Referenced by json_ereport_error(), and json_parse_manifest().

1059 {
1060  switch (error)
1061  {
1062  case JSON_SUCCESS:
1063  /* fall through to the error code after switch */
1064  break;
1065  case JSON_ESCAPING_INVALID:
1066  return psprintf(_("Escape sequence \"\\%s\" is invalid."),
1067  extract_token(lex));
1069  return psprintf(_("Character with value 0x%02x must be escaped."),
1070  (unsigned char) *(lex->token_terminator));
1071  case JSON_EXPECTED_END:
1072  return psprintf(_("Expected end of input, but found \"%s\"."),
1073  extract_token(lex));
1075  return psprintf(_("Expected array element or \"]\", but found \"%s\"."),
1076  extract_token(lex));
1078  return psprintf(_("Expected \",\" or \"]\", but found \"%s\"."),
1079  extract_token(lex));
1080  case JSON_EXPECTED_COLON:
1081  return psprintf(_("Expected \":\", but found \"%s\"."),
1082  extract_token(lex));
1083  case JSON_EXPECTED_JSON:
1084  return psprintf(_("Expected JSON value, but found \"%s\"."),
1085  extract_token(lex));
1086  case JSON_EXPECTED_MORE:
1087  return _("The input string ended unexpectedly.");
1089  return psprintf(_("Expected string or \"}\", but found \"%s\"."),
1090  extract_token(lex));
1092  return psprintf(_("Expected \",\" or \"}\", but found \"%s\"."),
1093  extract_token(lex));
1094  case JSON_EXPECTED_STRING:
1095  return psprintf(_("Expected string, but found \"%s\"."),
1096  extract_token(lex));
1097  case JSON_INVALID_TOKEN:
1098  return psprintf(_("Token \"%s\" is invalid."),
1099  extract_token(lex));
1101  return _("\\u0000 cannot be converted to text.");
1103  return _("\"\\u\" must be followed by four hexadecimal digits.");
1105  /* note: this case is only reachable in frontend not backend */
1106  return _("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8.");
1108  return _("Unicode high surrogate must not follow a high surrogate.");
1110  return _("Unicode low surrogate must follow a high surrogate.");
1111  }
1112 
1113  /*
1114  * We don't use a default: case, so that the compiler will warn about
1115  * unhandled enum values. But this needs to be here anyway to cover the
1116  * possibility of an incorrect input.
1117  */
1118  json_log_and_abort("unexpected json parse error type: %d", (int) error);
1119  return NULL; /* silence stupider compilers */
1120 }
static void error(void)
Definition: sql-dyntest.c:147
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static char * extract_token(JsonLexContext *lex)
Definition: jsonapi.c:1126
char * token_terminator
Definition: jsonapi.h:78
#define json_log_and_abort(...)
Definition: jsonapi.c:34
#define _(x)
Definition: elog.c:89

◆ json_lex()

JsonParseErrorType json_lex ( JsonLexContext lex)

Definition at line 526 of file jsonapi.c.

References 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_typeof(), lex_expect(), parse_array(), parse_object(), parse_object_field(), parse_scalar(), and pg_parse_json().

527 {
528  char *s;
529  int len;
530  JsonParseErrorType result;
531 
532  /* Skip leading whitespace. */
533  s = lex->token_terminator;
534  len = s - lex->input;
535  while (len < lex->input_length &&
536  (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
537  {
538  if (*s++ == '\n')
539  {
540  ++lex->line_number;
541  lex->line_start = s;
542  }
543  len++;
544  }
545  lex->token_start = s;
546 
547  /* Determine token type. */
548  if (len >= lex->input_length)
549  {
550  lex->token_start = NULL;
552  lex->token_terminator = s;
553  lex->token_type = JSON_TOKEN_END;
554  }
555  else
556  {
557  switch (*s)
558  {
559  /* Single-character token, some kind of punctuation mark. */
560  case '{':
562  lex->token_terminator = s + 1;
564  break;
565  case '}':
567  lex->token_terminator = s + 1;
569  break;
570  case '[':
572  lex->token_terminator = s + 1;
574  break;
575  case ']':
577  lex->token_terminator = s + 1;
579  break;
580  case ',':
582  lex->token_terminator = s + 1;
584  break;
585  case ':':
587  lex->token_terminator = s + 1;
589  break;
590  case '"':
591  /* string */
592  result = json_lex_string(lex);
593  if (result != JSON_SUCCESS)
594  return result;
596  break;
597  case '-':
598  /* Negative number. */
599  result = json_lex_number(lex, s + 1, NULL, NULL);
600  if (result != JSON_SUCCESS)
601  return result;
603  break;
604  case '0':
605  case '1':
606  case '2':
607  case '3':
608  case '4':
609  case '5':
610  case '6':
611  case '7':
612  case '8':
613  case '9':
614  /* Positive number. */
615  result = json_lex_number(lex, s, NULL, NULL);
616  if (result != JSON_SUCCESS)
617  return result;
619  break;
620  default:
621  {
622  char *p;
623 
624  /*
625  * We're not dealing with a string, number, legal
626  * punctuation mark, or end of string. The only legal
627  * tokens we might find here are true, false, and null,
628  * but for error reporting purposes we scan until we see a
629  * non-alphanumeric character. That way, we can report
630  * the whole word as an unexpected token, rather than just
631  * some unintuitive prefix thereof.
632  */
633  for (p = s; p - s < lex->input_length - len && JSON_ALPHANUMERIC_CHAR(*p); p++)
634  /* skip */ ;
635 
636  /*
637  * We got some sort of unexpected punctuation or an
638  * otherwise unexpected character, so just complain about
639  * that one character.
640  */
641  if (p == s)
642  {
644  lex->token_terminator = s + 1;
645  return JSON_INVALID_TOKEN;
646  }
647 
648  /*
649  * We've got a real alphanumeric token here. If it
650  * happens to be true, false, or null, all is well. If
651  * not, error out.
652  */
654  lex->token_terminator = p;
655  if (p - s == 4)
656  {
657  if (memcmp(s, "true", 4) == 0)
659  else if (memcmp(s, "null", 4) == 0)
661  else
662  return JSON_INVALID_TOKEN;
663  }
664  else if (p - s == 5 && memcmp(s, "false", 5) == 0)
666  else
667  return JSON_INVALID_TOKEN;
668 
669  }
670  } /* end of switch */
671  }
672 
673  return JSON_SUCCESS;
674 }
int line_number
Definition: jsonapi.h:82
static JsonParseErrorType json_lex_string(JsonLexContext *lex)
Definition: jsonapi.c:680
JsonTokenType token_type
Definition: jsonapi.h:80
char * prev_token_terminator
Definition: jsonapi.h:79
char * line_start
Definition: jsonapi.h:83
int input_length
Definition: jsonapi.h:75
char * token_start
Definition: jsonapi.h:77
#define JSON_ALPHANUMERIC_CHAR(c)
Definition: jsonapi.c:102
char * token_terminator
Definition: jsonapi.h:78
JsonParseErrorType
Definition: jsonapi.h:36
char * input
Definition: jsonapi.h:74
static JsonParseErrorType json_lex_number(JsonLexContext *lex, char *s, bool *num_err, int *total_len)
Definition: jsonapi.c:916

◆ makeJsonLexContextCstringLen()

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

Definition at line 155 of file jsonapi.c.

References encoding, JsonLexContext::input, JsonLexContext::input_encoding, JsonLexContext::input_length, 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().

156 {
157  JsonLexContext *lex = palloc0(sizeof(JsonLexContext));
158 
159  lex->input = lex->token_terminator = lex->line_start = json;
160  lex->line_number = 1;
161  lex->input_length = len;
162  lex->input_encoding = encoding;
163  if (need_escapes)
164  lex->strval = makeStringInfo();
165  return lex;
166 }
int line_number
Definition: jsonapi.h:82
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
char * line_start
Definition: jsonapi.h:83
int input_length
Definition: jsonapi.h:75
int input_encoding
Definition: jsonapi.h:76
StringInfo strval
Definition: jsonapi.h:84
void * palloc0(Size size)
Definition: mcxt.c:981
char * token_terminator
Definition: jsonapi.h:78
char * input
Definition: jsonapi.h:74
int32 encoding
Definition: pg_database.h:41

◆ pg_parse_json()

JsonParseErrorType pg_parse_json ( JsonLexContext lex,
JsonSemAction sem 
)

Definition at line 179 of file jsonapi.c.

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(), and pg_parse_json_or_ereport().

180 {
181  JsonTokenType tok;
182  JsonParseErrorType result;
183 
184  /* get the initial token */
185  result = json_lex(lex);
186  if (result != JSON_SUCCESS)
187  return result;
188 
189  tok = lex_peek(lex);
190 
191  /* parse by recursive descent */
192  switch (tok)
193  {
195  result = parse_object(lex, sem);
196  break;
198  result = parse_array(lex, sem);
199  break;
200  default:
201  result = parse_scalar(lex, sem); /* json can be a bare scalar */
202  }
203 
204  if (result == JSON_SUCCESS)
205  result = lex_expect(JSON_PARSE_END, lex, JSON_TOKEN_END);
206 
207  return result;
208 }
static JsonParseErrorType parse_scalar(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:273
JsonParseErrorType
Definition: jsonapi.h:36
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:526
static JsonParseErrorType parse_object(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:370
static JsonTokenType lex_peek(JsonLexContext *lex)
Definition: jsonapi.c:81
static JsonParseErrorType lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
Definition: jsonapi.c:93
static JsonParseErrorType parse_array(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:471
JsonTokenType
Definition: jsonapi.h:19

Variable Documentation

◆ nullSemAction

JsonSemAction nullSemAction

Definition at line 67 of file jsonapi.c.

Referenced by json_in(), and json_recv().