Details
-
Bug
-
Status: Open (View Workflow)
-
Major
-
Resolution: Unresolved
-
10.11, 11.4, 11.8, 12.3, 13.0
-
None
Description
JSON_ARRAY_APPEND and JSON_ARRAY_INSERT are documented to return the
modified document, or NULL if an argument is NULL. Given a path that
does not exist they return NULL with no error, no warning and no note -
and where earlier path/value pairs had already been applied, those edits
are thrown away too.
SELECT JSON_ARRAY_APPEND('{"a": [1]}', '$.zz', 6) AS v; |
v
|
NULL
|
No argument is NULL, the document is valid, the path is well formed, and
nothing is said. The outcome is outside both documented branches.
The five sibling mutators leave the document alone in the same
situation, which is the behaviour a caller would expect:
SELECT JSON_INSERT('{"a":1}', '$.b.c', 3) AS v; -- {"a": 1} |
SELECT JSON_REPLACE('{"a":1}', '$.zz', 3) AS v; -- {"a": 1} |
SELECT JSON_REMOVE('{"a":1}', '$.zz') AS v; -- {"a": 1} |
How to repeat
SELECT JSON_ARRAY_APPEND('{"a": [1]}', '$.zz', 6) AS no_such_member; |
SELECT JSON_ARRAY_APPEND('[1]', '$[5]', 6) AS past_the_end; |
SELECT JSON_ARRAY_APPEND('{"a": [1]}', '$.a[9]', 6) AS past_the_end_within; |
SELECT JSON_ARRAY_INSERT('[1,2,3]', '$', 9) AS root_is_not_a_slot; |
-- all NULL, all silent
|
The multi-pair form is the damaging one. Evaluation is documented to
run left to right with each pair applied to the result of the last, and
a pair that finds nothing discards the lot:
SELECT JSON_ARRAY_APPEND('{"a": [1]}', '$.a', 5) AS first_pair_alone; |
{"a": [1, 5]} |
|
|
SELECT JSON_ARRAY_APPEND('{"a": [1]}', '$.a', 5, '$.zz', 6) AS both_pairs; |
NULL
|
|
|
SELECT JSON_ARRAY_APPEND('{"a": [1]}', '$.zz', 6, '$.a', 5) AS reversed; |
NULL
|
Root cause
`Item_func_json_array_append::val_str()` jumps to a `return_null` label
when the path is not found. That label sets `null_value` and returns
without calling `report_json_error()`, so nothing is raised, and it is
reached after earlier pairs have already been composed into the result
buffer, which is then dropped.
Contract, `scripts/fill_help_tables.sql:430` (topic 356): *"Appends
values to the end of the specified arrays within a JSON document,
returning the result, or NULL if any of the arguments are NULL"* and
*"Evaluation is performed from left to right, with the resulting
document from the previous pair becoming the new value against which the
next pair is evaluated."*
Why it matters
One mistyped path in the last pair of a long call silently throws away
every edit before it, and the statement reports success.
Affected versions
Both functions were added in 10.2.3.
Verified on 10.11 only (10.11.19-MariaDB-debug, commit 1dab253482d).
Other branches were not tested.
Note
Found while auditing the JSON functions against their documented
contracts. Seven recorded results show these functions
returning NULL for a non-NULL argument list, but every one carries a
Warning. Nothing pins the silent path-not-found NULL, and
func_json.result:90-92 pins the silent behaviour as expected for the
scalar-document case.
Attachments
Issue Links
- split from
-
MDEV-40642 Project "JSON Phoenix" (placeholder)
-
- Open
-