aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/json.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/json.c')
-rw-r--r--src/backend/utils/adt/json.c38
1 files changed, 23 insertions, 15 deletions
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 1486eda8167..af8ddc6ae97 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -50,7 +50,7 @@ typedef enum /* contexts of JSON parser */
static inline void json_lex(JsonLexContext *lex);
static inline void json_lex_string(JsonLexContext *lex);
-static inline void json_lex_number(JsonLexContext *lex, char *s);
+static inline void json_lex_number(JsonLexContext *lex, char *s, bool *num_err);
static inline void parse_scalar(JsonLexContext *lex, JsonSemAction *sem);
static void parse_object_field(JsonLexContext *lex, JsonSemAction *sem);
static void parse_object(JsonLexContext *lex, JsonSemAction *sem);
@@ -147,8 +147,6 @@ lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
#define TYPCATEGORY_JSON 'j'
/* fake category for types that have a cast to json */
#define TYPCATEGORY_JSON_CAST 'c'
-/* letters appearing in numeric output that aren't valid in a JSON number */
-#define NON_NUMERIC_LETTER "NnAaIiFfTtYy"
/* chars to consider as part of an alphanumeric token */
#define JSON_ALPHANUMERIC_CHAR(c) \
(((c) >= 'a' && (c) <= 'z') || \
@@ -567,7 +565,7 @@ json_lex(JsonLexContext *lex)
break;
case '-':
/* Negative number. */
- json_lex_number(lex, s + 1);
+ json_lex_number(lex, s + 1, NULL);
lex->token_type = JSON_TOKEN_NUMBER;
break;
case '0':
@@ -581,7 +579,7 @@ json_lex(JsonLexContext *lex)
case '8':
case '9':
/* Positive number. */
- json_lex_number(lex, s);
+ json_lex_number(lex, s, NULL);
lex->token_type = JSON_TOKEN_NUMBER;
break;
default:
@@ -903,7 +901,7 @@ json_lex_string(JsonLexContext *lex)
*-------------------------------------------------------------------------
*/
static inline void
-json_lex_number(JsonLexContext *lex, char *s)
+json_lex_number(JsonLexContext *lex, char *s, bool *num_err)
{
bool error = false;
char *p;
@@ -976,10 +974,19 @@ json_lex_number(JsonLexContext *lex, char *s)
*/
for (p = s; len < lex->input_length && JSON_ALPHANUMERIC_CHAR(*p); p++, len++)
error = true;
- lex->prev_token_terminator = lex->token_terminator;
- lex->token_terminator = p;
- if (error)
- report_invalid_token(lex);
+
+ if (num_err != NULL)
+ {
+ /* let the caller handle the error */
+ *num_err = error;
+ }
+ else
+ {
+ lex->prev_token_terminator = lex->token_terminator;
+ lex->token_terminator = p;
+ if (error)
+ report_invalid_token(lex);
+ }
}
/*
@@ -1214,6 +1221,8 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
{
char *outputstr;
text *jsontext;
+ bool numeric_error;
+ JsonLexContext dummy_lex;
if (is_null)
{
@@ -1237,14 +1246,13 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
break;
case TYPCATEGORY_NUMERIC:
outputstr = OidOutputFunctionCall(typoutputfunc, val);
-
/*
* Don't call escape_json here if it's a valid JSON number.
- * Numeric output should usually be a valid JSON number and JSON
- * numbers shouldn't be quoted. Quote cases like "Nan" and
- * "Infinity", however.
*/
- if (strpbrk(outputstr, NON_NUMERIC_LETTER) == NULL)
+ dummy_lex.input = *outputstr == '-' ? outputstr + 1 : outputstr;
+ dummy_lex.input_length = strlen(dummy_lex.input);
+ json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error);
+ if (! numeric_error)
appendStringInfoString(result, outputstr);
else
escape_json(result, outputstr);