diff options
author | Amit Langote | 2024-04-18 05:33:47 +0000 |
---|---|---|
committer | Amit Langote | 2024-04-18 05:45:48 +0000 |
commit | b4fad46b6bc8a9bf46ff689bcb1bd4edf8f267af (patch) | |
tree | 48accd814bfb6c712699b8f26734fbf06c949b3e /src/backend | |
parent | 40126ac68f2ff96351cd6071350eb2d5cbd50145 (diff) |
SQL/JSON: Improve some error messages
This improves some error messages emitted by SQL/JSON query functions
by mentioning column name when available, such as when they are
invoked as part of evaluating JSON_TABLE() columns. To do so, a new
field column_name is added to both JsonFuncExpr and JsonExpr that is
only populated when creating those nodes for transformed JSON_TABLE()
columns.
While at it, relevant error messages are reworded for clarity.
Reported-by: Jian He <[email protected]>
Suggested-by: Jian He <[email protected]>
Discussion: https://postgr.es/m/CACJufxG_e0QLCgaELrr2ZNz7AxPeGCNKAORe3fHtFCQLsH4J4Q@mail.gmail.com
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/executor/execExprInterp.c | 43 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 1 | ||||
-rw-r--r-- | src/backend/parser/parse_jsontable.c | 10 | ||||
-rw-r--r-- | src/backend/utils/adt/jsonpath_exec.c | 45 |
4 files changed, 62 insertions, 37 deletions
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 41af28cb1eb..852186312c5 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -4312,7 +4312,8 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op, case JSON_QUERY_OP: *op->resvalue = JsonPathQuery(item, path, jsexpr->wrapper, &empty, !throw_error ? &error : NULL, - jsestate->args); + jsestate->args, + jsexpr->column_name); *op->resnull = (DatumGetPointer(*op->resvalue) == NULL); @@ -4337,7 +4338,8 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op, { JsonbValue *jbv = JsonPathValue(item, path, &empty, !throw_error ? &error : NULL, - jsestate->args); + jsestate->args, + jsexpr->column_name); if (jbv == NULL) { @@ -4407,30 +4409,33 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op, /* Handle ON EMPTY. */ if (empty) { + *op->resvalue = (Datum) 0; + *op->resnull = true; if (jsexpr->on_empty) { - if (jsexpr->on_empty->btype == JSON_BEHAVIOR_ERROR) - ereport(ERROR, - errcode(ERRCODE_NO_SQL_JSON_ITEM), - errmsg("no SQL/JSON item")); - else + if (jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR) + { jsestate->empty.value = BoolGetDatum(true); - - Assert(jsestate->jump_empty >= 0); - return jsestate->jump_empty; + Assert(jsestate->jump_empty >= 0); + return jsestate->jump_empty; + } + } + else if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR) + { + jsestate->error.value = BoolGetDatum(true); + Assert(!throw_error && jsestate->jump_error >= 0); + return jsestate->jump_error; } - else if (jsexpr->on_error->btype == JSON_BEHAVIOR_ERROR) + + if (jsexpr->column_name) ereport(ERROR, errcode(ERRCODE_NO_SQL_JSON_ITEM), - errmsg("no SQL/JSON item")); + errmsg("no SQL/JSON item found for specified path of column \"%s\"", + jsexpr->column_name)); else - jsestate->error.value = BoolGetDatum(true); - - *op->resvalue = (Datum) 0; - *op->resnull = true; - - Assert(!throw_error && jsestate->jump_error >= 0); - return jsestate->jump_error; + ereport(ERROR, + errcode(ERRCODE_NO_SQL_JSON_ITEM), + errmsg("no SQL/JSON item found for specified path")); } /* diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 4c98d7a046c..34ac17868b5 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -4311,6 +4311,7 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func) jsexpr = makeNode(JsonExpr); jsexpr->location = func->location; jsexpr->op = func->op; + jsexpr->column_name = func->column_name; /* * jsonpath machinery can only handle jsonb documents, so coerce the input diff --git a/src/backend/parser/parse_jsontable.c b/src/backend/parser/parse_jsontable.c index 99d3101f6b2..37f2cba0ef0 100644 --- a/src/backend/parser/parse_jsontable.c +++ b/src/backend/parser/parse_jsontable.c @@ -402,12 +402,6 @@ transformJsonTableColumn(JsonTableColumn *jtc, Node *contextItemExpr, Node *pathspec; JsonFuncExpr *jfexpr = makeNode(JsonFuncExpr); - /* - * XXX consider inventing JSON_TABLE_VALUE_OP, etc. and pass the column - * name via JsonExpr so that JsonPathValue(), etc. can provide error - * message tailored to JSON_TABLE(), such as by mentioning the column - * names in the message. - */ if (jtc->coltype == JTC_REGULAR) jfexpr->op = JSON_VALUE_OP; else if (jtc->coltype == JTC_EXISTS) @@ -415,6 +409,10 @@ transformJsonTableColumn(JsonTableColumn *jtc, Node *contextItemExpr, else jfexpr->op = JSON_QUERY_OP; + /* Pass the column name so any runtime JsonExpr errors can print it. */ + Assert(jtc->name != NULL); + jfexpr->column_name = pstrdup(jtc->name); + jfexpr->context_item = makeJsonValueExpr((Expr *) contextItemExpr, NULL, makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index 103572ed932..e74dc1b2d42 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -3899,7 +3899,8 @@ JsonPathExists(Datum jb, JsonPath *jp, bool *error, List *vars) */ Datum JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty, - bool *error, List *vars) + bool *error, List *vars, + const char *column_name) { JsonbValue *singleton; bool wrap; @@ -3950,10 +3951,17 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty, return (Datum) 0; } - ereport(ERROR, - (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM), - errmsg("JSON path expression in JSON_QUERY should return singleton item without wrapper"), - errhint("Use WITH WRAPPER clause to wrap SQL/JSON item sequence into array."))); + if (column_name) + ereport(ERROR, + (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM), + errmsg("JSON path expression for column \"%s\" should return single item without wrapper", + column_name), + errhint("Use WITH WRAPPER clause to wrap SQL/JSON items into array."))); + else + ereport(ERROR, + (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM), + errmsg("JSON path expression in JSON_QUERY should return single item without wrapper"), + errhint("Use WITH WRAPPER clause to wrap SQL/JSON items into array."))); } if (singleton) @@ -3970,7 +3978,8 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty, * *error to true. *empty is set to true if no match is found. */ JsonbValue * -JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars) +JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars, + const char *column_name) { JsonbValue *res; JsonValueList found = {0}; @@ -4006,9 +4015,15 @@ JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars) return NULL; } - ereport(ERROR, - (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM), - errmsg("JSON path expression in JSON_VALUE should return singleton scalar item"))); + if (column_name) + ereport(ERROR, + (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM), + errmsg("JSON path expression for column \"%s\" should return single scalar item", + column_name))); + else + ereport(ERROR, + (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM), + errmsg("JSON path expression in JSON_VALUE should return single scalar item"))); } res = JsonValueListHead(&found); @@ -4024,9 +4039,15 @@ JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars) return NULL; } - ereport(ERROR, - (errcode(ERRCODE_SQL_JSON_SCALAR_REQUIRED), - errmsg("JSON path expression in JSON_VALUE should return singleton scalar item"))); + if (column_name) + ereport(ERROR, + (errcode(ERRCODE_SQL_JSON_SCALAR_REQUIRED), + errmsg("JSON path expression for column \"%s\" should return single scalar item", + column_name))); + else + ereport(ERROR, + (errcode(ERRCODE_SQL_JSON_SCALAR_REQUIRED), + errmsg("JSON path expression in JSON_VALUE should return single scalar item"))); } if (res->type == jbvNull) |