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:
/// - [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"
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
/// Returns false if query exhausted all rows

View File

@@ -151,7 +151,6 @@ pub struct VectorSparseInvertedIndexMethodCursor {
delete_state: VectorSparseInvertedIndexDeleteState,
search_state: VectorSparseInvertedIndexSearchState,
search_result: VecDeque<(i64, f64)>,
search_row: Option<(i64, f64)>,
}
impl IndexMethod for VectorSparseInvertedIndexMethod {
@@ -199,7 +198,6 @@ impl VectorSparseInvertedIndexMethodCursor {
scratch_cursor: None,
main_btree: None,
search_result: VecDeque::new(),
search_row: None,
create_state: VectorSparseInvertedIndexCreateState::Init,
insert_state: VectorSparseInvertedIndexInsertState::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 {
return Err(LimboError::InternalError(
"cursor must be opened".to_string(),
@@ -521,7 +519,7 @@ impl IndexMethodCursor for VectorSparseInvertedIndexMethodCursor {
continue;
}
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 {
collected: collected.take(),
positions: positions.take(),
@@ -551,7 +549,7 @@ impl IndexMethodCursor for VectorSparseInvertedIndexMethodCursor {
limit: *limit,
};
}
SeekResult::TryAdvance => {
SeekResult::TryAdvance | SeekResult::NotFound => {
self.search_state = VectorSparseInvertedIndexSearchState::Next {
collected: collected.take(),
positions: positions.take(),
@@ -560,9 +558,6 @@ impl IndexMethodCursor for VectorSparseInvertedIndexMethodCursor {
limit: *limit,
};
}
SeekResult::NotFound => {
return Err(LimboError::Corrupt("inverted index corrupted".to_string()))
}
}
}
VectorSparseInvertedIndexSearchState::Read {
@@ -637,7 +632,7 @@ impl IndexMethodCursor for VectorSparseInvertedIndexMethodCursor {
let Some(rowid) = rowids.as_ref().unwrap().last() else {
let distances = distances.take().unwrap();
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!(
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>>> {
let result = self.search_row.as_ref().unwrap();
let result = self.search_result.front().unwrap();
Ok(IOResult::Done(Some(result.0)))
}
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)))
}
fn query_next(&mut self) -> Result<IOResult<bool>> {
self.search_row = self.search_result.pop_front();
Ok(IOResult::Done(self.search_row.is_some()))
let _ = self.search_result.pop_front();
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"),
start_reg,
count_reg: query.arguments.len() + 1,
});
program.emit_insn(Insn::Next {
cursor_id: index_cursor_id.expect("IndexMethod requires a index cursor"),
pc_if_next: loop_end,
pc_if_empty: loop_end,
});
program.preassign_label_to_next_insn(loop_start);
if let Some(table_cursor_id) = table_cursor_id {

View File

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

View File

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

View File

@@ -895,6 +895,7 @@ pub enum Insn {
cursor_id: CursorID,
start_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.