ephemeral table for update when rowid is being update

This commit is contained in:
pedrocarlo 2025-06-12 19:59:05 -03:00
parent edc6eb9a36
commit 74beac5ea8
6 changed files with 230 additions and 91 deletions

View file

@ -6610,7 +6610,8 @@ mod tests {
let page = page.get();
let page = page.get_contents();
let header_size = 8;
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(1))]);
let regs = &[Register::Value(Value::Integer(1))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let payload = add_record(1, 0, page, record, &conn);
assert_eq!(page.cell_count(), 1);
let free = compute_free_space(page, 4096);
@ -6639,8 +6640,8 @@ mod tests {
let mut cells = Vec::new();
let usable_space = 4096;
for i in 0..3 {
let record =
ImmutableRecord::from_registers(&[Register::Value(Value::Integer(i as i64))]);
let regs = &[Register::Value(Value::Integer(i as i64))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let payload = add_record(i, i, page, record, &conn);
assert_eq!(page.cell_count(), i + 1);
let free = compute_free_space(page, usable_space);
@ -6928,10 +6929,8 @@ mod tests {
pager.deref(),
)
.unwrap();
let value = ImmutableRecord::from_registers(&[Register::Value(Value::Blob(vec![
0;
*size
]))]);
let regs = &[Register::Value(Value::Blob(vec![0; *size]))];
let value = ImmutableRecord::from_registers(regs, regs.len());
tracing::info!("insert key:{}", key);
run_until_done(
|| cursor.insert(&BTreeKey::new_table_rowid(*key, Some(&value)), true),
@ -7022,8 +7021,8 @@ mod tests {
pager.deref(),
)
.unwrap();
let value =
ImmutableRecord::from_registers(&[Register::Value(Value::Blob(vec![0; size]))]);
let regs = &[Register::Value(Value::Blob(vec![0; size]))];
let value = ImmutableRecord::from_registers(regs, regs.len());
let btree_before = if do_validate {
format_btree(pager.clone(), root_page, 0)
} else {
@ -7143,11 +7142,11 @@ mod tests {
};
tracing::info!("insert {}/{}: {:?}", i + 1, inserts, key);
keys.push(key.clone());
let value = ImmutableRecord::from_registers(
&key.iter()
.map(|col| Register::Value(Value::Integer(*col)))
.collect::<Vec<_>>(),
);
let regs = key
.iter()
.map(|col| Register::Value(Value::Integer(*col)))
.collect::<Vec<_>>();
let value = ImmutableRecord::from_registers(&regs, regs.len());
run_until_done(
|| {
cursor.insert(
@ -7176,12 +7175,12 @@ mod tests {
tracing::info!("seeking key {}/{}: {:?}", i + 1, keys.len(), key);
let exists = run_until_done(
|| {
let regs = key
.iter()
.map(|col| Register::Value(Value::Integer(*col)))
.collect::<Vec<_>>();
cursor.seek(
SeekKey::IndexKey(&ImmutableRecord::from_registers(
&key.iter()
.map(|col| Register::Value(Value::Integer(*col)))
.collect::<Vec<_>>(),
)),
SeekKey::IndexKey(&ImmutableRecord::from_registers(&regs, regs.len())),
SeekOp::GE { eq_only: true },
)
},
@ -7244,8 +7243,8 @@ mod tests {
let usable_space = 4096;
let total_cells = 10;
for i in 0..total_cells {
let record =
ImmutableRecord::from_registers(&[Register::Value(Value::Integer(i as i64))]);
let regs = &[Register::Value(Value::Integer(i as i64))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let payload = add_record(i, i, page, record, &conn);
assert_eq!(page.cell_count(), i + 1);
let free = compute_free_space(page, usable_space);
@ -7650,8 +7649,8 @@ mod tests {
let mut cells = Vec::new();
let usable_space = 4096;
for i in 0..3 {
let record =
ImmutableRecord::from_registers(&[Register::Value(Value::Integer(i as i64))]);
let regs = &[Register::Value(Value::Integer(i as i64))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let payload = add_record(i, i, page, record, &conn);
assert_eq!(page.cell_count(), i + 1);
let free = compute_free_space(page, usable_space);
@ -7692,8 +7691,8 @@ mod tests {
let usable_space = 4096;
let total_cells = 10;
for i in 0..total_cells {
let record =
ImmutableRecord::from_registers(&[Register::Value(Value::Integer(i as i64))]);
let regs = &[Register::Value(Value::Integer(i as i64))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let payload = add_record(i, i, page, record, &conn);
assert_eq!(page.cell_count(), i + 1);
let free = compute_free_space(page, usable_space);
@ -7748,9 +7747,8 @@ mod tests {
// allow appends with extra place to insert
let cell_idx = rng.next_u64() as usize % (page.cell_count() + 1);
let free = compute_free_space(page, usable_space);
let record = ImmutableRecord::from_registers(&[Register::Value(
Value::Integer(i as i64),
)]);
let regs = &[Register::Value(Value::Integer(i as i64))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let mut payload: Vec<u8> = Vec::new();
fill_cell_payload(
page.page_type(),
@ -7827,9 +7825,8 @@ mod tests {
// allow appends with extra place to insert
let cell_idx = rng.next_u64() as usize % (page.cell_count() + 1);
let free = compute_free_space(page, usable_space);
let record = ImmutableRecord::from_registers(&[Register::Value(
Value::Integer(i as i64),
)]);
let regs = &[Register::Value(Value::Integer(i as i64))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let mut payload: Vec<u8> = Vec::new();
fill_cell_payload(
page.page_type(),
@ -7987,7 +7984,8 @@ mod tests {
let header_size = 8;
let usable_space = 4096;
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let payload = add_record(0, 0, page, record, &conn);
let free = compute_free_space(page, usable_space);
assert_eq!(free, 4096 - payload.len() as u16 - 2 - header_size);
@ -8003,7 +8001,8 @@ mod tests {
let page = page.get_contents();
let usable_space = 4096;
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let payload = add_record(0, 0, page, record, &conn);
assert_eq!(page.cell_count(), 1);
@ -8029,17 +8028,19 @@ mod tests {
let page = page.get_contents();
let usable_space = 4096;
let record = ImmutableRecord::from_registers(&[
let regs = &[
Register::Value(Value::Integer(0)),
Register::Value(Value::Text(Text::new("aaaaaaaa"))),
]);
];
let record = ImmutableRecord::from_registers(regs, regs.len());
let _ = add_record(0, 0, page, record, &conn);
assert_eq!(page.cell_count(), 1);
drop_cell(page, 0, usable_space).unwrap();
assert_eq!(page.cell_count(), 0);
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let payload = add_record(0, 0, page, record, &conn);
assert_eq!(page.cell_count(), 1);
@ -8063,10 +8064,11 @@ mod tests {
let page = page.get_contents();
let usable_space = 4096;
let record = ImmutableRecord::from_registers(&[
let regs = &[
Register::Value(Value::Integer(0)),
Register::Value(Value::Text(Text::new("aaaaaaaa"))),
]);
];
let record = ImmutableRecord::from_registers(regs, regs.len());
let _ = add_record(0, 0, page, record, &conn);
for _ in 0..100 {
@ -8074,7 +8076,8 @@ mod tests {
drop_cell(page, 0, usable_space).unwrap();
assert_eq!(page.cell_count(), 0);
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let payload = add_record(0, 0, page, record, &conn);
assert_eq!(page.cell_count(), 1);
@ -8099,11 +8102,14 @@ mod tests {
let page = page.get_contents();
let usable_space = 4096;
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let payload = add_record(0, 0, page, record, &conn);
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(1))]);
let regs = &[Register::Value(Value::Integer(1))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let _ = add_record(1, 1, page, record, &conn);
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(2))]);
let regs = &[Register::Value(Value::Integer(2))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let _ = add_record(2, 2, page, record, &conn);
drop_cell(page, 1, usable_space).unwrap();
@ -8122,21 +8128,25 @@ mod tests {
let page = page.get_contents();
let usable_space = 4096;
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let _ = add_record(0, 0, page, record, &conn);
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let _ = add_record(0, 0, page, record, &conn);
drop_cell(page, 0, usable_space).unwrap();
defragment_page(page, usable_space);
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let _ = add_record(0, 1, page, record, &conn);
drop_cell(page, 0, usable_space).unwrap();
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let _ = add_record(0, 1, page, record, &conn);
}
@ -8148,7 +8158,8 @@ mod tests {
let page = get_page(2);
let usable_space = 4096;
let insert = |pos, page| {
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let _ = add_record(0, pos, page, record, &conn);
};
let drop = |pos, page| {
@ -8188,7 +8199,8 @@ mod tests {
let page = get_page(2);
let usable_space = 4096;
let insert = |pos, page| {
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let _ = add_record(0, pos, page, record, &conn);
};
let drop = |pos, page| {
@ -8197,7 +8209,8 @@ mod tests {
let defragment = |page| {
defragment_page(page, usable_space);
};
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(0))]);
let regs = &[Register::Value(Value::Integer(0))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let mut payload: Vec<u8> = Vec::new();
fill_cell_payload(
page.get().get_contents().page_type(),
@ -8231,7 +8244,8 @@ mod tests {
for i in 0..10000 {
let mut cursor = BTreeCursor::new_table(None, pager.clone(), root_page);
tracing::info!("INSERT INTO t VALUES ({});", i,);
let value = ImmutableRecord::from_registers(&[Register::Value(Value::Integer(i))]);
let regs = &[Register::Value(Value::Integer(i))];
let value = ImmutableRecord::from_registers(regs, regs.len());
tracing::trace!("before insert {}", i);
run_until_done(
|| {
@ -8270,8 +8284,8 @@ mod tests {
let page = get_page(2);
let usable_space = 4096;
let record =
ImmutableRecord::from_registers(&[Register::Value(Value::Blob(vec![0; 3600]))]);
let regs = &[Register::Value(Value::Blob(vec![0; 3600]))];
let record = ImmutableRecord::from_registers(regs, regs.len());
let mut payload: Vec<u8> = Vec::new();
fill_cell_payload(
page.get().get_contents().page_type(),
@ -8306,9 +8320,8 @@ mod tests {
// Insert 10,000 records in to the BTree.
for i in 1..=10000 {
let mut cursor = BTreeCursor::new_table(None, pager.clone(), root_page);
let value = ImmutableRecord::from_registers(&[Register::Value(Value::Text(
Text::new("hello world"),
))]);
let regs = &[Register::Value(Value::Text(Text::new("hello world")))];
let value = ImmutableRecord::from_registers(regs, regs.len());
run_until_done(
|| {
@ -8385,10 +8398,11 @@ mod tests {
for i in 0..iterations {
let mut cursor = BTreeCursor::new_table(None, pager.clone(), root_page);
tracing::info!("INSERT INTO t VALUES ({});", i,);
let value = ImmutableRecord::from_registers(&[Register::Value(Value::Text(Text {
let regs = &[Register::Value(Value::Text(Text {
value: huge_texts[i].as_bytes().to_vec(),
subtype: crate::types::TextSubtype::Text,
}))]);
}))];
let value = ImmutableRecord::from_registers(regs, regs.len());
tracing::trace!("before insert {}", i);
tracing::debug!(
"=========== btree before ===========\n{}\n\n",
@ -8433,8 +8447,8 @@ mod tests {
let offset = 2; // blobs data starts at offset 2
let initial_text = "hello world";
let initial_blob = initial_text.as_bytes().to_vec();
let value =
ImmutableRecord::from_registers(&[Register::Value(Value::Blob(initial_blob.clone()))]);
let regs = &[Register::Value(Value::Blob(initial_blob.clone()))];
let value = ImmutableRecord::from_registers(regs, regs.len());
run_until_done(
|| {
@ -8509,8 +8523,8 @@ mod tests {
let mut large_blob = vec![b'A'; 40960 - 11]; // insert large blob. 40960 = 10 page long.
let hello_world = b"hello world";
large_blob.extend_from_slice(hello_world);
let value =
ImmutableRecord::from_registers(&[Register::Value(Value::Blob(large_blob.clone()))]);
let regs = &[Register::Value(Value::Blob(large_blob.clone()))];
let value = ImmutableRecord::from_registers(regs, regs.len());
run_until_done(
|| {
@ -8700,10 +8714,8 @@ mod tests {
page_type: PageType,
) {
let mut payload = Vec::new();
let record = ImmutableRecord::from_registers(&[Register::Value(Value::Blob(vec![
0;
size as usize
]))]);
let regs = &[Register::Value(Value::Blob(vec![0; size as usize]))];
let record = ImmutableRecord::from_registers(regs, regs.len());
fill_cell_payload(
page_type,
Some(i as i64),

View file

@ -22,13 +22,14 @@ use super::select::emit_simple_count;
use super::subquery::emit_subqueries;
use crate::error::SQLITE_CONSTRAINT_PRIMARYKEY;
use crate::function::Func;
use crate::schema::Schema;
use crate::schema::{BTreeTable, Column, Index, IndexColumn, Schema, Table, Type};
use crate::translate::compound_select::emit_program_for_compound_select;
use crate::translate::plan::{DeletePlan, Plan, Search};
use crate::translate::values::emit_values;
use crate::util::exprs_are_equivalent;
use crate::vdbe::builder::{CursorKey, CursorType, ProgramBuilder};
use crate::vdbe::insn::{CmpInsFlags, IdxInsertFlags, InsertFlags, RegisterOrLiteral};
use crate::vdbe::CursorID;
use crate::vdbe::{insn::Insn, BranchOffset};
use crate::{Result, SymbolTable};
@ -348,13 +349,20 @@ pub fn emit_query<'a>(
&plan.table_references,
&plan.join_order,
&mut plan.where_clause,
None,
)?;
// Process result columns and expressions in the inner loop
emit_loop(program, t_ctx, plan)?;
// Clean up and close the main execution loop
close_loop(program, t_ctx, &plan.table_references, &plan.join_order)?;
close_loop(
program,
t_ctx,
&plan.table_references,
&plan.join_order,
None,
)?;
program.preassign_label_to_next_insn(after_main_loop_label);
@ -439,6 +447,7 @@ fn emit_program_for_delete(
&plan.table_references,
&[JoinOrderMember::default()],
&mut plan.where_clause,
None,
)?;
emit_delete_insns(program, &mut t_ctx, &plan.table_references)?;
@ -449,6 +458,7 @@ fn emit_program_for_delete(
&mut t_ctx,
&plan.table_references,
&[JoinOrderMember::default()],
None,
)?;
program.preassign_label_to_next_insn(after_main_loop_label);
@ -603,6 +613,29 @@ fn emit_program_for_update(
});
}
let temp_cursor_id = {
// Sqlite determines we should create an ephemeral table if we do not have a FROM clause
// Difficult to say what items from the plan can be checked for this so currently just checking the where clause
// https://github.com/sqlite/sqlite/blob/master/src/update.c#L395
// https://github.com/sqlite/sqlite/blob/master/src/update.c#L670
if !plan.where_clause.is_empty() {
None
} else {
let table_ref = plan
.table_references
.joined_tables()
.first()
.expect("at least one table needs to be referenced for UPDATE");
let columns = table_ref.columns();
let rowid_alias_used = plan.set_clauses.iter().fold(false, |accum, (idx, _)| {
accum || columns[*idx].is_rowid_alias
});
rowid_alias_used.then(|| emit_ephemeral(program, &table_ref.table))
}
};
init_loop(
program,
&mut t_ctx,
@ -643,14 +676,16 @@ fn emit_program_for_update(
&plan.table_references,
&[JoinOrderMember::default()],
&mut plan.where_clause,
temp_cursor_id,
)?;
emit_update_insns(&plan, &t_ctx, program, index_cursors)?;
emit_update_insns(&plan, &t_ctx, program, index_cursors, temp_cursor_id)?;
close_loop(
program,
&mut t_ctx,
&plan.table_references,
&[JoinOrderMember::default()],
temp_cursor_id,
)?;
program.preassign_label_to_next_insn(after_main_loop_label);
@ -670,12 +705,13 @@ fn emit_update_insns(
t_ctx: &TranslateCtx,
program: &mut ProgramBuilder,
index_cursors: Vec<(usize, usize)>,
temp_cursor_id: Option<CursorID>,
) -> crate::Result<()> {
let table_ref = plan.table_references.joined_tables().first().unwrap();
let loop_labels = t_ctx.labels_main_loop.first().unwrap();
let (cursor_id, index, is_virtual) = match &table_ref.op {
let cursor_id = program.resolve_cursor_id(&CursorKey::table(table_ref.internal_id));
let (index, is_virtual) = match &table_ref.op {
Operation::Scan { index, .. } => (
program.resolve_cursor_id(&CursorKey::table(table_ref.internal_id)),
index.as_ref().map(|index| {
(
index.clone(),
@ -686,15 +722,10 @@ fn emit_update_insns(
table_ref.virtual_table().is_some(),
),
Operation::Search(search) => match search {
&Search::RowidEq { .. } | Search::Seek { index: None, .. } => (
program.resolve_cursor_id(&CursorKey::table(table_ref.internal_id)),
None,
false,
),
&Search::RowidEq { .. } | Search::Seek { index: None, .. } => (None, false),
Search::Seek {
index: Some(index), ..
} => (
program.resolve_cursor_id(&CursorKey::table(table_ref.internal_id)),
Some((
index.clone(),
program
@ -714,7 +745,7 @@ fn emit_update_insns(
},
);
program.emit_insn(Insn::RowId {
cursor_id,
cursor_id: temp_cursor_id.unwrap_or(cursor_id),
dest: beg,
});
@ -1107,3 +1138,77 @@ fn init_limit(
});
}
}
/// Emits an ephemeral table that reads the rowids from `table`
fn emit_ephemeral(program: &mut ProgramBuilder, table: &Table) -> CursorID {
let cursor_type = CursorType::BTreeTable(table.btree().unwrap());
let cursor_id = program.alloc_cursor_id(cursor_type);
let simple_table_rc = Rc::new(BTreeTable {
root_page: 0, // Not relevant for ephemeral table definition
name: "ephemeral_scratch".to_string(),
has_rowid: true,
primary_key_columns: vec![],
columns: vec![Column {
name: Some("rowid".to_string()),
ty: Type::Integer,
ty_str: "INTEGER".to_string(),
primary_key: false,
is_rowid_alias: false,
notnull: false,
default: None,
unique: false,
collation: None,
}],
is_strict: false,
unique_sets: None,
});
let temp_cursor_id = program.alloc_cursor_id(CursorType::BTreeTable(simple_table_rc));
let null_data_reg = program.alloc_register();
let rowid_reg = program.alloc_register();
program.emit_insn(Insn::Null {
dest: null_data_reg,
dest_end: Some(rowid_reg),
});
program.emit_insn(Insn::OpenEphemeral {
cursor_id: temp_cursor_id,
is_table: true,
});
program.emit_insn(Insn::OpenRead {
cursor_id,
root_page: table.get_root_page(),
});
let loop_labels = LoopLabels::new(program);
program.emit_insn(Insn::Rewind {
cursor_id,
pc_if_empty: loop_labels.loop_end,
});
program.preassign_label_to_next_insn(loop_labels.loop_start);
program.emit_insn(Insn::RowId {
cursor_id,
dest: rowid_reg,
});
program.emit_insn(Insn::Insert {
cursor: temp_cursor_id,
key_reg: rowid_reg,
record_reg: null_data_reg,
flag: InsertFlags(0), // TODO: when we use the flags see if this needs to change
table_name: table.get_name().to_string(),
});
program.preassign_label_to_next_insn(loop_labels.next);
program.emit_insn(Insn::Next {
cursor_id,
pc_if_next: loop_labels.loop_start,
});
program.preassign_label_to_next_insn(loop_labels.loop_end);
temp_cursor_id
}

View file

@ -357,6 +357,7 @@ pub fn open_loop(
table_references: &TableReferences,
join_order: &[JoinOrderMember],
predicates: &[WhereTerm],
temp_cursor_id: Option<CursorID>,
) -> Result<()> {
for (join_index, join) in join_order.iter().enumerate() {
let joined_table_index = join.original_idx;
@ -389,8 +390,11 @@ pub fn open_loop(
Operation::Scan { iter_dir, .. } => {
match &table.table {
Table::BTree(_) => {
let iteration_cursor_id = index_cursor_id.unwrap_or_else(|| {
table_cursor_id.expect("Either index or table cursor must be opened")
let iteration_cursor_id = temp_cursor_id.unwrap_or_else(|| {
index_cursor_id.unwrap_or_else(|| {
table_cursor_id
.expect("Either index or table cursor must be opened")
})
});
if *iter_dir == IterationDirection::Backwards {
program.emit_insn(Insn::Last {
@ -971,6 +975,7 @@ pub fn close_loop(
t_ctx: &mut TranslateCtx,
tables: &TableReferences,
join_order: &[JoinOrderMember],
temp_cursor_id: Option<CursorID>,
) -> Result<()> {
// We close the loops for all tables in reverse order, i.e. innermost first.
// OPEN t1
@ -995,8 +1000,11 @@ pub fn close_loop(
program.resolve_label(loop_labels.next, program.offset());
match &table.table {
Table::BTree(_) => {
let iteration_cursor_id = index_cursor_id.unwrap_or_else(|| {
table_cursor_id.expect("Either index or table cursor must be opened")
let iteration_cursor_id = temp_cursor_id.unwrap_or_else(|| {
index_cursor_id.unwrap_or_else(|| {
table_cursor_id
.expect("Either index or table cursor must be opened")
})
});
if *iter_dir == IterationDirection::Backwards {
program.emit_insn(Insn::Prev {

View file

@ -859,15 +859,18 @@ impl ImmutableRecord {
self.values.len()
}
pub fn from_registers(registers: &[Register]) -> Self {
let mut values = Vec::with_capacity(registers.len());
let mut serials = Vec::with_capacity(registers.len());
pub fn from_registers<'a>(
registers: impl IntoIterator<Item = &'a Register> + Clone,
len: usize,
) -> Self {
let mut values = Vec::with_capacity(len);
let mut serials = Vec::with_capacity(len);
let mut size_header = 0;
let mut size_values = 0;
let mut serial_type_buf = [0; 9];
// write serial types
for value in registers {
for value in registers.clone() {
let value = value.get_owned_value();
let serial_type = SerialType::from(value);
let n = write_varint(&mut serial_type_buf[0..], serial_type.into());

View file

@ -4236,15 +4236,25 @@ pub fn op_insert(
{
let mut cursor = state.get_cursor(*cursor);
let cursor = cursor.as_btree_mut();
let record = match &state.registers[*record_reg] {
Register::Record(r) => r,
_ => unreachable!("Not a record! Cannot insert a non record value."),
};
let key = match &state.registers[*key_reg].get_owned_value() {
Value::Integer(i) => *i,
_ => unreachable!("expected integer key"),
};
return_if_io!(cursor.insert(&BTreeKey::new_table_rowid(key, Some(record)), true));
let record = match &state.registers[*record_reg] {
Register::Record(r) => std::borrow::Cow::Borrowed(r),
Register::Value(value) => {
let x = 1;
let regs = &state.registers[*record_reg..*record_reg + 1];
let new_regs = [&state.registers[*record_reg]];
let record = ImmutableRecord::from_registers(new_regs, new_regs.len());
std::borrow::Cow::Owned(record)
}
Register::Aggregate(..) => unreachable!("Cannot insert an aggregate value."),
};
return_if_io!(cursor.insert(&BTreeKey::new_table_rowid(key, Some(record.as_ref())), true));
// Only update last_insert_rowid for regular table inserts, not schema modifications
if cursor.root_page() != 1 {
if let Some(rowid) = return_if_io!(cursor.rowid()) {

View file

@ -522,7 +522,8 @@ fn get_new_rowid<R: Rng>(cursor: &mut BTreeCursor, mut rng: R) -> Result<CursorR
}
fn make_record(registers: &[Register], start_reg: &usize, count: &usize) -> ImmutableRecord {
ImmutableRecord::from_registers(&registers[*start_reg..*start_reg + *count])
let regs = &registers[*start_reg..*start_reg + *count];
ImmutableRecord::from_registers(regs, regs.len())
}
#[instrument(skip(program), level = Level::TRACE)]