@@ -161,6 +161,7 @@ makeJsonLexContextCstringLen(JsonLexContext *lex, char *json,
161
161
else
162
162
memset (lex , 0 , sizeof (JsonLexContext ));
163
163
164
+ lex -> errormsg = NULL ;
164
165
lex -> input = lex -> token_terminator = lex -> line_start = json ;
165
166
lex -> line_number = 1 ;
166
167
lex -> input_length = len ;
@@ -175,18 +176,21 @@ makeJsonLexContextCstringLen(JsonLexContext *lex, char *json,
175
176
}
176
177
177
178
/*
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.
181
184
*/
182
185
void
183
186
freeJsonLexContext (JsonLexContext * lex )
184
187
{
185
188
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
+
190
194
if (lex -> flags & JSONLEX_FREE_STRUCT )
191
195
pfree (lex );
192
196
}
@@ -1145,72 +1149,71 @@ report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
1145
1149
return JSON_SUCCESS ; /* silence stupider compilers */
1146
1150
}
1147
1151
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
-
1164
1152
/*
1165
1153
* Construct an (already translated) detail message for a JSON error.
1166
1154
*
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.
1170
1157
*/
1171
1158
char *
1172
1159
json_errdetail (JsonParseErrorType error , JsonLexContext * lex )
1173
1160
{
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
+
1174
1175
switch (error )
1175
1176
{
1176
1177
case JSON_SUCCESS :
1177
1178
/* fall through to the error code after switch */
1178
1179
break ;
1179
1180
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 ;
1182
1183
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 ;
1185
1188
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 ;
1188
1191
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 ;
1191
1194
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 ;
1194
1197
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 ;
1197
1200
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 ;
1200
1203
case JSON_EXPECTED_MORE :
1201
1204
return _ ("The input string ended unexpectedly." );
1202
1205
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 ;
1205
1208
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 ;
1208
1211
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 ;
1211
1214
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 ;
1214
1217
case JSON_UNICODE_CODE_POINT_ZERO :
1215
1218
return _ ("\\u0000 cannot be converted to text." );
1216
1219
case JSON_UNICODE_ESCAPE_FORMAT :
@@ -1219,9 +1222,19 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
1219
1222
/* note: this case is only reachable in frontend not backend */
1220
1223
return _ ("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8." );
1221
1224
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
1223
1232
return psprintf (_ ("Unicode escape value could not be translated to the server's encoding %s." ),
1224
1233
GetDatabaseEncodingName ());
1234
+ #else
1235
+ Assert (false);
1236
+ break ;
1237
+ #endif
1225
1238
case JSON_UNICODE_HIGH_SURROGATE :
1226
1239
return _ ("Unicode high surrogate must not follow a high surrogate." );
1227
1240
case JSON_UNICODE_LOW_SURROGATE :
@@ -1230,13 +1243,17 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
1230
1243
/* fall through to the error code after switch */
1231
1244
break ;
1232
1245
}
1246
+ #undef token_error
1233
1247
1234
1248
/*
1235
1249
* We don't use a default: case, so that the compiler will warn about
1236
1250
* unhandled enum values. But this needs to be here anyway to cover the
1237
1251
* possibility of an incorrect input.
1238
1252
*/
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 ;
1241
1259
}
1242
- #endif
0 commit comments