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);
{
JsonbValue *jbv = JsonPathValue(item, path, &empty,
!throw_error ? &error : NULL,
- jsestate->args);
+ jsestate->args,
+ jsexpr->column_name);
if (jbv == NULL)
{
/* 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"));
}
/*
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
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)
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,
*/
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;
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)
* *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};
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);
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)
{
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 */
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;
/* SQL/JSON item */
extern bool JsonPathExists(Datum jb, JsonPath *path, bool *error, List *vars);
extern Datum JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper,
- bool *empty, bool *error, List *vars);
+ bool *empty, bool *error, List *vars,
+ const char *column_name);
extern JsonbValue *JsonPathValue(Datum jb, JsonPath *jp, bool *empty,
- bool *error, List *vars);
+ bool *error, List *vars,
+ const char *column_name);
extern PGDLLIMPORT const TableFuncRoutine JsonbTableRoutine;
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 specified path of 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 specified path of column "a"
SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH '$' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
a
---
ERROR: only string constants are supported in JSON_TABLE path specification
LINE 1: SELECT * FROM JSON_TABLE(jsonb '{"a": 123}', '$' || '.' || '...
^
+-- JsonPathQuery() error message mentioning column name
+SELECT * FROM JSON_TABLE('{"a": [{"b": "1"}, {"b": "2"}]}', '$' COLUMNS (b json path '$.a[*].b' ERROR ON ERROR));
+ERROR: JSON path expression for column "b" should return single item without wrapper
+HINT: Use WITH WRAPPER clause to wrap SQL/JSON items into array.
-- JSON_TABLE: nested paths
-- Duplicate path names
SELECT * FROM JSON_TABLE(
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 specified path of column "z21"
-- Parent columns xx1, xx appear before NESTED ones
SELECT sub.* FROM s,
(VALUES (23)) x(x), generate_series(13, 13) y,
(1 row)
SELECT JSON_VALUE(jsonb '[]', '$' ERROR ON ERROR);
-ERROR: JSON path expression in JSON_VALUE should return singleton scalar item
+ERROR: JSON path expression in JSON_VALUE should return single scalar item
SELECT JSON_VALUE(jsonb '{}', '$');
json_value
------------
(1 row)
SELECT JSON_VALUE(jsonb '{}', '$' ERROR ON ERROR);
-ERROR: JSON path expression in JSON_VALUE should return singleton scalar item
+ERROR: JSON path expression in JSON_VALUE should return single scalar item
SELECT JSON_VALUE(jsonb '1', '$.a');
json_value
------------
(1 row)
SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON ERROR);
-ERROR: no SQL/JSON item
+ERROR: no SQL/JSON item found for specified path
SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY ERROR ON ERROR);
-ERROR: no SQL/JSON item
+ERROR: no SQL/JSON item found for specified path
SELECT JSON_VALUE(jsonb '1', 'strict $.a' DEFAULT 2 ON ERROR);
json_value
------------
(1 row)
SELECT JSON_VALUE(jsonb '1', 'lax $.a' ERROR ON EMPTY DEFAULT '3' ON ERROR);
-ERROR: no SQL/JSON item
+ERROR: no SQL/JSON item found for specified path
SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' ERROR ON ERROR);
-ERROR: JSON path expression in JSON_VALUE should return singleton scalar item
+ERROR: JSON path expression in JSON_VALUE should return single scalar item
SELECT JSON_VALUE(jsonb '[1,2]', '$[*]' DEFAULT '0' ON ERROR);
json_value
------------
(1 row)
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY);
-ERROR: no SQL/JSON item
+ERROR: no SQL/JSON item found for specified path
SELECT JSON_QUERY(jsonb '[]', '$[*]' DEFAULT '"empty"' ON EMPTY);
json_query
------------
(1 row)
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY NULL ON ERROR);
-ERROR: no SQL/JSON item
+ERROR: no SQL/JSON item found for specified path
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY ARRAY ON ERROR);
-ERROR: no SQL/JSON item
+ERROR: no SQL/JSON item found for specified path
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY EMPTY OBJECT ON ERROR);
-ERROR: no SQL/JSON item
+ERROR: no SQL/JSON item found for specified path
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY ERROR ON ERROR);
-ERROR: no SQL/JSON item
+ERROR: no SQL/JSON item found for specified path
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON ERROR);
-ERROR: no SQL/JSON item
+ERROR: no SQL/JSON item found for specified path
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' ERROR ON ERROR);
-ERROR: JSON path expression in JSON_QUERY should return singleton item without wrapper
-HINT: Use WITH WRAPPER clause to wrap SQL/JSON item sequence into array.
+ERROR: JSON path expression in JSON_QUERY should return single item without wrapper
+HINT: Use WITH WRAPPER clause to wrap SQL/JSON items into array.
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' DEFAULT '"empty"' ON ERROR);
json_query
------------
(1 row)
SELECT JSON_QUERY(jsonb '{"a": 1}', '$.b' RETURNING sqljsonb_int_not_null ERROR ON ERROR);
-ERROR: no SQL/JSON item
+ERROR: no SQL/JSON item found for specified path
-- Test timestamptz passing and output
SELECT JSON_QUERY(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts);
json_query
-- Should fail (not supported)
SELECT * FROM JSON_TABLE(jsonb '{"a": 123}', '$' || '.' || 'a' COLUMNS (foo int));
+-- JsonPathQuery() error message mentioning column name
+SELECT * FROM JSON_TABLE('{"a": [{"b": "1"}, {"b": "2"}]}', '$' COLUMNS (b json path '$.a[*].b' ERROR ON ERROR));
+
-- JSON_TABLE: nested paths
-- Duplicate path names