use std::cell::RefCell; use std::rc::Rc; use crate::function::{AggFunc, Func, SingleRowFunc}; use crate::pager::Pager; use crate::schema::{Column, Schema, Table}; use crate::sqlite3_ondisk::{DatabaseHeader, MIN_PAGE_CACHE_SIZE}; use crate::util::normalize_ident; use crate::vdbe::{BranchOffset, Insn, Program, ProgramBuilder}; use anyhow::Result; use sqlite3_parser::ast::{self, Expr, Literal}; struct Select { columns: Vec, column_info: Vec, src_tables: Vec, // Tables we use to get data from. This includes "from" and "joins" limit: Option, exist_aggregation: bool, where_clause: Option, /// Ordered list of opened read table loops /// Used for generating a loop that looks like this: /// cursor 0 = open table 0 /// for each row in cursor 0 /// cursor 1 = open table 1 /// for each row in cursor 1 /// ... /// end cursor 1 /// end cursor 0 loops: Vec, } struct LoopInfo { rewind_offset: BranchOffset, rewind_label: BranchOffset, open_cursor: usize, } struct SrcTable { table: Table, alias: Option, join_info: Option, // FIXME: preferably this should be a reference with lifetime == Select ast expr } struct ColumnInfo { func: Option, args: Option>, columns_to_allocate: usize, /* number of result columns this col will result on */ } impl ColumnInfo { pub fn new() -> Self { Self { func: None, args: None, columns_to_allocate: 1, } } pub fn is_aggregation_function(&self) -> bool { matches!(self.func, Some(Func::Agg(_))) } } struct LimitInfo { limit_reg: usize, num: i64, goto_label: BranchOffset, } /// Translate SQL statement into bytecode program. pub fn translate( schema: &Schema, stmt: ast::Stmt, database_header: Rc>, pager: Rc, ) -> Result { match stmt { ast::Stmt::Select(select) => { let select = build_select(schema, select)?; translate_select(select) } ast::Stmt::Pragma(name, body) => translate_pragma(&name, body, database_header, pager), _ => todo!(), } } fn build_select(schema: &Schema, select: ast::Select) -> Result