mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 18:18:03 +00:00
refactor to include optional program builder argument
This commit is contained in:
parent
696c98877c
commit
517c7c81cd
10 changed files with 130 additions and 28 deletions
|
@ -355,6 +355,7 @@ impl Connection {
|
|||
Rc::downgrade(self),
|
||||
&syms,
|
||||
QueryMode::Normal,
|
||||
None,
|
||||
)?);
|
||||
Ok(Statement::new(
|
||||
program,
|
||||
|
@ -393,6 +394,7 @@ impl Connection {
|
|||
Rc::downgrade(self),
|
||||
&syms,
|
||||
cmd.into(),
|
||||
None,
|
||||
)?;
|
||||
let stmt = Statement::new(
|
||||
program.into(),
|
||||
|
@ -454,6 +456,7 @@ impl Connection {
|
|||
Rc::downgrade(self),
|
||||
&syms,
|
||||
QueryMode::Explain,
|
||||
None,
|
||||
)?;
|
||||
let _ = std::io::stdout().write_all(program.explain().as_bytes());
|
||||
}
|
||||
|
@ -470,6 +473,7 @@ impl Connection {
|
|||
Rc::downgrade(self),
|
||||
&syms,
|
||||
QueryMode::Normal,
|
||||
None,
|
||||
)?;
|
||||
|
||||
let mut state =
|
||||
|
|
|
@ -16,18 +16,25 @@ pub fn translate_delete(
|
|||
where_clause: Option<Box<Expr>>,
|
||||
limit: Option<Box<Limit>>,
|
||||
syms: &SymbolTable,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> Result<ProgramBuilder> {
|
||||
let mut delete_plan = prepare_delete_plan(schema, tbl_name, where_clause, limit)?;
|
||||
optimize_plan(&mut delete_plan, schema)?;
|
||||
let Plan::Delete(ref delete) = delete_plan else {
|
||||
panic!("delete_plan is not a DeletePlan");
|
||||
};
|
||||
let mut program = ProgramBuilder::new(ProgramBuilderOpts {
|
||||
let opts = ProgramBuilderOpts {
|
||||
query_mode,
|
||||
num_cursors: 1,
|
||||
approx_num_insns: estimate_num_instructions(delete),
|
||||
approx_num_labels: 0,
|
||||
});
|
||||
};
|
||||
let mut program = if let Some(mut program) = program {
|
||||
program.extend(&opts);
|
||||
program
|
||||
} else {
|
||||
ProgramBuilder::new(opts)
|
||||
};
|
||||
emit_program(&mut program, delete_plan, syms)?;
|
||||
Ok(program)
|
||||
}
|
||||
|
|
|
@ -21,15 +21,22 @@ pub fn translate_create_index(
|
|||
tbl_name: &str,
|
||||
columns: &[SortedColumn],
|
||||
schema: &Schema,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> crate::Result<ProgramBuilder> {
|
||||
let idx_name = normalize_ident(idx_name);
|
||||
let tbl_name = normalize_ident(tbl_name);
|
||||
let mut program = ProgramBuilder::new(crate::vdbe::builder::ProgramBuilderOpts {
|
||||
let opts = crate::vdbe::builder::ProgramBuilderOpts {
|
||||
query_mode: mode,
|
||||
num_cursors: 5,
|
||||
approx_num_insns: 40,
|
||||
approx_num_labels: 5,
|
||||
});
|
||||
};
|
||||
let mut program = if let Some(mut program) = program {
|
||||
program.extend(&opts);
|
||||
program
|
||||
} else {
|
||||
ProgramBuilder::new(opts)
|
||||
};
|
||||
|
||||
// Check if the index is being created on a valid btree table and
|
||||
// the name is globally unique in the schema.
|
||||
|
@ -311,14 +318,21 @@ pub fn translate_drop_index(
|
|||
idx_name: &str,
|
||||
if_exists: bool,
|
||||
schema: &Schema,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> crate::Result<ProgramBuilder> {
|
||||
let idx_name = normalize_ident(idx_name);
|
||||
let mut program = ProgramBuilder::new(crate::vdbe::builder::ProgramBuilderOpts {
|
||||
let opts = crate::vdbe::builder::ProgramBuilderOpts {
|
||||
query_mode: mode,
|
||||
num_cursors: 5,
|
||||
approx_num_insns: 40,
|
||||
approx_num_labels: 5,
|
||||
});
|
||||
};
|
||||
let mut program = if let Some(mut program) = program {
|
||||
program.extend(&opts);
|
||||
program
|
||||
} else {
|
||||
ProgramBuilder::new(opts)
|
||||
};
|
||||
|
||||
// Find the index in Schema
|
||||
let mut maybe_index = None;
|
||||
|
|
|
@ -34,13 +34,20 @@ pub fn translate_insert(
|
|||
body: &mut InsertBody,
|
||||
_returning: &Option<Vec<ResultColumn>>,
|
||||
syms: &SymbolTable,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> Result<ProgramBuilder> {
|
||||
let mut program = ProgramBuilder::new(ProgramBuilderOpts {
|
||||
let opts = ProgramBuilderOpts {
|
||||
query_mode,
|
||||
num_cursors: 1,
|
||||
approx_num_insns: 30,
|
||||
approx_num_labels: 5,
|
||||
});
|
||||
};
|
||||
let mut program = if let Some(mut program) = program {
|
||||
program.extend(&opts);
|
||||
program
|
||||
} else {
|
||||
ProgramBuilder::new(opts)
|
||||
};
|
||||
if with.is_some() {
|
||||
crate::bail_parse_error!("WITH clause is not supported");
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ use std::sync::Arc;
|
|||
use transaction::{translate_tx_begin, translate_tx_commit};
|
||||
use update::translate_update;
|
||||
|
||||
// TODO: for now leaving the return value as a Program. But ideally to support nested parsing of arbitraty
|
||||
// statements, we would have to return a program builder instead
|
||||
/// Translate SQL statement into bytecode program.
|
||||
pub fn translate(
|
||||
schema: &Schema,
|
||||
|
@ -60,6 +62,7 @@ pub fn translate(
|
|||
connection: Weak<Connection>,
|
||||
syms: &SymbolTable,
|
||||
query_mode: QueryMode,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> Result<Program> {
|
||||
let mut change_cnt_on = false;
|
||||
|
||||
|
@ -110,6 +113,7 @@ pub fn translate(
|
|||
&mut update,
|
||||
syms,
|
||||
ParseSchema::Reload,
|
||||
program,
|
||||
)?
|
||||
}
|
||||
_ => todo!(),
|
||||
|
@ -135,6 +139,7 @@ pub fn translate(
|
|||
&tbl_name.0,
|
||||
&columns,
|
||||
schema,
|
||||
program,
|
||||
)?
|
||||
}
|
||||
ast::Stmt::CreateTable {
|
||||
|
@ -149,11 +154,12 @@ pub fn translate(
|
|||
*body,
|
||||
if_not_exists,
|
||||
schema,
|
||||
program,
|
||||
)?,
|
||||
ast::Stmt::CreateTrigger { .. } => bail_parse_error!("CREATE TRIGGER not supported yet"),
|
||||
ast::Stmt::CreateView { .. } => bail_parse_error!("CREATE VIEW not supported yet"),
|
||||
ast::Stmt::CreateVirtualTable(vtab) => {
|
||||
translate_create_virtual_table(*vtab, schema, query_mode, &syms)?
|
||||
translate_create_virtual_table(*vtab, schema, query_mode, &syms, program)?
|
||||
}
|
||||
ast::Stmt::Delete(delete) => {
|
||||
let Delete {
|
||||
|
@ -163,17 +169,25 @@ pub fn translate(
|
|||
..
|
||||
} = *delete;
|
||||
change_cnt_on = true;
|
||||
translate_delete(query_mode, schema, &tbl_name, where_clause, limit, syms)?
|
||||
translate_delete(
|
||||
query_mode,
|
||||
schema,
|
||||
&tbl_name,
|
||||
where_clause,
|
||||
limit,
|
||||
syms,
|
||||
program,
|
||||
)?
|
||||
}
|
||||
ast::Stmt::Detach(_) => bail_parse_error!("DETACH not supported yet"),
|
||||
ast::Stmt::DropIndex {
|
||||
if_exists,
|
||||
idx_name,
|
||||
} => translate_drop_index(query_mode, &idx_name.name.0, if_exists, schema)?,
|
||||
} => translate_drop_index(query_mode, &idx_name.name.0, if_exists, schema, program)?,
|
||||
ast::Stmt::DropTable {
|
||||
if_exists,
|
||||
tbl_name,
|
||||
} => translate_drop_table(query_mode, tbl_name, if_exists, schema)?,
|
||||
} => translate_drop_table(query_mode, tbl_name, if_exists, schema, program)?,
|
||||
ast::Stmt::DropTrigger { .. } => bail_parse_error!("DROP TRIGGER not supported yet"),
|
||||
ast::Stmt::DropView { .. } => bail_parse_error!("DROP VIEW not supported yet"),
|
||||
ast::Stmt::Pragma(name, body) => pragma::translate_pragma(
|
||||
|
@ -183,15 +197,21 @@ pub fn translate(
|
|||
body.map(|b| *b),
|
||||
database_header.clone(),
|
||||
pager,
|
||||
program,
|
||||
)?,
|
||||
ast::Stmt::Reindex { .. } => bail_parse_error!("REINDEX not supported yet"),
|
||||
ast::Stmt::Release(_) => bail_parse_error!("RELEASE not supported yet"),
|
||||
ast::Stmt::Rollback { .. } => bail_parse_error!("ROLLBACK not supported yet"),
|
||||
ast::Stmt::Savepoint(_) => bail_parse_error!("SAVEPOINT not supported yet"),
|
||||
ast::Stmt::Select(select) => translate_select(query_mode, schema, *select, syms)?,
|
||||
ast::Stmt::Update(mut update) => {
|
||||
translate_update(query_mode, schema, &mut update, syms, ParseSchema::None)?
|
||||
}
|
||||
ast::Stmt::Select(select) => translate_select(query_mode, schema, *select, syms, program)?,
|
||||
ast::Stmt::Update(mut update) => translate_update(
|
||||
query_mode,
|
||||
schema,
|
||||
&mut update,
|
||||
syms,
|
||||
ParseSchema::None,
|
||||
program,
|
||||
)?,
|
||||
ast::Stmt::Vacuum(_, _) => bail_parse_error!("VACUUM not supported yet"),
|
||||
ast::Stmt::Insert(insert) => {
|
||||
let Insert {
|
||||
|
@ -213,6 +233,7 @@ pub fn translate(
|
|||
&mut body,
|
||||
&returning,
|
||||
syms,
|
||||
program,
|
||||
)?
|
||||
}
|
||||
};
|
||||
|
|
|
@ -41,13 +41,20 @@ pub fn translate_pragma(
|
|||
body: Option<ast::PragmaBody>,
|
||||
database_header: Arc<SpinLock<DatabaseHeader>>,
|
||||
pager: Rc<Pager>,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> crate::Result<ProgramBuilder> {
|
||||
let mut program = ProgramBuilder::new(ProgramBuilderOpts {
|
||||
let opts = ProgramBuilderOpts {
|
||||
query_mode,
|
||||
num_cursors: 0,
|
||||
approx_num_insns: 20,
|
||||
approx_num_labels: 0,
|
||||
});
|
||||
};
|
||||
let mut program = if let Some(mut program) = program {
|
||||
program.extend(&opts);
|
||||
program
|
||||
} else {
|
||||
ProgramBuilder::new(opts)
|
||||
};
|
||||
let init_label = program.emit_init();
|
||||
let start_offset = program.offset();
|
||||
let mut write = false;
|
||||
|
|
|
@ -34,16 +34,23 @@ pub fn translate_create_table(
|
|||
body: ast::CreateTableBody,
|
||||
if_not_exists: bool,
|
||||
schema: &Schema,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> Result<ProgramBuilder> {
|
||||
if temporary {
|
||||
bail_parse_error!("TEMPORARY table not supported yet");
|
||||
}
|
||||
let mut program = ProgramBuilder::new(ProgramBuilderOpts {
|
||||
let opts = ProgramBuilderOpts {
|
||||
query_mode,
|
||||
num_cursors: 1,
|
||||
approx_num_insns: 30,
|
||||
approx_num_labels: 1,
|
||||
});
|
||||
};
|
||||
let mut program = if let Some(mut program) = program {
|
||||
program.extend(&opts);
|
||||
program
|
||||
} else {
|
||||
ProgramBuilder::new(opts)
|
||||
};
|
||||
if schema.get_table(tbl_name.name.0.as_str()).is_some() {
|
||||
if if_not_exists {
|
||||
let init_label = program.emit_init();
|
||||
|
@ -533,6 +540,7 @@ pub fn translate_create_virtual_table(
|
|||
schema: &Schema,
|
||||
query_mode: QueryMode,
|
||||
syms: &SymbolTable,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> Result<ProgramBuilder> {
|
||||
let ast::CreateVirtualTable {
|
||||
if_not_exists,
|
||||
|
@ -570,12 +578,18 @@ pub fn translate_create_virtual_table(
|
|||
bail_parse_error!("Table {} already exists", tbl_name);
|
||||
}
|
||||
|
||||
let mut program = ProgramBuilder::new(ProgramBuilderOpts {
|
||||
let opts = ProgramBuilderOpts {
|
||||
query_mode,
|
||||
num_cursors: 2,
|
||||
approx_num_insns: 40,
|
||||
approx_num_labels: 2,
|
||||
});
|
||||
};
|
||||
let mut program = if let Some(mut program) = program {
|
||||
program.extend(&opts);
|
||||
program
|
||||
} else {
|
||||
ProgramBuilder::new(opts)
|
||||
};
|
||||
let init_label = program.emit_init();
|
||||
let start_offset = program.offset();
|
||||
let module_name_reg = program.emit_string8_new_reg(module_name_str.clone());
|
||||
|
@ -648,13 +662,20 @@ pub fn translate_drop_table(
|
|||
tbl_name: ast::QualifiedName,
|
||||
if_exists: bool,
|
||||
schema: &Schema,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> Result<ProgramBuilder> {
|
||||
let mut program = ProgramBuilder::new(ProgramBuilderOpts {
|
||||
let opts = ProgramBuilderOpts {
|
||||
query_mode,
|
||||
num_cursors: 1,
|
||||
approx_num_insns: 30,
|
||||
approx_num_labels: 1,
|
||||
});
|
||||
};
|
||||
let mut program = if let Some(mut program) = program {
|
||||
program.extend(&opts);
|
||||
program
|
||||
} else {
|
||||
ProgramBuilder::new(opts)
|
||||
};
|
||||
let table = schema.get_table(tbl_name.name.0.as_str());
|
||||
if table.is_none() {
|
||||
if if_exists {
|
||||
|
|
|
@ -24,6 +24,7 @@ pub fn translate_select(
|
|||
schema: &Schema,
|
||||
select: ast::Select,
|
||||
syms: &SymbolTable,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> Result<ProgramBuilder> {
|
||||
let mut select_plan = prepare_select_plan(schema, select, syms, None)?;
|
||||
optimize_plan(&mut select_plan, schema)?;
|
||||
|
@ -31,12 +32,18 @@ pub fn translate_select(
|
|||
panic!("select_plan is not a SelectPlan");
|
||||
};
|
||||
|
||||
let mut program = ProgramBuilder::new(ProgramBuilderOpts {
|
||||
let opts = ProgramBuilderOpts {
|
||||
query_mode,
|
||||
num_cursors: count_plan_required_cursors(select),
|
||||
approx_num_insns: estimate_num_instructions(select),
|
||||
approx_num_labels: estimate_num_labels(select),
|
||||
});
|
||||
};
|
||||
let mut program = if let Some(mut program) = program {
|
||||
program.extend(&opts);
|
||||
program
|
||||
} else {
|
||||
ProgramBuilder::new(opts)
|
||||
};
|
||||
emit_program(&mut program, select_plan, syms)?;
|
||||
Ok(program)
|
||||
}
|
||||
|
|
|
@ -52,16 +52,23 @@ pub fn translate_update(
|
|||
body: &mut Update,
|
||||
syms: &SymbolTable,
|
||||
parse_schema: ParseSchema,
|
||||
program: Option<ProgramBuilder>,
|
||||
) -> crate::Result<ProgramBuilder> {
|
||||
let mut plan = prepare_update_plan(schema, body, parse_schema)?;
|
||||
optimize_plan(&mut plan, schema)?;
|
||||
// TODO: freestyling these numbers
|
||||
let mut program = ProgramBuilder::new(ProgramBuilderOpts {
|
||||
let opts = ProgramBuilderOpts {
|
||||
query_mode,
|
||||
num_cursors: 1,
|
||||
approx_num_insns: 20,
|
||||
approx_num_labels: 4,
|
||||
});
|
||||
};
|
||||
let mut program = if let Some(mut program) = program {
|
||||
program.extend(&opts);
|
||||
program
|
||||
} else {
|
||||
ProgramBuilder::new(opts)
|
||||
};
|
||||
emit_program(&mut program, plan, syms)?;
|
||||
Ok(program)
|
||||
}
|
||||
|
|
|
@ -104,6 +104,13 @@ impl ProgramBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn extend(&mut self, opts: &ProgramBuilderOpts) {
|
||||
self.insns.reserve(opts.approx_num_insns);
|
||||
self.cursor_ref.reserve(opts.num_cursors);
|
||||
self.label_to_resolved_offset
|
||||
.reserve(opts.approx_num_labels);
|
||||
}
|
||||
|
||||
/// Start a new constant span. The next instruction to be emitted will be the first
|
||||
/// instruction in the span.
|
||||
pub fn constant_span_start(&mut self) -> usize {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue