From a9cb8157b548c3632ef40959bd6745ecc50a7eda Mon Sep 17 00:00:00 2001 From: gandeevanr Date: Wed, 7 Aug 2024 09:03:24 -0700 Subject: [PATCH] initial pass at implementing NewRowId --- core/pseudo.rs | 4 +++ core/storage/btree.rs | 68 ++++++++++++++++++++++++++++++++++++++++ core/translate/insert.rs | 2 +- core/types.rs | 1 + core/vdbe/explain.rs | 8 ++--- core/vdbe/mod.rs | 15 +++++++-- core/vdbe/sorter.rs | 4 +++ 7 files changed, 95 insertions(+), 7 deletions(-) diff --git a/core/pseudo.rs b/core/pseudo.rs index b05fa834f..7f4d94e08 100644 --- a/core/pseudo.rs +++ b/core/pseudo.rs @@ -50,6 +50,10 @@ impl Cursor for PseudoCursor { unimplemented!(); } + fn seek_to_last(&mut self) -> Result> { + unimplemented!(); + } + fn record(&self) -> Result>> { Ok(self.current.borrow()) } diff --git a/core/storage/btree.rs b/core/storage/btree.rs index e1fe41990..0bf6f4559 100644 --- a/core/storage/btree.rs +++ b/core/storage/btree.rs @@ -72,6 +72,18 @@ impl BTreeCursor { } } + fn is_empty_table(&mut self) -> Result> { + let page = self.pager.read_page(self.root_page)?; + let page = RefCell::borrow(&page); + if page.is_locked() { + return Ok(CursorResult::IO); + } + + let page = page.contents.read().unwrap(); + let page = page.as_ref().unwrap(); + Ok(CursorResult::Ok(page.cell_count() == 0)) + } + fn get_next_record(&mut self) -> Result, Option)>> { loop { let mem_page = { @@ -184,6 +196,42 @@ impl BTreeCursor { .replace(Some(Rc::new(MemPage::new(None, self.root_page, 0)))); } + fn move_to_rightmost(&mut self) -> Result> { + self.move_to_root(); + + loop { + let mem_page = self.page.borrow().as_ref().unwrap().clone(); + let page_idx = mem_page.page_idx; + let page = self.pager.read_page(page_idx)?; + let page = RefCell::borrow(&page); + if page.is_locked() { + return Ok(CursorResult::IO); + } + let page = page.contents.read().unwrap(); + let page = page.as_ref().unwrap(); + if page.is_leaf() { + if page.cell_count() > 0 { + mem_page.cell_idx.replace(page.cell_count()-1); + } + return Ok(CursorResult::Ok(())); + } + + match page.rightmost_pointer() { + Some(right_most_pointer) => { + mem_page.cell_idx.replace(page.cell_count()); + let mem_page = + MemPage::new(Some(mem_page.clone()), right_most_pointer as usize, 0); + self.page.replace(Some(Rc::new(mem_page))); + continue; + }, + + None => { + unreachable!("interior page should have a rightmost pointer"); + } + } + } + } + pub fn move_to(&mut self, key: u64) -> Result> { // For a table with N rows, we can find any row by row id in O(log(N)) time by starting at the root page and following the B-tree pointers. // B-trees consist of interior pages and leaf pages. Interior pages contain pointers to other pages, while leaf pages contain the actual row data. @@ -827,6 +875,26 @@ fn find_free_cell(page_ref: &PageContent, db_header: Ref, amount } impl Cursor for BTreeCursor { + fn seek_to_last(&mut self) -> Result> { + self.move_to_rightmost()?; + match self.get_next_record()? { + CursorResult::Ok((rowid, next)) => { + if rowid.is_none() { + match self.is_empty_table()? { + CursorResult::Ok(is_empty) => { + assert!(is_empty) + }, + CursorResult::IO => (), + } + } + self.rowid.replace(rowid); + self.record.replace(next); + Ok(CursorResult::Ok(())) + } + CursorResult::IO => Ok(CursorResult::IO), + } + } + fn is_empty(&self) -> bool { self.record.borrow().is_none() } diff --git a/core/translate/insert.rs b/core/translate/insert.rs index 8d525d719..823510dd5 100644 --- a/core/translate/insert.rs +++ b/core/translate/insert.rs @@ -148,7 +148,7 @@ pub fn translate_insert( }, notnull_label, ); - program.emit_insn(Insn::NewRowid { reg: row_id_reg }); + program.emit_insn(Insn::NewRowid { cursor: cursor_id, rowid_reg: row_id_reg, prev_largest_reg: 0 }); program.resolve_label(notnull_label, program.offset()); program.emit_insn(Insn::MustBeInt { reg: row_id_reg }); diff --git a/core/types.rs b/core/types.rs index cc0165a61..d7d06c772 100644 --- a/core/types.rs +++ b/core/types.rs @@ -370,6 +370,7 @@ pub trait Cursor { fn wait_for_completion(&mut self) -> Result<()>; fn rowid(&self) -> Result>; fn seek_rowid(&mut self, rowid: u64) -> Result>; + fn seek_to_last(&mut self) -> Result>; fn record(&self) -> Result>>; fn insert( &mut self, diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index 53020cd3c..ded6f0152 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -602,11 +602,11 @@ pub fn insn_to_str( 0, "".to_string(), ), - Insn::NewRowid { reg } => ( + Insn::NewRowid { cursor, rowid_reg, prev_largest_reg } => ( "NewRowId", - 0, - *reg as i32, - 0, + *cursor as i32, + *rowid_reg as i32, + *prev_largest_reg as i32, OwnedValue::Text(Rc::new("".to_string())), 0, "".to_string(), diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 67ce34f72..8c3a4c3f0 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -333,7 +333,9 @@ pub enum Insn { }, NewRowid { - reg: usize, + cursor: CursorID, // P1 + rowid_reg: usize, // P2 Destination register to store the new rowid + prev_largest_reg: usize // P3 Previous largest rowid in the table (Not used for now) }, MustBeInt { @@ -1412,7 +1414,16 @@ impl Program { cursor.wait_for_completion()?; state.pc += 1; } - Insn::NewRowid { reg: _ } => todo!(), + Insn::NewRowid { cursor, rowid_reg, .. } => { + let cursor = cursors.get_mut(cursor).unwrap(); + cursor.seek_to_last()?; + if let Some(rowid) = cursor.rowid()? { + state.registers[*rowid_reg] = OwnedValue::Integer((rowid+1) as i64); + } else { + state.registers[*rowid_reg] = OwnedValue::Integer(1); + } + state.pc += 1; + }, Insn::MustBeInt { reg } => { match state.registers[*reg] { OwnedValue::Integer(_) => {} diff --git a/core/vdbe/sorter.rs b/core/vdbe/sorter.rs index e489a99a4..b80ab6074 100644 --- a/core/vdbe/sorter.rs +++ b/core/vdbe/sorter.rs @@ -79,6 +79,10 @@ impl Cursor for Sorter { unimplemented!(); } + fn seek_to_last(&mut self) -> Result> { + unimplemented!(); + } + fn record(&self) -> Result>> { Ok(self.current.borrow()) }