mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 01:58:16 +00:00
core: basic op explain insert
This commit is contained in:
parent
0c703a228d
commit
bbed54d11c
4 changed files with 339 additions and 1 deletions
96
core/translate/insert.rs
Normal file
96
core/translate/insert.rs
Normal 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())
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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} {}",
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue