From 92ef37e68a9e95dbfff10e1bb1b369a957987fa4 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Wed, 15 Jan 2020 11:08:13 -0500
Subject: [PATCH 5/6] Frontendify jsonapi.c

---
 src/backend/utils/adt/jsonapi.c | 71 +++++++++++++++++++++++++++++++--
 1 file changed, 68 insertions(+), 3 deletions(-)

diff --git a/src/backend/utils/adt/jsonapi.c b/src/backend/utils/adt/jsonapi.c
index 20f7f0f7ac..f355bd9de1 100644
--- a/src/backend/utils/adt/jsonapi.c
+++ b/src/backend/utils/adt/jsonapi.c
@@ -13,12 +13,44 @@
  */
 #include "postgres.h"
 
-#include "mb/pg_wchar.h"
+#ifdef FRONTEND
+#include "common/logging.h"
+#include "libpq-fe.h"
+#else
 #include "miscadmin.h"
+#endif
+
+#include "mb/pg_wchar.h"
 #include "utils/jsonapi.h"
 
+#ifdef FRONTEND
+static void json_frontend_error(int dummy) pg_attribute_noreturn();
+
+static int dummy;
+#define errcode(something) (dummy = 1)
+static int errmsg(const char *fmt, ...) pg_attribute_printf(1,2);
+static int errdetail(const char *fmt, ...) pg_attribute_printf(1, 2);
+
+static void json_frontend_error(int dummy)
+{
+	exit(1);
+}
+static int errmsg(const char *fmt, ...)
+{
+	return 1;
+}
+static int errdetail(const char *fmt, ...)
+{
+	return 1;
+}
+
+#define json_error(rest) \
+	json_frontend_error(rest)
+#define check_stack_depth()
+#else
 #define json_error(rest) \
 	ereport(ERROR, (rest, report_json_context(lex)))
+#endif
 
 /*
  * The context of the parser is maintained by the recursive descent
@@ -48,7 +80,9 @@ static void parse_array_element(JsonLexContext *lex, JsonSemAction *sem);
 static void parse_array(JsonLexContext *lex, JsonSemAction *sem);
 static void report_parse_error(JsonParseContext ctx, JsonLexContext *lex) pg_attribute_noreturn();
 static void report_invalid_token(JsonLexContext *lex) pg_attribute_noreturn();
+#ifndef FRONTEND
 static int	report_json_context(JsonLexContext *lex);
+#endif
 static char *extract_mb_char(char *s);
 
 /* the null action object used for pure validation */
@@ -701,7 +735,11 @@ json_lex_string(JsonLexContext *lex)
 						ch = (ch * 16) + (*s - 'A') + 10;
 					else
 					{
+#ifdef FRONTEND
+						lex->token_terminator = s + PQmblen(s, PG_UTF8);
+#else
 						lex->token_terminator = s + pg_mblen(s);
+#endif
 						json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 									errmsg("invalid input syntax for type %s",
 										   "json"),
@@ -752,6 +790,14 @@ json_lex_string(JsonLexContext *lex)
 									errmsg("unsupported Unicode escape sequence"),
 									errdetail("\\u0000 cannot be converted to text.")));
 					}
+#ifdef FRONTEND
+					else
+					{
+						unicode_to_utf8(ch, (unsigned char *) utf8str);
+						utf8len = PQmblen(utf8str, PG_UTF8);
+						appendBinaryStringInfo(lex->strval, utf8str, utf8len);
+					}
+#else
 					else if (GetDatabaseEncoding() == PG_UTF8)
 					{
 						unicode_to_utf8(ch, (unsigned char *) utf8str);
@@ -773,7 +819,7 @@ json_lex_string(JsonLexContext *lex)
 									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.")));
 					}
-
+#endif
 				}
 			}
 			else if (lex->strval != NULL)
@@ -808,7 +854,11 @@ json_lex_string(JsonLexContext *lex)
 						break;
 					default:
 						/* Not a valid string escape, so error out. */
+#ifdef FRONTEND
+						lex->token_terminator = s + PQmblen(s, PG_UTF8);
+#else
 						lex->token_terminator = s + pg_mblen(s);
+#endif
 						json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 									errmsg("invalid input syntax for type %s",
 										   "json"),
@@ -825,7 +875,11 @@ json_lex_string(JsonLexContext *lex)
 				 * replace it with a switch statement, but testing so far has
 				 * shown it's not a performance win.
 				 */
-				lex->token_terminator = s + pg_mblen(s);
+#ifdef FRONTEND
+						lex->token_terminator = s + PQmblen(s, PG_UTF8);
+#else
+						lex->token_terminator = s + pg_mblen(s);
+#endif
 				json_error((errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 							errmsg("invalid input syntax for type %s", "json"),
 							errdetail("Escape sequence \"\\%s\" is invalid.",
@@ -1058,7 +1112,12 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
 									  token)));
 				break;
 			default:
+#ifdef FRONTEND
+				pg_log_fatal("unexpected json parse state: %d", ctx);
+				exit(1);
+#else
 				elog(ERROR, "unexpected json parse state: %d", ctx);
+#endif
 		}
 	}
 }
@@ -1085,6 +1144,7 @@ report_invalid_token(JsonLexContext *lex)
 				errdetail("Token \"%s\" is invalid.", token)));
 }
 
+#ifndef FRONTEND
 /*
  * Report a CONTEXT line for bogus JSON input.
  *
@@ -1156,6 +1216,7 @@ report_json_context(JsonLexContext *lex)
 	return errcontext("JSON data, line %d: %s%s%s",
 					  line_number, prefix, ctxt, suffix);
 }
+#endif
 
 /*
  * Extract a single, possibly multi-byte char from the input string.
@@ -1166,7 +1227,11 @@ extract_mb_char(char *s)
 	char	   *res;
 	int			len;
 
+#ifdef FRONTEND
+	len = PQmblen(s, PG_UTF8);
+#else
 	len = pg_mblen(s);
+#endif
 	res = palloc(len + 1);
 	memcpy(res, s, len);
 	res[len] = '\0';
-- 
2.17.2 (Apple Git-113)

