mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-20 16:44:19 +01:00
Merge pull request #1339 from tursodatabase/yeet-async-await-opcodes
refactor: fold Async/Await insns into a single instruction
This commit is contained in:
25
COMPAT.md
25
COMPAT.md
@@ -460,9 +460,7 @@ Modifiers:
|
||||
| HaltIfNull | No | |
|
||||
| IdxDelete | No | |
|
||||
| IdxGE | Yes | |
|
||||
| IdxInsert | No | |
|
||||
| IdxInsertAsync | Yes | |
|
||||
| IdxInsertAwait | Yes | |
|
||||
| IdxInsert | Yes | |
|
||||
| IdxLE | Yes | |
|
||||
| IdxLT | Yes | |
|
||||
| IdxRowid | No | |
|
||||
@@ -474,9 +472,7 @@ Modifiers:
|
||||
| IncrVacuum | No | |
|
||||
| Init | Yes | |
|
||||
| InitCoroutine | Yes | |
|
||||
| Insert | No | |
|
||||
| InsertAsync | Yes | |
|
||||
| InsertAwait | Yes | |
|
||||
| Insert | Yes | |
|
||||
| InsertInt | No | |
|
||||
| Int64 | No | |
|
||||
| Integer | Yes | |
|
||||
@@ -497,9 +493,7 @@ Modifiers:
|
||||
| MustBeInt | Yes | |
|
||||
| Ne | Yes | |
|
||||
| NewRowid | Yes | |
|
||||
| Next | No | |
|
||||
| NextAsync | Yes | |
|
||||
| NextAwait | Yes | |
|
||||
| Next | Yes | |
|
||||
| Noop | Yes | |
|
||||
| Not | Yes | |
|
||||
| NotExists | Yes | |
|
||||
@@ -512,18 +506,13 @@ Modifiers:
|
||||
| OpenEphemeral | No | |
|
||||
| OpenPseudo | Yes | |
|
||||
| OpenRead | Yes | |
|
||||
| OpenReadAsync | Yes | |
|
||||
| OpenWrite | No | |
|
||||
| OpenWriteAsync | Yes | |
|
||||
| OpenWriteAwait | Yes | |
|
||||
| OpenWrite | Yes | |
|
||||
| Or | Yes | |
|
||||
| Pagecount | Partial| no temp databases |
|
||||
| Param | No | |
|
||||
| ParseSchema | No | |
|
||||
| Permutation | No | |
|
||||
| Prev | No | |
|
||||
| PrevAsync | Yes | |
|
||||
| PrevAwait | Yes | |
|
||||
| Prev | Yes | |
|
||||
| Program | No | |
|
||||
| ReadCookie | Partial| no temp databases, only user_version supported |
|
||||
| Real | Yes | |
|
||||
@@ -533,8 +522,6 @@ Modifiers:
|
||||
| ResultRow | Yes | |
|
||||
| Return | Yes | |
|
||||
| Rewind | Yes | |
|
||||
| RewindAsync | Yes | |
|
||||
| RewindAwait | Yes | |
|
||||
| RowData | No | |
|
||||
| RowId | Yes | |
|
||||
| RowKey | No | |
|
||||
@@ -580,7 +567,7 @@ Modifiers:
|
||||
| VDestroy | No | |
|
||||
| VFilter | Yes | |
|
||||
| VNext | Yes | |
|
||||
| VOpen | Yes |VOpenAsync|
|
||||
| VOpen | Yes | |
|
||||
| VRename | No | |
|
||||
| VUpdate | Yes | |
|
||||
| Vacuum | No | |
|
||||
|
||||
@@ -2972,11 +2972,6 @@ impl BTreeCursor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait_for_completion(&mut self) -> Result<()> {
|
||||
// TODO: Wait for pager I/O to complete
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn rowid(&self) -> Result<Option<u64>> {
|
||||
if let Some(mv_cursor) = &self.mv_cursor {
|
||||
let mv_cursor = mv_cursor.borrow();
|
||||
|
||||
@@ -431,8 +431,7 @@ fn emit_delete_insns(
|
||||
conflict_action,
|
||||
});
|
||||
} else {
|
||||
program.emit_insn(Insn::DeleteAsync { cursor_id });
|
||||
program.emit_insn(Insn::DeleteAwait { cursor_id });
|
||||
program.emit_insn(Insn::Delete { cursor_id });
|
||||
}
|
||||
if let Some(limit) = limit {
|
||||
let limit_reg = program.alloc_register();
|
||||
@@ -683,13 +682,12 @@ fn emit_update_insns(
|
||||
count: table_ref.columns().len(),
|
||||
dest_reg: record_reg,
|
||||
});
|
||||
program.emit_insn(Insn::InsertAsync {
|
||||
program.emit_insn(Insn::Insert {
|
||||
cursor: cursor_id,
|
||||
key_reg: beg,
|
||||
record_reg,
|
||||
flag: 0,
|
||||
});
|
||||
program.emit_insn(Insn::InsertAwait { cursor_id });
|
||||
} else if let Some(vtab) = table_ref.virtual_table() {
|
||||
let arg_count = table_ref.columns().len() + 2;
|
||||
program.emit_insn(Insn::VUpdate {
|
||||
|
||||
@@ -96,11 +96,10 @@ pub fn translate_create_index(
|
||||
});
|
||||
|
||||
// open the sqlite schema table for writing and create a new entry for the index
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
root_page: RegisterOrLiteral::Literal(sqlite_table.root_page),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
let sql = create_idx_stmt_to_sql(&tbl_name, &idx_name, unique_if_not_exists, &columns);
|
||||
emit_schema_entry(
|
||||
&mut program,
|
||||
@@ -137,18 +136,14 @@ pub fn translate_create_index(
|
||||
});
|
||||
|
||||
// open the table we are creating the index on for reading
|
||||
program.emit_insn(Insn::OpenReadAsync {
|
||||
program.emit_insn(Insn::OpenRead {
|
||||
cursor_id: table_cursor_id,
|
||||
root_page: tbl.root_page,
|
||||
});
|
||||
program.emit_insn(Insn::OpenReadAwait {});
|
||||
|
||||
program.emit_insn(Insn::RewindAsync {
|
||||
cursor_id: table_cursor_id,
|
||||
});
|
||||
let loop_start_label = program.allocate_label();
|
||||
let loop_end_label = program.allocate_label();
|
||||
program.emit_insn(Insn::RewindAwait {
|
||||
program.emit_insn(Insn::Rewind {
|
||||
cursor_id: table_cursor_id,
|
||||
pc_if_empty: loop_end_label,
|
||||
});
|
||||
@@ -184,10 +179,7 @@ pub fn translate_create_index(
|
||||
record_reg,
|
||||
});
|
||||
|
||||
program.emit_insn(Insn::NextAsync {
|
||||
cursor_id: table_cursor_id,
|
||||
});
|
||||
program.emit_insn(Insn::NextAwait {
|
||||
program.emit_insn(Insn::Next {
|
||||
cursor_id: table_cursor_id,
|
||||
pc_if_next: loop_start_label,
|
||||
});
|
||||
@@ -195,11 +187,10 @@ pub fn translate_create_index(
|
||||
|
||||
// Open the index btree we created for writing to insert the
|
||||
// newly sorted index records.
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id: btree_cursor_id,
|
||||
root_page: RegisterOrLiteral::Register(root_page_reg),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
|
||||
let sorted_loop_start = program.allocate_label();
|
||||
let sorted_loop_end = program.allocate_label();
|
||||
@@ -222,16 +213,13 @@ pub fn translate_create_index(
|
||||
cursor_id: btree_cursor_id,
|
||||
});
|
||||
// insert new index record
|
||||
program.emit_insn(Insn::IdxInsertAsync {
|
||||
program.emit_insn(Insn::IdxInsert {
|
||||
cursor_id: btree_cursor_id,
|
||||
record_reg: sorted_record_reg,
|
||||
unpacked_start: None, // TODO: optimize with these to avoid decoding record twice
|
||||
unpacked_count: None,
|
||||
flags: IdxInsertFlags::new().use_seek(false),
|
||||
});
|
||||
program.emit_insn(Insn::IdxInsertAwait {
|
||||
cursor_id: btree_cursor_id,
|
||||
});
|
||||
program.emit_insn(Insn::SorterNext {
|
||||
cursor_id: sorter_cursor_id,
|
||||
pc_if_next: sorted_loop_start,
|
||||
|
||||
@@ -168,11 +168,10 @@ pub fn translate_insert(
|
||||
program.emit_insn(Insn::EndCoroutine { yield_reg });
|
||||
program.resolve_label(jump_on_definition_label, program.offset());
|
||||
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page: RegisterOrLiteral::Literal(root_page),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
|
||||
// Main loop
|
||||
// FIXME: rollback is not implemented. E.g. if you insert 2 rows and one fails to unique constraint violation,
|
||||
@@ -184,11 +183,10 @@ pub fn translate_insert(
|
||||
});
|
||||
} else {
|
||||
// Single row - populate registers directly
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page: RegisterOrLiteral::Literal(root_page),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
|
||||
populate_column_registers(
|
||||
&mut program,
|
||||
@@ -202,11 +200,10 @@ pub fn translate_insert(
|
||||
}
|
||||
// Open all the index btrees for writing
|
||||
for idx_cursor in idx_cursors.iter() {
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id: idx_cursor.2,
|
||||
root_page: idx_cursor.1.into(),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
}
|
||||
// Common record insertion logic for both single and multiple rows
|
||||
let check_rowid_is_integer_label = rowid_alias_reg.and(Some(program.allocate_label()));
|
||||
@@ -293,13 +290,12 @@ pub fn translate_insert(
|
||||
dest_reg: record_register,
|
||||
});
|
||||
|
||||
program.emit_insn(Insn::InsertAsync {
|
||||
program.emit_insn(Insn::Insert {
|
||||
cursor: cursor_id,
|
||||
key_reg: rowid_reg,
|
||||
record_reg: record_register,
|
||||
flag: 0,
|
||||
});
|
||||
program.emit_insn(Insn::InsertAwait { cursor_id });
|
||||
for index_col_mapping in index_col_mappings.iter() {
|
||||
// find which cursor we opened earlier for this index
|
||||
let idx_cursor_id = idx_cursors
|
||||
@@ -337,7 +333,7 @@ pub fn translate_insert(
|
||||
});
|
||||
|
||||
// now do the actual index insertion using the unpacked registers
|
||||
program.emit_insn(Insn::IdxInsertAsync {
|
||||
program.emit_insn(Insn::IdxInsert {
|
||||
cursor_id: idx_cursor_id,
|
||||
record_reg,
|
||||
unpacked_start: Some(idx_start_reg), // TODO: enable optimization
|
||||
@@ -345,9 +341,6 @@ pub fn translate_insert(
|
||||
// TODO: figure out how to determine whether or not we need to seek prior to insert.
|
||||
flags: IdxInsertFlags::new(),
|
||||
});
|
||||
program.emit_insn(Insn::IdxInsertAwait {
|
||||
cursor_id: idx_cursor_id,
|
||||
});
|
||||
}
|
||||
if inserting_multiple_rows {
|
||||
// For multiple rows, loop back
|
||||
|
||||
@@ -39,7 +39,7 @@ pub struct LeftJoinMetadata {
|
||||
pub struct LoopLabels {
|
||||
/// jump to the start of the loop body
|
||||
pub loop_start: BranchOffset,
|
||||
/// jump to the NextAsync instruction (or equivalent)
|
||||
/// jump to the Next instruction (or equivalent)
|
||||
pub next: BranchOffset,
|
||||
/// jump to the end of the loop, exiting it
|
||||
pub loop_end: BranchOffset,
|
||||
@@ -96,44 +96,39 @@ pub fn init_loop(
|
||||
match (mode, &table.table) {
|
||||
(OperationMode::SELECT, Table::BTree(btree)) => {
|
||||
let root_page = btree.root_page;
|
||||
program.emit_insn(Insn::OpenReadAsync {
|
||||
program.emit_insn(Insn::OpenRead {
|
||||
cursor_id,
|
||||
root_page,
|
||||
});
|
||||
program.emit_insn(Insn::OpenReadAwait {});
|
||||
if let Some(index_cursor_id) = index_cursor_id {
|
||||
program.emit_insn(Insn::OpenReadAsync {
|
||||
program.emit_insn(Insn::OpenRead {
|
||||
cursor_id: index_cursor_id,
|
||||
root_page: index.as_ref().unwrap().root_page,
|
||||
});
|
||||
program.emit_insn(Insn::OpenReadAwait {});
|
||||
}
|
||||
}
|
||||
(OperationMode::DELETE, Table::BTree(btree)) => {
|
||||
let root_page = btree.root_page;
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page: root_page.into(),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
}
|
||||
(OperationMode::UPDATE, Table::BTree(btree)) => {
|
||||
let root_page = btree.root_page;
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page: root_page.into(),
|
||||
});
|
||||
if let Some(index_cursor_id) = index_cursor_id {
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id: index_cursor_id,
|
||||
root_page: index.as_ref().unwrap().root_page.into(),
|
||||
});
|
||||
}
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
}
|
||||
(_, Table::Virtual(_)) => {
|
||||
program.emit_insn(Insn::VOpenAsync { cursor_id });
|
||||
program.emit_insn(Insn::VOpenAwait {});
|
||||
program.emit_insn(Insn::VOpen { cursor_id });
|
||||
}
|
||||
_ => {
|
||||
unimplemented!()
|
||||
@@ -148,18 +143,16 @@ pub fn init_loop(
|
||||
|
||||
match mode {
|
||||
OperationMode::SELECT => {
|
||||
program.emit_insn(Insn::OpenReadAsync {
|
||||
program.emit_insn(Insn::OpenRead {
|
||||
cursor_id: table_cursor_id,
|
||||
root_page: table.table.get_root_page(),
|
||||
});
|
||||
program.emit_insn(Insn::OpenReadAwait {});
|
||||
}
|
||||
OperationMode::DELETE | OperationMode::UPDATE => {
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id: table_cursor_id,
|
||||
root_page: table.table.get_root_page().into(),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
}
|
||||
_ => {
|
||||
unimplemented!()
|
||||
@@ -177,18 +170,16 @@ pub fn init_loop(
|
||||
|
||||
match mode {
|
||||
OperationMode::SELECT => {
|
||||
program.emit_insn(Insn::OpenReadAsync {
|
||||
program.emit_insn(Insn::OpenRead {
|
||||
cursor_id: index_cursor_id,
|
||||
root_page: index.root_page,
|
||||
});
|
||||
program.emit_insn(Insn::OpenReadAwait);
|
||||
}
|
||||
OperationMode::UPDATE | OperationMode::DELETE => {
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id: index_cursor_id,
|
||||
root_page: index.root_page.into(),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
}
|
||||
_ => {
|
||||
unimplemented!()
|
||||
@@ -204,7 +195,7 @@ pub fn init_loop(
|
||||
}
|
||||
|
||||
/// Set up the main query execution loop
|
||||
/// For example in the case of a nested table scan, this means emitting the RewindAsync instruction
|
||||
/// For example in the case of a nested table scan, this means emitting the Rewind instruction
|
||||
/// for all tables involved, outermost first.
|
||||
pub fn open_loop(
|
||||
program: &mut ProgramBuilder,
|
||||
@@ -289,51 +280,36 @@ pub fn open_loop(
|
||||
let iteration_cursor_id = index_cursor_id.unwrap_or(cursor_id);
|
||||
if !matches!(&table.table, Table::Virtual(_)) {
|
||||
if *iter_dir == IterationDirection::Backwards {
|
||||
program.emit_insn(Insn::LastAsync {
|
||||
program.emit_insn(Insn::Last {
|
||||
cursor_id: iteration_cursor_id,
|
||||
pc_if_empty: loop_end,
|
||||
});
|
||||
} else {
|
||||
program.emit_insn(Insn::RewindAsync {
|
||||
program.emit_insn(Insn::Rewind {
|
||||
cursor_id: iteration_cursor_id,
|
||||
pc_if_empty: loop_end,
|
||||
});
|
||||
}
|
||||
}
|
||||
match &table.table {
|
||||
Table::BTree(_) => {
|
||||
program.emit_insn(if *iter_dir == IterationDirection::Backwards {
|
||||
Insn::LastAwait {
|
||||
cursor_id: iteration_cursor_id,
|
||||
pc_if_empty: loop_end,
|
||||
}
|
||||
} else {
|
||||
Insn::RewindAwait {
|
||||
cursor_id: iteration_cursor_id,
|
||||
pc_if_empty: loop_end,
|
||||
}
|
||||
})
|
||||
if let Table::Virtual(ref table) = table.table {
|
||||
let start_reg =
|
||||
program.alloc_registers(table.args.as_ref().map(|a| a.len()).unwrap_or(0));
|
||||
let mut cur_reg = start_reg;
|
||||
let args = match table.args.as_ref() {
|
||||
Some(args) => args,
|
||||
None => &vec![],
|
||||
};
|
||||
for arg in args {
|
||||
let reg = cur_reg;
|
||||
cur_reg += 1;
|
||||
let _ = translate_expr(program, Some(tables), arg, reg, &t_ctx.resolver)?;
|
||||
}
|
||||
Table::Virtual(ref table) => {
|
||||
let start_reg = program
|
||||
.alloc_registers(table.args.as_ref().map(|a| a.len()).unwrap_or(0));
|
||||
let mut cur_reg = start_reg;
|
||||
let args = match table.args.as_ref() {
|
||||
Some(args) => args,
|
||||
None => &vec![],
|
||||
};
|
||||
for arg in args {
|
||||
let reg = cur_reg;
|
||||
cur_reg += 1;
|
||||
let _ =
|
||||
translate_expr(program, Some(tables), arg, reg, &t_ctx.resolver)?;
|
||||
}
|
||||
program.emit_insn(Insn::VFilter {
|
||||
cursor_id,
|
||||
pc_if_empty: loop_end,
|
||||
arg_count: table.args.as_ref().map_or(0, |args| args.len()),
|
||||
args_reg: start_reg,
|
||||
});
|
||||
}
|
||||
other => panic!("Unsupported table reference type: {:?}", other),
|
||||
program.emit_insn(Insn::VFilter {
|
||||
cursor_id,
|
||||
pc_if_empty: loop_end,
|
||||
arg_count: table.args.as_ref().map_or(0, |args| args.len()),
|
||||
args_reg: start_reg,
|
||||
});
|
||||
}
|
||||
program.resolve_label(loop_start, program.offset());
|
||||
|
||||
@@ -702,7 +678,7 @@ fn emit_loop_source(
|
||||
}
|
||||
|
||||
/// Closes the loop for a given source operator.
|
||||
/// For example in the case of a nested table scan, this means emitting the NextAsync instruction
|
||||
/// For example in the case of a nested table scan, this means emitting the Next instruction
|
||||
/// for all tables involved, innermost first.
|
||||
pub fn close_loop(
|
||||
program: &mut ProgramBuilder,
|
||||
@@ -727,7 +703,7 @@ pub fn close_loop(
|
||||
match &table.op {
|
||||
Operation::Subquery { .. } => {
|
||||
program.resolve_label(loop_labels.next, program.offset());
|
||||
// A subquery has no cursor to call NextAsync on, so it just emits a Goto
|
||||
// A subquery has no cursor to call Next on, so it just emits a Goto
|
||||
// to the Yield instruction, which in turn jumps back to the main loop of the subquery,
|
||||
// so that the next row from the subquery can be read.
|
||||
program.emit_insn(Insn::Goto {
|
||||
@@ -745,21 +721,12 @@ pub fn close_loop(
|
||||
match &table.table {
|
||||
Table::BTree(_) => {
|
||||
if *iter_dir == IterationDirection::Backwards {
|
||||
program.emit_insn(Insn::PrevAsync {
|
||||
program.emit_insn(Insn::Prev {
|
||||
cursor_id: iteration_cursor_id,
|
||||
pc_if_prev: loop_labels.loop_start,
|
||||
});
|
||||
} else {
|
||||
program.emit_insn(Insn::NextAsync {
|
||||
cursor_id: iteration_cursor_id,
|
||||
});
|
||||
}
|
||||
if *iter_dir == IterationDirection::Backwards {
|
||||
program.emit_insn(Insn::PrevAwait {
|
||||
cursor_id: iteration_cursor_id,
|
||||
pc_if_next: loop_labels.loop_start,
|
||||
});
|
||||
} else {
|
||||
program.emit_insn(Insn::NextAwait {
|
||||
program.emit_insn(Insn::Next {
|
||||
cursor_id: iteration_cursor_id,
|
||||
pc_if_next: loop_labels.loop_start,
|
||||
});
|
||||
@@ -776,7 +743,7 @@ pub fn close_loop(
|
||||
}
|
||||
Operation::Search(search) => {
|
||||
program.resolve_label(loop_labels.next, program.offset());
|
||||
// Rowid equality point lookups are handled with a SeekRowid instruction which does not loop, so there is no need to emit a NextAsync instruction.
|
||||
// Rowid equality point lookups are handled with a SeekRowid instruction which does not loop, so there is no need to emit a Next instruction.
|
||||
if !matches!(search, Search::RowidEq { .. }) {
|
||||
let (cursor_id, iter_dir) = match search {
|
||||
Search::Seek {
|
||||
@@ -796,14 +763,12 @@ pub fn close_loop(
|
||||
};
|
||||
|
||||
if iter_dir == IterationDirection::Backwards {
|
||||
program.emit_insn(Insn::PrevAsync { cursor_id });
|
||||
program.emit_insn(Insn::PrevAwait {
|
||||
program.emit_insn(Insn::Prev {
|
||||
cursor_id,
|
||||
pc_if_next: loop_labels.loop_start,
|
||||
pc_if_prev: loop_labels.loop_start,
|
||||
});
|
||||
} else {
|
||||
program.emit_insn(Insn::NextAsync { cursor_id });
|
||||
program.emit_insn(Insn::NextAwait {
|
||||
program.emit_insn(Insn::Next {
|
||||
cursor_id,
|
||||
pc_if_next: loop_labels.loop_start,
|
||||
});
|
||||
@@ -881,10 +846,7 @@ fn emit_seek(
|
||||
) -> Result<()> {
|
||||
let Some(seek) = seek_def.seek.as_ref() else {
|
||||
assert!(seek_def.iter_dir == IterationDirection::Backwards, "A SeekDef without a seek operation should only be used in backwards iteration direction");
|
||||
program.emit_insn(Insn::LastAsync {
|
||||
cursor_id: seek_cursor_id,
|
||||
});
|
||||
program.emit_insn(Insn::LastAwait {
|
||||
program.emit_insn(Insn::Last {
|
||||
cursor_id: seek_cursor_id,
|
||||
pc_if_empty: loop_end,
|
||||
});
|
||||
|
||||
@@ -102,11 +102,10 @@ pub fn translate_create_table(
|
||||
Some(SQLITE_TABLEID.to_owned()),
|
||||
CursorType::BTreeTable(table.clone()),
|
||||
);
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
root_page: 1usize.into(),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
|
||||
// Add the table entry to sqlite_schema
|
||||
emit_schema_entry(
|
||||
@@ -220,15 +219,12 @@ pub fn emit_schema_entry(
|
||||
dest_reg: record_reg,
|
||||
});
|
||||
|
||||
program.emit_insn(Insn::InsertAsync {
|
||||
program.emit_insn(Insn::Insert {
|
||||
cursor: sqlite_schema_cursor_id,
|
||||
key_reg: rowid_reg,
|
||||
record_reg,
|
||||
flag: 0,
|
||||
});
|
||||
program.emit_insn(Insn::InsertAwait {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
});
|
||||
}
|
||||
|
||||
struct PrimaryKeyColumnInfo<'a> {
|
||||
@@ -499,11 +495,10 @@ pub fn translate_create_virtual_table(
|
||||
Some(SQLITE_TABLEID.to_owned()),
|
||||
CursorType::BTreeTable(table.clone()),
|
||||
);
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
root_page: 1usize.into(),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
|
||||
let sql = create_vtable_body_to_str(&vtab);
|
||||
emit_schema_entry(
|
||||
@@ -578,19 +573,15 @@ pub fn translate_drop_table(
|
||||
Some(table_name.to_string()),
|
||||
CursorType::BTreeTable(schema_table.clone()),
|
||||
);
|
||||
program.emit_insn(Insn::OpenWriteAsync {
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
root_page: 1usize.into(),
|
||||
});
|
||||
program.emit_insn(Insn::OpenWriteAwait {});
|
||||
|
||||
// 1. Remove all entries from the schema table related to the table we are dropping, except for triggers
|
||||
// loop to beginning of schema table
|
||||
program.emit_insn(Insn::RewindAsync {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
});
|
||||
let end_metadata_label = program.allocate_label();
|
||||
program.emit_insn(Insn::RewindAwait {
|
||||
program.emit_insn(Insn::Rewind {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
pc_if_empty: end_metadata_label,
|
||||
});
|
||||
@@ -625,18 +616,12 @@ pub fn translate_drop_table(
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
dest: row_id_reg,
|
||||
});
|
||||
program.emit_insn(Insn::DeleteAsync {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
});
|
||||
program.emit_insn(Insn::DeleteAwait {
|
||||
program.emit_insn(Insn::Delete {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
});
|
||||
|
||||
program.resolve_label(next_label, program.offset());
|
||||
program.emit_insn(Insn::NextAsync {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
});
|
||||
program.emit_insn(Insn::NextAwait {
|
||||
program.emit_insn(Insn::Next {
|
||||
cursor_id: sqlite_schema_cursor_id,
|
||||
pc_if_next: metadata_loop,
|
||||
});
|
||||
|
||||
@@ -327,17 +327,11 @@ impl ProgramBuilder {
|
||||
} => {
|
||||
resolve(target_pc, "IfNot");
|
||||
}
|
||||
Insn::RewindAwait {
|
||||
cursor_id: _cursor_id,
|
||||
pc_if_empty,
|
||||
} => {
|
||||
resolve(pc_if_empty, "RewindAwait");
|
||||
Insn::Rewind { pc_if_empty, .. } => {
|
||||
resolve(pc_if_empty, "Rewind");
|
||||
}
|
||||
Insn::LastAwait {
|
||||
cursor_id: _cursor_id,
|
||||
pc_if_empty,
|
||||
} => {
|
||||
resolve(pc_if_empty, "LastAwait");
|
||||
Insn::Last { pc_if_empty, .. } => {
|
||||
resolve(pc_if_empty, "Last");
|
||||
}
|
||||
Insn::Goto { target_pc } => {
|
||||
resolve(target_pc, "Goto");
|
||||
@@ -366,11 +360,11 @@ impl ProgramBuilder {
|
||||
Insn::IfPos { target_pc, .. } => {
|
||||
resolve(target_pc, "IfPos");
|
||||
}
|
||||
Insn::NextAwait { pc_if_next, .. } => {
|
||||
resolve(pc_if_next, "NextAwait");
|
||||
Insn::Next { pc_if_next, .. } => {
|
||||
resolve(pc_if_next, "Next");
|
||||
}
|
||||
Insn::PrevAwait { pc_if_next, .. } => {
|
||||
resolve(pc_if_next, "PrevAwait");
|
||||
Insn::Prev { pc_if_prev, .. } => {
|
||||
resolve(pc_if_prev, "Prev");
|
||||
}
|
||||
Insn::InitCoroutine {
|
||||
yield_reg: _,
|
||||
|
||||
@@ -813,14 +813,14 @@ pub fn op_if_not(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_open_read_async(
|
||||
pub fn op_open_read(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::OpenReadAsync {
|
||||
let Insn::OpenRead {
|
||||
cursor_id,
|
||||
root_page,
|
||||
} = insn
|
||||
@@ -855,43 +855,32 @@ pub fn op_open_read_async(
|
||||
.replace(Cursor::new_btree(cursor));
|
||||
}
|
||||
CursorType::Pseudo(_) => {
|
||||
panic!("OpenReadAsync on pseudo cursor");
|
||||
panic!("OpenRead on pseudo cursor");
|
||||
}
|
||||
CursorType::Sorter => {
|
||||
panic!("OpenReadAsync on sorter cursor");
|
||||
panic!("OpenRead on sorter cursor");
|
||||
}
|
||||
CursorType::VirtualTable(_) => {
|
||||
panic!("OpenReadAsync on virtual table cursor, use Insn:VOpenAsync instead");
|
||||
panic!("OpenRead on virtual table cursor, use Insn:VOpen instead");
|
||||
}
|
||||
}
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_open_read_await(
|
||||
pub fn op_vopen(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_vopen_async(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::VOpenAsync { cursor_id } = insn else {
|
||||
let Insn::VOpen { cursor_id } = insn else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
let (_, cursor_type) = program.cursor_ref.get(*cursor_id).unwrap();
|
||||
let CursorType::VirtualTable(virtual_table) = cursor_type else {
|
||||
panic!("VOpenAsync on non-virtual table cursor");
|
||||
panic!("VOpen on non-virtual table cursor");
|
||||
};
|
||||
let cursor = virtual_table.open()?;
|
||||
state
|
||||
@@ -962,17 +951,6 @@ pub fn op_vcreate(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_vopen_await(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_vfilter(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
@@ -1119,7 +1097,7 @@ pub fn op_vnext(
|
||||
};
|
||||
let (_, cursor_type) = program.cursor_ref.get(*cursor_id).unwrap();
|
||||
let CursorType::VirtualTable(virtual_table) = cursor_type else {
|
||||
panic!("VNextAsync on non-virtual table cursor");
|
||||
panic!("VNext on non-virtual table cursor");
|
||||
};
|
||||
let has_more = {
|
||||
let mut cursor = state.get_cursor(*cursor_id);
|
||||
@@ -1161,53 +1139,14 @@ pub fn op_open_pseudo(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_rewind_async(
|
||||
pub fn op_rewind(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::RewindAsync { cursor_id } = insn else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
{
|
||||
let mut cursor =
|
||||
must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "RewindAsync");
|
||||
let cursor = cursor.as_btree_mut();
|
||||
return_if_io!(cursor.rewind());
|
||||
}
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_last_async(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::LastAsync { cursor_id } = insn else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
{
|
||||
let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "LastAsync");
|
||||
let cursor = cursor.as_btree_mut();
|
||||
return_if_io!(cursor.last());
|
||||
}
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_last_await(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::LastAwait {
|
||||
let Insn::Rewind {
|
||||
cursor_id,
|
||||
pc_if_empty,
|
||||
} = insn
|
||||
@@ -1216,9 +1155,9 @@ pub fn op_last_await(
|
||||
};
|
||||
assert!(pc_if_empty.is_offset());
|
||||
let is_empty = {
|
||||
let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "LastAwait");
|
||||
let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "Rewind");
|
||||
let cursor = cursor.as_btree_mut();
|
||||
cursor.wait_for_completion()?;
|
||||
return_if_io!(cursor.rewind());
|
||||
cursor.is_empty()
|
||||
};
|
||||
if is_empty {
|
||||
@@ -1229,14 +1168,14 @@ pub fn op_last_await(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_rewind_await(
|
||||
pub fn op_last(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::RewindAwait {
|
||||
let Insn::Last {
|
||||
cursor_id,
|
||||
pc_if_empty,
|
||||
} = insn
|
||||
@@ -1245,10 +1184,9 @@ pub fn op_rewind_await(
|
||||
};
|
||||
assert!(pc_if_empty.is_offset());
|
||||
let is_empty = {
|
||||
let mut cursor =
|
||||
must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "RewindAwait");
|
||||
let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "Last");
|
||||
let cursor = cursor.as_btree_mut();
|
||||
cursor.wait_for_completion()?;
|
||||
return_if_io!(cursor.last());
|
||||
cursor.is_empty()
|
||||
};
|
||||
if is_empty {
|
||||
@@ -1471,54 +1409,14 @@ pub fn op_result_row(
|
||||
return Ok(InsnFunctionStepResult::Row);
|
||||
}
|
||||
|
||||
pub fn op_next_async(
|
||||
pub fn op_next(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::NextAsync { cursor_id } = insn else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
{
|
||||
let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "NextAsync");
|
||||
let cursor = cursor.as_btree_mut();
|
||||
cursor.set_null_flag(false);
|
||||
return_if_io!(cursor.next());
|
||||
}
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_prev_async(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::PrevAsync { cursor_id } = insn else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
{
|
||||
let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "PrevAsync");
|
||||
let cursor = cursor.as_btree_mut();
|
||||
cursor.set_null_flag(false);
|
||||
return_if_io!(cursor.prev());
|
||||
}
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_prev_await(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::PrevAwait {
|
||||
let Insn::Next {
|
||||
cursor_id,
|
||||
pc_if_next,
|
||||
} = insn
|
||||
@@ -1527,9 +1425,11 @@ pub fn op_prev_await(
|
||||
};
|
||||
assert!(pc_if_next.is_offset());
|
||||
let is_empty = {
|
||||
let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "PrevAwait");
|
||||
let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "Next");
|
||||
let cursor = cursor.as_btree_mut();
|
||||
cursor.wait_for_completion()?;
|
||||
cursor.set_null_flag(false);
|
||||
return_if_io!(cursor.next());
|
||||
|
||||
cursor.is_empty()
|
||||
};
|
||||
if !is_empty {
|
||||
@@ -1540,29 +1440,31 @@ pub fn op_prev_await(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_next_await(
|
||||
pub fn op_prev(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::NextAwait {
|
||||
let Insn::Prev {
|
||||
cursor_id,
|
||||
pc_if_next,
|
||||
pc_if_prev,
|
||||
} = insn
|
||||
else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
assert!(pc_if_next.is_offset());
|
||||
assert!(pc_if_prev.is_offset());
|
||||
let is_empty = {
|
||||
let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "NextAwait");
|
||||
let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "Prev");
|
||||
let cursor = cursor.as_btree_mut();
|
||||
cursor.wait_for_completion()?;
|
||||
cursor.set_null_flag(false);
|
||||
return_if_io!(cursor.prev());
|
||||
|
||||
cursor.is_empty()
|
||||
};
|
||||
if !is_empty {
|
||||
state.pc = pc_if_next.to_offset_int();
|
||||
state.pc = pc_if_prev.to_offset_int();
|
||||
} else {
|
||||
state.pc += 1;
|
||||
}
|
||||
@@ -3737,14 +3639,14 @@ pub fn op_yield(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_insert_async(
|
||||
pub fn op_insert(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::InsertAsync {
|
||||
let Insn::Insert {
|
||||
cursor,
|
||||
key_reg,
|
||||
record_reg,
|
||||
@@ -3768,25 +3670,6 @@ pub fn op_insert_async(
|
||||
// if we were to set to false after starting a balance procedure, it might
|
||||
// leave undefined state.
|
||||
return_if_io!(cursor.insert(&BTreeKey::new_table_rowid(key as u64, Some(record)), true));
|
||||
}
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_insert_await(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::InsertAwait { cursor_id } = insn else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
{
|
||||
let mut cursor = state.get_cursor(*cursor_id);
|
||||
let cursor = cursor.as_btree_mut();
|
||||
cursor.wait_for_completion()?;
|
||||
// Only update last_insert_rowid for regular table inserts, not schema modifications
|
||||
if cursor.root_page() != 1 {
|
||||
if let Some(rowid) = cursor.rowid()? {
|
||||
@@ -3802,14 +3685,14 @@ pub fn op_insert_await(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_delete_async(
|
||||
pub fn op_delete(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::DeleteAsync { cursor_id } = insn else {
|
||||
let Insn::Delete { cursor_id } = insn else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
{
|
||||
@@ -3817,19 +3700,21 @@ pub fn op_delete_async(
|
||||
let cursor = cursor.as_btree_mut();
|
||||
return_if_io!(cursor.delete());
|
||||
}
|
||||
let prev_changes = program.n_change.get();
|
||||
program.n_change.set(prev_changes + 1);
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_idx_insert_async(
|
||||
pub fn op_idx_insert(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
dbg!("op_idx_insert_async");
|
||||
if let Insn::IdxInsertAsync {
|
||||
dbg!("op_idx_insert_");
|
||||
if let Insn::IdxInsert {
|
||||
cursor_id,
|
||||
record_reg,
|
||||
flags,
|
||||
@@ -3871,55 +3756,16 @@ pub fn op_idx_insert_async(
|
||||
|
||||
dbg!(moved_before);
|
||||
// Start insertion of row. This might trigger a balance procedure which will take care of moving to different pages,
|
||||
// therefore, we don't want to seek again if that happens, meaning we don't want to return on io without moving to `Await` opcode
|
||||
// therefore, we don't want to seek again if that happens, meaning we don't want to return on io without moving to the following opcode
|
||||
// because it could trigger a movement to child page after a balance root which will leave the current page as the root page.
|
||||
return_if_io!(cursor.insert(&BTreeKey::new_index_key(record), moved_before));
|
||||
}
|
||||
state.pc += 1;
|
||||
}
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_idx_insert_await(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
if let Insn::IdxInsertAwait { cursor_id } = *insn {
|
||||
{
|
||||
let mut cursor = state.get_cursor(cursor_id);
|
||||
let cursor = cursor.as_btree_mut();
|
||||
cursor.wait_for_completion()?;
|
||||
}
|
||||
// TODO: flag optimizations, update n_change if OPFLAG_NCHANGE
|
||||
state.pc += 1;
|
||||
}
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_delete_await(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::DeleteAwait { cursor_id } = insn else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
{
|
||||
let mut cursor = state.get_cursor(*cursor_id);
|
||||
let cursor = cursor.as_btree_mut();
|
||||
cursor.wait_for_completion()?;
|
||||
}
|
||||
let prev_changes = program.n_change.get();
|
||||
program.n_change.set(prev_changes + 1);
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_new_rowid(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
@@ -4072,14 +3918,14 @@ pub fn op_offset_limit(
|
||||
// this cursor may be reused for next insert
|
||||
// Update: tablemoveto is used to travers on not exists, on insert depending on flags if nonseek it traverses again.
|
||||
// If not there might be some optimizations obviously.
|
||||
pub fn op_open_write_async(
|
||||
pub fn op_open_write(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::OpenWriteAsync {
|
||||
let Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page,
|
||||
..
|
||||
@@ -4093,7 +3939,7 @@ pub fn op_open_write_async(
|
||||
OwnedValue::Integer(val) => *val as u64,
|
||||
_ => {
|
||||
return Err(LimboError::InternalError(
|
||||
"OpenWriteAsync: the value in root_page is not an integer".into(),
|
||||
"OpenWrite: the value in root_page is not an integer".into(),
|
||||
));
|
||||
}
|
||||
},
|
||||
@@ -4128,20 +3974,6 @@ pub fn op_open_write_async(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_open_write_await(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::OpenWriteAwait {} = insn else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_copy(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
@@ -4592,7 +4424,7 @@ pub fn op_open_ephemeral(
|
||||
panic!("OpenEphemeral on sorter cursor");
|
||||
}
|
||||
CursorType::VirtualTable(_) => {
|
||||
panic!("OpenEphemeral on virtual table cursor, use Insn::VOpenAsync instead");
|
||||
panic!("OpenEphemeral on virtual table cursor, use Insn::VOpen instead");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -336,11 +336,11 @@ pub fn insn_to_str(
|
||||
0,
|
||||
format!("if !r[{}] goto {}", reg, target_pc.to_debug_int()),
|
||||
),
|
||||
Insn::OpenReadAsync {
|
||||
Insn::OpenRead {
|
||||
cursor_id,
|
||||
root_page,
|
||||
} => (
|
||||
"OpenReadAsync",
|
||||
"OpenRead",
|
||||
*cursor_id as i32,
|
||||
*root_page as i32,
|
||||
0,
|
||||
@@ -355,17 +355,8 @@ pub fn insn_to_str(
|
||||
root_page
|
||||
),
|
||||
),
|
||||
Insn::OpenReadAwait => (
|
||||
"OpenReadAwait",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::VOpenAsync { cursor_id } => (
|
||||
"VOpenAsync",
|
||||
Insn::VOpen { cursor_id } => (
|
||||
"VOpen",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
@@ -373,15 +364,6 @@ pub fn insn_to_str(
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::VOpenAwait => (
|
||||
"VOpenAwait",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::VCreate {
|
||||
table_name,
|
||||
module_name,
|
||||
@@ -462,27 +444,18 @@ pub fn insn_to_str(
|
||||
0,
|
||||
format!("{} columns in r[{}]", num_fields, content_reg),
|
||||
),
|
||||
Insn::RewindAsync { cursor_id } => (
|
||||
"RewindAsync",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::RewindAwait {
|
||||
Insn::Rewind {
|
||||
cursor_id,
|
||||
pc_if_empty,
|
||||
} => (
|
||||
"RewindAwait",
|
||||
"Rewind",
|
||||
*cursor_id as i32,
|
||||
pc_if_empty.to_debug_int(),
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
format!(
|
||||
"Rewind table {}",
|
||||
"Rewind {}",
|
||||
program.cursor_ref[*cursor_id]
|
||||
.0
|
||||
.as_ref()
|
||||
@@ -573,20 +546,11 @@ pub fn insn_to_str(
|
||||
format!("output=r[{}..{}]", start_reg, start_reg + count - 1)
|
||||
},
|
||||
),
|
||||
Insn::NextAsync { cursor_id } => (
|
||||
"NextAsync",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::NextAwait {
|
||||
Insn::Next {
|
||||
cursor_id,
|
||||
pc_if_next,
|
||||
} => (
|
||||
"NextAwait",
|
||||
"Next",
|
||||
*cursor_id as i32,
|
||||
pc_if_next.to_debug_int(),
|
||||
0,
|
||||
@@ -795,14 +759,14 @@ pub fn insn_to_str(
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::IdxInsertAsync {
|
||||
Insn::IdxInsert {
|
||||
cursor_id,
|
||||
record_reg,
|
||||
unpacked_start,
|
||||
flags,
|
||||
..
|
||||
} => (
|
||||
"IdxInsertAsync",
|
||||
"IdxInsert",
|
||||
*cursor_id as i32,
|
||||
*record_reg as i32,
|
||||
unpacked_start.unwrap_or(0) as i32,
|
||||
@@ -810,15 +774,6 @@ pub fn insn_to_str(
|
||||
flags.0 as u16,
|
||||
format!("key=r[{}]", record_reg),
|
||||
),
|
||||
Insn::IdxInsertAwait { cursor_id } => (
|
||||
"IdxInsertAwait",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::IdxGT {
|
||||
cursor_id,
|
||||
start_reg,
|
||||
@@ -1034,13 +989,13 @@ pub fn insn_to_str(
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::InsertAsync {
|
||||
Insn::Insert {
|
||||
cursor,
|
||||
key_reg,
|
||||
record_reg,
|
||||
flag,
|
||||
} => (
|
||||
"InsertAsync",
|
||||
"Insert",
|
||||
*cursor as i32,
|
||||
*record_reg as i32,
|
||||
*key_reg as i32,
|
||||
@@ -1048,26 +1003,8 @@ pub fn insn_to_str(
|
||||
*flag as u16,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::InsertAwait { cursor_id } => (
|
||||
"InsertAwait",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::DeleteAsync { cursor_id } => (
|
||||
"DeleteAsync",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::DeleteAwait { cursor_id } => (
|
||||
"DeleteAwait",
|
||||
Insn::Delete { cursor_id } => (
|
||||
"Delete",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
@@ -1135,12 +1072,12 @@ pub fn insn_to_str(
|
||||
limit_reg, combined_reg, limit_reg, offset_reg, combined_reg
|
||||
),
|
||||
),
|
||||
Insn::OpenWriteAsync {
|
||||
Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page,
|
||||
..
|
||||
} => (
|
||||
"OpenWriteAsync",
|
||||
"OpenWrite",
|
||||
*cursor_id as i32,
|
||||
match root_page {
|
||||
RegisterOrLiteral::Literal(i) => *i as _,
|
||||
@@ -1151,15 +1088,6 @@ pub fn insn_to_str(
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::OpenWriteAwait {} => (
|
||||
"OpenWriteAwait",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::Copy {
|
||||
src_reg,
|
||||
dst_reg,
|
||||
@@ -1221,10 +1149,13 @@ pub fn insn_to_str(
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::LastAsync { cursor_id } => (
|
||||
"LastAsync",
|
||||
Insn::Last {
|
||||
cursor_id,
|
||||
pc_if_empty,
|
||||
} => (
|
||||
"Last",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
pc_if_empty.to_debug_int(),
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
@@ -1248,28 +1179,13 @@ pub fn insn_to_str(
|
||||
0,
|
||||
where_clause.clone(),
|
||||
),
|
||||
Insn::LastAwait { cursor_id, .. } => (
|
||||
"LastAwait",
|
||||
Insn::Prev {
|
||||
cursor_id,
|
||||
pc_if_prev,
|
||||
} => (
|
||||
"Prev",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::PrevAsync { cursor_id } => (
|
||||
"PrevAsync",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::PrevAwait { cursor_id, .. } => (
|
||||
"PrevAwait",
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
pc_if_prev.to_debug_int(),
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
|
||||
@@ -257,22 +257,16 @@ pub enum Insn {
|
||||
jump_if_null: bool,
|
||||
},
|
||||
/// Open a cursor for reading.
|
||||
OpenReadAsync {
|
||||
OpenRead {
|
||||
cursor_id: CursorID,
|
||||
root_page: PageIdx,
|
||||
},
|
||||
|
||||
/// Await for the completion of open cursor.
|
||||
OpenReadAwait,
|
||||
|
||||
/// Open a cursor for a virtual table.
|
||||
VOpenAsync {
|
||||
VOpen {
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
|
||||
/// Await for the completion of open cursor for a virtual table.
|
||||
VOpenAwait,
|
||||
|
||||
/// Create a new virtual table.
|
||||
VCreate {
|
||||
module_name: usize, // P1: Name of the module that contains the virtual table implementation
|
||||
@@ -319,21 +313,12 @@ pub enum Insn {
|
||||
},
|
||||
|
||||
/// Rewind the cursor to the beginning of the B-Tree.
|
||||
RewindAsync {
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
|
||||
/// Await for the completion of cursor rewind.
|
||||
RewindAwait {
|
||||
Rewind {
|
||||
cursor_id: CursorID,
|
||||
pc_if_empty: BranchOffset,
|
||||
},
|
||||
|
||||
LastAsync {
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
|
||||
LastAwait {
|
||||
Last {
|
||||
cursor_id: CursorID,
|
||||
pc_if_empty: BranchOffset,
|
||||
},
|
||||
@@ -368,23 +353,14 @@ pub enum Insn {
|
||||
},
|
||||
|
||||
/// Advance the cursor to the next row.
|
||||
NextAsync {
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
|
||||
/// Await for the completion of cursor advance.
|
||||
NextAwait {
|
||||
Next {
|
||||
cursor_id: CursorID,
|
||||
pc_if_next: BranchOffset,
|
||||
},
|
||||
|
||||
PrevAsync {
|
||||
Prev {
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
|
||||
PrevAwait {
|
||||
cursor_id: CursorID,
|
||||
pc_if_next: BranchOffset,
|
||||
pc_if_prev: BranchOffset,
|
||||
},
|
||||
|
||||
/// Halt the program.
|
||||
@@ -498,16 +474,13 @@ pub enum Insn {
|
||||
/// P3 + P4 are for the original column values that make up that key in unpacked (pre-serialized) form.
|
||||
/// If P5 has the OPFLAG_APPEND bit set, that is a hint to the b-tree layer that this insert is likely to be an append.
|
||||
/// OPFLAG_NCHANGE bit set, then the change counter is incremented by this instruction. If the OPFLAG_NCHANGE bit is clear, then the change counter is unchanged
|
||||
IdxInsertAsync {
|
||||
IdxInsert {
|
||||
cursor_id: CursorID,
|
||||
record_reg: usize, // P2 the register containing the record to insert
|
||||
unpacked_start: Option<usize>, // P3 the index of the first register for the unpacked key
|
||||
unpacked_count: Option<u16>, // P4 # of unpacked values in the key in P2
|
||||
flags: IdxInsertFlags, // TODO: optimization
|
||||
},
|
||||
IdxInsertAwait {
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
|
||||
/// The P4 register values beginning with P3 form an unpacked index key that omits the PRIMARY KEY. Compare this key value against the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID fields at the end.
|
||||
/// If the P1 index entry is greater or equal than the key value then jump to P2. Otherwise fall through to the next instruction.
|
||||
@@ -642,22 +615,14 @@ pub enum Insn {
|
||||
end_offset: BranchOffset,
|
||||
},
|
||||
|
||||
InsertAsync {
|
||||
Insert {
|
||||
cursor: CursorID,
|
||||
key_reg: usize, // Must be int.
|
||||
record_reg: usize, // Blob of record data.
|
||||
flag: usize, // Flags used by insert, for now not used.
|
||||
},
|
||||
|
||||
InsertAwait {
|
||||
cursor_id: usize,
|
||||
},
|
||||
|
||||
DeleteAsync {
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
|
||||
DeleteAwait {
|
||||
Delete {
|
||||
cursor_id: CursorID,
|
||||
},
|
||||
|
||||
@@ -687,13 +652,11 @@ pub enum Insn {
|
||||
offset_reg: usize,
|
||||
},
|
||||
|
||||
OpenWriteAsync {
|
||||
OpenWrite {
|
||||
cursor_id: CursorID,
|
||||
root_page: RegisterOrLiteral<PageIdx>,
|
||||
},
|
||||
|
||||
OpenWriteAwait {},
|
||||
|
||||
Copy {
|
||||
src_reg: usize,
|
||||
dst_reg: usize,
|
||||
@@ -847,28 +810,22 @@ impl Insn {
|
||||
Insn::Ge { .. } => execute::op_ge,
|
||||
Insn::If { .. } => execute::op_if,
|
||||
Insn::IfNot { .. } => execute::op_if_not,
|
||||
Insn::OpenReadAsync { .. } => execute::op_open_read_async,
|
||||
Insn::OpenReadAwait => execute::op_open_read_await,
|
||||
Insn::VOpenAsync { .. } => execute::op_vopen_async,
|
||||
Insn::VOpenAwait => execute::op_vopen_await,
|
||||
Insn::OpenRead { .. } => execute::op_open_read,
|
||||
Insn::VOpen { .. } => execute::op_vopen,
|
||||
Insn::VCreate { .. } => execute::op_vcreate,
|
||||
Insn::VFilter { .. } => execute::op_vfilter,
|
||||
Insn::VColumn { .. } => execute::op_vcolumn,
|
||||
Insn::VUpdate { .. } => execute::op_vupdate,
|
||||
Insn::VNext { .. } => execute::op_vnext,
|
||||
Insn::OpenPseudo { .. } => execute::op_open_pseudo,
|
||||
Insn::RewindAsync { .. } => execute::op_rewind_async,
|
||||
Insn::RewindAwait { .. } => execute::op_rewind_await,
|
||||
Insn::LastAsync { .. } => execute::op_last_async,
|
||||
Insn::LastAwait { .. } => execute::op_last_await,
|
||||
Insn::Rewind { .. } => execute::op_rewind,
|
||||
Insn::Last { .. } => execute::op_last,
|
||||
Insn::Column { .. } => execute::op_column,
|
||||
Insn::TypeCheck { .. } => execute::op_type_check,
|
||||
Insn::MakeRecord { .. } => execute::op_make_record,
|
||||
Insn::ResultRow { .. } => execute::op_result_row,
|
||||
Insn::NextAsync { .. } => execute::op_next_async,
|
||||
Insn::NextAwait { .. } => execute::op_next_await,
|
||||
Insn::PrevAsync { .. } => execute::op_prev_async,
|
||||
Insn::PrevAwait { .. } => execute::op_prev_await,
|
||||
Insn::Next { .. } => execute::op_next,
|
||||
Insn::Prev { .. } => execute::op_prev,
|
||||
Insn::Halt { .. } => execute::op_halt,
|
||||
Insn::Transaction { .. } => execute::op_transaction,
|
||||
Insn::AutoCommit { .. } => execute::op_auto_commit,
|
||||
@@ -904,19 +861,15 @@ impl Insn {
|
||||
Insn::InitCoroutine { .. } => execute::op_init_coroutine,
|
||||
Insn::EndCoroutine { .. } => execute::op_end_coroutine,
|
||||
Insn::Yield { .. } => execute::op_yield,
|
||||
Insn::InsertAsync { .. } => execute::op_insert_async,
|
||||
Insn::InsertAwait { .. } => execute::op_insert_await,
|
||||
Insn::IdxInsertAsync { .. } => execute::op_idx_insert_async,
|
||||
Insn::IdxInsertAwait { .. } => execute::op_idx_insert_await,
|
||||
Insn::DeleteAsync { .. } => execute::op_delete_async,
|
||||
Insn::DeleteAwait { .. } => execute::op_delete_await,
|
||||
Insn::Insert { .. } => execute::op_insert,
|
||||
Insn::IdxInsert { .. } => execute::op_idx_insert,
|
||||
Insn::Delete { .. } => execute::op_delete,
|
||||
Insn::NewRowid { .. } => execute::op_new_rowid,
|
||||
Insn::MustBeInt { .. } => execute::op_must_be_int,
|
||||
Insn::SoftNull { .. } => execute::op_soft_null,
|
||||
Insn::NotExists { .. } => execute::op_not_exists,
|
||||
Insn::OffsetLimit { .. } => execute::op_offset_limit,
|
||||
Insn::OpenWriteAsync { .. } => execute::op_open_write_async,
|
||||
Insn::OpenWriteAwait { .. } => execute::op_open_write_await,
|
||||
Insn::OpenWrite { .. } => execute::op_open_write,
|
||||
Insn::Copy { .. } => execute::op_copy,
|
||||
Insn::CreateBtree { .. } => execute::op_create_btree,
|
||||
Insn::Destroy { .. } => execute::op_destroy,
|
||||
|
||||
@@ -563,8 +563,8 @@ fn print_insn(program: &Program, addr: InsnReference, insn: &Insn, indent: Strin
|
||||
fn get_indent_count(indent_count: usize, curr_insn: &Insn, prev_insn: Option<&Insn>) -> usize {
|
||||
let indent_count = if let Some(insn) = prev_insn {
|
||||
match insn {
|
||||
Insn::RewindAwait { .. }
|
||||
| Insn::LastAwait { .. }
|
||||
Insn::Rewind { .. }
|
||||
| Insn::Last { .. }
|
||||
| Insn::SorterSort { .. }
|
||||
| Insn::SeekGE { .. }
|
||||
| Insn::SeekGT { .. }
|
||||
@@ -578,9 +578,7 @@ fn get_indent_count(indent_count: usize, curr_insn: &Insn, prev_insn: Option<&In
|
||||
};
|
||||
|
||||
match curr_insn {
|
||||
Insn::NextAsync { .. } | Insn::SorterNext { .. } | Insn::PrevAsync { .. } => {
|
||||
indent_count - 1
|
||||
}
|
||||
Insn::Next { .. } | Insn::SorterNext { .. } | Insn::Prev { .. } => indent_count - 1,
|
||||
_ => indent_count,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user