0010-Relocating-jsonapi.c.patch
application/octet-stream
Filename: 0010-Relocating-jsonapi.c.patch
Type: application/octet-stream
Part: 4
Patch
Format: format-patch
Series: patch 0010
Subject: Relocating jsonapi.c
| File | + | − |
|---|---|---|
| src/backend/utils/adt/jsonb.c | 1 | 1 |
| src/backend/utils/adt/json.c | 1 | 1 |
| src/backend/utils/adt/jsonfuncs.c | 4 | 3 |
| src/backend/utils/adt/Makefile | 0 | 1 |
| src/common/jsonapi.c | 122 | 151 |
| src/common/Makefile | 1 | 0 |
| src/include/common/jsonapi.h | 16 | 3 |
| src/include/utils/jsonfuncs.h | 1 | 1 |
From a2c7d0e798004fc5c22ef8eef204a8eefc19e4a5 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Thu, 23 Jan 2020 11:39:55 -0800
Subject: [PATCH 10/11] Relocating jsonapi.c
Moving src/backend/utils/adt/jsonapi.c to src/common/jsonapi.c
and reworking the code to not include elog, pg_mblen and similar
backend-only functions.
Along the way, simplifying Robert's implementation with macros
to make the json parsing code more compact and (to my eyes)
easier to read.
---
src/backend/utils/adt/Makefile | 1 -
src/backend/utils/adt/json.c | 2 +-
src/backend/utils/adt/jsonb.c | 2 +-
src/backend/utils/adt/jsonfuncs.c | 7 +-
src/common/Makefile | 1 +
src/{backend/utils/adt => common}/jsonapi.c | 273 +++++++++-----------
src/include/common/jsonapi.h | 19 +-
src/include/utils/jsonfuncs.h | 2 +-
8 files changed, 146 insertions(+), 161 deletions(-)
rename src/{backend/utils/adt => common}/jsonapi.c (84%)
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 790d7a24fb..13efa9338c 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -44,7 +44,6 @@ OBJS = \
int.o \
int8.o \
json.o \
- jsonapi.o \
jsonb.o \
jsonb_gin.o \
jsonb_op.o \
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 8333711988..3f9a3c9e6e 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -129,7 +129,7 @@ json_recv(PG_FUNCTION_ARGS)
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
/* Validate it. */
- lex = makeJsonLexContextCstringLen(str, nbytes, false);
+ lex = makeJsonLexContextCstringLen(str, nbytes, GetDatabaseEncoding(), false);
pg_parse_json_or_ereport(lex, &nullSemAction);
PG_RETURN_TEXT_P(cstring_to_text_with_len(str, nbytes));
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index d1d4542f74..1f85f68e30 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -262,7 +262,7 @@ jsonb_from_cstring(char *json, int len)
memset(&state, 0, sizeof(state));
memset(&sem, 0, sizeof(sem));
- lex = makeJsonLexContextCstringLen(json, len, true);
+ lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
sem.semstate = (void *) &state;
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index d5e2c56f14..2b403ea7da 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -495,7 +495,7 @@ static void transform_string_values_scalar(void *state, char *token, JsonTokenTy
* ereport(ERROR).
*/
void
-pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem)
+pg_parse_json_or_ereport(JsonLexContext *lex, const JsonSemAction *sem)
{
JsonParseErrorType result;
@@ -515,6 +515,7 @@ makeJsonLexContext(text *json, bool need_escapes)
{
return makeJsonLexContextCstringLen(VARDATA_ANY(json),
VARSIZE_ANY_EXHDR(json),
+ GetDatabaseEncoding(),
need_escapes);
}
@@ -2606,7 +2607,7 @@ populate_array_json(PopulateArrayContext *ctx, char *json, int len)
PopulateArrayState state;
JsonSemAction sem;
- state.lex = makeJsonLexContextCstringLen(json, len, true);
+ state.lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
state.ctx = ctx;
memset(&sem, 0, sizeof(sem));
@@ -3449,7 +3450,7 @@ get_json_object_as_hash(char *json, int len, const char *funcname)
HASHCTL ctl;
HTAB *tab;
JHashState *state;
- JsonLexContext *lex = makeJsonLexContextCstringLen(json, len, true);
+ JsonLexContext *lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
JsonSemAction *sem;
memset(&ctl, 0, sizeof(ctl));
diff --git a/src/common/Makefile b/src/common/Makefile
index 3882cd7a3d..e9caa08418 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -56,6 +56,7 @@ OBJS_COMMON = \
f2s.o \
file_perm.o \
ip.o \
+ jsonapi.o \
keywords.o \
kwlookup.o \
link-canary.o \
diff --git a/src/backend/utils/adt/jsonapi.c b/src/common/jsonapi.c
similarity index 84%
rename from src/backend/utils/adt/jsonapi.c
rename to src/common/jsonapi.c
index ee26dc324f..49e1bb44c9 100644
--- a/src/backend/utils/adt/jsonapi.c
+++ b/src/common/jsonapi.c
@@ -11,12 +11,25 @@
*
*-------------------------------------------------------------------------
*/
+#ifndef FRONTEND
#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
#include "common/jsonapi.h"
#include "common/pg_wchar.h"
+
+#ifndef FRONTEND
#include "miscadmin.h"
-#include "utils/mbutils.h"
+#endif
+
+#define INSIST(x) \
+do { \
+ JsonParseErrorType parse_result; \
+ if((parse_result = (x)) != JSON_SUCCESS) \
+ return parse_result; \
+} while (0)
/*
* The context of the parser is maintained by the recursive descent
@@ -36,19 +49,20 @@ typedef enum /* contexts of JSON parser */
JSON_PARSE_END /* saw the end of a document, expect nothing */
} JsonParseContext;
+static inline JsonParseErrorType lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token);
static inline JsonParseErrorType json_lex_string(JsonLexContext *lex);
static inline JsonParseErrorType json_lex_number(JsonLexContext *lex, char *s,
bool *num_err, int *total_len);
-static inline 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 inline JsonParseErrorType parse_scalar(JsonLexContext *lex, const JsonSemAction *sem);
+static JsonParseErrorType parse_object_field(JsonLexContext *lex, const JsonSemAction *sem);
+static JsonParseErrorType parse_object(JsonLexContext *lex, const JsonSemAction *sem);
+static JsonParseErrorType parse_array_element(JsonLexContext *lex, const JsonSemAction *sem);
+static JsonParseErrorType parse_array(JsonLexContext *lex, const JsonSemAction *sem);
static JsonParseErrorType report_parse_error(JsonParseContext ctx, JsonLexContext *lex);
static char *extract_token(JsonLexContext *lex);
/* the null action object used for pure validation */
-JsonSemAction nullSemAction =
+const JsonSemAction nullSemAction =
{
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL
@@ -56,32 +70,6 @@ JsonSemAction nullSemAction =
/* Recursive Descent parser support routines */
-/*
- * lex_peek
- *
- * what is the current look_ahead token?
-*/
-static inline JsonTokenType
-lex_peek(JsonLexContext *lex)
-{
- return lex->token_type;
-}
-
-/*
- * lex_expect
- *
- * move the lexer to the next token if the current look_ahead token matches
- * the parameter token. Otherwise, report an error.
- */
-static inline JsonParseErrorType
-lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
-{
- if (lex_peek(lex) == token)
- return json_lex(lex);
- else
- return report_parse_error(ctx, lex);
-}
-
/* chars to consider as part of an alphanumeric token */
#define JSON_ALPHANUMERIC_CHAR(c) \
(((c) >= 'a' && (c) <= 'z') || \
@@ -122,7 +110,8 @@ IsValidJsonNumber(const char *str, int len)
dummy_lex.input_length = len;
}
- json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error, &total_len);
+ if (JSON_SUCCESS != json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error, &total_len))
+ return false;
return (!numeric_error) && (total_len == dummy_lex.input_length);
}
@@ -136,13 +125,21 @@ IsValidJsonNumber(const char *str, int len)
* if really required.
*/
JsonLexContext *
-makeJsonLexContextCstringLen(char *json, int len, bool need_escapes)
+makeJsonLexContextCstringLen(char *json, int len, pg_enc encoding, bool need_escapes)
{
- JsonLexContext *lex = palloc0(sizeof(JsonLexContext));
+ JsonLexContext *lex;
+
+#ifndef FRONTEND
+ lex = (JsonLexContext*) palloc0fast(sizeof(JsonLexContext));
+#else
+ lex = (JsonLexContext*) malloc(sizeof(JsonLexContext));
+ memset(lex, 0, sizeof(JsonLexContext));
+#endif
lex->input = lex->token_terminator = lex->line_start = json;
lex->line_number = 1;
lex->input_length = len;
+ lex->input_encoding = encoding;
if (need_escapes)
lex->strval = makeStringInfo();
return lex;
@@ -159,15 +156,12 @@ makeJsonLexContextCstringLen(char *json, int len, bool need_escapes)
* pointer to a state object to be passed to those routines.
*/
JsonParseErrorType
-pg_parse_json(JsonLexContext *lex, JsonSemAction *sem)
+pg_parse_json(JsonLexContext *lex, const JsonSemAction *sem)
{
JsonTokenType tok;
- JsonParseErrorType result;
/* get the initial token */
- result = json_lex(lex);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(json_lex(lex));
tok = lex_peek(lex);
@@ -175,19 +169,16 @@ pg_parse_json(JsonLexContext *lex, JsonSemAction *sem)
switch (tok)
{
case JSON_TOKEN_OBJECT_START:
- result = parse_object(lex, sem);
+ INSIST(parse_object(lex, sem));
break;
case JSON_TOKEN_ARRAY_START:
- result = parse_array(lex, sem);
+ INSIST(parse_array(lex, sem));
break;
default:
- result = parse_scalar(lex, sem); /* json can be a bare scalar */
+ INSIST(parse_scalar(lex, sem)); /* json can be a bare scalar */
}
- if (result == JSON_SUCCESS)
- result = lex_expect(JSON_PARSE_END, lex, JSON_TOKEN_END);
-
- return result;
+ return lex_expect(JSON_PARSE_END, lex, JSON_TOKEN_END);
}
/*
@@ -203,7 +194,6 @@ json_count_array_elements(JsonLexContext *lex, int *elements)
{
JsonLexContext copylex;
int count;
- JsonParseErrorType result;
/*
* It's safe to do this with a shallow copy because the lexical routines
@@ -215,29 +205,20 @@ json_count_array_elements(JsonLexContext *lex, int *elements)
copylex.lex_level++;
count = 0;
- result = lex_expect(JSON_PARSE_ARRAY_START, ©lex,
- JSON_TOKEN_ARRAY_START);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(lex_expect(JSON_PARSE_ARRAY_START, ©lex, JSON_TOKEN_ARRAY_START));
if (lex_peek(©lex) != JSON_TOKEN_ARRAY_END)
{
while (1)
{
count++;
- result = parse_array_element(©lex, &nullSemAction);
- if (result != JSON_SUCCESS)
- return result;
+ if (JSON_SUCCESS != parse_array_element(©lex, &nullSemAction))
+ break;
if (copylex.token_type != JSON_TOKEN_COMMA)
break;
- result = json_lex(©lex);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(json_lex(©lex));
}
}
- result = lex_expect(JSON_PARSE_ARRAY_NEXT, ©lex,
- JSON_TOKEN_ARRAY_END);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(lex_expect(JSON_PARSE_ARRAY_NEXT, ©lex, JSON_TOKEN_ARRAY_END));
*elements = count;
return JSON_SUCCESS;
@@ -253,22 +234,30 @@ json_count_array_elements(JsonLexContext *lex, int *elements)
* - object field
*/
static inline JsonParseErrorType
-parse_scalar(JsonLexContext *lex, JsonSemAction *sem)
+parse_scalar(JsonLexContext *lex, const JsonSemAction *sem)
{
char *val = NULL;
json_scalar_action sfunc = sem->scalar;
JsonTokenType tok = lex_peek(lex);
- JsonParseErrorType result;
/* a scalar must be a string, a number, true, false, or null */
- if (tok != JSON_TOKEN_STRING && tok != JSON_TOKEN_NUMBER &&
- tok != JSON_TOKEN_TRUE && tok != JSON_TOKEN_FALSE &&
- tok != JSON_TOKEN_NULL)
- return report_parse_error(JSON_PARSE_VALUE, lex);
+ switch (tok)
+ {
+ case JSON_TOKEN_STRING:
+ case JSON_TOKEN_NUMBER:
+ case JSON_TOKEN_TRUE:
+ case JSON_TOKEN_FALSE:
+ case JSON_TOKEN_NULL:
+ break;
+ default:
+ return report_parse_error(JSON_PARSE_VALUE, lex);
+ }
/* if no semantic function, just consume the token */
if (sfunc == NULL)
+ {
return json_lex(lex);
+ }
/* extract the de-escaped string value, or the raw lexeme */
if (lex_peek(lex) == JSON_TOKEN_STRING)
@@ -278,7 +267,7 @@ parse_scalar(JsonLexContext *lex, JsonSemAction *sem)
}
else
{
- int len = (lex->token_terminator - lex->token_start);
+ int len = (lex->token_terminator - lex->token_start);
val = palloc(len + 1);
memcpy(val, lex->token_start, len);
@@ -286,18 +275,15 @@ parse_scalar(JsonLexContext *lex, JsonSemAction *sem)
}
/* consume the token */
- result = json_lex(lex);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(json_lex(lex));
/* invoke the callback */
(*sfunc) (sem->semstate, val, tok);
-
return JSON_SUCCESS;
}
static JsonParseErrorType
-parse_object_field(JsonLexContext *lex, JsonSemAction *sem)
+parse_object_field(JsonLexContext *lex, const JsonSemAction *sem)
{
/*
* An object field is "fieldname" : value where value can be a scalar,
@@ -310,19 +296,14 @@ parse_object_field(JsonLexContext *lex, JsonSemAction *sem)
json_ofield_action oend = sem->object_field_end;
bool isnull;
JsonTokenType tok;
- JsonParseErrorType result;
if (lex_peek(lex) != JSON_TOKEN_STRING)
return report_parse_error(JSON_PARSE_STRING, lex);
if ((ostart != NULL || oend != NULL) && lex->strval != NULL)
fname = pstrdup(lex->strval->data);
- result = json_lex(lex);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(json_lex(lex));
- result = lex_expect(JSON_PARSE_OBJECT_LABEL, lex, JSON_TOKEN_COLON);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(lex_expect(JSON_PARSE_OBJECT_LABEL, lex, JSON_TOKEN_COLON));
tok = lex_peek(lex);
isnull = tok == JSON_TOKEN_NULL;
@@ -333,16 +314,14 @@ parse_object_field(JsonLexContext *lex, JsonSemAction *sem)
switch (tok)
{
case JSON_TOKEN_OBJECT_START:
- result = parse_object(lex, sem);
+ INSIST(parse_object(lex, sem));
break;
case JSON_TOKEN_ARRAY_START:
- result = parse_array(lex, sem);
+ INSIST(parse_array(lex, sem));
break;
default:
- result = parse_scalar(lex, sem);
+ INSIST(parse_scalar(lex, sem));
}
- if (result != JSON_SUCCESS)
- return result;
if (oend != NULL)
(*oend) (sem->semstate, fname, isnull);
@@ -350,7 +329,7 @@ parse_object_field(JsonLexContext *lex, JsonSemAction *sem)
}
static JsonParseErrorType
-parse_object(JsonLexContext *lex, JsonSemAction *sem)
+parse_object(JsonLexContext *lex, const JsonSemAction *sem)
{
/*
* an object is a possibly empty sequence of object fields, separated by
@@ -359,9 +338,12 @@ parse_object(JsonLexContext *lex, JsonSemAction *sem)
json_struct_action ostart = sem->object_start;
json_struct_action oend = sem->object_end;
JsonTokenType tok;
- JsonParseErrorType result;
+#ifndef FRONTEND
check_stack_depth();
+#else
+ /* TODO: What do we do in frontend code? */
+#endif
if (ostart != NULL)
(*ostart) (sem->semstate);
@@ -375,51 +357,41 @@ parse_object(JsonLexContext *lex, JsonSemAction *sem)
lex->lex_level++;
Assert(lex_peek(lex) == JSON_TOKEN_OBJECT_START);
- result = json_lex(lex);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(json_lex(lex));
tok = lex_peek(lex);
switch (tok)
{
case JSON_TOKEN_STRING:
- result = parse_object_field(lex, sem);
- while (result == JSON_SUCCESS && lex_peek(lex) == JSON_TOKEN_COMMA)
+ INSIST(parse_object_field(lex, sem));
+ while (lex_peek(lex) == JSON_TOKEN_COMMA)
{
- result = json_lex(lex);
- if (result != JSON_SUCCESS)
- break;
- result = parse_object_field(lex, sem);
+ INSIST(json_lex(lex));
+ INSIST(parse_object_field(lex, sem));
}
break;
case JSON_TOKEN_OBJECT_END:
break;
default:
/* case of an invalid initial token inside the object */
- result = report_parse_error(JSON_PARSE_OBJECT_START, lex);
+ return report_parse_error(JSON_PARSE_OBJECT_START, lex);
}
- if (result != JSON_SUCCESS)
- return result;
- result = lex_expect(JSON_PARSE_OBJECT_NEXT, lex, JSON_TOKEN_OBJECT_END);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(lex_expect(JSON_PARSE_OBJECT_NEXT, lex, JSON_TOKEN_OBJECT_END));
lex->lex_level--;
if (oend != NULL)
(*oend) (sem->semstate);
-
return JSON_SUCCESS;
}
static JsonParseErrorType
-parse_array_element(JsonLexContext *lex, JsonSemAction *sem)
+parse_array_element(JsonLexContext *lex, const JsonSemAction *sem)
{
json_aelem_action astart = sem->array_element_start;
json_aelem_action aend = sem->array_element_end;
JsonTokenType tok = lex_peek(lex);
- JsonParseErrorType result;
bool isnull;
@@ -432,26 +404,22 @@ parse_array_element(JsonLexContext *lex, JsonSemAction *sem)
switch (tok)
{
case JSON_TOKEN_OBJECT_START:
- result = parse_object(lex, sem);
+ INSIST(parse_object(lex, sem));
break;
case JSON_TOKEN_ARRAY_START:
- result = parse_array(lex, sem);
+ INSIST(parse_array(lex, sem));
break;
default:
- result = parse_scalar(lex, sem);
+ INSIST(parse_scalar(lex, sem));
}
- if (result != JSON_SUCCESS)
- return result;
-
if (aend != NULL)
(*aend) (sem->semstate, isnull);
-
return JSON_SUCCESS;
}
static JsonParseErrorType
-parse_array(JsonLexContext *lex, JsonSemAction *sem)
+parse_array(JsonLexContext *lex, const JsonSemAction *sem)
{
/*
* an array is a possibly empty sequence of array elements, separated by
@@ -459,9 +427,12 @@ parse_array(JsonLexContext *lex, JsonSemAction *sem)
*/
json_struct_action astart = sem->array_start;
json_struct_action aend = sem->array_end;
- JsonParseErrorType result;
+#ifndef FRONTEND
check_stack_depth();
+#else
+ /* TODO: What do we do in frontend code? */
+#endif
if (astart != NULL)
(*astart) (sem->semstate);
@@ -474,31 +445,25 @@ parse_array(JsonLexContext *lex, JsonSemAction *sem)
*/
lex->lex_level++;
- result = lex_expect(JSON_PARSE_ARRAY_START, lex, JSON_TOKEN_ARRAY_START);
- if (result == JSON_SUCCESS && lex_peek(lex) != JSON_TOKEN_ARRAY_END)
+ INSIST(lex_expect(JSON_PARSE_ARRAY_START, lex, JSON_TOKEN_ARRAY_START));
+ if (lex_peek(lex) != JSON_TOKEN_ARRAY_END)
{
- result = parse_array_element(lex, sem);
- while (result == JSON_SUCCESS && lex_peek(lex) == JSON_TOKEN_COMMA)
+ INSIST(parse_array_element(lex, sem));
+
+ while (lex_peek(lex) == JSON_TOKEN_COMMA)
{
- result = json_lex(lex);
- if (result != JSON_SUCCESS)
- break;
- result = parse_array_element(lex, sem);
+ INSIST(json_lex(lex));
+ INSIST(parse_array_element(lex, sem));
}
}
- if (result != JSON_SUCCESS)
- return result;
- result = lex_expect(JSON_PARSE_ARRAY_NEXT, lex, JSON_TOKEN_ARRAY_END);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(lex_expect(JSON_PARSE_ARRAY_NEXT, lex, JSON_TOKEN_ARRAY_END));
lex->lex_level--;
if (aend != NULL)
(*aend) (sem->semstate);
-
return JSON_SUCCESS;
}
@@ -510,7 +475,6 @@ json_lex(JsonLexContext *lex)
{
char *s;
int len;
- JsonParseErrorType result;
/* Skip leading whitespace. */
s = lex->token_terminator;
@@ -534,7 +498,6 @@ json_lex(JsonLexContext *lex)
lex->token_type = JSON_TOKEN_END;
}
else
- {
switch (*s)
{
/* Single-character token, some kind of punctuation mark. */
@@ -570,16 +533,12 @@ json_lex(JsonLexContext *lex)
break;
case '"':
/* string */
- result = json_lex_string(lex);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(json_lex_string(lex));
lex->token_type = JSON_TOKEN_STRING;
break;
case '-':
/* Negative number. */
- result = json_lex_number(lex, s + 1, NULL, NULL);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(json_lex_number(lex, s + 1, NULL, NULL));
lex->token_type = JSON_TOKEN_NUMBER;
break;
case '0':
@@ -593,9 +552,7 @@ json_lex(JsonLexContext *lex)
case '8':
case '9':
/* Positive number. */
- result = json_lex_number(lex, s, NULL, NULL);
- if (result != JSON_SUCCESS)
- return result;
+ INSIST(json_lex_number(lex, s, NULL, NULL));
lex->token_type = JSON_TOKEN_NUMBER;
break;
default:
@@ -649,11 +606,23 @@ json_lex(JsonLexContext *lex)
}
} /* end of switch */
- }
-
return JSON_SUCCESS;
}
+/*
+ * lex_expect
+ *
+ * move the lexer to the next token if the current look_ahead token matches
+ * the parameter token. Otherwise, report an error.
+ */
+static inline JsonParseErrorType
+lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
+{
+ if (lex_peek(lex) == token)
+ return json_lex(lex);
+ return report_parse_error(ctx, lex);
+}
+
/*
* The next token in the input stream is known to be a string; lex it.
*/
@@ -721,7 +690,7 @@ json_lex_string(JsonLexContext *lex)
ch = (ch * 16) + (*s - 'A') + 10;
else
{
- lex->token_terminator = s + pg_mblen(s);
+ lex->token_terminator = s + pg_wchar_table[lex->input_encoding].mblen((const unsigned char *) s);
return JSON_UNICODE_ESCAPE_FORMAT;
}
}
@@ -760,7 +729,7 @@ json_lex_string(JsonLexContext *lex)
/* We can't allow this, since our TEXT type doesn't */
return JSON_UNICODE_CODE_POINT_ZERO;
}
- else if (GetDatabaseEncoding() == PG_UTF8)
+ else if (lex->input_encoding == PG_UTF8)
{
unicode_to_utf8(ch, (unsigned char *) utf8str);
utf8len = pg_utf_mblen((unsigned char *) utf8str);
@@ -810,7 +779,7 @@ json_lex_string(JsonLexContext *lex)
default:
/* Not a valid string escape, so signal error. */
lex->token_start = s;
- lex->token_terminator = s + pg_mblen(s);
+ lex->token_terminator = s + pg_wchar_table[lex->input_encoding].mblen((const unsigned char *) s);
return JSON_ESCAPING_INVALID;
}
}
@@ -824,7 +793,7 @@ json_lex_string(JsonLexContext *lex)
* shown it's not a performance win.
*/
lex->token_start = s;
- lex->token_terminator = s + pg_mblen(s);
+ lex->token_terminator = s + pg_wchar_table[lex->input_encoding].mblen((const unsigned char *) s);
return JSON_ESCAPING_INVALID;
}
@@ -833,7 +802,6 @@ json_lex_string(JsonLexContext *lex)
{
if (hi_surrogate != -1)
return JSON_UNICODE_LOW_SURROGATE;
-
appendStringInfoChar(lex->strval, *s);
}
@@ -967,7 +935,6 @@ json_lex_number(JsonLexContext *lex, char *s,
if (error)
return JSON_INVALID_TOKEN;
}
-
return JSON_SUCCESS;
}
@@ -983,7 +950,6 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
if (lex->token_start == NULL || lex->token_type == JSON_TOKEN_END)
return JSON_EXPECTED_MORE;
- /* Otherwise choose the error type based on the parsing context. */
switch (ctx)
{
case JSON_PARSE_END:
@@ -1005,7 +971,7 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
case JSON_PARSE_OBJECT_COMMA:
return JSON_EXPECTED_STRING;
default:
- elog(ERROR, "unexpected json parse state: %d", ctx);
+ return JSON_BAD_PARSER_STATE;;
}
}
@@ -1018,7 +984,12 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
switch (error)
{
case JSON_SUCCESS:
+ case JSON_BAD_PARSER_STATE:
+#ifdef FRONTEND
+ return _("internal error in json parser");
+#else
elog(ERROR, "internal error in json parser");
+#endif
break;
case JSON_ESCAPING_INVALID:
return psprintf(_("Escape sequence \"\\%s\" is invalid."),
diff --git a/src/include/common/jsonapi.h b/src/include/common/jsonapi.h
index da20ffce64..1836b5e591 100644
--- a/src/include/common/jsonapi.h
+++ b/src/include/common/jsonapi.h
@@ -14,6 +14,7 @@
#ifndef JSONAPI_H
#define JSONAPI_H
+#include "common/pg_wchar.h"
#include "lib/stringinfo.h"
typedef enum
@@ -52,7 +53,8 @@ typedef enum
JSON_UNICODE_ESCAPE_FORMAT,
JSON_UNICODE_HIGH_ESCAPE,
JSON_UNICODE_HIGH_SURROGATE,
- JSON_UNICODE_LOW_SURROGATE
+ JSON_UNICODE_LOW_SURROGATE,
+ JSON_BAD_PARSER_STATE
} JsonParseErrorType;
@@ -73,6 +75,7 @@ typedef struct JsonLexContext
{
char *input;
int input_length;
+ pg_enc input_encoding;
char *token_start;
char *token_terminator;
char *prev_token_terminator;
@@ -114,6 +117,9 @@ typedef struct JsonSemAction
json_scalar_action scalar;
} JsonSemAction;
+/* the null action object used for pure validation */
+extern const JsonSemAction nullSemAction;
+
/*
* pg_parse_json will parse the string in the lex calling the
* action functions in sem at the appropriate points. It is
@@ -124,10 +130,10 @@ typedef struct JsonSemAction
* does nothing and just continues.
*/
extern JsonParseErrorType pg_parse_json(JsonLexContext *lex,
- JsonSemAction *sem);
+ const JsonSemAction *sem);
/* the null action object used for pure validation */
-extern JsonSemAction nullSemAction;
+extern const JsonSemAction nullSemAction;
/*
* json_count_array_elements performs a fast secondary parse to determine the
@@ -149,11 +155,18 @@ extern JsonParseErrorType json_count_array_elements(JsonLexContext *lex,
*/
extern JsonLexContext *makeJsonLexContextCstringLen(char *json,
int len,
+ pg_enc encoding,
bool need_escapes);
/* lex one token */
extern JsonParseErrorType json_lex(JsonLexContext *lex);
+/* Get the current look_ahead token. */
+static inline JsonTokenType lex_peek(JsonLexContext *lex)
+{
+ return lex->token_type;
+}
+
/* construct an error detail string for a json error */
extern char *json_errdetail(JsonParseErrorType error, JsonLexContext *lex);
diff --git a/src/include/utils/jsonfuncs.h b/src/include/utils/jsonfuncs.h
index 1f1b4029cb..f29437d29e 100644
--- a/src/include/utils/jsonfuncs.h
+++ b/src/include/utils/jsonfuncs.h
@@ -40,7 +40,7 @@ typedef text *(*JsonTransformStringValuesAction) (void *state, char *elem_value,
extern JsonLexContext *makeJsonLexContext(text *json, bool need_escapes);
/* try to parse json, and ereport(ERROR) on failure */
-extern void pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem);
+extern void pg_parse_json_or_ereport(JsonLexContext *lex, const JsonSemAction *sem);
/* report an error during json lexing or parsing */
extern void json_ereport_error(JsonParseErrorType error, JsonLexContext *lex);
--
2.21.1 (Apple Git-122.3)