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
* 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>,
}
fn new_page() -> Page {
let mut page = Page::new_leaf();
page.fw_position = 8;
page
}
impl Builder {
pub fn new() -> Self {
Self {
current_page: Page::new_leaf(),
current_page: new_page(),
n_records_on_current_page: 0,
leaf_pages: Vec::new(),
schema: None,
@ -24,7 +29,7 @@ impl Builder {
pub fn add_record(&mut self, record: Record) {
if self.current_page_is_full(&record) {
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;
}
@ -61,6 +66,7 @@ impl Into<Database> for Builder {
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
}
}
@ -85,7 +91,7 @@ mod tests {
builder.add_record(record);
let database: Database = builder.into();
let file = File::create("foo.txt")?;
let file = File::create("foo.db")?;
let writer = BufWriter::new(file);
write(database, writer)?;
Ok(())

View file

@ -2,7 +2,7 @@ use std::io::{BufWriter, Error, Write};
use std::mem;
use crate::varint;
use crate::page;
use crate::page::Page;
use crate::page::{Page, PageType};
use crate::record::Record;
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> {
let mut current_top_layer = database.leaf_pages;
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);
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
//
// recursiveAssignPagenumbers(table_root_page); // 3 extra passes... :(
// recursiveSetPageReferences(table_root_page); // don't think combining is possible
// recursiveWritePages(channel, table_root_page);
assign_pagenumbers(table_root_page, 2);
set_page_references(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(())
}

View file

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