handle fields with embedded nuls

This commit is contained in:
Damien Elmes 2020-03-24 14:53:33 +10:00
parent 5c5d1c2af5
commit 289bdde20c
2 changed files with 65 additions and 45 deletions

View file

@ -40,11 +40,16 @@ serde_repr = "0.1.5"
num_enum = "0.4.2"
unicase = "2.6.0"
[target.'cfg(target_vendor="apple")'.dependencies]
rusqlite = { version = "0.21.0", features = ["trace", "functions", "collation"] }
# pinned until rusqlite 0.22 comes out
[target.'cfg(target_vendor="apple")'.dependencies.rusqlite]
git = "https://github.com/ankitects/rusqlite.git"
branch="nulsafe-text"
features = ["trace", "functions", "collation"]
[target.'cfg(not(target_vendor="apple"))'.dependencies]
rusqlite = { version = "0.21.0", features = ["trace", "functions", "collation", "bundled"] }
[target.'cfg(not(target_vendor="apple"))'.dependencies.rusqlite]
git = "https://github.com/ankitects/rusqlite.git"
branch="nulsafe-text"
features = ["trace", "functions", "collation", "bundled"]
[target.'cfg(linux)'.dependencies]
reqwest = { version = "0.10.1", features = ["json", "native-tls-vendored"] }

View file

@ -14,7 +14,7 @@ use crate::{
types::{ObjID, Usn},
};
use regex::Regex;
use rusqlite::{params, Connection, NO_PARAMS};
use rusqlite::{functions::FunctionFlags, params, Connection, NO_PARAMS};
use std::cmp::Ordering;
use std::{
borrow::Cow,
@ -71,27 +71,41 @@ fn open_or_create_collection_db(path: &Path) -> Result<Connection> {
/// to split provided fields and return field at zero-based index.
/// If out of range, returns empty string.
fn add_field_index_function(db: &Connection) -> rusqlite::Result<()> {
db.create_scalar_function("field_at_index", 2, true, |ctx| {
db.create_scalar_function(
"field_at_index",
2,
FunctionFlags::SQLITE_DETERMINISTIC,
|ctx| {
let mut fields = ctx.get_raw(0).as_str()?.split('\x1f');
let idx: u16 = ctx.get(1)?;
Ok(fields.nth(idx as usize).unwrap_or("").to_string())
})
},
)
}
fn add_without_combining_function(db: &Connection) -> rusqlite::Result<()> {
db.create_scalar_function("without_combining", 1, true, |ctx| {
db.create_scalar_function(
"without_combining",
1,
FunctionFlags::SQLITE_DETERMINISTIC,
|ctx| {
let text = ctx.get_raw(0).as_str()?;
Ok(match without_combining(text) {
Cow::Borrowed(_) => None,
Cow::Owned(o) => Some(o),
})
})
},
)
}
/// Adds sql function regexp(regex, string) -> is_match
/// Taken from the rusqlite docs
fn add_regexp_function(db: &Connection) -> rusqlite::Result<()> {
db.create_scalar_function("regexp", 2, true, move |ctx| {
db.create_scalar_function(
"regexp",
2,
FunctionFlags::SQLITE_DETERMINISTIC,
move |ctx| {
assert_eq!(ctx.len(), 2, "called with unexpected number of arguments");
let saved_re: Option<&Regex> = ctx.get_aux(0)?;
@ -122,7 +136,8 @@ fn add_regexp_function(db: &Connection) -> rusqlite::Result<()> {
}
Ok(is_match)
})
},
)
}
/// Fetch schema version from database.