fix escaping of * in field search

mentioned in
https://github.com/ankitects/anki/pull/769
This commit is contained in:
Damien Elmes 2020-09-27 16:00:21 +10:00
parent d9562a1898
commit 7e872de875

View file

@ -13,6 +13,8 @@ use crate::{
text::{normalize_to_nfc, strip_html_preserving_image_filenames, without_combining},
timestamp::TimestampSecs,
};
use lazy_static::lazy_static;
use regex::Regex;
use std::{borrow::Cow, fmt::Write};
pub(crate) struct SqlWriter<'a> {
@ -391,12 +393,15 @@ impl SqlWriter<'_> {
}
let cmp;
let cmp_trailer;
if is_re {
cmp = "regexp";
cmp_trailer = "";
self.args.push(format!("(?i){}", val));
} else {
cmp = "like";
self.args.push(val.replace('*', "%"));
cmp_trailer = "escape '\\'";
self.args.push(convert_glob_char(val).into())
}
let arg_idx = self.args.len();
@ -404,10 +409,11 @@ impl SqlWriter<'_> {
.iter()
.map(|(ntid, ord)| {
format!(
"(n.mid = {mid} and field_at_index(n.flds, {ord}) {cmp} ?{n})",
"(n.mid = {mid} and field_at_index(n.flds, {ord}) {cmp} ?{n} {cmp_trailer})",
mid = ntid,
ord = ord.unwrap_or_default(),
cmp = cmp,
cmp_trailer = cmp_trailer,
n = arg_idx
)
})
@ -455,6 +461,14 @@ impl SqlWriter<'_> {
}
}
/// Replace * with %, leaving \* alone.
fn convert_glob_char(val: &str) -> Cow<str> {
lazy_static! {
static ref RE: Regex = Regex::new(r"(^|[^\\])\*").unwrap();
}
RE.replace_all(val, "${1}%")
}
/// Convert a string with _, % or * characters into a regex.
/// If string contains no globbing characters, return None.
fn glob_to_re(glob: &str) -> Option<String> {
@ -596,10 +610,10 @@ mod test {
s(ctx, "front:te*st"),
(
concat!(
"(((n.mid = 1581236385344 and field_at_index(n.flds, 0) like ?1) or ",
"(n.mid = 1581236385345 and field_at_index(n.flds, 0) like ?1) or ",
"(n.mid = 1581236385346 and field_at_index(n.flds, 0) like ?1) or ",
"(n.mid = 1581236385347 and field_at_index(n.flds, 0) like ?1)))"
"(((n.mid = 1581236385344 and field_at_index(n.flds, 0) like ?1 escape '\\') or ",
"(n.mid = 1581236385345 and field_at_index(n.flds, 0) like ?1 escape '\\') or ",
"(n.mid = 1581236385346 and field_at_index(n.flds, 0) like ?1 escape '\\') or ",
"(n.mid = 1581236385347 and field_at_index(n.flds, 0) like ?1 escape '\\')))"
)
.into(),
vec!["te%st".into()]
@ -788,4 +802,12 @@ mod test {
RequiredTable::Notes
);
}
#[test]
fn convert_glob() {
assert_eq!(&convert_glob_char("foo*bar"), "foo%bar");
assert_eq!(&convert_glob_char("*bar"), "%bar");
assert_eq!(&convert_glob_char("\n*bar"), "\n%bar");
assert_eq!(&convert_glob_char(r"\*bar"), r"\*bar");
}
}