diff --git a/core/lib.rs b/core/lib.rs index cdb35549b..21650f46d 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -186,7 +186,6 @@ impl Connection { match cmd { Cmd::Stmt(stmt) => { let program = Rc::new(translate::translate( - sql.as_str(), &*self.schema.borrow(), stmt, self.header.clone(), @@ -212,7 +211,6 @@ impl Connection { match cmd { Cmd::Stmt(stmt) => { let program = Rc::new(translate::translate( - sql.as_str(), &*self.schema.borrow(), stmt, self.header.clone(), @@ -224,7 +222,6 @@ impl Connection { } Cmd::Explain(stmt) => { let program = translate::translate( - sql.as_str(), &*self.schema.borrow(), stmt, self.header.clone(), @@ -259,7 +256,6 @@ impl Connection { match cmd { Cmd::Explain(stmt) => { let program = translate::translate( - sql.as_str(), &*self.schema.borrow(), stmt, self.header.clone(), @@ -271,7 +267,6 @@ impl Connection { Cmd::ExplainQueryPlan(_stmt) => todo!(), Cmd::Stmt(stmt) => { let program = translate::translate( - sql.as_str(), &*self.schema.borrow(), stmt, self.header.clone(), diff --git a/core/translate/mod.rs b/core/translate/mod.rs index c78b196a6..cb2463239 100644 --- a/core/translate/mod.rs +++ b/core/translate/mod.rs @@ -16,6 +16,7 @@ pub(crate) mod planner; pub(crate) mod select; use std::cell::RefCell; +use std::fmt::Display; use std::rc::{Rc, Weak}; use crate::schema::Schema; @@ -26,10 +27,10 @@ use crate::{bail_parse_error, Connection, Result}; use insert::translate_insert; use select::translate_select; use sqlite3_parser::ast; +use sqlite3_parser::ast::fmt::ToTokens; /// Translate SQL statement into bytecode program. pub fn translate( - sql: &str, // raw sql query before parsing into stmt, useful for CREATE TABLE schema: &Schema, stmt: ast::Stmt, database_header: Rc>, @@ -53,7 +54,6 @@ pub fn translate( bail_parse_error!("TEMPORARY table not supported yet"); } translate_create_table( - sql, tbl_name, body, if_not_exists, @@ -144,7 +144,6 @@ addr opcode p1 p2 p3 p4 p5 comment */ fn translate_create_table( - sql: &str, tbl_name: ast::QualifiedName, body: ast::CreateTableBody, if_not_exists: bool, @@ -153,6 +152,33 @@ fn translate_create_table( schema: &Schema, ) -> Result { let mut program = ProgramBuilder::new(); + if schema.get_table(tbl_name.name.0.as_str()).is_some() { + if if_not_exists { + 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(); + program.emit_insn(Insn::Halt { + err_code: 0, + description: String::new(), + }); + program.resolve_label(init_label, program.offset()); + program.emit_insn(Insn::Transaction { write: true }); + program.emit_constant_insns(); + program.emit_insn(Insn::Goto { + target_pc: start_offset, + }); + return Ok(program.build(database_header, connection)); + } + bail_parse_error!("Table {} already exists", tbl_name); + } + + let sql = create_table_body_to_str(&tbl_name, &body); + let parse_schema_label = program.allocate_label(); let init_label = program.allocate_label(); program.emit_insn_with_label_dependency( @@ -362,3 +388,27 @@ fn update_pragma(name: &str, value: i64, header: Rc>, pa _ => todo!(), } } + +struct TableFormatter<'a> { + body: &'a ast::CreateTableBody, +} +impl<'a> Display for TableFormatter<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.body.to_fmt(f) + } +} + +fn create_table_body_to_str(tbl_name: &ast::QualifiedName, body: &ast::CreateTableBody) -> String { + let mut sql = String::new(); + let formatter = TableFormatter { body }; + sql.push_str(format!("CREATE TABLE {} {}", tbl_name.name.0, formatter).as_str()); + match body { + ast::CreateTableBody::ColumnsAndConstraints { + columns: _, + constraints: _, + options: _, + } => {} + ast::CreateTableBody::AsSelect(_select) => todo!("as select not yet supported"), + } + sql +} diff --git a/core/vdbe/builder.rs b/core/vdbe/builder.rs index e9d8ac953..2c7561c28 100644 --- a/core/vdbe/builder.rs +++ b/core/vdbe/builder.rs @@ -319,7 +319,7 @@ impl ProgramBuilder { assert!(*target_pc < 0); *target_pc = to_offset; } - Insn::IsNull { src, target_pc } => { + Insn::IsNull { src: _, target_pc } => { assert!(*target_pc < 0); *target_pc = to_offset; }