Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 29ceacc

Browse files
committed
Improve error reporting in jsonpath
This commit contains multiple improvements to error reporting in jsonpath including but not limited to getting rid of following things: * definition of error messages in macros, * errdetail() when valueable information could fit to errmsg(), * word "singleton" which is not properly explained anywhere, * line breaks in error messages. Reported-by: Tom Lane Discussion: https://postgr.es/m/14890.1555523005%40sss.pgh.pa.us Author: Alexander Korotkov Reviewed-by: Tom Lane
1 parent b84dbc8 commit 29ceacc

File tree

7 files changed

+130
-247
lines changed

7 files changed

+130
-247
lines changed

src/backend/utils/adt/jsonpath_exec.c

+33-87
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,6 @@
7777
#include "utils/varlena.h"
7878

7979

80-
/* Standard error message for SQL/JSON errors */
81-
#define ERRMSG_JSON_ARRAY_NOT_FOUND "SQL/JSON array not found"
82-
#define ERRMSG_JSON_OBJECT_NOT_FOUND "SQL/JSON object not found"
83-
#define ERRMSG_JSON_MEMBER_NOT_FOUND "SQL/JSON member not found"
84-
#define ERRMSG_JSON_NUMBER_NOT_FOUND "SQL/JSON number not found"
85-
#define ERRMSG_JSON_SCALAR_REQUIRED "SQL/JSON scalar required"
86-
#define ERRMSG_SINGLETON_JSON_ITEM_REQUIRED "singleton SQL/JSON item required"
87-
#define ERRMSG_NON_NUMERIC_JSON_ITEM "non-numeric SQL/JSON item"
88-
#define ERRMSG_INVALID_JSON_SUBSCRIPT "invalid SQL/JSON subscript"
89-
9080
/*
9181
* Represents "base object" and it's "id" for .keyvalue() evaluation.
9282
*/
@@ -349,8 +339,7 @@ jsonb_path_match(PG_FUNCTION_ARGS)
349339
if (!silent)
350340
ereport(ERROR,
351341
(errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
352-
errmsg(ERRMSG_SINGLETON_JSON_ITEM_REQUIRED),
353-
errdetail("expression should return a singleton boolean")));
342+
errmsg("single boolean result is expected")));
354343

355344
PG_RETURN_NULL();
356345
}
@@ -498,8 +487,8 @@ executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors,
498487
{
499488
ereport(ERROR,
500489
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
501-
errmsg("jsonb containing jsonpath variables "
502-
"is not an object")));
490+
errmsg("\"vars\" argument is not an object"),
491+
errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.")));
503492
}
504493

505494
cxt.vars = vars;
@@ -608,24 +597,16 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
608597
}
609598
else if (!jspIgnoreStructuralErrors(cxt))
610599
{
611-
StringInfoData keybuf;
612-
char *keystr;
613-
614600
Assert(found);
615601

616602
if (!jspThrowErrors(cxt))
617603
return jperError;
618604

619-
initStringInfo(&keybuf);
620-
621-
keystr = pnstrdup(key.val.string.val, key.val.string.len);
622-
escape_json(&keybuf, keystr);
623-
624605
ereport(ERROR,
625606
(errcode(ERRCODE_JSON_MEMBER_NOT_FOUND), \
626-
errmsg(ERRMSG_JSON_MEMBER_NOT_FOUND),
627-
errdetail("JSON object does not contain key %s",
628-
keybuf.data)));
607+
errmsg("JSON object does not contain key \"%s\"",
608+
pnstrdup(key.val.string.val,
609+
key.val.string.len))));
629610
}
630611
}
631612
else if (unwrap && JsonbType(jb) == jbvArray)
@@ -635,9 +616,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
635616
Assert(found);
636617
RETURN_ERROR(ereport(ERROR,
637618
(errcode(ERRCODE_JSON_MEMBER_NOT_FOUND),
638-
errmsg(ERRMSG_JSON_MEMBER_NOT_FOUND),
639-
errdetail("jsonpath member accessor can "
640-
"only be applied to an object"))));
619+
errmsg("jsonpath member accessor can only be applied to an object"))));
641620
}
642621
break;
643622

@@ -666,9 +645,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
666645
else if (!jspIgnoreStructuralErrors(cxt))
667646
RETURN_ERROR(ereport(ERROR,
668647
(errcode(ERRCODE_JSON_ARRAY_NOT_FOUND),
669-
errmsg(ERRMSG_JSON_ARRAY_NOT_FOUND),
670-
errdetail("jsonpath wildcard array accessor "
671-
"can only be applied to an array"))));
648+
errmsg("jsonpath wildcard array accessor can only be applied to an array"))));
672649
break;
673650

674651
case jpiIndexArray:
@@ -716,9 +693,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
716693
index_to >= size))
717694
RETURN_ERROR(ereport(ERROR,
718695
(errcode(ERRCODE_INVALID_JSON_SUBSCRIPT),
719-
errmsg(ERRMSG_INVALID_JSON_SUBSCRIPT),
720-
errdetail("jsonpath array subscript is "
721-
"out of bounds"))));
696+
errmsg("jsonpath array subscript is out of bounds"))));
722697

723698
if (index_from < 0)
724699
index_from = 0;
@@ -775,9 +750,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
775750
{
776751
RETURN_ERROR(ereport(ERROR,
777752
(errcode(ERRCODE_JSON_ARRAY_NOT_FOUND),
778-
errmsg(ERRMSG_JSON_ARRAY_NOT_FOUND),
779-
errdetail("jsonpath array accessor can "
780-
"only be applied to an array"))));
753+
errmsg("jsonpath array accessor can only be applied to an array"))));
781754
}
782755
break;
783756

@@ -789,8 +762,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
789762
bool hasNext = jspGetNext(jsp, &elem);
790763

791764
if (cxt->innermostArraySize < 0)
792-
elog(ERROR, "evaluating jsonpath LAST outside of "
793-
"array subscript");
765+
elog(ERROR, "evaluating jsonpath LAST outside of array subscript");
794766

795767
if (!hasNext && !found)
796768
{
@@ -832,9 +804,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
832804
Assert(found);
833805
RETURN_ERROR(ereport(ERROR,
834806
(errcode(ERRCODE_JSON_OBJECT_NOT_FOUND),
835-
errmsg(ERRMSG_JSON_OBJECT_NOT_FOUND),
836-
errdetail("jsonpath wildcard member accessor "
837-
"can only be applied to an object"))));
807+
errmsg("jsonpath wildcard member accessor can only be applied to an object"))));
838808
}
839809
break;
840810

@@ -964,10 +934,8 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
964934
if (!jspIgnoreStructuralErrors(cxt))
965935
RETURN_ERROR(ereport(ERROR,
966936
(errcode(ERRCODE_JSON_ARRAY_NOT_FOUND),
967-
errmsg(ERRMSG_JSON_ARRAY_NOT_FOUND),
968-
errdetail("jsonpath item method .%s() "
969-
"can only be applied to an array",
970-
jspOperationName(jsp->type)))));
937+
errmsg("jsonpath item method .%s() can only be applied to an array",
938+
jspOperationName(jsp->type)))));
971939
break;
972940
}
973941

@@ -1020,11 +988,8 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
1020988
if (have_error)
1021989
RETURN_ERROR(ereport(ERROR,
1022990
(errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
1023-
errmsg(ERRMSG_NON_NUMERIC_JSON_ITEM),
1024-
errdetail("jsonpath item method .%s() "
1025-
"can only be applied to "
1026-
"a numeric value",
1027-
jspOperationName(jsp->type)))));
991+
errmsg("jsonpath item method .%s() can only be applied to a numeric value",
992+
jspOperationName(jsp->type)))));
1028993
res = jperOk;
1029994
}
1030995
else if (jb->type == jbvString)
@@ -1044,10 +1009,8 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
10441009
if (have_error || isinf(val))
10451010
RETURN_ERROR(ereport(ERROR,
10461011
(errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
1047-
errmsg(ERRMSG_NON_NUMERIC_JSON_ITEM),
1048-
errdetail("jsonpath item method .%s() can "
1049-
"only be applied to a numeric value",
1050-
jspOperationName(jsp->type)))));
1012+
errmsg("jsonpath item method .%s() can only be applied to a numeric value",
1013+
jspOperationName(jsp->type)))));
10511014

10521015
jb = &jbv;
10531016
jb->type = jbvNumeric;
@@ -1059,11 +1022,8 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
10591022
if (res == jperNotFound)
10601023
RETURN_ERROR(ereport(ERROR,
10611024
(errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
1062-
errmsg(ERRMSG_NON_NUMERIC_JSON_ITEM),
1063-
errdetail("jsonpath item method .%s() "
1064-
"can only be applied to a "
1065-
"string or numeric value",
1066-
jspOperationName(jsp->type)))));
1025+
errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1026+
jspOperationName(jsp->type)))));
10671027

10681028
res = executeNextItem(cxt, jsp, NULL, jb, found, true);
10691029
}
@@ -1546,19 +1506,15 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
15461506
!(lval = getScalar(JsonValueListHead(&lseq), jbvNumeric)))
15471507
RETURN_ERROR(ereport(ERROR,
15481508
(errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
1549-
errmsg(ERRMSG_SINGLETON_JSON_ITEM_REQUIRED),
1550-
errdetail("left operand of binary jsonpath operator %s "
1551-
"is not a singleton numeric value",
1552-
jspOperationName(jsp->type)))));
1509+
errmsg("left operand of jsonpath operator %s is not a single numeric value",
1510+
jspOperationName(jsp->type)))));
15531511

15541512
if (JsonValueListLength(&rseq) != 1 ||
15551513
!(rval = getScalar(JsonValueListHead(&rseq), jbvNumeric)))
15561514
RETURN_ERROR(ereport(ERROR,
15571515
(errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
1558-
errmsg(ERRMSG_SINGLETON_JSON_ITEM_REQUIRED),
1559-
errdetail("right operand of binary jsonpath operator %s "
1560-
"is not a singleton numeric value",
1561-
jspOperationName(jsp->type)))));
1516+
errmsg("right operand of jsonpath operator %s is not a single numeric value",
1517+
jspOperationName(jsp->type)))));
15621518

15631519
if (jspThrowErrors(cxt))
15641520
{
@@ -1625,10 +1581,8 @@ executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
16251581

16261582
RETURN_ERROR(ereport(ERROR,
16271583
(errcode(ERRCODE_JSON_NUMBER_NOT_FOUND),
1628-
errmsg(ERRMSG_JSON_NUMBER_NOT_FOUND),
1629-
errdetail("operand of unary jsonpath operator %s "
1630-
"is not a numeric value",
1631-
jspOperationName(jsp->type)))));
1584+
errmsg("operand of unary jsonpath operator %s is not a numeric value",
1585+
jspOperationName(jsp->type)))));
16321586
}
16331587

16341588
if (func)
@@ -1738,10 +1692,8 @@ executeNumericItemMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
17381692
if (!(jb = getScalar(jb, jbvNumeric)))
17391693
RETURN_ERROR(ereport(ERROR,
17401694
(errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
1741-
errmsg(ERRMSG_NON_NUMERIC_JSON_ITEM),
1742-
errdetail("jsonpath item method .%s() can only "
1743-
"be applied to a numeric value",
1744-
jspOperationName(jsp->type)))));
1695+
errmsg("jsonpath item method .%s() can only be applied to a numeric value",
1696+
jspOperationName(jsp->type)))));
17451697

17461698
datum = DirectFunctionCall1(func, NumericGetDatum(jb->val.numeric));
17471699

@@ -1799,10 +1751,8 @@ executeKeyValueMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
17991751
if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
18001752
RETURN_ERROR(ereport(ERROR,
18011753
(errcode(ERRCODE_JSON_OBJECT_NOT_FOUND),
1802-
errmsg(ERRMSG_JSON_OBJECT_NOT_FOUND),
1803-
errdetail("jsonpath item method .%s() "
1804-
"can only be applied to an object",
1805-
jspOperationName(jsp->type)))));
1754+
errmsg("jsonpath item method .%s() can only be applied to an object",
1755+
jspOperationName(jsp->type)))));
18061756

18071757
jbc = jb->val.binary.data;
18081758

@@ -1984,7 +1934,7 @@ getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable,
19841934
{
19851935
ereport(ERROR,
19861936
(errcode(ERRCODE_UNDEFINED_OBJECT),
1987-
errmsg("cannot find jsonpath variable '%s'",
1937+
errmsg("cannot find jsonpath variable \"%s\"",
19881938
pnstrdup(varName, varNameLength))));
19891939
}
19901940

@@ -2144,9 +2094,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
21442094
!(jbv = getScalar(JsonValueListHead(&found), jbvNumeric)))
21452095
RETURN_ERROR(ereport(ERROR,
21462096
(errcode(ERRCODE_INVALID_JSON_SUBSCRIPT),
2147-
errmsg(ERRMSG_INVALID_JSON_SUBSCRIPT),
2148-
errdetail("jsonpath array subscript is not a "
2149-
"singleton numeric value"))));
2097+
errmsg("jsonpath array subscript is not a single numeric value"))));
21502098

21512099
numeric_index = DirectFunctionCall2(numeric_trunc,
21522100
NumericGetDatum(jbv->val.numeric),
@@ -2158,9 +2106,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
21582106
if (have_error)
21592107
RETURN_ERROR(ereport(ERROR,
21602108
(errcode(ERRCODE_INVALID_JSON_SUBSCRIPT),
2161-
errmsg(ERRMSG_INVALID_JSON_SUBSCRIPT),
2162-
errdetail("jsonpath array subscript is "
2163-
"out of integer range"))));
2109+
errmsg("jsonpath array subscript is out of integer range"))));
21642110

21652111
return jperOk;
21662112
}

src/backend/utils/adt/jsonpath_gram.y

+5-1
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,11 @@ makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern,
511511
cflags |= REG_EXPANDED;
512512
break;
513513
default:
514-
yyerror(NULL, "unrecognized flag of LIKE_REGEX predicate");
514+
ereport(ERROR,
515+
(errcode(ERRCODE_SYNTAX_ERROR),
516+
errmsg("invalid input syntax for type %s", "jsonpath"),
517+
errdetail("unrecognized flag character \"%c\" in LIKE_REGEX predicate",
518+
flags->val[i])));
515519
break;
516520
}
517521
}

src/backend/utils/adt/jsonpath_scan.l

+11-12
Original file line numberDiff line numberDiff line change
@@ -142,21 +142,21 @@ hex_fail \\x{hex_dig}{0,1}
142142

143143
<xnq,xq,xvq,xsq>{hex_char} { parseHexChar(yytext); }
144144

145-
<xnq,xq,xvq,xsq>{unicode}*{unicodefail} { yyerror(NULL, "Unicode sequence is invalid"); }
145+
<xnq,xq,xvq,xsq>{unicode}*{unicodefail} { yyerror(NULL, "invalid unicode sequence"); }
146146

147-
<xnq,xq,xvq,xsq>{hex_fail} { yyerror(NULL, "Hex character sequence is invalid"); }
147+
<xnq,xq,xvq,xsq>{hex_fail} { yyerror(NULL, "invalid hex character sequence"); }
148148

149149
<xnq,xq,xvq,xsq>{unicode}+\\ {
150150
/* throw back the \\, and treat as unicode */
151151
yyless(yyleng - 1);
152152
parseUnicode(yytext, yyleng);
153153
}
154154

155-
<xnq,xq,xvq,xsq>\\. { yyerror(NULL, "Escape sequence is invalid"); }
155+
<xnq,xq,xvq,xsq>\\. { yyerror(NULL, "escape sequence is invalid"); }
156156

157-
<xnq,xq,xvq,xsq>\\ { yyerror(NULL, "Unexpected end after backslash"); }
157+
<xnq,xq,xvq,xsq>\\ { yyerror(NULL, "unexpected end after backslash"); }
158158

159-
<xq,xvq,xsq><<EOF>> { yyerror(NULL, "Unexpected end of quoted string"); }
159+
<xq,xvq,xsq><<EOF>> { yyerror(NULL, "unexpected end of quoted string"); }
160160

161161
<xq>\" {
162162
yylval->str = scanstring;
@@ -186,7 +186,7 @@ hex_fail \\x{hex_dig}{0,1}
186186

187187
<xc>\* { }
188188

189-
<xc><<EOF>> { yyerror(NULL, "Unexpected end of comment"); }
189+
<xc><<EOF>> { yyerror(NULL, "unexpected end of comment"); }
190190

191191
\&\& { return AND_P; }
192192

@@ -261,7 +261,7 @@ hex_fail \\x{hex_dig}{0,1}
261261
return INT_P;
262262
}
263263

264-
({realfail1}|{realfail2}) { yyerror(NULL, "Floating point number is invalid"); }
264+
({realfail1}|{realfail2}) { yyerror(NULL, "invalid floating point number"); }
265265

266266
{any}+ {
267267
addstring(true, yytext, yyleng);
@@ -295,17 +295,16 @@ jsonpath_yyerror(JsonPathParseResult **result, const char *message)
295295
{
296296
ereport(ERROR,
297297
(errcode(ERRCODE_SYNTAX_ERROR),
298-
errmsg("bad jsonpath representation"),
299298
/* translator: %s is typically "syntax error" */
300-
errdetail("%s at end of input", message)));
299+
errmsg("%s at end of jsonpath input", _(message))));
301300
}
302301
else
303302
{
304303
ereport(ERROR,
305304
(errcode(ERRCODE_SYNTAX_ERROR),
306-
errmsg("bad jsonpath representation"),
307305
/* translator: first %s is typically "syntax error" */
308-
errdetail("%s at or near \"%s\"", message, yytext)));
306+
errmsg("%s at or near \"%s\" of jsonpath input",
307+
_(message), yytext)));
309308
}
310309
}
311310

@@ -495,7 +494,7 @@ hexval(char c)
495494
return c - 'a' + 0xA;
496495
if (c >= 'A' && c <= 'F')
497496
return c - 'A' + 0xA;
498-
elog(ERROR, "invalid hexadecimal digit");
497+
jsonpath_yyerror(NULL, "invalid hexadecimal digit");
499498
return 0; /* not reached */
500499
}
501500

0 commit comments

Comments
 (0)