From c13ad4db322c57e1fb6c040ff2f85e957b9d0e79 Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Tue, 9 Apr 2024 20:31:30 +0900 Subject: [PATCH v1] JSON_TABLE(): mention column name in the ON EMPTY error message --- src/backend/executor/execExprInterp.c | 36 ++++++++++--------- src/backend/parser/parse_expr.c | 1 + src/backend/parser/parse_jsontable.c | 1 + src/include/nodes/parsenodes.h | 2 ++ src/include/nodes/primnodes.h | 3 ++ .../regress/expected/sqljson_jsontable.out | 6 ++-- 6 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 41af28cb1e..0becee67a8 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -4409,28 +4409,32 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op, { 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; + } + } + else if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR) + { + jsestate->error.value = BoolGetDatum(true); - Assert(jsestate->jump_empty >= 0); - return jsestate->jump_empty; + *op->resvalue = (Datum) 0; + *op->resnull = 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 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")); } /* diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 4c98d7a046..34ac17868b 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 99d3101f6b..b3920f0531 100644 --- a/src/backend/parser/parse_jsontable.c +++ b/src/backend/parser/parse_jsontable.c @@ -327,6 +327,7 @@ transformJsonTableColumns(JsonTableParseContext *cxt, List *columns, jfe = transformJsonTableColumn(rawc, (Node *) param, passingArgs); + jfe->column_name = pstrdup(rawc->name); colexpr = transformExpr(pstate, (Node *) jfe, EXPR_KIND_FROM_FUNCTION); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index f763f790b1..c0ff75e643 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1791,6 +1791,8 @@ typedef struct JsonFuncExpr { NodeTag type; JsonExprOp op; /* expression type */ + char *column_name; /* JSON_TABLE() column name or NULL if this is + * not for a JSON_TABLE() */ JsonValueExpr *context_item; /* context item expression */ Node *pathspec; /* JSON path specification expression */ List *passing; /* list of PASSING clause arguments, if any */ diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index dafe93a4c9..9b662b8dd2 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -1782,6 +1782,9 @@ typedef struct JsonExpr JsonExprOp op; + char *column_name; /* JSON_TABLE() column name or NULL if this is + * not for a JSON_TABLE() */ + /* jsonb-valued expression to query */ Node *formatted_expr; diff --git a/src/test/regress/expected/sqljson_jsontable.out b/src/test/regress/expected/sqljson_jsontable.out index a00eec8a6f..849a02d9c0 100644 --- a/src/test/regress/expected/sqljson_jsontable.out +++ b/src/test/regress/expected/sqljson_jsontable.out @@ -492,11 +492,11 @@ FROM ON true; ERROR: invalid input syntax for type integer: "err" SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH '$.a' ERROR ON EMPTY)) jt; -ERROR: no SQL/JSON item +ERROR: no SQL/JSON item found for column "a" SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'strict $.a' ERROR ON ERROR) ERROR ON ERROR) jt; ERROR: jsonpath member accessor can only be applied to an object SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'lax $.a' ERROR ON EMPTY) ERROR ON ERROR) jt; -ERROR: no SQL/JSON item +ERROR: no SQL/JSON item found for column "a" SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH '$' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt; a --- @@ -849,7 +849,7 @@ SELECT sub.* FROM s, xx int path '$.c', NESTED PATH '$.a.za[1]' columns (NESTED PATH '$.z21[*]' COLUMNS (z21 int path '$?(@ >= $"x")' ERROR ON ERROR)) )) sub; -ERROR: no SQL/JSON item +ERROR: no SQL/JSON item found for column "z21" -- Parent columns xx1, xx appear before NESTED ones SELECT sub.* FROM s, (VALUES (23)) x(x), generate_series(13, 13) y, -- 2.43.0