summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorAmit Langote2024-04-18 05:33:47 +0000
committerAmit Langote2024-04-18 05:45:48 +0000
commitb4fad46b6bc8a9bf46ff689bcb1bd4edf8f267af (patch)
tree48accd814bfb6c712699b8f26734fbf06c949b3e /src/backend
parent40126ac68f2ff96351cd6071350eb2d5cbd50145 (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.c43
-rw-r--r--src/backend/parser/parse_expr.c1
-rw-r--r--src/backend/parser/parse_jsontable.c10
-rw-r--r--src/backend/utils/adt/jsonpath_exec.c45
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)