Skip to content

Commit 0c92718

Browse files
authored
Merge pull request #9147 from hantmac/fix/parse-json-path
fix: support SQL-style double-quoted identifier in get_path()
2 parents dceb7ce + b51c38f commit 0c92718

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

src/common/jsonb/src/functions.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,7 @@ pub fn parse_json_path(path: &[u8]) -> Result<Vec<JsonPath>, Error> {
816816
}
817817
let s = std::str::from_utf8(&path[prev_idx..idx - 2])?;
818818
let json_path = JsonPath::String(Cow::Borrowed(s));
819+
819820
json_paths.push(json_path);
820821
} else {
821822
prev_idx = idx - 1;
@@ -836,6 +837,34 @@ pub fn parse_json_path(path: &[u8]) -> Result<Vec<JsonPath>, Error> {
836837
return Err(Error::InvalidToken);
837838
}
838839
}
840+
} else if c == b'"' {
841+
prev_idx = idx;
842+
loop {
843+
let c = read_char(path, &mut idx)?;
844+
if c == b'\\' {
845+
idx += 1;
846+
let c = read_char(path, &mut idx)?;
847+
if c == b'"' {
848+
idx += 1;
849+
}
850+
} else if c != b'"' {
851+
idx += 1;
852+
} else {
853+
// Try to read to check if has extra strings, string value can only have one.
854+
let c = read_char(path, &mut idx);
855+
match c {
856+
Ok(_) => return Err(Error::InvalidToken),
857+
Err(_) => break,
858+
}
859+
}
860+
}
861+
let s = std::str::from_utf8(&path[prev_idx..idx - 1])?;
862+
let json_path = JsonPath::String(Cow::Borrowed(s));
863+
if json_paths.is_empty() {
864+
json_paths.push(json_path);
865+
} else {
866+
return Err(Error::InvalidToken);
867+
}
839868
} else {
840869
if c == b':' || c == b'.' {
841870
if idx == 1 {

src/common/jsonb/tests/it/functions.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use common_jsonb::object_keys;
3232
use common_jsonb::parse_json_path;
3333
use common_jsonb::parse_value;
3434
use common_jsonb::to_string;
35+
use common_jsonb::Error;
3536
use common_jsonb::JsonPath;
3637
use common_jsonb::Number;
3738
use common_jsonb::Object;
@@ -361,6 +362,8 @@ fn test_parse_json_path() {
361362
JsonPath::String(Cow::from("k2")),
362363
JsonPath::String(Cow::from("k3")),
363364
]),
365+
("\"k1\"", vec![JsonPath::String(Cow::from("k1"))]),
366+
("\"k1k2\"", vec![JsonPath::String(Cow::from("k1k2"))]),
364367
(r#"k1["k2"][1]"#, vec![
365368
JsonPath::String(Cow::from("k1")),
366369
JsonPath::String(Cow::from("k2")),
@@ -372,6 +375,18 @@ fn test_parse_json_path() {
372375
let path = parse_json_path(s.as_bytes()).unwrap();
373376
assert_eq!(&path[..], &expect[..]);
374377
}
378+
379+
let wrong_sources = vec![
380+
(r#"\"\"\\k1\"\""#, Error::InvalidToken),
381+
(r#"\\k1\\'"#, Error::InvalidToken),
382+
];
383+
for (s, expect) in wrong_sources {
384+
let path = parse_json_path(s.as_bytes());
385+
match path {
386+
Ok(_) => println!(),
387+
Err(_) => assert_eq!(Error::InvalidToken, expect),
388+
}
389+
}
375390
}
376391

377392
#[test]

0 commit comments

Comments
 (0)