refactor to include optional program builder argument

This commit is contained in:
pedrocarlo 2025-05-21 01:42:37 -03:00
parent 696c98877c
commit 517c7c81cd
10 changed files with 130 additions and 28 deletions

View file

@ -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 =

View file

@ -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)
}

View file

@ -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;

View file

@ -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");
}

View file

@ -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,
)?
}
};

View file

@ -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;

View file

@ -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 {

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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 {