mirror of
https://github.com/isar/rusqlite.git
synced 2025-02-01 09:50:52 +08:00
Add unit test demonstrating a closure-based UDF.
This commit is contained in:
parent
3913e89f94
commit
3baf7b10f8
@ -313,7 +313,7 @@ impl InnerSqliteConnection {
|
|||||||
if let Ok(cstr) = str_to_cstring(&e.message) {
|
if let Ok(cstr) = str_to_cstring(&e.message) {
|
||||||
ffi::sqlite3_result_error(ctx.ctx, cstr.as_ptr(), -1);
|
ffi::sqlite3_result_error(ctx.ctx, cstr.as_ptr(), -1);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -343,6 +343,7 @@ impl InnerSqliteConnection {
|
|||||||
mod test {
|
mod test {
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use libc::c_double;
|
use libc::c_double;
|
||||||
use self::regex::Regex;
|
use self::regex::Regex;
|
||||||
|
|
||||||
@ -365,19 +366,24 @@ mod test {
|
|||||||
assert_eq!(3f64, result.unwrap());
|
assert_eq!(3f64, result.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn regexp(ctx: &Context) -> SqliteResult<bool> {
|
// This implementation of a regexp scalar function uses SQLite's auxilliary data
|
||||||
|
// (https://www.sqlite.org/c3ref/get_auxdata.html) to avoid recompiling the regular
|
||||||
|
// expression multiple times within one query.
|
||||||
|
fn regexp_with_auxilliary(ctx: &Context) -> SqliteResult<bool> {
|
||||||
assert!(ctx.len() == 2, "called with unexpected number of arguments");
|
assert!(ctx.len() == 2, "called with unexpected number of arguments");
|
||||||
|
|
||||||
let saved_re: Option<&Regex> = unsafe { ctx.get_aux(0) };
|
let saved_re: Option<&Regex> = unsafe { ctx.get_aux(0) };
|
||||||
let new_re = match saved_re {
|
let new_re = match saved_re {
|
||||||
None => {
|
None => {
|
||||||
let s = try!(ctx.get::<String>(0));
|
let s = try!(ctx.get::<String>(0));
|
||||||
let r = try!(Regex::new(&s).map_err(|e| SqliteError {
|
let r = try!(Regex::new(&s).map_err(|e| {
|
||||||
code: ffi::SQLITE_ERROR,
|
SqliteError {
|
||||||
message: format!("Invalid regular expression: {}", e),
|
code: ffi::SQLITE_ERROR,
|
||||||
|
message: format!("Invalid regular expression: {}", e),
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
Some(r)
|
Some(r)
|
||||||
},
|
}
|
||||||
Some(_) => None,
|
Some(_) => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -397,7 +403,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn test_function_regexp() {
|
fn test_function_regexp_with_auxilliary() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = SqliteConnection::open_in_memory().unwrap();
|
||||||
db.execute_batch("BEGIN;
|
db.execute_batch("BEGIN;
|
||||||
CREATE TABLE foo (x string);
|
CREATE TABLE foo (x string);
|
||||||
@ -405,7 +411,58 @@ mod test {
|
|||||||
INSERT INTO foo VALUES ('lXsi');
|
INSERT INTO foo VALUES ('lXsi');
|
||||||
INSERT INTO foo VALUES ('lisX');
|
INSERT INTO foo VALUES ('lisX');
|
||||||
END;").unwrap();
|
END;").unwrap();
|
||||||
db.create_scalar_function("regexp", 2, true, regexp).unwrap();
|
db.create_scalar_function("regexp", 2, true, regexp_with_auxilliary).unwrap();
|
||||||
|
|
||||||
|
let result = db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')",
|
||||||
|
&[],
|
||||||
|
|r| r.get::<bool>(0));
|
||||||
|
|
||||||
|
assert_eq!(true, result.unwrap());
|
||||||
|
|
||||||
|
let result = db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1",
|
||||||
|
&[],
|
||||||
|
|r| r.get::<i64>(0));
|
||||||
|
|
||||||
|
assert_eq!(2, result.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
fn test_function_regexp_with_hashmap_cache() {
|
||||||
|
let db = SqliteConnection::open_in_memory().unwrap();
|
||||||
|
db.execute_batch("BEGIN;
|
||||||
|
CREATE TABLE foo (x string);
|
||||||
|
INSERT INTO foo VALUES ('lisa');
|
||||||
|
INSERT INTO foo VALUES ('lXsi');
|
||||||
|
INSERT INTO foo VALUES ('lisX');
|
||||||
|
END;").unwrap();
|
||||||
|
|
||||||
|
// This implementation of a regexp scalar function uses a captured HashMap
|
||||||
|
// to keep cached regular expressions around (even across multiple queries)
|
||||||
|
// until the function is removed.
|
||||||
|
let mut cached_regexes = HashMap::new();
|
||||||
|
db.create_scalar_function("regexp", 2, true, move |ctx| {
|
||||||
|
assert!(ctx.len() == 2, "called with unexpected number of arguments");
|
||||||
|
|
||||||
|
let regex_s = try!(ctx.get::<String>(0));
|
||||||
|
let entry = cached_regexes.entry(regex_s.clone());
|
||||||
|
let regex = {
|
||||||
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
|
match entry {
|
||||||
|
Occupied(occ) => occ.into_mut(),
|
||||||
|
Vacant(vac) => {
|
||||||
|
let r = try!(Regex::new(®ex_s).map_err(|e| SqliteError {
|
||||||
|
code: ffi::SQLITE_ERROR,
|
||||||
|
message: format!("Invalid regular expression: {}", e),
|
||||||
|
}));
|
||||||
|
vac.insert(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = try!(ctx.get::<String>(1));
|
||||||
|
Ok(regex.is_match(&text))
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
let result = db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')",
|
let result = db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')",
|
||||||
&[],
|
&[],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user