make query_start method to return bool - if result will have some rows or not

This commit is contained in:
Nikita Sivukhin
2025-10-27 23:07:37 +04:00
parent e42ce24534
commit 8acbe3de66
6 changed files with 23 additions and 20 deletions

View File

@@ -87,7 +87,9 @@ pub trait IndexMethodCursor {
/// For example, for 2 patterns ["SELECT * FROM {table} LIMIT ?", "SELECT * FROM {table} WHERE x = ?"], query_start(...) call can have following arguments: /// For example, for 2 patterns ["SELECT * FROM {table} LIMIT ?", "SELECT * FROM {table} WHERE x = ?"], query_start(...) call can have following arguments:
/// - [Integer(0), Integer(10)] - pattern "SELECT * FROM {table} LIMIT ?" was chosen with LIMIT parameter equals to 10 /// - [Integer(0), Integer(10)] - pattern "SELECT * FROM {table} LIMIT ?" was chosen with LIMIT parameter equals to 10
/// - [Integer(1), Text("turso")] - pattern "SELECT * FROM {table} WHERE x = ?" was chosen with equality comparison equals to "turso" /// - [Integer(1), Text("turso")] - pattern "SELECT * FROM {table} WHERE x = ?" was chosen with equality comparison equals to "turso"
fn query_start(&mut self, values: &[Register]) -> Result<IOResult<()>>; ///
/// Returns false if query will produce no rows (similar to VFilter/Rewind op codes)
fn query_start(&mut self, values: &[Register]) -> Result<IOResult<bool>>;
/// Moves cursor to the next response row /// Moves cursor to the next response row
/// Returns false if query exhausted all rows /// Returns false if query exhausted all rows

View File

@@ -151,7 +151,6 @@ pub struct VectorSparseInvertedIndexMethodCursor {
delete_state: VectorSparseInvertedIndexDeleteState, delete_state: VectorSparseInvertedIndexDeleteState,
search_state: VectorSparseInvertedIndexSearchState, search_state: VectorSparseInvertedIndexSearchState,
search_result: VecDeque<(i64, f64)>, search_result: VecDeque<(i64, f64)>,
search_row: Option<(i64, f64)>,
} }
impl IndexMethod for VectorSparseInvertedIndexMethod { impl IndexMethod for VectorSparseInvertedIndexMethod {
@@ -199,7 +198,6 @@ impl VectorSparseInvertedIndexMethodCursor {
scratch_cursor: None, scratch_cursor: None,
main_btree: None, main_btree: None,
search_result: VecDeque::new(), search_result: VecDeque::new(),
search_row: None,
create_state: VectorSparseInvertedIndexCreateState::Init, create_state: VectorSparseInvertedIndexCreateState::Init,
insert_state: VectorSparseInvertedIndexInsertState::Init, insert_state: VectorSparseInvertedIndexInsertState::Init,
delete_state: VectorSparseInvertedIndexDeleteState::Init, delete_state: VectorSparseInvertedIndexDeleteState::Init,
@@ -459,7 +457,7 @@ impl IndexMethodCursor for VectorSparseInvertedIndexMethodCursor {
} }
} }
fn query_start(&mut self, values: &[Register]) -> Result<IOResult<()>> { fn query_start(&mut self, values: &[Register]) -> Result<IOResult<bool>> {
let Some(scratch) = &mut self.scratch_cursor else { let Some(scratch) = &mut self.scratch_cursor else {
return Err(LimboError::InternalError( return Err(LimboError::InternalError(
"cursor must be opened".to_string(), "cursor must be opened".to_string(),
@@ -521,7 +519,7 @@ impl IndexMethodCursor for VectorSparseInvertedIndexMethodCursor {
continue; continue;
} }
let position = p[*idx]; let position = p[*idx];
let key = ImmutableRecord::from_values(&[Value::Integer(position as i64)], 2); let key = ImmutableRecord::from_values(&[Value::Integer(position as i64)], 1);
self.search_state = VectorSparseInvertedIndexSearchState::Seek { self.search_state = VectorSparseInvertedIndexSearchState::Seek {
collected: collected.take(), collected: collected.take(),
positions: positions.take(), positions: positions.take(),
@@ -551,7 +549,7 @@ impl IndexMethodCursor for VectorSparseInvertedIndexMethodCursor {
limit: *limit, limit: *limit,
}; };
} }
SeekResult::TryAdvance => { SeekResult::TryAdvance | SeekResult::NotFound => {
self.search_state = VectorSparseInvertedIndexSearchState::Next { self.search_state = VectorSparseInvertedIndexSearchState::Next {
collected: collected.take(), collected: collected.take(),
positions: positions.take(), positions: positions.take(),
@@ -560,9 +558,6 @@ impl IndexMethodCursor for VectorSparseInvertedIndexMethodCursor {
limit: *limit, limit: *limit,
}; };
} }
SeekResult::NotFound => {
return Err(LimboError::Corrupt("inverted index corrupted".to_string()))
}
} }
} }
VectorSparseInvertedIndexSearchState::Read { VectorSparseInvertedIndexSearchState::Read {
@@ -637,7 +632,7 @@ impl IndexMethodCursor for VectorSparseInvertedIndexMethodCursor {
let Some(rowid) = rowids.as_ref().unwrap().last() else { let Some(rowid) = rowids.as_ref().unwrap().last() else {
let distances = distances.take().unwrap(); let distances = distances.take().unwrap();
self.search_result = distances.iter().map(|(d, i)| (*i, d.0)).collect(); self.search_result = distances.iter().map(|(d, i)| (*i, d.0)).collect();
return Ok(IOResult::Done(())); return Ok(IOResult::Done(!self.search_result.is_empty()));
}; };
let result = return_if_io!( let result = return_if_io!(
main.seek(SeekKey::TableRowId(*rowid), SeekOp::GE { eq_only: true }) main.seek(SeekKey::TableRowId(*rowid), SeekOp::GE { eq_only: true })
@@ -709,17 +704,17 @@ impl IndexMethodCursor for VectorSparseInvertedIndexMethodCursor {
} }
fn query_rowid(&mut self) -> Result<IOResult<Option<i64>>> { fn query_rowid(&mut self) -> Result<IOResult<Option<i64>>> {
let result = self.search_row.as_ref().unwrap(); let result = self.search_result.front().unwrap();
Ok(IOResult::Done(Some(result.0))) Ok(IOResult::Done(Some(result.0)))
} }
fn query_column(&mut self, _: usize) -> Result<IOResult<Value>> { fn query_column(&mut self, _: usize) -> Result<IOResult<Value>> {
let result = self.search_row.as_ref().unwrap(); let result = self.search_result.front().unwrap();
Ok(IOResult::Done(Value::Float(result.1))) Ok(IOResult::Done(Value::Float(result.1)))
} }
fn query_next(&mut self) -> Result<IOResult<bool>> { fn query_next(&mut self) -> Result<IOResult<bool>> {
self.search_row = self.search_result.pop_front(); let _ = self.search_result.pop_front();
Ok(IOResult::Done(self.search_row.is_some())) Ok(IOResult::Done(!self.search_result.is_empty()))
} }
} }

View File

@@ -720,10 +720,7 @@ pub fn open_loop(
cursor_id: index_cursor_id.expect("IndexMethod requires a index cursor"), cursor_id: index_cursor_id.expect("IndexMethod requires a index cursor"),
start_reg, start_reg,
count_reg: query.arguments.len() + 1, count_reg: query.arguments.len() + 1,
}); pc_if_empty: loop_end,
program.emit_insn(Insn::Next {
cursor_id: index_cursor_id.expect("IndexMethod requires a index cursor"),
pc_if_next: loop_end,
}); });
program.preassign_label_to_next_insn(loop_start); program.preassign_label_to_next_insn(loop_start);
if let Some(table_cursor_id) = table_cursor_id { if let Some(table_cursor_id) = table_cursor_id {

View File

@@ -819,6 +819,9 @@ impl ProgramBuilder {
Insn::IdxLT { target_pc, .. } => { Insn::IdxLT { target_pc, .. } => {
resolve(target_pc, "IdxLT"); resolve(target_pc, "IdxLT");
} }
Insn::IndexMethodQuery { pc_if_empty, .. } => {
resolve(pc_if_empty, "IndexMethodQuery");
}
Insn::IsNull { reg: _, target_pc } => { Insn::IsNull { reg: _, target_pc } => {
resolve(target_pc, "IsNull"); resolve(target_pc, "IsNull");
} }

View File

@@ -7248,6 +7248,7 @@ pub fn op_index_method_query(
cursor_id, cursor_id,
start_reg, start_reg,
count_reg, count_reg,
pc_if_empty,
}, },
insn insn
); );
@@ -7260,8 +7261,12 @@ pub fn op_index_method_query(
} }
let cursor = state.cursors[*cursor_id].as_mut().unwrap(); let cursor = state.cursors[*cursor_id].as_mut().unwrap();
let cursor = cursor.as_index_method_mut(); let cursor = cursor.as_index_method_mut();
return_if_io!(cursor.query_start(&state.registers[*start_reg..*start_reg + *count_reg])); let has_rows = return_if_io!(cursor.query_start(&state.registers[*start_reg..*start_reg + *count_reg]));
state.pc += 1; if !has_rows {
state.pc = pc_if_empty.as_offset_int();
} else {
state.pc += 1;
}
Ok(InsnFunctionStepResult::Step) Ok(InsnFunctionStepResult::Step)
} }

View File

@@ -895,6 +895,7 @@ pub enum Insn {
cursor_id: CursorID, cursor_id: CursorID,
start_reg: usize, start_reg: usize,
count_reg: usize, count_reg: usize,
pc_if_empty: BranchOffset,
}, },
/// Deletes an entire database table or index whose root page in the database file is given by P1. /// Deletes an entire database table or index whose root page in the database file is given by P1.