mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-26 11:31:37 +08:00
Add support to updatable virtual tables
This commit is contained in:
parent
624c3a2d05
commit
3787f432a4
@ -84,6 +84,43 @@ const ZERO_MODULE: ffi::sqlite3_module = unsafe {
|
|||||||
.module
|
.module
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Create an modifiable virtual table implementation.
|
||||||
|
///
|
||||||
|
/// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
|
||||||
|
#[must_use]
|
||||||
|
pub fn update_module<'vtab, T: UpdateVTab<'vtab>>() -> &'static Module<'vtab, T> {
|
||||||
|
#[allow(clippy::needless_update)]
|
||||||
|
&Module {
|
||||||
|
base: ffi::sqlite3_module {
|
||||||
|
iVersion: 2,
|
||||||
|
xCreate: Some(rust_create::<T>),
|
||||||
|
xConnect: Some(rust_connect::<T>),
|
||||||
|
xBestIndex: Some(rust_best_index::<T>),
|
||||||
|
xDisconnect: Some(rust_disconnect::<T>),
|
||||||
|
xDestroy: Some(rust_destroy::<T>),
|
||||||
|
xOpen: Some(rust_open::<T>),
|
||||||
|
xClose: Some(rust_close::<T::Cursor>),
|
||||||
|
xFilter: Some(rust_filter::<T::Cursor>),
|
||||||
|
xNext: Some(rust_next::<T::Cursor>),
|
||||||
|
xEof: Some(rust_eof::<T::Cursor>),
|
||||||
|
xColumn: Some(rust_column::<T::Cursor>),
|
||||||
|
xRowid: Some(rust_rowid::<T::Cursor>),
|
||||||
|
xUpdate: Some(rust_update::<T>),
|
||||||
|
xBegin: None,
|
||||||
|
xSync: None,
|
||||||
|
xCommit: None,
|
||||||
|
xRollback: None,
|
||||||
|
xFindFunction: None,
|
||||||
|
xRename: None,
|
||||||
|
xSavepoint: None,
|
||||||
|
xRelease: None,
|
||||||
|
xRollbackTo: None,
|
||||||
|
..ZERO_MODULE
|
||||||
|
},
|
||||||
|
phantom: PhantomData::<&'vtab T>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a read-only virtual table implementation.
|
/// Create a read-only virtual table implementation.
|
||||||
///
|
///
|
||||||
/// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
|
/// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
|
||||||
@ -280,6 +317,21 @@ pub trait CreateVTab<'vtab>: VTab<'vtab> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Non-read-only virtual table instance trait.
|
||||||
|
///
|
||||||
|
/// (See [SQLite doc](https://sqlite.org/vtab.html#xupdate))
|
||||||
|
pub trait UpdateVTab<'vtab>: CreateVTab<'vtab> {
|
||||||
|
/// Delete rowid or PK
|
||||||
|
fn delete(&mut self, arg: ValueRef<'_>) -> Result<()>;
|
||||||
|
/// Insert: args[0] == NULL: old rowid or PK, args[1]: new rowid or PK,
|
||||||
|
/// args[2]: ... Return the new rowid.
|
||||||
|
// TODO Make the distinction between argv[1] == NULL and argv[1] != NULL ?
|
||||||
|
fn insert(&mut self, args: &Values<'_>) -> Result<i64>;
|
||||||
|
/// Update: args[0] != NULL: old rowid or PK, args[1]: new row id or PK,
|
||||||
|
/// args[2]: ...
|
||||||
|
fn update(&mut self, args: &Values<'_>) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
/// Index constraint operator.
|
/// Index constraint operator.
|
||||||
/// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details.
|
/// See [Virtual Table Constraint Operator Codes](https://sqlite.org/c3ref/c_index_constraint_eq.html) for details.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -1153,6 +1205,49 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn rust_update<'vtab, T: 'vtab>(
|
||||||
|
vtab: *mut ffi::sqlite3_vtab,
|
||||||
|
argc: c_int,
|
||||||
|
argv: *mut *mut ffi::sqlite3_value,
|
||||||
|
p_rowid: *mut ffi::sqlite3_int64,
|
||||||
|
) -> c_int
|
||||||
|
where
|
||||||
|
T: UpdateVTab<'vtab>,
|
||||||
|
{
|
||||||
|
assert!(argc >= 1);
|
||||||
|
let args = slice::from_raw_parts_mut(argv, argc as usize);
|
||||||
|
let vt = vtab.cast::<T>();
|
||||||
|
let r = if args.len() == 1 {
|
||||||
|
(*vt).delete(ValueRef::from_value(args[0]))
|
||||||
|
} else if ffi::sqlite3_value_type(args[0]) == ffi::SQLITE_NULL {
|
||||||
|
// TODO Make the distinction between argv[1] == NULL and argv[1] != NULL ?
|
||||||
|
let values = Values { args };
|
||||||
|
match (*vt).insert(&values) {
|
||||||
|
Ok(rowid) => {
|
||||||
|
*p_rowid = rowid;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let values = Values { args };
|
||||||
|
(*vt).update(&values)
|
||||||
|
};
|
||||||
|
match r {
|
||||||
|
Ok(_) => ffi::SQLITE_OK,
|
||||||
|
Err(Error::SqliteFailure(err, s)) => {
|
||||||
|
if let Some(err_msg) = s {
|
||||||
|
set_err_msg(vtab, &err_msg);
|
||||||
|
}
|
||||||
|
err.extended_code
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
set_err_msg(vtab, &err.to_string());
|
||||||
|
ffi::SQLITE_ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Virtual table cursors can set an error message by assigning a string to
|
/// Virtual table cursors can set an error message by assigning a string to
|
||||||
/// `zErrMsg`.
|
/// `zErrMsg`.
|
||||||
#[cold]
|
#[cold]
|
||||||
|
Loading…
Reference in New Issue
Block a user