From b5bd31a47b781be588c373ef3f60922f6b18d451 Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Thu, 21 Aug 2025 12:32:35 +0300 Subject: [PATCH] Remove old unused data structures and functions --- core/translate/insert.rs | 313 +-------------------------------------- 1 file changed, 2 insertions(+), 311 deletions(-) diff --git a/core/translate/insert.rs b/core/translate/insert.rs index c5aace89a..7e7317271 100644 --- a/core/translate/insert.rs +++ b/core/translate/insert.rs @@ -6,7 +6,7 @@ use turso_sqlite3_parser::ast::{ }; use crate::error::{SQLITE_CONSTRAINT_NOTNULL, SQLITE_CONSTRAINT_PRIMARYKEY}; -use crate::schema::{self, IndexColumn, Table}; +use crate::schema::{self, Table}; use crate::translate::emitter::{ emit_cdc_insns, emit_cdc_patch_record, prepare_cdc_if_necessary, OperationMode, }; @@ -586,19 +586,6 @@ pub fn translate_insert( Ok(program) } -#[derive(Debug)] -/// Represents how a column should be populated during an INSERT. -/// Contains both the column definition and optionally the index into the VALUES tuple. -struct ColumnMapping<'a> { - /// Reference to the column definition from the table schema - column: &'a Column, - /// If Some(i), use the i-th value from the VALUES tuple - /// If None, use NULL (column was not specified in INSERT statement) - value_index: Option, - /// The default value for the column, if defined - default_value: Option<&'a Expr>, -} - pub const ROWID_COLUMN: &Column = &Column { name: None, ty: schema::Type::Integer, @@ -612,302 +599,6 @@ pub const ROWID_COLUMN: &Column = &Column { hidden: false, }; -/// Resolves how each column in a table should be populated during an INSERT. -/// Returns a Vec of ColumnMapping, one for each column in the table's schema. -/// -/// For each column, specifies: -/// 1. The column definition (type, constraints, etc) -/// 2. Where to get the value from: -/// - Some(i) -> use i-th value from the VALUES tuple -/// - None -> use NULL (column wasn't specified in INSERT) -/// -/// Two cases are handled: -/// 1. No column list specified (INSERT INTO t VALUES ...): -/// - Values are assigned to columns in table definition order -/// - If fewer values than columns, remaining columns map to None -/// 2. Column list specified (INSERT INTO t (col1, col3) VALUES ...): -/// - Named columns map to their corresponding value index -/// - Unspecified columns map to None -fn resolve_columns_for_insert<'a>( - table: &'a Table, - columns: &Option, - num_values: usize, -) -> Result>> { - let table_columns = table.columns(); - - // +1 for rowid implicit ROWID column - let mut column_mappings = Vec::with_capacity(table_columns.len() + 1); - column_mappings.push(ColumnMapping { - column: ROWID_COLUMN, - value_index: None, - default_value: None, - }); - for column in table_columns { - column_mappings.push(ColumnMapping { - column, - value_index: None, - default_value: column.default.as_ref(), - }); - } - - if columns.is_none() { - // Case 1: No columns specified - map values to columns in order - let mut value_idx = 0; - for (i, col) in table_columns.iter().enumerate() { - column_mappings[i + 1].value_index = if col.hidden { None } else { Some(value_idx) }; - if !col.hidden { - value_idx += 1; - } - } - - if num_values != value_idx { - crate::bail_parse_error!( - "table {} has {} columns but {} values were supplied", - &table.get_name(), - value_idx, - num_values - ); - } - } else { - // Case 2: Columns specified - map named columns to their values - // Map each named column to its value index - for (value_index, column_name) in columns.as_ref().unwrap().iter().enumerate() { - let column_name = normalize_ident(column_name.as_str()); - let table_index = if column_name == ROWID { - Some(0) - } else { - column_mappings.iter().position(|c| { - c.column - .name - .as_ref() - .is_some_and(|name| name.eq_ignore_ascii_case(&column_name)) - }) - }; - - let Some(table_index) = table_index else { - crate::bail_parse_error!( - "table {} has no column named {}", - &table.get_name(), - column_name - ); - }; - - column_mappings[table_index].value_index = Some(value_index); - } - } - - Ok(column_mappings) -} - -/// Represents how a column in an index should be populated during an INSERT. -/// Similar to ColumnMapping above but includes the index name, as well as multiple -/// possible value indices for each. -#[derive(Debug, Default)] -struct IndexColMapping { - idx_name: String, - columns: Vec<(usize, IndexColumn)>, - value_indicies: Vec>, -} - -impl IndexColMapping { - fn new(name: String) -> Self { - IndexColMapping { - idx_name: name, - ..Default::default() - } - } -} - -/// Example: -/// Table 'test': (a, b, c); -/// Index 'idx': test(a, b); -///________________________________ -/// Insert (a, c): (2, 3) -/// Record: (2, NULL, 3) -/// IndexColMapping: (a, b) = (2, NULL) -fn resolve_indicies_for_insert( - schema: &Schema, - table: &Table, - columns: &[ColumnMapping<'_>], -) -> Result> { - let mut index_col_mappings = Vec::new(); - // Iterate over all indices for this table - for index in schema.get_indices(table.get_name()) { - let mut idx_map = IndexColMapping::new(index.name.clone()); - // For each column in the index (in the order defined by the index), - // try to find the corresponding column in the insert’s column mapping. - for idx_col in &index.columns { - let target_name = normalize_ident(idx_col.name.as_str()); - if let Some((i, col_mapping)) = columns.iter().enumerate().find(|(_, mapping)| { - mapping - .column - .name - .as_ref() - .is_some_and(|name| name.eq_ignore_ascii_case(&target_name)) - }) { - idx_map.columns.push((i, idx_col.clone())); - idx_map.value_indicies.push(col_mapping.value_index); - } else { - return Err(crate::LimboError::ParseError(format!( - "Column {} not found in index {}", - target_name, index.name - ))); - } - } - // Add the mapping if at least one column was found. - if !idx_map.columns.is_empty() { - index_col_mappings.push(idx_map); - } - } - Ok(index_col_mappings) -} - -fn populate_columns_multiple_rows( - program: &mut ProgramBuilder, - column_mappings: &[ColumnMapping], // columns in order of table definition - column_registers_start: usize, - yield_reg: usize, - resolver: &Resolver, - temp_table_ctx: &Option, -) -> Result<()> { - // In case when both rowid and rowid-alias column provided in the query - turso-db overwrite rowid with **latest** value from the list - // As we iterate by column in natural order of their definition in scheme, - // we need to track last value_index we wrote to the rowid and overwrite rowid register only if new value_index is greater - let mut last_rowid_explicit_value = None; - for (i, mapping) in column_mappings.iter().enumerate() { - let column_register = column_registers_start + i; - - if let Some(value_index) = mapping.value_index { - let write_directly_to_rowid_reg = mapping.column.is_rowid_alias; - let write_reg = if write_directly_to_rowid_reg { - if last_rowid_explicit_value.is_some_and(|x| x > value_index) { - continue; - } - last_rowid_explicit_value = Some(value_index); - column_registers_start // rowid always the first register in the array for insertion record - } else { - column_register - }; - if let Some(temp_table_ctx) = temp_table_ctx { - program.emit_column_or_rowid(temp_table_ctx.cursor_id, value_index, write_reg); - } else { - program.emit_insn(Insn::Copy { - src_reg: yield_reg + value_index, - dst_reg: write_reg, - extra_amount: 0, - }); - } - // write_reg can be euqal to column_register if column list explicitly mention "rowid" - if write_reg != column_register { - program.emit_null(column_register, None); - program.mark_last_insn_constant(); - } - } else if mapping.column.is_rowid_alias { - program.emit_insn(Insn::SoftNull { - reg: column_register, - }); - } else if let Some(default_expr) = mapping.default_value { - translate_expr(program, None, default_expr, column_register, resolver)?; - } else { - // Column was not specified as has no DEFAULT - use NULL if it is nullable, otherwise error - // Rowid alias columns can be NULL because we will autogenerate a rowid in that case. - let is_nullable = !mapping.column.primary_key || mapping.column.is_rowid_alias; - if is_nullable { - program.emit_insn(Insn::Null { - dest: column_register, - dest_end: None, - }); - } else { - crate::bail_parse_error!( - "column {} is not nullable", - mapping.column.name.as_ref().expect("column name is None") - ); - } - } - } - Ok(()) -} - -/// Populates the column registers with values for a single row -#[allow(clippy::too_many_arguments)] -fn populate_column_registers( - program: &mut ProgramBuilder, - value: &[Expr], - column_mappings: &[ColumnMapping], - column_registers_start: usize, - resolver: &Resolver, -) -> Result<()> { - // In case when both rowid and rowid-alias column provided in the query - turso-db overwrite rowid with **latest** value from the list - // As we iterate by column in natural order of their definition in scheme, - // we need to track last value_index we wrote to the rowid and overwrite rowid register only if new value_index is greater - let mut last_rowid_explicit_value = None; - for (i, mapping) in column_mappings.iter().enumerate() { - let column_register = column_registers_start + i; - - // Column has a value in the VALUES tuple - if let Some(value_index) = mapping.value_index { - // When inserting a single row, SQLite writes the value provided for the rowid alias column (INTEGER PRIMARY KEY) - // directly into the rowid register and writes a NULL into the rowid alias column. - let write_directly_to_rowid_reg = mapping.column.is_rowid_alias; - let write_reg = if write_directly_to_rowid_reg { - if last_rowid_explicit_value.is_some_and(|x| x > value_index) { - continue; - } - last_rowid_explicit_value = Some(value_index); - column_registers_start // rowid always the first register in the array for insertion record - } else { - column_register - }; - - translate_expr_no_constant_opt( - program, - None, - value.get(value_index).expect("value index out of bounds"), - write_reg, - resolver, - NoConstantOptReason::RegisterReuse, - )?; - // write_reg can be euqal to column_register if column list explicitly mention "rowid" - if write_reg != column_register { - program.emit_null(column_register, None); - program.mark_last_insn_constant(); - } - } else if mapping.column.hidden { - program.emit_insn(Insn::Null { - dest: column_register, - dest_end: None, - }); - program.mark_last_insn_constant(); - } else if let Some(default_expr) = mapping.default_value { - translate_expr_no_constant_opt( - program, - None, - default_expr, - column_register, - resolver, - NoConstantOptReason::RegisterReuse, - )?; - } else { - // Column was not specified as has no DEFAULT - use NULL if it is nullable, otherwise error - // Rowid alias columns can be NULL because we will autogenerate a rowid in that case. - let is_nullable = !mapping.column.primary_key || mapping.column.is_rowid_alias; - if is_nullable { - program.emit_insn(Insn::Null { - dest: column_register, - dest_end: None, - }); - program.mark_last_insn_constant(); - } else { - crate::bail_parse_error!( - "column {} is not nullable", - mapping.column.name.as_ref().expect("column name is None") - ); - } - } - } - Ok(()) -} - /// Represents how a table should be populated during an INSERT. #[derive(Debug)] struct Insertion<'a> { @@ -1149,7 +840,7 @@ fn translate_rows_multiple<'short, 'long: 'short>( let translate_value_fn = |prg: &mut ProgramBuilder, value_index: usize, column_register: usize| { if let Some(temp_table_ctx) = temp_table_ctx { - prg.emit_column(temp_table_ctx.cursor_id, value_index, column_register); + prg.emit_column_or_rowid(temp_table_ctx.cursor_id, value_index, column_register); } else { prg.emit_insn(Insn::Copy { src_reg: yield_reg + value_index,