rusqlite/src/vtab/series.rs

285 lines
8.4 KiB
Rust
Raw Normal View History

//! generate series virtual table.
//! Port of C [generate series "function"](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/series.c).
2016-08-15 01:53:47 +08:00
use std::default::Default;
2018-07-15 00:47:52 +08:00
use std::os::raw::c_int;
2016-08-15 01:53:47 +08:00
use ffi;
2018-05-14 01:49:11 +08:00
use types::Type;
2018-07-15 00:47:52 +08:00
use vtab::{eponymous_only_module, Context, IndexConstraintOp, IndexInfo, Module, VTab, VTabConnection, VTabCursor, Values};
use {Connection, Result};
2016-08-15 01:53:47 +08:00
/// Register the "generate_series" module.
pub fn load_module(conn: &Connection) -> Result<()> {
let aux: Option<()> = None;
2018-07-15 00:47:52 +08:00
conn.create_module::<SeriesTab>("generate_series", &SERIES_MODULE, aux)
2016-08-15 01:53:47 +08:00
}
2018-07-15 00:47:52 +08:00
lazy_static! {
static ref SERIES_MODULE: Module<SeriesTab> = eponymous_only_module::<SeriesTab>();
}
2016-08-15 01:53:47 +08:00
// Column numbers
// const SERIES_COLUMN_VALUE : c_int = 0;
const SERIES_COLUMN_START: c_int = 1;
const SERIES_COLUMN_STOP: c_int = 2;
const SERIES_COLUMN_STEP: c_int = 3;
2016-08-15 01:53:47 +08:00
bitflags! {
#[repr(C)]
struct QueryPlanFlags: ::std::os::raw::c_int {
2016-08-15 01:53:47 +08:00
// start = $value -- constraint exists
const START = 1;
2016-08-15 01:53:47 +08:00
// stop = $value -- constraint exists
const STOP = 2;
2016-08-15 01:53:47 +08:00
// step = $value -- constraint exists
const STEP = 4;
2016-08-15 01:53:47 +08:00
// output in descending order
const DESC = 8;
2016-08-15 01:53:47 +08:00
// Both start and stop
2018-01-27 17:32:58 +08:00
const BOTH = QueryPlanFlags::START.bits | QueryPlanFlags::STOP.bits;
2016-08-15 01:53:47 +08:00
}
}
/// An instance of the Series virtual table
#[repr(C)]
struct SeriesTab {
/// Base class. Must be first
base: ffi::sqlite3_vtab,
}
impl VTab for SeriesTab {
2018-07-15 00:47:52 +08:00
type Aux = ();
type Cursor = SeriesTabCursor;
2018-07-15 00:47:52 +08:00
fn connect(
_: &mut VTabConnection,
_aux: Option<&()>,
_args: &[&[u8]],
) -> Result<(String, SeriesTab)> {
let vtab = SeriesTab {
base: ffi::sqlite3_vtab::default(),
};
Ok((
"CREATE TABLE x(value,start hidden,stop hidden,step hidden)".to_owned(),
vtab,
))
}
2016-08-15 01:53:47 +08:00
fn best_index(&self, info: &mut IndexInfo) -> Result<()> {
// The query plan bitmask
let mut idx_num: QueryPlanFlags = QueryPlanFlags::empty();
// Index of the start= constraint
let mut start_idx = None;
// Index of the stop= constraint
let mut stop_idx = None;
// Index of the step= constraint
let mut step_idx = None;
for (i, constraint) in info.constraints().enumerate() {
if !constraint.is_usable() {
2016-08-15 01:53:47 +08:00
continue;
}
2018-07-15 00:47:52 +08:00
if constraint.operator() != IndexConstraintOp::SQLITE_INDEX_CONSTRAINT_EQ {
2016-08-15 01:53:47 +08:00
continue;
}
match constraint.column() {
2016-08-15 01:53:47 +08:00
SERIES_COLUMN_START => {
start_idx = Some(i);
2018-01-27 17:32:58 +08:00
idx_num |= QueryPlanFlags::START;
2016-08-15 01:53:47 +08:00
}
SERIES_COLUMN_STOP => {
stop_idx = Some(i);
2018-01-27 17:32:58 +08:00
idx_num |= QueryPlanFlags::STOP;
2016-08-15 01:53:47 +08:00
}
SERIES_COLUMN_STEP => {
step_idx = Some(i);
2018-01-27 17:32:58 +08:00
idx_num |= QueryPlanFlags::STEP;
2016-08-15 01:53:47 +08:00
}
_ => {}
};
}
let mut num_of_arg = 0;
if let Some(start_idx) = start_idx {
num_of_arg += 1;
2016-08-20 18:06:24 +08:00
let mut constraint_usage = info.constraint_usage(start_idx);
constraint_usage.set_argv_index(num_of_arg);
constraint_usage.set_omit(true);
2016-08-15 01:53:47 +08:00
}
if let Some(stop_idx) = stop_idx {
num_of_arg += 1;
2016-08-20 18:06:24 +08:00
let mut constraint_usage = info.constraint_usage(stop_idx);
constraint_usage.set_argv_index(num_of_arg);
constraint_usage.set_omit(true);
2016-08-15 01:53:47 +08:00
}
if let Some(step_idx) = step_idx {
num_of_arg += 1;
2016-08-20 18:06:24 +08:00
let mut constraint_usage = info.constraint_usage(step_idx);
constraint_usage.set_argv_index(num_of_arg);
constraint_usage.set_omit(true);
2016-08-15 01:53:47 +08:00
}
2018-01-27 17:32:58 +08:00
if idx_num.contains(QueryPlanFlags::BOTH) {
2016-08-15 01:53:47 +08:00
// Both start= and stop= boundaries are available.
2018-05-14 01:49:11 +08:00
info.set_estimated_cost(f64::from(
2 - if idx_num.contains(QueryPlanFlags::STEP) {
2018-05-06 23:21:36 +08:00
1
} else {
0
2018-05-14 01:49:11 +08:00
},
));
2016-08-15 01:53:47 +08:00
info.set_estimated_rows(1000);
2018-07-10 00:53:52 +08:00
let order_by_consumed = {
let mut order_bys = info.order_bys();
if let Some(order_by) = order_bys.next() {
if order_by.is_order_by_desc() {
idx_num |= QueryPlanFlags::DESC;
}
true
} else {
false
2016-08-15 01:53:47 +08:00
}
2018-07-10 00:53:52 +08:00
};
if order_by_consumed {
2016-08-15 01:53:47 +08:00
info.set_order_by_consumed(true);
}
} else {
2018-05-14 01:16:12 +08:00
info.set_estimated_cost(2_147_483_647f64);
info.set_estimated_rows(2_147_483_647);
2016-08-15 01:53:47 +08:00
}
info.set_idx_num(idx_num.bits());
Ok(())
}
fn open(&self) -> Result<SeriesTabCursor> {
Ok(SeriesTabCursor::new())
}
}
/// A cursor for the Series virtual table
#[derive(Default)]
#[repr(C)]
struct SeriesTabCursor {
/// Base class. Must be first
base: ffi::sqlite3_vtab_cursor,
/// True to count down rather than up
is_desc: bool,
/// The rowid
row_id: i64,
/// Current value ("value")
value: i64,
/// Mimimum value ("start")
min_value: i64,
/// Maximum value ("stop")
max_value: i64,
/// Increment ("step")
step: i64,
}
impl SeriesTabCursor {
fn new() -> SeriesTabCursor {
2018-06-29 03:07:05 +08:00
SeriesTabCursor::default()
2016-08-15 01:53:47 +08:00
}
}
impl VTabCursor for SeriesTabCursor {
type Table = SeriesTab;
2018-05-06 23:21:36 +08:00
fn filter(&mut self, idx_num: c_int, _idx_str: Option<&str>, args: &Values) -> Result<()> {
2016-08-15 01:53:47 +08:00
let idx_num = QueryPlanFlags::from_bits_truncate(idx_num);
let mut i = 0;
2018-01-27 17:32:58 +08:00
if idx_num.contains(QueryPlanFlags::START) {
2016-08-15 01:53:47 +08:00
self.min_value = try!(args.get(i));
i += 1;
} else {
self.min_value = 0;
}
2018-01-27 17:32:58 +08:00
if idx_num.contains(QueryPlanFlags::STOP) {
2016-08-15 01:53:47 +08:00
self.max_value = try!(args.get(i));
i += 1;
} else {
2018-05-14 01:16:12 +08:00
self.max_value = 0xffff_ffff;
2016-08-15 01:53:47 +08:00
}
2018-01-27 17:32:58 +08:00
if idx_num.contains(QueryPlanFlags::STEP) {
2016-08-15 01:53:47 +08:00
self.step = try!(args.get(i));
if self.step < 1 {
self.step = 1;
}
} else {
self.step = 1;
};
2018-05-14 01:49:11 +08:00
for arg in args.iter() {
if arg.data_type() == Type::Null {
// If any of the constraints have a NULL value, then return no rows.
self.min_value = 1;
self.max_value = 0;
break;
}
}
2018-01-27 17:32:58 +08:00
self.is_desc = idx_num.contains(QueryPlanFlags::DESC);
2016-08-15 01:53:47 +08:00
if self.is_desc {
self.value = self.max_value;
2018-05-14 01:49:11 +08:00
if self.step > 0 {
2016-08-15 01:53:47 +08:00
self.value -= (self.max_value - self.min_value) % self.step;
}
} else {
self.value = self.min_value;
}
2018-05-14 01:49:11 +08:00
self.row_id = 1;
2016-08-15 01:53:47 +08:00
Ok(())
}
fn next(&mut self) -> Result<()> {
if self.is_desc {
self.value -= self.step;
} else {
self.value += self.step;
}
self.row_id += 1;
Ok(())
}
fn eof(&self) -> bool {
if self.is_desc {
self.value < self.min_value
} else {
self.value > self.max_value
}
}
fn column(&self, ctx: &mut Context, i: c_int) -> Result<()> {
2016-08-15 01:53:47 +08:00
let x = match i {
SERIES_COLUMN_START => self.min_value,
SERIES_COLUMN_STOP => self.max_value,
SERIES_COLUMN_STEP => self.step,
_ => self.value,
};
ctx.set_result(&x)
2016-08-15 01:53:47 +08:00
}
fn rowid(&self) -> Result<i64> {
Ok(self.row_id)
}
}
2016-08-15 15:09:38 +08:00
#[cfg(test)]
mod test {
use ffi;
2018-05-06 23:21:36 +08:00
use vtab::series;
use Connection;
2016-08-15 15:09:38 +08:00
#[test]
fn test_series_module() {
let version = unsafe { ffi::sqlite3_libversion_number() };
if version < 3008012 {
return;
}
let db = Connection::open_in_memory().unwrap();
series::load_module(&db).unwrap();
let mut s = db.prepare("SELECT * FROM generate_series(0,20,5)").unwrap();
2018-06-11 01:21:55 +08:00
let series = s.query_map(&[], |row| row.get::<_, i32>(0)).unwrap();
2016-08-15 15:09:38 +08:00
let mut expected = 0;
for value in series {
assert_eq!(expected, value.unwrap());
expected += 5;
}
}
}