writes the database file, needs bugfixing

This commit is contained in:
Sander Hautvast 2022-10-30 11:38:23 +01:00
parent 7a475577f2
commit 74baede692
4 changed files with 95 additions and 18 deletions

View file

@ -1,4 +1,24 @@
# Sqlighte.Rs # Sqlighte.Rs
* rust version of https://gitlab.com/sander-hautvast/sqlighter * rust version of https://gitlab.com/sander-hautvast/sqlighter
* still very much work in progress * still work in progress
Creating a database will be as simple as:
```rust
fn test_build() -> Result<(), Error> {
let mut builder = Builder::new();
builder.schema(
"foo",
"create table foo(bar varchar(10))",
);
let mut record = Record::new(1);
record.add_value(values::string("helloworld"));
builder.add_record(record);
let database: Database = builder.into();
let file = File::create("foo.db")?;
let writer = BufWriter::new(file);
write(database, writer)?;
Ok(())
}
```

View file

@ -10,11 +10,16 @@ pub struct Builder {
schema: Option<SchemaRecord>, schema: Option<SchemaRecord>,
} }
fn new_page() -> Page {
let mut page = Page::new_leaf();
page.fw_position = 8;
page
}
impl Builder { impl Builder {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
current_page: Page::new_leaf(), current_page: new_page(),
n_records_on_current_page: 0, n_records_on_current_page: 0,
leaf_pages: Vec::new(), leaf_pages: Vec::new(),
schema: None, schema: None,
@ -24,7 +29,7 @@ impl Builder {
pub fn add_record(&mut self, record: Record) { pub fn add_record(&mut self, record: Record) {
if self.current_page_is_full(&record) { if self.current_page_is_full(&record) {
self.finish_current_page(); self.finish_current_page();
self.leaf_pages.push(mem::replace(&mut self.current_page, Page::new_leaf())); self.leaf_pages.push(mem::replace(&mut self.current_page, new_page()));
self.n_records_on_current_page = 0; self.n_records_on_current_page = 0;
} }
@ -61,6 +66,7 @@ impl Into<Database> for Builder {
self.current_page.put_u16(self.current_page.bw_position - 1); self.current_page.put_u16(self.current_page.bw_position - 1);
} }
self.leaf_pages.push(self.current_page);
Database::new(self.schema.unwrap(), self.leaf_pages) //panics is schema is not set Database::new(self.schema.unwrap(), self.leaf_pages) //panics is schema is not set
} }
} }
@ -85,7 +91,7 @@ mod tests {
builder.add_record(record); builder.add_record(record);
let database: Database = builder.into(); let database: Database = builder.into();
let file = File::create("foo.txt")?; let file = File::create("foo.db")?;
let writer = BufWriter::new(file); let writer = BufWriter::new(file);
write(database, writer)?; write(database, writer)?;
Ok(()) Ok(())

View file

@ -2,7 +2,7 @@ use std::io::{BufWriter, Error, Write};
use std::mem; use std::mem;
use crate::varint; use crate::varint;
use crate::page; use crate::page;
use crate::page::Page; use crate::page::{Page, PageType};
use crate::record::Record; use crate::record::Record;
use crate::values; use crate::values;
@ -53,17 +53,60 @@ impl Into<Record> for SchemaRecord {
pub fn write<W: Write>(database: Database, mut writer: BufWriter<W>) -> Result<(), Error> { pub fn write<W: Write>(database: Database, mut writer: BufWriter<W>) -> Result<(), Error> {
let mut current_top_layer = database.leaf_pages; let mut current_top_layer = database.leaf_pages;
let mut n_pages = current_top_layer.len(); let mut n_pages = current_top_layer.len();
while current_top_layer.len() > 1 { // interior page needed? while current_top_layer.len() > 1 { // db needs interior pages?
current_top_layer = create_interior_pages(current_top_layer); current_top_layer = create_interior_pages(current_top_layer);
n_pages += current_top_layer.len(); n_pages += current_top_layer.len();
} }
let table_root_page = current_top_layer.get(0); // let table_root_page = current_top_layer.get_mut(0).unwrap();
writer.write_all(&create_header_page(n_pages + 1, database.schema).data)?; // 1 for header page writer.write_all(&create_header_page(n_pages + 1, database.schema).data)?; // 1 for header page
//
// recursiveAssignPagenumbers(table_root_page); // 3 extra passes... :( assign_pagenumbers(table_root_page, 2);
// recursiveSetPageReferences(table_root_page); // don't think combining is possible set_page_references(table_root_page);
// recursiveWritePages(channel, table_root_page); write_pages(&mut writer, table_root_page)?;
Ok(())
}
fn assign_pagenumbers(page: &mut Page, page_counter: u32) {
page.number = page_counter;
let mut counter = page_counter;
for child in page.children.iter_mut() {
counter += 1;
assign_pagenumbers(child, counter);
}
}
fn set_page_references(page: &mut Page) {
if let PageType::Interior = page.page_type {
page.fw_position = page::POSITION_CELL_COUNT;
page.put_u16((page.children.len() - 1) as u16);
page.fw_position = page::POSITION_RIGHTMOST_POINTER_LEAFPAGES;
page.put_u32(page.get_page_nr_last_child());
let index = 0;
let before_last = page.children.len() - 1;
let child_numbers: Vec<u32> = page.children.iter().map(|child| child.number).collect();
for child_page_number in child_numbers {
if index < before_last {
page.fw_position = page::START_OF_INTERIOR_PAGE + (index as u16) * 2;
page.fw_position = page.get_u16();
page.put_u32(child_page_number);
}
}
}
for child in page.children.iter_mut() {
set_page_references(child);
}
}
fn write_pages<W: Write>(writer: &mut BufWriter<W>, page: &Page) -> Result<(), Error> {
writer.write(&page.data)?;
for child in page.children.iter() {
write_pages(writer, child)?;
}
Ok(()) Ok(())
} }

View file

@ -4,12 +4,13 @@ use crate::database;
pub const POSITION_CELL_COUNT: u16 = 3; pub const POSITION_CELL_COUNT: u16 = 3;
pub const START_OF_CONTENT_AREA: u16 = 5; pub const START_OF_CONTENT_AREA: u16 = 5;
pub const START_OF_INTERIOR_PAGE: u16 = 12; pub const START_OF_INTERIOR_PAGE: u16 = 12;
pub const POSITION_RIGHTMOST_POINTER_LEAFPAGES: u16 = 8;
pub enum PageType { pub enum PageType {
Leaf, Leaf,
Interior, Interior,
Root, Root,
Other Other,
} }
/// Represents an SQLite page /// Represents an SQLite page
@ -18,9 +19,9 @@ pub struct Page {
pub fw_position: u16, pub fw_position: u16,
pub bw_position: u16, pub bw_position: u16,
pub key: u64, pub key: u64,
children: Vec<Page>, pub children: Vec<Page>,
number: u32, pub number: u32,
page_type: PageType, pub page_type: PageType,
} }
impl Page { impl Page {
@ -81,6 +82,7 @@ impl Page {
self.data[self.bw_position as usize] = *v; self.data[self.bw_position as usize] = *v;
self.bw_position += 1; self.bw_position += 1;
} }
self.bw_position -= bytes.len() as u16;
} }
pub fn put_u8(&mut self, value: u8) { pub fn put_u8(&mut self, value: u8) {
@ -108,9 +110,15 @@ impl Page {
} }
// may panic // may panic
pub fn get_page_nr_last_child(self) -> u32 { pub fn get_page_nr_last_child(&self) -> u32 {
self.children[self.children.len() - 1].number self.children[self.children.len() - 1].number
} }
pub fn get_u16(&self) -> u16 {
let position = self.fw_position as usize;
(self.data[position] as u16) << 8 + self.data[position + 1]
// does not increase the fw pointerr
}
} }
fn u16_to_bytes(value: u16) -> [u8; 2] { fn u16_to_bytes(value: u16) -> [u8; 2] {