@@ -161,6 +161,7 @@ makeJsonLexContextCstringLen(JsonLexContext *lex, char *json,
161161 else
162162 memset (lex , 0 , sizeof (JsonLexContext ));
163163
164+ lex -> errormsg = NULL ;
164165 lex -> input = lex -> token_terminator = lex -> line_start = json ;
165166 lex -> line_number = 1 ;
166167 lex -> input_length = len ;
@@ -175,18 +176,21 @@ makeJsonLexContextCstringLen(JsonLexContext *lex, char *json,
175176}
176177
177178/*
178- * Free memory in a JsonLexContext. There's no need for this if a *lex
179- * pointer was given when the object was made and need_escapes was false,
180- * or (in backend environment) a memory context delete/reset is imminent.
179+ * Free memory in a JsonLexContext.
180+ *
181+ * There's no need for this if a *lex pointer was given when the object was
182+ * made, need_escapes was false, and json_errdetail() was not called; or if (in
183+ * backend environment) a memory context delete/reset is imminent.
181184 */
182185void
183186freeJsonLexContext (JsonLexContext * lex )
184187{
185188 if (lex -> flags & JSONLEX_FREE_STRVAL )
186- {
187- pfree (lex -> strval -> data );
188- pfree (lex -> strval );
189- }
189+ destroyStringInfo (lex -> strval );
190+
191+ if (lex -> errormsg )
192+ destroyStringInfo (lex -> errormsg );
193+
190194 if (lex -> flags & JSONLEX_FREE_STRUCT )
191195 pfree (lex );
192196}
@@ -1145,72 +1149,71 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
11451149 return JSON_SUCCESS ; /* silence stupider compilers */
11461150}
11471151
1148-
1149- #ifndef FRONTEND
1150- /*
1151- * Extract the current token from a lexing context, for error reporting.
1152- */
1153- static char *
1154- extract_token (JsonLexContext * lex )
1155- {
1156- int toklen = lex -> token_terminator - lex -> token_start ;
1157- char * token = palloc (toklen + 1 );
1158-
1159- memcpy (token , lex -> token_start , toklen );
1160- token [toklen ] = '\0' ;
1161- return token ;
1162- }
1163-
11641152/*
11651153 * Construct an (already translated) detail message for a JSON error.
11661154 *
1167- * Note that the error message generated by this routine may not be
1168- * palloc'd, making it unsafe for frontend code as there is no way to
1169- * know if this can be safely pfree'd or not.
1155+ * The returned pointer should not be freed, the allocation is either static
1156+ * or owned by the JsonLexContext.
11701157 */
11711158char *
11721159json_errdetail (JsonParseErrorType error , JsonLexContext * lex )
11731160{
1161+ if (lex -> errormsg )
1162+ resetStringInfo (lex -> errormsg );
1163+ else
1164+ lex -> errormsg = makeStringInfo ();
1165+
1166+ /*
1167+ * A helper for error messages that should print the current token. The
1168+ * format must contain exactly one %.*s specifier.
1169+ */
1170+ #define token_error (lex , format ) \
1171+ appendStringInfo((lex)->errormsg, _(format), \
1172+ (int) ((lex)->token_terminator - (lex)->token_start), \
1173+ (lex)->token_start);
1174+
11741175 switch (error )
11751176 {
11761177 case JSON_SUCCESS :
11771178 /* fall through to the error code after switch */
11781179 break ;
11791180 case JSON_ESCAPING_INVALID :
1180- return psprintf ( _ ( "Escape sequence \"\\%s\" is invalid." ),
1181- extract_token ( lex )) ;
1181+ token_error ( lex , "Escape sequence \"\\%.* s\" is invalid." );
1182+ break ;
11821183 case JSON_ESCAPING_REQUIRED :
1183- return psprintf (_ ("Character with value 0x%02x must be escaped." ),
1184- (unsigned char ) * (lex -> token_terminator ));
1184+ appendStringInfo (lex -> errormsg ,
1185+ _ ("Character with value 0x%02x must be escaped." ),
1186+ (unsigned char ) * (lex -> token_terminator ));
1187+ break ;
11851188 case JSON_EXPECTED_END :
1186- return psprintf ( _ ( "Expected end of input, but found \"%s\"." ),
1187- extract_token ( lex )) ;
1189+ token_error ( lex , "Expected end of input, but found \"%.* s\"." );
1190+ break ;
11881191 case JSON_EXPECTED_ARRAY_FIRST :
1189- return psprintf ( _ ( "Expected array element or \"]\", but found \"%s\"." ),
1190- extract_token ( lex )) ;
1192+ token_error ( lex , "Expected array element or \"]\", but found \"%.* s\"." );
1193+ break ;
11911194 case JSON_EXPECTED_ARRAY_NEXT :
1192- return psprintf ( _ ( "Expected \",\" or \"]\", but found \"%s\"." ),
1193- extract_token ( lex )) ;
1195+ token_error ( lex , "Expected \",\" or \"]\", but found \"%.* s\"." );
1196+ break ;
11941197 case JSON_EXPECTED_COLON :
1195- return psprintf ( _ ( "Expected \":\", but found \"%s\"." ),
1196- extract_token ( lex )) ;
1198+ token_error ( lex , "Expected \":\", but found \"%.* s\"." );
1199+ break ;
11971200 case JSON_EXPECTED_JSON :
1198- return psprintf ( _ ( "Expected JSON value, but found \"%s\"." ),
1199- extract_token ( lex )) ;
1201+ token_error ( lex , "Expected JSON value, but found \"%.* s\"." );
1202+ break ;
12001203 case JSON_EXPECTED_MORE :
12011204 return _ ("The input string ended unexpectedly." );
12021205 case JSON_EXPECTED_OBJECT_FIRST :
1203- return psprintf ( _ ( "Expected string or \"}\", but found \"%s\"." ),
1204- extract_token ( lex )) ;
1206+ token_error ( lex , "Expected string or \"}\", but found \"%.* s\"." );
1207+ break ;
12051208 case JSON_EXPECTED_OBJECT_NEXT :
1206- return psprintf ( _ ( "Expected \",\" or \"}\", but found \"%s\"." ),
1207- extract_token ( lex )) ;
1209+ token_error ( lex , "Expected \",\" or \"}\", but found \"%.* s\"." );
1210+ break ;
12081211 case JSON_EXPECTED_STRING :
1209- return psprintf ( _ ( "Expected string, but found \"%s\"." ),
1210- extract_token ( lex )) ;
1212+ token_error ( lex , "Expected string, but found \"%.* s\"." );
1213+ break ;
12111214 case JSON_INVALID_TOKEN :
1212- return psprintf ( _ ( "Token \"%s\" is invalid." ),
1213- extract_token ( lex )) ;
1215+ token_error ( lex , "Token \"%.* s\" is invalid." );
1216+ break ;
12141217 case JSON_UNICODE_CODE_POINT_ZERO :
12151218 return _ ("\\u0000 cannot be converted to text." );
12161219 case JSON_UNICODE_ESCAPE_FORMAT :
@@ -1219,9 +1222,19 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
12191222 /* note: this case is only reachable in frontend not backend */
12201223 return _ ("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8." );
12211224 case JSON_UNICODE_UNTRANSLATABLE :
1222- /* note: this case is only reachable in backend not frontend */
1225+
1226+ /*
1227+ * Note: this case is only reachable in backend and not frontend.
1228+ * #ifdef it away so the frontend doesn't try to link against
1229+ * backend functionality.
1230+ */
1231+ #ifndef FRONTEND
12231232 return psprintf (_ ("Unicode escape value could not be translated to the server's encoding %s." ),
12241233 GetDatabaseEncodingName ());
1234+ #else
1235+ Assert (false);
1236+ break ;
1237+ #endif
12251238 case JSON_UNICODE_HIGH_SURROGATE :
12261239 return _ ("Unicode high surrogate must not follow a high surrogate." );
12271240 case JSON_UNICODE_LOW_SURROGATE :
@@ -1230,13 +1243,17 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
12301243 /* fall through to the error code after switch */
12311244 break ;
12321245 }
1246+ #undef token_error
12331247
12341248 /*
12351249 * We don't use a default: case, so that the compiler will warn about
12361250 * unhandled enum values. But this needs to be here anyway to cover the
12371251 * possibility of an incorrect input.
12381252 */
1239- elog (ERROR , "unexpected json parse error type: %d" , (int ) error );
1240- return NULL ;
1253+ if (lex -> errormsg -> len == 0 )
1254+ appendStringInfo (lex -> errormsg ,
1255+ _ ("unexpected json parse error type: %d" ),
1256+ (int ) error );
1257+
1258+ return lex -> errormsg -> data ;
12411259}
1242- #endif
0 commit comments