mod btree; mod buffer_pool; mod io; mod pager; mod schema; mod sqlite3_ondisk; mod storage; mod translate; mod types; mod vdbe; #[cfg(not(target_family = "wasm"))] #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use anyhow::Result; use fallible_iterator::FallibleIterator; use pager::Pager; use schema::Schema; use sqlite3_parser::{ast::Cmd, lexer::sql::Parser}; use std::rc::Rc; #[cfg(feature = "fs")] pub use io::PlatformIO; pub use io::{Buffer, Completion, File, IO}; pub use storage::{PageIO, PageSource}; pub use types::Value; pub struct Database { pager: Rc, schema: Rc, } impl Database { #[cfg(feature = "fs")] pub fn open_file(io: Rc, path: &str) -> Result { let file = io.open_file(path)?; let storage = storage::PageSource::from_file(file); Self::open(io, storage) } pub fn open(io: Rc, page_source: PageSource) -> Result { let db_header = Pager::begin_open(&page_source)?; io.run_once()?; let pager = Rc::new(Pager::finish_open(db_header, page_source)?); let bootstrap_schema = Rc::new(Schema::new()); let conn = Connection { pager: pager.clone(), schema: bootstrap_schema.clone(), }; let mut schema = Schema::new(); let rows = conn.query("SELECT * FROM sqlite_schema")?; if let Some(mut rows) = rows { loop { match rows.next()? { RowResult::Row(row) => { let ty = row.get::(0)?; if ty != "table" { continue; } let name: String = row.get::(1)?; let root_page: i64 = row.get::(3)?; let sql: String = row.get::(4)?; let table = schema::Table::from_sql(&sql, root_page as usize)?; assert_eq!(table.name, name); schema.add_table(table.name.to_owned(), table); } RowResult::IO => { // TODO: How do we ensure that the I/O we submitted to // read the schema is actually complete? io.run_once()?; } RowResult::Done => break, } } } let schema = Rc::new(schema); Ok(Database { pager, schema }) } pub fn connect(&self) -> Connection { Connection { pager: self.pager.clone(), schema: self.schema.clone(), } } } pub struct Connection { pager: Rc, schema: Rc, } impl Connection { pub fn prepare(&self, sql: impl Into) -> Result { let sql = sql.into(); let mut parser = Parser::new(sql.as_bytes()); let cmd = parser.next()?; if let Some(cmd) = cmd { match cmd { Cmd::Stmt(stmt) => { let program = Rc::new(translate::translate(&self.schema, stmt)?); Ok(Statement::new(program, self.pager.clone())) } Cmd::Explain(_stmt) => todo!(), Cmd::ExplainQueryPlan(_stmt) => todo!(), } } else { todo!() } } pub fn query(&self, sql: impl Into) -> Result> { let sql = sql.into(); let mut parser = Parser::new(sql.as_bytes()); let cmd = parser.next()?; if let Some(cmd) = cmd { match cmd { Cmd::Stmt(stmt) => { let program = Rc::new(translate::translate(&self.schema, stmt)?); let stmt = Statement::new(program, self.pager.clone()); Ok(Some(Rows { stmt })) } Cmd::Explain(stmt) => { let program = translate::translate(&self.schema, stmt)?; program.explain(); Ok(None) } Cmd::ExplainQueryPlan(_stmt) => Ok(None), } } else { Ok(None) } } pub fn execute(&self, sql: impl Into) -> Result<()> { let sql = sql.into(); let mut parser = Parser::new(sql.as_bytes()); let cmd = parser.next()?; if let Some(cmd) = cmd { match cmd { Cmd::Explain(stmt) => { let program = translate::translate(&self.schema, stmt)?; program.explain(); } Cmd::ExplainQueryPlan(_stmt) => todo!(), Cmd::Stmt(stmt) => { let program = translate::translate(&self.schema, stmt)?; let mut state = vdbe::ProgramState::new(program.max_registers); program.step(&mut state, self.pager.clone())?; } } } Ok(()) } } pub struct Statement { program: Rc, state: vdbe::ProgramState, pager: Rc, } impl Statement { pub fn new(program: Rc, pager: Rc) -> Self { let state = vdbe::ProgramState::new(program.max_registers); Self { program, state, pager, } } pub fn step(&mut self) -> Result> { let result = self.program.step(&mut self.state, self.pager.clone())?; match result { vdbe::StepResult::Row(row) => Ok(RowResult::Row(Row { values: row.values })), vdbe::StepResult::IO => Ok(RowResult::IO), vdbe::StepResult::Done => Ok(RowResult::Done), } } pub fn query(&mut self) -> Result { let stmt = Statement::new(self.program.clone(), self.pager.clone()); Ok(Rows::new(stmt)) } pub fn reset(&self) {} } pub enum RowResult<'a> { Row(Row<'a>), IO, Done, } pub struct Row<'a> { pub values: Vec>, } impl<'a> Row<'a> { pub fn get(&self, idx: usize) -> Result { let value = &self.values[idx]; T::from_value(value) } } pub struct Rows { stmt: Statement, } impl Rows { pub fn new(stmt: Statement) -> Self { Self { stmt } } pub fn next(&mut self) -> Result> { self.stmt.step() } }