mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-09 02:04:22 +01:00
Add SeekLE/SeekLT operations to VDBE
This commit is contained in:
@@ -1203,11 +1203,13 @@ pub enum CursorResult<T> {
|
||||
IO,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum SeekOp {
|
||||
EQ,
|
||||
GE,
|
||||
GT,
|
||||
LE,
|
||||
LT,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
|
||||
@@ -413,6 +413,12 @@ impl ProgramBuilder {
|
||||
Insn::SeekGT { target_pc, .. } => {
|
||||
resolve(target_pc, "SeekGT");
|
||||
}
|
||||
Insn::SeekLE { target_pc, .. } => {
|
||||
resolve(target_pc, "SeekLE");
|
||||
}
|
||||
Insn::SeekLT { target_pc, .. } => {
|
||||
resolve(target_pc, "SeekLT");
|
||||
}
|
||||
Insn::IdxGE { target_pc, .. } => {
|
||||
resolve(target_pc, "IdxGE");
|
||||
}
|
||||
|
||||
@@ -1892,97 +1892,69 @@ pub fn op_deferred_seek(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_seek_ge(
|
||||
pub fn op_seek(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::SeekGE {
|
||||
let (Insn::SeekGE {
|
||||
cursor_id,
|
||||
start_reg,
|
||||
num_regs,
|
||||
target_pc,
|
||||
is_index,
|
||||
} = insn
|
||||
else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
assert!(target_pc.is_offset());
|
||||
if *is_index {
|
||||
let found = {
|
||||
let mut cursor = state.get_cursor(*cursor_id);
|
||||
let cursor = cursor.as_btree_mut();
|
||||
let record_from_regs = make_record(&state.registers, start_reg, num_regs);
|
||||
let found =
|
||||
return_if_io!(cursor.seek(SeekKey::IndexKey(&record_from_regs), SeekOp::GE));
|
||||
found
|
||||
};
|
||||
if !found {
|
||||
state.pc = target_pc.to_offset_int();
|
||||
} else {
|
||||
state.pc += 1;
|
||||
}
|
||||
} else {
|
||||
let pc = {
|
||||
let mut cursor = state.get_cursor(*cursor_id);
|
||||
let cursor = cursor.as_btree_mut();
|
||||
let rowid = match state.registers[*start_reg].get_owned_value() {
|
||||
OwnedValue::Null => {
|
||||
// All integer values are greater than null so we just rewind the cursor
|
||||
return_if_io!(cursor.rewind());
|
||||
None
|
||||
}
|
||||
OwnedValue::Integer(rowid) => Some(*rowid as u64),
|
||||
_ => {
|
||||
return Err(LimboError::InternalError(
|
||||
"SeekGE: the value in the register is not an integer".into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
match rowid {
|
||||
Some(rowid) => {
|
||||
let found = return_if_io!(cursor.seek(SeekKey::TableRowId(rowid), SeekOp::GE));
|
||||
if !found {
|
||||
target_pc.to_offset_int()
|
||||
} else {
|
||||
state.pc + 1
|
||||
}
|
||||
}
|
||||
None => state.pc + 1,
|
||||
}
|
||||
};
|
||||
state.pc = pc;
|
||||
}
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_seek_gt(
|
||||
program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
pager: &Rc<Pager>,
|
||||
mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::SeekGT {
|
||||
| Insn::SeekGT {
|
||||
cursor_id,
|
||||
start_reg,
|
||||
num_regs,
|
||||
target_pc,
|
||||
is_index,
|
||||
} = insn
|
||||
}
|
||||
| Insn::SeekLE {
|
||||
cursor_id,
|
||||
start_reg,
|
||||
num_regs,
|
||||
target_pc,
|
||||
is_index,
|
||||
}
|
||||
| Insn::SeekLT {
|
||||
cursor_id,
|
||||
start_reg,
|
||||
num_regs,
|
||||
target_pc,
|
||||
is_index,
|
||||
}) = insn
|
||||
else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
assert!(target_pc.is_offset());
|
||||
assert!(
|
||||
target_pc.is_offset(),
|
||||
"target_pc should be an offset, is: {:?}",
|
||||
target_pc
|
||||
);
|
||||
let op = match insn {
|
||||
Insn::SeekGE { .. } => SeekOp::GE,
|
||||
Insn::SeekGT { .. } => SeekOp::GT,
|
||||
Insn::SeekLE { .. } => SeekOp::LE,
|
||||
Insn::SeekLT { .. } => SeekOp::LT,
|
||||
_ => unreachable!("unexpected Insn {:?}", insn),
|
||||
};
|
||||
let op_name = match op {
|
||||
SeekOp::GE => "SeekGE",
|
||||
SeekOp::GT => "SeekGT",
|
||||
SeekOp::LE => "SeekLE",
|
||||
SeekOp::LT => "SeekLT",
|
||||
_ => unreachable!("unexpected SeekOp {:?}", op),
|
||||
};
|
||||
if *is_index {
|
||||
let found = {
|
||||
let mut cursor = state.get_cursor(*cursor_id);
|
||||
let cursor = cursor.as_btree_mut();
|
||||
let record_from_regs = make_record(&state.registers, start_reg, num_regs);
|
||||
let found =
|
||||
return_if_io!(cursor.seek(SeekKey::IndexKey(&record_from_regs), SeekOp::GT));
|
||||
let found = return_if_io!(cursor.seek(SeekKey::IndexKey(&record_from_regs), op));
|
||||
found
|
||||
};
|
||||
if !found {
|
||||
@@ -2002,14 +1974,15 @@ pub fn op_seek_gt(
|
||||
}
|
||||
OwnedValue::Integer(rowid) => Some(*rowid as u64),
|
||||
_ => {
|
||||
return Err(LimboError::InternalError(
|
||||
"SeekGT: the value in the register is not an integer".into(),
|
||||
));
|
||||
return Err(LimboError::InternalError(format!(
|
||||
"{}: the value in the register is not an integer",
|
||||
op_name
|
||||
)));
|
||||
}
|
||||
};
|
||||
let found = match rowid {
|
||||
Some(rowid) => {
|
||||
let found = return_if_io!(cursor.seek(SeekKey::TableRowId(rowid), SeekOp::GT));
|
||||
let found = return_if_io!(cursor.seek(SeekKey::TableRowId(rowid), op));
|
||||
if !found {
|
||||
target_pc.to_offset_int()
|
||||
} else {
|
||||
|
||||
@@ -736,23 +736,35 @@ pub fn insn_to_str(
|
||||
start_reg,
|
||||
num_regs: _,
|
||||
target_pc,
|
||||
} => (
|
||||
"SeekGT",
|
||||
*cursor_id as i32,
|
||||
target_pc.to_debug_int(),
|
||||
*start_reg as i32,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::SeekGE {
|
||||
}
|
||||
| Insn::SeekGE {
|
||||
is_index: _,
|
||||
cursor_id,
|
||||
start_reg,
|
||||
num_regs: _,
|
||||
target_pc,
|
||||
}
|
||||
| Insn::SeekLE {
|
||||
is_index: _,
|
||||
cursor_id,
|
||||
start_reg,
|
||||
num_regs: _,
|
||||
target_pc,
|
||||
}
|
||||
| Insn::SeekLT {
|
||||
is_index: _,
|
||||
cursor_id,
|
||||
start_reg,
|
||||
num_regs: _,
|
||||
target_pc,
|
||||
} => (
|
||||
"SeekGE",
|
||||
match insn {
|
||||
Insn::SeekGT { .. } => "SeekGT",
|
||||
Insn::SeekGE { .. } => "SeekGE",
|
||||
Insn::SeekLE { .. } => "SeekLE",
|
||||
Insn::SeekLT { .. } => "SeekLT",
|
||||
_ => unreachable!(),
|
||||
},
|
||||
*cursor_id as i32,
|
||||
target_pc.to_debug_int(),
|
||||
*start_reg as i32,
|
||||
@@ -1213,9 +1225,9 @@ pub fn insn_to_str(
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::LastAsync { .. } => (
|
||||
Insn::LastAsync { cursor_id } => (
|
||||
"LastAsync",
|
||||
0,
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
@@ -1240,27 +1252,27 @@ pub fn insn_to_str(
|
||||
0,
|
||||
where_clause.clone(),
|
||||
),
|
||||
Insn::LastAwait { .. } => (
|
||||
Insn::LastAwait { cursor_id, .. } => (
|
||||
"LastAwait",
|
||||
0,
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::PrevAsync { .. } => (
|
||||
Insn::PrevAsync { cursor_id } => (
|
||||
"PrevAsync",
|
||||
0,
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
0,
|
||||
"".to_string(),
|
||||
),
|
||||
Insn::PrevAwait { .. } => (
|
||||
Insn::PrevAwait { cursor_id, .. } => (
|
||||
"PrevAwait",
|
||||
0,
|
||||
*cursor_id as i32,
|
||||
0,
|
||||
0,
|
||||
OwnedValue::build_text(""),
|
||||
|
||||
@@ -501,6 +501,30 @@ pub enum Insn {
|
||||
|
||||
/// 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.
|
||||
// If cursor_id refers to an SQL table (B-Tree that uses integer keys), use the value in start_reg as the key.
|
||||
// If cursor_id refers to an SQL index, then start_reg is the first in an array of num_regs registers that are used as an unpacked index key.
|
||||
// Seek to the first index entry that is less than or equal to the given key. If not found, jump to the given PC. Otherwise, continue to the next instruction.
|
||||
SeekLE {
|
||||
is_index: bool,
|
||||
cursor_id: CursorID,
|
||||
start_reg: usize,
|
||||
num_regs: usize,
|
||||
target_pc: BranchOffset,
|
||||
},
|
||||
|
||||
// If cursor_id refers to an SQL table (B-Tree that uses integer keys), use the value in start_reg as the key.
|
||||
// If cursor_id refers to an SQL index, then start_reg is the first in an array of num_regs registers that are used as an unpacked index key.
|
||||
// Seek to the first index entry that is less than the given key. If not found, jump to the given PC. Otherwise, continue to the next instruction.
|
||||
SeekLT {
|
||||
is_index: bool,
|
||||
cursor_id: CursorID,
|
||||
start_reg: usize,
|
||||
num_regs: usize,
|
||||
target_pc: BranchOffset,
|
||||
},
|
||||
|
||||
// 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.
|
||||
IdxGE {
|
||||
cursor_id: CursorID,
|
||||
start_reg: usize,
|
||||
@@ -1306,8 +1330,10 @@ impl Insn {
|
||||
|
||||
Insn::SeekRowid { .. } => execute::op_seek_rowid,
|
||||
Insn::DeferredSeek { .. } => execute::op_deferred_seek,
|
||||
Insn::SeekGE { .. } => execute::op_seek_ge,
|
||||
Insn::SeekGT { .. } => execute::op_seek_gt,
|
||||
Insn::SeekGE { .. } => execute::op_seek,
|
||||
Insn::SeekGT { .. } => execute::op_seek,
|
||||
Insn::SeekLE { .. } => execute::op_seek,
|
||||
Insn::SeekLT { .. } => execute::op_seek,
|
||||
Insn::SeekEnd { .. } => execute::op_seek_end,
|
||||
Insn::IdxGE { .. } => execute::op_idx_ge,
|
||||
Insn::IdxGT { .. } => execute::op_idx_gt,
|
||||
|
||||
@@ -561,7 +561,10 @@ fn get_indent_count(indent_count: usize, curr_insn: &Insn, prev_insn: Option<&In
|
||||
| Insn::LastAwait { .. }
|
||||
| Insn::SorterSort { .. }
|
||||
| Insn::SeekGE { .. }
|
||||
| Insn::SeekGT { .. } => indent_count + 1,
|
||||
| Insn::SeekGT { .. }
|
||||
| Insn::SeekLE { .. }
|
||||
| Insn::SeekLT { .. } => indent_count + 1,
|
||||
|
||||
_ => indent_count,
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user