jsonparser.patch
text/x-patch
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/utils/adt/json.c | 43 | 0 |
| src/include/utils/jsonapi.h | 1 | 0 |
*** a/src/backend/utils/adt/json.c
--- b/src/backend/utils/adt/json.c
***************
*** 212,217 **** makeJsonLexContext(char *json, bool need_escapes)
--- 212,218 ----
lex->input = lex->token_terminator = lex->line_start = json;
lex->line_number = 1;
+ lex->input_length = strlen(json);
if (need_escapes)
lex->strval = makeStringInfo();
return lex;
***************
*** 398,416 **** static void
json_lex(JsonLexContext *lex)
{
char *s;
!
/* Skip leading whitespace. */
s = lex->token_terminator;
! while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
{
if (*s == '\n')
++lex->line_number;
++s;
}
lex->token_start = s;
/* Determine token type. */
! if (*s == '\0')
{
lex->token_start = NULL;
lex->prev_token_terminator = lex->token_terminator;
--- 399,420 ----
json_lex(JsonLexContext *lex)
{
char *s;
! int len;
/* Skip leading whitespace. */
s = lex->token_terminator;
! len = s - lex->input;
! while (len < lex->input_length &&
! (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
{
if (*s == '\n')
++lex->line_number;
++s;
+ ++len;
}
lex->token_start = s;
/* Determine token type. */
! if (len >= lex->input_length)
{
lex->token_start = NULL;
lex->prev_token_terminator = lex->token_terminator;
***************
*** 476,482 **** json_lex(JsonLexContext *lex)
* whole word as an unexpected token, rather than just some
* unintuitive prefix thereof.
*/
! for (p = s; JSON_ALPHANUMERIC_CHAR(*p); p++)
/* skip */ ;
/*
--- 480,486 ----
* whole word as an unexpected token, rather than just some
* unintuitive prefix thereof.
*/
! for (p = s; JSON_ALPHANUMERIC_CHAR(*p) && p - s < lex->input_length - len; p++)
/* skip */ ;
/*
***************
*** 519,539 **** static void
json_lex_string(JsonLexContext *lex)
{
char *s;
!
if (lex->strval != NULL)
resetStringInfo(lex->strval);
! for (s = lex->token_start + 1; *s != '"'; s++)
{
! /* Per RFC4627, these characters MUST be escaped. */
! if ((unsigned char) *s < 32)
{
! /* A NUL byte marks the (premature) end of the string. */
! if (*s == '\0')
! {
! lex->token_terminator = s;
! report_invalid_token(lex);
! }
/* Since *s isn't printable, exclude it from the context string */
lex->token_terminator = s;
ereport(ERROR,
--- 523,545 ----
json_lex_string(JsonLexContext *lex)
{
char *s;
! int len;
if (lex->strval != NULL)
resetStringInfo(lex->strval);
! len = lex->token_start - lex->input;
! len++;
! for (s = lex->token_start + 1; *s != '"'; s++, len++)
{
! /* Premature end of the string. */
! if (len >= lex->input_length)
{
! lex->token_terminator = s;
! report_invalid_token(lex);
! }
! else if ((unsigned char) *s < 32)
! {
! /* Per RFC4627, these characters MUST be escaped. */
/* Since *s isn't printable, exclude it from the context string */
lex->token_terminator = s;
ereport(ERROR,
***************
*** 547,553 **** json_lex_string(JsonLexContext *lex)
{
/* OK, we have an escape character. */
s++;
! if (*s == '\0')
{
lex->token_terminator = s;
report_invalid_token(lex);
--- 553,560 ----
{
/* OK, we have an escape character. */
s++;
! len++;
! if (len >= lex->input_length)
{
lex->token_terminator = s;
report_invalid_token(lex);
***************
*** 560,566 **** json_lex_string(JsonLexContext *lex)
for (i = 1; i <= 4; i++)
{
s++;
! if (*s == '\0')
{
lex->token_terminator = s;
report_invalid_token(lex);
--- 567,574 ----
for (i = 1; i <= 4; i++)
{
s++;
! len++;
! if (len >= lex->input_length)
{
lex->token_terminator = s;
report_invalid_token(lex);
***************
*** 690,696 **** json_lex_number(JsonLexContext *lex, char *s)
--- 698,706 ----
{
bool error = false;
char *p;
+ int len;
+ len = s - lex->input;
/* Part (1): leading sign indicator. */
/* Caller already did this for us; so do nothing. */
***************
*** 702,741 **** json_lex_number(JsonLexContext *lex, char *s)
do
{
s++;
! } while (*s >= '0' && *s <= '9');
}
else
error = true;
/* Part (3): parse optional decimal portion. */
! if (*s == '.')
{
s++;
! if (*s < '0' || *s > '9')
error = true;
else
{
do
{
s++;
! } while (*s >= '0' && *s <= '9');
}
}
/* Part (4): parse optional exponent. */
! if (*s == 'e' || *s == 'E')
{
s++;
! if (*s == '+' || *s == '-')
s++;
! if (*s < '0' || *s > '9')
error = true;
else
{
do
{
s++;
! } while (*s >= '0' && *s <= '9');
}
}
--- 712,759 ----
do
{
s++;
! len++;
! } while (*s >= '0' && *s <= '9' && len < lex->input_length);
}
else
error = true;
/* Part (3): parse optional decimal portion. */
! if (len < lex->input_length && *s == '.')
{
s++;
! len++;
! if (len == lex->input_length || *s < '0' || *s > '9')
error = true;
else
{
do
{
s++;
! len++;
! } while (*s >= '0' && *s <= '9' && len < lex->input_length);
}
}
/* Part (4): parse optional exponent. */
! if (len < lex->input_length && (*s == 'e' || *s == 'E'))
{
s++;
! len++;
! if (len < lex->input_length && (*s == '+' || *s == '-'))
! {
s++;
! len++;
! }
! if (len == lex->input_length || *s < '0' || *s > '9')
error = true;
else
{
do
{
s++;
! len++;
! } while (len < lex->input_length && *s >= '0' && *s <= '9');
}
}
***************
*** 744,750 **** json_lex_number(JsonLexContext *lex, char *s)
* here should be considered part of the token for error-reporting
* purposes.
*/
! for (p = s; JSON_ALPHANUMERIC_CHAR(*p); p++)
error = true;
lex->prev_token_terminator = lex->token_terminator;
lex->token_terminator = p;
--- 762,768 ----
* here should be considered part of the token for error-reporting
* purposes.
*/
! for (p = s; JSON_ALPHANUMERIC_CHAR(*p) && len < lex->input_length; p++, len++)
error = true;
lex->prev_token_terminator = lex->token_terminator;
lex->token_terminator = p;
*** a/src/include/utils/jsonapi.h
--- b/src/include/utils/jsonapi.h
***************
*** 36,41 **** typedef enum
--- 36,42 ----
typedef struct JsonLexContext
{
char *input;
+ int input_length;
char *token_start;
char *token_terminator;
char *prev_token_terminator;