From d05e1fc82a51cb583a0367e72b1afc0de561dd00 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Wed, 15 Jan 2020 10:36:52 -0500
Subject: [PATCH 4/6] Introduce json_error() macro.

---
 src/backend/utils/adt/jsonapi.c | 221 +++++++++++++-------------------
 1 file changed, 90 insertions(+), 131 deletions(-)

diff --git a/src/backend/utils/adt/jsonapi.c b/src/backend/utils/adt/jsonapi.c
index fc8af9f861..20f7f0f7ac 100644
--- a/src/backend/utils/adt/jsonapi.c
+++ b/src/backend/utils/adt/jsonapi.c
@@ -17,6 +17,9 @@
 #include "miscadmin.h"
 #include "utils/jsonapi.h"
 
+#define json_error(rest) \
+	ereport(ERROR, (rest, report_json_context(lex)))
+
 /*
  * The context of the parser is maintained by the recursive descent
  * mechanism, but is passed explicitly to the error reporting routine
@@ -163,6 +166,7 @@ IsValidJsonNumber(const char *str, int len)
 	return (!numeric_error) && (total_len == dummy_lex.input_length);
 }
 
+#ifndef FRONTEND
 /*
  * makeJsonLexContext
  *
@@ -182,6 +186,7 @@ makeJsonLexContext(text *json, bool need_escapes)
 										VARSIZE_ANY_EXHDR(json),
 										need_escapes);
 }
+#endif
 
 JsonLexContext *
 makeJsonLexContextCstringLen(char *json, int len, bool need_escapes)
@@ -659,12 +664,10 @@ json_lex_string(JsonLexContext *lex)
 			/* Per RFC4627, these characters MUST be escaped. */
 			/* Since *s isn't printable, exclude it from the context string */
 			lex->token_terminator = s;
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-					 errmsg("invalid input syntax for type %s", "json"),
-					 errdetail("Character with value 0x%02x must be escaped.",
-							   (unsigned char) *s),
-					 report_json_context(lex)));
+			json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+						errmsg("invalid input syntax for type %s", "json"),
+						errdetail("Character with value 0x%02x must be escaped.",
+								  (unsigned char) *s)));
 		}
 		else if (*s == '\\')
 		{
@@ -699,12 +702,10 @@ json_lex_string(JsonLexContext *lex)
 					else
 					{
 						lex->token_terminator = s + pg_mblen(s);
-						ereport(ERROR,
-								(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-								 errmsg("invalid input syntax for type %s",
-										"json"),
-								 errdetail("\"\\u\" must be followed by four hexadecimal digits."),
-								 report_json_context(lex)));
+						json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+									errmsg("invalid input syntax for type %s",
+										   "json"),
+									errdetail("\"\\u\" must be followed by four hexadecimal digits.")));
 					}
 				}
 				if (lex->strval != NULL)
@@ -715,33 +716,27 @@ json_lex_string(JsonLexContext *lex)
 					if (ch >= 0xd800 && ch <= 0xdbff)
 					{
 						if (hi_surrogate != -1)
-							ereport(ERROR,
-									(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-									 errmsg("invalid input syntax for type %s",
-											"json"),
-									 errdetail("Unicode high surrogate must not follow a high surrogate."),
-									 report_json_context(lex)));
+							json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+										errmsg("invalid input syntax for type %s",
+											   "json"),
+										errdetail("Unicode high surrogate must not follow a high surrogate.")));
 						hi_surrogate = (ch & 0x3ff) << 10;
 						continue;
 					}
 					else if (ch >= 0xdc00 && ch <= 0xdfff)
 					{
 						if (hi_surrogate == -1)
-							ereport(ERROR,
-									(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-									 errmsg("invalid input syntax for type %s", "json"),
-									 errdetail("Unicode low surrogate must follow a high surrogate."),
-									 report_json_context(lex)));
+							json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+										errmsg("invalid input syntax for type %s", "json"),
+										errdetail("Unicode low surrogate must follow a high surrogate.")));
 						ch = 0x10000 + hi_surrogate + (ch & 0x3ff);
 						hi_surrogate = -1;
 					}
 
 					if (hi_surrogate != -1)
-						ereport(ERROR,
-								(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-								 errmsg("invalid input syntax for type %s", "json"),
-								 errdetail("Unicode low surrogate must follow a high surrogate."),
-								 report_json_context(lex)));
+						json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+									errmsg("invalid input syntax for type %s", "json"),
+									errdetail("Unicode low surrogate must follow a high surrogate.")));
 
 					/*
 					 * For UTF8, replace the escape sequence by the actual
@@ -753,11 +748,9 @@ json_lex_string(JsonLexContext *lex)
 					if (ch == 0)
 					{
 						/* We can't allow this, since our TEXT type doesn't */
-						ereport(ERROR,
-								(errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
-								 errmsg("unsupported Unicode escape sequence"),
-								 errdetail("\\u0000 cannot be converted to text."),
-								 report_json_context(lex)));
+						json_error((errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
+									errmsg("unsupported Unicode escape sequence"),
+									errdetail("\\u0000 cannot be converted to text.")));
 					}
 					else if (GetDatabaseEncoding() == PG_UTF8)
 					{
@@ -776,11 +769,9 @@ json_lex_string(JsonLexContext *lex)
 					}
 					else
 					{
-						ereport(ERROR,
-								(errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
-								 errmsg("unsupported Unicode escape sequence"),
-								 errdetail("Unicode escape values cannot be used for code point values above 007F when the server encoding is not UTF8."),
-								 report_json_context(lex)));
+						json_error((errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
+									errmsg("unsupported Unicode escape sequence"),
+									errdetail("Unicode escape values cannot be used for code point values above 007F when the server encoding is not UTF8.")));
 					}
 
 				}
@@ -788,12 +779,10 @@ json_lex_string(JsonLexContext *lex)
 			else if (lex->strval != NULL)
 			{
 				if (hi_surrogate != -1)
-					ereport(ERROR,
-							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-							 errmsg("invalid input syntax for type %s",
-									"json"),
-							 errdetail("Unicode low surrogate must follow a high surrogate."),
-							 report_json_context(lex)));
+					json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+								errmsg("invalid input syntax for type %s",
+									   "json"),
+								errdetail("Unicode low surrogate must follow a high surrogate.")));
 
 				switch (*s)
 				{
@@ -820,13 +809,11 @@ json_lex_string(JsonLexContext *lex)
 					default:
 						/* Not a valid string escape, so error out. */
 						lex->token_terminator = s + pg_mblen(s);
-						ereport(ERROR,
-								(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-								 errmsg("invalid input syntax for type %s",
-										"json"),
-								 errdetail("Escape sequence \"\\%s\" is invalid.",
-										   extract_mb_char(s)),
-								 report_json_context(lex)));
+						json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+									errmsg("invalid input syntax for type %s",
+										   "json"),
+									errdetail("Escape sequence \"\\%s\" is invalid.",
+											  extract_mb_char(s))));
 				}
 			}
 			else if (strchr("\"\\/bfnrt", *s) == NULL)
@@ -839,23 +826,19 @@ json_lex_string(JsonLexContext *lex)
 				 * shown it's not a performance win.
 				 */
 				lex->token_terminator = s + pg_mblen(s);
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-						 errmsg("invalid input syntax for type %s", "json"),
-						 errdetail("Escape sequence \"\\%s\" is invalid.",
-								   extract_mb_char(s)),
-						 report_json_context(lex)));
+				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							errmsg("invalid input syntax for type %s", "json"),
+							errdetail("Escape sequence \"\\%s\" is invalid.",
+									  extract_mb_char(s))));
 			}
 
 		}
 		else if (lex->strval != NULL)
 		{
 			if (hi_surrogate != -1)
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-						 errmsg("invalid input syntax for type %s", "json"),
-						 errdetail("Unicode low surrogate must follow a high surrogate."),
-						 report_json_context(lex)));
+				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							errmsg("invalid input syntax for type %s", "json"),
+							errdetail("Unicode low surrogate must follow a high surrogate.")));
 
 			appendStringInfoChar(lex->strval, *s);
 		}
@@ -863,11 +846,9 @@ json_lex_string(JsonLexContext *lex)
 	}
 
 	if (hi_surrogate != -1)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-				 errmsg("invalid input syntax for type %s", "json"),
-				 errdetail("Unicode low surrogate must follow a high surrogate."),
-				 report_json_context(lex)));
+		json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+					errmsg("invalid input syntax for type %s", "json"),
+					errdetail("Unicode low surrogate must follow a high surrogate.")));
 
 	/* Hooray, we found the end of the string! */
 	lex->prev_token_terminator = lex->token_terminator;
@@ -1008,11 +989,9 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
 
 	/* Handle case where the input ended prematurely. */
 	if (lex->token_start == NULL || lex->token_type == JSON_TOKEN_END)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-				 errmsg("invalid input syntax for type %s", "json"),
-				 errdetail("The input string ended unexpectedly."),
-				 report_json_context(lex)));
+		json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+					errmsg("invalid input syntax for type %s", "json"),
+					errdetail("The input string ended unexpectedly.")));
 
 	/* Separate out the current token. */
 	toklen = lex->token_terminator - lex->token_start;
@@ -1022,79 +1001,61 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
 
 	/* Complain, with the appropriate detail message. */
 	if (ctx == JSON_PARSE_END)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-				 errmsg("invalid input syntax for type %s", "json"),
-				 errdetail("Expected end of input, but found \"%s\".",
-						   token),
-				 report_json_context(lex)));
+		json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+					errmsg("invalid input syntax for type %s", "json"),
+					errdetail("Expected end of input, but found \"%s\".",
+							  token)));
 	else
 	{
 		switch (ctx)
 		{
 			case JSON_PARSE_VALUE:
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-						 errmsg("invalid input syntax for type %s", "json"),
-						 errdetail("Expected JSON value, but found \"%s\".",
-								   token),
-						 report_json_context(lex)));
+				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							errmsg("invalid input syntax for type %s", "json"),
+							errdetail("Expected JSON value, but found \"%s\".",
+									  token)));
 				break;
 			case JSON_PARSE_STRING:
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-						 errmsg("invalid input syntax for type %s", "json"),
-						 errdetail("Expected string, but found \"%s\".",
-								   token),
-						 report_json_context(lex)));
+				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							errmsg("invalid input syntax for type %s", "json"),
+							errdetail("Expected string, but found \"%s\".",
+									  token)));
 				break;
 			case JSON_PARSE_ARRAY_START:
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-						 errmsg("invalid input syntax for type %s", "json"),
-						 errdetail("Expected array element or \"]\", but found \"%s\".",
-								   token),
-						 report_json_context(lex)));
+				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							errmsg("invalid input syntax for type %s", "json"),
+							errdetail("Expected array element or \"]\", but found \"%s\".",
+									  token)));
 				break;
 			case JSON_PARSE_ARRAY_NEXT:
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-						 errmsg("invalid input syntax for type %s", "json"),
-						 errdetail("Expected \",\" or \"]\", but found \"%s\".",
-								   token),
-						 report_json_context(lex)));
+				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							errmsg("invalid input syntax for type %s", "json"),
+							errdetail("Expected \",\" or \"]\", but found \"%s\".",
+									  token)));
 				break;
 			case JSON_PARSE_OBJECT_START:
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-						 errmsg("invalid input syntax for type %s", "json"),
-						 errdetail("Expected string or \"}\", but found \"%s\".",
-								   token),
-						 report_json_context(lex)));
+				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							errmsg("invalid input syntax for type %s", "json"),
+							errdetail("Expected string or \"}\", but found \"%s\".",
+									  token)));
 				break;
 			case JSON_PARSE_OBJECT_LABEL:
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-						 errmsg("invalid input syntax for type %s", "json"),
-						 errdetail("Expected \":\", but found \"%s\".",
-								   token),
-						 report_json_context(lex)));
+				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							errmsg("invalid input syntax for type %s", "json"),
+							errdetail("Expected \":\", but found \"%s\".",
+									  token)));
 				break;
 			case JSON_PARSE_OBJECT_NEXT:
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-						 errmsg("invalid input syntax for type %s", "json"),
-						 errdetail("Expected \",\" or \"}\", but found \"%s\".",
-								   token),
-						 report_json_context(lex)));
+				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							errmsg("invalid input syntax for type %s", "json"),
+							errdetail("Expected \",\" or \"}\", but found \"%s\".",
+									  token)));
 				break;
 			case JSON_PARSE_OBJECT_COMMA:
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-						 errmsg("invalid input syntax for type %s", "json"),
-						 errdetail("Expected string, but found \"%s\".",
-								   token),
-						 report_json_context(lex)));
+				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							errmsg("invalid input syntax for type %s", "json"),
+							errdetail("Expected string, but found \"%s\".",
+									  token)));
 				break;
 			default:
 				elog(ERROR, "unexpected json parse state: %d", ctx);
@@ -1119,11 +1080,9 @@ report_invalid_token(JsonLexContext *lex)
 	memcpy(token, lex->token_start, toklen);
 	token[toklen] = '\0';
 
-	ereport(ERROR,
-			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-			 errmsg("invalid input syntax for type %s", "json"),
-			 errdetail("Token \"%s\" is invalid.", token),
-			 report_json_context(lex)));
+	json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				errmsg("invalid input syntax for type %s", "json"),
+				errdetail("Token \"%s\" is invalid.", token)));
 }
 
 /*
-- 
2.17.2 (Apple Git-113)

