writes the database file, needs bugfixing
This commit is contained in:
parent
7a475577f2
commit
74baede692
4 changed files with 95 additions and 18 deletions
22
README.md
22
README.md
|
|
@ -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(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +80,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_build() -> Result<(), Error>{
|
fn test_build() -> Result<(), Error> {
|
||||||
let mut builder = Builder::new();
|
let mut builder = Builder::new();
|
||||||
builder.schema(
|
builder.schema(
|
||||||
"foo",
|
"foo",
|
||||||
|
|
@ -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(())
|
||||||
|
|
|
||||||
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
20
src/page.rs
20
src/page.rs
|
|
@ -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 {
|
||||||
|
|
@ -36,7 +37,7 @@ impl Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default(size: usize) -> Self{
|
fn default(size: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: vec![0; size],
|
data: vec![0; size],
|
||||||
fw_position: 0,
|
fw_position: 0,
|
||||||
|
|
@ -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] {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue