summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas2020-01-27 16:22:13 +0000
committerRobert Haas2020-01-27 16:22:13 +0000
commit73ce2a03f30b52d6bfb26bc28f1e3e1aa1637577 (patch)
treea6a19f146fb7281f146fec7d413a79032fd1557f
parent1f3a021730be98b880d94cabbe21de7e4d8136f5 (diff)
Move some code from jsonapi.c to jsonfuncs.c.
Specifically, move those functions that depend on ereport() from jsonapi.c to jsonfuncs.c, in preparation for allowing jsonapi.c to be used from frontend code. A few cases where elog(ERROR, ...) is used for can't-happen conditions are left alone; we can handle those in some other way in frontend code. Reviewed by Mark Dilger and Andrew Dunstan. Discussion: http://postgr.es/m/CA+TgmoYfOXhd27MUDGioVh6QtpD0C1K-f6ObSA10AWiHBAL5bA@mail.gmail.com
-rw-r--r--src/backend/utils/adt/json.c2
-rw-r--r--src/backend/utils/adt/jsonapi.c127
-rw-r--r--src/backend/utils/adt/jsonb.c2
-rw-r--r--src/backend/utils/adt/jsonfuncs.c126
-rw-r--r--src/include/utils/jsonapi.h15
-rw-r--r--src/include/utils/jsonfuncs.h9
6 files changed, 140 insertions, 141 deletions
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index e73a60ece8a..f6cd2b99115 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -23,7 +23,7 @@
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/json.h"
-#include "utils/jsonapi.h"
+#include "utils/jsonfuncs.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
diff --git a/src/backend/utils/adt/jsonapi.c b/src/backend/utils/adt/jsonapi.c
index 129fbd65d51..1ac3b7beda8 100644
--- a/src/backend/utils/adt/jsonapi.c
+++ b/src/backend/utils/adt/jsonapi.c
@@ -44,7 +44,6 @@ 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 int report_json_context(JsonLexContext *lex);
static char *extract_token(JsonLexContext *lex);
/* the null action object used for pure validation */
@@ -128,26 +127,14 @@ IsValidJsonNumber(const char *str, int len)
}
/*
- * makeJsonLexContext
+ * makeJsonLexContextCstringLen
*
- * lex constructor, with or without StringInfo object
- * for de-escaped lexemes.
+ * lex constructor, with or without StringInfo object for de-escaped lexemes.
*
* Without is better as it makes the processing faster, so only make one
* if really required.
- *
- * If you already have the json as a text* value, use the first of these
- * functions, otherwise use makeJsonLexContextCstringLen().
*/
JsonLexContext *
-makeJsonLexContext(text *json, bool need_escapes)
-{
- return makeJsonLexContextCstringLen(VARDATA_ANY(json),
- VARSIZE_ANY_EXHDR(json),
- need_escapes);
-}
-
-JsonLexContext *
makeJsonLexContextCstringLen(char *json, int len, bool need_escapes)
{
JsonLexContext *lex = palloc0(sizeof(JsonLexContext));
@@ -203,23 +190,6 @@ pg_parse_json(JsonLexContext *lex, JsonSemAction *sem)
}
/*
- * pg_parse_json_or_ereport
- *
- * This fuction is like pg_parse_json, except that it does not return a
- * JsonParseErrorType. Instead, in case of any failure, this function will
- * ereport(ERROR).
- */
-void
-pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem)
-{
- JsonParseErrorType result;
-
- result = pg_parse_json(lex, sem);
- if (result != JSON_SUCCESS)
- json_ereport_error(result, lex);
-}
-
-/*
* json_count_array_elements
*
* Returns number of array elements in lex context at start of array token
@@ -1039,27 +1009,6 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
}
/*
- * Report a JSON error.
- */
-void
-json_ereport_error(JsonParseErrorType error, JsonLexContext *lex)
-{
- if (error == JSON_UNICODE_HIGH_ESCAPE ||
- error == JSON_UNICODE_CODE_POINT_ZERO)
- ereport(ERROR,
- (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
- errmsg("unsupported Unicode escape sequence"),
- errdetail("%s", json_errdetail(error, lex)),
- report_json_context(lex)));
- else
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input syntax for type %s", "json"),
- errdetail("%s", json_errdetail(error, lex)),
- report_json_context(lex)));
-}
-
-/*
* Construct a detail message for a JSON error.
*/
char *
@@ -1119,78 +1068,6 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
}
/*
- * Report a CONTEXT line for bogus JSON input.
- *
- * lex->token_terminator must be set to identify the spot where we detected
- * the error. Note that lex->token_start might be NULL, in case we recognized
- * error at EOF.
- *
- * The return value isn't meaningful, but we make it non-void so that this
- * can be invoked inside ereport().
- */
-static int
-report_json_context(JsonLexContext *lex)
-{
- const char *context_start;
- const char *context_end;
- const char *line_start;
- int line_number;
- char *ctxt;
- int ctxtlen;
- const char *prefix;
- const char *suffix;
-
- /* Choose boundaries for the part of the input we will display */
- context_start = lex->input;
- context_end = lex->token_terminator;
- line_start = context_start;
- line_number = 1;
- for (;;)
- {
- /* Always advance over newlines */
- if (context_start < context_end && *context_start == '\n')
- {
- context_start++;
- line_start = context_start;
- line_number++;
- continue;
- }
- /* Otherwise, done as soon as we are close enough to context_end */
- if (context_end - context_start < 50)
- break;
- /* Advance to next multibyte character */
- if (IS_HIGHBIT_SET(*context_start))
- context_start += pg_mblen(context_start);
- else
- context_start++;
- }
-
- /*
- * We add "..." to indicate that the excerpt doesn't start at the
- * beginning of the line ... but if we're within 3 characters of the
- * beginning of the line, we might as well just show the whole line.
- */
- if (context_start - line_start <= 3)
- context_start = line_start;
-
- /* Get a null-terminated copy of the data to present */
- ctxtlen = context_end - context_start;
- ctxt = palloc(ctxtlen + 1);
- memcpy(ctxt, context_start, ctxtlen);
- ctxt[ctxtlen] = '\0';
-
- /*
- * Show the context, prefixing "..." if not starting at start of line, and
- * suffixing "..." if not ending at end of line.
- */
- prefix = (context_start > line_start) ? "..." : "";
- suffix = (lex->token_type != JSON_TOKEN_END && context_end - lex->input < lex->input_length && *context_end != '\n' && *context_end != '\r') ? "..." : "";
-
- return errcontext("JSON data, line %d: %s%s%s",
- line_number, prefix, ctxt, suffix);
-}
-
-/*
* Extract the current token from a lexing context, for error reporting.
*/
static char *
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index 83d7f68b821..c912f8932df 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -23,8 +23,8 @@
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/json.h"
-#include "utils/jsonapi.h"
#include "utils/jsonb.h"
+#include "utils/jsonfuncs.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 9eff5068553..66ea11b971c 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -329,6 +329,8 @@ typedef struct JsObject
hash_destroy((jso)->val.json_hash); \
} while (0)
+static int report_json_context(JsonLexContext *lex);
+
/* semantic action functions for json_object_keys */
static void okeys_object_field_start(void *state, char *fname, bool isnull);
static void okeys_array_start(void *state);
@@ -485,6 +487,37 @@ static void transform_string_values_array_element_start(void *state, bool isnull
static void transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype);
/*
+ * pg_parse_json_or_ereport
+ *
+ * This fuction is like pg_parse_json, except that it does not return a
+ * JsonParseErrorType. Instead, in case of any failure, this function will
+ * ereport(ERROR).
+ */
+void
+pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem)
+{
+ JsonParseErrorType result;
+
+ result = pg_parse_json(lex, sem);
+ if (result != JSON_SUCCESS)
+ json_ereport_error(result, lex);
+}
+
+/*
+ * makeJsonLexContext
+ *
+ * This is like makeJsonLexContextCstringLen, but it accepts a text value
+ * directly.
+ */
+JsonLexContext *
+makeJsonLexContext(text *json, bool need_escapes)
+{
+ return makeJsonLexContextCstringLen(VARDATA_ANY(json),
+ VARSIZE_ANY_EXHDR(json),
+ need_escapes);
+}
+
+/*
* SQL function json_object_keys
*
* Returns the set of keys for the object argument.
@@ -573,6 +606,99 @@ jsonb_object_keys(PG_FUNCTION_ARGS)
SRF_RETURN_DONE(funcctx);
}
+/*
+ * Report a JSON error.
+ */
+void
+json_ereport_error(JsonParseErrorType error, JsonLexContext *lex)
+{
+ if (error == JSON_UNICODE_HIGH_ESCAPE ||
+ error == JSON_UNICODE_CODE_POINT_ZERO)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
+ errmsg("unsupported Unicode escape sequence"),
+ errdetail("%s", json_errdetail(error, lex)),
+ report_json_context(lex)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for type %s", "json"),
+ errdetail("%s", json_errdetail(error, lex)),
+ report_json_context(lex)));
+}
+
+/*
+ * Report a CONTEXT line for bogus JSON input.
+ *
+ * lex->token_terminator must be set to identify the spot where we detected
+ * the error. Note that lex->token_start might be NULL, in case we recognized
+ * error at EOF.
+ *
+ * The return value isn't meaningful, but we make it non-void so that this
+ * can be invoked inside ereport().
+ */
+static int
+report_json_context(JsonLexContext *lex)
+{
+ const char *context_start;
+ const char *context_end;
+ const char *line_start;
+ int line_number;
+ char *ctxt;
+ int ctxtlen;
+ const char *prefix;
+ const char *suffix;
+
+ /* Choose boundaries for the part of the input we will display */
+ context_start = lex->input;
+ context_end = lex->token_terminator;
+ line_start = context_start;
+ line_number = 1;
+ for (;;)
+ {
+ /* Always advance over newlines */
+ if (context_start < context_end && *context_start == '\n')
+ {
+ context_start++;
+ line_start = context_start;
+ line_number++;
+ continue;
+ }
+ /* Otherwise, done as soon as we are close enough to context_end */
+ if (context_end - context_start < 50)
+ break;
+ /* Advance to next multibyte character */
+ if (IS_HIGHBIT_SET(*context_start))
+ context_start += pg_mblen(context_start);
+ else
+ context_start++;
+ }
+
+ /*
+ * We add "..." to indicate that the excerpt doesn't start at the
+ * beginning of the line ... but if we're within 3 characters of the
+ * beginning of the line, we might as well just show the whole line.
+ */
+ if (context_start - line_start <= 3)
+ context_start = line_start;
+
+ /* Get a null-terminated copy of the data to present */
+ ctxtlen = context_end - context_start;
+ ctxt = palloc(ctxtlen + 1);
+ memcpy(ctxt, context_start, ctxtlen);
+ ctxt[ctxtlen] = '\0';
+
+ /*
+ * Show the context, prefixing "..." if not starting at start of line, and
+ * suffixing "..." if not ending at end of line.
+ */
+ prefix = (context_start > line_start) ? "..." : "";
+ suffix = (lex->token_type != JSON_TOKEN_END && context_end - lex->input < lex->input_length && *context_end != '\n' && *context_end != '\r') ? "..." : "";
+
+ return errcontext("JSON data, line %d: %s%s%s",
+ line_number, prefix, ctxt, suffix);
+}
+
Datum
json_object_keys(PG_FUNCTION_ARGS)
diff --git a/src/include/utils/jsonapi.h b/src/include/utils/jsonapi.h
index 74dc35c41c6..4d69b184951 100644
--- a/src/include/utils/jsonapi.h
+++ b/src/include/utils/jsonapi.h
@@ -126,12 +126,6 @@ typedef struct JsonSemAction
extern JsonParseErrorType pg_parse_json(JsonLexContext *lex,
JsonSemAction *sem);
-/*
- * Same thing, but signal errors via ereport(ERROR) instead of returning
- * a result code.
- */
-extern void pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem);
-
/* the null action object used for pure validation */
extern JsonSemAction nullSemAction;
@@ -148,15 +142,11 @@ extern JsonParseErrorType json_count_array_elements(JsonLexContext *lex,
int *elements);
/*
- * constructors for JsonLexContext, with or without strval element.
+ * constructor for JsonLexContext, with or without strval element.
* If supplied, the strval element will contain a de-escaped version of
* the lexeme. However, doing this imposes a performance penalty, so
* it should be avoided if the de-escaped lexeme is not required.
- *
- * If you already have the json as a text* value, use the first of these
- * functions, otherwise use makeJsonLexContextCstringLen().
*/
-extern JsonLexContext *makeJsonLexContext(text *json, bool need_escapes);
extern JsonLexContext *makeJsonLexContextCstringLen(char *json,
int len,
bool need_escapes);
@@ -164,9 +154,6 @@ extern JsonLexContext *makeJsonLexContextCstringLen(char *json,
/* lex one token */
extern JsonParseErrorType json_lex(JsonLexContext *lex);
-/* report an error during json lexing or parsing */
-extern void json_ereport_error(JsonParseErrorType error, JsonLexContext *lex);
-
/* 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 19f087ccae9..b993f38409f 100644
--- a/src/include/utils/jsonfuncs.h
+++ b/src/include/utils/jsonfuncs.h
@@ -36,6 +36,15 @@ typedef void (*JsonIterateStringValuesAction) (void *state, char *elem_value, in
/* an action that will be applied to each value in transform_json(b)_values functions */
typedef text *(*JsonTransformStringValuesAction) (void *state, char *elem_value, int elem_len);
+/* build a JsonLexContext from a text datum */
+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);
+
+/* report an error during json lexing or parsing */
+extern void json_ereport_error(JsonParseErrorType error, JsonLexContext *lex);
+
extern uint32 parse_jsonb_index_flags(Jsonb *jb);
extern void iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state,
JsonIterateStringValuesAction action);