core: basic op explain insert

This commit is contained in:
Pere Diaz Bou 2024-07-20 15:47:59 +02:00
parent 0c703a228d
commit bbed54d11c
4 changed files with 339 additions and 1 deletions

96
core/translate/insert.rs Normal file
View file

@ -0,0 +1,96 @@
use std::{ops::Deref, rc::Rc};
use sqlite3_parser::ast::{
DistinctNames, InsertBody, Name, QualifiedName, ResolveType, ResultColumn, Select, With,
};
use crate::Result;
use crate::{
schema::{self, Schema, Table},
translate::expr::resolve_ident_qualified,
vdbe::{builder::ProgramBuilder, Insn, Program},
};
pub fn translate_insert(
schema: &Schema,
with: &Option<With>,
or_conflict: &Option<ResolveType>,
tbl_name: &QualifiedName,
columns: &Option<DistinctNames>,
body: &InsertBody,
returning: &Option<Vec<ResultColumn>>,
) -> Result<Program> {
assert!(with.is_none());
assert!(or_conflict.is_none());
let mut program = ProgramBuilder::new();
let init_label = program.allocate_label();
program.emit_insn_with_label_dependency(
Insn::Init {
target_pc: init_label,
},
init_label,
);
let start_offset = program.offset();
dbg!(tbl_name);
dbg!(columns);
dbg!(returning);
dbg!(with);
dbg!(body);
let yield_reg = program.alloc_register();
let jump_on_definition_label = program.allocate_label();
program.emit_insn(Insn::InitCoroutine {
yield_reg,
jump_on_definition: jump_on_definition_label,
start_offset: program.offset() + 1,
});
match body {
InsertBody::Select(select, None) => match &select.body.select {
sqlite3_parser::ast::OneSelect::Select {
distinctness: _,
columns: _,
from: _,
where_clause: _,
group_by: _,
window_clause: _,
} => todo!(),
sqlite3_parser::ast::OneSelect::Values(values) => {}
},
InsertBody::DefaultValues => todo!("default values not yet supported"),
_ => todo!(),
}
program.emit_insn(Insn::EndCoroutine { yield_reg });
// open table
let table_name = &tbl_name.name;
let table = match schema.get_table(table_name.0.as_str()) {
Some(table) => table,
None => crate::bail_corrupt_error!("Parse error: no such table: {}", table_name),
};
let table = Rc::new(Table::BTree(table));
let cursor_id = program.alloc_cursor_id(
Some(table_name.0.clone()),
Some(table.clone().deref().clone()),
);
let root_page = match table.as_ref() {
Table::BTree(btree) => btree.root_page,
Table::Pseudo(_) => todo!(),
};
program.emit_insn(Insn::OpenWriteAsync {
cursor_id,
root_page,
});
program.emit_insn(Insn::OpenWriteAwait {});
program.emit_insn(Insn::Halt);
program.resolve_label(init_label, program.offset());
program.emit_insn(Insn::Transaction);
program.emit_constant_insns();
program.emit_insn(Insn::Goto {
target_pc: start_offset,
});
program.resolve_deferred_labels();
Ok(program.build())
}

View file

@ -8,6 +8,7 @@
//! will read rows from the database and filter them according to a WHERE clause.
pub(crate) mod expr;
pub(crate) mod insert;
pub(crate) mod select;
pub(crate) mod where_clause;
@ -20,6 +21,7 @@ use crate::sqlite3_ondisk::{DatabaseHeader, MIN_PAGE_CACHE_SIZE};
use crate::util::normalize_ident;
use crate::vdbe::{builder::ProgramBuilder, Insn, Program};
use crate::{bail_parse_error, Result};
use insert::translate_insert;
use select::{prepare_select, translate_select};
use sqlite3_parser::ast;
@ -49,7 +51,6 @@ pub fn translate(
ast::Stmt::DropTable { .. } => bail_parse_error!("DROP TABLE not supported yet"),
ast::Stmt::DropTrigger { .. } => bail_parse_error!("DROP TRIGGER not supported yet"),
ast::Stmt::DropView { .. } => bail_parse_error!("DROP VIEW not supported yet"),
ast::Stmt::Insert { .. } => bail_parse_error!("INSERT not supported yet"),
ast::Stmt::Pragma(name, body) => translate_pragma(&name, body, database_header, pager),
ast::Stmt::Reindex { .. } => bail_parse_error!("REINDEX not supported yet"),
ast::Stmt::Release(_) => bail_parse_error!("RELEASE not supported yet"),
@ -61,6 +62,22 @@ pub fn translate(
}
ast::Stmt::Update { .. } => bail_parse_error!("UPDATE not supported yet"),
ast::Stmt::Vacuum(_, _) => bail_parse_error!("VACUUM not supported yet"),
ast::Stmt::Insert {
with,
or_conflict,
tbl_name,
columns,
body,
returning,
} => translate_insert(
schema,
&with,
&or_conflict,
&tbl_name,
&columns,
&body,
&returning,
),
}
}

View file

@ -507,6 +507,137 @@ pub fn insn_to_str(program: &Program, addr: InsnReference, insn: &Insn, indent:
0,
format!("r[{}]=func(r[{}..])", dest, start_reg),
),
Insn::InitCoroutine {
yield_reg,
jump_on_definition,
start_offset,
} => (
"InitCoroutine",
*yield_reg as i32,
*jump_on_definition as i32,
*start_offset as i32,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
Insn::EndCoroutine { yield_reg } => (
"EndCoroutine",
*yield_reg as i32,
0,
0,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
Insn::Yield {
yield_reg,
end_offset,
} => (
"Yield",
*yield_reg as i32,
*end_offset as i32,
0,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
Insn::InsertAsync {
cursor,
key_reg,
record_reg,
flag,
} => (
"InsertAsync",
*cursor as i32,
*record_reg as i32,
*key_reg as i32,
OwnedValue::Text(Rc::new("".to_string())),
*flag as u16,
format!(""),
),
Insn::InsertAwait {} => (
"InsertAwait",
0,
0,
0,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
Insn::NewRowid { reg } => (
"NewRowId",
0,
*reg as i32,
0,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
Insn::MustBeInt { reg } => (
"MustBeInt",
*reg as i32,
0,
0,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
Insn::SoftNull { reg } => (
"SoftNull",
*reg as i32,
0,
0,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
Insn::NotExists {
cursor,
rowid_reg,
target_pc,
} => (
"NotExists",
*cursor as i32,
*target_pc as i32,
*rowid_reg as i32,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
Insn::OpenWriteAsync {
cursor_id,
root_page,
} => (
"OpenWriteAsync",
*cursor_id as i32,
*root_page as i32,
0,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
Insn::OpenWriteAwait {} => (
"OpenWriteAsync",
0,
0,
0,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
Insn::Copy {
src_reg,
dst_reg,
amount,
} => (
"Copy",
*src_reg as i32,
*dst_reg as i32,
*amount as i32,
OwnedValue::Text(Rc::new("".to_string())),
0,
format!(""),
),
};
format!(
"{:<4} {:<17} {:<4} {:<4} {:<4} {:<13} {:<2} {}",

View file

@ -279,6 +279,61 @@ pub enum Insn {
dest: usize, // P3
func: ScalarFunc, // P4
},
InitCoroutine {
yield_reg: usize,
jump_on_definition: BranchOffset,
start_offset: BranchOffset,
},
EndCoroutine {
yield_reg: usize,
},
Yield {
yield_reg: usize,
end_offset: BranchOffset,
},
InsertAsync {
cursor: CursorID,
key_reg: usize, // Must be int.
record_reg: usize, // Blob of record data.
flag: usize, // Flags used by insert, for now not used.
},
InsertAwait {},
NewRowid {
reg: usize,
},
MustBeInt {
reg: usize,
},
SoftNull {
reg: usize,
},
NotExists {
cursor: CursorID,
rowid_reg: usize,
target_pc: BranchOffset,
},
OpenWriteAsync {
cursor_id: CursorID,
root_page: PageIdx,
},
OpenWriteAwait {},
Copy {
src_reg: usize,
dst_reg: usize,
amount: usize, // 0 amount means we include src_reg, dst_reg..=dst_reg+amount = src_reg..=src_reg+amount
},
}
// Index of insn in list of insns
@ -1198,6 +1253,45 @@ impl Program {
state.pc += 1;
}
},
Insn::InitCoroutine {
yield_reg,
jump_on_definition,
start_offset,
} => todo!(),
Insn::EndCoroutine { yield_reg } => todo!(),
Insn::Yield {
yield_reg,
end_offset,
} => todo!(),
Insn::InsertAsync {
cursor,
key_reg,
record_reg,
flag,
} => todo!(),
Insn::InsertAwait {} => todo!(),
Insn::NewRowid { reg } => todo!(),
Insn::MustBeInt { reg } => todo!(),
Insn::SoftNull { reg } => todo!(),
Insn::NotExists {
cursor,
rowid_reg,
target_pc,
} => todo!(),
Insn::OpenWriteAsync {
cursor_id,
root_page,
} => todo!(),
Insn::OpenWriteAwait {} => todo!(),
Insn::Copy {
src_reg,
dst_reg,
amount,
} => {
for i in 0..=*amount {
state.registers[*dst_reg + i] = state.registers[*src_reg + i].clone();
}
}
}
}
}