diff --git a/core/schema.rs b/core/schema.rs index d91a8a9e8..b910a81e2 100644 --- a/core/schema.rs +++ b/core/schema.rs @@ -83,6 +83,13 @@ impl Table { Table::Pseudo(table) => &table.columns, } } + + pub fn has_rowid(&self) -> bool { + match self { + Table::BTree(table) => table.has_rowid, + Table::Pseudo(_) => todo!(), + } + } } impl PartialEq for Table { diff --git a/core/translate/expr.rs b/core/translate/expr.rs index 163357978..1d5c5ea6e 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -11,7 +11,7 @@ use crate::{ pub fn translate_expr( program: &mut ProgramBuilder, - select: &Select, + select: Option<&Select>, expr: &ast::Expr, target_register: usize, cursor_hint: Option, @@ -435,7 +435,7 @@ pub fn translate_expr( ast::Expr::Parenthesized(_) => todo!(), ast::Expr::Qualified(tbl, ident) => { let (idx, col_type, cursor_id, is_primary_key) = - resolve_ident_qualified(program, &tbl.0, &ident.0, select, cursor_hint)?; + resolve_ident_qualified(program, &tbl.0, &ident.0, select.unwrap(), cursor_hint)?; if is_primary_key { program.emit_insn(Insn::RowId { cursor_id, @@ -614,12 +614,12 @@ pub fn resolve_ident_qualified( pub fn resolve_ident_table( program: &ProgramBuilder, ident: &String, - select: &Select, + select: Option<&Select>, cursor_hint: Option, ) -> Result<(usize, Type, usize, bool)> { let ident = normalize_ident(ident); let mut found = Vec::new(); - for join in &select.src_tables { + for join in &select.unwrap().src_tables { match join.table { Table::BTree(ref table) => { let res = table diff --git a/core/translate/insert.rs b/core/translate/insert.rs index 851384a66..3a614ae4b 100644 --- a/core/translate/insert.rs +++ b/core/translate/insert.rs @@ -7,7 +7,7 @@ use sqlite3_parser::ast::{ use crate::Result; use crate::{ schema::{self, Schema, Table}, - translate::expr::resolve_ident_qualified, + translate::expr::{resolve_ident_qualified, translate_expr}, vdbe::{builder::ProgramBuilder, Insn, Program}, }; @@ -37,31 +37,6 @@ pub fn translate_insert( 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; @@ -78,12 +53,131 @@ pub fn translate_insert( Table::BTree(btree) => btree.root_page, Table::Pseudo(_) => todo!(), }; + + let mut num_cols = table.columns().len(); + if table.has_rowid() { + num_cols += 1; + } + // column_registers_start[0] == rowid if has rowid + let column_registers_start = program.alloc_registers(num_cols); + + // Coroutine for values + let yield_reg = program.alloc_register(); + let jump_on_definition_label = program.allocate_label(); + { + program.emit_insn_with_label_dependency( + Insn::InitCoroutine { + yield_reg, + jump_on_definition: jump_on_definition_label, + start_offset: program.offset() + 1, + }, + jump_on_definition_label, + ); + 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) => { + for value in values { + for (col, expr) in value.iter().enumerate() { + let mut col = col; + if table.has_rowid() { + col += 1; + } + translate_expr( + &mut program, + None, + expr, + column_registers_start + col, + None, + )?; + } + program.emit_insn(Insn::Yield { + yield_reg, + end_offset: 0, + }); + } + } + }, + InsertBody::DefaultValues => todo!("default values not yet supported"), + _ => todo!(), + } + program.emit_insn(Insn::EndCoroutine { yield_reg }); + } + + program.resolve_label(jump_on_definition_label, program.offset()); program.emit_insn(Insn::OpenWriteAsync { cursor_id, root_page, }); program.emit_insn(Insn::OpenWriteAwait {}); + // Main loop + let record_register = program.alloc_register(); + let halt_label = program.allocate_label(); + program.emit_insn_with_label_dependency( + Insn::Yield { + yield_reg, + end_offset: halt_label, + }, + halt_label, + ); + + if table.has_rowid() { + let key_reg = column_registers_start + 1; + let row_id_reg = column_registers_start; + // copy key to rowid + program.emit_insn(Insn::Copy { + src_reg: key_reg, + dst_reg: row_id_reg, + amount: 0, + }); + program.emit_insn(Insn::SoftNull { reg: key_reg }); + + let notnull_label = program.allocate_label(); + program.emit_insn_with_label_dependency( + Insn::NotNull { + reg: row_id_reg, + target_pc: notnull_label, + }, + notnull_label, + ); + program.emit_insn(Insn::NewRowid { reg: row_id_reg }); + + program.resolve_label(notnull_label, program.offset()); + program.emit_insn(Insn::MustBeInt { reg: row_id_reg }); + let make_record_label = program.allocate_label(); + program.emit_insn_with_label_dependency( + Insn::NotExists { + cursor: cursor_id, + rowid_reg: row_id_reg, + target_pc: make_record_label, + }, + make_record_label, + ); + program.emit_insn(Insn::Halt); // Add error code 1555 and rollback + program.resolve_label(make_record_label, program.offset()); + program.emit_insn(Insn::MakeRecord { + start_reg: column_registers_start, + count: num_cols, + dest_reg: record_register, + }); + program.emit_insn(Insn::InsertAsync { + cursor: cursor_id, + key_reg: column_registers_start, + record_reg: record_register, + flag: 0, + }); + program.emit_insn(Insn::InsertAwait {}); + } + + program.resolve_label(halt_label, program.offset()); program.emit_insn(Insn::Halt); program.resolve_label(init_label, program.offset()); program.emit_insn(Insn::Transaction); diff --git a/core/translate/select.rs b/core/translate/select.rs index fe832dcaf..5e79039d5 100644 --- a/core/translate/select.rs +++ b/core/translate/select.rs @@ -274,7 +274,13 @@ pub fn translate_select(mut select: Select) -> Result { let limit_info = if let Some(limit) = &select.limit { assert!(limit.offset.is_none()); let target_register = program.alloc_register(); - let limit_reg = translate_expr(&mut program, &select, &limit.expr, target_register, None)?; + let limit_reg = translate_expr( + &mut program, + Some(&select), + &limit.expr, + target_register, + None, + )?; let num = if let ast::Expr::Literal(ast::Literal::Numeric(num)) = &limit.expr { num.parse::()? } else { @@ -326,7 +332,7 @@ pub fn translate_select(mut select: Select) -> Result { } else { &col.expr }; - translate_expr(&mut program, &select, sort_col_expr, target, None)?; + translate_expr(&mut program, Some(&select), sort_col_expr, target, None)?; } let (_, result_cols_count) = translate_columns(&mut program, &select, None)?; sort_info @@ -742,7 +748,7 @@ fn translate_column( cursor_hint, )?; } else { - let _ = translate_expr(program, select, expr, target_register, cursor_hint)?; + let _ = translate_expr(program, Some(select), expr, target_register, cursor_hint)?; } } ast::ResultColumn::Star => { @@ -807,7 +813,7 @@ fn translate_aggregation( } let expr = &args[0]; let expr_reg = program.alloc_register(); - let _ = translate_expr(program, select, expr, expr_reg, cursor_hint)?; + let _ = translate_expr(program, Some(select), expr, expr_reg, cursor_hint)?; program.emit_insn(Insn::AggStep { acc_reg: target_register, col: expr_reg, @@ -822,7 +828,7 @@ fn translate_aggregation( } else { let expr = &args[0]; let expr_reg = program.alloc_register(); - let _ = translate_expr(program, select, expr, expr_reg, cursor_hint); + let _ = translate_expr(program, Some(select), expr, expr_reg, cursor_hint); expr_reg }; program.emit_insn(Insn::AggStep { @@ -865,8 +871,14 @@ fn translate_aggregation( ast::Expr::Literal(ast::Literal::String(String::from("\",\""))); } - translate_expr(program, select, expr, expr_reg, cursor_hint)?; - translate_expr(program, select, &delimiter_expr, delimiter_reg, cursor_hint)?; + translate_expr(program, Some(select), expr, expr_reg, cursor_hint)?; + translate_expr( + program, + Some(select), + &delimiter_expr, + delimiter_reg, + cursor_hint, + )?; program.emit_insn(Insn::AggStep { acc_reg: target_register, @@ -883,7 +895,7 @@ fn translate_aggregation( } let expr = &args[0]; let expr_reg = program.alloc_register(); - let _ = translate_expr(program, select, expr, expr_reg, cursor_hint); + let _ = translate_expr(program, Some(select), expr, expr_reg, cursor_hint); program.emit_insn(Insn::AggStep { acc_reg: target_register, col: expr_reg, @@ -898,7 +910,7 @@ fn translate_aggregation( } let expr = &args[0]; let expr_reg = program.alloc_register(); - let _ = translate_expr(program, select, expr, expr_reg, cursor_hint); + let _ = translate_expr(program, Some(select), expr, expr_reg, cursor_hint); program.emit_insn(Insn::AggStep { acc_reg: target_register, col: expr_reg, @@ -932,8 +944,14 @@ fn translate_aggregation( _ => crate::bail_parse_error!("Incorrect delimiter parameter"), }; - translate_expr(program, select, expr, expr_reg, cursor_hint)?; - translate_expr(program, select, &delimiter_expr, delimiter_reg, cursor_hint)?; + translate_expr(program, Some(select), expr, expr_reg, cursor_hint)?; + translate_expr( + program, + Some(select), + &delimiter_expr, + delimiter_reg, + cursor_hint, + )?; program.emit_insn(Insn::AggStep { acc_reg: target_register, @@ -950,7 +968,7 @@ fn translate_aggregation( } let expr = &args[0]; let expr_reg = program.alloc_register(); - let _ = translate_expr(program, select, expr, expr_reg, cursor_hint)?; + let _ = translate_expr(program, Some(select), expr, expr_reg, cursor_hint)?; program.emit_insn(Insn::AggStep { acc_reg: target_register, col: expr_reg, @@ -965,7 +983,7 @@ fn translate_aggregation( } let expr = &args[0]; let expr_reg = program.alloc_register(); - let _ = translate_expr(program, select, expr, expr_reg, cursor_hint)?; + let _ = translate_expr(program, Some(select), expr, expr_reg, cursor_hint)?; program.emit_insn(Insn::AggStep { acc_reg: target_register, col: expr_reg, diff --git a/core/translate/where_clause.rs b/core/translate/where_clause.rs index 4b6e89acb..e4ec529ba 100644 --- a/core/translate/where_clause.rs +++ b/core/translate/where_clause.rs @@ -306,12 +306,12 @@ fn translate_condition_expr( ast::Expr::Binary(lhs, op, rhs) => { let lhs_reg = program.alloc_register(); let rhs_reg = program.alloc_register(); - let _ = translate_expr(program, select, lhs, lhs_reg, cursor_hint); + let _ = translate_expr(program, Some(select), lhs, lhs_reg, cursor_hint); match lhs.as_ref() { ast::Expr::Literal(_) => program.mark_last_insn_constant(), _ => {} } - let _ = translate_expr(program, select, rhs, rhs_reg, cursor_hint); + let _ = translate_expr(program, Some(select), rhs, rhs_reg, cursor_hint); match rhs.as_ref() { ast::Expr::Literal(_) => program.mark_last_insn_constant(), _ => {} @@ -657,9 +657,9 @@ fn translate_condition_expr( let pattern_reg = program.alloc_register(); let column_reg = program.alloc_register(); // LIKE(pattern, column). We should translate the pattern first before the column - let _ = translate_expr(program, select, rhs, pattern_reg, cursor_hint)?; + let _ = translate_expr(program, Some(select), rhs, pattern_reg, cursor_hint)?; program.mark_last_insn_constant(); - let _ = translate_expr(program, select, lhs, column_reg, cursor_hint)?; + let _ = translate_expr(program, Some(select), lhs, column_reg, cursor_hint)?; program.emit_insn(Insn::Function { func: ScalarFunc::Like, start_reg: pattern_reg,