mod btree; mod buffer_pool; mod pager; mod schema; mod sqlite3_ondisk; mod types; mod vdbe; use anyhow::Result; use fallible_iterator::FallibleIterator; use pager::Pager; use schema::Schema; use sqlite3_parser::{ast::Cmd, lexer::sql::Parser}; use std::sync::Arc; use vdbe::Program; pub use types::Value; pub struct Database { pager: Arc, schema: Arc, } impl Database { pub fn open(io: Arc, path: &str) -> Result { let pager = Arc::new(Pager::open(io.clone(), path)?); let schema = Arc::new(Schema::new()); let conn = Connection { pager: pager.clone(), schema: schema.clone(), }; conn.query("SELECT * FROM sqlite_schema")?; Ok(Database { pager, schema }) } pub fn connect(&self) -> Connection { Connection { pager: self.pager.clone(), schema: self.schema.clone(), } } } pub struct Connection { pager: Arc, schema: Arc, } 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 = Arc::new(vdbe::translate(&self.schema, stmt)?); Ok(Statement { program, pager: 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 = Arc::new(vdbe::translate(&self.schema, stmt)?); let state = vdbe::ProgramState::new(program.max_registers); Ok(Some(Rows::new(state, program, self.pager.clone()))) } Cmd::Explain(stmt) => { let program = vdbe::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 = vdbe::translate(&self.schema, stmt)?; program.explain(); } Cmd::ExplainQueryPlan(_stmt) => todo!(), Cmd::Stmt(stmt) => { let program = vdbe::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: Arc, pager: Arc, } impl Statement { pub fn query(&self) -> Result { let state = vdbe::ProgramState::new(self.program.max_registers); Ok(Rows::new(state, self.program.clone(), self.pager.clone())) } pub fn reset(&self) { } } pub struct Rows { state: vdbe::ProgramState, program: Arc, pager: Arc, } impl Rows { pub fn new(state: vdbe::ProgramState, program: Arc, pager: Arc) -> Self { Self { state, program, pager, } } pub fn next(&mut self) -> Result> { loop { let result = self.program.step(&mut self.state, self.pager.clone())?; match result { vdbe::StepResult::Row(row) => { return Ok(Some(Row { values: row.values })); } vdbe::StepResult::IO => todo!(), vdbe::StepResult::Done => { return Ok(None); } } } } } pub struct Row { pub values: Vec, } impl Row { pub fn get(&self, idx: usize) -> Result { let value = &self.values[idx]; T::from_value(value) } } pub type DatabaseRef = usize; pub trait IO { /// Open a database file. fn open(&self, path: &str) -> Result; /// Get a page from the database file. fn get(&self, database_ref: DatabaseRef, page_idx: usize, buf: &mut [u8]) -> Result<()>; }