mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-22 16:29:20 +08:00
Introduce VTabConnection and OrderBy
This commit is contained in:
parent
ce0c9a6344
commit
ce39b9a3c0
@ -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)> {
|
||||
|
@ -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)> {
|
||||
|
@ -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) => {
|
||||
|
@ -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) {
|
||||
idx_num |= QueryPlanFlags::DESC;
|
||||
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user