mirror of
https://github.com/isar/rusqlite.git
synced 2025-01-21 01:00:51 +08:00
Make index constraints and values iterable
This commit is contained in:
parent
1d342ef5f3
commit
b11a4b1c73
125
src/vtab/mod.rs
125
src/vtab/mod.rs
@ -4,13 +4,14 @@ use std::borrow::Cow::{self, Borrowed, Owned};
|
|||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use std::slice;
|
||||||
use libc;
|
use libc;
|
||||||
|
|
||||||
use {Connection, Error, Result, InnerConnection, str_to_cstring};
|
use {Connection, Error, Result, InnerConnection, str_to_cstring};
|
||||||
use error::error_from_sqlite_code;
|
use error::error_from_sqlite_code;
|
||||||
use ffi;
|
use ffi;
|
||||||
use functions::ToResult;
|
use functions::ToResult;
|
||||||
use types::FromSql;
|
use types::{FromSql, ValueRef};
|
||||||
|
|
||||||
// let conn: Connection = ...;
|
// let conn: Connection = ...;
|
||||||
// let mod: Module = ...; // VTab builder
|
// let mod: Module = ...; // VTab builder
|
||||||
@ -43,7 +44,8 @@ use types::FromSql;
|
|||||||
/// Virtual table instance trait.
|
/// Virtual table instance trait.
|
||||||
pub trait VTab<C: VTabCursor<Self>>: Sized {
|
pub trait VTab<C: VTabCursor<Self>>: Sized {
|
||||||
/// Create a new instance of a virtual table in response to a CREATE VIRTUAL TABLE statement.
|
/// Create a new instance of a virtual table in response to a CREATE VIRTUAL TABLE statement.
|
||||||
/// The `db` parameter is a pointer to the SQLite database connection that is executing the CREATE VIRTUAL TABLE statement.
|
/// The `db` parameter is a pointer to the SQLite database connection that is executing
|
||||||
|
/// the CREATE VIRTUAL TABLE statement.
|
||||||
fn connect(db: *mut ffi::sqlite3, aux: *mut libc::c_void, args: &[&[u8]]) -> Result<Self>;
|
fn connect(db: *mut ffi::sqlite3, aux: *mut libc::c_void, args: &[&[u8]]) -> Result<Self>;
|
||||||
/// Determine the best way to access the virtual table.
|
/// Determine the best way to access the virtual table.
|
||||||
fn best_index(&self, info: &mut IndexInfo) -> Result<()>;
|
fn best_index(&self, info: &mut IndexInfo) -> Result<()>;
|
||||||
@ -67,36 +69,10 @@ bitflags! {
|
|||||||
pub struct IndexInfo(*mut ffi::sqlite3_index_info);
|
pub struct IndexInfo(*mut ffi::sqlite3_index_info);
|
||||||
|
|
||||||
impl IndexInfo {
|
impl IndexInfo {
|
||||||
/// Number of constraints
|
pub fn constraints(&self) -> IndexConstraintIter {
|
||||||
pub fn num_of_constraint(&self) -> usize {
|
let constraints =
|
||||||
unsafe { (*self.0).nConstraint as usize }
|
unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
|
||||||
}
|
IndexConstraintIter { iter: constraints.iter() }
|
||||||
/// Column constrained. -1 for ROWID
|
|
||||||
pub fn constraint_column(&self, constraint_idx: usize) -> libc::c_int {
|
|
||||||
use std::slice;
|
|
||||||
unsafe {
|
|
||||||
let constraints = slice::from_raw_parts((*self.0).aConstraint,
|
|
||||||
(*self.0).nConstraint as usize);
|
|
||||||
constraints[constraint_idx].iColumn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Constraint operator
|
|
||||||
pub fn constraint_operator(&self, constraint_idx: usize) -> IndexConstraintOp {
|
|
||||||
use std::slice;
|
|
||||||
unsafe {
|
|
||||||
let constraints = slice::from_raw_parts((*self.0).aConstraint,
|
|
||||||
(*self.0).nConstraint as usize);
|
|
||||||
IndexConstraintOp::from_bits_truncate(constraints[constraint_idx].op)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// True if this constraint is usable
|
|
||||||
pub fn is_constraint_usable(&self, constraint_idx: usize) -> bool {
|
|
||||||
use std::slice;
|
|
||||||
unsafe {
|
|
||||||
let constraints = slice::from_raw_parts((*self.0).aConstraint,
|
|
||||||
(*self.0).nConstraint as usize);
|
|
||||||
constraints[constraint_idx].usable != 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of terms in the ORDER BY clause
|
/// Number of terms in the ORDER BY clause
|
||||||
@ -105,7 +81,6 @@ impl IndexInfo {
|
|||||||
}
|
}
|
||||||
/// Column number
|
/// Column number
|
||||||
pub fn order_by_column(&self, order_by_idx: usize) -> libc::c_int {
|
pub fn order_by_column(&self, order_by_idx: usize) -> libc::c_int {
|
||||||
use std::slice;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let order_bys = slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize);
|
let order_bys = slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize);
|
||||||
order_bys[order_by_idx].iColumn
|
order_bys[order_by_idx].iColumn
|
||||||
@ -113,7 +88,6 @@ impl IndexInfo {
|
|||||||
}
|
}
|
||||||
/// True for DESC. False for ASC.
|
/// True for DESC. False for ASC.
|
||||||
pub fn is_order_by_desc(&self, order_by_idx: usize) -> bool {
|
pub fn is_order_by_desc(&self, order_by_idx: usize) -> bool {
|
||||||
use std::slice;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let order_bys = slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize);
|
let order_bys = slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize);
|
||||||
order_bys[order_by_idx].desc != 0
|
order_bys[order_by_idx].desc != 0
|
||||||
@ -122,7 +96,6 @@ impl IndexInfo {
|
|||||||
|
|
||||||
/// if `argv_index` > 0, constraint is part of argv to xFilter
|
/// if `argv_index` > 0, constraint is part of argv to xFilter
|
||||||
pub fn set_argv_index(&mut self, constraint_idx: usize, argv_index: libc::c_int) {
|
pub fn set_argv_index(&mut self, constraint_idx: usize, argv_index: libc::c_int) {
|
||||||
use std::slice;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut constraint_usages = slice::from_raw_parts_mut((*self.0).aConstraintUsage,
|
let mut constraint_usages = slice::from_raw_parts_mut((*self.0).aConstraintUsage,
|
||||||
(*self.0).nConstraint as usize);
|
(*self.0).nConstraint as usize);
|
||||||
@ -131,7 +104,6 @@ impl IndexInfo {
|
|||||||
}
|
}
|
||||||
/// if `omit`, do not code a test for this constraint
|
/// if `omit`, do not code a test for this constraint
|
||||||
pub fn set_omit(&mut self, constraint_idx: usize, omit: bool) {
|
pub fn set_omit(&mut self, constraint_idx: usize, omit: bool) {
|
||||||
use std::slice;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut constraint_usages = slice::from_raw_parts_mut((*self.0).aConstraintUsage,
|
let mut constraint_usages = slice::from_raw_parts_mut((*self.0).aConstraintUsage,
|
||||||
(*self.0).nConstraint as usize);
|
(*self.0).nConstraint as usize);
|
||||||
@ -163,6 +135,38 @@ impl IndexInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub struct IndexConstraintIter<'a> {
|
||||||
|
iter: slice::Iter<'a, ffi::Struct_sqlite3_index_constraint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for IndexConstraintIter<'a> {
|
||||||
|
type Item = IndexConstraint<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<IndexConstraint<'a>> {
|
||||||
|
self.iter.next().map(|raw| IndexConstraint(raw))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.iter.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IndexConstraint<'a>(&'a ffi::Struct_sqlite3_index_constraint);
|
||||||
|
|
||||||
|
impl<'a> IndexConstraint<'a> {
|
||||||
|
/// Column constrained. -1 for ROWID
|
||||||
|
pub fn column(&self) -> libc::c_int {
|
||||||
|
self.0.iColumn
|
||||||
|
}
|
||||||
|
/// Constraint operator
|
||||||
|
pub fn operator(&self) -> IndexConstraintOp {
|
||||||
|
IndexConstraintOp::from_bits_truncate(self.0.op)
|
||||||
|
}
|
||||||
|
/// True if this constraint is usable
|
||||||
|
pub fn is_usable(&self) -> bool {
|
||||||
|
self.0.usable != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Virtual table cursor trait.
|
/// Virtual table cursor trait.
|
||||||
pub trait VTabCursor<V: VTab<Self>>: Sized {
|
pub trait VTabCursor<V: VTab<Self>>: Sized {
|
||||||
@ -172,9 +176,11 @@ pub trait VTabCursor<V: VTab<Self>>: Sized {
|
|||||||
fn filter(&mut self, idx_num: libc::c_int, idx_str: Option<&str>, args: &Values) -> Result<()>;
|
fn filter(&mut self, idx_num: libc::c_int, idx_str: Option<&str>, args: &Values) -> Result<()>;
|
||||||
/// Advance cursor to the next row of a result set initiated by `filter`.
|
/// Advance cursor to the next row of a result set initiated by `filter`.
|
||||||
fn next(&mut self) -> Result<()>;
|
fn next(&mut self) -> Result<()>;
|
||||||
/// Must return `false` if the cursor currently points to a valid row of data, or `true` otherwise.
|
/// Must return `false` if the cursor currently points to a valid row of data,
|
||||||
|
/// or `true` otherwise.
|
||||||
fn eof(&self) -> bool;
|
fn eof(&self) -> bool;
|
||||||
/// Find the value for the `i`-th column of the current row. `i` is zero-based so the first column is numbered 0.
|
/// Find the value for the `i`-th column of the current row.
|
||||||
|
/// `i` is zero-based so the first column is numbered 0.
|
||||||
/// May return its result back to SQLite using one of the specified `ctx`.
|
/// May return its result back to SQLite using one of the specified `ctx`.
|
||||||
fn column(&self, ctx: &mut Context, i: libc::c_int) -> Result<()>;
|
fn column(&self, ctx: &mut Context, i: libc::c_int) -> Result<()>;
|
||||||
/// Return the rowid of row that the cursor is currently pointing at.
|
/// Return the rowid of row that the cursor is currently pointing at.
|
||||||
@ -185,7 +191,7 @@ pub trait VTabCursor<V: VTab<Self>>: Sized {
|
|||||||
pub struct Context(*mut ffi::sqlite3_context);
|
pub struct Context(*mut ffi::sqlite3_context);
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn set_result(&mut self, value: &ToResult) {
|
pub fn set_result<T: ToResult>(&mut self, value: &T) {
|
||||||
unsafe {
|
unsafe {
|
||||||
value.set_result(self.0);
|
value.set_result(self.0);
|
||||||
}
|
}
|
||||||
@ -206,7 +212,6 @@ impl<'a> Values<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
|
pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
|
||||||
use types::ValueRef;
|
|
||||||
let arg = self.args[idx];
|
let arg = self.args[idx];
|
||||||
let value = unsafe { ValueRef::from_value(arg) };
|
let value = unsafe { ValueRef::from_value(arg) };
|
||||||
FromSql::column_result(value).map_err(|err| match err {
|
FromSql::column_result(value).map_err(|err| match err {
|
||||||
@ -214,6 +219,35 @@ impl<'a> Values<'a> {
|
|||||||
_ => err,
|
_ => err,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> ValueIter {
|
||||||
|
ValueIter { iter: self.args.iter() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a Values<'a> {
|
||||||
|
type Item = ValueRef<'a>;
|
||||||
|
type IntoIter = ValueIter<'a>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> ValueIter<'a> {
|
||||||
|
self.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ValueIter<'a> {
|
||||||
|
iter: slice::Iter<'a, *mut ffi::sqlite3_value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for ValueIter<'a> {
|
||||||
|
type Item = ValueRef<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<ValueRef<'a>> {
|
||||||
|
self.iter.next().map(|raw| { unsafe { ValueRef::from_value(*raw) } })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.iter.size_hint()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
@ -297,7 +331,8 @@ macro_rules! init_module {
|
|||||||
static $module_name: ffi::sqlite3_module = ffi::sqlite3_module {
|
static $module_name: ffi::sqlite3_module = ffi::sqlite3_module {
|
||||||
iVersion: 1,
|
iVersion: 1,
|
||||||
xCreate: $create, /* For eponymous-only virtual tables, the xCreate method is NULL */
|
xCreate: $create, /* For eponymous-only virtual tables, the xCreate method is NULL */
|
||||||
xConnect: Some($connect), /* A virtual table is eponymous if its xCreate method is the exact same function as the xConnect method */
|
xConnect: Some($connect), /* A virtual table is eponymous if its xCreate method is
|
||||||
|
the exact same function as the xConnect method */
|
||||||
xBestIndex: Some($best_index),
|
xBestIndex: Some($best_index),
|
||||||
xDisconnect: Some($disconnect),
|
xDisconnect: Some($disconnect),
|
||||||
xDestroy: $destroy,
|
xDestroy: $destroy,
|
||||||
@ -495,8 +530,9 @@ pub unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
|
|||||||
(*vtab).zErrMsg = mprintf(err_msg);
|
(*vtab).zErrMsg = mprintf(err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// To raise an error, the `column` method should use this method to set the error message and return the error code.
|
/// To raise an error, the `column` method should use this method to set the error message
|
||||||
pub unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> libc::c_int {
|
/// and return the error code.
|
||||||
|
unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> libc::c_int {
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => ffi::SQLITE_OK,
|
Ok(_) => ffi::SQLITE_OK,
|
||||||
@ -527,7 +563,8 @@ pub unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Space to hold this error message string must be obtained from an SQLite memory allocation function.
|
// Space to hold this error message string must be obtained
|
||||||
|
// from an SQLite memory allocation function.
|
||||||
pub fn mprintf(err_msg: &str) -> *mut ::libc::c_char {
|
pub fn mprintf(err_msg: &str) -> *mut ::libc::c_char {
|
||||||
let c_format = CString::new("%s").unwrap();
|
let c_format = CString::new("%s").unwrap();
|
||||||
let c_err = CString::new(err_msg).unwrap();
|
let c_err = CString::new(err_msg).unwrap();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//! generate_series virtual table.
|
//! generate series virtual table.
|
||||||
//! Port of C [generate_series "function"](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/series.c).
|
//! Port of C [generate series "function"](http://www.sqlite.org/cgi/src/finfo?name=ext/misc/series.c).
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use libc;
|
use libc;
|
||||||
|
|
||||||
@ -81,14 +81,14 @@ impl VTab<SeriesTabCursor> for SeriesTab {
|
|||||||
let mut stop_idx = None;
|
let mut stop_idx = None;
|
||||||
// Index of the step= constraint
|
// Index of the step= constraint
|
||||||
let mut step_idx = None;
|
let mut step_idx = None;
|
||||||
for i in 0..info.num_of_constraint() {
|
for (i, constraint) in info.constraints().enumerate() {
|
||||||
if !info.is_constraint_usable(i) {
|
if !constraint.is_usable() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if info.constraint_operator(i) != vtab::SQLITE_INDEX_CONSTRAINT_EQ {
|
if constraint.operator() != vtab::SQLITE_INDEX_CONSTRAINT_EQ {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match info.constraint_column(i) {
|
match constraint.column() {
|
||||||
SERIES_COLUMN_START => {
|
SERIES_COLUMN_START => {
|
||||||
start_idx = Some(i);
|
start_idx = Some(i);
|
||||||
idx_num |= START;
|
idx_num |= START;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user