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 ffi;
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};
// http://sqlite.org/bindptr.html
@ -64,7 +64,7 @@ impl Module for ArrayModule {
}
fn connect(
_: &mut ffi::sqlite3,
_: &mut VTabConnection,
_aux: Option<&()>,
_args: &[&[u8]],
) -> Result<(String, ArrayTab)> {

View File

@ -11,8 +11,8 @@ use error::error_from_sqlite_code;
use ffi;
use types::Null;
use vtab::{
dequote, escape_double_quote, parse_boolean, Context, IndexInfo, Module, VTab, VTabCursor,
Values,
dequote, escape_double_quote, parse_boolean, Context, IndexInfo, Module, VTab, VTabConnection,
VTabCursor, Values,
};
use {Connection, Error, Result};
@ -86,7 +86,7 @@ impl Module for CSVModule {
}
fn connect(
_: &mut ffi::sqlite3,
_: &mut VTabConnection,
_aux: Option<&()>,
args: &[&[u8]],
) -> 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 }
//
// 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
pub trait Module {
type Aux;
@ -50,7 +72,7 @@ pub trait Module {
/// The `db` parameter is a pointer to the SQLite database connection that is executing
/// the CREATE VIRTUAL TABLE statement.
fn create(
db: &mut ffi::sqlite3,
db: &mut VTabConnection,
aux: Option<&Self::Aux>,
args: &[&[u8]],
) -> 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
/// to an _existing_ virtual table whereas `create` is called to create a new virtual table from scratch.
fn connect(
db: &mut ffi::sqlite3,
db: &mut VTabConnection,
aux: Option<&Self::Aux>,
args: &[&[u8]],
) -> 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
pub fn num_of_order_by(&self) -> 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
pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage {
@ -153,6 +169,7 @@ impl IndexInfo {
}
}
}
pub struct IndexConstraintIter<'a> {
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.
pub trait VTabCursor: Sized {
type Table: VTab;
@ -554,13 +600,14 @@ macro_rules! create_or_connect {
use std::slice;
use vtab::mprintf;
let mut conn = VTabConnection(db);
let aux = aux as *mut $aux;
let args = slice::from_raw_parts(argv, argc as usize);
let vec = args
.iter()
.map(|&cs| CStr::from_ptr(cs).to_bytes()) // FIXME .to_str() -> Result<&str, Utf8Error>
.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)) => {
match ::std::ffi::CString::new(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 ffi;
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};
/// Register the "generate_series" module.
@ -47,7 +47,7 @@ impl Module for Series {
}
fn connect(
_: &mut ffi::sqlite3,
_: &mut VTabConnection,
_aux: Option<&()>,
_args: &[&[u8]],
) -> Result<(String, SeriesTab)> {
@ -155,10 +155,18 @@ impl VTab for SeriesTab {
},
));
info.set_estimated_rows(1000);
if info.num_of_order_by() == 1 {
if info.is_order_by_desc(0) {
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
}
};
if order_by_consumed {
info.set_order_by_consumed(true);
}
} else {