Introduce VTabConnection and OrderBy

This commit is contained in:
gwenn 2018-07-09 18:53:52 +02:00
parent ce0c9a6344
commit ce39b9a3c0
4 changed files with 82 additions and 27 deletions

View File

@ -7,7 +7,7 @@ use std::rc::Rc;
use error::error_from_sqlite_code; use error::error_from_sqlite_code;
use ffi; use ffi;
use types::{ToSql, ToSqlOutput, Value}; use types::{ToSql, ToSqlOutput, Value};
use vtab::{self, Context, IndexInfo, Module, VTab, VTabCursor, Values}; use vtab::{self, Context, IndexInfo, Module, VTab, VTabConnection, VTabCursor, Values};
use {Connection, Error, Result}; use {Connection, Error, Result};
// http://sqlite.org/bindptr.html // http://sqlite.org/bindptr.html
@ -64,7 +64,7 @@ impl Module for ArrayModule {
} }
fn connect( fn connect(
_: &mut ffi::sqlite3, _: &mut VTabConnection,
_aux: Option<&()>, _aux: Option<&()>,
_args: &[&[u8]], _args: &[&[u8]],
) -> Result<(String, ArrayTab)> { ) -> Result<(String, ArrayTab)> {

View File

@ -11,8 +11,8 @@ use error::error_from_sqlite_code;
use ffi; use ffi;
use types::Null; use types::Null;
use vtab::{ use vtab::{
dequote, escape_double_quote, parse_boolean, Context, IndexInfo, Module, VTab, VTabCursor, dequote, escape_double_quote, parse_boolean, Context, IndexInfo, Module, VTab, VTabConnection,
Values, VTabCursor, Values,
}; };
use {Connection, Error, Result}; use {Connection, Error, Result};
@ -86,7 +86,7 @@ impl Module for CSVModule {
} }
fn connect( fn connect(
_: &mut ffi::sqlite3, _: &mut VTabConnection,
_aux: Option<&()>, _aux: Option<&()>,
args: &[&[u8]], args: &[&[u8]],
) -> Result<(String, CSVTab)> { ) -> Result<(String, CSVTab)> {

View File

@ -39,6 +39,28 @@ use {str_to_cstring, Connection, Error, InnerConnection, Result};
// \-> if not eof { cursor.column or xrowid } else { cursor.xclose } // \-> if not eof { cursor.column or xrowid } else { cursor.xclose }
// //
// db: *mut ffi::sqlite3
// module: *const ffi::sqlite3_module => Module
// aux: *mut c_void => Module::Aux
// ffi::sqlite3_vtab => VTab
// ffi::sqlite3_vtab_cursor => VTabCursor
pub struct VTabConnection(*mut ffi::sqlite3);
impl VTabConnection {
/// Get access to the underlying SQLite database connection handle.
///
/// # Warning
///
/// You should not need to use this function. If you do need to, please [open an issue
/// on the rusqlite repository](https://github.com/jgallagher/rusqlite/issues) and describe
/// your use case. This function is unsafe because it gives you raw access to the SQLite
/// connection, and what you do with it could impact the safety of this `Connection`.
pub unsafe fn handle(&mut self) -> *mut ffi::sqlite3 {
self.0
}
}
/// Module instance trait /// Module instance trait
pub trait Module { pub trait Module {
type Aux; type Aux;
@ -50,7 +72,7 @@ pub trait Module {
/// The `db` parameter is a pointer to the SQLite database connection that is executing /// The `db` parameter is a pointer to the SQLite database connection that is executing
/// the CREATE VIRTUAL TABLE statement. /// the CREATE VIRTUAL TABLE statement.
fn create( fn create(
db: &mut ffi::sqlite3, db: &mut VTabConnection,
aux: Option<&Self::Aux>, aux: Option<&Self::Aux>,
args: &[&[u8]], args: &[&[u8]],
) -> Result<(String, Self::Table)> { ) -> Result<(String, Self::Table)> {
@ -59,7 +81,7 @@ pub trait Module {
/// Similar to `create`. The difference is that `connect` is called to establish a new connection /// Similar to `create`. The difference is that `connect` is called to establish a new connection
/// to an _existing_ virtual table whereas `create` is called to create a new virtual table from scratch. /// to an _existing_ virtual table whereas `create` is called to create a new virtual table from scratch.
fn connect( fn connect(
db: &mut ffi::sqlite3, db: &mut VTabConnection,
aux: Option<&Self::Aux>, aux: Option<&Self::Aux>,
args: &[&[u8]], args: &[&[u8]],
) -> Result<(String, Self::Table)>; ) -> Result<(String, Self::Table)>;
@ -99,24 +121,18 @@ impl IndexInfo {
} }
} }
pub fn order_bys(&self) -> OrderByIter {
let order_bys =
unsafe { slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize) };
OrderByIter {
iter: order_bys.iter(),
}
}
/// Number of terms in the ORDER BY clause /// Number of terms in the ORDER BY clause
pub fn num_of_order_by(&self) -> usize { pub fn num_of_order_by(&self) -> usize {
unsafe { (*self.0).nOrderBy as usize } unsafe { (*self.0).nOrderBy as usize }
} }
/// Column number
pub fn order_by_column(&self, order_by_idx: usize) -> c_int {
unsafe {
let order_bys = slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize);
order_bys[order_by_idx].iColumn
}
}
/// True for DESC. False for ASC.
pub fn is_order_by_desc(&self, order_by_idx: usize) -> bool {
unsafe {
let order_bys = slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize);
order_bys[order_by_idx].desc != 0
}
}
/// if `argv_index` > 0, constraint is part of argv to xFilter /// if `argv_index` > 0, constraint is part of argv to xFilter
pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage { pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage {
@ -153,6 +169,7 @@ impl IndexInfo {
} }
} }
} }
pub struct IndexConstraintIter<'a> { pub struct IndexConstraintIter<'a> {
iter: slice::Iter<'a, ffi::sqlite3_index_constraint>, iter: slice::Iter<'a, ffi::sqlite3_index_constraint>,
} }
@ -199,6 +216,35 @@ impl<'a> IndexConstraintUsage<'a> {
} }
} }
pub struct OrderByIter<'a> {
iter: slice::Iter<'a, ffi::sqlite3_index_info_sqlite3_index_orderby>,
}
impl<'a> Iterator for OrderByIter<'a> {
type Item = OrderBy<'a>;
fn next(&mut self) -> Option<OrderBy<'a>> {
self.iter.next().map(|raw| OrderBy(raw))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
pub struct OrderBy<'a>(&'a ffi::sqlite3_index_info_sqlite3_index_orderby);
impl<'a> OrderBy<'a> {
/// Column number
pub fn column(&self) -> c_int {
self.0.iColumn
}
/// True for DESC. False for ASC.
pub fn is_order_by_desc(&self) -> bool {
self.0.desc != 0
}
}
/// Virtual table cursor trait. /// Virtual table cursor trait.
pub trait VTabCursor: Sized { pub trait VTabCursor: Sized {
type Table: VTab; type Table: VTab;
@ -554,13 +600,14 @@ macro_rules! create_or_connect {
use std::slice; use std::slice;
use vtab::mprintf; use vtab::mprintf;
let mut conn = VTabConnection(db);
let aux = aux as *mut $aux; let aux = aux as *mut $aux;
let args = slice::from_raw_parts(argv, argc as usize); let args = slice::from_raw_parts(argv, argc as usize);
let vec = args let vec = args
.iter() .iter()
.map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error> .map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
.collect::<Vec<_>>(); .collect::<Vec<_>>();
match $module::$module_func(db.as_mut().expect("non null db pointer"), aux.as_ref(), &vec[..]) { match $module::$module_func(&mut conn, aux.as_ref(), &vec[..]) {
Ok((sql, vtab)) => { Ok((sql, vtab)) => {
match ::std::ffi::CString::new(sql) { match ::std::ffi::CString::new(sql) {
Ok(c_sql) => { Ok(c_sql) => {

View File

@ -6,7 +6,7 @@ use std::os::raw::{c_char, c_int, c_void};
use error::error_from_sqlite_code; use error::error_from_sqlite_code;
use ffi; use ffi;
use types::Type; use types::Type;
use vtab::{self, Context, IndexInfo, Module, VTab, VTabCursor, Values}; use vtab::{self, Context, IndexInfo, Module, VTab, VTabConnection, VTabCursor, Values};
use {Connection, Error, Result}; use {Connection, Error, Result};
/// Register the "generate_series" module. /// Register the "generate_series" module.
@ -47,7 +47,7 @@ impl Module for Series {
} }
fn connect( fn connect(
_: &mut ffi::sqlite3, _: &mut VTabConnection,
_aux: Option<&()>, _aux: Option<&()>,
_args: &[&[u8]], _args: &[&[u8]],
) -> Result<(String, SeriesTab)> { ) -> Result<(String, SeriesTab)> {
@ -155,10 +155,18 @@ impl VTab for SeriesTab {
}, },
)); ));
info.set_estimated_rows(1000); info.set_estimated_rows(1000);
if info.num_of_order_by() == 1 { let order_by_consumed = {
if info.is_order_by_desc(0) { 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; idx_num |= QueryPlanFlags::DESC;
} }
true
} else {
false
}
};
if order_by_consumed {
info.set_order_by_consumed(true); info.set_order_by_consumed(true);
} }
} else { } else {