mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-09 18:24:20 +01:00
Add VBegin, VRename, VRollback and VCommit opcodes
This commit is contained in:
@@ -1407,6 +1407,73 @@ pub fn op_vdestroy(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_vbegin(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Arc<Pager>,
|
||||
mv_store: Option<&Arc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
load_insn!(VBegin { cursor_id }, insn);
|
||||
let cursor = state.get_cursor(*cursor_id);
|
||||
let cursor = cursor.as_virtual_mut();
|
||||
cursor.begin()?;
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_vcommit(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Arc<Pager>,
|
||||
mv_store: Option<&Arc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
load_insn!(VCommit { cursor_id }, insn);
|
||||
let cursor = state.get_cursor(*cursor_id);
|
||||
let cursor = cursor.as_virtual_mut();
|
||||
cursor.commit()?;
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_vrollback(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Arc<Pager>,
|
||||
mv_store: Option<&Arc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
load_insn!(VRollback { cursor_id }, insn);
|
||||
let cursor = state.get_cursor(*cursor_id);
|
||||
let cursor = cursor.as_virtual_mut();
|
||||
cursor.rollback()?;
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_vrename(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Arc<Pager>,
|
||||
mv_store: Option<&Arc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
load_insn!(
|
||||
VRename {
|
||||
cursor_id,
|
||||
new_table_name
|
||||
},
|
||||
insn
|
||||
);
|
||||
let conn = program.connection.clone();
|
||||
let cursor = state.get_cursor(*cursor_id);
|
||||
let cursor = cursor.as_virtual_mut();
|
||||
cursor.rename(&new_table_name)?;
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_open_pseudo(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
|
||||
@@ -488,6 +488,42 @@ pub fn insn_to_row(
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::VBegin{cursor_id} => (
|
||||
"VBegin",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
Value::build_text(""),
|
||||
0,
|
||||
"".into()
|
||||
),
|
||||
Insn::VRollback{cursor_id} => (
|
||||
"VRollback",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
Value::build_text(""),
|
||||
0,
|
||||
"".into(),
|
||||
),
|
||||
Insn::VCommit{cursor_id} => (
|
||||
"VCommit",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
Value::build_text(""),
|
||||
0,
|
||||
"".into(),
|
||||
),
|
||||
Insn::VRename{cursor_id, new_table_name} => (
|
||||
"VCommit",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
Value::build_text(&new_table_name),
|
||||
0,
|
||||
"".into(),
|
||||
),
|
||||
Insn::OpenPseudo {
|
||||
cursor_id,
|
||||
content_reg,
|
||||
|
||||
@@ -412,6 +412,24 @@ pub enum Insn {
|
||||
/// The database within which this virtual table needs to be destroyed (P1).
|
||||
db: usize,
|
||||
},
|
||||
VBegin {
|
||||
/// The database within which this virtual table transaction needs to begin (P1).
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
VRollback {
|
||||
/// The database within which this virtual table transaction needs to rollback (P1).
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
VCommit {
|
||||
/// The database within which this virtual table transaction needs to commit (P1).
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
VRename {
|
||||
/// The database within which this virtual table needs to be renamed (P1).
|
||||
cursor_id: CursorID,
|
||||
/// New name of the virtual table (P2).
|
||||
new_table_name: String,
|
||||
},
|
||||
|
||||
/// Open a cursor for a pseudo-table that contains a single row.
|
||||
OpenPseudo {
|
||||
@@ -1383,6 +1401,10 @@ impl InsnVariants {
|
||||
InsnVariants::SequenceTest => execute::op_sequence_test,
|
||||
InsnVariants::FkCounter => execute::op_fk_counter,
|
||||
InsnVariants::FkIfZero => execute::op_fk_if_zero,
|
||||
InsnVariants::VBegin => execute::op_vbegin,
|
||||
InsnVariants::VCommit => execute::op_vcommit,
|
||||
InsnVariants::VRollback => execute::op_vrollback,
|
||||
InsnVariants::VRename => execute::op_vrename,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
81
core/vtab.rs
81
core/vtab.rs
@@ -225,6 +225,54 @@ impl VirtualTableCursor {
|
||||
VirtualTableCursor::Internal(cursor) => cursor.write().filter(&args, idx_str, idx_num),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn begin(&self) -> crate::Result<()> {
|
||||
match self {
|
||||
VirtualTableCursor::Pragma(_) => Err(LimboError::ExtensionError(
|
||||
"Pragma virtual tables do not support transactions".to_string(),
|
||||
)),
|
||||
VirtualTableCursor::External(cursor) => cursor.begin(),
|
||||
VirtualTableCursor::Internal(_) => Err(LimboError::ExtensionError(
|
||||
"Internal virtual tables currently do not support transactions".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn rollback(&self) -> crate::Result<()> {
|
||||
match self {
|
||||
VirtualTableCursor::Pragma(_) => Err(LimboError::ExtensionError(
|
||||
"Pragma virtual tables do not support transactions".to_string(),
|
||||
)),
|
||||
VirtualTableCursor::External(cursor) => cursor.rollback(),
|
||||
VirtualTableCursor::Internal(_) => Err(LimboError::ExtensionError(
|
||||
"Internal virtual tables currently do not support transactions".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn commit(&self) -> crate::Result<()> {
|
||||
match self {
|
||||
VirtualTableCursor::Pragma(_) => Err(LimboError::ExtensionError(
|
||||
"Pragma virtual tables do not support transactions".to_string(),
|
||||
)),
|
||||
VirtualTableCursor::External(cursor) => cursor.commit(),
|
||||
VirtualTableCursor::Internal(_) => Err(LimboError::ExtensionError(
|
||||
"Internal virtual tables currently do not support transactions".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn rename(&self, new_name: &str) -> crate::Result<()> {
|
||||
match self {
|
||||
VirtualTableCursor::Pragma(_) => Err(LimboError::ExtensionError(
|
||||
"Pragma virtual tables do not support renaming".to_string(),
|
||||
)),
|
||||
VirtualTableCursor::External(cursor) => cursor.rename(new_name),
|
||||
VirtualTableCursor::Internal(_) => Err(LimboError::ExtensionError(
|
||||
"Internal virtual tables currently do not support renaming".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -374,6 +422,39 @@ impl ExtVirtualTableCursor {
|
||||
unsafe { (self.implementation.rowid)(self.cursor.as_ptr()) }
|
||||
}
|
||||
|
||||
fn begin(&self) -> crate::Result<()> {
|
||||
let rc = unsafe { (self.implementation.begin)(self.cursor.as_ptr()) };
|
||||
match rc {
|
||||
ResultCode::OK => Ok(()),
|
||||
_ => Err(LimboError::ExtensionError("Begin failed".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn rollback(&self) -> crate::Result<()> {
|
||||
let rc = unsafe { (self.implementation.rollback)(self.cursor.as_ptr()) };
|
||||
match rc {
|
||||
ResultCode::OK => Ok(()),
|
||||
_ => Err(LimboError::ExtensionError("Rollback failed".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn commit(&self) -> crate::Result<()> {
|
||||
let rc = unsafe { (self.implementation.commit)(self.cursor.as_ptr()) };
|
||||
match rc {
|
||||
ResultCode::OK => Ok(()),
|
||||
_ => Err(LimboError::ExtensionError("Commit failed".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn rename(&self, new_name: &str) -> crate::Result<()> {
|
||||
let c_new_name = std::ffi::CString::new(new_name).unwrap();
|
||||
let rc = unsafe { (self.implementation.rename)(self.cursor.as_ptr(), c_new_name.as_ptr()) };
|
||||
match rc {
|
||||
ResultCode::OK => Ok(()),
|
||||
_ => Err(LimboError::ExtensionError("Rename failed".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
fn filter(
|
||||
&self,
|
||||
|
||||
@@ -28,6 +28,10 @@ pub struct VTabModuleImpl {
|
||||
pub rowid: VtabRowIDFn,
|
||||
pub destroy: VtabFnDestroy,
|
||||
pub best_idx: BestIdxFn,
|
||||
pub begin: VtabBegin,
|
||||
pub commit: VtabCommit,
|
||||
pub rollback: VtabRollback,
|
||||
pub rename: VtabRename,
|
||||
}
|
||||
|
||||
// SAFETY: VTabModuleImpl contains function pointers and a name pointer that are
|
||||
@@ -108,6 +112,12 @@ pub type VtabFnUpdate = unsafe extern "C" fn(
|
||||
|
||||
pub type VtabFnDestroy = unsafe extern "C" fn(table: *const c_void) -> ResultCode;
|
||||
|
||||
pub type VtabBegin = unsafe extern "C" fn(table: *mut c_void) -> ResultCode;
|
||||
pub type VtabCommit = unsafe extern "C" fn(table: *mut c_void) -> ResultCode;
|
||||
pub type VtabRollback = unsafe extern "C" fn(table: *mut c_void) -> ResultCode;
|
||||
pub type VtabRename =
|
||||
unsafe extern "C" fn(table: *mut c_void, new_name: *const c_char) -> ResultCode;
|
||||
|
||||
pub type BestIdxFn = unsafe extern "C" fn(
|
||||
constraints: *const ConstraintInfo,
|
||||
constraint_len: i32,
|
||||
@@ -140,9 +150,21 @@ pub trait VTable {
|
||||
/// 'conn' is an Option to allow for testing. Otherwise a valid connection to the core database
|
||||
/// that created the virtual table will be available to use in your extension here.
|
||||
fn open(&self, _conn: Option<Arc<Connection>>) -> Result<Self::Cursor, Self::Error>;
|
||||
fn begin(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn commit(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn rollback(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn update(&mut self, _rowid: i64, _args: &[Value]) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn rename(&mut self, _new_name: &str) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn insert(&mut self, _args: &[Value]) -> Result<i64, Self::Error> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ pub fn derive_vtab_module(input: TokenStream) -> TokenStream {
|
||||
let rowid_fn_name = format_ident!("rowid_{}", struct_name);
|
||||
let destroy_fn_name = format_ident!("destroy_{}", struct_name);
|
||||
let best_idx_fn_name = format_ident!("best_idx_{}", struct_name);
|
||||
let begin_fn_name = format_ident!("begin_{}", struct_name);
|
||||
let rollback_fn_name = format_ident!("rollback_{}", struct_name);
|
||||
let commit_fn_name = format_ident!("commit_{}", struct_name);
|
||||
let rename_fn_name = format_ident!("rename_{}", struct_name);
|
||||
|
||||
let expanded = quote! {
|
||||
impl #struct_name {
|
||||
@@ -227,6 +231,75 @@ pub fn derive_vtab_module(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn #begin_fn_name(
|
||||
table: *mut ::std::ffi::c_void,
|
||||
) -> ::turso_ext::ResultCode {
|
||||
let table = if table.is_null() {
|
||||
return ::turso_ext::ResultCode::Error;
|
||||
} else {
|
||||
&mut *(table as *mut <#struct_name as ::turso_ext::VTabModule>::Table)
|
||||
};
|
||||
if <#struct_name as ::turso_ext::VTabModule>::Table::begin(table).is_err() {
|
||||
return ::turso_ext::ResultCode::Error;
|
||||
}
|
||||
::turso_ext::ResultCode::OK
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn #rollback_fn_name(
|
||||
table: *mut ::std::ffi::c_void,
|
||||
) -> ::turso_ext::ResultCode {
|
||||
let table = if table.is_null() {
|
||||
return ::turso_ext::ResultCode::Error;
|
||||
} else {
|
||||
&mut *(table as *mut <#struct_name as ::turso_ext::VTabModule>::Table)
|
||||
};
|
||||
if <#struct_name as ::turso_ext::VTabModule>::Table::rollback(table).is_err() {
|
||||
return ::turso_ext::ResultCode::Error;
|
||||
}
|
||||
::turso_ext::ResultCode::OK
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn #commit_fn_name(
|
||||
table: *mut ::std::ffi::c_void,
|
||||
) -> ::turso_ext::ResultCode {
|
||||
let table = if table.is_null() {
|
||||
return ::turso_ext::ResultCode::Error;
|
||||
} else {
|
||||
&mut *(table as *mut <#struct_name as ::turso_ext::VTabModule>::Table)
|
||||
};
|
||||
if <#struct_name as ::turso_ext::VTabModule>::Table::commit(table).is_err() {
|
||||
return ::turso_ext::ResultCode::Error;
|
||||
}
|
||||
::turso_ext::ResultCode::OK
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn #rename_fn_name(
|
||||
table: *mut ::std::ffi::c_void,
|
||||
name: *const ::std::ffi::c_char,
|
||||
) -> ::turso_ext::ResultCode {
|
||||
let table = if table.is_null() {
|
||||
return ::turso_ext::ResultCode::Error;
|
||||
} else {
|
||||
&mut *(table as *mut <#struct_name as ::turso_ext::VTabModule>::Table)
|
||||
};
|
||||
let name_str = if name.is_null() {
|
||||
return ::turso_ext::ResultCode::Error;
|
||||
} else {
|
||||
match ::std::ffi::CStr::from_ptr(name).to_str() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return ::turso_ext::ResultCode::Error,
|
||||
}
|
||||
};
|
||||
if <#struct_name as ::turso_ext::VTabModule>::Table::rename(table, name_str).is_err() {
|
||||
return ::turso_ext::ResultCode::Error;
|
||||
}
|
||||
::turso_ext::ResultCode::OK
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn #register_fn_name(
|
||||
api: *const ::turso_ext::ExtensionApi
|
||||
@@ -251,6 +324,10 @@ pub fn derive_vtab_module(input: TokenStream) -> TokenStream {
|
||||
rowid: Self::#rowid_fn_name,
|
||||
destroy: Self::#destroy_fn_name,
|
||||
best_idx: Self::#best_idx_fn_name,
|
||||
begin: Self::#begin_fn_name,
|
||||
rollback: Self::#rollback_fn_name,
|
||||
commit: Self::#commit_fn_name,
|
||||
rename: Self::#rename_fn_name,
|
||||
};
|
||||
(api.register_vtab_module)(api.ctx, name_c, module, <#struct_name as ::turso_ext::VTabModule>::VTAB_KIND)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user