Details
-
Bug
-
Status: Open (View Workflow)
-
Major
-
Resolution: Unresolved
-
10.11, 11.4, 11.8, 12.3, 13.0
-
None
Description
JSON_SEARCH builds the path it returns out of punctuation it writes,
key names it copies from the document, and the index of any array step.
The punctuation is written through the converting append, so in ucs2 a
bracket is the two bytes 005B. The index is not: its decimal digits go
in as single bytes, whatever the character set.
SET NAMES utf8mb4; |
SET @d = CONVERT('[["V"],["V"]]' USING ucs2); |
SELECT HEX(JSON_SEARCH(@d, 'one', CONVERT('V' USING ucs2))) AS h; |
h
|
00220024005B30005D005B30005D0022
|
Reading that across: 0022 is a quote, 0024 a dollar, 005B an opening
bracket - and then 30, one byte, where a ucs2 character is two. Every
character after it is read from the wrong place: what comes back is not
the path, and the closing quote is no longer where the string thinks it
is.
How to repeat
SET NAMES utf8mb4; |
SET @d = CONVERT('[["V"],["V"]]' USING ucs2); |
SELECT HEX(JSON_SEARCH(@d, 'one', CONVERT('V' USING ucs2))) AS with_an_index; |
-- 00220024005B30005D005B30005D0022 <- 30 is one byte
|
|
|
-- a path with no array step comes out correctly
|
SET @o = CONVERT('{"a":"V"}' USING ucs2); |
SELECT HEX(JSON_SEARCH(@o, 'one', CONVERT('V' USING ucs2))) AS keys_only; |
-- 00220024002E00610022 <- every character two bytes
|
|
|
-- an index of two digits puts two raw bytes in
|
SET @d11 = CONVERT(CONCAT('[', REPEAT('"x",', 10), '"V"]') USING ucs2); |
SELECT HEX(JSON_SEARCH(@d11, 'one', CONVERT('V' USING ucs2))) AS two_digits; |
Root cause
`append_json_path()` writes the brackets with `str->append('[')` and
`str->append(']')`, which convert into the character set of the result,
and the number between them with `str->append_ulonglong()`, which writes
decimal digits as bytes. Only the array-index branch is affected; a
path made of member names is composed correctly.
Contract, `scripts/fill_help_tables.sql:462` (topic 388): *"Returns the
path to the given string within a JSON document."*
Note
JSON_VALID() still answers 1 for the returned value, because the
corrupted run happens to lie between the surrounding quotes. So nothing
downstream has any reason to reject it.
Affected versions
JSON_SEARCH was added in 10.2.3 and has written the index this way
throughout.
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. None. No test in the suite writes a JSON_SEARCH
array-index step in a character set of more than one byte.
Attachments
Issue Links
- split from
-
MDEV-40642 Project "JSON Phoenix" (placeholder)
-
- Open
-