while moving to storage in pages
This commit is contained in:
parent
3281edc350
commit
68a2224dc7
16 changed files with 355 additions and 203 deletions
|
|
@ -1,18 +1,18 @@
|
||||||
use csv::table::Table;
|
use csv::table::Table;
|
||||||
|
|
||||||
fn main() {
|
// fn main() {
|
||||||
let left = Table::from_csv(include_str!("data/left.csv"), Some("\t"));
|
// let left = Table::from_csv(include_str!("data/left.csv"), Some("\t"));
|
||||||
let right = Table::from_csv(include_str!("data/right.csv"), Some("\t"));
|
// let right = Table::from_csv(include_str!("data/right.csv"), Some("\t"));
|
||||||
println!("left:");
|
// println!("left:");
|
||||||
left.select("*");
|
// left.select("*");
|
||||||
println!("\nright:");
|
// println!("\nright:");
|
||||||
right.select("*");
|
// right.select("*");
|
||||||
println!("\njoin on name:");
|
// println!("\njoin on name:");
|
||||||
left.left_join(&right, "name", "name", false)
|
// left.left_join(&right, "name", "name", false)
|
||||||
.select("name, cowdung, value");
|
// .select("name, cowdung, value");
|
||||||
println!("\nleft join on name:");
|
// println!("\nleft join on name:");
|
||||||
left.left_join(&right, "name", "name", true).select("*");
|
// left.left_join(&right, "name", "name", true).select("*");
|
||||||
println!("\nright join on name:");
|
// println!("\nright join on name:");
|
||||||
left.right_join(&right, "name", "name", true)
|
// left.right_join(&right, "name", "name", true)
|
||||||
.select("name,cowdung,value");
|
// .select("name,cowdung,value");
|
||||||
}
|
// }
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use csv::table::Table;
|
use csv::table::Table;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let table = Table::from_csv(include_str!("data/table.csv"), Some("\t"));
|
// let table = Table::from_csv(include_str!("data/table.csv"), Some("\t"));
|
||||||
println!("not ordered:");
|
// println!("not ordered:");
|
||||||
table.select("*");
|
// table.select("*");
|
||||||
|
//
|
||||||
println!("order by name ascending:");
|
// println!("order by name ascending:");
|
||||||
table.order_by("name").select("*");
|
// table.order_by("name").select("*");
|
||||||
|
//
|
||||||
println!("\nTODO descending");
|
// println!("\nTODO descending");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
src/data/test.csv
Normal file
3
src/data/test.csv
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
name value
|
||||||
|
a 3
|
||||||
|
b 4
|
||||||
|
18
src/id_sequence.rs
Normal file
18
src/id_sequence.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ThreadSafeIdGenerator {
|
||||||
|
counter: AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ThreadSafeIdGenerator {
|
||||||
|
pub fn new(start: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
counter: AtomicUsize::new(start),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(&self) -> usize {
|
||||||
|
self.counter.fetch_add(1, Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/join.rs
48
src/join.rs
|
|
@ -1,29 +1,29 @@
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
|
|
||||||
impl Table {
|
impl Table {
|
||||||
pub fn left_join(&self, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table {
|
// pub fn left_join(&self, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table {
|
||||||
join(self, right, left_col, right_col, outer)
|
// join(self, right, left_col, right_col, outer)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn right_join(&self, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table {
|
||||||
|
// join(right, self, right_col, left_col, outer)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn right_join(&self, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table {
|
// pub fn join(left: &Table, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table {
|
||||||
join(right, self, right_col, left_col, outer)
|
// let mut joined = Table::new("join");
|
||||||
}
|
// left.cols.iter().for_each(|c| joined.add_column(c, true));
|
||||||
}
|
// right.cols.iter().for_each(|c| joined.add_column(c, true));
|
||||||
|
// let left_col_index = left.get_index(left_col);
|
||||||
pub fn join(left: &Table, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table {
|
// let right_col_index = right.get_index(right_col);
|
||||||
let mut joined = Table::new("join");
|
//
|
||||||
left.cols.iter().for_each(|c| joined.add_column(c, true));
|
// for record in left.iter_records() {
|
||||||
right.cols.iter().for_each(|c| joined.add_column(c, true));
|
// let lv = record.get(left_col_index);
|
||||||
let left_col_index = left.get_index(left_col);
|
// if let Some(right_record) = right.where_clause(right_col_index, lv) {
|
||||||
let right_col_index = right.get_index(right_col);
|
// joined.add_record(record + right_record);
|
||||||
|
// } else if outer {
|
||||||
for record in left.iter_records() {
|
// joined.add_record(record.clone());
|
||||||
let lv = record.get(left_col_index);
|
// }
|
||||||
if let Some(right_record) = right.where_clause(right_col_index, lv) {
|
// }
|
||||||
joined.add_record(record + right_record);
|
// joined
|
||||||
} else if outer {
|
// }
|
||||||
joined.add_record(record.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
joined
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,5 @@ pub mod table;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
mod varint;
|
mod varint;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
|
mod id_sequence;
|
||||||
|
mod record;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use csv::table::Table;
|
use csv::table::Table;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let csv = include_str!("data/portfolios.csv");
|
let csv = include_str!("data/test.csv");
|
||||||
let table = Table::from_csv(csv, None);
|
let table = Table::from_csv(csv, None);
|
||||||
table.order_by("name").select("*");
|
println!("{:?}",table);
|
||||||
|
table.select("*");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
src/order.rs
26
src/order.rs
|
|
@ -3,17 +3,17 @@ use std::collections::BTreeMap;
|
||||||
use crate::table::{Key, Table};
|
use crate::table::{Key, Table};
|
||||||
|
|
||||||
impl Table {
|
impl Table {
|
||||||
pub fn order_by(&self, expression: &str) -> Self {
|
// pub fn order_by(&self, expression: &str) -> Self {
|
||||||
let indexes = self.get_column_indexes(expression);
|
// let indexes = self.get_column_indexes(expression);
|
||||||
if self.views.contains_key(expression) {}
|
// if self.views.contains_key(expression) {}
|
||||||
|
//
|
||||||
let mut sorted_records = BTreeMap::new();
|
// let mut sorted_records = BTreeMap::new();
|
||||||
for record in self.iter() {
|
// for record in self.iter() {
|
||||||
let key = indexes.iter().map(|i| record.get(*i).clone()).collect();
|
// let key = indexes.iter().map(|i| record.get(*i).clone()).collect();
|
||||||
sorted_records.insert(Key::compound(key), record.clone());
|
// sorted_records.insert(Key::compound(key), record.clone());
|
||||||
}
|
// }
|
||||||
let mut ordered = Table::empty_copy(self);
|
// let mut ordered = Table::empty_copy(self);
|
||||||
ordered.records = sorted_records;
|
// ordered.records = sorted_records;
|
||||||
ordered
|
// ordered
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
77
src/page.rs
77
src/page.rs
|
|
@ -1,71 +1,86 @@
|
||||||
use std::ops::Add;
|
use crate::record::Record;
|
||||||
|
use crate::value::Value;
|
||||||
use crate::value::{Value, NULL};
|
use crate::varint;
|
||||||
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
|
|
||||||
const PAGE_SIZE: usize = 4096;
|
const PAGE_SIZE: usize = 4096;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum PageType {
|
pub enum PageType {
|
||||||
Root,
|
Root,
|
||||||
Interior,
|
Interior,
|
||||||
Leaf,
|
Leaf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Page {
|
pub struct Page {
|
||||||
pagetype: PageType,
|
pagetype: PageType,
|
||||||
|
id: usize,
|
||||||
|
start: Value,
|
||||||
|
end: Value,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
index_pos: u16,
|
index_pos: u16,
|
||||||
data_pos: u16,
|
data_pos: u16,
|
||||||
key: usize,
|
key: usize,
|
||||||
children: Vec<Page>,
|
children: Vec<Page>,
|
||||||
|
n_records: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Page {
|
impl Page {
|
||||||
pub fn new(pagetype: PageType) -> Self {
|
pub fn new(pagetype: PageType, id: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pagetype,
|
pagetype,
|
||||||
|
id,
|
||||||
|
start: Value::null(),
|
||||||
|
end: Value::null(),
|
||||||
data: vec![0; PAGE_SIZE],
|
data: vec![0; PAGE_SIZE],
|
||||||
index_pos: 0,
|
index_pos: 0,
|
||||||
data_pos: (PAGE_SIZE - 1) as u16,
|
data_pos: (PAGE_SIZE - 1) as u16,
|
||||||
key: 0,
|
key: 0,
|
||||||
children: vec![],
|
children: vec![],
|
||||||
|
n_records: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_record(&mut self, record: Record) {}
|
pub fn insert(&mut self, record: Record) {
|
||||||
|
let bytes: Vec<u8> = record.into();
|
||||||
|
self.insert_data(bytes);
|
||||||
|
self.insert_index(self.data_pos);
|
||||||
|
self.n_records += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
fn insert_data(&mut self, bytes: Vec<u8>) {
|
||||||
pub struct Record {
|
let end = self.data_pos as usize;
|
||||||
values: Vec<Value>,
|
self.data_pos -= bytes.len() as u16;
|
||||||
|
self.data.splice(self.data_pos as usize..end, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Record {
|
fn insert_index(&mut self, value: u16) {
|
||||||
pub fn string_len(&self) -> usize {
|
let bytes = u16_to_bytes(value);
|
||||||
self.values.iter().map(Value::string_len).sum()
|
let start = self.index_pos as usize;
|
||||||
|
self.index_pos += bytes.len() as u16;
|
||||||
|
self.data.splice(start..self.index_pos as usize, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_value(&mut self, value: impl Into<Value>) {
|
pub fn get(&self, index: usize) -> Option<Record> {
|
||||||
self.values.push(value.into());
|
if index < self.n_records {
|
||||||
|
let index = BigEndian::read_u16(&self.data[index * 2..=index * 2 + 1]);
|
||||||
|
let (nbytes, len) = varint::read(&self.data[index as usize..]);
|
||||||
|
Some(
|
||||||
|
(
|
||||||
|
len,
|
||||||
|
&self.data[nbytes + index as usize..nbytes + index as usize + len as usize],
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, index: usize) -> Value {
|
|
||||||
self.values.get(index).map(|v| v.clone()).unwrap_or(NULL)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add for &Record {
|
fn u16_to_bytes(value: u16) -> Vec<u8> {
|
||||||
type Output = Record;
|
let mut buf = vec![0; 2];
|
||||||
|
BigEndian::write_u16(&mut buf, value);
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
buf
|
||||||
let mut sum = Record::default();
|
|
||||||
sum.values.append(&mut self.values.clone());
|
|
||||||
sum.values.append(&mut rhs.values.clone()); // use refs?
|
|
||||||
sum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Record {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self { values: vec![] }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ impl Table {
|
||||||
print!("| {:<w$} ", col);
|
print!("| {:<w$} ", col);
|
||||||
}
|
}
|
||||||
println!("|");
|
println!("|");
|
||||||
for record in self.iter_records() {
|
for record in self.iter() {
|
||||||
for col in self.iter_colums() {
|
for col in self.iter_colums() {
|
||||||
let w = column_widths.get(col).unwrap_or(&0);
|
let w = column_widths.get(col).unwrap_or(&0);
|
||||||
// eprintln!("{}", w);
|
// eprintln!("{}", w);
|
||||||
|
|
@ -45,7 +45,7 @@ impl Table {
|
||||||
print!("| {:<w$} ", col);
|
print!("| {:<w$} ", col);
|
||||||
}
|
}
|
||||||
println!("|");
|
println!("|");
|
||||||
for record in self.iter_records() {
|
for record in self.iter() {
|
||||||
for col in self.select_columns(&columns) {
|
for col in self.select_columns(&columns) {
|
||||||
let w = column_widths.get(col).unwrap_or(&0);
|
let w = column_widths.get(col).unwrap_or(&0);
|
||||||
// eprintln!("{}", w);
|
// eprintln!("{}", w);
|
||||||
|
|
@ -66,7 +66,7 @@ impl Table {
|
||||||
for col in self.iter_colums() {
|
for col in self.iter_colums() {
|
||||||
widths.insert(col, col.len());
|
widths.insert(col, col.len());
|
||||||
}
|
}
|
||||||
for record in self.iter_records().skip(offset).take(nrecords) {
|
for record in self.iter().skip(offset).take(nrecords) {
|
||||||
for col in self.iter_colums() {
|
for col in self.iter_colums() {
|
||||||
let e = widths.get_mut(&col).unwrap();
|
let e = widths.get_mut(&col).unwrap();
|
||||||
let index = self.get_index(col);
|
let index = self.get_index(col);
|
||||||
|
|
@ -92,7 +92,7 @@ impl Table {
|
||||||
for col in self.select_columns(columns) {
|
for col in self.select_columns(columns) {
|
||||||
widths.insert(col, col.len());
|
widths.insert(col, col.len());
|
||||||
}
|
}
|
||||||
for record in self.iter_records().skip(offset).take(nrecords) {
|
for record in self.iter().skip(offset).take(nrecords) {
|
||||||
for col in self.select_columns(columns) {
|
for col in self.select_columns(columns) {
|
||||||
let e = widths.get_mut(&col).unwrap();
|
let e = widths.get_mut(&col).unwrap();
|
||||||
let index = self.get_index(&col);
|
let index = self.get_index(&col);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use crate::table::{Record, Table};
|
use crate::table::Table;
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use crate::record::Record;
|
||||||
|
|
||||||
const EOL: &str = "\n";
|
const EOL: &str = "\n";
|
||||||
|
|
||||||
|
|
|
||||||
141
src/record.rs
Normal file
141
src/record.rs
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
use crate::value::Value;
|
||||||
|
use crate::varint;
|
||||||
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Record {
|
||||||
|
pub rowid: u64,
|
||||||
|
pub(crate) values: Vec<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Record {
|
||||||
|
pub fn string_len(&self) -> usize {
|
||||||
|
self.values.iter().map(Value::string_len).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_len(&self) -> u16 {
|
||||||
|
let record_length: u16 = self.values.iter().map(Value::bytes_len).sum();
|
||||||
|
record_length + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_value(&mut self, value: impl Into<Value>) {
|
||||||
|
self.values.push(value.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, index: usize) -> &Value {
|
||||||
|
self.values.get(index).unwrap() //TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for &Record {
|
||||||
|
type Output = Record;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
let mut sum = Record::default();
|
||||||
|
sum.values.append(&mut self.values.clone());
|
||||||
|
sum.values.append(&mut rhs.values.clone()); // use refs?
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Record> for Vec<u8> {
|
||||||
|
fn from(mut record: Record) -> Vec<u8> {
|
||||||
|
let record_length = record.bytes_len();
|
||||||
|
let mut length_bytes = varint::write(u64::from(record_length));
|
||||||
|
let mut rowid_bytes = varint::write(record.rowid);
|
||||||
|
|
||||||
|
let mut buffer =
|
||||||
|
Vec::with_capacity(length_bytes.len() + rowid_bytes.len() + record_length as usize);
|
||||||
|
buffer.append(&mut length_bytes);
|
||||||
|
buffer.append(&mut rowid_bytes);
|
||||||
|
|
||||||
|
// 'The initial portion of the payload that does not spill to overflow pages.'
|
||||||
|
let length_of_encoded_column_types: usize =
|
||||||
|
record.values.iter().map(|v| v.datatype_bytes.len()).sum();
|
||||||
|
buffer.append(&mut varint::write(
|
||||||
|
(length_of_encoded_column_types + 1) as u64,
|
||||||
|
));
|
||||||
|
|
||||||
|
//write all types
|
||||||
|
for v in &mut record.values {
|
||||||
|
buffer.append(&mut v.datatype_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write all values
|
||||||
|
for v in &mut record.values {
|
||||||
|
buffer.append(&mut v.data);
|
||||||
|
}
|
||||||
|
buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Record> for (u64, &[u8]) {
|
||||||
|
fn into(self) -> Record {
|
||||||
|
let (len, data) = self;
|
||||||
|
let len = len as usize; //meh
|
||||||
|
let (mut offset, rowid) = varint::read(data);
|
||||||
|
|
||||||
|
let mut datatypes = vec![];
|
||||||
|
|
||||||
|
//read n of fields
|
||||||
|
while (offset < len) {
|
||||||
|
let (inc, datatype) = varint::read(&data[offset..]);
|
||||||
|
datatypes.push(datatype);
|
||||||
|
offset += inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut values: Vec<Value> = vec![];
|
||||||
|
for dt in datatypes {
|
||||||
|
match dt {
|
||||||
|
13.. if dt % 2 == 0 => {
|
||||||
|
let len = ((dt >> 1) - 13) as usize;
|
||||||
|
if let Ok(text) = String::from_utf8(data[offset..len].to_vec()) {
|
||||||
|
values.push(text.into());
|
||||||
|
}
|
||||||
|
offset += len;
|
||||||
|
}
|
||||||
|
12.. if dt % 2 == 0 => {
|
||||||
|
let len = ((dt >> 1) - 12) as usize;
|
||||||
|
// no blobs yet
|
||||||
|
offset += len;
|
||||||
|
}
|
||||||
|
9 => values.push(1.into()),
|
||||||
|
8 => values.push(0.into()),
|
||||||
|
7 => {
|
||||||
|
values.push(BigEndian::read_f64(&data[offset..offset + 8]).into());
|
||||||
|
offset += 8;
|
||||||
|
}
|
||||||
|
1..=6 => {
|
||||||
|
let (inc, v) = read_int(&data[offset..], dt);
|
||||||
|
values.push(v.into());
|
||||||
|
offset += inc;
|
||||||
|
}
|
||||||
|
0 => {
|
||||||
|
values.push(Value::null());
|
||||||
|
}
|
||||||
|
_ => panic!("unknown datatype"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Record { rowid, values }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_int(buf: &[u8], datatype: u64) -> (usize, i64) {
|
||||||
|
let nb = match datatype {
|
||||||
|
6 => 8,
|
||||||
|
5 => 6,
|
||||||
|
_ => datatype as usize,
|
||||||
|
};
|
||||||
|
(nb, BigEndian::read_i64(&buf[..nb]))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Record {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
rowid: 0,
|
||||||
|
values: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
|
||||||
use crate::value::{Value, NULL};
|
use crate::value::Value;
|
||||||
|
|
||||||
use super::tokens::{Token, TokenType};
|
use super::tokens::{Token, TokenType};
|
||||||
|
|
||||||
|
|
@ -154,7 +154,7 @@ impl Scanner {
|
||||||
|
|
||||||
fn add_token(&mut self, tokentype: TokenType) {
|
fn add_token(&mut self, tokentype: TokenType) {
|
||||||
let text = self.source[self.start..self.current].to_string();
|
let text = self.source[self.start..self.current].to_string();
|
||||||
self.tokens.push(Token::new(tokentype, text, NULL));
|
self.tokens.push(Token::new(tokentype, text, Value::null()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_literal(&mut self, tokentype: TokenType, literal: Value) {
|
fn add_literal(&mut self, tokentype: TokenType, literal: Value) {
|
||||||
|
|
|
||||||
107
src/table.rs
107
src/table.rs
|
|
@ -1,32 +1,43 @@
|
||||||
|
use crate::id_sequence::ThreadSafeIdGenerator;
|
||||||
|
use crate::page::{Page, PageType};
|
||||||
|
use crate::record::Record;
|
||||||
|
use crate::value::Value;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::{BTreeMap, HashMap},
|
collections::{BTreeMap, HashMap}
|
||||||
iter::Map,
|
|
||||||
ops::Add,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::value::Value;
|
#[derive(Debug)]
|
||||||
|
|
||||||
pub struct View {
|
pub struct View {
|
||||||
records: BTreeMap<Key, Key>,
|
records: BTreeMap<Key, Key>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
name: String,
|
name: String,
|
||||||
cols_by_name: HashMap<String, usize>,
|
cols_by_name: HashMap<String, usize>,
|
||||||
pub(crate) cols: Vec<String>,
|
pub(crate) cols: Vec<String>,
|
||||||
pub(crate) records: BTreeMap<Key, Record>,
|
pub(crate) root: Rc<RefCell<Page>>,
|
||||||
pub views: HashMap<String, View>,
|
pub views: HashMap<String, View>,
|
||||||
|
page_ids: ThreadSafeIdGenerator,
|
||||||
|
row_ids: ThreadSafeIdGenerator,
|
||||||
|
current_page: Rc<RefCell<Page>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Table {
|
impl Table {
|
||||||
pub fn new(name: impl Into<String>) -> Self {
|
pub fn new(name: impl Into<String>) -> Self {
|
||||||
|
let root = Rc::new(RefCell::new(Page::new(PageType::Root, 0)));
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
cols_by_name: HashMap::new(),
|
cols_by_name: HashMap::new(),
|
||||||
cols: vec![],
|
cols: vec![],
|
||||||
records: BTreeMap::new(),
|
root: Rc::clone(&root),
|
||||||
views: HashMap::new(),
|
views: HashMap::new(),
|
||||||
|
page_ids: ThreadSafeIdGenerator::new(1),
|
||||||
|
row_ids: ThreadSafeIdGenerator::new(0),
|
||||||
|
current_page: root,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,8 +53,7 @@ impl Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_record(&mut self, record: Record) {
|
pub fn add_record(&mut self, record: Record) {
|
||||||
let index = self.records.len();
|
self.current_page.borrow_mut().insert(record);
|
||||||
self.records.insert(Key::integer(index), record);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_column(&self, name: impl Into<String>) -> bool {
|
pub fn has_column(&self, name: impl Into<String>) -> bool {
|
||||||
|
|
@ -85,12 +95,9 @@ impl Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> TableIter {
|
pub fn iter(&self) -> TableIter {
|
||||||
self.iter_records()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_records(&self) -> TableIter {
|
|
||||||
TableIter {
|
TableIter {
|
||||||
table_iter: self.records.iter(),
|
rootPage: Rc::clone(&self.root),
|
||||||
|
index: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,69 +115,27 @@ impl Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn where_clause(&self, colindex: usize, value: &Value) -> Option<&Record> {
|
// pub fn where_clause(&self, colindex: usize, value: &Value) -> Option<&Record> {
|
||||||
for record in self.iter_records() {
|
// for record in self.iter() {
|
||||||
let r = record.get(colindex);
|
// let r = record.get(colindex);
|
||||||
if r == value {
|
// if r == value {
|
||||||
return Some(record);
|
// return Some(record);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
None
|
// None
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
pub struct TableIter {
|
||||||
pub struct Record {
|
rootPage: Rc<RefCell<Page>>,
|
||||||
values: Vec<Value>,
|
index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Record {
|
impl Iterator for TableIter {
|
||||||
pub fn string_len(&self) -> usize {
|
type Item = Record;
|
||||||
self.values.iter().map(Value::string_len).sum()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_value(&mut self, value: impl Into<Value>) {
|
|
||||||
self.values.push(value.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, index: usize) -> &Value {
|
|
||||||
self.values.get(index).unwrap() //TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for &Record {
|
|
||||||
type Output = Record;
|
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
|
||||||
let mut sum = Record::default();
|
|
||||||
sum.values.append(&mut self.values.clone());
|
|
||||||
sum.values.append(&mut rhs.values.clone()); // use refs?
|
|
||||||
sum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Record {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self { values: vec![] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TableIter<'a> {
|
|
||||||
table_iter: std::collections::btree_map::Iter<'a, Key, Record>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ViewIter<'a> {
|
|
||||||
iter: Map<
|
|
||||||
std::collections::btree_map::Iter<'a, Key, Key>,
|
|
||||||
Box<dyn Fn((&'a Key, &'a Key)) -> Option<&'a Record>>,
|
|
||||||
>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for TableIter<'a> {
|
|
||||||
type Item = &'a Record;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.table_iter.next().map(|e| e.1)
|
self.rootPage.borrow().get(self.index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
33
src/value.rs
33
src/value.rs
|
|
@ -2,13 +2,13 @@ use std::{cmp::Ordering, fmt::Display};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use byteorder::{BigEndian, ByteOrder};
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
|
use crate::varint;
|
||||||
pub const NULL: Value = Value::null();
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, Ord)]
|
||||||
pub struct Value {
|
pub struct Value {
|
||||||
datatype: u64,
|
pub(crate) datatype: u64,
|
||||||
data: Vec<u8>,
|
pub(crate) datatype_bytes: Vec<u8>,
|
||||||
|
pub(crate) data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Value {
|
impl PartialOrd for Value {
|
||||||
|
|
@ -61,21 +61,26 @@ pub enum Datatype {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
pub const fn null() -> Self {
|
fn new(datatype: u64, data: Vec<u8>) -> Self {
|
||||||
// NULL
|
|
||||||
Self {
|
Self {
|
||||||
data: vec![],
|
datatype,
|
||||||
datatype: 0,
|
data,
|
||||||
|
datatype_bytes: varint::write(datatype),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bytes_len(&self) -> u16 {
|
||||||
|
(self.datatype_bytes.len() + self.data.len()) as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn null() -> Self {
|
||||||
|
Self::new(0 ,vec![])
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_f64(value: f64) -> Self {
|
pub fn from_f64(value: f64) -> Self {
|
||||||
let mut buf = vec![0; 8];
|
let mut buf = vec![0; 8];
|
||||||
BigEndian::write_f64(&mut buf, value);
|
BigEndian::write_f64(&mut buf, value);
|
||||||
Self {
|
Self::new(7, buf)
|
||||||
datatype: 7,
|
|
||||||
data: buf,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_i64(value: i64) -> Self {
|
pub fn from_i64(value: i64) -> Self {
|
||||||
|
|
@ -87,14 +92,14 @@ impl Value {
|
||||||
(int_datatype(data.len()), data)
|
(int_datatype(data.len()), data)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Self { datatype, data }
|
Self::new(datatype,data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_text(value: impl Into<String>) -> Self {
|
pub fn from_text(value: impl Into<String>) -> Self {
|
||||||
let value: String = value.into();
|
let value: String = value.into();
|
||||||
let datatype = (13 + value.len() * 2) as u64;
|
let datatype = (13 + value.len() * 2) as u64;
|
||||||
let data = value.as_bytes().to_vec();
|
let data = value.as_bytes().to_vec();
|
||||||
Self { datatype, data }
|
Self::new(datatype,data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn datatype(&self) -> anyhow::Result<Datatype> {
|
pub fn datatype(&self) -> anyhow::Result<Datatype> {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ const SLOT_4_2_0: u64 = 0xf01fc07f;
|
||||||
|
|
||||||
/// varints as implemented in `SQLite`
|
/// varints as implemented in `SQLite`
|
||||||
|
|
||||||
pub fn write(value: i64) -> Vec<u8> {
|
pub fn write(value: u64) -> Vec<u8> {
|
||||||
let mut v = value;
|
let mut v = value;
|
||||||
if (v & ((0xff00_0000) << 32)) == 0 {
|
if (v & ((0xff00_0000) << 32)) == 0 {
|
||||||
if v == 0 {
|
if v == 0 {
|
||||||
|
|
@ -30,15 +30,15 @@ pub fn write(value: i64) -> Vec<u8> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(data: Vec<u8>) -> u64 {
|
pub fn read(data: &[u8]) -> (usize, u64) {
|
||||||
let mut a = data[0] as u64;
|
let mut a = data[0] as u64;
|
||||||
if (data[0] as i8) >= 0 {
|
if (data[0] as i8) >= 0 {
|
||||||
return a;
|
return (1,a);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut b = data[1] as u64;
|
let mut b = data[1] as u64;
|
||||||
if (b & 0x80) == 0 {
|
if (b & 0x80) == 0 {
|
||||||
return ((a & 0x7f) << 7) | b;
|
return (2,((a & 0x7f) << 7) | b);
|
||||||
}
|
}
|
||||||
|
|
||||||
a = (a << 14) | data[2] as u64;
|
a = (a << 14) | data[2] as u64;
|
||||||
|
|
@ -46,7 +46,7 @@ pub fn read(data: Vec<u8>) -> u64 {
|
||||||
a &= SLOT_2_0;
|
a &= SLOT_2_0;
|
||||||
b = (b & 0x7f) << 7;
|
b = (b & 0x7f) << 7;
|
||||||
a |= b;
|
a |= b;
|
||||||
return a;
|
return (3,a);
|
||||||
}
|
}
|
||||||
|
|
||||||
a &= SLOT_2_0;
|
a &= SLOT_2_0;
|
||||||
|
|
@ -55,7 +55,7 @@ pub fn read(data: Vec<u8>) -> u64 {
|
||||||
if (b & 0x80) == 0 {
|
if (b & 0x80) == 0 {
|
||||||
b &= SLOT_2_0;
|
b &= SLOT_2_0;
|
||||||
a = (a << 7) | b;
|
a = (a << 7) | b;
|
||||||
return a;
|
return (4,a);
|
||||||
}
|
}
|
||||||
|
|
||||||
b &= SLOT_2_0;
|
b &= SLOT_2_0;
|
||||||
|
|
@ -67,7 +67,7 @@ pub fn read(data: Vec<u8>) -> u64 {
|
||||||
b = b << 7;
|
b = b << 7;
|
||||||
a |= b;
|
a |= b;
|
||||||
s = s >> 18;
|
s = s >> 18;
|
||||||
return (s << 32) | a;
|
return (5,(s << 32) | a);
|
||||||
}
|
}
|
||||||
|
|
||||||
s = (s << 7) | b;
|
s = (s << 7) | b;
|
||||||
|
|
@ -76,7 +76,7 @@ pub fn read(data: Vec<u8>) -> u64 {
|
||||||
a &= SLOT_2_0;
|
a &= SLOT_2_0;
|
||||||
a = (a << 7) | b;
|
a = (a << 7) | b;
|
||||||
s = s >> 18;
|
s = s >> 18;
|
||||||
return (s << 32) | a;
|
return (6,(s << 32) | a);
|
||||||
}
|
}
|
||||||
|
|
||||||
a = a << 14;
|
a = a << 14;
|
||||||
|
|
@ -87,7 +87,7 @@ pub fn read(data: Vec<u8>) -> u64 {
|
||||||
b = b << 7;
|
b = b << 7;
|
||||||
a |= b;
|
a |= b;
|
||||||
s = s >> 11;
|
s = s >> 11;
|
||||||
return (s << 32) | a;
|
return (7,(s << 32) | a);
|
||||||
}
|
}
|
||||||
|
|
||||||
a &= SLOT_2_0;
|
a &= SLOT_2_0;
|
||||||
|
|
@ -96,7 +96,7 @@ pub fn read(data: Vec<u8>) -> u64 {
|
||||||
b &= SLOT_4_2_0;
|
b &= SLOT_4_2_0;
|
||||||
a = (a << 7) | b;
|
a = (a << 7) | b;
|
||||||
s = s >> 14;
|
s = s >> 14;
|
||||||
return (s << 32) | a;
|
return (8,(s << 32) | a);
|
||||||
}
|
}
|
||||||
|
|
||||||
a = a << 15;
|
a = a << 15;
|
||||||
|
|
@ -109,7 +109,7 @@ pub fn read(data: Vec<u8>) -> u64 {
|
||||||
b &= 0x7f;
|
b &= 0x7f;
|
||||||
b = b >> 3;
|
b = b >> 3;
|
||||||
s |= b;
|
s |= b;
|
||||||
(s << 32) | a
|
(9,(s << 32) | a)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -118,15 +118,15 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_0() {
|
fn test_0() {
|
||||||
assert_eq!(0, read(write(0)));
|
assert_eq!(0, read(&write(0)).1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_127() {
|
fn test_127() {
|
||||||
assert_eq!(127, read(write(127)));
|
assert_eq!(127, read(&write(127)).1);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_m127() {
|
fn test_m127() {
|
||||||
assert_eq!(398639861, read(write(398639861)));
|
assert_eq!(398639861, read(&write(398639861)).1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue