mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39: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 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)> {
|
||||||
|
@ -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)> {
|
||||||
|
@ -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) => {
|
||||||
|
@ -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();
|
||||||
idx_num |= QueryPlanFlags::DESC;
|
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);
|
info.set_order_by_consumed(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user